Merge pull request #5695 from christianbeeznest/ofaj-21887

Message: Fix message status update on deletion for sender and receiver - refs BT#21887
pull/5699/head
Nicolas Ducoulombier 1 year ago committed by GitHub
commit f31c75647b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 3
      assets/vue/components/message/constants.js
  2. 23
      assets/vue/services/message.js
  3. 8
      assets/vue/views/message/MessageCreate.vue
  4. 21
      assets/vue/views/message/MessageList.vue
  5. 2
      src/CoreBundle/DataProvider/Extension/MessageExtension.php
  6. 37
      src/CoreBundle/Entity/Message.php
  7. 1
      src/CoreBundle/Entity/MessageRelUser.php
  8. 2
      src/CoreBundle/Migrations/Schema/V200/Version20200821224244.php
  9. 4
      src/CoreBundle/Repository/MessageRepository.php
  10. 75
      src/CoreBundle/State/MessageProcessor.php

@ -9,5 +9,6 @@ export const MESSAGE_TYPE_WALL = 4;
export const MESSAGE_TYPE_GROUP = 5;
export const MESSAGE_TYPE_INVITATION = 6;
export const MESSAGE_TYPE_CONVERSATION = 7;
export const MESSAGE_TYPE_SENDER = 8;
export const MESSAGE_STATUS_DELETED = 3;
export const MESSAGE_STATUS_SENDER_DELETED = 3;

@ -1,5 +1,6 @@
import makeService from "./api"
import baseService from "./baseService"
import axios from "axios"
// MIGRATION IN PROGRESS. makeService is deprecated
// if you use some method in this service you should try to refactor it with new baseService defining async functions
@ -22,7 +23,27 @@ async function countUnreadMessages(params) {
return await baseService.get(`/api/messages?${queryParams}`)
}
async function deleteMessageForUser(messageId, userId) {
return await axios.patch(`/api/messages/${messageId}/delete-for-user`,
{ userId: userId },
{
headers: {
'Content-Type': 'application/json'
}
})
}
async function checkAndUpdateMessageStatus(messageId) {
return await axios.patch(`/api/messages/${messageId}/check-and-update-status`, {}, {
headers: {
'Content-Type': 'application/json'
}
})
}
export const messageService = {
create,
countUnreadMessages,
}
deleteMessageForUser,
checkAndUpdateMessageStatus,
};

@ -36,12 +36,18 @@ const message = ref({
const isLoading = ref(false)
const onSubmit = async (messageToSend) => {
if (!messageToSend.receivers || messageToSend.receivers.length === 0) {
notification.showErrorNotification("You must add at least one recipient.")
return
}
isLoading.value = true
try {
await messageService.create(messageToSend)
notification.showSuccessNotification("Message sent succesfully.")
} catch (error) {
notification.showErrorNotification(error)
notification.showErrorNotification(error.message || "Error sending message.")
} finally {
isLoading.value = false
}

@ -217,7 +217,7 @@ import DataTable from "primevue/datatable"
import Column from "primevue/column"
import { useConfirm } from "primevue/useconfirm"
import { useQuery } from "@vue/apollo-composable"
import { MESSAGE_STATUS_DELETED, MESSAGE_TYPE_INBOX } from "../../components/message/constants"
import { MESSAGE_STATUS_SENDER_DELETED, MESSAGE_TYPE_INBOX, MESSAGE_TYPE_SENDER } from "../../components/message/constants"
import { GET_USER_MESSAGE_TAGS } from "../../graphql/queries/MessageTag"
import { useNotification } from "../../composables/notification"
import { useMessageRelUserStore } from "../../store/messageRelUserStore"
@ -226,6 +226,7 @@ import SectionHeader from "../../components/layout/SectionHeader.vue"
import InputGroup from "primevue/inputgroup"
import InputText from "primevue/inputtext"
import BaseAppLink from "../../components/basecomponents/BaseAppLink.vue"
import { messageService } from "../../services/message"
const route = useRoute()
const router = useRouter()
@ -367,6 +368,8 @@ function showInbox() {
"order[sendDate]": "desc",
itemsPerPage: initialRowsPerPage,
page: 1,
'receivers.receiver': securityStore.user["@id"],
'receivers.receiverType': MESSAGE_TYPE_INBOX,
}
loadMessages()
@ -381,6 +384,7 @@ function showInboxByTag(tag) {
"order[sendDate]": "desc",
itemsPerPage: initialRowsPerPage,
page: 1,
'receivers.receiverType': MESSAGE_TYPE_INBOX,
}
loadMessages()
@ -396,6 +400,7 @@ function showUnread() {
"receivers.read": false,
itemsPerPage: initialRowsPerPage,
page: 1,
'receivers.receiverType': MESSAGE_TYPE_INBOX,
}
loadMessages()
@ -408,6 +413,7 @@ function showSent() {
fetchPayload = {
sender: securityStore.user["@id"],
"receivers.receiverType": MESSAGE_TYPE_SENDER,
"order[sendDate]": "desc",
itemsPerPage: initialRowsPerPage,
page: 1,
@ -449,17 +455,26 @@ function findMyReceiver(message) {
return receivers.find(({ receiver }) => receiver["@id"] === securityStore.user["@id"])
}
function extractUserId(apiId) {
return apiId.split('/').pop()
}
async function deleteMessage(message) {
try {
const userId = extractUserId(securityStore.user["@id"])
const messageId = extractUserId(message["@id"])
if (message.sender["@id"] === securityStore.user["@id"]) {
message.status = MESSAGE_STATUS_DELETED
await store.dispatch("message/update", message)
await messageService.deleteMessageForUser(messageId, userId)
} else {
const myReceiver = findMyReceiver(message)
if (myReceiver) {
await store.dispatch("messagereluser/del", myReceiver)
}
}
await messageService.checkAndUpdateMessageStatus(messageId)
notification.showSuccessNotification(t("Message deleted"))
await messageRelUserStore.findUnreadCount()
loadMessages()

@ -105,7 +105,7 @@ final class MessageExtension implements QueryCollectionExtensionInterface // , Q
$qb->setParameters([
'current' => $user,
'deleted' => Message::MESSAGE_STATUS_DELETED,
'deleted' => Message::MESSAGE_STATUS_SENDER_DELETED,
// 'currentList' => [$user->getId()],
'inbox' => Message::MESSAGE_TYPE_INBOX,
// 'outbox' => Message::MESSAGE_TYPE_OUTBOX,

@ -14,6 +14,7 @@ use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Put;
use Chamilo\CoreBundle\Filter\SearchOrFilter;
@ -51,6 +52,20 @@ use Symfony\Component\Validator\Constraints as Assert;
provider: MessageByGroupStateProvider::class
),
new Post(securityPostDenormalize: "is_granted('CREATE', object)"),
new Patch(
uriTemplate: '/messages/{id}/delete-for-user',
inputFormats: ['json' => ['application/json']],
security: "is_granted('ROLE_USER')",
output: false,
processor: MessageProcessor::class,
),
new Patch(
uriTemplate: '/messages/{id}/check-and-update-status',
inputFormats: ['json' => ['application/json']],
security: "is_granted('ROLE_USER')",
output: false,
processor: MessageProcessor::class,
),
],
normalizationContext: [
'groups' => ['message:read'],
@ -62,17 +77,15 @@ use Symfony\Component\Validator\Constraints as Assert;
processor: MessageProcessor::class,
)]
#[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(SearchFilter::class, properties: [
'msgType' => 'exact',
'status' => 'exact',
'sender' => 'exact',
'receivers.receiver' => 'exact',
'receivers.receiverType' => 'exact',
'receivers.tags.tag' => 'exact',
'parent' => 'exact',
])]
#[ApiFilter(
BooleanFilter::class,
properties: ['receivers.read']
@ -85,7 +98,7 @@ class Message
public const MESSAGE_TYPE_INVITATION = 6;
public const MESSAGE_TYPE_CONVERSATION = 7;
// status
public const MESSAGE_STATUS_DELETED = 3;
public const MESSAGE_STATUS_SENDER_DELETED = 3;
public const MESSAGE_STATUS_DRAFT = 4;
public const MESSAGE_STATUS_INVITATION_PENDING = 5;
public const MESSAGE_STATUS_INVITATION_ACCEPTED = 6;

@ -46,6 +46,7 @@ class MessageRelUser
{
public const TYPE_TO = 1;
public const TYPE_CC = 2;
public const TYPE_SENDER = 8;
#[Groups(['message_rel_user:read'])]
#[ORM\Column(name: 'id', type: 'integer')]

@ -66,7 +66,7 @@ final class Version20200821224244 extends AbstractMigrationChamilo
$newTypeQueries[] = sprintf(
'UPDATE message SET status = %d WHERE msg_type = %d',
Message::MESSAGE_STATUS_DELETED,
Message::MESSAGE_STATUS_SENDER_DELETED,
self::OLD_MESSAGE_STATUS_DELETED
);
$newTypeQueries[] = sprintf(

@ -79,7 +79,7 @@ class MessageRepository extends ServiceEntityRepository
$qb->where('m.group = :groupId')
->andWhere('m.status NOT IN (:excludedStatuses)')
->setParameter('groupId', $groupId)
->setParameter('excludedStatuses', [Message::MESSAGE_STATUS_DRAFT, Message::MESSAGE_STATUS_DELETED])
->setParameter('excludedStatuses', [Message::MESSAGE_STATUS_DRAFT, Message::MESSAGE_STATUS_SENDER_DELETED])
->orderBy('m.id', 'ASC')
;
@ -304,7 +304,7 @@ class MessageRepository extends ServiceEntityRepository
/** @var Message $message */
foreach ($messages as $message) {
$message->setMsgType(Message::MESSAGE_STATUS_DELETED);
$message->setMsgType(Message::MESSAGE_STATUS_SENDER_DELETED);
$entityManager->persist($message);
}

@ -8,6 +8,7 @@ namespace Chamilo\CoreBundle\State;
use ApiPlatform\Metadata\DeleteOperationInterface;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post;
use ApiPlatform\State\ProcessorInterface;
use Chamilo\CoreBundle\Entity\Message;
@ -16,6 +17,8 @@ use Chamilo\CoreBundle\Entity\MessageRelUser;
use Chamilo\CoreBundle\Repository\ResourceNodeRepository;
use Doctrine\ORM\EntityManagerInterface;
use Notification;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\HttpFoundation\RequestStack;
use Vich\UploaderBundle\Storage\FlysystemStorage;
final class MessageProcessor implements ProcessorInterface
@ -26,6 +29,8 @@ final class MessageProcessor implements ProcessorInterface
private readonly FlysystemStorage $storage,
private readonly EntityManagerInterface $entityManager,
private readonly ResourceNodeRepository $resourceNodeRepository,
private readonly Security $security,
private readonly RequestStack $requestStack
) {}
public function process($data, Operation $operation, array $uriVariables = [], array $context = [])
@ -34,6 +39,14 @@ final class MessageProcessor implements ProcessorInterface
return $this->removeProcessor->process($data, $operation, $uriVariables, $context);
}
if ($operation instanceof Patch && str_contains($operation->getUriTemplate(), 'delete-for-user')) {
return $this->processDeleteForUser($data);
}
if ($operation instanceof Patch && str_contains($operation->getUriTemplate(), 'check-and-update-status')) {
return $this->checkAndUpdateMessageStatus($data);
}
/** @var Message $message */
$message = $this->persistProcessor->process($data, $operation, $uriVariables, $context);
@ -47,12 +60,66 @@ final class MessageProcessor implements ProcessorInterface
}
}
$user = $this->security->getUser();
if (!$user) {
throw new \LogicException('User not found.');
}
$messageRelUser = new MessageRelUser();
$messageRelUser->setMessage($message);
$messageRelUser->setReceiver($user);
$messageRelUser->setReceiverType(MessageRelUser::TYPE_SENDER);
$this->entityManager->persist($messageRelUser);
if ($message->getMsgType() === Message::MESSAGE_TYPE_INBOX) {
$this->saveNotificationForInboxMessage($message);
}
$this->entityManager->flush();
if ($operation instanceof Post) {
if (Message::MESSAGE_TYPE_INBOX === $message->getMsgType()) {
$this->saveNotificationForInboxMessage($message);
}
return $message;
}
private function processDeleteForUser($data): Message
{
/** @var Message $message */
$message = $data;
$request = $this->requestStack->getCurrentRequest();
if (!$request) {
throw new \LogicException('Cannot get current request');
}
$requestData = json_decode($request->getContent(), true);
if (!isset($requestData['userId'])) {
throw new \InvalidArgumentException('The field userId is required.');
}
$userId = $requestData['userId'];
$messageRelUserRepository = $this->entityManager->getRepository(MessageRelUser::class);
$messageRelUser = $messageRelUserRepository->findOneBy([
'message' => $message,
'receiver' => $userId,
]);
if ($messageRelUser) {
$this->entityManager->remove($messageRelUser);
$this->entityManager->flush();
}
return $message;
}
private function checkAndUpdateMessageStatus($data): Message
{
/** @var Message $message */
$message = $data;
$messageRelUserRepository = $this->entityManager->getRepository(MessageRelUser::class);
$remainingReceivers = $messageRelUserRepository->count(['message' => $message]);
if ($remainingReceivers === 0) {
$message->setStatus(Message::MESSAGE_STATUS_SENDER_DELETED);
$this->entityManager->flush();
}
return $message;

Loading…
Cancel
Save