mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-12 13:24:25 +00:00
wip: continue sync to remote
This commit is contained in:
parent
782436ee2e
commit
59a64e9a62
@ -35,7 +35,7 @@ class CalendarRange implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
/**
|
/**
|
||||||
* @ORM\OneToOne(targetEntity=Calendar::class, mappedBy="calendarRange")
|
* @ORM\OneToOne(targetEntity=Calendar::class, mappedBy="calendarRange")
|
||||||
*/
|
*/
|
||||||
private Calendar $calendar;
|
private ?Calendar $calendar = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="datetimetz_immutable")
|
* @ORM\Column(type="datetimetz_immutable")
|
||||||
|
@ -11,6 +11,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Chill\CalendarBundle\Messenger\Handler;
|
namespace Chill\CalendarBundle\Messenger\Handler;
|
||||||
|
|
||||||
|
use Chill\CalendarBundle\Entity\CalendarRange;
|
||||||
use Chill\CalendarBundle\Entity\Invite;
|
use Chill\CalendarBundle\Entity\Invite;
|
||||||
use Chill\CalendarBundle\Messenger\Message\CalendarMessage;
|
use Chill\CalendarBundle\Messenger\Message\CalendarMessage;
|
||||||
use Chill\CalendarBundle\RemoteCalendar\Connector\RemoteCalendarConnectorInterface;
|
use Chill\CalendarBundle\RemoteCalendar\Connector\RemoteCalendarConnectorInterface;
|
||||||
@ -62,12 +63,17 @@ class CalendarToRemoteHandler implements MessageHandlerInterface
|
|||||||
if (null !== $calendarMessage->getPreviousCalendarRangeId()) {
|
if (null !== $calendarMessage->getPreviousCalendarRangeId()) {
|
||||||
$previousCalendarRange = $this->calendarRangeRepository
|
$previousCalendarRange = $this->calendarRangeRepository
|
||||||
->find($calendarMessage->getPreviousCalendarRangeId());
|
->find($calendarMessage->getPreviousCalendarRangeId());
|
||||||
|
} else {
|
||||||
|
$previousCalendarRange = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null !== $calendarMessage->getPreviousMainUserId()) {
|
if (null !== $calendarMessage->getPreviousMainUserId()) {
|
||||||
$previousMainUser = $this->userRepository
|
$previousMainUser = $this->userRepository
|
||||||
->find($calendarMessage->getPreviousMainUserId());
|
->find($calendarMessage->getPreviousMainUserId());
|
||||||
|
} else {
|
||||||
|
$previousMainUser = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$newInvites = array_filter(
|
$newInvites = array_filter(
|
||||||
array_map(
|
array_map(
|
||||||
function ($id) { return $this->inviteRepository->find($id); },
|
function ($id) { return $this->inviteRepository->find($id); },
|
||||||
@ -79,13 +85,22 @@ class CalendarToRemoteHandler implements MessageHandlerInterface
|
|||||||
$this->calendarConnector->syncCalendar(
|
$this->calendarConnector->syncCalendar(
|
||||||
$calendar,
|
$calendar,
|
||||||
$calendarMessage->getAction(),
|
$calendarMessage->getAction(),
|
||||||
$previousCalendarRange ?? null,
|
$previousCalendarRange,
|
||||||
$previousMainUser ?? null,
|
$previousMainUser,
|
||||||
$calendarMessage->getOldInvites(),
|
$calendarMessage->getOldInvites(),
|
||||||
$newInvites
|
$newInvites
|
||||||
);
|
);
|
||||||
|
|
||||||
$calendar->preventEnqueueChanges = true;
|
$calendar->preventEnqueueChanges = true;
|
||||||
|
|
||||||
|
if ($calendar->hasCalendarRange()) {
|
||||||
|
$calendar->getCalendarRange()->preventEnqueueChanges = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($previousCalendarRange instanceof CalendarRange) {
|
||||||
|
$previousCalendarRange->preventEnqueueChanges = true;
|
||||||
|
}
|
||||||
|
|
||||||
$this->entityManager->flush();
|
$this->entityManager->flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,9 @@ use Chill\PersonBundle\Entity\Person;
|
|||||||
use Chill\PersonBundle\Templating\Entity\PersonRenderInterface;
|
use Chill\PersonBundle\Templating\Entity\PersonRenderInterface;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use DateTimeZone;
|
use DateTimeZone;
|
||||||
|
use Symfony\Component\Templating\EngineInterface;
|
||||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
use Twig\Environment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert Chill Calendar event to Remote MS Graph event, and MS Graph
|
* Convert Chill Calendar event to Remote MS Graph event, and MS Graph
|
||||||
@ -39,8 +41,11 @@ class RemoteEventConverter
|
|||||||
|
|
||||||
private TranslatorInterface $translator;
|
private TranslatorInterface $translator;
|
||||||
|
|
||||||
public function __construct(PersonRenderInterface $personRender, TranslatorInterface $translator)
|
private EngineInterface $engine;
|
||||||
|
|
||||||
|
public function __construct(EngineInterface $engine, PersonRenderInterface $personRender, TranslatorInterface $translator)
|
||||||
{
|
{
|
||||||
|
$this->engine = $engine;
|
||||||
$this->translator = $translator;
|
$this->translator = $translator;
|
||||||
$this->personRender = $personRender;
|
$this->personRender = $personRender;
|
||||||
$this->defaultDateTimeZone = (new DateTimeImmutable())->getTimezone();
|
$this->defaultDateTimeZone = (new DateTimeImmutable())->getTimezone();
|
||||||
@ -79,38 +84,59 @@ class RemoteEventConverter
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function calendarToEvent(Calendar $calendar): array
|
public function calendarToEvent(Calendar $calendar): array
|
||||||
|
{
|
||||||
|
return array_merge(
|
||||||
|
[
|
||||||
|
'subject' => '[Chill] ' .
|
||||||
|
implode(
|
||||||
|
', ',
|
||||||
|
$calendar->getPersons()->map(function (Person $p) {
|
||||||
|
return $this->personRender->renderString($p, []);
|
||||||
|
})->toArray()
|
||||||
|
),
|
||||||
|
'start' => [
|
||||||
|
'dateTime' => $calendar->getStartDate()->setTimezone($this->remoteDateTimeZone)
|
||||||
|
->format(self::REMOTE_DATE_FORMAT),
|
||||||
|
'timeZone' => 'UTC',
|
||||||
|
],
|
||||||
|
'end' => [
|
||||||
|
'dateTime' => $calendar->getEndDate()->setTimezone($this->remoteDateTimeZone)
|
||||||
|
->format(self::REMOTE_DATE_FORMAT),
|
||||||
|
'timeZone' => 'UTC',
|
||||||
|
],
|
||||||
|
'allowNewTimeProposals' => false,
|
||||||
|
'transactionId' => 'calendar_' . $calendar->getId(),
|
||||||
|
'body' => [
|
||||||
|
'contentType' => 'text',
|
||||||
|
'content' => $this->engine->render(
|
||||||
|
'@ChillCalendar/MSGraph/calendar_event_body.html.twig',
|
||||||
|
['calendar' => $calendar]
|
||||||
|
),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
$this->calendarToEventAttendeesOnly($calendar)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function calendarToEventAttendeesOnly(Calendar $calendar): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'subject' => '[Chill] ' .
|
|
||||||
implode(
|
|
||||||
', ',
|
|
||||||
$calendar->getPersons()->map(function (Person $p) {
|
|
||||||
return $this->personRender->renderString($p, []);
|
|
||||||
})->toArray()
|
|
||||||
),
|
|
||||||
'start' => [
|
|
||||||
'dateTime' => $calendar->getStartDate()->setTimezone($this->remoteDateTimeZone)
|
|
||||||
->format(self::REMOTE_DATE_FORMAT),
|
|
||||||
'timeZone' => 'UTC',
|
|
||||||
],
|
|
||||||
'end' => [
|
|
||||||
'dateTime' => $calendar->getEndDate()->setTimezone($this->remoteDateTimeZone)
|
|
||||||
->format(self::REMOTE_DATE_FORMAT),
|
|
||||||
'timeZone' => 'UTC',
|
|
||||||
],
|
|
||||||
'allowNewTimeProposals' => false,
|
|
||||||
'attendees' => $calendar->getInvites()->map(
|
'attendees' => $calendar->getInvites()->map(
|
||||||
static function (Invite $i) {
|
function (Invite $i) {
|
||||||
return [
|
return $this->buildInviteToAttendee($i);
|
||||||
'emailAddress' => [
|
}
|
||||||
'address' => $i->getUser()->getEmail(),
|
|
||||||
'name' => $i->getUser()->getLabel(),
|
|
||||||
],
|
|
||||||
'type' => 'Required',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
)->toArray(),
|
)->toArray(),
|
||||||
'transactionId' => 'calendar_' . $calendar->getId(),
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildInviteToAttendee(Invite $invite): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'emailAddress' => [
|
||||||
|
'address' => $invite->getUser()->getEmail(),
|
||||||
|
'name' => $invite->getUser()->getLabel(),
|
||||||
|
],
|
||||||
|
'type' => 'Required',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ use Symfony\Component\HttpFoundation\RedirectResponse;
|
|||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||||
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||||
{
|
{
|
||||||
@ -40,6 +41,8 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
|||||||
|
|
||||||
private RemoteEventConverter $remoteEventConverter;
|
private RemoteEventConverter $remoteEventConverter;
|
||||||
|
|
||||||
|
private TranslatorInterface $translator;
|
||||||
|
|
||||||
private OnBehalfOfUserTokenStorage $tokenStorage;
|
private OnBehalfOfUserTokenStorage $tokenStorage;
|
||||||
|
|
||||||
private UrlGeneratorInterface $urlGenerator;
|
private UrlGeneratorInterface $urlGenerator;
|
||||||
@ -54,6 +57,7 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
|||||||
OnBehalfOfUserTokenStorage $tokenStorage,
|
OnBehalfOfUserTokenStorage $tokenStorage,
|
||||||
OnBehalfOfUserHttpClient $userHttpClient,
|
OnBehalfOfUserHttpClient $userHttpClient,
|
||||||
RemoteEventConverter $remoteEventConverter,
|
RemoteEventConverter $remoteEventConverter,
|
||||||
|
TranslatorInterface $translator,
|
||||||
UrlGeneratorInterface $urlGenerator
|
UrlGeneratorInterface $urlGenerator
|
||||||
) {
|
) {
|
||||||
$this->calendarRangeRepository = $calendarRangeRepository;
|
$this->calendarRangeRepository = $calendarRangeRepository;
|
||||||
@ -62,6 +66,7 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
|||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
$this->remoteEventConverter = $remoteEventConverter;
|
$this->remoteEventConverter = $remoteEventConverter;
|
||||||
$this->tokenStorage = $tokenStorage;
|
$this->tokenStorage = $tokenStorage;
|
||||||
|
$this->translator = $translator;
|
||||||
$this->urlGenerator = $urlGenerator;
|
$this->urlGenerator = $urlGenerator;
|
||||||
$this->userHttpClient = $userHttpClient;
|
$this->userHttpClient = $userHttpClient;
|
||||||
}
|
}
|
||||||
@ -162,9 +167,16 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
|||||||
} else {
|
} else {
|
||||||
if (null !== $previousMainUser) {
|
if (null !== $previousMainUser) {
|
||||||
// cancel event in previousMainUserCalendar
|
// cancel event in previousMainUserCalendar
|
||||||
// CREATE event in currentMainUser
|
$this->cancelOnRemote(
|
||||||
|
$calendar->getRemoteId(),
|
||||||
|
$this->translator->trans('remote_ms_graph.cancel_event_because_main_user_is_%label%', ['%label%' => $calendar->getMainUser()]),
|
||||||
|
$previousMainUser,
|
||||||
|
'calendar_'.$calendar->getRemoteId()
|
||||||
|
);
|
||||||
|
$this->createCalendarOnRemote($calendar);
|
||||||
|
} else {
|
||||||
|
$this->patchCalendarOnRemote($calendar, $newInvites);
|
||||||
}
|
}
|
||||||
// PATCH event in currentMainUer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($calendar->hasCalendarRange() && $calendar->getCalendarRange()->hasRemoteId()) {
|
if ($calendar->hasCalendarRange() && $calendar->getCalendarRange()->hasRemoteId()) {
|
||||||
@ -172,10 +184,19 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
|||||||
$calendar->getCalendarRange()->getRemoteId(),
|
$calendar->getCalendarRange()->getRemoteId(),
|
||||||
$calendar->getCalendarRange()->getUser()
|
$calendar->getCalendarRange()->getUser()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$calendar->getCalendarRange()
|
||||||
|
->addRemoteAttributes([
|
||||||
|
'lastModifiedDateTime' => null,
|
||||||
|
'changeKey' => null,
|
||||||
|
'previousId' => $calendar->getCalendarRange()->getRemoteId()
|
||||||
|
])
|
||||||
|
->setRemoteId('')
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null !== $previousCalendarRange) {
|
if (null !== $previousCalendarRange) {
|
||||||
// create previousCalendarRange
|
$this->createRemoteCalendarRange($previousCalendarRange);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,6 +209,34 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function patchCalendarOnRemote(Calendar $calendar, array $newInvites): void
|
||||||
|
{
|
||||||
|
$eventDatas = [];
|
||||||
|
$eventDatas[] = $this->remoteEventConverter->calendarToEvent($calendar);
|
||||||
|
|
||||||
|
if (0 < count($newInvites)) {
|
||||||
|
$eventDatas[] = $this->remoteEventConverter->calendarToEventAttendeesOnly($calendar);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($eventDatas as $eventData) {
|
||||||
|
[
|
||||||
|
'id' => $id,
|
||||||
|
'lastModifiedDateTime' => $lastModified,
|
||||||
|
'changeKey' => $changeKey
|
||||||
|
] = $this->patchOnRemote(
|
||||||
|
$calendar->getRemoteId(),
|
||||||
|
$eventData,
|
||||||
|
$calendar->getMainUser(),
|
||||||
|
'calendar_'.$calendar->getId()
|
||||||
|
);
|
||||||
|
|
||||||
|
$calendar->addRemoteAttributes([
|
||||||
|
'lastModifiedDateTime' => $lastModified,
|
||||||
|
'changeKey' => $changeKey,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function createCalendarOnRemote(Calendar $calendar): void
|
private function createCalendarOnRemote(Calendar $calendar): void
|
||||||
{
|
{
|
||||||
$eventData = $this->remoteEventConverter->calendarToEvent($calendar);
|
$eventData = $this->remoteEventConverter->calendarToEvent($calendar);
|
||||||
@ -227,7 +276,6 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
|||||||
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
dump($eventData);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$event = $this->machineHttpClient->request(
|
$event = $this->machineHttpClient->request(
|
||||||
@ -257,9 +305,8 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
|||||||
private function createRemoteCalendarRange(CalendarRange $calendarRange): void
|
private function createRemoteCalendarRange(CalendarRange $calendarRange): void
|
||||||
{
|
{
|
||||||
$userId = $this->mapCalendarToUser->getUserId($calendarRange->getUser());
|
$userId = $this->mapCalendarToUser->getUserId($calendarRange->getUser());
|
||||||
$calendarId = $this->mapCalendarToUser->getCalendarId($calendarRange->getUser());
|
|
||||||
|
|
||||||
if (null === $userId || null === $calendarId) {
|
if (null === $userId) {
|
||||||
$this->logger->warning('user does not have userId nor calendarId', [
|
$this->logger->warning('user does not have userId nor calendarId', [
|
||||||
'user_id' => $calendarRange->getUser()->getId(),
|
'user_id' => $calendarRange->getUser()->getId(),
|
||||||
'calendar_range_id' => $calendarRange->getId(),
|
'calendar_range_id' => $calendarRange->getId(),
|
||||||
@ -270,27 +317,20 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
|||||||
|
|
||||||
$eventData = $this->remoteEventConverter->calendarRangeToEvent($calendarRange);
|
$eventData = $this->remoteEventConverter->calendarRangeToEvent($calendarRange);
|
||||||
|
|
||||||
try {
|
[
|
||||||
$event = $this->machineHttpClient->request(
|
'id' => $id,
|
||||||
'POST',
|
'lastModifiedDateTime' => $lastModified,
|
||||||
'users/' . $userId . '/calendar/events',
|
'changeKey' => $changeKey
|
||||||
[
|
] = $this->createOnRemote(
|
||||||
'json' => $eventData,
|
$eventData,
|
||||||
]
|
$calendarRange->getUser(),
|
||||||
)->toArray();
|
'calendar_range_' . $calendarRange->getId()
|
||||||
} catch (ClientExceptionInterface $e) {
|
);
|
||||||
$this->logger->warning('could not save calendar range to remote', [
|
|
||||||
'exception' => $e->getTraceAsString(),
|
|
||||||
'calendarRangeId' => $calendarRange->getId(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
throw $e;
|
$calendarRange->setRemoteId($id)
|
||||||
}
|
|
||||||
|
|
||||||
$calendarRange->setRemoteId($event['id'])
|
|
||||||
->addRemoteAttributes([
|
->addRemoteAttributes([
|
||||||
'lastModifiedDateTime' => $this->remoteEventConverter->getLastModifiedDate($event)->getTimestamp(),
|
'lastModifiedDateTime' => $lastModified,
|
||||||
'changeKey' => $event['changeKey'],
|
'changeKey' => $changeKey
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,6 +404,35 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function cancelOnRemote(string $remoteId, string $comment, User $user, string $identifier): void
|
||||||
|
{
|
||||||
|
$userId = $this->mapCalendarToUser->getUserId($user);
|
||||||
|
|
||||||
|
if (null === $userId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->machineHttpClient->request(
|
||||||
|
'POST',
|
||||||
|
"users/{$userId}/calendar/events/{$remoteId}/cancel",
|
||||||
|
[
|
||||||
|
'json' => ['Comment' => $comment]
|
||||||
|
]
|
||||||
|
);
|
||||||
|
} catch (ClientExceptionInterface $e) {
|
||||||
|
$this->logger->warning('could not update calendar range to remote', [
|
||||||
|
'exception' => $e->getTraceAsString(),
|
||||||
|
'content' => $e->getResponse()->getContent(),
|
||||||
|
'calendarRangeId' => $identifier,
|
||||||
|
]);
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $identifier an identifier for logging in case of something does not work
|
* @param string $identifier an identifier for logging in case of something does not work
|
||||||
*
|
*
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
Ce rendez-vous a été généré automatiquement par Chill.
|
||||||
|
|
||||||
|
Pour modifier ou supprimer ce rendez-vous, utilisez l’adresse suivante:
|
||||||
|
|
||||||
|
{{ absolute_url(path('chill_calendar_calendar_edit', {'id': calendar.id, '_locale': 'fr'})) }}
|
||||||
|
|
||||||
|
{{ calendar.comment.comment|nl2br }}
|
||||||
|
|
||||||
|
Usagers et tiers concernés:
|
||||||
|
|
||||||
|
{% for p in calendar.persons %}
|
||||||
|
- {{ p|chill_entity_render_string }}
|
||||||
|
{%- endfor -%}
|
||||||
|
{% for t in calendar.professionals %}
|
||||||
|
- {{ t|chill_entity_render_string }}
|
||||||
|
{% endfor %}
|
@ -40,6 +40,7 @@ remote_ms_graph:
|
|||||||
oof: En dehors du bureau
|
oof: En dehors du bureau
|
||||||
workingElsewhere: Travaille à l'extérieur
|
workingElsewhere: Travaille à l'extérieur
|
||||||
unknown: Inconnu
|
unknown: Inconnu
|
||||||
|
cancel_event_because_main_user_is_%label%: L'événement est transféré à l'utilisateur %label%
|
||||||
|
|
||||||
remote_calendar:
|
remote_calendar:
|
||||||
calendar_range_title: Plage de disponibilité Chill
|
calendar_range_title: Plage de disponibilité Chill
|
||||||
|
Loading…
x
Reference in New Issue
Block a user