mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-12 13:24:25 +00:00
Sync user absence / presence within MapAndSubscribeUserCalendarCommand
This commit is contained in:
parent
2861945a52
commit
77d4b13c1b
@ -18,9 +18,12 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Chill\CalendarBundle\Command;
|
namespace Chill\CalendarBundle\Command;
|
||||||
|
|
||||||
|
use Chill\CalendarBundle\Exception\UserAbsenceSyncException;
|
||||||
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\EventsOnUserSubscriptionCreator;
|
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\EventsOnUserSubscriptionCreator;
|
||||||
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\MapCalendarToUser;
|
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\MapCalendarToUser;
|
||||||
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\MSGraphUserRepository;
|
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\MSGraphUserRepository;
|
||||||
|
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\MSUserAbsenceSync;
|
||||||
|
use Chill\MainBundle\Repository\UserRepositoryInterface;
|
||||||
use DateInterval;
|
use DateInterval;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
@ -30,32 +33,17 @@ use Symfony\Component\Console\Input\InputInterface;
|
|||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
class MapAndSubscribeUserCalendarCommand extends Command
|
final class MapAndSubscribeUserCalendarCommand extends Command
|
||||||
{
|
{
|
||||||
private EntityManagerInterface $em;
|
|
||||||
|
|
||||||
private EventsOnUserSubscriptionCreator $eventsOnUserSubscriptionCreator;
|
|
||||||
|
|
||||||
private LoggerInterface $logger;
|
|
||||||
|
|
||||||
private MapCalendarToUser $mapCalendarToUser;
|
|
||||||
|
|
||||||
private MSGraphUserRepository $userRepository;
|
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
EntityManagerInterface $em,
|
private readonly EntityManagerInterface $em,
|
||||||
EventsOnUserSubscriptionCreator $eventsOnUserSubscriptionCreator,
|
private readonly EventsOnUserSubscriptionCreator $eventsOnUserSubscriptionCreator,
|
||||||
LoggerInterface $logger,
|
private readonly LoggerInterface $logger,
|
||||||
MapCalendarToUser $mapCalendarToUser,
|
private readonly MapCalendarToUser $mapCalendarToUser,
|
||||||
MSGraphUserRepository $userRepository
|
private readonly UserRepositoryInterface $userRepository,
|
||||||
|
private readonly MSUserAbsenceSync $userAbsenceSync,
|
||||||
) {
|
) {
|
||||||
parent::__construct('chill:calendar:msgraph-user-map-subscribe');
|
parent::__construct('chill:calendar:msgraph-user-map-subscribe');
|
||||||
|
|
||||||
$this->em = $em;
|
|
||||||
$this->eventsOnUserSubscriptionCreator = $eventsOnUserSubscriptionCreator;
|
|
||||||
$this->logger = $logger;
|
|
||||||
$this->mapCalendarToUser = $mapCalendarToUser;
|
|
||||||
$this->userRepository = $userRepository;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function execute(InputInterface $input, OutputInterface $output): int
|
public function execute(InputInterface $input, OutputInterface $output): int
|
||||||
@ -67,83 +55,109 @@ class MapAndSubscribeUserCalendarCommand extends Command
|
|||||||
/** @var DateInterval $interval the interval before the end of the expiration */
|
/** @var DateInterval $interval the interval before the end of the expiration */
|
||||||
$interval = new DateInterval('P1D');
|
$interval = new DateInterval('P1D');
|
||||||
$expiration = (new DateTimeImmutable('now'))->add(new DateInterval($input->getOption('subscription-duration')));
|
$expiration = (new DateTimeImmutable('now'))->add(new DateInterval($input->getOption('subscription-duration')));
|
||||||
$total = $this->userRepository->countByMostOldSubscriptionOrWithoutSubscriptionOrData($interval);
|
$users = $this->userRepository->findAllAsArray('fr');
|
||||||
$created = 0;
|
$created = 0;
|
||||||
$renewed = 0;
|
$renewed = 0;
|
||||||
|
|
||||||
$this->logger->info(self::class . ' the number of user to get - renew', [
|
$this->logger->info(self::class . ' start user to get - renew', [
|
||||||
'total' => $total,
|
|
||||||
'expiration' => $expiration->format(DateTimeImmutable::ATOM),
|
'expiration' => $expiration->format(DateTimeImmutable::ATOM),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
while ($offset < $total) {
|
foreach ($users as $u) {
|
||||||
$users = $this->userRepository->findByMostOldSubscriptionOrWithoutSubscriptionOrData(
|
++$offset;
|
||||||
$interval,
|
|
||||||
$limit,
|
|
||||||
$offset
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach ($users as $user) {
|
if (false === $u['enabled']) {
|
||||||
if (!$this->mapCalendarToUser->hasUserId($user)) {
|
continue;
|
||||||
$this->mapCalendarToUser->writeMetadata($user);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->mapCalendarToUser->hasUserId($user)) {
|
|
||||||
// we first try to renew an existing subscription, if any.
|
|
||||||
// if not, or if it fails, we try to create a new one
|
|
||||||
if ($this->mapCalendarToUser->hasActiveSubscription($user)) {
|
|
||||||
$this->logger->debug(self::class . ' renew a subscription for', [
|
|
||||||
'userId' => $user->getId(),
|
|
||||||
'username' => $user->getUsernameCanonical(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
['secret' => $secret, 'id' => $id, 'expiration' => $expirationTs]
|
|
||||||
= $this->eventsOnUserSubscriptionCreator->renewSubscriptionForUser($user, $expiration);
|
|
||||||
$this->mapCalendarToUser->writeSubscriptionMetadata($user, $expirationTs, $id, $secret);
|
|
||||||
|
|
||||||
if (0 !== $expirationTs) {
|
|
||||||
++$renewed;
|
|
||||||
} else {
|
|
||||||
$this->logger->warning(self::class . ' could not renew subscription for a user', [
|
|
||||||
'userId' => $user->getId(),
|
|
||||||
'username' => $user->getUsernameCanonical(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$this->mapCalendarToUser->hasActiveSubscription($user)) {
|
|
||||||
$this->logger->debug(self::class . ' create a subscription for', [
|
|
||||||
'userId' => $user->getId(),
|
|
||||||
'username' => $user->getUsernameCanonical(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
['secret' => $secret, 'id' => $id, 'expiration' => $expirationTs]
|
|
||||||
= $this->eventsOnUserSubscriptionCreator->createSubscriptionForUser($user, $expiration);
|
|
||||||
$this->mapCalendarToUser->writeSubscriptionMetadata($user, $expirationTs, $id, $secret);
|
|
||||||
|
|
||||||
if (0 !== $expirationTs) {
|
|
||||||
++$created;
|
|
||||||
} else {
|
|
||||||
$this->logger->warning(self::class . ' could not create subscription for a user', [
|
|
||||||
'userId' => $user->getId(),
|
|
||||||
'username' => $user->getUsernameCanonical(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
++$offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->em->flush();
|
$user = $this->userRepository->find($u['id']);
|
||||||
$this->em->clear();
|
|
||||||
|
if (null === $user) {
|
||||||
|
$this->logger->error("could not find user by id", ['uid' => $u['id']]);
|
||||||
|
$output->writeln("could not find user by id : " . $u['id']);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->mapCalendarToUser->hasUserId($user)) {
|
||||||
|
$user = $this->mapCalendarToUser->writeMetadata($user);
|
||||||
|
|
||||||
|
// if user still does not have userid, continue
|
||||||
|
if (!$this->mapCalendarToUser->hasUserId($user)) {
|
||||||
|
$this->logger->warning("user does not have a counterpart on ms api", ['userId' => $user->getId(), 'email' => $user->getEmail()]);
|
||||||
|
$output->writeln(sprintf("giving up for user with email %s and id %s", $user->getEmail(), $user->getId()));
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sync user absence
|
||||||
|
try {
|
||||||
|
$this->userAbsenceSync->syncUserAbsence($user);
|
||||||
|
} catch (UserAbsenceSyncException $e) {
|
||||||
|
$this->logger->error("could not sync user absence", ['userId' => $user->getId(), 'email' => $user->getEmail(), 'exception' => $e->getTraceAsString(), "message" => $e->getMessage()]);
|
||||||
|
$output->writeln(sprintf("Could not sync user absence: id: %s and email: %s", $user->getId(), $user->getEmail()));
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we first try to renew an existing subscription, if any.
|
||||||
|
// if not, or if it fails, we try to create a new one
|
||||||
|
if ($this->mapCalendarToUser->hasActiveSubscription($user)) {
|
||||||
|
$this->logger->debug(self::class . ' renew a subscription for', [
|
||||||
|
'userId' => $user->getId(),
|
||||||
|
'username' => $user->getUsernameCanonical(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
['secret' => $secret, 'id' => $id, 'expiration' => $expirationTs]
|
||||||
|
= $this->eventsOnUserSubscriptionCreator->renewSubscriptionForUser($user, $expiration);
|
||||||
|
$this->mapCalendarToUser->writeSubscriptionMetadata($user, $expirationTs, $id, $secret);
|
||||||
|
|
||||||
|
if (0 !== $expirationTs) {
|
||||||
|
++$renewed;
|
||||||
|
} else {
|
||||||
|
$this->logger->warning(self::class . ' could not renew subscription for a user', [
|
||||||
|
'userId' => $user->getId(),
|
||||||
|
'username' => $user->getUsernameCanonical(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->mapCalendarToUser->hasActiveSubscription($user)) {
|
||||||
|
$this->logger->debug(self::class . ' create a subscription for', [
|
||||||
|
'userId' => $user->getId(),
|
||||||
|
'username' => $user->getUsernameCanonical(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
['secret' => $secret, 'id' => $id, 'expiration' => $expirationTs]
|
||||||
|
= $this->eventsOnUserSubscriptionCreator->createSubscriptionForUser($user, $expiration);
|
||||||
|
$this->mapCalendarToUser->writeSubscriptionMetadata($user, $expirationTs, $id, $secret);
|
||||||
|
|
||||||
|
if (0 !== $expirationTs) {
|
||||||
|
++$created;
|
||||||
|
} else {
|
||||||
|
$this->logger->warning(self::class . ' could not create subscription for a user', [
|
||||||
|
'userId' => $user->getId(),
|
||||||
|
'username' => $user->getUsernameCanonical(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (0 === $offset % $limit) {
|
||||||
|
$this->em->flush();
|
||||||
|
$this->em->clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->em->flush();
|
||||||
|
$this->em->clear();
|
||||||
|
|
||||||
$this->logger->warning(self::class . ' process executed', [
|
$this->logger->warning(self::class . ' process executed', [
|
||||||
'created' => $created,
|
'created' => $created,
|
||||||
'renewed' => $renewed,
|
'renewed' => $renewed,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$output->writeln("users synchronized");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,7 +166,7 @@ class MapAndSubscribeUserCalendarCommand extends Command
|
|||||||
parent::configure();
|
parent::configure();
|
||||||
|
|
||||||
$this
|
$this
|
||||||
->setDescription('MSGraph: collect user metadata and create subscription on events for users')
|
->setDescription('MSGraph: collect user metadata and create subscription on events for users, and sync the user absence-presence')
|
||||||
->addOption(
|
->addOption(
|
||||||
'renew-before-end-interval',
|
'renew-before-end-interval',
|
||||||
'r',
|
'r',
|
||||||
|
@ -65,7 +65,7 @@ class MSGraphUserRepository
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array|User[]
|
* @return array<User>
|
||||||
*/
|
*/
|
||||||
public function findByMostOldSubscriptionOrWithoutSubscriptionOrData(DateInterval $interval, int $limit = 50, int $offset = 0): array
|
public function findByMostOldSubscriptionOrWithoutSubscriptionOrData(DateInterval $interval, int $limit = 50, int $offset = 0): array
|
||||||
{
|
{
|
||||||
|
@ -13,6 +13,7 @@ namespace Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph;
|
|||||||
|
|
||||||
use Chill\CalendarBundle\Exception\UserAbsenceSyncException;
|
use Chill\CalendarBundle\Exception\UserAbsenceSyncException;
|
||||||
use Chill\MainBundle\Entity\User;
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Component\Clock\ClockInterface;
|
use Symfony\Component\Clock\ClockInterface;
|
||||||
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
||||||
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
|
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
|
||||||
@ -43,7 +44,7 @@ final readonly class MSUserAbsenceReader implements MSUserAbsenceReaderInterface
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
$automaticRepliesSettings = $this->machineHttpClient
|
$automaticRepliesSettings = $this->machineHttpClient
|
||||||
->request('GET', '/users/' . $id . '/mailboxSettings/automaticRepliesSetting')
|
->request('GET', 'users/' . $id . '/mailboxSettings/automaticRepliesSetting')
|
||||||
->toArray(true);
|
->toArray(true);
|
||||||
} catch (ClientExceptionInterface|DecodingExceptionInterface|RedirectionExceptionInterface|TransportExceptionInterface $e) {
|
} catch (ClientExceptionInterface|DecodingExceptionInterface|RedirectionExceptionInterface|TransportExceptionInterface $e) {
|
||||||
throw new UserAbsenceSyncException("Error receiving response for mailboxSettings", 0, $e);
|
throw new UserAbsenceSyncException("Error receiving response for mailboxSettings", 0, $e);
|
||||||
|
@ -12,6 +12,7 @@ declare(strict_types=1);
|
|||||||
namespace Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph;
|
namespace Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph;
|
||||||
|
|
||||||
use Chill\MainBundle\Entity\User;
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Component\Clock\ClockInterface;
|
use Symfony\Component\Clock\ClockInterface;
|
||||||
|
|
||||||
readonly class MSUserAbsenceSync
|
readonly class MSUserAbsenceSync
|
||||||
@ -19,6 +20,7 @@ readonly class MSUserAbsenceSync
|
|||||||
public function __construct(
|
public function __construct(
|
||||||
private MSUserAbsenceReaderInterface $absenceReader,
|
private MSUserAbsenceReaderInterface $absenceReader,
|
||||||
private ClockInterface $clock,
|
private ClockInterface $clock,
|
||||||
|
private LoggerInterface $logger,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,9 +37,13 @@ readonly class MSUserAbsenceSync
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->logger->info("will change user absence", ['userId' => $user->getId()]);
|
||||||
|
|
||||||
if ($absence) {
|
if ($absence) {
|
||||||
|
$this->logger->debug("make user absent", ['userId' => $user->getId()]);
|
||||||
$user->setAbsenceStart($this->clock->now());
|
$user->setAbsenceStart($this->clock->now());
|
||||||
} else {
|
} else {
|
||||||
|
$this->logger->debug("make user present", ['userId' => $user->getId()]);
|
||||||
$user->setAbsenceStart(null);
|
$user->setAbsenceStart(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\MSUserAbsenceSync;
|
|||||||
use Chill\MainBundle\Entity\User;
|
use Chill\MainBundle\Entity\User;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Prophecy\PhpUnit\ProphecyTrait;
|
use Prophecy\PhpUnit\ProphecyTrait;
|
||||||
|
use Psr\Log\NullLogger;
|
||||||
use Symfony\Component\Clock\MockClock;
|
use Symfony\Component\Clock\MockClock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,7 +38,7 @@ class MSUserAbsenceSyncTest extends TestCase
|
|||||||
|
|
||||||
$clock = new MockClock(new \DateTimeImmutable('2023-07-01T12:00:00'));
|
$clock = new MockClock(new \DateTimeImmutable('2023-07-01T12:00:00'));
|
||||||
|
|
||||||
$syncer = new MSUserAbsenceSync($userAbsenceReader->reveal(), $clock);
|
$syncer = new MSUserAbsenceSync($userAbsenceReader->reveal(), $clock, new NullLogger());
|
||||||
|
|
||||||
$syncer->syncUserAbsence($user);
|
$syncer->syncUserAbsence($user);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user