mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
handling sync for calendar invite
This commit is contained in:
parent
c329862e96
commit
e75b258e44
@ -13,6 +13,7 @@ namespace Chill\CalendarBundle\Controller;
|
|||||||
|
|
||||||
use Chill\CalendarBundle\Entity\Calendar;
|
use Chill\CalendarBundle\Entity\Calendar;
|
||||||
use Chill\CalendarBundle\Entity\Invite;
|
use Chill\CalendarBundle\Entity\Invite;
|
||||||
|
use Chill\CalendarBundle\Messenger\Message\InviteUpdateMessage;
|
||||||
use Chill\CalendarBundle\Security\Voter\InviteVoter;
|
use Chill\CalendarBundle\Security\Voter\InviteVoter;
|
||||||
use Chill\MainBundle\Entity\User;
|
use Chill\MainBundle\Entity\User;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
@ -20,6 +21,7 @@ use Symfony\Component\HttpFoundation\JsonResponse;
|
|||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||||
|
use Symfony\Component\Messenger\MessageBusInterface;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
use Symfony\Component\Security\Core\Security;
|
use Symfony\Component\Security\Core\Security;
|
||||||
use function in_array;
|
use function in_array;
|
||||||
@ -28,12 +30,15 @@ class InviteApiController
|
|||||||
{
|
{
|
||||||
private EntityManagerInterface $entityManager;
|
private EntityManagerInterface $entityManager;
|
||||||
|
|
||||||
|
private MessageBusInterface $messageBus;
|
||||||
|
|
||||||
private Security $security;
|
private Security $security;
|
||||||
|
|
||||||
public function __construct(Security $security, EntityManagerInterface $entityManager)
|
public function __construct(EntityManagerInterface $entityManager, MessageBusInterface $messageBus, Security $security)
|
||||||
{
|
{
|
||||||
$this->security = $security;
|
|
||||||
$this->entityManager = $entityManager;
|
$this->entityManager = $entityManager;
|
||||||
|
$this->messageBus = $messageBus;
|
||||||
|
$this->security = $security;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -64,6 +69,8 @@ class InviteApiController
|
|||||||
$invite->setStatus($answer);
|
$invite->setStatus($answer);
|
||||||
$this->entityManager->flush();
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
$this->messageBus->dispatch(new InviteUpdateMessage($invite, $this->security->getUser()));
|
||||||
|
|
||||||
return new JsonResponse(null, Response::HTTP_ACCEPTED, [], false);
|
return new JsonResponse(null, Response::HTTP_ACCEPTED, [], false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,11 +21,20 @@ use LogicException;
|
|||||||
use Symfony\Component\Serializer\Annotation as Serializer;
|
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Table(name="chill_calendar.invite")
|
* An invitation for another user to a Calendar.
|
||||||
|
*
|
||||||
|
* The event/calendar in the user may have a different id than the mainUser. We add then fields to store the
|
||||||
|
* remote id of this event in the remote calendar.
|
||||||
|
*
|
||||||
|
* @ORM\Table(name="chill_calendar.invite", indexes={
|
||||||
|
* @ORM\Index(name="idx_calendar_invite_remote", columns={"remoteId"})
|
||||||
|
* })
|
||||||
* @ORM\Entity
|
* @ORM\Entity
|
||||||
*/
|
*/
|
||||||
class Invite implements TrackUpdateInterface, TrackCreationInterface
|
class Invite implements TrackUpdateInterface, TrackCreationInterface
|
||||||
{
|
{
|
||||||
|
use RemoteCalendarTrait;
|
||||||
|
|
||||||
use TrackCreationTrait;
|
use TrackCreationTrait;
|
||||||
|
|
||||||
use TrackUpdateTrait;
|
use TrackUpdateTrait;
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Chill\CalendarBundle\Messenger\Handler;
|
||||||
|
|
||||||
|
use Chill\CalendarBundle\Messenger\Message\InviteUpdateMessage;
|
||||||
|
use Chill\CalendarBundle\RemoteCalendar\Connector\RemoteCalendarConnectorInterface;
|
||||||
|
use Chill\CalendarBundle\Repository\InviteRepository;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @AsMessageHandler
|
||||||
|
*/
|
||||||
|
class InviteUpdateHandler implements MessageHandlerInterface
|
||||||
|
{
|
||||||
|
private EntityManagerInterface $em;
|
||||||
|
|
||||||
|
private InviteRepository $inviteRepository;
|
||||||
|
|
||||||
|
private RemoteCalendarConnectorInterface $remoteCalendarConnector;
|
||||||
|
|
||||||
|
public function __construct(EntityManagerInterface $em, InviteRepository $inviteRepository, RemoteCalendarConnectorInterface $remoteCalendarConnector)
|
||||||
|
{
|
||||||
|
$this->em = $em;
|
||||||
|
$this->inviteRepository = $inviteRepository;
|
||||||
|
$this->remoteCalendarConnector = $remoteCalendarConnector;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __invoke(InviteUpdateMessage $inviteUpdateMessage): void
|
||||||
|
{
|
||||||
|
if (null === $invite = $this->inviteRepository->find($inviteUpdateMessage->getInviteId())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->remoteCalendarConnector->syncInvite($invite);
|
||||||
|
|
||||||
|
$this->em->flush();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Chill\CalendarBundle\Messenger\Message;
|
||||||
|
|
||||||
|
use Chill\CalendarBundle\Entity\Invite;
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
|
||||||
|
class InviteUpdateMessage
|
||||||
|
{
|
||||||
|
private int $byUserId;
|
||||||
|
|
||||||
|
private int $inviteId;
|
||||||
|
|
||||||
|
public function __construct(Invite $invite, User $byUser)
|
||||||
|
{
|
||||||
|
$this->inviteId = $invite->getId();
|
||||||
|
$this->byUserId = $byUser->getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getByUserId(): int
|
||||||
|
{
|
||||||
|
return $this->byUserId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInviteId(): int
|
||||||
|
{
|
||||||
|
return $this->inviteId;
|
||||||
|
}
|
||||||
|
}
|
@ -112,6 +112,7 @@ class RemoteEventConverter
|
|||||||
['calendar' => $calendar]
|
['calendar' => $calendar]
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
'responseRequested' => true,
|
||||||
],
|
],
|
||||||
$this->calendarToEventAttendeesOnly($calendar)
|
$this->calendarToEventAttendeesOnly($calendar)
|
||||||
);
|
);
|
||||||
|
@ -13,6 +13,7 @@ namespace Chill\CalendarBundle\RemoteCalendar\Connector;
|
|||||||
|
|
||||||
use Chill\CalendarBundle\Entity\Calendar;
|
use Chill\CalendarBundle\Entity\Calendar;
|
||||||
use Chill\CalendarBundle\Entity\CalendarRange;
|
use Chill\CalendarBundle\Entity\CalendarRange;
|
||||||
|
use Chill\CalendarBundle\Entity\Invite;
|
||||||
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\MachineHttpClient;
|
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\MachineHttpClient;
|
||||||
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\MapCalendarToUser;
|
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\MapCalendarToUser;
|
||||||
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\OnBehalfOfUserHttpClient;
|
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\OnBehalfOfUserHttpClient;
|
||||||
@ -209,6 +210,67 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function syncInvite(Invite $invite): void
|
||||||
|
{
|
||||||
|
if ('' === $remoteId = $invite->getCalendar()->getRemoteId()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $invite->getUser()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $userId = $this->mapCalendarToUser->getUserId($invite->getUser())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($invite->hasRemoteId()) {
|
||||||
|
$remoteIdAttendeeCalendar = $invite->getRemoteId();
|
||||||
|
} else {
|
||||||
|
$remoteIdAttendeeCalendar = $this->findRemoteIdOnUserCalendar($invite->getCalendar(), $invite->getUser());
|
||||||
|
$invite->setRemoteId($remoteIdAttendeeCalendar);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($invite->getStatus()) {
|
||||||
|
case Invite::PENDING:
|
||||||
|
return;
|
||||||
|
|
||||||
|
case Invite::ACCEPTED:
|
||||||
|
$url = "/v1.0/users/{$userId}/calendar/events/{$remoteIdAttendeeCalendar}/accept";
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Invite::TENTATIVELY_ACCEPTED:
|
||||||
|
$url = "/v1.0/users/{$userId}/calendar/events/{$remoteIdAttendeeCalendar}/tentativelyAccept";
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Invite::DECLINED:
|
||||||
|
$url = "/v1.0/users/{$userId}/calendar/events/{$remoteIdAttendeeCalendar}/decline";
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Exception('not supported');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->machineHttpClient->request(
|
||||||
|
'POST',
|
||||||
|
$url,
|
||||||
|
['json' => ['sendResponse' => true]]
|
||||||
|
);
|
||||||
|
} catch (ClientExceptionInterface $e) {
|
||||||
|
$this->logger->warning('could not update calendar range to remote', [
|
||||||
|
'exception' => $e->getTraceAsString(),
|
||||||
|
'content' => $e->getResponse()->getContent(),
|
||||||
|
'calendarRangeId' => 'invite_' . $invite->getId(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function cancelOnRemote(string $remoteId, string $comment, User $user, string $identifier): void
|
private function cancelOnRemote(string $remoteId, string $comment, User $user, string $identifier): void
|
||||||
{
|
{
|
||||||
$userId = $this->mapCalendarToUser->getUserId($user);
|
$userId = $this->mapCalendarToUser->getUserId($user);
|
||||||
@ -333,6 +395,44 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the remoteId is not the same across different user calendars. This method allow to find
|
||||||
|
* the correct remoteId in another calendar.
|
||||||
|
*
|
||||||
|
* For achieving this, the iCalUid is used.
|
||||||
|
*/
|
||||||
|
private function findRemoteIdOnUserCalendar(Calendar $calendar, User $user): ?string
|
||||||
|
{
|
||||||
|
// find the icalUid on original user
|
||||||
|
$event = $this->getOnRemote($calendar->getMainUser(), $calendar->getRemoteId());
|
||||||
|
$userId = $this->mapCalendarToUser->getUserId($user);
|
||||||
|
|
||||||
|
if ('' === $iCalUid = ($event['iCalUId'] ?? '')) {
|
||||||
|
throw new Exception('no iCalUid for this event');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$events = $this->machineHttpClient->request(
|
||||||
|
'GET',
|
||||||
|
"/v1.0/users/{$userId}/calendar/events",
|
||||||
|
[
|
||||||
|
'query' => [
|
||||||
|
'$select' => 'id',
|
||||||
|
'$filter' => "iCalUId eq '{$iCalUid}'",
|
||||||
|
],
|
||||||
|
]
|
||||||
|
)->toArray();
|
||||||
|
} catch (ClientExceptionInterface $clientException) {
|
||||||
|
throw $clientException;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (1 !== count($events['value'])) {
|
||||||
|
throw new Exception('multiple events found with same iCalUid');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $events['value'][0]['id'];
|
||||||
|
}
|
||||||
|
|
||||||
private function getOnRemote(User $user, string $remoteId): array
|
private function getOnRemote(User $user, string $remoteId): array
|
||||||
{
|
{
|
||||||
$userId = $this->mapCalendarToUser->getUserId($user);
|
$userId = $this->mapCalendarToUser->getUserId($user);
|
||||||
@ -345,10 +445,13 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return $this->machineHttpClient->request(
|
$v = $this->machineHttpClient->request(
|
||||||
'GET',
|
'GET',
|
||||||
'users/' . $userId . '/calendar/events/' . $remoteId
|
'users/' . $userId . '/calendar/events/' . $remoteId
|
||||||
)->toArray();
|
)->toArray();
|
||||||
|
dump($v);
|
||||||
|
|
||||||
|
return $v;
|
||||||
} catch (ClientExceptionInterface $e) {
|
} catch (ClientExceptionInterface $e) {
|
||||||
$this->logger->warning('Could not get event from calendar', [
|
$this->logger->warning('Could not get event from calendar', [
|
||||||
'remoteId' => $remoteId,
|
'remoteId' => $remoteId,
|
||||||
|
@ -13,6 +13,7 @@ namespace Chill\CalendarBundle\RemoteCalendar\Connector;
|
|||||||
|
|
||||||
use Chill\CalendarBundle\Entity\Calendar;
|
use Chill\CalendarBundle\Entity\Calendar;
|
||||||
use Chill\CalendarBundle\Entity\CalendarRange;
|
use Chill\CalendarBundle\Entity\CalendarRange;
|
||||||
|
use Chill\CalendarBundle\Entity\Invite;
|
||||||
use Chill\MainBundle\Entity\User;
|
use Chill\MainBundle\Entity\User;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use LogicException;
|
use LogicException;
|
||||||
@ -46,4 +47,8 @@ class NullRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
|||||||
public function syncCalendarRange(CalendarRange $calendarRange): void
|
public function syncCalendarRange(CalendarRange $calendarRange): void
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function syncInvite(Invite $invite): void
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ namespace Chill\CalendarBundle\RemoteCalendar\Connector;
|
|||||||
|
|
||||||
use Chill\CalendarBundle\Entity\Calendar;
|
use Chill\CalendarBundle\Entity\Calendar;
|
||||||
use Chill\CalendarBundle\Entity\CalendarRange;
|
use Chill\CalendarBundle\Entity\CalendarRange;
|
||||||
|
use Chill\CalendarBundle\Entity\Invite;
|
||||||
use Chill\CalendarBundle\RemoteCalendar\Model\RemoteEvent;
|
use Chill\CalendarBundle\RemoteCalendar\Model\RemoteEvent;
|
||||||
use Chill\MainBundle\Entity\User;
|
use Chill\MainBundle\Entity\User;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
@ -46,4 +47,6 @@ interface RemoteCalendarConnectorInterface
|
|||||||
public function syncCalendar(Calendar $calendar, string $action, ?CalendarRange $previousCalendarRange, ?User $previousMainUser, ?array $oldInvites, ?array $newInvites): void;
|
public function syncCalendar(Calendar $calendar, string $action, ?CalendarRange $previousCalendarRange, ?User $previousMainUser, ?array $oldInvites, ?array $newInvites): void;
|
||||||
|
|
||||||
public function syncCalendarRange(CalendarRange $calendarRange): void;
|
public function syncCalendarRange(CalendarRange $calendarRange): void;
|
||||||
|
|
||||||
|
public function syncInvite(Invite $invite): void;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Chill\Migrations\Calendar;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
final class Version20220608084052 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE chill_calendar.invite DROP remoteAttributes');
|
||||||
|
$this->addSql('ALTER TABLE chill_calendar.invite DROP remoteId');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Add remoteId for invitation';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE chill_calendar.invite ADD remoteAttributes JSON DEFAULT \'[]\' NOT NULL');
|
||||||
|
$this->addSql('ALTER TABLE chill_calendar.invite ADD remoteId TEXT DEFAULT \'\' NOT NULL');
|
||||||
|
$this->addSql('CREATE INDEX idx_calendar_invite_remote ON chill_calendar.invite (remoteId)');
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user