mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
190 lines
5.9 KiB
PHP
190 lines
5.9 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);
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
|
|
namespace Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\RemoteToLocalSync;
|
|
|
|
use Chill\CalendarBundle\Entity\Calendar;
|
|
use Chill\CalendarBundle\Entity\Invite;
|
|
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\RemoteEventConverter;
|
|
use Chill\MainBundle\Entity\User;
|
|
use Chill\MainBundle\Repository\UserRepositoryInterface;
|
|
use LogicException;
|
|
use Psr\Log\LoggerInterface;
|
|
use RuntimeException;
|
|
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
|
use function in_array;
|
|
|
|
class CalendarSyncer
|
|
{
|
|
private LoggerInterface $logger;
|
|
|
|
private HttpClientInterface $machineHttpClient;
|
|
|
|
private UserRepositoryInterface $userRepository;
|
|
|
|
public function __construct(LoggerInterface $logger, HttpClientInterface $machineHttpClient, UserRepositoryInterface $userRepository)
|
|
{
|
|
$this->logger = $logger;
|
|
$this->machineHttpClient = $machineHttpClient;
|
|
$this->userRepository = $userRepository;
|
|
}
|
|
|
|
public function handleCalendarSync(Calendar $calendar, array $notification, User $user): void
|
|
{
|
|
switch ($notification['changeType']) {
|
|
case 'deleted':
|
|
$this->handleDeleteCalendar($calendar, $notification, $user);
|
|
|
|
break;
|
|
|
|
case 'updated':
|
|
$this->handleUpdateCalendar($calendar, $notification, $user);
|
|
|
|
break;
|
|
|
|
default:
|
|
throw new RuntimeException('this change type is not supported: ' . $notification['changeType']);
|
|
}
|
|
}
|
|
|
|
private function handleDeleteCalendar(Calendar $calendar, array $notification, User $user): void
|
|
{
|
|
$calendar
|
|
->setStatus(Calendar::STATUS_CANCELED)
|
|
->setCalendarRange(null);
|
|
$calendar->preventEnqueueChanges = true;
|
|
}
|
|
|
|
private function handleUpdateCalendar(Calendar $calendar, array $notification, User $user): void
|
|
{
|
|
try {
|
|
$new = $this->machineHttpClient->request(
|
|
'GET',
|
|
$notification['resource']
|
|
)->toArray();
|
|
} catch (ClientExceptionInterface $clientException) {
|
|
$this->logger->warning(__CLASS__ . ' could not retrieve event from ms graph. Already deleted ?', [
|
|
'calendarId' => $calendar->getId(),
|
|
'remoteEventId' => $notification['resource'],
|
|
]);
|
|
|
|
throw $clientException;
|
|
}
|
|
|
|
if (false === $new['isOrganizer']) {
|
|
return;
|
|
}
|
|
|
|
$lastModified = RemoteEventConverter::convertStringDateWithTimezone(
|
|
$new['lastModifiedDateTime']
|
|
);
|
|
|
|
if ($calendar->getRemoteAttributes()['lastModifiedDateTime'] === $lastModified->getTimestamp()) {
|
|
$this->logger->info(__CLASS__ . ' change key is equals. Source is probably a local update', [
|
|
'calendarRangeId' => $calendar->getId(),
|
|
'remoteEventId' => $notification['resource'],
|
|
]);
|
|
|
|
return;
|
|
}
|
|
|
|
$this->syncAttendees($calendar, $new['attendees']);
|
|
|
|
$startDate = RemoteEventConverter::convertStringDateWithoutTimezone($new['start']['dateTime']);
|
|
$endDate = RemoteEventConverter::convertStringDateWithoutTimezone($new['end']['dateTime']);
|
|
|
|
if ($startDate->getTimestamp() !== $calendar->getStartDate()->getTimestamp()) {
|
|
$calendar->setStartDate($startDate);
|
|
}
|
|
|
|
if ($endDate->getTimestamp() !== $calendar->getEndDate()->getTimestamp()) {
|
|
$calendar->setEndDate($endDate);
|
|
}
|
|
|
|
$calendar
|
|
->addRemoteAttributes([
|
|
'lastModifiedDateTime' => $lastModified->getTimestamp(),
|
|
'changeKey' => $new['changeKey'],
|
|
])
|
|
->preventEnqueueChanges = true;
|
|
}
|
|
|
|
private function syncAttendees(Calendar $calendar, array $attendees): void
|
|
{
|
|
$emails = [];
|
|
|
|
foreach ($attendees as $attendee) {
|
|
$status = $attendee['status']['response'];
|
|
|
|
if ('organizer' === $status) {
|
|
continue;
|
|
}
|
|
|
|
$email = $attendee['emailAddress']['address'];
|
|
$emails[] = strtolower($email);
|
|
$user = $this->userRepository->findOneByUsernameOrEmail($email);
|
|
|
|
if (null === $user) {
|
|
continue;
|
|
}
|
|
|
|
if (!$calendar->isInvited($user)) {
|
|
$calendar->addUser($user);
|
|
}
|
|
|
|
$invite = $calendar->getInviteForUser($user);
|
|
|
|
switch ($status) {
|
|
// possible cases: none, organizer, tentativelyAccepted, accepted, declined, notResponded.
|
|
case 'none':
|
|
case 'notResponded':
|
|
$invite->setStatus(Invite::PENDING);
|
|
|
|
break;
|
|
|
|
case 'tentativelyAccepted':
|
|
$invite->setStatus(Invite::TENTATIVELY_ACCEPTED);
|
|
|
|
break;
|
|
|
|
case 'accepted':
|
|
$invite->setStatus(Invite::ACCEPTED);
|
|
|
|
break;
|
|
|
|
case 'declined':
|
|
$invite->setStatus(Invite::DECLINED);
|
|
|
|
break;
|
|
|
|
default:
|
|
throw new LogicException('should not happens, not implemented: ' . $status);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
foreach ($calendar->getUsers() as $user) {
|
|
if (!in_array(strtolower($user->getEmailCanonical()), $emails, true)) {
|
|
$calendar->removeUser($user);
|
|
}
|
|
}
|
|
}
|
|
}
|