Message: Fix receivers

pull/4734/head
Angel Fernando Quiroz Campos 1 year ago
parent 6f951d0ddd
commit 482f038a54
  1. 2
      public/main/inc/lib/message.lib.php
  2. 4
      public/main/my_space/myStudents.php
  3. 74
      src/CoreBundle/DataPersister/MessageDataPersister.php
  4. 2
      src/CoreBundle/Entity/Listener/SkillRelUserListener.php
  5. 221
      src/CoreBundle/Entity/Message.php
  6. 53
      src/CoreBundle/Entity/MessageRelUser.php
  7. 2
      src/CoreBundle/Security/Authorization/Voter/MessageVoter.php
  8. 14
      tests/CoreBundle/Repository/MessageRepositoryTest.php

@ -287,7 +287,7 @@ class MessageManager
$message = (new Message())
->setSender($userSender)
->addReceiver($userRecipient)
->addReceiverTo($userRecipient)
->setTitle($subject)
->setContent($content)
->setGroup($group)

@ -498,7 +498,7 @@ switch ($action) {
->setTitle($subject)
->setContent($content)
->setSender(api_get_user_entity())
->addReceiver($student)
->addReceiverTo($student)
->setMsgType(Message::MESSAGE_TYPE_CONVERSATION)
;
$em->persist($message);
@ -523,7 +523,7 @@ switch ($action) {
->setTitle(sprintf(get_lang('Follow up message about student %s'), $studentFullName))
->setContent($content)
->setSender(api_get_user_entity())
->addReceiver(api_get_user_entity($boss['boss_id']))
->addReceiverTo(api_get_user_entity($boss['boss_id']))
->setMsgType(Message::MESSAGE_TYPE_CONVERSATION)
;
$em->persist($message);

@ -1,74 +0,0 @@
<?php
declare(strict_types=1);
/* For licensing terms, see /license.txt */
namespace Chamilo\CoreBundle\DataPersister;
use ApiPlatform\Core\DataPersister\ContextAwareDataPersisterInterface;
use ApiPlatform\Core\DataPersister\ResumableDataPersisterInterface;
use Chamilo\CoreBundle\Entity\Message;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Messenger\MessageBusInterface;
class MessageDataPersister implements ContextAwareDataPersisterInterface, ResumableDataPersisterInterface
{
private EntityManager $entityManager;
private ContextAwareDataPersisterInterface $decorated;
private MessageBusInterface $bus;
public function __construct(ContextAwareDataPersisterInterface $decorated, EntityManager $entityManager, MessageBusInterface $bus)
{
$this->decorated = $decorated;
$this->entityManager = $entityManager;
$this->bus = $bus;
}
public function supports($data, array $context = []): bool
{
return $this->decorated->supports($data, $context);
}
public function persist($data, array $context = [])
{
$result = $this->decorated->persist($data, $context);
if ($data instanceof Message && (
($context['collection_operation_name'] ?? null) === 'post' ||
($context['graphql_operation_name'] ?? null) === 'create'
//($context['item_operation_name'] ?? null) === 'put' // on update
)
) {
/*if (Message::MESSAGE_TYPE_INBOX === $result->getMsgType()) {
$messageSent = clone $result;
$messageSent
->setMsgType(Message::MESSAGE_TYPE_OUTBOX)
//->setRead(true)
;
$this->entityManager->persist($messageSent);
$this->entityManager->flush();
echo 'send11';
// Send message.
$this->bus->dispatch($data);
}*/
}
/*$this->entityManager->persist($data);
$this->entityManager->flush();*/
return $result;
}
public function remove($data, array $context = []): void
{
$this->entityManager->remove($data);
$this->entityManager->flush();
}
public function resumable(array $context = []): bool
{
return true;
}
}

@ -52,7 +52,7 @@ class SkillRelUserListener
$message = (new Message())
->setTitle($this->translator->trans('You have achieved a new skill.'))
->setContent($message)
->addReceiver($user)
->addReceiverTo($user)
->setSender($currentUser)
;

@ -27,15 +27,40 @@ use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
#[ApiResource(operations: [new Get(security: 'is_granted(\'VIEW\', object)'), new Put(security: 'is_granted(\'EDIT\', object)'), new Delete(security: 'is_granted(\'DELETE\', object)'), new GetCollection(security: 'is_granted(\'ROLE_USER\')'), new Post(securityPostDenormalize: 'is_granted(\'CREATE\', object)')], normalizationContext: ['groups' => ['message:read']], denormalizationContext: ['groups' => ['message:write']], security: 'is_granted(\'ROLE_USER\')')]
#[ORM\Table(name: 'message')]
#[ORM\Index(columns: ['user_sender_id'], name: 'idx_message_user_sender')]
#[ORM\Index(columns: ['group_id'], name: 'idx_message_group')]
#[ORM\Index(columns: ['msg_type'], name: 'idx_message_type')]
#[ORM\Entity(repositoryClass: MessageRepository::class)]
#[ORM\EntityListeners([MessageListener::class])]
#[ApiResource(
operations: [
new Get(security: "is_granted('VIEW', object)"),
new Put(security: "is_granted('EDIT', object)"),
new Delete(security: "is_granted('DELETE', object)"),
new GetCollection(security: "is_granted('ROLE_USER')"),
new Post(securityPostDenormalize: "is_granted('CREATE', object)"),
],
normalizationContext: [
'groups' => ['message:read'],
],
denormalizationContext: [
'groups' => ['message:write'],
],
security: "is_granted('ROLE_USER')"
)]
#[ApiFilter(filterClass: OrderFilter::class, properties: ['title', 'sendDate'])]
#[ApiFilter(filterClass: SearchFilter::class, properties: ['msgType' => 'exact', 'status' => 'exact', 'sender' => 'exact', 'receivers.receiver' => 'exact', 'receivers.tags.tag' => 'exact', 'parent' => 'exact'])]
#[ApiFilter(
filterClass: SearchFilter::class,
properties: [
'msgType' => 'exact',
'status' => 'exact',
'sender' => 'exact',
'receivers.receiver' => 'exact',
'receivers.tags.tag' => 'exact',
'parent' => 'exact',
]
)]
class Message
{
public const MESSAGE_TYPE_INBOX = 1;
@ -60,22 +85,12 @@ class Message
#[ORM\JoinColumn(name: 'user_sender_id', referencedColumnName: 'id', nullable: false)]
protected User $sender;
/**
* @var Collection|MessageRelUser[]
* @var Collection<int, MessageRelUser>
*/
#[Assert\Valid]
#[Groups(['message:read', 'message:write'])]
#[ORM\OneToMany(mappedBy: 'message', targetEntity: MessageRelUser::class, cascade: ['persist', 'remove'])]
protected array|null|Collection $receivers;
/**
* @var Collection|MessageRelUser[]
*/
#[Groups(['message:read', 'message:write'])]
protected array|null|Collection $receiversTo;
/**
* @var Collection|MessageRelUser[]
*/
#[Groups(['message:read', 'message:write'])]
protected array|null|Collection $receiversCc;
#[Groups(['message:write'])]
protected Collection $receivers;
#[Assert\NotBlank]
#[Groups(['message:read', 'message:write'])]
#[ORM\Column(name: 'msg_type', type: 'smallint', nullable: false)]
@ -95,8 +110,7 @@ class Message
#[Groups(['message:read', 'message:write'])]
#[ORM\Column(name: 'content', type: 'text', nullable: false)]
protected string $content;
#[Groups(['message:read', 'message:write'])]
protected ?MessageRelUser $firstReceiver = null;
#[ORM\ManyToOne(targetEntity: Usergroup::class)]
#[ORM\JoinColumn(name: 'group_id', referencedColumnName: 'id', onDelete: 'CASCADE')]
protected ?Usergroup $group = null;
@ -133,56 +147,44 @@ class Message
$this->attachments = new ArrayCollection();
$this->children = new ArrayCollection();
$this->receivers = new ArrayCollection();
$this->receiversCc = new ArrayCollection();
$this->receiversTo = new ArrayCollection();
$this->likes = new ArrayCollection();
$this->votes = 0;
$this->status = 0;
}
/**
* @return null|Collection|MessageRelUser[]
* @return Collection<int, MessageRelUser>
*/
public function getReceivers(): null|Collection|array
public function getReceivers(): Collection
{
return $this->receivers;
}
/**
* @return MessageRelUser[]
* @return Collection<int, MessageRelUser>
*/
public function getReceiversTo(): array
{
/*return $this->getReceivers()->filter(function (MessageRelUser $messageRelUser) {
return MessageRelUser::TYPE_TO === $messageRelUser->getReceiverType();
});*/
$list = [];
foreach ($this->receivers as $receiver) {
if (MessageRelUser::TYPE_TO === $receiver->getReceiverType()) {
$list[] = $receiver;
}
}
return $list;
#[Groups(['message:read'])]
public function getReceiversTo(): Collection
{
return $this->receivers
->filter(
fn(MessageRelUser $messageRelUser) => MessageRelUser::TYPE_TO === $messageRelUser->getReceiverType()
);
}
/**
* @return array<int, MessageRelUser>
* @return Collection<int, MessageRelUser>
*/
public function getReceiversCc(): array
#[Groups(['message:read'])]
public function getReceiversCc(): Collection
{
$list = [];
foreach ($this->receivers as $receiver) {
if (MessageRelUser::TYPE_CC === $receiver->getReceiverType()) {
$list[] = $receiver;
}
}
/*
For some reason this doesn't work, api platform returns an obj instead a collection.
$result = $this->receivers->filter(function (MessageRelUser $messageRelUser) {
error_log((string)$messageRelUser->getId());
return MessageRelUser::TYPE_CC === $messageRelUser->getReceiverType();
});
*/
return $list;
return $this->receivers
->filter(
fn(MessageRelUser $messageRelUser) => MessageRelUser::TYPE_CC === $messageRelUser->getReceiverType()
);
}
#[Groups(['message:read'])]
public function getFirstReceiver(): ?MessageRelUser
{
if ($this->receivers->count() > 0) {
@ -191,109 +193,153 @@ class Message
return null;
}
public function hasReceiver(User $receiver): bool
public function hasUserReceiver(User $receiver): bool
{
if ($this->receivers->count()) {
$criteria = Criteria::create()->where(Criteria::expr()->eq('receiver', $receiver))->andWhere(Criteria::expr()->eq('message', $this));
$criteria = Criteria::create()
->where(
Criteria::expr()->eq('receiver', $receiver)
)
->andWhere(
Criteria::expr()->eq('message', $this)
);
return $this->receivers->matching($criteria)->count() > 0;
}
return false;
}
public function addReceiver(User $receiver, int $receiverType = MessageRelUser::TYPE_TO): self
public function addReceiverTo(User $receiver): self
{
$messageRelUser = (new MessageRelUser())
->setReceiver($receiver)
->setReceiverType(MessageRelUser::TYPE_TO);
$this->addReceiver($messageRelUser);
return $this;
}
public function addReceiver(MessageRelUser $messageRelUser): self
{
$messageRelUser = (new MessageRelUser())->setReceiver($receiver)->setReceiverType($receiverType)->setMessage($this);
if (!$this->receivers->contains($messageRelUser)) {
$this->receivers->add($messageRelUser);
$messageRelUser->setMessage($this);
}
return $this;
}
public function setReceivers(Collection|MessageRelUser $receivers): self
public function addReceiverCc(User $receiver): self
{
/** @var MessageRelUser $receiver */
foreach ($receivers as $receiver) {
$receiver->setMessage($this);
}
$this->receivers = $receivers;
$messageRelUser = (new MessageRelUser())
->setReceiver($receiver)
->setReceiverType(MessageRelUser::TYPE_CC);
$this->addReceiver($messageRelUser);
return $this;
}
public function setSender(User $sender): self
public function removeReceiver(MessageRelUser $messageRelUser): self
{
$this->sender = $sender;
$this->receivers->removeElement($messageRelUser);
return $this;
}
public function getSender(): User
{
return $this->sender;
}
public function setMsgType(int $msgType): self
public function setSender(User $sender): self
{
$this->msgType = $msgType;
$this->sender = $sender;
return $this;
}
public function getMsgType(): int
{
return $this->msgType;
}
public function setSendDate(DateTime $sendDate): self
public function setMsgType(int $msgType): self
{
$this->sendDate = $sendDate;
$this->msgType = $msgType;
return $this;
}
public function getSendDate(): DateTime
{
return $this->sendDate;
}
public function setTitle(string $title): self
public function setSendDate(DateTime $sendDate): self
{
$this->title = $title;
$this->sendDate = $sendDate;
return $this;
}
public function getTitle(): string
{
return $this->title;
}
public function setContent(string $content): self
public function setTitle(string $title): self
{
$this->content = $content;
$this->title = $title;
return $this;
}
public function getContent(): string
{
return $this->content;
}
public function setUpdateDate(DateTime $updateDate): self
public function setContent(string $content): self
{
$this->updateDate = $updateDate;
$this->content = $content;
return $this;
}
public function getUpdateDate(): ?DateTime
{
return $this->updateDate;
}
public function setUpdateDate(DateTime $updateDate): self
{
$this->updateDate = $updateDate;
return $this;
}
public function getId(): ?int
{
return $this->id;
}
public function getVotes(): int
{
return $this->votes;
}
public function setVotes(int $votes): self
{
$this->votes = $votes;
return $this;
}
public function getVotes(): int
{
return $this->votes;
}
/**
* @return Collection<int, MessageAttachment>
*/
@ -301,6 +347,7 @@ class Message
{
return $this->attachments;
}
public function addAttachment(MessageAttachment $attachment): self
{
$this->attachments->add($attachment);
@ -308,10 +355,19 @@ class Message
return $this;
}
public function getParent(): ?self
{
return $this->parent;
}
public function setParent(self $parent = null): self
{
$this->parent = $parent;
return $this;
}
/**
* @return Collection<int, Message>
*/
@ -319,6 +375,7 @@ class Message
{
return $this->children;
}
public function addChild(self $child): self
{
$this->children[] = $child;
@ -326,16 +383,12 @@ class Message
return $this;
}
public function setParent(self $parent = null): self
{
$this->parent = $parent;
return $this;
}
public function getGroup(): ?Usergroup
{
return $this->group;
}
public function setGroup(?Usergroup $group): self
{
// $this->msgType = self::MESSAGE_TYPE_GROUP;
@ -343,10 +396,12 @@ class Message
return $this;
}
public function getStatus(): int
{
return $this->status;
}
public function setStatus(int $status): self
{
$this->status = $status;

@ -9,8 +9,6 @@ namespace Chamilo\CoreBundle\Entity;
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Metadata\ApiFilter;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Link;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
@ -19,46 +17,65 @@ use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
#[ApiResource]
#[UniqueEntity(fields: ['message', 'receiver'], errorPath: 'message', message: 'This message-receiver relation is already used.')]
#[UniqueEntity(
fields: ['message', 'receiver'],
message: 'This message-receiver relation is already used.',
errorPath: 'message'
)]
#[ORM\Table(name: 'message_rel_user')]
#[ORM\UniqueConstraint(name: 'message_receiver', columns: ['message_id', 'user_id'])]
#[ORM\Entity]
#[ApiFilter(filterClass: SearchFilter::class, properties: ['star' => 'exact', 'receiver' => 'exact', 'read' => 'exact', 'starred' => 'exact', 'tags.tag' => 'exact'])]
#[ApiResource(uriTemplate: '/messages/{id}/receivers.{_format}', uriVariables: ['id' => new Link(fromClass: \Chamilo\CoreBundle\Entity\Message::class, identifiers: ['id'])], status: 200, filters: ['annotated_chamilo_core_bundle_entity_message_rel_user_api_platform_core_bridge_doctrine_orm_filter_search_filter'], operations: [new GetCollection()])]
#[ApiFilter(
filterClass: SearchFilter::class,
properties: [
'star' => 'exact',
'receiver' => 'exact',
'read' => 'exact',
'starred' => 'exact',
'tags.tag' => 'exact',
]
)]
class MessageRelUser
{
public const TYPE_TO = 1;
public const TYPE_CC = 2;
#[Groups(['message:read', 'message:write'])]
#[ORM\Column(name: 'id', type: 'bigint')]
#[ORM\Id]
#[ORM\GeneratedValue]
protected ?int $id = null;
#[ORM\ManyToOne(targetEntity: \Chamilo\CoreBundle\Entity\Message::class, inversedBy: 'receivers', cascade: ['persist'])]
#[ORM\ManyToOne(targetEntity: Message::class, cascade: ['persist'], inversedBy: 'receivers')]
#[ORM\JoinColumn(name: 'message_id', referencedColumnName: 'id', nullable: false)]
protected Message $message;
#[Assert\NotNull]
#[Groups(['message:read', 'message:write'])]
#[ORM\ManyToOne(targetEntity: \Chamilo\CoreBundle\Entity\User::class, cascade: ['persist'], inversedBy: 'receivedMessages')]
#[ORM\ManyToOne(targetEntity: User::class, cascade: ['persist'], inversedBy: 'receivedMessages')]
#[ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')]
protected User $receiver;
#[Groups(['message:read', 'message:write'])]
#[ORM\Column(name: 'msg_read', type: 'boolean', nullable: false)]
protected bool $read;
#[Groups(['message:read', 'message:write'])]
#[ORM\Column(name: 'receiver_type', type: 'smallint', nullable: false)]
protected int $receiverType;
#[Groups(['message:read', 'message:write'])]
#[ORM\Column(name: 'starred', type: 'boolean', nullable: false)]
protected bool $starred;
/**
* @var Collection|MessageTag[]
* @var Collection<int, MessageTag>
*/
#[Assert\Valid]
#[Groups(['message:read', 'message:write'])]
#[Groups(['message:read'])]
#[ORM\JoinTable(name: 'message_rel_user_rel_tags')]
#[ORM\ManyToMany(targetEntity: \Chamilo\CoreBundle\Entity\MessageTag::class, inversedBy: 'messageRelUsers', cascade: ['persist', 'remove'])]
#[ORM\ManyToMany(targetEntity: MessageTag::class, inversedBy: 'messageRelUsers', cascade: ['persist', 'remove'])]
protected Collection $tags;
public function __construct()
{
$this->tags = new ArrayCollection();
@ -66,10 +83,12 @@ class MessageRelUser
$this->starred = false;
$this->receiverType = self::TYPE_TO;
}
public function getId(): ?int
{
return $this->id;
}
/**
* @return Collection|MessageTag[]
*/
@ -77,6 +96,7 @@ class MessageRelUser
{
return $this->tags;
}
public function addTag(MessageTag $tag): self
{
if (!$this->tags->contains($tag)) {
@ -85,6 +105,7 @@ class MessageRelUser
return $this;
}
public function removeTag(MessageTag $tag): self
{
if ($this->tags->contains($tag)) {
@ -93,50 +114,60 @@ class MessageRelUser
return $this;
}
public function isRead(): bool
{
return $this->read;
}
public function setRead(bool $read): self
{
$this->read = $read;
return $this;
}
public function isStarred(): bool
{
return $this->starred;
}
public function setStarred(bool $starred): self
{
$this->starred = $starred;
return $this;
}
public function getMessage(): Message
{
return $this->message;
}
public function setMessage(Message $message): self
{
$this->message = $message;
return $this;
}
public function getReceiver(): User
{
return $this->receiver;
}
public function setReceiver(User $receiver): self
{
$this->receiver = $receiver;
return $this;
}
public function getReceiverType(): int
{
return $this->receiverType;
}
public function setReceiverType(int $receiverType): self
{
$this->receiverType = $receiverType;

@ -76,7 +76,7 @@ class MessageVoter extends Voter
break;
case self::VIEW:
if ($message->hasReceiver($user) || $message->getSender() === $user) {
if ($message->hasUserReceiver($user) || $message->getSender() === $user) {
return true;
}

@ -40,7 +40,7 @@ class MessageRepositoryTest extends AbstractApiTest
->setContent('content')
->setMsgType(Message::MESSAGE_TYPE_INBOX)
->setSender($admin)
->addReceiver($testUser)
->addReceiverTo($testUser)
->setSendDate(new DateTime())
->setVotes(0)
->setGroup(null)
@ -53,7 +53,7 @@ class MessageRepositoryTest extends AbstractApiTest
$this->assertNotNull($message->getUpdateDate());
$this->assertNull($message->getParent());
$this->assertTrue($message->hasReceiver($testUser));
$this->assertTrue($message->hasUserReceiver($testUser));
$transport = $this->getContainer()->get('messenger.transport.sync_priority_high');
$this->assertCount(1, $transport->getSent());
@ -98,7 +98,7 @@ class MessageRepositoryTest extends AbstractApiTest
->setContent('content')
->setMsgType(Message::MESSAGE_TYPE_INBOX)
->setSender($admin)
->addReceiver($testUser)
->addReceiverTo($testUser)
;
$this->assertHasNoEntityViolations($message);
@ -318,7 +318,7 @@ class MessageRepositoryTest extends AbstractApiTest
->setContent('content')
->setMsgType(Message::MESSAGE_TYPE_INBOX)
->setSender($admin)
->addReceiver($testUser)
->addReceiverTo($testUser)
;
$this->assertHasNoEntityViolations($message);
@ -389,8 +389,8 @@ class MessageRepositoryTest extends AbstractApiTest
->setContent('content')
->setMsgType(Message::MESSAGE_TYPE_INBOX)
->setSender($admin)
->addReceiver($testUser)
->addReceiver($receiverCopy, MessageRelUser::TYPE_CC)
->addReceiverTo($testUser)
->addReceiverCc($receiverCopy, MessageRelUser::TYPE_CC)
;
$this->assertHasNoEntityViolations($message);
@ -659,7 +659,7 @@ class MessageRepositoryTest extends AbstractApiTest
->setContent('content')
->setMsgType(Message::MESSAGE_TYPE_INBOX)
->setSender($admin)
->addReceiver($testUser)
->addReceiverTo($testUser)
;
$this->assertHasNoEntityViolations($message);

Loading…
Cancel
Save