This commit is contained in:
afornerot 2019-07-19 16:51:11 +02:00
parent bf1c7299b1
commit 030fd9a119
17 changed files with 401 additions and 31 deletions

View File

@ -153,7 +153,7 @@ class Group
* @var ArrayCollection $message
* @var Message
*
* @ORM\OneToMany(targetEntity="Cadoles\WebsocketBundle\Entity\Message", mappedBy="user", cascade={"persist"}, orphanRemoval=true)
* @ORM\OneToMany(targetEntity="Cadoles\WebsocketBundle\Entity\Message", mappedBy="group", cascade={"persist"}, orphanRemoval=true)
*/
protected $messages;

View File

@ -260,7 +260,12 @@ class User implements UserInterface, \Serializable
* @ORM\OneToMany(targetEntity="Cadoles\WebsocketBundle\Entity\Message", mappedBy="user", cascade={"persist"}, orphanRemoval=true)
*/
private $messages;
/**
* @ORM\ManyToMany(targetEntity="Cadoles\WebsocketBundle\Entity\Message", mappedBy="readers")
*/
protected $messagereaders;
//== CODE A NE PAS REGENERER
/**
@ -1382,4 +1387,38 @@ class User implements UserInterface, \Serializable
{
return $this->messages;
}
/**
* Add messagereader
*
* @param \Cadoles\WebsocketBundle\Entity\Message $messagereader
*
* @return User
*/
public function addMessagereader(\Cadoles\WebsocketBundle\Entity\Message $messagereader)
{
$this->messagereaders[] = $messagereader;
return $this;
}
/**
* Remove messagereader
*
* @param \Cadoles\WebsocketBundle\Entity\Message $messagereader
*/
public function removeMessagereader(\Cadoles\WebsocketBundle\Entity\Message $messagereader)
{
$this->messagereaders->removeElement($messagereader);
}
/**
* Get messagereaders
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getMessagereaders()
{
return $this->messagereaders;
}
}

View File

@ -100,6 +100,10 @@ body {
font-size: 35px;
}
.navbar-top-links li a .badge {
margin-left: 10px;
}
@media (max-width: 767px) {
.navbar-default .navbar-header #title {
display: none;

View File

@ -152,7 +152,7 @@
{% block localexternalscript %}
{% endblock %}
<script>
{% block localjavascript %}

View File

@ -446,7 +446,7 @@ class PageController extends Controller
public function viewAction(Request $request,$id,$access=null) {
// usage soit portal / user / group
$usage=$request->query->get('usage');
$group=$request->query->get('group');
$groupid=$request->query->get('group');
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository($this->labelentity)->find($id);
@ -474,6 +474,44 @@ class PageController extends Controller
}
}
// On marque tt les messages comme lu par l'utilisateur
if($usage=="group") {
// On calcule le nombre de message non lu pour le groupe
$group=$em->getRepository("CadolesCoreBundle:Group")->find($groupid);
$qb = $em ->createQueryBuilder();
$tm = $qb ->select($qb->expr()->count('m.id'))
->from('CadolesWebsocketBundle:Message', 'm')
->where('m.group = :group')
->andWhere('m.user != :user')
->setParameter('group', $group)
->setParameter('user', $this->getUser())
->getQuery()->getSingleScalarResult();
$qb = $em ->createQueryBuilder();
$tr = $qb ->select($qb->expr()->count('m.id'))
->from('CadolesWebsocketBundle:Message', 'm')
->where('m.group = :group')
->andWhere('m.user != :user')
->andWhere(':user MEMBER OF m.readers')
->setParameter('group', $group)
->setParameter('user', $this->getUser())
->getQuery()->getSingleScalarResult();
if($tm-$tr>0) {
$messages=$em->getRepository("CadolesWebsocketBundle:Message")->findBy(["group"=>$group]);
foreach($messages as $message) {
$readers=$message->getReaders();
if ( !$readers->contains($this->getUser()) ) {
$message->addReader($this->getUser());
}
$em->persist($message);
$em->flush();
}
}
}
// Type Calendrier
if($entity->getPageCategory()->getId()==-100) {
$entity->setUrl($this->generateUrl('cadoles_portal_user_calendar_view'));
@ -485,7 +523,7 @@ class PageController extends Controller
'access' => $access,
'canupdate' => $canupdate,
'usage' => $usage,
'group' => $group
'group' => $groupid
]);
}
@ -500,7 +538,7 @@ class PageController extends Controller
'access' => $access,
'canupdate' => $canupdate,
'usage' => $usage,
'group' => $group
'group' => $groupid
]);
}
@ -514,7 +552,7 @@ class PageController extends Controller
'access' => $access,
'canupdate' => $canupdate,
'usage' => $usage,
'group' => $group
'group' => $groupid
]);
}
// Type Widgets
@ -529,7 +567,7 @@ class PageController extends Controller
'mode' => "view",
'widgets' => $this->getDoctrine()->getRepository("CadolesPortalBundle:Widget")->getWidgetAccess($access,'config'),
'usage' => $usage,
'group' => $group
'group' => $groupid
]);
}
// Type Editeur
@ -542,7 +580,7 @@ class PageController extends Controller
'access' => $access,
'canupdate' => $canupdate,
'usage' => $usage,
'group' => $group
'group' => $groupid
]);
}

View File

@ -1875,7 +1875,7 @@ class PagewidgetController extends Controller
'tool' => "cadoles_websocket_chat",
'access' => $access,
'usage' => $usage,
'group' => $group
'group' => $group,
]);
}
}

View File

@ -133,7 +133,6 @@ class Page
private $templategroups;
/* champs calculé non stocké en base */
private $canupdate;
@ -147,6 +146,17 @@ class Page
return $this;
}
/* champs calculé non stocké en base */
private $counterread;
public function getCounterRead()
{
return $this->counterread;
}
public function setCounterRead($counterread)
{
$this->counterread = $counterread;
return $this;
}
// A garder pour forcer l'id en init
public function setId($id)

View File

@ -131,6 +131,29 @@ class PageRepository extends EntityRepository
}
}
// On calcule le nombre de message non lu pour le groupe
$tm = $this ->getEntityManager()->createQueryBuilder()
->select($qb->expr()->count('m.id'))
->from('CadolesWebsocketBundle:Message', 'm')
->where('m.group = :group')
->andWhere('m.user != :user')
->setParameter('group', $groupshared)
->setParameter('user', $user)
->getQuery()->getSingleScalarResult();
$tr = $this ->getEntityManager()->createQueryBuilder()
->select($qb->expr()->count('m.id'))
->from('CadolesWebsocketBundle:Message', 'm')
->where('m.group = :group')
->andWhere('m.user != :user')
->andWhere(':user MEMBER OF m.readers')
->setParameter('group', $groupshared)
->setParameter('user', $user)
->getQuery()->getSingleScalarResult();
foreach($pagesshared as $key2 => $pageshared) {
$pagesshared[$key2]->setCounterRead($tm-$tr);
}
$groupsshared[$key]->pagesshared=$pagesshared;
}
}

View File

@ -45,15 +45,30 @@
{% set forcereload=false %}
{% endif %}
{% set isactive="" %}
{% if entity.id is defined and page.id==entity.id %}
<li id="menupage-{{page.id}}" class="active" style="cursor:pointer"><a onClick="showPage({{ page.id }},{{ page.pagecategory.id }},'{{ page.canupdate }}','group','{{forcereload}}','{{groupshared.id}}')">Groupe = {{ groupshared.label }}</a></li>
{% else %}
<li id="menupage-{{page.id}}"><a style="cursor:pointer" onClick="showPage({{ page.id }},{{ page.pagecategory.id }},'{{ page.canupdate }}','group','{{forcereload}}','{{groupshared.id}}')">Groupe = {{ groupshared.label }}</a></li>
{% set isactive="class='active'" %}
{% endif %}
<li id="menupage-{{page.id}}" {{ isactive }} style="cursor:pointer">
<a data-group="{{groupshared.id}}" onClick="showPage({{ page.id }},{{ page.pagecategory.id }},'{{ page.canupdate }}','group','{{forcereload}}','{{groupshared.id}}')">
Groupe = {{ groupshared.label }}
{% if page.counterread > 0 %}
<span id="badge-{{groupshared.id}}" class="badge">{{page.counterread}}</span>
{% endif %}
</a>
</li>
{% else %}
<ul id="pagesshared" class="nav navbar-top-links navbar-left">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Groupe = {{ groupshared.label }}<span class="caret"></span></a>
<a data-group="{{groupshared.id}}" href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
Groupe = {{ groupshared.label }}
<span class="caret"></span>
{% if groupshared.pagesshared[0].counterread > 0 %}
<span id="badge-{{groupshared.id}}" class="badge">{{groupshared.pagesshared[0].counterread}}</span>
{% endif %}
</a>
<ul class="dropdown-menu">
{% for page in groupshared.pagesshared %}
{% set forcereload=true %}
@ -61,11 +76,16 @@
{% set forcereload=false %}
{% endif %}
{% set isactive="" %}
{% if entity.id is defined and page.id==entity.id %}
<li id="menupage-{{page.id}}" class="active" style="cursor:pointer"><a onClick="showPage({{ page.id }},{{ page.pagecategory.id }},'{{ page.canupdate }}','group','{{forcereload}}','{{groupshared.id}}')">{{ page.name }}</a></li>
{% else %}
<li id="menupage-{{page.id}}"><a style="cursor:pointer" onClick="showPage({{ page.id }},{{ page.pagecategory.id }},'{{ page.canupdate }}','group','{{forcereload}}','{{groupshared.id}}')">{{ page.name }}</a></li>
{% set isactive="class='active'" %}
{% endif %}
<li id="menupage-{{page.id}}" {{isactive}} style="cursor:pointer">
<a onClick="showPage({{ page.id }},{{ page.pagecategory.id }},'{{ page.canupdate }}','group','{{forcereload}}','{{groupshared.id}}')">
{{ page.name }}
</a>
</li>
{% endfor %}
</ul>
</li>
@ -182,7 +202,19 @@
</div>
</div>
</div>
</div>
</div>
{%if app.user %}
<a id="refreshcounter" data-event=""></a>
{% endif %}
{% endblock %}
{% block localexternalscript %}
{% if app.user %}
<script src="/{{alias}}/bundles/goswebsocket/js/vendor/autobahn.min.js"></script>
<script src="/{{alias}}/bundles/goswebsocket/js/gos_web_socket_client.js"></script>
{% endif %}
{% endblock %}
{% block localjavascript %}
@ -235,7 +267,55 @@
responsive: true,
iDisplayLength: 10,
order: [[ 1, "asc" ]],
});
});
// Init socket de counter
var _WS_URI = "wss://{{ gos_web_socket_server_host }}:{{ gos_web_socket_server_port }}";
var _WS_URI = "wss://{{ gos_web_socket_server_host }}:5555";
var webSocket = WS.connect(_WS_URI);
var globalsession;
webSocket.on("socket/connect", function (session) {
globalsession=session;
session.call("websocket/rpc/update_connection_data", {"userid": "{{app.user.id}}" }).then(
function (result)
{
//console.log("RPC Valid!", result);
},
function (error, desc)
{
//console.log("RPC Error", error, desc);
}
);
// The callback function in "subscribe" is called everytime an event is published in that channel.
session.subscribe("websocket/counter", function (uri, payload) {
if(payload.log) {
console.log("Received message", payload.log);
}
if(payload.alert) {
alert(payload.alert);
}
if(payload.from!={{app.user.id}}) {
menu=$("a[data-group='"+payload.group+"']");
if(menu.length) {
if(payload.add) {
console.log("Ajout counter pour group "+payload.group+" by "+payload.from);
if(menu.children(".badge").length) {
menu.children(".badge").html(+(menu.children(".badge").html())+1);
}
else menu.append("<span id='badge-"+payload.group+"' class='badge'>1</span");
}
}
}
});
$(document).on('click', '#refreshcounter', function(){
event=$(this).data("event");
session.publish("websocket/counter", event);
});
});
});
$(window).resize(function() {
@ -308,6 +388,11 @@
else
$("#pagecontainer").append("<iframe id='page-"+id+"' data-category='"+catid+"' class='pageframe' src='"+url+"' style='border:none; width:100%'></iframe>");
// Détruire le badge associé car normalement de fait on a lu les notif
if(usage=="group") {
$("#badge-"+groupid).remove()
}
// Cacher les actions possibles sur la page
$("#menuupdate").hide();
@ -377,4 +462,9 @@
$(location).attr('href', url);
};
// Permet de déclencher l'évenement de modification des counter
function counter(event) {
$('#refreshcounter').data("event",event);
$('#refreshcounter').click();
};
{% endblock %}

View File

@ -74,6 +74,7 @@ class ChatController extends Controller
'border' => $border,
'colorbodyback' => $colorbodyback,
'colorbodyfont' => $colorbodyfont,
'fgmanager' => ($usergroup->getFgmanager()||$user->getRole()=="ROLE_ADMIN"||$user->getRole()=="ROLE_MODO"),
'form' => $form->createView()
]);
}

View File

@ -40,6 +40,17 @@ class Message
*/
private $group;
/**
* @ORM\ManyToMany(targetEntity="Cadoles\CoreBundle\Entity\User", inversedBy="messagereaders", cascade={"persist"})
* @ORM\JoinTable(name="messageuser",
* joinColumns={@ORM\JoinColumn(name="message", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="user", referencedColumnName="id")}
* )
*/
protected $readers;
/**
* Constructor
*/
@ -155,4 +166,38 @@ class Message
{
return $this->group;
}
/**
* Add reader
*
* @param \Cadoles\CoreBundle\Entity\User $reader
*
* @return Message
*/
public function addReader(\Cadoles\CoreBundle\Entity\User $reader)
{
$this->readers[] = $reader;
return $this;
}
/**
* Remove reader
*
* @param \Cadoles\CoreBundle\Entity\User $reader
*/
public function removeReader(\Cadoles\CoreBundle\Entity\User $reader)
{
$this->readers->removeElement($reader);
}
/**
* Get readers
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getReaders()
{
return $this->readers;
}
}

View File

@ -21,6 +21,7 @@ class RPCService implements RpcInterface {
*/
public function updateConnectionData(ConnectionInterface $connection, WampRequest $request, $params) {
$connection->userkey = $params['userkey'];
$connection->userid = $params['userid'];
return array("result" => array_sum($params));
}

View File

@ -5,6 +5,12 @@ services:
tags:
- { name: gos_web_socket.topic }
cadoles.websocket.counter:
class: Cadoles\WebsocketBundle\Topic\WebsocketCounter
arguments: ['@gos_web_socket.websocket.client_manipulator','@doctrine.orm.entity_manager','@service_container']
tags:
- { name: gos_web_socket.topic }
cadoles.websocket.rpc:
class: Cadoles\WebsocketBundle\RPC\RPCService
tags:

View File

@ -6,6 +6,11 @@ websocket_topic:
group:
pattern: '[-+]?\d+'
websocket_counter:
channel: websocket/counter
handler:
callback: 'websocket.counter'
websocket_rpc:
channel: websocket/rpc/{method}
handler:

View File

@ -26,6 +26,7 @@
.msgavatar {
float:left;
height:40px;
text-align: center;
}
.msgdiv {
float:left;
@ -52,7 +53,9 @@
<div id='message-{{message.id}}' class='message row'>
<div class='msgavatar'>
<img id='user_avatar_img' src='/{{ alias }}/uploads/avatar/{{message.user.avatar}}' class='avatar'><br>
<i class='delmessage fa fa-trash fa-fw' data-id='{{message.id}}' style='cursor: pointer;'></i>
{% if fgmanager or message.user == app.user %}
<i class='delmessage fa fa-trash fa-fw' data-id='{{message.id}}' style='cursor: pointer;'></i>
{% endif %}
</div>
<div class='msgdiv'>
<div class='msgtitle'>
@ -87,11 +90,11 @@
session.call("websocket/rpc/update_connection_data", {"userkey": "{{userkey}}" }).then(
function (result)
{
console.log("RPC Valid!", result);
//console.log("RPC Valid!", result);
},
function (error, desc)
{
console.log("RPC Error", error, desc);
//console.log("RPC Error", error, desc);
}
);
@ -101,7 +104,7 @@
html ="<div id='message-"+payload.msg.id+"' class='message row'>";
html+="<div class='msgavatar'>";
html+="<img id='user_avatar_img' src='/{{ alias }}/uploads/avatar/"+payload.msg.avatar+"' class='avatar'><br>";
if(payload.msg.userid=={{app.user.id}}) {
if(payload.msg.userid=={{app.user.id}} || '{{ fgmanager }}'=='1') {
html+="<i class='delmessage fa fa-trash fa-fw' data-id='"+payload.msg.id+"' style='cursor: pointer;'></i>";
}
html+="</div>";
@ -111,10 +114,8 @@
html+="</div>";
html+="</div>";
$(".mychat").prepend(html);
console.log("Received message by "+payload.msg.userid+" = ",payload.msg);
//console.log("Received message by "+payload.msg.userid+" = ",payload.msg);
}
if(payload.log) {
@ -136,14 +137,18 @@
event={type: "add", message: data};
session.publish("websocket/channel/{{groupid}}", event);
CKEDITOR.instances["chat_message"].setData('');
event={type: "add", group:{{groupid}}};
parent.parent.counter(event);
}
});
$(document).on('click', '.delmessage', function(){
console.log("suppression");
id=$(this).data("id");
event={type: "del", id: id};
session.publish("websocket/channel/{{groupid}}", event);
});
})
{% endif %}

View File

@ -0,0 +1,100 @@
<?php
namespace Cadoles\WebsocketBundle\Topic;
use Gos\Bundle\WebSocketBundle\Topic\TopicInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Wamp\Topic;
use Gos\Bundle\WebSocketBundle\Router\WampRequest;
use Doctrine\ORM\EntityManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Gos\Bundle\WebSocketBundle\Client\ClientManipulatorInterface;
use Cadoles\WebsocketBundle\Entity\Message;
class WebsocketCounter implements TopicInterface
{
protected $em;
protected $container;
protected $clientManipulator;
public function __construct(ClientManipulatorInterface $clientManipulator, EntityManager $em, ContainerInterface $container) {
$this->clientManipulator = $clientManipulator;
$this->em = $em;
$this->container = $container;
}
/**
* This will receive any Subscription requests for this topic.
*
* @param ConnectionInterface $connection
* @param Topic $topic
* @param WampRequest $request
* @return void
*/
public function onSubscribe(ConnectionInterface $connection, Topic $topic, WampRequest $request)
{
$userid=$connection->userid;
//this will broadcast the message to ALL subscribers of this topic.
//$topic->broadcast(['log' => $connection->resourceId." has joined ".$topic->getId()." ".$userid]);
}
/**
* This will receive any UnSubscription requests for this topic.
*
* @param ConnectionInterface $connection
* @param Topic $topic
* @param WampRequest $request
* @return void
*/
public function onUnSubscribe(ConnectionInterface $connection, Topic $topic, WampRequest $request)
{
//this will broadcast the message to ALL subscribers of this topic.
//$topic->broadcast(['msg' => $connection->resourceId . " has left " . $topic->getId()]);
}
/**
* This will receive any Publish requests for this topic.
*
* @param ConnectionInterface $connection
* @param Topic $topic
* @param WampRequest $request
* @param $event
* @param array $exclude
* @param array $eligible
* @return mixed|void
*/
public function onPublish(ConnectionInterface $connection, Topic $topic, WampRequest $request, $event, array $exclude, array $eligible)
{
$userid=$connection->userid;
$user=$this->em->getRepository("CadolesCoreBundle:User")->find($userid);
if(!$user)
return;
$group=$this->em->getRepository("CadolesCoreBundle:Group")->find($event["group"]);
if(!$group)
return;
$usergroup=$this->em->getRepository("CadolesCoreBundle:UserGroup")->findOneBy(["user"=>$user,"group"=>$group]);
if(!$usergroup)
return;
$topic->broadcast([$event["type"] => 1, "group" => $event["group"] , "from" =>$userid]);
}
/**
* Like RPC is will use to prefix the channel
* @return string
*/
public function getName()
{
return 'websocket.counter';
}
}

View File

@ -37,7 +37,7 @@ class WebsocketTopic implements TopicInterface
public function onSubscribe(ConnectionInterface $connection, Topic $topic, WampRequest $request)
{
//this will broadcast the message to ALL subscribers of this topic.
$topic->broadcast(['log' => $connection->resourceId." has joined ".$topic->getId()]);
//$topic->broadcast(['log' => $connection->resourceId." has joined ".$topic->getId()]);
}
@ -107,8 +107,11 @@ class WebsocketTopic implements TopicInterface
if($event["type"]=="del") {
$message=$this->em->getRepository("CadolesWebsocketBundle:Message")->find($event["id"]);
if($message&&($usergroup->getFgmanager()||$message->getUser()==$user)) {
$topic->broadcast(['del' => $message->getId()]);
if($message&&($usergroup->getFgmanager()||$message->getUser()==$user||$user->getRole()=="ROLE_ADMIN"||$user->getRole()=="ROLE_MODO" )) {
$id=$message->getId();
$this->em->remove($message);
$this->em->flush();
$topic->broadcast(['del' => $id]);
}
else $topic->broadcast(['log' => "Suppression interdite"]);
}