mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
294 lines
10 KiB
PHP
294 lines
10 KiB
PHP
<?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\RemoteCalendar\Connector;
|
|
|
|
use Chill\CalendarBundle\Entity\CalendarRange;
|
|
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\MachineHttpClient;
|
|
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\MapCalendarToUser;
|
|
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\OnBehalfOfUserHttpClient;
|
|
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\OnBehalfOfUserTokenStorage;
|
|
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\RemoteEventConverter;
|
|
use Chill\MainBundle\Entity\User;
|
|
use DateTimeImmutable;
|
|
use Psr\Log\LoggerInterface;
|
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
|
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
|
|
|
class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
|
{
|
|
private LoggerInterface $logger;
|
|
|
|
private MachineHttpClient $machineHttpClient;
|
|
|
|
private MapCalendarToUser $mapCalendarToUser;
|
|
|
|
private RemoteEventConverter $remoteEventConverter;
|
|
|
|
private OnBehalfOfUserTokenStorage $tokenStorage;
|
|
|
|
private UrlGeneratorInterface $urlGenerator;
|
|
|
|
private OnBehalfOfUserHttpClient $userHttpClient;
|
|
|
|
public function __construct(
|
|
MachineHttpClient $machineHttpClient,
|
|
MapCalendarToUser $mapCalendarToUser,
|
|
LoggerInterface $logger,
|
|
OnBehalfOfUserTokenStorage $tokenStorage,
|
|
OnBehalfOfUserHttpClient $userHttpClient,
|
|
RemoteEventConverter $remoteEventConverter,
|
|
UrlGeneratorInterface $urlGenerator
|
|
) {
|
|
$this->machineHttpClient = $machineHttpClient;
|
|
$this->mapCalendarToUser = $mapCalendarToUser;
|
|
$this->logger = $logger;
|
|
$this->remoteEventConverter = $remoteEventConverter;
|
|
$this->tokenStorage = $tokenStorage;
|
|
$this->urlGenerator = $urlGenerator;
|
|
$this->userHttpClient = $userHttpClient;
|
|
}
|
|
|
|
public function getMakeReadyResponse(string $returnPath): Response
|
|
{
|
|
return new RedirectResponse($this->urlGenerator
|
|
->generate('chill_calendar_remote_connect_azure', ['returnPath' => $returnPath]));
|
|
}
|
|
|
|
public function isReady(): bool
|
|
{
|
|
return $this->tokenStorage->hasToken();
|
|
}
|
|
|
|
public function listEventsForUser(User $user, DateTimeImmutable $startDate, DateTimeImmutable $endDate): array
|
|
{
|
|
$userId = $this->mapCalendarToUser->getUserId($user);
|
|
|
|
if (null === $userId) {
|
|
return [];
|
|
}
|
|
|
|
try {
|
|
$bareEvents = $this->userHttpClient->request(
|
|
'GET',
|
|
'users/' . $userId . '/calendarView',
|
|
[
|
|
'query' => [
|
|
'startDateTime' => $startDate->format(DateTimeImmutable::ATOM),
|
|
'endDateTime' => $endDate->format(DateTimeImmutable::ATOM),
|
|
'$select' => 'id,subject,start,end',
|
|
],
|
|
]
|
|
)->toArray();
|
|
|
|
return array_map(function ($item) { return $this->remoteEventConverter->convertToRemote($item); }, $bareEvents['value']);
|
|
} catch (ClientExceptionInterface $e) {
|
|
if (403 === $e->getResponse()->getStatusCode()) {
|
|
return $this->getScheduleTimesForUser($user, $startDate, $endDate);
|
|
}
|
|
|
|
$this->logger->debug('Could not get list of event on MSGraph', [
|
|
'error_code' => $e->getResponse()->getStatusCode(),
|
|
'error' => $e->getResponse()->getInfo(),
|
|
]);
|
|
|
|
return [];
|
|
}
|
|
}
|
|
|
|
public function removeCalendarRange(string $remoteId, array $remoteAttributes, User $user): void
|
|
{
|
|
if ('' === $remoteId) {
|
|
return;
|
|
}
|
|
|
|
$this->removeEvent($remoteId, $user);
|
|
}
|
|
|
|
public function syncCalendarRange(CalendarRange $calendarRange): void
|
|
{
|
|
if ($calendarRange->hasRemoteId()) {
|
|
$this->updateRemoteCalendarRange($calendarRange);
|
|
} else {
|
|
$this->createRemoteCalendarRange($calendarRange);
|
|
}
|
|
}
|
|
|
|
private function createRemoteCalendarRange(CalendarRange $calendarRange): void
|
|
{
|
|
$userId = $this->mapCalendarToUser->getUserId($calendarRange->getUser());
|
|
$calendarId = $this->mapCalendarToUser->getCalendarId($calendarRange->getUser());
|
|
|
|
if (null === $userId || null === $calendarId) {
|
|
$this->logger->warning('user does not have userId nor calendarId', [
|
|
'user_id' => $calendarRange->getUser()->getId(),
|
|
'calendar_range_id' => $calendarRange->getId(),
|
|
]);
|
|
|
|
return;
|
|
}
|
|
|
|
$eventData = $this->remoteEventConverter->calendarRangeToEvent($calendarRange);
|
|
|
|
try {
|
|
$event = $this->machineHttpClient->request(
|
|
'POST',
|
|
'users/' . $userId . '/calendar/events',
|
|
[
|
|
'json' => $eventData,
|
|
]
|
|
)->toArray();
|
|
} catch (ClientExceptionInterface $e) {
|
|
$this->logger->warning('could not save calendar range to remote', [
|
|
'exception' => $e->getTraceAsString(),
|
|
'calendarRangeId' => $calendarRange->getId(),
|
|
]);
|
|
|
|
throw $e;
|
|
}
|
|
|
|
$calendarRange->setRemoteId($event['id'])
|
|
->addRemoteAttributes([
|
|
'lastModifiedDateTime' => $this->remoteEventConverter->getLastModifiedDate($event)->getTimestamp(),
|
|
'changeKey' => $event['changeKey'],
|
|
]);
|
|
}
|
|
|
|
private function getScheduleTimesForUser(User $user, DateTimeImmutable $startDate, DateTimeImmutable $endDate): array
|
|
{
|
|
$userId = $this->mapCalendarToUser->getUserId($user);
|
|
|
|
if (null === $userId) {
|
|
return [];
|
|
}
|
|
|
|
if (null === $user->getEmailCanonical() || '' === $user->getEmailCanonical()) {
|
|
return [];
|
|
}
|
|
|
|
$body = [
|
|
'schedules' => [$user->getEmailCanonical()],
|
|
'startTime' => [
|
|
'dateTime' => ($startDate->setTimezone(RemoteEventConverter::getRemoteTimeZone())->format(RemoteEventConverter::getRemoteDateTimeSimpleFormat())),
|
|
'timeZone' => 'UTC',
|
|
],
|
|
'endTime' => [
|
|
'dateTime' => ($endDate->setTimezone(RemoteEventConverter::getRemoteTimeZone())->format(RemoteEventConverter::getRemoteDateTimeSimpleFormat())),
|
|
'timeZone' => 'UTC',
|
|
],
|
|
];
|
|
|
|
try {
|
|
$response = $this->userHttpClient->request('POST', 'users/' . $userId . '/calendar/getSchedule', [
|
|
'json' => $body,
|
|
])->toArray();
|
|
} catch (ClientExceptionInterface $e) {
|
|
$this->logger->debug('Could not get schedule on MSGraph', [
|
|
'error_code' => $e->getResponse()->getStatusCode(),
|
|
'error' => $e->getResponse()->getInfo(),
|
|
]);
|
|
|
|
return [];
|
|
}
|
|
|
|
return array_map(
|
|
function ($item) {
|
|
return $this->remoteEventConverter->convertAvailabilityToRemoteEvent($item);
|
|
},
|
|
$response['value'][0]['scheduleItems']
|
|
);
|
|
}
|
|
|
|
private function removeEvent($remoteId, User $user): void
|
|
{
|
|
$userId = $this->mapCalendarToUser->getUserId($user);
|
|
|
|
try {
|
|
$this->machineHttpClient->request(
|
|
'DELETE',
|
|
'users/' . $userId . '/calendar/events/' . $remoteId
|
|
);
|
|
} catch (ClientExceptionInterface $e) {
|
|
$this->logger->warning('could not remove event from calendar', [
|
|
'event_remote_id' => $remoteId,
|
|
'user_id' => $user->getId(),
|
|
]);
|
|
}
|
|
}
|
|
|
|
private function updateRemoteCalendarRange(CalendarRange $calendarRange): void
|
|
{
|
|
$userId = $this->mapCalendarToUser->getUserId($calendarRange->getUser());
|
|
$calendarId = $this->mapCalendarToUser->getCalendarId($calendarRange->getUser());
|
|
|
|
if (null === $userId || null === $calendarId) {
|
|
$this->logger->warning('user does not have userId nor calendarId', [
|
|
'user_id' => $calendarRange->getUser()->getId(),
|
|
'calendar_range_id' => $calendarRange->getId(),
|
|
]);
|
|
|
|
return;
|
|
}
|
|
|
|
try {
|
|
$event = $this->machineHttpClient->request(
|
|
'GET',
|
|
'users/' . $userId . '/calendar/events/' . $calendarRange->getRemoteId()
|
|
)->toArray();
|
|
} catch (ClientExceptionInterface $e) {
|
|
$this->logger->warning('Could not get event from calendar', [
|
|
'calendar_range_id' => $calendarRange->getId(),
|
|
'calendar_range_remote_id' => $calendarRange->getRemoteId(),
|
|
]);
|
|
|
|
throw $e;
|
|
}
|
|
|
|
if ($this->remoteEventConverter->getLastModifiedDate($event)->getTimestamp() > $calendarRange->getUpdatedAt()->getTimestamp()) {
|
|
$this->logger->info('Skip updating as the lastModified date seems more fresh than the database one', [
|
|
'calendar_range_id' => $calendarRange->getId(),
|
|
'calendar_range_remote_id' => $calendarRange->getRemoteId(),
|
|
'db_last_updated' => $calendarRange->getUpdatedAt()->getTimestamp(),
|
|
'remote_last_updated' => $this->remoteEventConverter->getLastModifiedDate($event)->getTimestamp(),
|
|
]);
|
|
|
|
return;
|
|
}
|
|
|
|
$eventData = $this->remoteEventConverter->calendarRangeToEvent($calendarRange);
|
|
|
|
try {
|
|
$event = $this->machineHttpClient->request(
|
|
'PATCH',
|
|
'users/' . $userId . '/calendar/events/' . $calendarRange->getRemoteId(),
|
|
[
|
|
'json' => $eventData,
|
|
]
|
|
)->toArray();
|
|
} catch (ClientExceptionInterface $e) {
|
|
$this->logger->warning('could not update calendar range to remote', [
|
|
'exception' => $e->getTraceAsString(),
|
|
'calendarRangeId' => $calendarRange->getId(),
|
|
]);
|
|
|
|
throw $e;
|
|
}
|
|
|
|
$calendarRange
|
|
->addRemoteAttributes([
|
|
'lastModifiedDateTime' => $this->remoteEventConverter->getLastModifiedDate($event)->getTimestamp(),
|
|
'changeKey' => $event['changeKey'],
|
|
]);
|
|
}
|
|
}
|