mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-08-28 02:23:51 +00:00
Merge remote-tracking branch 'origin/master' into 616_rapid-action
This commit is contained in:
@@ -21,6 +21,6 @@ class ChillCalendarBundle extends Bundle
|
||||
{
|
||||
parent::build($container);
|
||||
|
||||
$container->addCompilerPass(new RemoteCalendarCompilerPass());
|
||||
$container->addCompilerPass(new RemoteCalendarCompilerPass(), \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION, 0);
|
||||
}
|
||||
}
|
||||
|
@@ -29,22 +29,12 @@ use TheNetworg\OAuth2\Client\Provider\Azure;
|
||||
|
||||
class AzureGrantAdminConsentAndAcquireToken extends Command
|
||||
{
|
||||
private Azure $azure;
|
||||
|
||||
private ClientRegistry $clientRegistry;
|
||||
|
||||
private MachineTokenStorage $machineTokenStorage;
|
||||
|
||||
public function __construct(Azure $azure, ClientRegistry $clientRegistry, MachineTokenStorage $machineTokenStorage)
|
||||
public function __construct(private readonly Azure $azure, private readonly ClientRegistry $clientRegistry, private readonly MachineTokenStorage $machineTokenStorage)
|
||||
{
|
||||
parent::__construct('chill:calendar:msgraph-grant-admin-consent');
|
||||
|
||||
$this->azure = $azure;
|
||||
$this->clientRegistry = $clientRegistry;
|
||||
$this->machineTokenStorage = $machineTokenStorage;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
/** @var FormatterHelper $formatter */
|
||||
$formatter = $this->getHelper('formatter');
|
||||
@@ -76,8 +66,8 @@ class AzureGrantAdminConsentAndAcquireToken extends Command
|
||||
|
||||
$output->writeln('Token information:');
|
||||
$output->writeln($token->getToken());
|
||||
$output->writeln('Expires at: ' . $token->getExpires());
|
||||
$output->writeln('To inspect the token content, go to https://jwt.ms/#access_token=' . urlencode($token->getToken()));
|
||||
$output->writeln('Expires at: '.$token->getExpires());
|
||||
$output->writeln('To inspect the token content, go to https://jwt.ms/#access_token='.urlencode($token->getToken()));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -21,11 +21,8 @@ namespace Chill\CalendarBundle\Command;
|
||||
use Chill\CalendarBundle\Exception\UserAbsenceSyncException;
|
||||
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\EventsOnUserSubscriptionCreator;
|
||||
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\MapCalendarToUser;
|
||||
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\MSGraphUserRepository;
|
||||
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\MSUserAbsenceSync;
|
||||
use Chill\MainBundle\Repository\UserRepositoryInterface;
|
||||
use DateInterval;
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
@@ -48,19 +45,17 @@ final class MapAndSubscribeUserCalendarCommand extends Command
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$this->logger->info(self::class . ' execute command');
|
||||
$this->logger->info(self::class.' execute command');
|
||||
|
||||
$limit = 50;
|
||||
$offset = 0;
|
||||
/** @var DateInterval $interval the interval before the end of the expiration */
|
||||
$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')));
|
||||
$users = $this->userRepository->findAllAsArray('fr');
|
||||
$created = 0;
|
||||
$renewed = 0;
|
||||
|
||||
$this->logger->info(self::class . ' start user to get - renew', [
|
||||
'expiration' => $expiration->format(DateTimeImmutable::ATOM),
|
||||
$this->logger->info(self::class.' start user to get - renew', [
|
||||
'expiration' => $expiration->format(\DateTimeImmutable::ATOM),
|
||||
]);
|
||||
|
||||
foreach ($users as $u) {
|
||||
@@ -73,8 +68,8 @@ final class MapAndSubscribeUserCalendarCommand extends Command
|
||||
$user = $this->userRepository->find($u['id']);
|
||||
|
||||
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']);
|
||||
$this->logger->error('could not find user by id', ['uid' => $u['id']]);
|
||||
$output->writeln('could not find user by id : '.$u['id']);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -83,8 +78,8 @@ final class MapAndSubscribeUserCalendarCommand extends Command
|
||||
|
||||
// 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()));
|
||||
$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;
|
||||
}
|
||||
@@ -94,15 +89,14 @@ final class MapAndSubscribeUserCalendarCommand extends Command
|
||||
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;
|
||||
$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()));
|
||||
}
|
||||
|
||||
// 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', [
|
||||
$this->logger->debug(self::class.' renew a subscription for', [
|
||||
'userId' => $user->getId(),
|
||||
'username' => $user->getUsernameCanonical(),
|
||||
]);
|
||||
@@ -114,7 +108,7 @@ final class MapAndSubscribeUserCalendarCommand extends Command
|
||||
if (0 !== $expirationTs) {
|
||||
++$renewed;
|
||||
} else {
|
||||
$this->logger->warning(self::class . ' could not renew subscription for a user', [
|
||||
$this->logger->warning(self::class.' could not renew subscription for a user', [
|
||||
'userId' => $user->getId(),
|
||||
'username' => $user->getUsernameCanonical(),
|
||||
]);
|
||||
@@ -122,7 +116,7 @@ final class MapAndSubscribeUserCalendarCommand extends Command
|
||||
}
|
||||
|
||||
if (!$this->mapCalendarToUser->hasActiveSubscription($user)) {
|
||||
$this->logger->debug(self::class . ' create a subscription for', [
|
||||
$this->logger->debug(self::class.' create a subscription for', [
|
||||
'userId' => $user->getId(),
|
||||
'username' => $user->getUsernameCanonical(),
|
||||
]);
|
||||
@@ -134,14 +128,13 @@ final class MapAndSubscribeUserCalendarCommand extends Command
|
||||
if (0 !== $expirationTs) {
|
||||
++$created;
|
||||
} else {
|
||||
$this->logger->warning(self::class . ' could not create subscription for a user', [
|
||||
$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();
|
||||
@@ -151,12 +144,12 @@ final class MapAndSubscribeUserCalendarCommand extends Command
|
||||
$this->em->flush();
|
||||
$this->em->clear();
|
||||
|
||||
$this->logger->warning(self::class . ' process executed', [
|
||||
$this->logger->warning(self::class.' process executed', [
|
||||
'created' => $created,
|
||||
'renewed' => $renewed,
|
||||
]);
|
||||
|
||||
$output->writeln("users synchronized");
|
||||
$output->writeln('users synchronized');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -25,13 +25,9 @@ use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class SendShortMessageOnEligibleCalendar extends Command
|
||||
{
|
||||
private BulkCalendarShortMessageSender $messageSender;
|
||||
|
||||
public function __construct(BulkCalendarShortMessageSender $messageSender)
|
||||
public function __construct(private readonly BulkCalendarShortMessageSender $messageSender)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->messageSender = $messageSender;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
@@ -39,7 +35,7 @@ class SendShortMessageOnEligibleCalendar extends Command
|
||||
return 'chill:calendar:send-short-messages';
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$this->messageSender->sendBulkMessageToEligibleCalendars();
|
||||
|
||||
|
@@ -26,8 +26,6 @@ use Chill\MainBundle\Repository\UserRepositoryInterface;
|
||||
use Chill\MainBundle\Service\ShortMessage\ShortMessageTransporterInterface;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\PersonBundle\Repository\PersonRepository;
|
||||
use DateInterval;
|
||||
use DateTimeImmutable;
|
||||
use libphonenumber\PhoneNumber;
|
||||
use libphonenumber\PhoneNumberFormat;
|
||||
use libphonenumber\PhoneNumberType;
|
||||
@@ -38,39 +36,18 @@ use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
use Symfony\Component\Console\Question\Question;
|
||||
use UnexpectedValueException;
|
||||
use function count;
|
||||
|
||||
class SendTestShortMessageOnCalendarCommand extends Command
|
||||
{
|
||||
private ShortMessageForCalendarBuilderInterface $messageForCalendarBuilder;
|
||||
|
||||
private PersonRepository $personRepository;
|
||||
|
||||
private PhoneNumberHelperInterface $phoneNumberHelper;
|
||||
|
||||
private PhoneNumberUtil $phoneNumberUtil;
|
||||
|
||||
private ShortMessageTransporterInterface $transporter;
|
||||
|
||||
private UserRepositoryInterface $userRepository;
|
||||
|
||||
public function __construct(
|
||||
PersonRepository $personRepository,
|
||||
PhoneNumberUtil $phoneNumberUtil,
|
||||
PhoneNumberHelperInterface $phoneNumberHelper,
|
||||
ShortMessageForCalendarBuilderInterface $messageForCalendarBuilder,
|
||||
ShortMessageTransporterInterface $transporter,
|
||||
UserRepositoryInterface $userRepository
|
||||
private readonly PersonRepository $personRepository,
|
||||
private readonly PhoneNumberUtil $phoneNumberUtil,
|
||||
private readonly PhoneNumberHelperInterface $phoneNumberHelper,
|
||||
private readonly ShortMessageForCalendarBuilderInterface $messageForCalendarBuilder,
|
||||
private readonly ShortMessageTransporterInterface $transporter,
|
||||
private readonly UserRepositoryInterface $userRepository
|
||||
) {
|
||||
parent::__construct();
|
||||
|
||||
$this->personRepository = $personRepository;
|
||||
$this->phoneNumberUtil = $phoneNumberUtil;
|
||||
$this->phoneNumberHelper = $phoneNumberHelper;
|
||||
$this->messageForCalendarBuilder = $messageForCalendarBuilder;
|
||||
$this->transporter = $transporter;
|
||||
$this->userRepository = $userRepository;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
@@ -93,20 +70,20 @@ class SendTestShortMessageOnCalendarCommand extends Command
|
||||
|
||||
// start date
|
||||
$question = new Question('When will start the appointment ? (default: "1 hour") ', '1 hour');
|
||||
$startDate = new DateTimeImmutable($helper->ask($input, $output, $question));
|
||||
$startDate = new \DateTimeImmutable($helper->ask($input, $output, $question));
|
||||
|
||||
if (false === $startDate) {
|
||||
throw new UnexpectedValueException('could not create a date with this date and time');
|
||||
throw new \UnexpectedValueException('could not create a date with this date and time');
|
||||
}
|
||||
|
||||
$calendar->setStartDate($startDate);
|
||||
|
||||
// end date
|
||||
$question = new Question('How long will last the appointment ? (default: "PT30M") ', 'PT30M');
|
||||
$interval = new DateInterval($helper->ask($input, $output, $question));
|
||||
$interval = new \DateInterval($helper->ask($input, $output, $question));
|
||||
|
||||
if (false === $interval) {
|
||||
throw new UnexpectedValueException('could not create the interval');
|
||||
throw new \UnexpectedValueException('could not create the interval');
|
||||
}
|
||||
|
||||
$calendar->setEndDate($calendar->getStartDate()->add($interval));
|
||||
@@ -116,17 +93,17 @@ class SendTestShortMessageOnCalendarCommand extends Command
|
||||
$question
|
||||
->setValidator(function ($answer): Person {
|
||||
if (!is_numeric($answer)) {
|
||||
throw new UnexpectedValueException('the answer must be numeric');
|
||||
throw new \UnexpectedValueException('the answer must be numeric');
|
||||
}
|
||||
|
||||
if (0 >= (int) $answer) {
|
||||
throw new UnexpectedValueException('the answer must be greater than zero');
|
||||
throw new \UnexpectedValueException('the answer must be greater than zero');
|
||||
}
|
||||
|
||||
$person = $this->personRepository->find((int) $answer);
|
||||
|
||||
if (null === $person) {
|
||||
throw new UnexpectedValueException('The person is not found');
|
||||
throw new \UnexpectedValueException('The person is not found');
|
||||
}
|
||||
|
||||
return $person;
|
||||
@@ -140,17 +117,17 @@ class SendTestShortMessageOnCalendarCommand extends Command
|
||||
$question
|
||||
->setValidator(function ($answer): User {
|
||||
if (!is_numeric($answer)) {
|
||||
throw new UnexpectedValueException('the answer must be numeric');
|
||||
throw new \UnexpectedValueException('the answer must be numeric');
|
||||
}
|
||||
|
||||
if (0 >= (int) $answer) {
|
||||
throw new UnexpectedValueException('the answer must be greater than zero');
|
||||
throw new \UnexpectedValueException('the answer must be greater than zero');
|
||||
}
|
||||
|
||||
$user = $this->userRepository->find((int) $answer);
|
||||
|
||||
if (null === $user) {
|
||||
throw new UnexpectedValueException('The user is not found');
|
||||
throw new \UnexpectedValueException('The user is not found');
|
||||
}
|
||||
|
||||
return $user;
|
||||
@@ -169,13 +146,13 @@ class SendTestShortMessageOnCalendarCommand extends Command
|
||||
|
||||
$question->setNormalizer(function ($answer): PhoneNumber {
|
||||
if (null === $answer) {
|
||||
throw new UnexpectedValueException('The person is not found');
|
||||
throw new \UnexpectedValueException('The person is not found');
|
||||
}
|
||||
|
||||
$phone = $this->phoneNumberUtil->parse($answer, 'BE');
|
||||
|
||||
if (!$this->phoneNumberUtil->isPossibleNumberForType($phone, PhoneNumberType::MOBILE)) {
|
||||
throw new UnexpectedValueException('Phone number si not a mobile');
|
||||
throw new \UnexpectedValueException('Phone number si not a mobile');
|
||||
}
|
||||
|
||||
return $phone;
|
||||
@@ -188,7 +165,7 @@ class SendTestShortMessageOnCalendarCommand extends Command
|
||||
|
||||
$messages = $this->messageForCalendarBuilder->buildMessageForCalendar($calendar);
|
||||
|
||||
if (0 === count($messages)) {
|
||||
if (0 === \count($messages)) {
|
||||
$output->writeln('no message to send to this user');
|
||||
}
|
||||
|
||||
|
@@ -23,6 +23,6 @@ class AdminController extends AbstractController
|
||||
*/
|
||||
public function indexAdminAction()
|
||||
{
|
||||
return $this->render('ChillCalendarBundle:Admin:index.html.twig');
|
||||
return $this->render('@ChillCalendar/Admin/index.html.twig');
|
||||
}
|
||||
}
|
||||
|
@@ -15,7 +15,6 @@ use Chill\CalendarBundle\Repository\CalendarRepository;
|
||||
use Chill\MainBundle\CRUD\Controller\ApiController;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Serializer\Model\Collection;
|
||||
use DateTimeImmutable;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
@@ -24,11 +23,8 @@ use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
class CalendarAPIController extends ApiController
|
||||
{
|
||||
private CalendarRepository $calendarRepository;
|
||||
|
||||
public function __construct(CalendarRepository $calendarRepository)
|
||||
public function __construct(private readonly CalendarRepository $calendarRepository)
|
||||
{
|
||||
$this->calendarRepository = $calendarRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -45,8 +41,8 @@ class CalendarAPIController extends ApiController
|
||||
throw new BadRequestHttpException('You must provide a dateFrom parameter');
|
||||
}
|
||||
|
||||
if (false === $dateFrom = DateTimeImmutable::createFromFormat(
|
||||
DateTimeImmutable::ATOM,
|
||||
if (false === $dateFrom = \DateTimeImmutable::createFromFormat(
|
||||
\DateTimeImmutable::ATOM,
|
||||
$request->query->get('dateFrom')
|
||||
)) {
|
||||
throw new BadRequestHttpException('dateFrom not parsable');
|
||||
@@ -56,8 +52,8 @@ class CalendarAPIController extends ApiController
|
||||
throw new BadRequestHttpException('You must provide a dateTo parameter');
|
||||
}
|
||||
|
||||
if (false === $dateTo = DateTimeImmutable::createFromFormat(
|
||||
DateTimeImmutable::ATOM,
|
||||
if (false === $dateTo = \DateTimeImmutable::createFromFormat(
|
||||
\DateTimeImmutable::ATOM,
|
||||
$request->query->get('dateTo')
|
||||
)) {
|
||||
throw new BadRequestHttpException('dateTo not parsable');
|
||||
|
@@ -30,11 +30,8 @@ use Chill\PersonBundle\Repository\PersonRepository;
|
||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||
use Chill\ThirdPartyBundle\Entity\ThirdParty;
|
||||
use DateTimeImmutable;
|
||||
use Exception;
|
||||
use http\Exception\UnexpectedValueException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use RuntimeException;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
use Symfony\Component\Form\Form;
|
||||
@@ -49,56 +46,20 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class CalendarController extends AbstractController
|
||||
{
|
||||
private AccompanyingPeriodRepository $accompanyingPeriodRepository;
|
||||
|
||||
private CalendarACLAwareRepositoryInterface $calendarACLAwareRepository;
|
||||
|
||||
private DocGeneratorTemplateRepository $docGeneratorTemplateRepository;
|
||||
|
||||
private FilterOrderHelperFactoryInterface $filterOrderHelperFactory;
|
||||
|
||||
private LoggerInterface $logger;
|
||||
|
||||
private PaginatorFactory $paginator;
|
||||
|
||||
private PersonRepository $personRepository;
|
||||
|
||||
private RemoteCalendarConnectorInterface $remoteCalendarConnector;
|
||||
|
||||
private SerializerInterface $serializer;
|
||||
|
||||
private TranslatableStringHelperInterface $translatableStringHelper;
|
||||
|
||||
private TranslatorInterface $translator;
|
||||
|
||||
private UserRepositoryInterface $userRepository;
|
||||
|
||||
public function __construct(
|
||||
CalendarACLAwareRepositoryInterface $calendarACLAwareRepository,
|
||||
DocGeneratorTemplateRepository $docGeneratorTemplateRepository,
|
||||
FilterOrderHelperFactoryInterface $filterOrderHelperFactory,
|
||||
LoggerInterface $logger,
|
||||
PaginatorFactory $paginator,
|
||||
RemoteCalendarConnectorInterface $remoteCalendarConnector,
|
||||
SerializerInterface $serializer,
|
||||
TranslatableStringHelperInterface $translatableStringHelper,
|
||||
PersonRepository $personRepository,
|
||||
AccompanyingPeriodRepository $accompanyingPeriodRepository,
|
||||
UserRepositoryInterface $userRepository,
|
||||
TranslatorInterface $translator
|
||||
private readonly CalendarACLAwareRepositoryInterface $calendarACLAwareRepository,
|
||||
private readonly DocGeneratorTemplateRepository $docGeneratorTemplateRepository,
|
||||
private readonly FilterOrderHelperFactoryInterface $filterOrderHelperFactory,
|
||||
private readonly LoggerInterface $logger,
|
||||
private readonly PaginatorFactory $paginator,
|
||||
private readonly RemoteCalendarConnectorInterface $remoteCalendarConnector,
|
||||
private readonly SerializerInterface $serializer,
|
||||
private readonly TranslatableStringHelperInterface $translatableStringHelper,
|
||||
private readonly PersonRepository $personRepository,
|
||||
private readonly AccompanyingPeriodRepository $accompanyingPeriodRepository,
|
||||
private readonly UserRepositoryInterface $userRepository,
|
||||
private readonly TranslatorInterface $translator
|
||||
) {
|
||||
$this->calendarACLAwareRepository = $calendarACLAwareRepository;
|
||||
$this->docGeneratorTemplateRepository = $docGeneratorTemplateRepository;
|
||||
$this->filterOrderHelperFactory = $filterOrderHelperFactory;
|
||||
$this->logger = $logger;
|
||||
$this->paginator = $paginator;
|
||||
$this->remoteCalendarConnector = $remoteCalendarConnector;
|
||||
$this->serializer = $serializer;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
$this->personRepository = $personRepository;
|
||||
$this->accompanyingPeriodRepository = $accompanyingPeriodRepository;
|
||||
$this->userRepository = $userRepository;
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,12 +80,12 @@ class CalendarController extends AbstractController
|
||||
$view = '@ChillCalendar/Calendar/confirm_deleteByPerson.html.twig';
|
||||
$redirectRoute = $this->generateUrl('chill_calendar_calendar_list_by_person', ['id' => $person->getId()]);
|
||||
} else {
|
||||
throw new RuntimeException('nor person or accompanying period');
|
||||
throw new \RuntimeException('nor person or accompanying period');
|
||||
}
|
||||
|
||||
$form = $this->createDeleteForm($entity);
|
||||
|
||||
if ($request->getMethod() === Request::METHOD_DELETE) {
|
||||
if (Request::METHOD_DELETE === $request->getMethod()) {
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isValid()) {
|
||||
@@ -175,7 +136,7 @@ class CalendarController extends AbstractController
|
||||
$view = '@ChillCalendar/Calendar/editByPerson.html.twig';
|
||||
$redirectRoute = $this->generateUrl('chill_calendar_calendar_list_by_person', ['id' => $person->getId()]);
|
||||
} else {
|
||||
throw new RuntimeException('no person nor accompanying period');
|
||||
throw new \RuntimeException('no person nor accompanying period');
|
||||
}
|
||||
|
||||
$form = $this->createForm(CalendarType::class, $entity)
|
||||
@@ -185,7 +146,7 @@ class CalendarController extends AbstractController
|
||||
$templates = $this->docGeneratorTemplateRepository->findByEntity(Calendar::class);
|
||||
|
||||
foreach ($templates as $template) {
|
||||
$form->add('save_and_generate_doc_' . $template->getId(), SubmitType::class, [
|
||||
$form->add('save_and_generate_doc_'.$template->getId(), SubmitType::class, [
|
||||
'label' => $this->translatableStringHelper->localize($template->getName()),
|
||||
]);
|
||||
}
|
||||
@@ -202,7 +163,7 @@ class CalendarController extends AbstractController
|
||||
}
|
||||
|
||||
foreach ($templates as $template) {
|
||||
if ($form->get('save_and_generate_doc_' . $template->getId())->isClicked()) {
|
||||
if ($form->get('save_and_generate_doc_'.$template->getId())->isClicked()) {
|
||||
return $this->redirectToRoute('chill_docgenerator_generate_from_template', [
|
||||
'entityClassName' => Calendar::class,
|
||||
'entityId' => $entity->getId(),
|
||||
@@ -364,7 +325,7 @@ class CalendarController extends AbstractController
|
||||
$form->add('save_and_upload_doc', SubmitType::class);
|
||||
|
||||
foreach ($templates as $template) {
|
||||
$form->add('save_and_generate_doc_' . $template->getId(), SubmitType::class, [
|
||||
$form->add('save_and_generate_doc_'.$template->getId(), SubmitType::class, [
|
||||
'label' => $this->translatableStringHelper->localize($template->getName()),
|
||||
]);
|
||||
}
|
||||
@@ -379,12 +340,12 @@ class CalendarController extends AbstractController
|
||||
|
||||
if ($form->get('save_and_upload_doc')->isClicked()) {
|
||||
return $this->redirectToRoute('chill_calendar_calendardoc_new', [
|
||||
'id' => $entity->getId()
|
||||
'id' => $entity->getId(),
|
||||
]);
|
||||
}
|
||||
|
||||
foreach ($templates as $template) {
|
||||
if ($form->get('save_and_generate_doc_' . $template->getId())->isClicked()) {
|
||||
if ($form->get('save_and_generate_doc_'.$template->getId())->isClicked()) {
|
||||
return $this->redirectToRoute('chill_docgenerator_generate_from_template', [
|
||||
'entityClassName' => Calendar::class,
|
||||
'entityId' => $entity->getId(),
|
||||
@@ -429,7 +390,7 @@ class CalendarController extends AbstractController
|
||||
*/
|
||||
public function showAction(Request $request, int $id): Response
|
||||
{
|
||||
throw new Exception('not implemented');
|
||||
throw new \Exception('not implemented');
|
||||
$view = null;
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
@@ -446,7 +407,7 @@ class CalendarController extends AbstractController
|
||||
}
|
||||
|
||||
/** @var Calendar $entity */
|
||||
$entity = $em->getRepository(\Chill\CalendarBundle\Entity\Calendar::class)->find($id);
|
||||
$entity = $em->getRepository(Calendar::class)->find($id);
|
||||
|
||||
if (null === $entity) {
|
||||
throw $this->createNotFoundException('Unable to find Calendar entity.');
|
||||
@@ -490,7 +451,7 @@ class CalendarController extends AbstractController
|
||||
'entity' => $entity,
|
||||
'user' => $user,
|
||||
'activityData' => $activityData,
|
||||
//'delete_form' => $deleteForm->createView(),
|
||||
// 'delete_form' => $deleteForm->createView(),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -535,12 +496,12 @@ class CalendarController extends AbstractController
|
||||
'returnPath' => $request->query->get('returnPath', null),
|
||||
];
|
||||
|
||||
if ($calendar->getContext() === 'accompanying_period') {
|
||||
if ('accompanying_period' === $calendar->getContext()) {
|
||||
$routeParams['accompanying_period_id'] = $calendar->getAccompanyingPeriod()->getId();
|
||||
} elseif ($calendar->getContext() === 'person') {
|
||||
} elseif ('person' === $calendar->getContext()) {
|
||||
$routeParams['person_id'] = $calendar->getPerson()->getId();
|
||||
} else {
|
||||
throw new RuntimeException('context not found for this calendar');
|
||||
throw new \RuntimeException('context not found for this calendar');
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('chill_activity_activity_new', $routeParams);
|
||||
@@ -549,7 +510,7 @@ class CalendarController extends AbstractController
|
||||
private function buildListFilterOrder(): FilterOrderHelper
|
||||
{
|
||||
$filterOrder = $this->filterOrderHelperFactory->create(self::class);
|
||||
$filterOrder->addDateRange('startDate', null, new DateTimeImmutable('3 days ago'), null);
|
||||
$filterOrder->addDateRange('startDate', null, new \DateTimeImmutable('3 days ago'), null);
|
||||
|
||||
return $filterOrder->build();
|
||||
}
|
||||
|
@@ -16,7 +16,6 @@ use Chill\CalendarBundle\Entity\CalendarDoc;
|
||||
use Chill\CalendarBundle\Form\CalendarDocCreateType;
|
||||
use Chill\CalendarBundle\Form\CalendarDocEditType;
|
||||
use Chill\CalendarBundle\Security\Voter\CalendarDocVoter;
|
||||
use Chill\DocGeneratorBundle\Repository\DocGeneratorTemplateRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
use Symfony\Component\Form\FormFactoryInterface;
|
||||
@@ -27,40 +26,16 @@ use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use Symfony\Component\Templating\EngineInterface;
|
||||
use UnexpectedValueException;
|
||||
|
||||
class CalendarDocController
|
||||
final readonly class CalendarDocController
|
||||
{
|
||||
private DocGeneratorTemplateRepository $docGeneratorTemplateRepository;
|
||||
|
||||
private EngineInterface $engine;
|
||||
|
||||
private EntityManagerInterface $entityManager;
|
||||
|
||||
private FormFactoryInterface $formFactory;
|
||||
|
||||
private Security $security;
|
||||
|
||||
private SerializerInterface $serializer;
|
||||
|
||||
private UrlGeneratorInterface $urlGenerator;
|
||||
|
||||
public function __construct(
|
||||
DocGeneratorTemplateRepository $docGeneratorTemplateRepository,
|
||||
EngineInterface $engine,
|
||||
EntityManagerInterface $entityManager,
|
||||
FormFactoryInterface $formFactory,
|
||||
Security $security,
|
||||
UrlGeneratorInterface $urlGenerator
|
||||
private \Twig\Environment $engine,
|
||||
private EntityManagerInterface $entityManager,
|
||||
private FormFactoryInterface $formFactory,
|
||||
private Security $security,
|
||||
private UrlGeneratorInterface $urlGenerator,
|
||||
) {
|
||||
$this->docGeneratorTemplateRepository = $docGeneratorTemplateRepository;
|
||||
$this->engine = $engine;
|
||||
$this->entityManager = $entityManager;
|
||||
$this->formFactory = $formFactory;
|
||||
$this->security = $security;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,7 +66,7 @@ class CalendarDocController
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new UnexpectedValueException('Unsupported context');
|
||||
throw new \UnexpectedValueException('Unsupported context');
|
||||
}
|
||||
|
||||
$calendarDocDTO = new CalendarDoc\CalendarDocCreateDTO();
|
||||
@@ -208,7 +183,7 @@ class CalendarDocController
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new UnexpectedValueException('Unsupported context');
|
||||
throw new \UnexpectedValueException('Unsupported context');
|
||||
}
|
||||
|
||||
$calendarDocEditDTO = new CalendarDoc\CalendarDocEditDTO($calendarDoc);
|
||||
|
@@ -15,21 +15,16 @@ use Chill\CalendarBundle\Repository\CalendarRangeRepository;
|
||||
use Chill\MainBundle\CRUD\Controller\ApiController;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Serializer\Model\Collection;
|
||||
use DateTimeImmutable;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
class CalendarRangeAPIController extends ApiController
|
||||
{
|
||||
private CalendarRangeRepository $calendarRangeRepository;
|
||||
|
||||
public function __construct(CalendarRangeRepository $calendarRangeRepository)
|
||||
public function __construct(private readonly CalendarRangeRepository $calendarRangeRepository)
|
||||
{
|
||||
$this->calendarRangeRepository = $calendarRangeRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -40,15 +35,15 @@ class CalendarRangeAPIController extends ApiController
|
||||
*/
|
||||
public function availableRanges(User $user, Request $request, string $_format): JsonResponse
|
||||
{
|
||||
//return new JsonResponse(['ok' => true], 200, [], false);
|
||||
// return new JsonResponse(['ok' => true], 200, [], false);
|
||||
$this->denyAccessUnlessGranted('ROLE_USER');
|
||||
|
||||
if (!$request->query->has('dateFrom')) {
|
||||
throw new BadRequestHttpException('You must provide a dateFrom parameter');
|
||||
}
|
||||
|
||||
if (false === $dateFrom = DateTimeImmutable::createFromFormat(
|
||||
DateTimeImmutable::ATOM,
|
||||
if (false === $dateFrom = \DateTimeImmutable::createFromFormat(
|
||||
\DateTimeImmutable::ATOM,
|
||||
$request->query->get('dateFrom')
|
||||
)) {
|
||||
throw new BadRequestHttpException('dateFrom not parsable');
|
||||
@@ -58,8 +53,8 @@ class CalendarRangeAPIController extends ApiController
|
||||
throw new BadRequestHttpException('You must provide a dateTo parameter');
|
||||
}
|
||||
|
||||
if (false === $dateTo = DateTimeImmutable::createFromFormat(
|
||||
DateTimeImmutable::ATOM,
|
||||
if (false === $dateTo = \DateTimeImmutable::createFromFormat(
|
||||
\DateTimeImmutable::ATOM,
|
||||
$request->query->get('dateTo')
|
||||
)) {
|
||||
throw new BadRequestHttpException('dateTo not parsable');
|
||||
|
@@ -31,21 +31,11 @@ use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\Messenger\MessageBusInterface;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use function in_array;
|
||||
|
||||
class InviteApiController
|
||||
{
|
||||
private EntityManagerInterface $entityManager;
|
||||
|
||||
private MessageBusInterface $messageBus;
|
||||
|
||||
private Security $security;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, MessageBusInterface $messageBus, Security $security)
|
||||
public function __construct(private readonly EntityManagerInterface $entityManager, private readonly MessageBusInterface $messageBus, private readonly Security $security)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->messageBus = $messageBus;
|
||||
$this->security = $security;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,7 +59,7 @@ class InviteApiController
|
||||
throw new AccessDeniedHttpException('not allowed to answer on this invitation');
|
||||
}
|
||||
|
||||
if (!in_array($answer, Invite::STATUSES, true)) {
|
||||
if (!\in_array($answer, Invite::STATUSES, true)) {
|
||||
throw new BadRequestHttpException('answer not valid');
|
||||
}
|
||||
|
||||
|
@@ -30,16 +30,8 @@ use TheNetworg\OAuth2\Client\Token\AccessToken;
|
||||
|
||||
class RemoteCalendarConnectAzureController
|
||||
{
|
||||
private ClientRegistry $clientRegistry;
|
||||
|
||||
private OnBehalfOfUserTokenStorage $MSGraphTokenStorage;
|
||||
|
||||
public function __construct(
|
||||
ClientRegistry $clientRegistry,
|
||||
OnBehalfOfUserTokenStorage $MSGraphTokenStorage
|
||||
) {
|
||||
$this->clientRegistry = $clientRegistry;
|
||||
$this->MSGraphTokenStorage = $MSGraphTokenStorage;
|
||||
public function __construct(private readonly ClientRegistry $clientRegistry, private readonly OnBehalfOfUserTokenStorage $MSGraphTokenStorage)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -19,21 +19,16 @@ declare(strict_types=1);
|
||||
namespace Chill\CalendarBundle\Controller;
|
||||
|
||||
use Chill\CalendarBundle\Messenger\Message\MSGraphChangeNotificationMessage;
|
||||
use JsonException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\Messenger\MessageBusInterface;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use const JSON_THROW_ON_ERROR;
|
||||
|
||||
class RemoteCalendarMSGraphSyncController
|
||||
{
|
||||
private MessageBusInterface $messageBus;
|
||||
|
||||
public function __construct(MessageBusInterface $messageBus)
|
||||
public function __construct(private readonly MessageBusInterface $messageBus)
|
||||
{
|
||||
$this->messageBus = $messageBus;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,8 +44,8 @@ class RemoteCalendarMSGraphSyncController
|
||||
}
|
||||
|
||||
try {
|
||||
$body = json_decode($request->getContent(), true, 512, JSON_THROW_ON_ERROR);
|
||||
} catch (JsonException $e) {
|
||||
$body = json_decode($request->getContent(), true, 512, \JSON_THROW_ON_ERROR);
|
||||
} catch (\JsonException $e) {
|
||||
throw new BadRequestHttpException('could not decode json', $e);
|
||||
}
|
||||
|
||||
|
@@ -22,31 +22,20 @@ use Chill\CalendarBundle\RemoteCalendar\Connector\RemoteCalendarConnectorInterfa
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Pagination\PaginatorFactory;
|
||||
use Chill\MainBundle\Serializer\Model\Collection;
|
||||
use DateTimeImmutable;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use function count;
|
||||
|
||||
/**
|
||||
* Contains method to get events (Calendar) from remote calendar.
|
||||
*/
|
||||
class RemoteCalendarProxyController
|
||||
{
|
||||
private PaginatorFactory $paginatorFactory;
|
||||
|
||||
private RemoteCalendarConnectorInterface $remoteCalendarConnector;
|
||||
|
||||
private SerializerInterface $serializer;
|
||||
|
||||
public function __construct(PaginatorFactory $paginatorFactory, RemoteCalendarConnectorInterface $remoteCalendarConnector, SerializerInterface $serializer)
|
||||
public function __construct(private readonly PaginatorFactory $paginatorFactory, private readonly RemoteCalendarConnectorInterface $remoteCalendarConnector, private readonly SerializerInterface $serializer)
|
||||
{
|
||||
$this->paginatorFactory = $paginatorFactory;
|
||||
$this->remoteCalendarConnector = $remoteCalendarConnector;
|
||||
$this->serializer = $serializer;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,8 +47,8 @@ class RemoteCalendarProxyController
|
||||
throw new BadRequestHttpException('You must provide a dateFrom parameter');
|
||||
}
|
||||
|
||||
if (false === $dateFrom = DateTimeImmutable::createFromFormat(
|
||||
DateTimeImmutable::ATOM,
|
||||
if (false === $dateFrom = \DateTimeImmutable::createFromFormat(
|
||||
\DateTimeImmutable::ATOM,
|
||||
$request->query->get('dateFrom')
|
||||
)) {
|
||||
throw new BadRequestHttpException('dateFrom not parsable');
|
||||
@@ -69,8 +58,8 @@ class RemoteCalendarProxyController
|
||||
throw new BadRequestHttpException('You must provide a dateTo parameter');
|
||||
}
|
||||
|
||||
if (false === $dateTo = DateTimeImmutable::createFromFormat(
|
||||
DateTimeImmutable::ATOM,
|
||||
if (false === $dateTo = \DateTimeImmutable::createFromFormat(
|
||||
\DateTimeImmutable::ATOM,
|
||||
$request->query->get('dateTo')
|
||||
)) {
|
||||
throw new BadRequestHttpException('dateTo not parsable');
|
||||
@@ -98,8 +87,8 @@ class RemoteCalendarProxyController
|
||||
|
||||
// in some case, we cannot paginate: we have to fetch all the items at once. We must avoid
|
||||
// further requests by forcing the number of items returned.
|
||||
if (count($events) > $paginator->getItemsPerPage()) {
|
||||
$paginator->setItemsPerPage(count($events));
|
||||
if (\count($events) > $paginator->getItemsPerPage()) {
|
||||
$paginator->setItemsPerPage(\count($events));
|
||||
}
|
||||
|
||||
$collection = new Collection($events, $paginator);
|
||||
|
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
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\DataFixtures\ORM;
|
||||
|
||||
use Chill\CalendarBundle\Security\Voter\CalendarVoter;
|
||||
use Chill\MainBundle\DataFixtures\ORM\LoadPermissionsGroup;
|
||||
use Chill\MainBundle\Entity\PermissionsGroup;
|
||||
use Chill\MainBundle\Entity\RoleScope;
|
||||
use Doctrine\Bundle\FixturesBundle\Fixture;
|
||||
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
|
||||
class LoadCalendarACL extends Fixture implements OrderedFixtureInterface
|
||||
{
|
||||
public function load(ObjectManager $manager): void
|
||||
{
|
||||
$roleScopes = [];
|
||||
|
||||
foreach ([
|
||||
CalendarVoter::CREATE,
|
||||
CalendarVoter::DELETE,
|
||||
CalendarVoter::DELETE,
|
||||
] as $role) {
|
||||
$roleScopes[] = $r = (new RoleScope())
|
||||
->setRole($role);
|
||||
$manager->persist($r);
|
||||
}
|
||||
|
||||
foreach (LoadPermissionsGroup::$refs as $permissionGroupRef) {
|
||||
/** @var PermissionsGroup $group */
|
||||
$group = $this->getReference($permissionGroupRef);
|
||||
|
||||
foreach ($roleScopes as $scope) {
|
||||
$group->addRoleScope($scope);
|
||||
}
|
||||
}
|
||||
|
||||
$manager->flush();
|
||||
}
|
||||
|
||||
public function getOrder(): int
|
||||
{
|
||||
return 16000;
|
||||
}
|
||||
}
|
@@ -18,7 +18,6 @@ use Chill\MainBundle\Entity\Location;
|
||||
use Chill\MainBundle\Entity\LocationType;
|
||||
use Chill\MainBundle\Entity\PostalCode;
|
||||
use Chill\MainBundle\Repository\UserRepository;
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\Bundle\FixturesBundle\Fixture;
|
||||
use Doctrine\Bundle\FixturesBundle\FixtureGroupInterface;
|
||||
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
|
||||
@@ -29,12 +28,8 @@ class LoadCalendarRange extends Fixture implements FixtureGroupInterface, Ordere
|
||||
{
|
||||
public static array $references = [];
|
||||
|
||||
private UserRepository $userRepository;
|
||||
|
||||
public function __construct(
|
||||
UserRepository $userRepository
|
||||
) {
|
||||
$this->userRepository = $userRepository;
|
||||
public function __construct(private readonly UserRepository $userRepository)
|
||||
{
|
||||
}
|
||||
|
||||
public static function getGroups(): array
|
||||
@@ -49,10 +44,6 @@ class LoadCalendarRange extends Fixture implements FixtureGroupInterface, Ordere
|
||||
|
||||
public function load(ObjectManager $manager): void
|
||||
{
|
||||
$arr = range(-50, 50);
|
||||
|
||||
echo "Creating calendar range ('plage de disponibilités')\n";
|
||||
|
||||
$users = $this->userRepository->findAll();
|
||||
|
||||
$location = (new Location())
|
||||
@@ -73,6 +64,8 @@ class LoadCalendarRange extends Fixture implements FixtureGroupInterface, Ordere
|
||||
$manager->persist($type);
|
||||
$manager->persist($location);
|
||||
|
||||
$now = new \DateTimeImmutable();
|
||||
|
||||
$days = [
|
||||
'2021-08-23',
|
||||
'2021-08-24',
|
||||
@@ -82,8 +75,12 @@ class LoadCalendarRange extends Fixture implements FixtureGroupInterface, Ordere
|
||||
'2021-08-31',
|
||||
'2021-09-01',
|
||||
'2021-09-02',
|
||||
(new DateTimeImmutable('tomorrow'))->format('Y-m-d'),
|
||||
(new DateTimeImmutable('today'))->format('Y-m-d'),
|
||||
(new \DateTimeImmutable('tomorrow'))->format('Y-m-d'),
|
||||
(new \DateTimeImmutable('today'))->format('Y-m-d'),
|
||||
$now->add(new \DateInterval('P7D'))->format('Y-m-d'),
|
||||
$now->add(new \DateInterval('P8D'))->format('Y-m-d'),
|
||||
$now->add(new \DateInterval('P9D'))->format('Y-m-d'),
|
||||
$now->add(new \DateInterval('P10D'))->format('Y-m-d'),
|
||||
];
|
||||
|
||||
$hours = [
|
||||
@@ -96,9 +93,9 @@ class LoadCalendarRange extends Fixture implements FixtureGroupInterface, Ordere
|
||||
foreach ($users as $u) {
|
||||
foreach ($days as $d) {
|
||||
foreach ($hours as $h) {
|
||||
$event = $d . ' ' . $h;
|
||||
$startEvent = new DateTimeImmutable($event);
|
||||
$endEvent = new DateTimeImmutable($event . ' + 1 hours');
|
||||
$event = $d.' '.$h;
|
||||
$startEvent = new \DateTimeImmutable($event);
|
||||
$endEvent = new \DateTimeImmutable($event.' + 1 hours');
|
||||
$calendarRange = (new CalendarRange())
|
||||
->setUser($u)
|
||||
->setStartDate($startEvent)
|
||||
|
@@ -39,12 +39,12 @@ class LoadCancelReason extends Fixture implements FixtureGroupInterface
|
||||
];
|
||||
|
||||
foreach ($arr as $a) {
|
||||
echo 'Creating calendar cancel reason : ' . $a['name'] . "\n";
|
||||
echo 'Creating calendar cancel reason : '.$a['name']."\n";
|
||||
$cancelReason = (new CancelReason())
|
||||
->setCanceledBy($a['name'])
|
||||
->setActive(true);
|
||||
$manager->persist($cancelReason);
|
||||
$reference = 'CancelReason_' . $a['name'];
|
||||
$reference = 'CancelReason_'.$a['name'];
|
||||
$this->addReference($reference, $cancelReason);
|
||||
static::$references[] = $reference;
|
||||
}
|
||||
|
@@ -46,12 +46,12 @@ class LoadInvite extends Fixture implements FixtureGroupInterface
|
||||
];
|
||||
|
||||
foreach ($arr as $a) {
|
||||
echo 'Creating calendar invite : ' . $a['name']['fr'] . "\n";
|
||||
echo 'Creating calendar invite : '.$a['name']['fr']."\n";
|
||||
$invite = (new Invite())
|
||||
->setStatus($a['status'])
|
||||
->setUser($this->getRandomUser());
|
||||
$manager->persist($invite);
|
||||
$reference = 'Invite_' . $a['name']['fr'];
|
||||
$reference = 'Invite_'.$a['name']['fr'];
|
||||
$this->addReference($reference, $invite);
|
||||
static::$references[] = $reference;
|
||||
}
|
||||
|
@@ -31,7 +31,7 @@ class ChillCalendarExtension extends Extension implements PrependExtensionInterf
|
||||
$configuration = new Configuration();
|
||||
$config = $this->processConfiguration($configuration, $configs);
|
||||
|
||||
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
|
||||
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
|
||||
$loader->load('services.yml');
|
||||
$loader->load('services/exports.yaml');
|
||||
$loader->load('services/controller.yml');
|
||||
|
@@ -24,28 +24,26 @@ use Chill\MainBundle\Entity\User;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\ThirdPartyBundle\Entity\ThirdParty;
|
||||
use DateInterval;
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\Common\Collections\ReadableCollection;
|
||||
use Doctrine\Common\Collections\Selectable;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use LogicException;
|
||||
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||
|
||||
use Symfony\Component\Validator\Constraints\Range;
|
||||
use Symfony\Component\Validator\Mapping\ClassMetadata;
|
||||
use function in_array;
|
||||
|
||||
/**
|
||||
* @ORM\Table(
|
||||
* name="chill_calendar.calendar",
|
||||
* uniqueConstraints={@ORM\UniqueConstraint(name="idx_calendar_remote", columns={"remoteId"}, options={"where": "remoteId <> ''"})}
|
||||
* )
|
||||
*
|
||||
* @ORM\Entity
|
||||
*
|
||||
* @Serializer\DiscriminatorMap(typeProperty="type", mapping={
|
||||
* "chill_calendar_calendar": Calendar::class
|
||||
* })
|
||||
@@ -58,20 +56,20 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
|
||||
use TrackUpdateTrait;
|
||||
|
||||
public const SMS_CANCEL_PENDING = 'sms_cancel_pending';
|
||||
final public const SMS_CANCEL_PENDING = 'sms_cancel_pending';
|
||||
|
||||
public const SMS_PENDING = 'sms_pending';
|
||||
final public const SMS_PENDING = 'sms_pending';
|
||||
|
||||
public const SMS_SENT = 'sms_sent';
|
||||
final public const SMS_SENT = 'sms_sent';
|
||||
|
||||
public const STATUS_CANCELED = 'canceled';
|
||||
final public const STATUS_CANCELED = 'canceled';
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public const STATUS_MOVED = 'moved';
|
||||
final public const STATUS_MOVED = 'moved';
|
||||
|
||||
public const STATUS_VALID = 'valid';
|
||||
final public const STATUS_VALID = 'valid';
|
||||
|
||||
/**
|
||||
* a list of invite which have been added during this session.
|
||||
@@ -93,6 +91,7 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod", inversedBy="calendars")
|
||||
*
|
||||
* @Serializer\Groups({"calendar:read", "read"})
|
||||
*/
|
||||
private ?AccompanyingPeriod $accompanyingPeriod = null;
|
||||
@@ -104,6 +103,7 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
|
||||
/**
|
||||
* @ORM\OneToOne(targetEntity="CalendarRange", inversedBy="calendar")
|
||||
*
|
||||
* @Serializer\Groups({"calendar:read", "read"})
|
||||
*/
|
||||
private ?CalendarRange $calendarRange = null;
|
||||
@@ -115,6 +115,7 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
|
||||
/**
|
||||
* @ORM\Embedded(class=CommentEmbeddable::class, columnPrefix="comment_")
|
||||
*
|
||||
* @Serializer\Groups({"calendar:read", "read", "docgen:read"})
|
||||
*/
|
||||
private CommentEmbeddable $comment;
|
||||
@@ -125,22 +126,28 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
private int $dateTimeVersion = 0;
|
||||
|
||||
/**
|
||||
* @var Collection<CalendarDoc::class>
|
||||
* @var Collection<CalendarDoc>
|
||||
*
|
||||
* @ORM\OneToMany(targetEntity=CalendarDoc::class, mappedBy="calendar", orphanRemoval=true)
|
||||
*/
|
||||
private Collection $documents;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="datetime_immutable", nullable=false)
|
||||
*
|
||||
* @Serializer\Groups({"calendar:read", "read", "calendar:light", "docgen:read"})
|
||||
*
|
||||
* @Assert\NotNull(message="calendar.An end date is required")
|
||||
*/
|
||||
private ?DateTimeImmutable $endDate = null;
|
||||
private ?\DateTimeImmutable $endDate = null;
|
||||
|
||||
/**
|
||||
* @ORM\Id
|
||||
*
|
||||
* @ORM\GeneratedValue
|
||||
*
|
||||
* @ORM\Column(type="integer")
|
||||
*
|
||||
* @Serializer\Groups({"calendar:read", "read", "calendar:light", "docgen:read"})
|
||||
*/
|
||||
private ?int $id = null;
|
||||
@@ -152,57 +159,80 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
* orphanRemoval=true,
|
||||
* cascade={"persist", "remove", "merge", "detach"}
|
||||
* )
|
||||
*
|
||||
* @ORM\JoinTable(name="chill_calendar.calendar_to_invites")
|
||||
*
|
||||
* @Serializer\Groups({"read", "docgen:read"})
|
||||
*
|
||||
* @var Collection&Selectable<int, Invite>
|
||||
*/
|
||||
private Collection $invites;
|
||||
private Collection&Selectable $invites;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Location")
|
||||
*
|
||||
* @Serializer\Groups({"read", "docgen:read"})
|
||||
*
|
||||
* @Assert\NotNull(message="calendar.A location is required")
|
||||
*/
|
||||
private ?Location $location = null;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
|
||||
*
|
||||
* @Serializer\Groups({"calendar:read", "read", "calendar:light", "docgen:read"})
|
||||
*
|
||||
* @Serializer\Context(normalizationContext={"read"}, groups={"calendar:light"})
|
||||
*
|
||||
* @Assert\NotNull(message="calendar.A main user is mandatory")
|
||||
*/
|
||||
private ?User $mainUser = null;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=Person::class)
|
||||
*
|
||||
* @ORM\JoinColumn(nullable=true)
|
||||
*/
|
||||
private ?Person $person = null;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToMany(targetEntity="Chill\PersonBundle\Entity\Person", inversedBy="calendars")
|
||||
*
|
||||
* @ORM\JoinTable(name="chill_calendar.calendar_to_persons")
|
||||
*
|
||||
* @Serializer\Groups({"calendar:read", "read", "calendar:light", "docgen:read"})
|
||||
*
|
||||
* @Serializer\Context(normalizationContext={"read"}, groups={"calendar:light"})
|
||||
*
|
||||
* @Assert\Count(min=1, minMessage="calendar.At least {{ limit }} person is required.")
|
||||
*
|
||||
* @var Collection<Person>
|
||||
*/
|
||||
private Collection $persons;
|
||||
|
||||
/**
|
||||
* @ORM\Embedded(class=PrivateCommentEmbeddable::class, columnPrefix="privateComment_")
|
||||
*
|
||||
* @Serializer\Groups({"calendar:read"})
|
||||
*/
|
||||
private PrivateCommentEmbeddable $privateComment;
|
||||
|
||||
/**
|
||||
* @var Collection<ThirdParty>
|
||||
*
|
||||
* @ORM\ManyToMany(targetEntity="Chill\ThirdPartyBundle\Entity\ThirdParty")
|
||||
*
|
||||
* @ORM\JoinTable(name="chill_calendar.calendar_to_thirdparties")
|
||||
*
|
||||
* @Serializer\Groups({"calendar:read", "read", "calendar:light", "docgen:read"})
|
||||
*
|
||||
* @Serializer\Context(normalizationContext={"read"}, groups={"calendar:light"})
|
||||
*/
|
||||
private Collection $professionals;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="boolean", nullable=true)
|
||||
*
|
||||
* @Serializer\Groups({"docgen:read"})
|
||||
*/
|
||||
private ?bool $sendSMS = false;
|
||||
@@ -214,21 +244,27 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="datetime_immutable", nullable=false)
|
||||
*
|
||||
* @Serializer\Groups({"calendar:read", "read", "calendar:light", "docgen:read"})
|
||||
*
|
||||
* @Serializer\Context(normalizationContext={"read"}, groups={"calendar:light"})
|
||||
*
|
||||
* @Assert\NotNull(message="calendar.A start date is required")
|
||||
*/
|
||||
private ?DateTimeImmutable $startDate = null;
|
||||
private ?\DateTimeImmutable $startDate = null;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255, nullable=false, options={"default": "valid"})
|
||||
*
|
||||
* @Serializer\Groups({"calendar:read", "read", "calendar:light"})
|
||||
*
|
||||
* @Serializer\Context(normalizationContext={"read"}, groups={"calendar:light"})
|
||||
*/
|
||||
private string $status = self::STATUS_VALID;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="boolean", nullable=true)
|
||||
*
|
||||
* @Serializer\Groups({"docgen:read"})
|
||||
*/
|
||||
private ?bool $urgent = false;
|
||||
@@ -261,7 +297,7 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
public function addInvite(Invite $invite): self
|
||||
{
|
||||
if ($invite->getCalendar() instanceof Calendar && $invite->getCalendar() !== $this) {
|
||||
throw new LogicException('Not allowed to move an invitation to another Calendar');
|
||||
throw new \LogicException('Not allowed to move an invitation to another Calendar');
|
||||
}
|
||||
|
||||
$this->invites[] = $invite;
|
||||
@@ -317,16 +353,11 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
|
||||
public function getCenters(): ?iterable
|
||||
{
|
||||
switch ($this->getContext()) {
|
||||
case 'person':
|
||||
return [$this->getPerson()->getCenter()];
|
||||
|
||||
case 'accompanying_period':
|
||||
return $this->getAccompanyingPeriod()->getCenters();
|
||||
|
||||
default:
|
||||
throw new LogicException('context not supported: ' . $this->getContext());
|
||||
}
|
||||
return match ($this->getContext()) {
|
||||
'person' => [$this->getPerson()->getCenter()],
|
||||
'accompanying_period' => $this->getAccompanyingPeriod()->getCenters(),
|
||||
default => throw new \LogicException('context not supported: '.$this->getContext()),
|
||||
};
|
||||
}
|
||||
|
||||
public function getComment(): CommentEmbeddable
|
||||
@@ -339,11 +370,11 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
*/
|
||||
public function getContext(): ?string
|
||||
{
|
||||
if ($this->getAccompanyingPeriod() !== null) {
|
||||
if (null !== $this->getAccompanyingPeriod()) {
|
||||
return 'accompanying_period';
|
||||
}
|
||||
|
||||
if ($this->getPerson() !== null) {
|
||||
if (null !== $this->getPerson()) {
|
||||
return 'person';
|
||||
}
|
||||
|
||||
@@ -366,16 +397,16 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
/**
|
||||
* @Serializer\Groups({"docgen:read"})
|
||||
*/
|
||||
public function getDuration(): ?DateInterval
|
||||
public function getDuration(): ?\DateInterval
|
||||
{
|
||||
if ($this->getStartDate() === null || $this->getEndDate() === null) {
|
||||
if (null === $this->getStartDate() || null === $this->getEndDate()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->getStartDate()->diff($this->getEndDate());
|
||||
}
|
||||
|
||||
public function getEndDate(): ?DateTimeImmutable
|
||||
public function getEndDate(): ?\DateTimeImmutable
|
||||
{
|
||||
return $this->endDate;
|
||||
}
|
||||
@@ -454,7 +485,7 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
$personsNotAssociated = [];
|
||||
|
||||
foreach ($this->persons as $person) {
|
||||
if (!in_array($person, $this->getPersonsAssociated(), true)) {
|
||||
if (!\in_array($person, $this->getPersonsAssociated(), true)) {
|
||||
$personsNotAssociated[] = $person;
|
||||
}
|
||||
}
|
||||
@@ -488,7 +519,7 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
return $this->smsStatus;
|
||||
}
|
||||
|
||||
public function getStartDate(): ?DateTimeImmutable
|
||||
public function getStartDate(): ?\DateTimeImmutable
|
||||
{
|
||||
return $this->startDate;
|
||||
}
|
||||
@@ -510,6 +541,7 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
|
||||
/**
|
||||
* @return ReadableCollection<(int|string), User>
|
||||
*
|
||||
* @Serializer\Groups({"calendar:read", "read"})
|
||||
*/
|
||||
public function getUsers(): ReadableCollection
|
||||
@@ -559,7 +591,7 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
public function removeDocument(CalendarDoc $calendarDoc): self
|
||||
{
|
||||
if ($calendarDoc->getCalendar() !== $this) {
|
||||
throw new LogicException('cannot remove document of another calendar');
|
||||
throw new \LogicException('cannot remove document of another calendar');
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -653,7 +685,7 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setEndDate(DateTimeImmutable $endDate): self
|
||||
public function setEndDate(\DateTimeImmutable $endDate): self
|
||||
{
|
||||
if (null === $this->endDate || $this->endDate->getTimestamp() !== $endDate->getTimestamp()) {
|
||||
$this->increaseaDatetimeVersion();
|
||||
@@ -711,7 +743,7 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setStartDate(DateTimeImmutable $startDate): self
|
||||
public function setStartDate(\DateTimeImmutable $startDate): self
|
||||
{
|
||||
if (null === $this->startDate || $this->startDate->getTimestamp() !== $startDate->getTimestamp()) {
|
||||
$this->increaseaDatetimeVersion();
|
||||
@@ -726,7 +758,7 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
{
|
||||
$this->status = $status;
|
||||
|
||||
if (self::STATUS_CANCELED === $status && $this->getSmsStatus() === self::SMS_SENT) {
|
||||
if (self::STATUS_CANCELED === $status && self::SMS_SENT === $this->getSmsStatus()) {
|
||||
$this->setSmsStatus(self::SMS_CANCEL_PENDING);
|
||||
}
|
||||
|
||||
|
@@ -22,6 +22,7 @@ use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
*
|
||||
* @ORM\Table(
|
||||
* name="chill_calendar.calendar_doc",
|
||||
* )
|
||||
@@ -34,6 +35,7 @@ class CalendarDoc implements TrackCreationInterface, TrackUpdateInterface
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=Calendar::class, inversedBy="documents")
|
||||
*
|
||||
* @ORM\JoinColumn(nullable=false)
|
||||
*/
|
||||
private Calendar $calendar;
|
||||
@@ -45,27 +47,26 @@ class CalendarDoc implements TrackCreationInterface, TrackUpdateInterface
|
||||
|
||||
/**
|
||||
* @ORM\Id
|
||||
*
|
||||
* @ORM\GeneratedValue
|
||||
*
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
private ?int $id = null;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=StoredObject::class, cascade={"persist"})
|
||||
* @ORM\JoinColumn(nullable=false)
|
||||
*/
|
||||
private ?StoredObject $storedObject;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="boolean", nullable=false, options={"default": false})
|
||||
*/
|
||||
private bool $trackDateTimeVersion = false;
|
||||
|
||||
public function __construct(Calendar $calendar, ?StoredObject $storedObject)
|
||||
public function __construct(Calendar $calendar, /**
|
||||
* @ORM\ManyToOne(targetEntity=StoredObject::class, cascade={"persist"})
|
||||
*
|
||||
* @ORM\JoinColumn(nullable=false)
|
||||
*/
|
||||
private ?StoredObject $storedObject)
|
||||
{
|
||||
$this->setCalendar($calendar);
|
||||
|
||||
$this->storedObject = $storedObject;
|
||||
$this->datetimeVersion = $calendar->getDateTimeVersion();
|
||||
}
|
||||
|
||||
@@ -112,8 +113,6 @@ class CalendarDoc implements TrackCreationInterface, TrackUpdateInterface
|
||||
|
||||
/**
|
||||
* @internal use @see{Calendar::removeDocument} instead
|
||||
*
|
||||
* @param Calendar $calendar
|
||||
*/
|
||||
public function setCalendar(?Calendar $calendar): CalendarDoc
|
||||
{
|
||||
|
@@ -18,12 +18,14 @@ class CalendarDocCreateDTO
|
||||
{
|
||||
/**
|
||||
* @Assert\NotNull
|
||||
*
|
||||
* @Assert\Valid
|
||||
*/
|
||||
public ?StoredObject $doc = null;
|
||||
|
||||
/**
|
||||
* @Assert\NotBlank
|
||||
*
|
||||
* @Assert\NotNull
|
||||
*/
|
||||
public ?string $title = '';
|
||||
|
@@ -24,6 +24,7 @@ class CalendarDocEditDTO
|
||||
|
||||
/**
|
||||
* @Assert\NotBlank
|
||||
*
|
||||
* @Assert\NotNull
|
||||
*/
|
||||
public ?string $title = '';
|
||||
|
@@ -17,7 +17,6 @@ use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
|
||||
use Chill\MainBundle\Doctrine\Model\TrackUpdateTrait;
|
||||
use Chill\MainBundle\Entity\Location;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
@@ -27,6 +26,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||
* name="chill_calendar.calendar_range",
|
||||
* uniqueConstraints={@ORM\UniqueConstraint(name="idx_calendar_range_remote", columns={"remoteId"}, options={"where": "remoteId <> ''"})}
|
||||
* )
|
||||
*
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class CalendarRange implements TrackCreationInterface, TrackUpdateInterface
|
||||
@@ -44,37 +44,49 @@ class CalendarRange implements TrackCreationInterface, TrackUpdateInterface
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="datetime_immutable", nullable=false)
|
||||
*
|
||||
* @Groups({"read", "write", "calendar:read"})
|
||||
*
|
||||
* @Assert\NotNull
|
||||
*/
|
||||
private ?DateTimeImmutable $endDate = null;
|
||||
private ?\DateTimeImmutable $endDate = null;
|
||||
|
||||
/**
|
||||
* @ORM\Id
|
||||
*
|
||||
* @ORM\GeneratedValue
|
||||
*
|
||||
* @ORM\Column(type="integer")
|
||||
*
|
||||
* @Groups({"read"})
|
||||
*/
|
||||
private $id;
|
||||
private ?int $id = null;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=Location::class)
|
||||
*
|
||||
* @ORM\JoinColumn(nullable=false)
|
||||
*
|
||||
* @Groups({"read", "write", "calendar:read"})
|
||||
*
|
||||
* @Assert\NotNull
|
||||
*/
|
||||
private ?Location $location = null;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="datetime_immutable", nullable=false)
|
||||
*
|
||||
* @groups({"read", "write", "calendar:read"})
|
||||
*
|
||||
* @Assert\NotNull
|
||||
*/
|
||||
private ?DateTimeImmutable $startDate = null;
|
||||
private ?\DateTimeImmutable $startDate = null;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
|
||||
*
|
||||
* @Groups({"read", "write", "calendar:read"})
|
||||
*
|
||||
* @Assert\NotNull
|
||||
*/
|
||||
private ?User $user = null;
|
||||
@@ -84,7 +96,7 @@ class CalendarRange implements TrackCreationInterface, TrackUpdateInterface
|
||||
return $this->calendar;
|
||||
}
|
||||
|
||||
public function getEndDate(): ?DateTimeImmutable
|
||||
public function getEndDate(): ?\DateTimeImmutable
|
||||
{
|
||||
return $this->endDate;
|
||||
}
|
||||
@@ -99,7 +111,7 @@ class CalendarRange implements TrackCreationInterface, TrackUpdateInterface
|
||||
return $this->location;
|
||||
}
|
||||
|
||||
public function getStartDate(): ?DateTimeImmutable
|
||||
public function getStartDate(): ?\DateTimeImmutable
|
||||
{
|
||||
return $this->startDate;
|
||||
}
|
||||
@@ -117,7 +129,7 @@ class CalendarRange implements TrackCreationInterface, TrackUpdateInterface
|
||||
$this->calendar = $calendar;
|
||||
}
|
||||
|
||||
public function setEndDate(DateTimeImmutable $endDate): self
|
||||
public function setEndDate(\DateTimeImmutable $endDate): self
|
||||
{
|
||||
$this->endDate = $endDate;
|
||||
|
||||
@@ -131,7 +143,7 @@ class CalendarRange implements TrackCreationInterface, TrackUpdateInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setStartDate(DateTimeImmutable $startDate): self
|
||||
public function setStartDate(\DateTimeImmutable $startDate): self
|
||||
{
|
||||
$this->startDate = $startDate;
|
||||
|
||||
|
@@ -16,37 +16,40 @@ use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Table(name="chill_calendar.cancel_reason")
|
||||
*
|
||||
* @ORM\Entity(repositoryClass=CancelReasonRepository::class)
|
||||
*/
|
||||
class CancelReason
|
||||
{
|
||||
public const CANCELEDBY_DONOTCOUNT = 'CANCELEDBY_DONOTCOUNT';
|
||||
final public const CANCELEDBY_DONOTCOUNT = 'CANCELEDBY_DONOTCOUNT';
|
||||
|
||||
public const CANCELEDBY_PERSON = 'CANCELEDBY_PERSON';
|
||||
final public const CANCELEDBY_PERSON = 'CANCELEDBY_PERSON';
|
||||
|
||||
public const CANCELEDBY_USER = 'CANCELEDBY_USER';
|
||||
final public const CANCELEDBY_USER = 'CANCELEDBY_USER';
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="boolean")
|
||||
*/
|
||||
private $active;
|
||||
private ?bool $active = null;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255)
|
||||
*/
|
||||
private $canceledBy;
|
||||
private ?string $canceledBy = null;
|
||||
|
||||
/**
|
||||
* @ORM\Id
|
||||
*
|
||||
* @ORM\GeneratedValue
|
||||
*
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
private $id;
|
||||
private ?int $id = null;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="json")
|
||||
*/
|
||||
private $name = [];
|
||||
private array $name = [];
|
||||
|
||||
public function getActive(): ?bool
|
||||
{
|
||||
|
@@ -17,7 +17,6 @@ use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
|
||||
use Chill\MainBundle\Doctrine\Model\TrackUpdateTrait;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use LogicException;
|
||||
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||
|
||||
/**
|
||||
@@ -30,6 +29,7 @@ use Symfony\Component\Serializer\Annotation as Serializer;
|
||||
* name="chill_calendar.invite",
|
||||
* uniqueConstraints={@ORM\UniqueConstraint(name="idx_calendar_invite_remote", columns={"remoteId"}, options={"where": "remoteId <> ''"})}
|
||||
* )
|
||||
*
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class Invite implements TrackUpdateInterface, TrackCreationInterface
|
||||
@@ -40,23 +40,23 @@ class Invite implements TrackUpdateInterface, TrackCreationInterface
|
||||
|
||||
use TrackUpdateTrait;
|
||||
|
||||
public const ACCEPTED = 'accepted';
|
||||
final public const ACCEPTED = 'accepted';
|
||||
|
||||
public const DECLINED = 'declined';
|
||||
final public const DECLINED = 'declined';
|
||||
|
||||
public const PENDING = 'pending';
|
||||
final public const PENDING = 'pending';
|
||||
|
||||
/**
|
||||
* all statuses in one const.
|
||||
*/
|
||||
public const STATUSES = [
|
||||
final public const STATUSES = [
|
||||
self::ACCEPTED,
|
||||
self::DECLINED,
|
||||
self::PENDING,
|
||||
self::TENTATIVELY_ACCEPTED,
|
||||
];
|
||||
|
||||
public const TENTATIVELY_ACCEPTED = 'tentative';
|
||||
final public const TENTATIVELY_ACCEPTED = 'tentative';
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=Calendar::class, inversedBy="invites")
|
||||
@@ -65,21 +65,27 @@ class Invite implements TrackUpdateInterface, TrackCreationInterface
|
||||
|
||||
/**
|
||||
* @ORM\Id
|
||||
*
|
||||
* @ORM\GeneratedValue
|
||||
*
|
||||
* @ORM\Column(type="integer")
|
||||
*
|
||||
* @Serializer\Groups(groups={"calendar:read", "read"})
|
||||
*/
|
||||
private ?int $id = null;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="text", nullable=false, options={"default": "pending"})
|
||||
*
|
||||
* @Serializer\Groups(groups={"calendar:read", "read", "docgen:read"})
|
||||
*/
|
||||
private string $status = self::PENDING;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
|
||||
*
|
||||
* @ORM\JoinColumn(nullable=false)
|
||||
*
|
||||
* @Serializer\Groups(groups={"calendar:read", "read", "docgen:read"})
|
||||
*/
|
||||
private ?User $user = null;
|
||||
@@ -122,7 +128,7 @@ class Invite implements TrackUpdateInterface, TrackCreationInterface
|
||||
public function setUser(?User $user): self
|
||||
{
|
||||
if ($user instanceof User && $this->user instanceof User && $user !== $this->user) {
|
||||
throw new LogicException('Not allowed to associate an invite to a different user');
|
||||
throw new \LogicException('Not allowed to associate an invite to a different user');
|
||||
}
|
||||
|
||||
$this->user = $user;
|
||||
|
@@ -15,15 +15,10 @@ use Chill\ActivityBundle\Entity\Activity;
|
||||
use Doctrine\Persistence\Event\LifecycleEventArgs;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
|
||||
use function array_key_exists;
|
||||
|
||||
class ListenToActivityCreate
|
||||
{
|
||||
private RequestStack $requestStack;
|
||||
|
||||
public function __construct(RequestStack $requestStack)
|
||||
public function __construct(private readonly RequestStack $requestStack)
|
||||
{
|
||||
$this->requestStack = $requestStack;
|
||||
}
|
||||
|
||||
public function postPersist(Activity $activity, LifecycleEventArgs $event): void
|
||||
@@ -38,7 +33,7 @@ class ListenToActivityCreate
|
||||
if ($request->query->has('activityData')) {
|
||||
$activityData = $request->query->get('activityData');
|
||||
|
||||
if (array_key_exists('calendarId', $activityData)) {
|
||||
if (\array_key_exists('calendarId', $activityData)) {
|
||||
$calendarId = $activityData['calendarId'];
|
||||
|
||||
// Attach the activity to the calendar
|
||||
|
@@ -13,7 +13,7 @@ namespace Chill\CalendarBundle\Exception;
|
||||
|
||||
class UserAbsenceSyncException extends \LogicException
|
||||
{
|
||||
public function __construct(string $message = "", int $code = 20_230_706, ?\Throwable $previous = null)
|
||||
public function __construct(string $message = '', int $code = 20_230_706, ?\Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
@@ -15,23 +15,13 @@ use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\MainBundle\Repository\UserRepository;
|
||||
use Chill\MainBundle\Templating\Entity\UserRender;
|
||||
use Closure;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use function in_array;
|
||||
|
||||
final class AgentAggregator implements AggregatorInterface
|
||||
final readonly class AgentAggregator implements AggregatorInterface
|
||||
{
|
||||
private UserRender $userRender;
|
||||
|
||||
private UserRepository $userRepository;
|
||||
|
||||
public function __construct(
|
||||
UserRepository $userRepository,
|
||||
UserRender $userRender
|
||||
) {
|
||||
$this->userRepository = $userRepository;
|
||||
$this->userRender = $userRender;
|
||||
public function __construct(private UserRepository $userRepository, private UserRender $userRender)
|
||||
{
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
@@ -41,7 +31,7 @@ final class AgentAggregator implements AggregatorInterface
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
if (!in_array('caluser', $qb->getAllAliases(), true)) {
|
||||
if (!\in_array('caluser', $qb->getAllAliases(), true)) {
|
||||
$qb->join('cal.mainUser', 'caluser');
|
||||
}
|
||||
|
||||
@@ -58,12 +48,13 @@ final class AgentAggregator implements AggregatorInterface
|
||||
{
|
||||
// no form
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data): Closure
|
||||
public function getLabels($key, array $values, $data): \Closure
|
||||
{
|
||||
return function ($value): string {
|
||||
if ('_header' === $value) {
|
||||
|
@@ -15,23 +15,13 @@ use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\CalendarBundle\Repository\CancelReasonRepository;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Closure;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use function in_array;
|
||||
|
||||
class CancelReasonAggregator implements AggregatorInterface
|
||||
{
|
||||
private CancelReasonRepository $cancelReasonRepository;
|
||||
|
||||
private TranslatableStringHelper $translatableStringHelper;
|
||||
|
||||
public function __construct(
|
||||
CancelReasonRepository $cancelReasonRepository,
|
||||
TranslatableStringHelper $translatableStringHelper
|
||||
) {
|
||||
$this->cancelReasonRepository = $cancelReasonRepository;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
public function __construct(private readonly CancelReasonRepository $cancelReasonRepository, private readonly TranslatableStringHelper $translatableStringHelper)
|
||||
{
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
@@ -42,7 +32,7 @@ class CancelReasonAggregator implements AggregatorInterface
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
// TODO: still needs to take into account calendars without a cancel reason somehow
|
||||
if (!in_array('calcancel', $qb->getAllAliases(), true)) {
|
||||
if (!\in_array('calcancel', $qb->getAllAliases(), true)) {
|
||||
$qb->join('cal.cancelReason', 'calcancel');
|
||||
}
|
||||
|
||||
@@ -59,12 +49,13 @@ class CancelReasonAggregator implements AggregatorInterface
|
||||
{
|
||||
// no form
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data): Closure
|
||||
public function getLabels($key, array $values, $data): \Closure
|
||||
{
|
||||
return function ($value): string {
|
||||
if ('_header' === $value) {
|
||||
|
@@ -12,26 +12,22 @@ declare(strict_types=1);
|
||||
namespace Chill\CalendarBundle\Export\Aggregator;
|
||||
|
||||
use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Entity\User\UserJobHistory;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\MainBundle\Repository\UserJobRepository;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Closure;
|
||||
use Doctrine\ORM\Query\Expr\Join;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use function in_array;
|
||||
|
||||
final class JobAggregator implements AggregatorInterface
|
||||
final readonly class JobAggregator implements AggregatorInterface
|
||||
{
|
||||
private UserJobRepository $jobRepository;
|
||||
|
||||
private TranslatableStringHelper $translatableStringHelper;
|
||||
private const PREFIX = 'cal_agg_job';
|
||||
|
||||
public function __construct(
|
||||
UserJobRepository $jobRepository,
|
||||
TranslatableStringHelper $translatableStringHelper
|
||||
private UserJobRepository $jobRepository,
|
||||
private TranslatableStringHelper $translatableStringHelper
|
||||
) {
|
||||
$this->jobRepository = $jobRepository;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
@@ -41,12 +37,28 @@ final class JobAggregator implements AggregatorInterface
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
if (!in_array('caluser', $qb->getAllAliases(), true)) {
|
||||
$qb->join('cal.mainUser', 'caluser');
|
||||
}
|
||||
$p = self::PREFIX;
|
||||
|
||||
$qb->addSelect('IDENTITY(caluser.userJob) as job_aggregator');
|
||||
$qb->addGroupBy('job_aggregator');
|
||||
$qb
|
||||
->leftJoin('cal.mainUser', "{$p}_user")
|
||||
->leftJoin(
|
||||
UserJobHistory::class,
|
||||
"{$p}_history",
|
||||
Join::WITH,
|
||||
$qb->expr()->eq("{$p}_history.user", "{$p}_user")
|
||||
)
|
||||
// job_at based on cal.startDate
|
||||
->andWhere(
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->lte("{$p}_history.startDate", 'cal.startDate'),
|
||||
$qb->expr()->orX(
|
||||
$qb->expr()->isNull("{$p}_history.endDate"),
|
||||
$qb->expr()->gt("{$p}_history.endDate", 'cal.startDate')
|
||||
)
|
||||
)
|
||||
)
|
||||
->addSelect("IDENTITY({$p}_history.job) AS {$p}_select")
|
||||
->addGroupBy("{$p}_select");
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
@@ -56,14 +68,14 @@ final class JobAggregator implements AggregatorInterface
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// no form
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data): Closure
|
||||
public function getLabels($key, array $values, $data): \Closure
|
||||
{
|
||||
return function ($value): string {
|
||||
if ('_header' === $value) {
|
||||
@@ -74,7 +86,9 @@ final class JobAggregator implements AggregatorInterface
|
||||
return '';
|
||||
}
|
||||
|
||||
$j = $this->jobRepository->find($value);
|
||||
if (null === $j = $this->jobRepository->find($value)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $this->translatableStringHelper->localize(
|
||||
$j->getLabel()
|
||||
@@ -84,11 +98,11 @@ final class JobAggregator implements AggregatorInterface
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['job_aggregator'];
|
||||
return [self::PREFIX.'_select'];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Group calendars by agent job';
|
||||
return 'export.aggregator.calendar.agent_job.Group calendars by agent job';
|
||||
}
|
||||
}
|
||||
|
@@ -14,19 +14,13 @@ namespace Chill\CalendarBundle\Export\Aggregator;
|
||||
use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\MainBundle\Repository\LocationRepository;
|
||||
use Closure;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use function in_array;
|
||||
|
||||
final class LocationAggregator implements AggregatorInterface
|
||||
final readonly class LocationAggregator implements AggregatorInterface
|
||||
{
|
||||
private LocationRepository $locationRepository;
|
||||
|
||||
public function __construct(
|
||||
LocationRepository $locationRepository
|
||||
) {
|
||||
$this->locationRepository = $locationRepository;
|
||||
public function __construct(private LocationRepository $locationRepository)
|
||||
{
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
@@ -36,7 +30,7 @@ final class LocationAggregator implements AggregatorInterface
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
if (!in_array('calloc', $qb->getAllAliases(), true)) {
|
||||
if (!\in_array('calloc', $qb->getAllAliases(), true)) {
|
||||
$qb->join('cal.location', 'calloc');
|
||||
}
|
||||
$qb->addSelect('IDENTITY(cal.location) as location_aggregator');
|
||||
@@ -52,12 +46,13 @@ final class LocationAggregator implements AggregatorInterface
|
||||
{
|
||||
// no form
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data): Closure
|
||||
public function getLabels($key, array $values, $data): \Closure
|
||||
{
|
||||
return function ($value): string {
|
||||
if ('_header' === $value) {
|
||||
|
@@ -15,23 +15,13 @@ use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\MainBundle\Repository\LocationTypeRepository;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Closure;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use function in_array;
|
||||
|
||||
final class LocationTypeAggregator implements AggregatorInterface
|
||||
final readonly class LocationTypeAggregator implements AggregatorInterface
|
||||
{
|
||||
private LocationTypeRepository $locationTypeRepository;
|
||||
|
||||
private TranslatableStringHelper $translatableStringHelper;
|
||||
|
||||
public function __construct(
|
||||
LocationTypeRepository $locationTypeRepository,
|
||||
TranslatableStringHelper $translatableStringHelper
|
||||
) {
|
||||
$this->locationTypeRepository = $locationTypeRepository;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
public function __construct(private LocationTypeRepository $locationTypeRepository, private TranslatableStringHelper $translatableStringHelper)
|
||||
{
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
@@ -41,7 +31,7 @@ final class LocationTypeAggregator implements AggregatorInterface
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
if (!in_array('calloc', $qb->getAllAliases(), true)) {
|
||||
if (!\in_array('calloc', $qb->getAllAliases(), true)) {
|
||||
$qb->join('cal.location', 'calloc');
|
||||
}
|
||||
|
||||
@@ -58,12 +48,13 @@ final class LocationTypeAggregator implements AggregatorInterface
|
||||
{
|
||||
// no form
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data): Closure
|
||||
public function getLabels($key, array $values, $data): \Closure
|
||||
{
|
||||
return function ($value): string {
|
||||
if ('_header' === $value) {
|
||||
|
@@ -13,7 +13,6 @@ namespace Chill\CalendarBundle\Export\Aggregator;
|
||||
|
||||
use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Closure;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
@@ -40,12 +39,13 @@ class MonthYearAggregator implements AggregatorInterface
|
||||
{
|
||||
// No form needed
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data): Closure
|
||||
public function getLabels($key, array $values, $data): \Closure
|
||||
{
|
||||
return static function ($value): string {
|
||||
if ('_header' === $value) {
|
||||
|
@@ -12,26 +12,22 @@ declare(strict_types=1);
|
||||
namespace Chill\CalendarBundle\Export\Aggregator;
|
||||
|
||||
use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Entity\User\UserScopeHistory;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\MainBundle\Repository\ScopeRepository;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Closure;
|
||||
use Doctrine\ORM\Query\Expr\Join;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use function in_array;
|
||||
|
||||
final class ScopeAggregator implements AggregatorInterface
|
||||
final readonly class ScopeAggregator implements AggregatorInterface
|
||||
{
|
||||
private ScopeRepository $scopeRepository;
|
||||
|
||||
private TranslatableStringHelper $translatableStringHelper;
|
||||
private const PREFIX = 'cal_agg_scope';
|
||||
|
||||
public function __construct(
|
||||
ScopeRepository $scopeRepository,
|
||||
TranslatableStringHelper $translatableStringHelper
|
||||
private ScopeRepository $scopeRepository,
|
||||
private TranslatableStringHelper $translatableStringHelper
|
||||
) {
|
||||
$this->scopeRepository = $scopeRepository;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
@@ -41,12 +37,28 @@ final class ScopeAggregator implements AggregatorInterface
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
if (!in_array('caluser', $qb->getAllAliases(), true)) {
|
||||
$qb->join('cal.mainUser', 'caluser');
|
||||
}
|
||||
$p = self::PREFIX;
|
||||
|
||||
$qb->addSelect('IDENTITY(caluser.mainScope) as scope_aggregator');
|
||||
$qb->addGroupBy('scope_aggregator');
|
||||
$qb
|
||||
->leftJoin('cal.mainUser', "{$p}_user")
|
||||
->leftJoin(
|
||||
UserScopeHistory::class,
|
||||
"{$p}_history",
|
||||
Join::WITH,
|
||||
$qb->expr()->eq("{$p}_history.user", "{$p}_user")
|
||||
)
|
||||
// scope_at based on cal.startDate
|
||||
->andWhere(
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->lte("{$p}_history.startDate", 'cal.startDate'),
|
||||
$qb->expr()->orX(
|
||||
$qb->expr()->isNull("{$p}_history.endDate"),
|
||||
$qb->expr()->gt("{$p}_history.endDate", 'cal.startDate')
|
||||
)
|
||||
)
|
||||
)
|
||||
->addSelect("IDENTITY({$p}_history.scope) AS {$p}_select")
|
||||
->addGroupBy("{$p}_select");
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
@@ -56,14 +68,14 @@ final class ScopeAggregator implements AggregatorInterface
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// no form
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data): Closure
|
||||
public function getLabels($key, array $values, $data): \Closure
|
||||
{
|
||||
return function ($value): string {
|
||||
if ('_header' === $value) {
|
||||
@@ -74,7 +86,9 @@ final class ScopeAggregator implements AggregatorInterface
|
||||
return '';
|
||||
}
|
||||
|
||||
$s = $this->scopeRepository->find($value);
|
||||
if (null === $s = $this->scopeRepository->find($value)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $this->translatableStringHelper->localize(
|
||||
$s->getName()
|
||||
@@ -84,11 +98,11 @@ final class ScopeAggregator implements AggregatorInterface
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['scope_aggregator'];
|
||||
return [self::PREFIX.'_select'];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Group calendars by agent scope';
|
||||
return 'export.aggregator.calendar.agent_scope.Group calendars by agent scope';
|
||||
}
|
||||
}
|
||||
|
@@ -20,20 +20,14 @@ namespace Chill\CalendarBundle\Export\Aggregator;
|
||||
|
||||
use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Closure;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use LogicException;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class UrgencyAggregator implements AggregatorInterface
|
||||
{
|
||||
private TranslatorInterface $translator;
|
||||
|
||||
public function __construct(
|
||||
TranslatorInterface $translator
|
||||
) {
|
||||
$this->translator = $translator;
|
||||
public function __construct(private readonly TranslatorInterface $translator)
|
||||
{
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
@@ -56,28 +50,24 @@ class UrgencyAggregator implements AggregatorInterface
|
||||
{
|
||||
// no form
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data): Closure
|
||||
public function getLabels($key, array $values, $data): \Closure
|
||||
{
|
||||
return function ($value): string {
|
||||
if ('_header' === $value) {
|
||||
return 'Urgency';
|
||||
}
|
||||
|
||||
switch ($value) {
|
||||
case true:
|
||||
return $this->translator->trans('is urgent');
|
||||
|
||||
case false:
|
||||
return $this->translator->trans('is not urgent');
|
||||
|
||||
default:
|
||||
throw new LogicException(sprintf('The value %s is not valid', $value));
|
||||
}
|
||||
return match ($value) {
|
||||
true => $this->translator->trans('is urgent'),
|
||||
false => $this->translator->trans('is not urgent'),
|
||||
default => throw new \LogicException(sprintf('The value %s is not valid', $value)),
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -16,5 +16,5 @@ namespace Chill\CalendarBundle\Export;
|
||||
*/
|
||||
abstract class Declarations
|
||||
{
|
||||
public const CALENDAR_TYPE = 'calendar';
|
||||
final public const CALENDAR_TYPE = 'calendar';
|
||||
}
|
||||
|
@@ -13,11 +13,11 @@ namespace Chill\CalendarBundle\Export\Export;
|
||||
|
||||
use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\CalendarBundle\Repository\CalendarRepository;
|
||||
use Chill\MainBundle\Export\AccompanyingCourseExportHelper;
|
||||
use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||
use Closure;
|
||||
use Doctrine\ORM\AbstractQuery;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
@@ -25,17 +25,16 @@ use Symfony\Component\Validator\Exception\LogicException;
|
||||
|
||||
class CountCalendars implements ExportInterface, GroupedExportInterface
|
||||
{
|
||||
private CalendarRepository $calendarRepository;
|
||||
|
||||
public function __construct(CalendarRepository $calendarRepository)
|
||||
{
|
||||
$this->calendarRepository = $calendarRepository;
|
||||
public function __construct(
|
||||
private readonly CalendarRepository $calendarRepository,
|
||||
) {
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// No form necessary
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
@@ -98,6 +97,9 @@ class CountCalendars implements ExportInterface, GroupedExportInterface
|
||||
$qb = $this->calendarRepository->createQueryBuilder('cal');
|
||||
|
||||
$qb->select('COUNT(cal.id) AS export_result');
|
||||
$qb->leftJoin('cal.accompanyingPeriod', 'acp');
|
||||
|
||||
AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb);
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
@@ -13,29 +13,26 @@ namespace Chill\CalendarBundle\Export\Export;
|
||||
|
||||
use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\CalendarBundle\Repository\CalendarRepository;
|
||||
use Chill\MainBundle\Export\AccompanyingCourseExportHelper;
|
||||
use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use LogicException;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class StatCalendarAvgDuration implements ExportInterface, GroupedExportInterface
|
||||
{
|
||||
private CalendarRepository $calendarRepository;
|
||||
|
||||
public function __construct(
|
||||
CalendarRepository $calendarRepository
|
||||
) {
|
||||
$this->calendarRepository = $calendarRepository;
|
||||
public function __construct(private readonly CalendarRepository $calendarRepository)
|
||||
{
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder): void
|
||||
{
|
||||
// no form needed
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
@@ -59,7 +56,7 @@ class StatCalendarAvgDuration implements ExportInterface, GroupedExportInterface
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
if ('export_result' !== $key) {
|
||||
throw new LogicException("the key {$key} is not used by this export");
|
||||
throw new \LogicException("the key {$key} is not used by this export");
|
||||
}
|
||||
|
||||
$labels = array_combine($values, $values);
|
||||
@@ -92,8 +89,10 @@ class StatCalendarAvgDuration implements ExportInterface, GroupedExportInterface
|
||||
{
|
||||
$qb = $this->calendarRepository->createQueryBuilder('cal');
|
||||
|
||||
$qb
|
||||
->select('AVG(cal.endDate - cal.startDate) AS export_result');
|
||||
$qb->select('AVG(cal.endDate - cal.startDate) AS export_result');
|
||||
$qb->join('cal.accompanyingPeriod', 'acp');
|
||||
|
||||
AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb);
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
@@ -13,29 +13,26 @@ namespace Chill\CalendarBundle\Export\Export;
|
||||
|
||||
use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\CalendarBundle\Repository\CalendarRepository;
|
||||
use Chill\MainBundle\Export\AccompanyingCourseExportHelper;
|
||||
use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use LogicException;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class StatCalendarSumDuration implements ExportInterface, GroupedExportInterface
|
||||
{
|
||||
private CalendarRepository $calendarRepository;
|
||||
|
||||
public function __construct(
|
||||
CalendarRepository $calendarRepository
|
||||
) {
|
||||
$this->calendarRepository = $calendarRepository;
|
||||
public function __construct(private readonly CalendarRepository $calendarRepository)
|
||||
{
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder): void
|
||||
{
|
||||
// no form needed
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
@@ -59,7 +56,7 @@ class StatCalendarSumDuration implements ExportInterface, GroupedExportInterface
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
if ('export_result' !== $key) {
|
||||
throw new LogicException("the key {$key} is not used by this export");
|
||||
throw new \LogicException("the key {$key} is not used by this export");
|
||||
}
|
||||
|
||||
$labels = array_combine($values, $values);
|
||||
@@ -92,8 +89,10 @@ class StatCalendarSumDuration implements ExportInterface, GroupedExportInterface
|
||||
{
|
||||
$qb = $this->calendarRepository->createQueryBuilder('cal');
|
||||
|
||||
$qb
|
||||
->select('SUM(cal.endDate - cal.startDate) AS export_result');
|
||||
$qb->select('SUM(cal.endDate - cal.startDate) AS export_result');
|
||||
$qb->join('cal.accompanyingPeriod', 'acp');
|
||||
|
||||
AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb);
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
@@ -22,11 +22,8 @@ use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class AgentFilter implements FilterInterface
|
||||
{
|
||||
private UserRender $userRender;
|
||||
|
||||
public function __construct(UserRender $userRender)
|
||||
public function __construct(private readonly UserRender $userRender)
|
||||
{
|
||||
$this->userRender = $userRender;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
@@ -63,6 +60,7 @@ class AgentFilter implements FilterInterface
|
||||
'expanded' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
|
@@ -21,11 +21,8 @@ use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class BetweenDatesFilter implements FilterInterface
|
||||
{
|
||||
private RollingDateConverterInterface $rollingDateConverter;
|
||||
|
||||
public function __construct(RollingDateConverterInterface $rollingDateConverter)
|
||||
public function __construct(private readonly RollingDateConverterInterface $rollingDateConverter)
|
||||
{
|
||||
$this->rollingDateConverter = $rollingDateConverter;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
@@ -63,6 +60,7 @@ class BetweenDatesFilter implements FilterInterface
|
||||
->add('date_from', PickRollingDateType::class, [])
|
||||
->add('date_to', PickRollingDateType::class, []);
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return ['date_from' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), 'date_to' => new RollingDate(RollingDate::T_TODAY)];
|
||||
|
@@ -20,7 +20,6 @@ namespace Chill\CalendarBundle\Export\Filter;
|
||||
|
||||
use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Doctrine\ORM\Query\Expr\Andx;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
@@ -29,17 +28,14 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
class CalendarRangeFilter implements FilterInterface
|
||||
{
|
||||
private const CHOICES = [
|
||||
'Not made within a calendar range' => true,
|
||||
'Made within a calendar range' => false,
|
||||
'Not made within a calendar range' => 'true',
|
||||
'Made within a calendar range' => 'false',
|
||||
];
|
||||
|
||||
private const DEFAULT_CHOICE = false;
|
||||
private const DEFAULT_CHOICE = 'false';
|
||||
|
||||
private TranslatorInterface $translator;
|
||||
|
||||
public function __construct(TranslatorInterface $translator)
|
||||
public function __construct(private readonly TranslatorInterface $translator)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
@@ -71,6 +67,7 @@ class CalendarRangeFilter implements FilterInterface
|
||||
'empty_data' => self::DEFAULT_CHOICE,
|
||||
]);
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return ['hasCalendarRange' => self::DEFAULT_CHOICE];
|
||||
|
@@ -12,28 +12,24 @@ declare(strict_types=1);
|
||||
namespace Chill\CalendarBundle\Export\Filter;
|
||||
|
||||
use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Entity\User\UserJobHistory;
|
||||
use Chill\MainBundle\Entity\UserJob;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\MainBundle\Repository\UserJobRepositoryInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Doctrine\ORM\Query\Expr\Andx;
|
||||
use Doctrine\ORM\Query\Expr\Join;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
use function in_array;
|
||||
|
||||
class JobFilter implements FilterInterface
|
||||
final readonly class JobFilter implements FilterInterface
|
||||
{
|
||||
protected TranslatorInterface $translator;
|
||||
|
||||
private TranslatableStringHelper $translatableStringHelper;
|
||||
private const PREFIX = 'cal_filter_job';
|
||||
|
||||
public function __construct(
|
||||
TranslatorInterface $translator,
|
||||
TranslatableStringHelper $translatableStringHelper
|
||||
private TranslatableStringHelper $translatableStringHelper,
|
||||
private UserJobRepositoryInterface $userJobRepository
|
||||
) {
|
||||
$this->translator = $translator;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
@@ -43,21 +39,31 @@ class JobFilter implements FilterInterface
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
if (!in_array('caluser', $qb->getAllAliases(), true)) {
|
||||
$qb->join('cal.mainUser', 'caluser');
|
||||
}
|
||||
$p = self::PREFIX;
|
||||
|
||||
$where = $qb->getDQLPart('where');
|
||||
$clause = $qb->expr()->in('caluser.userJob', ':job');
|
||||
|
||||
if ($where instanceof Andx) {
|
||||
$where->add($clause);
|
||||
} else {
|
||||
$where = $qb->expr()->andX($clause);
|
||||
}
|
||||
|
||||
$qb->add('where', $where);
|
||||
$qb->setParameter('job', $data['job']);
|
||||
$qb
|
||||
->leftJoin('cal.mainUser', "{$p}_user")
|
||||
->leftJoin(
|
||||
UserJobHistory::class,
|
||||
"{$p}_history",
|
||||
Join::WITH,
|
||||
$qb->expr()->eq("{$p}_history.user", "{$p}_user")
|
||||
)
|
||||
// job_at based on cal.startDate
|
||||
->andWhere(
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->lte("{$p}_history.startDate", 'cal.startDate'),
|
||||
$qb->expr()->orX(
|
||||
$qb->expr()->isNull("{$p}_history.endDate"),
|
||||
$qb->expr()->gt("{$p}_history.endDate", 'cal.startDate')
|
||||
)
|
||||
)
|
||||
)
|
||||
->andWhere($qb->expr()->in("{$p}_history.job", ":{$p}_job"))
|
||||
->setParameter(
|
||||
"{$p}_job",
|
||||
$data['job']
|
||||
);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
@@ -67,18 +73,16 @@ class JobFilter implements FilterInterface
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('job', EntityType::class, [
|
||||
'class' => UserJob::class,
|
||||
'choice_label' => fn (UserJob $j) => $this->translatableStringHelper->localize(
|
||||
$j->getLabel()
|
||||
),
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
]);
|
||||
}
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
$builder
|
||||
->add('job', EntityType::class, [
|
||||
'class' => UserJob::class,
|
||||
'choices' => $this->userJobRepository->findAllActive(),
|
||||
'choice_label' => fn (UserJob $j) => $this->translatableStringHelper->localize(
|
||||
$j->getLabel()
|
||||
),
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function describeAction($data, $format = 'string'): array
|
||||
@@ -91,13 +95,20 @@ class JobFilter implements FilterInterface
|
||||
);
|
||||
}
|
||||
|
||||
return ['Filtered by agent job: only %jobs%', [
|
||||
return ['export.filter.calendar.agent_job.Filtered by agent job: only %jobs%', [
|
||||
'%jobs%' => implode(', ', $userJobs),
|
||||
]];
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [
|
||||
'job' => [],
|
||||
];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Filter calendars by agent job';
|
||||
return 'export.filter.calendar.agent_job.Filter calendars by agent job';
|
||||
}
|
||||
}
|
||||
|
@@ -13,27 +13,25 @@ namespace Chill\CalendarBundle\Export\Filter;
|
||||
|
||||
use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Entity\Scope;
|
||||
use Chill\MainBundle\Entity\User\UserScopeHistory;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\MainBundle\Repository\ScopeRepositoryInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Doctrine\ORM\Query\Expr\Andx;
|
||||
use Doctrine\ORM\Query\Expr\Join;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
use function in_array;
|
||||
|
||||
class ScopeFilter implements FilterInterface
|
||||
{
|
||||
protected TranslatorInterface $translator;
|
||||
|
||||
private TranslatableStringHelper $translatableStringHelper;
|
||||
private const PREFIX = 'cal_filter_scope';
|
||||
|
||||
public function __construct(
|
||||
TranslatorInterface $translator,
|
||||
TranslatableStringHelper $translatableStringHelper
|
||||
protected TranslatorInterface $translator,
|
||||
private readonly TranslatableStringHelper $translatableStringHelper,
|
||||
private readonly ScopeRepositoryInterface $scopeRepository
|
||||
) {
|
||||
$this->translator = $translator;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
@@ -43,45 +41,53 @@ class ScopeFilter implements FilterInterface
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
if (!in_array('caluser', $qb->getAllAliases(), true)) {
|
||||
$qb->join('cal.mainUser', 'caluser');
|
||||
}
|
||||
$p = self::PREFIX;
|
||||
|
||||
$where = $qb->getDQLPart('where');
|
||||
$clause = $qb->expr()->in('caluser.mainScope', ':scope');
|
||||
|
||||
if ($where instanceof Andx) {
|
||||
$where->add($clause);
|
||||
} else {
|
||||
$where = $qb->expr()->andX($clause);
|
||||
}
|
||||
|
||||
$qb->add('where', $where);
|
||||
$qb->setParameter('scope', $data['scope']);
|
||||
$qb
|
||||
->leftJoin('cal.mainUser', "{$p}_user")
|
||||
->leftJoin(
|
||||
UserScopeHistory::class,
|
||||
"{$p}_history",
|
||||
Join::WITH,
|
||||
$qb->expr()->eq("{$p}_history.user", "{$p}_user")
|
||||
)
|
||||
// scope_at based on cal.startDate
|
||||
->andWhere(
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->lte("{$p}_history.startDate", 'cal.startDate'),
|
||||
$qb->expr()->orX(
|
||||
$qb->expr()->isNull("{$p}_history.endDate"),
|
||||
$qb->expr()->gt("{$p}_history.endDate", 'cal.startDate')
|
||||
)
|
||||
)
|
||||
)
|
||||
->andWhere($qb->expr()->in("{$p}_history.scope", ":{$p}_scope"))
|
||||
->setParameter(
|
||||
"{$p}_scope",
|
||||
$data['scope']
|
||||
);
|
||||
}
|
||||
|
||||
public function applyOn()
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::CALENDAR_TYPE;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('scope', EntityType::class, [
|
||||
'class' => Scope::class,
|
||||
'choice_label' => fn (Scope $s) => $this->translatableStringHelper->localize(
|
||||
$s->getName()
|
||||
),
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
]);
|
||||
}
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
$builder
|
||||
->add('scope', EntityType::class, [
|
||||
'class' => Scope::class,
|
||||
'choices' => $this->scopeRepository->findAllActive(),
|
||||
'choice_label' => fn (Scope $s) => $this->translatableStringHelper->localize(
|
||||
$s->getName()
|
||||
),
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function describeAction($data, $format = 'string')
|
||||
public function describeAction($data, $format = 'string'): array
|
||||
{
|
||||
$scopes = [];
|
||||
|
||||
@@ -91,13 +97,20 @@ class ScopeFilter implements FilterInterface
|
||||
);
|
||||
}
|
||||
|
||||
return ['Filtered by agent scope: only %scopes%', [
|
||||
return ['export.filter.calendar.agent_scope.Filtered by agent scope: only %scopes%', [
|
||||
'%scopes%' => implode(', ', $scopes),
|
||||
]];
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return 'Filter calendars by agent scope';
|
||||
return [
|
||||
'scope' => [],
|
||||
];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'export.filter.calendar.agent_scope.Filter calendars by agent scope';
|
||||
}
|
||||
}
|
||||
|
@@ -12,7 +12,6 @@ declare(strict_types=1);
|
||||
namespace Chill\CalendarBundle\Form;
|
||||
|
||||
use Chill\CalendarBundle\Entity\CalendarDoc\CalendarDocEditDTO;
|
||||
use Chill\DocStoreBundle\Form\StoredObjectType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
@@ -21,7 +21,6 @@ use Chill\MainBundle\Form\Type\CommentType;
|
||||
use Chill\MainBundle\Form\Type\PrivateCommentType;
|
||||
use Chill\PersonBundle\Form\DataTransformer\PersonsToIdDataTransformer;
|
||||
use Chill\ThirdPartyBundle\Form\DataTransformer\ThirdPartiesToIdDataTransformer;
|
||||
use DateTimeImmutable;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\CallbackTransformer;
|
||||
@@ -32,32 +31,14 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class CalendarType extends AbstractType
|
||||
{
|
||||
private IdToCalendarRangeDataTransformer $calendarRangeDataTransformer;
|
||||
|
||||
private IdToLocationDataTransformer $idToLocationDataTransformer;
|
||||
|
||||
private IdToUserDataTransformer $idToUserDataTransformer;
|
||||
|
||||
private IdToUsersDataTransformer $idToUsersDataTransformer;
|
||||
|
||||
private ThirdPartiesToIdDataTransformer $partiesToIdDataTransformer;
|
||||
|
||||
private PersonsToIdDataTransformer $personsToIdDataTransformer;
|
||||
|
||||
public function __construct(
|
||||
PersonsToIdDataTransformer $personsToIdDataTransformer,
|
||||
IdToUserDataTransformer $idToUserDataTransformer,
|
||||
IdToUsersDataTransformer $idToUsersDataTransformer,
|
||||
IdToLocationDataTransformer $idToLocationDataTransformer,
|
||||
ThirdPartiesToIdDataTransformer $partiesToIdDataTransformer,
|
||||
IdToCalendarRangeDataTransformer $idToCalendarRangeDataTransformer
|
||||
private readonly PersonsToIdDataTransformer $personsToIdDataTransformer,
|
||||
private readonly IdToUserDataTransformer $idToUserDataTransformer,
|
||||
private readonly IdToUsersDataTransformer $idToUsersDataTransformer,
|
||||
private readonly IdToLocationDataTransformer $idToLocationDataTransformer,
|
||||
private readonly ThirdPartiesToIdDataTransformer $partiesToIdDataTransformer,
|
||||
private readonly IdToCalendarRangeDataTransformer $calendarRangeDataTransformer
|
||||
) {
|
||||
$this->personsToIdDataTransformer = $personsToIdDataTransformer;
|
||||
$this->idToUserDataTransformer = $idToUserDataTransformer;
|
||||
$this->idToUsersDataTransformer = $idToUsersDataTransformer;
|
||||
$this->idToLocationDataTransformer = $idToLocationDataTransformer;
|
||||
$this->partiesToIdDataTransformer = $partiesToIdDataTransformer;
|
||||
$this->calendarRangeDataTransformer = $idToCalendarRangeDataTransformer;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
@@ -91,42 +72,42 @@ class CalendarType extends AbstractType
|
||||
$builder->add('startDate', HiddenType::class);
|
||||
$builder->get('startDate')
|
||||
->addModelTransformer(new CallbackTransformer(
|
||||
static function (?DateTimeImmutable $dateTimeImmutable): string {
|
||||
static function (?\DateTimeImmutable $dateTimeImmutable): string {
|
||||
if (null !== $dateTimeImmutable) {
|
||||
$res = date_format($dateTimeImmutable, DateTimeImmutable::ATOM);
|
||||
$res = date_format($dateTimeImmutable, \DateTimeImmutable::ATOM);
|
||||
} else {
|
||||
$res = '';
|
||||
}
|
||||
|
||||
return $res;
|
||||
},
|
||||
static function (?string $dateAsString): ?DateTimeImmutable {
|
||||
static function (?string $dateAsString): ?\DateTimeImmutable {
|
||||
if ('' === $dateAsString || null === $dateAsString) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return DateTimeImmutable::createFromFormat(DateTimeImmutable::ATOM, $dateAsString);
|
||||
return \DateTimeImmutable::createFromFormat(\DateTimeImmutable::ATOM, $dateAsString);
|
||||
}
|
||||
));
|
||||
|
||||
$builder->add('endDate', HiddenType::class);
|
||||
$builder->get('endDate')
|
||||
->addModelTransformer(new CallbackTransformer(
|
||||
static function (?DateTimeImmutable $dateTimeImmutable): string {
|
||||
static function (?\DateTimeImmutable $dateTimeImmutable): string {
|
||||
if (null !== $dateTimeImmutable) {
|
||||
$res = date_format($dateTimeImmutable, DateTimeImmutable::ATOM);
|
||||
$res = date_format($dateTimeImmutable, \DateTimeImmutable::ATOM);
|
||||
} else {
|
||||
$res = '';
|
||||
}
|
||||
|
||||
return $res;
|
||||
},
|
||||
static function (?string $dateAsString): ?DateTimeImmutable {
|
||||
static function (?string $dateAsString): ?\DateTimeImmutable {
|
||||
if ('' === $dateAsString || null === $dateAsString) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return DateTimeImmutable::createFromFormat(DateTimeImmutable::ATOM, $dateAsString);
|
||||
return \DateTimeImmutable::createFromFormat(\DateTimeImmutable::ATOM, $dateAsString);
|
||||
}
|
||||
));
|
||||
|
||||
|
@@ -19,16 +19,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface
|
||||
{
|
||||
protected TranslatorInterface $translator;
|
||||
|
||||
private Security $security;
|
||||
|
||||
public function __construct(
|
||||
Security $security,
|
||||
TranslatorInterface $translator
|
||||
) {
|
||||
$this->security = $security;
|
||||
$this->translator = $translator;
|
||||
public function __construct(private readonly Security $security, protected TranslatorInterface $translator)
|
||||
{
|
||||
}
|
||||
|
||||
public function buildMenu($menuId, MenuItem $menu, array $parameters)
|
||||
|
@@ -19,16 +19,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class PersonMenuBuilder implements LocalMenuBuilderInterface
|
||||
{
|
||||
protected TranslatorInterface $translator;
|
||||
|
||||
private Security $security;
|
||||
|
||||
public function __construct(
|
||||
Security $security,
|
||||
TranslatorInterface $translator
|
||||
) {
|
||||
$this->security = $security;
|
||||
$this->translator = $translator;
|
||||
public function __construct(private readonly Security $security, protected TranslatorInterface $translator)
|
||||
{
|
||||
}
|
||||
|
||||
public function buildMenu($menuId, MenuItem $menu, array $parameters)
|
||||
|
@@ -18,16 +18,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class UserMenuBuilder implements LocalMenuBuilderInterface
|
||||
{
|
||||
public TranslatorInterface $translator;
|
||||
|
||||
private Security $security;
|
||||
|
||||
public function __construct(
|
||||
Security $security,
|
||||
TranslatorInterface $translator
|
||||
) {
|
||||
$this->security = $security;
|
||||
$this->translator = $translator;
|
||||
public function __construct(private readonly Security $security, public TranslatorInterface $translator)
|
||||
{
|
||||
}
|
||||
|
||||
public function buildMenu($menuId, MenuItem $menu, array $parameters)
|
||||
|
@@ -21,7 +21,6 @@ namespace Chill\CalendarBundle\Messenger\Doctrine;
|
||||
use Chill\CalendarBundle\Entity\Calendar;
|
||||
use Chill\CalendarBundle\Messenger\Message\CalendarMessage;
|
||||
use Chill\CalendarBundle\Messenger\Message\CalendarRemovedMessage;
|
||||
use Doctrine\ORM\Event\LifecycleEventArgs;
|
||||
use Doctrine\ORM\Event\PostPersistEventArgs;
|
||||
use Doctrine\ORM\Event\PostRemoveEventArgs;
|
||||
use Doctrine\ORM\Event\PostUpdateEventArgs;
|
||||
@@ -30,14 +29,8 @@ use Symfony\Component\Security\Core\Security;
|
||||
|
||||
class CalendarEntityListener
|
||||
{
|
||||
private MessageBusInterface $messageBus;
|
||||
|
||||
private Security $security;
|
||||
|
||||
public function __construct(MessageBusInterface $messageBus, Security $security)
|
||||
public function __construct(private readonly MessageBusInterface $messageBus, private readonly Security $security)
|
||||
{
|
||||
$this->messageBus = $messageBus;
|
||||
$this->security = $security;
|
||||
}
|
||||
|
||||
public function postPersist(Calendar $calendar, PostPersistEventArgs $args): void
|
||||
|
@@ -21,7 +21,6 @@ namespace Chill\CalendarBundle\Messenger\Doctrine;
|
||||
use Chill\CalendarBundle\Entity\CalendarRange;
|
||||
use Chill\CalendarBundle\Messenger\Message\CalendarRangeMessage;
|
||||
use Chill\CalendarBundle\Messenger\Message\CalendarRangeRemovedMessage;
|
||||
use Doctrine\ORM\Event\LifecycleEventArgs;
|
||||
use Doctrine\ORM\Event\PostPersistEventArgs;
|
||||
use Doctrine\ORM\Event\PostRemoveEventArgs;
|
||||
use Doctrine\ORM\Event\PostUpdateEventArgs;
|
||||
@@ -30,14 +29,8 @@ use Symfony\Component\Security\Core\Security;
|
||||
|
||||
class CalendarRangeEntityListener
|
||||
{
|
||||
private MessageBusInterface $messageBus;
|
||||
|
||||
private Security $security;
|
||||
|
||||
public function __construct(MessageBusInterface $messageBus, Security $security)
|
||||
public function __construct(private readonly MessageBusInterface $messageBus, private readonly Security $security)
|
||||
{
|
||||
$this->messageBus = $messageBus;
|
||||
$this->security = $security;
|
||||
}
|
||||
|
||||
public function postPersist(CalendarRange $calendarRange, PostPersistEventArgs $eventArgs): void
|
||||
|
@@ -31,14 +31,8 @@ use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
|
||||
*/
|
||||
class CalendarRangeRemoveToRemoteHandler implements MessageHandlerInterface
|
||||
{
|
||||
private RemoteCalendarConnectorInterface $remoteCalendarConnector;
|
||||
|
||||
private UserRepository $userRepository;
|
||||
|
||||
public function __construct(RemoteCalendarConnectorInterface $remoteCalendarConnector, UserRepository $userRepository)
|
||||
public function __construct(private readonly RemoteCalendarConnectorInterface $remoteCalendarConnector, private readonly UserRepository $userRepository)
|
||||
{
|
||||
$this->remoteCalendarConnector = $remoteCalendarConnector;
|
||||
$this->userRepository = $userRepository;
|
||||
}
|
||||
|
||||
public function __invoke(CalendarRangeRemovedMessage $calendarRangeRemovedMessage)
|
||||
|
@@ -32,20 +32,8 @@ use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
|
||||
*/
|
||||
class CalendarRangeToRemoteHandler implements MessageHandlerInterface
|
||||
{
|
||||
private CalendarRangeRepository $calendarRangeRepository;
|
||||
|
||||
private EntityManagerInterface $entityManager;
|
||||
|
||||
private RemoteCalendarConnectorInterface $remoteCalendarConnector;
|
||||
|
||||
public function __construct(
|
||||
CalendarRangeRepository $calendarRangeRepository,
|
||||
RemoteCalendarConnectorInterface $remoteCalendarConnector,
|
||||
EntityManagerInterface $entityManager
|
||||
) {
|
||||
$this->calendarRangeRepository = $calendarRangeRepository;
|
||||
$this->remoteCalendarConnector = $remoteCalendarConnector;
|
||||
$this->entityManager = $entityManager;
|
||||
public function __construct(private readonly CalendarRangeRepository $calendarRangeRepository, private readonly RemoteCalendarConnectorInterface $remoteCalendarConnector, private readonly EntityManagerInterface $entityManager)
|
||||
{
|
||||
}
|
||||
|
||||
public function __invoke(CalendarRangeMessage $calendarRangeMessage): void
|
||||
|
@@ -31,17 +31,8 @@ use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
|
||||
*/
|
||||
class CalendarRemoveHandler implements MessageHandlerInterface
|
||||
{
|
||||
private CalendarRangeRepository $calendarRangeRepository;
|
||||
|
||||
private RemoteCalendarConnectorInterface $remoteCalendarConnector;
|
||||
|
||||
private UserRepositoryInterface $userRepository;
|
||||
|
||||
public function __construct(RemoteCalendarConnectorInterface $remoteCalendarConnector, CalendarRangeRepository $calendarRangeRepository, UserRepositoryInterface $userRepository)
|
||||
public function __construct(private readonly RemoteCalendarConnectorInterface $remoteCalendarConnector, private readonly CalendarRangeRepository $calendarRangeRepository, private readonly UserRepositoryInterface $userRepository)
|
||||
{
|
||||
$this->remoteCalendarConnector = $remoteCalendarConnector;
|
||||
$this->calendarRangeRepository = $calendarRangeRepository;
|
||||
$this->userRepository = $userRepository;
|
||||
}
|
||||
|
||||
public function __invoke(CalendarRemovedMessage $message)
|
||||
|
@@ -37,32 +37,8 @@ use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
|
||||
*/
|
||||
class CalendarToRemoteHandler implements MessageHandlerInterface
|
||||
{
|
||||
private RemoteCalendarConnectorInterface $calendarConnector;
|
||||
|
||||
private CalendarRangeRepository $calendarRangeRepository;
|
||||
|
||||
private CalendarRepository $calendarRepository;
|
||||
|
||||
private EntityManagerInterface $entityManager;
|
||||
|
||||
private InviteRepository $inviteRepository;
|
||||
|
||||
private UserRepository $userRepository;
|
||||
|
||||
public function __construct(
|
||||
CalendarRangeRepository $calendarRangeRepository,
|
||||
CalendarRepository $calendarRepository,
|
||||
EntityManagerInterface $entityManager,
|
||||
InviteRepository $inviteRepository,
|
||||
RemoteCalendarConnectorInterface $calendarConnector,
|
||||
UserRepository $userRepository
|
||||
) {
|
||||
$this->calendarConnector = $calendarConnector;
|
||||
$this->calendarRepository = $calendarRepository;
|
||||
$this->calendarRangeRepository = $calendarRangeRepository;
|
||||
$this->entityManager = $entityManager;
|
||||
$this->userRepository = $userRepository;
|
||||
$this->inviteRepository = $inviteRepository;
|
||||
public function __construct(private readonly CalendarRangeRepository $calendarRangeRepository, private readonly CalendarRepository $calendarRepository, private readonly EntityManagerInterface $entityManager, private readonly InviteRepository $inviteRepository, private readonly RemoteCalendarConnectorInterface $calendarConnector, private readonly UserRepository $userRepository)
|
||||
{
|
||||
}
|
||||
|
||||
public function __invoke(CalendarMessage $calendarMessage)
|
||||
|
@@ -31,17 +31,8 @@ use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
|
||||
*/
|
||||
class InviteUpdateHandler implements MessageHandlerInterface
|
||||
{
|
||||
private EntityManagerInterface $em;
|
||||
|
||||
private InviteRepository $inviteRepository;
|
||||
|
||||
private RemoteCalendarConnectorInterface $remoteCalendarConnector;
|
||||
|
||||
public function __construct(EntityManagerInterface $em, InviteRepository $inviteRepository, RemoteCalendarConnectorInterface $remoteCalendarConnector)
|
||||
public function __construct(private readonly EntityManagerInterface $em, private readonly InviteRepository $inviteRepository, private readonly RemoteCalendarConnectorInterface $remoteCalendarConnector)
|
||||
{
|
||||
$this->em = $em;
|
||||
$this->inviteRepository = $inviteRepository;
|
||||
$this->remoteCalendarConnector = $remoteCalendarConnector;
|
||||
}
|
||||
|
||||
public function __invoke(InviteUpdateMessage $inviteUpdateMessage): void
|
||||
|
@@ -36,40 +36,8 @@ use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
|
||||
*/
|
||||
class MSGraphChangeNotificationHandler implements MessageHandlerInterface
|
||||
{
|
||||
private CalendarRangeRepository $calendarRangeRepository;
|
||||
|
||||
private CalendarRangeSyncer $calendarRangeSyncer;
|
||||
|
||||
private CalendarRepository $calendarRepository;
|
||||
|
||||
private CalendarSyncer $calendarSyncer;
|
||||
|
||||
private EntityManagerInterface $em;
|
||||
|
||||
private LoggerInterface $logger;
|
||||
|
||||
private MapCalendarToUser $mapCalendarToUser;
|
||||
|
||||
private UserRepository $userRepository;
|
||||
|
||||
public function __construct(
|
||||
CalendarRangeRepository $calendarRangeRepository,
|
||||
CalendarRangeSyncer $calendarRangeSyncer,
|
||||
CalendarRepository $calendarRepository,
|
||||
CalendarSyncer $calendarSyncer,
|
||||
EntityManagerInterface $em,
|
||||
LoggerInterface $logger,
|
||||
MapCalendarToUser $mapCalendarToUser,
|
||||
UserRepository $userRepository
|
||||
) {
|
||||
$this->calendarRangeRepository = $calendarRangeRepository;
|
||||
$this->calendarRangeSyncer = $calendarRangeSyncer;
|
||||
$this->calendarRepository = $calendarRepository;
|
||||
$this->calendarSyncer = $calendarSyncer;
|
||||
$this->em = $em;
|
||||
$this->logger = $logger;
|
||||
$this->mapCalendarToUser = $mapCalendarToUser;
|
||||
$this->userRepository = $userRepository;
|
||||
public function __construct(private readonly CalendarRangeRepository $calendarRangeRepository, private readonly CalendarRangeSyncer $calendarRangeSyncer, private readonly CalendarRepository $calendarRepository, private readonly CalendarSyncer $calendarSyncer, private readonly EntityManagerInterface $em, private readonly LoggerInterface $logger, private readonly MapCalendarToUser $mapCalendarToUser, private readonly UserRepository $userRepository)
|
||||
{
|
||||
}
|
||||
|
||||
public function __invoke(MSGraphChangeNotificationMessage $changeNotificationMessage): void
|
||||
@@ -77,7 +45,7 @@ class MSGraphChangeNotificationHandler implements MessageHandlerInterface
|
||||
$user = $this->userRepository->find($changeNotificationMessage->getUserId());
|
||||
|
||||
if (null === $user) {
|
||||
$this->logger->warning(self::class . ' notification concern non-existent user, skipping');
|
||||
$this->logger->warning(self::class.' notification concern non-existent user, skipping');
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -86,7 +54,7 @@ class MSGraphChangeNotificationHandler implements MessageHandlerInterface
|
||||
$secret = $this->mapCalendarToUser->getSubscriptionSecret($user);
|
||||
|
||||
if ($secret !== ($notification['clientState'] ?? -1)) {
|
||||
$this->logger->warning(self::class . ' could not validate secret, skipping');
|
||||
$this->logger->warning(self::class.' could not validate secret, skipping');
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -101,7 +69,7 @@ class MSGraphChangeNotificationHandler implements MessageHandlerInterface
|
||||
$this->calendarSyncer->handleCalendarSync($calendar, $notification, $user);
|
||||
$this->em->flush();
|
||||
} else {
|
||||
$this->logger->info(self::class . ' id not found in any calendar nor calendar range');
|
||||
$this->logger->info(self::class.' id not found in any calendar nor calendar range');
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -24,15 +24,13 @@ use Chill\MainBundle\Entity\User;
|
||||
|
||||
class CalendarMessage
|
||||
{
|
||||
public const CALENDAR_PERSIST = 'CHILL_CALENDAR_CALENDAR_PERSIST';
|
||||
final public const CALENDAR_PERSIST = 'CHILL_CALENDAR_CALENDAR_PERSIST';
|
||||
|
||||
public const CALENDAR_UPDATE = 'CHILL_CALENDAR_CALENDAR_UPDATE';
|
||||
final public const CALENDAR_UPDATE = 'CHILL_CALENDAR_CALENDAR_UPDATE';
|
||||
|
||||
private string $action;
|
||||
private readonly int $byUserId;
|
||||
|
||||
private int $byUserId;
|
||||
|
||||
private int $calendarId;
|
||||
private readonly int $calendarId;
|
||||
|
||||
private array $newInvitesIds = [];
|
||||
|
||||
@@ -47,12 +45,11 @@ class CalendarMessage
|
||||
|
||||
public function __construct(
|
||||
Calendar $calendar,
|
||||
string $action,
|
||||
private readonly string $action,
|
||||
User $byUser
|
||||
) {
|
||||
$this->calendarId = $calendar->getId();
|
||||
$this->byUserId = $byUser->getId();
|
||||
$this->action = $action;
|
||||
$this->previousCalendarRangeId = null !== $calendar->previousCalendarRange ?
|
||||
$calendar->previousCalendarRange->getId() : null;
|
||||
$this->previousMainUserId = null !== $calendar->previousMainUser ?
|
||||
|
@@ -23,19 +23,16 @@ use Chill\MainBundle\Entity\User;
|
||||
|
||||
class CalendarRangeMessage
|
||||
{
|
||||
public const CALENDAR_RANGE_PERSIST = 'CHILL_CALENDAR_CALENDAR_RANGE_PERSIST';
|
||||
final public const CALENDAR_RANGE_PERSIST = 'CHILL_CALENDAR_CALENDAR_RANGE_PERSIST';
|
||||
|
||||
public const CALENDAR_RANGE_UPDATE = 'CHILL_CALENDAR_CALENDAR_RANGE_UPDATE';
|
||||
|
||||
private string $action;
|
||||
final public const CALENDAR_RANGE_UPDATE = 'CHILL_CALENDAR_CALENDAR_RANGE_UPDATE';
|
||||
|
||||
private ?int $byUserId = null;
|
||||
|
||||
private int $calendarRangeId;
|
||||
private readonly int $calendarRangeId;
|
||||
|
||||
public function __construct(CalendarRange $calendarRange, string $action, ?User $byUser)
|
||||
public function __construct(CalendarRange $calendarRange, private readonly string $action, ?User $byUser)
|
||||
{
|
||||
$this->action = $action;
|
||||
$this->calendarRangeId = $calendarRange->getId();
|
||||
|
||||
if (null !== $byUser) {
|
||||
|
@@ -25,11 +25,11 @@ class CalendarRangeRemovedMessage
|
||||
{
|
||||
private ?int $byUserId = null;
|
||||
|
||||
private int $calendarRangeUserId;
|
||||
private readonly int $calendarRangeUserId;
|
||||
|
||||
private array $remoteAttributes;
|
||||
private readonly array $remoteAttributes;
|
||||
|
||||
private string $remoteId;
|
||||
private readonly string $remoteId;
|
||||
|
||||
public function __construct(CalendarRange $calendarRange, ?User $byUser)
|
||||
{
|
||||
|
@@ -27,11 +27,11 @@ class CalendarRemovedMessage
|
||||
|
||||
private ?int $byUserId = null;
|
||||
|
||||
private int $calendarUserId;
|
||||
private readonly int $calendarUserId;
|
||||
|
||||
private array $remoteAttributes;
|
||||
private readonly array $remoteAttributes;
|
||||
|
||||
private string $remoteId;
|
||||
private readonly string $remoteId;
|
||||
|
||||
public function __construct(Calendar $calendar, ?User $byUser)
|
||||
{
|
||||
|
@@ -23,9 +23,9 @@ use Chill\MainBundle\Entity\User;
|
||||
|
||||
class InviteUpdateMessage
|
||||
{
|
||||
private int $byUserId;
|
||||
private readonly int $byUserId;
|
||||
|
||||
private int $inviteId;
|
||||
private readonly int $inviteId;
|
||||
|
||||
public function __construct(Invite $invite, User $byUser)
|
||||
{
|
||||
|
@@ -20,14 +20,8 @@ namespace Chill\CalendarBundle\Messenger\Message;
|
||||
|
||||
class MSGraphChangeNotificationMessage
|
||||
{
|
||||
private array $content;
|
||||
|
||||
private int $userId;
|
||||
|
||||
public function __construct(array $content, int $userId)
|
||||
public function __construct(private readonly array $content, private readonly int $userId)
|
||||
{
|
||||
$this->content = $content;
|
||||
$this->userId = $userId;
|
||||
}
|
||||
|
||||
public function getContent(): array
|
||||
|
@@ -24,14 +24,8 @@ use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||
|
||||
class AddressConverter
|
||||
{
|
||||
private AddressRender $addressRender;
|
||||
|
||||
private TranslatableStringHelperInterface $translatableStringHelper;
|
||||
|
||||
public function __construct(AddressRender $addressRender, TranslatableStringHelperInterface $translatableStringHelper)
|
||||
public function __construct(private readonly AddressRender $addressRender, private readonly TranslatableStringHelperInterface $translatableStringHelper)
|
||||
{
|
||||
$this->addressRender = $addressRender;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function addressToRemote(Address $address): array
|
||||
|
@@ -19,8 +19,6 @@ declare(strict_types=1);
|
||||
namespace Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph;
|
||||
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use DateTimeImmutable;
|
||||
use LogicException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
||||
@@ -30,39 +28,23 @@ use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
||||
*/
|
||||
class EventsOnUserSubscriptionCreator
|
||||
{
|
||||
private LoggerInterface $logger;
|
||||
|
||||
private MachineHttpClient $machineHttpClient;
|
||||
|
||||
private MapCalendarToUser $mapCalendarToUser;
|
||||
|
||||
private UrlGeneratorInterface $urlGenerator;
|
||||
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
MachineHttpClient $machineHttpClient,
|
||||
MapCalendarToUser $mapCalendarToUser,
|
||||
UrlGeneratorInterface $urlGenerator
|
||||
) {
|
||||
$this->logger = $logger;
|
||||
$this->machineHttpClient = $machineHttpClient;
|
||||
$this->mapCalendarToUser = $mapCalendarToUser;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
public function __construct(private readonly LoggerInterface $logger, private readonly MachineHttpClient $machineHttpClient, private readonly MapCalendarToUser $mapCalendarToUser, private readonly UrlGeneratorInterface $urlGenerator)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{secret: string, id: string, expiration: int}
|
||||
*
|
||||
* @throws ClientExceptionInterface
|
||||
* @throws \Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface
|
||||
* @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
|
||||
* @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
|
||||
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
|
||||
*
|
||||
* @return array<secret: string, id: string, expiration: int>
|
||||
*/
|
||||
public function createSubscriptionForUser(User $user, DateTimeImmutable $expiration): array
|
||||
public function createSubscriptionForUser(User $user, \DateTimeImmutable $expiration): array
|
||||
{
|
||||
if (null === $userId = $this->mapCalendarToUser->getUserId($user)) {
|
||||
throw new LogicException('no user id');
|
||||
throw new \LogicException('no user id');
|
||||
}
|
||||
|
||||
$subscription = [
|
||||
@@ -74,7 +56,7 @@ class EventsOnUserSubscriptionCreator
|
||||
),
|
||||
'resource' => "/users/{$userId}/calendar/events",
|
||||
'clientState' => $secret = base64_encode(openssl_random_pseudo_bytes(92, $cstrong)),
|
||||
'expirationDateTime' => $expiration->format(DateTimeImmutable::ATOM),
|
||||
'expirationDateTime' => $expiration->format(\DateTimeImmutable::ATOM),
|
||||
];
|
||||
|
||||
try {
|
||||
@@ -97,26 +79,26 @@ class EventsOnUserSubscriptionCreator
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{secret: string, id: string, expiration: int}
|
||||
*
|
||||
* @throws ClientExceptionInterface
|
||||
* @throws \Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface
|
||||
* @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
|
||||
* @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
|
||||
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
|
||||
*
|
||||
* @return array<secret: string, id: string, expiration: int>
|
||||
*/
|
||||
public function renewSubscriptionForUser(User $user, DateTimeImmutable $expiration): array
|
||||
public function renewSubscriptionForUser(User $user, \DateTimeImmutable $expiration): array
|
||||
{
|
||||
if (null === $userId = $this->mapCalendarToUser->getUserId($user)) {
|
||||
throw new LogicException('no user id');
|
||||
throw new \LogicException('no user id');
|
||||
}
|
||||
|
||||
if (null === $subscriptionId = $this->mapCalendarToUser->getActiveSubscriptionId($user)) {
|
||||
throw new LogicException('no user id');
|
||||
throw new \LogicException('no user id');
|
||||
}
|
||||
|
||||
$subscription = [
|
||||
'expirationDateTime' => $expiration->format(DateTimeImmutable::ATOM),
|
||||
'expirationDateTime' => $expiration->format(\DateTimeImmutable::ATOM),
|
||||
];
|
||||
|
||||
try {
|
||||
|
@@ -22,11 +22,8 @@ use Chill\MainBundle\Entity\Location;
|
||||
|
||||
class LocationConverter
|
||||
{
|
||||
private AddressConverter $addressConverter;
|
||||
|
||||
public function __construct(AddressConverter $addressConverter)
|
||||
public function __construct(private readonly AddressConverter $addressConverter)
|
||||
{
|
||||
$this->addressConverter = $addressConverter;
|
||||
}
|
||||
|
||||
public function locationToRemote(Location $location): array
|
||||
|
@@ -13,7 +13,6 @@ namespace Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph;
|
||||
|
||||
use Chill\CalendarBundle\Exception\UserAbsenceSyncException;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Clock\ClockInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
|
||||
@@ -34,7 +33,7 @@ final readonly class MSUserAbsenceReader implements MSUserAbsenceReaderInterface
|
||||
/**
|
||||
* @throw UserAbsenceSyncException when the data cannot be reached or is not valid from microsoft
|
||||
*/
|
||||
public function isUserAbsent(User $user): bool|null
|
||||
public function isUserAbsent(User $user): ?bool
|
||||
{
|
||||
$id = $this->mapCalendarToUser->getUserId($user);
|
||||
|
||||
@@ -44,26 +43,24 @@ final readonly class MSUserAbsenceReader implements MSUserAbsenceReaderInterface
|
||||
|
||||
try {
|
||||
$automaticRepliesSettings = $this->machineHttpClient
|
||||
->request('GET', 'users/' . $id . '/mailboxSettings/automaticRepliesSetting')
|
||||
->request('GET', 'users/'.$id.'/mailboxSettings/automaticRepliesSetting')
|
||||
->toArray(true);
|
||||
} 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);
|
||||
} catch (ServerExceptionInterface $e) {
|
||||
throw new UserAbsenceSyncException("Server error receiving response for mailboxSettings", 0, $e);
|
||||
throw new UserAbsenceSyncException('Server error receiving response for mailboxSettings', 0, $e);
|
||||
}
|
||||
|
||||
if (!array_key_exists("status", $automaticRepliesSettings)) {
|
||||
throw new \LogicException("no key \"status\" on automatic replies settings: " . json_encode($automaticRepliesSettings, JSON_THROW_ON_ERROR));
|
||||
if (!array_key_exists('status', $automaticRepliesSettings)) {
|
||||
throw new \LogicException('no key "status" on automatic replies settings: '.json_encode($automaticRepliesSettings, JSON_THROW_ON_ERROR));
|
||||
}
|
||||
|
||||
return match ($automaticRepliesSettings['status']) {
|
||||
'disabled' => false,
|
||||
'alwaysEnabled' => true,
|
||||
'scheduled' =>
|
||||
RemoteEventConverter::convertStringDateWithoutTimezone($automaticRepliesSettings['scheduledStartDateTime']['dateTime']) < $this->clock->now()
|
||||
'scheduled' => RemoteEventConverter::convertStringDateWithoutTimezone($automaticRepliesSettings['scheduledStartDateTime']['dateTime']) < $this->clock->now()
|
||||
&& RemoteEventConverter::convertStringDateWithoutTimezone($automaticRepliesSettings['scheduledEndDateTime']['dateTime']) > $this->clock->now(),
|
||||
default => throw new UserAbsenceSyncException("this status is not documented by Microsoft")
|
||||
default => throw new UserAbsenceSyncException('this status is not documented by Microsoft')
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -18,5 +18,5 @@ interface MSUserAbsenceReaderInterface
|
||||
/**
|
||||
* @throw UserAbsenceSyncException when the data cannot be reached or is not valid from microsoft
|
||||
*/
|
||||
public function isUserAbsent(User $user): bool|null;
|
||||
public function isUserAbsent(User $user): ?bool;
|
||||
}
|
||||
|
@@ -37,13 +37,13 @@ readonly class MSUserAbsenceSync
|
||||
return;
|
||||
}
|
||||
|
||||
$this->logger->info("will change user absence", ['userId' => $user->getId()]);
|
||||
$this->logger->info('will change user absence', ['userId' => $user->getId()]);
|
||||
|
||||
if ($absence) {
|
||||
$this->logger->debug("make user absent", ['userId' => $user->getId()]);
|
||||
$this->logger->debug('make user absent', ['userId' => $user->getId()]);
|
||||
$user->setAbsenceStart($this->clock->now());
|
||||
} else {
|
||||
$this->logger->debug("make user present", ['userId' => $user->getId()]);
|
||||
$this->logger->debug('make user present', ['userId' => $user->getId()]);
|
||||
$user->setAbsenceStart(null);
|
||||
}
|
||||
}
|
||||
|
@@ -19,7 +19,6 @@ declare(strict_types=1);
|
||||
namespace Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph;
|
||||
|
||||
use League\OAuth2\Client\Tool\BearerAuthorizationTrait;
|
||||
use LogicException;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||
use Symfony\Contracts\HttpClient\ResponseStreamInterface;
|
||||
@@ -28,22 +27,16 @@ class MachineHttpClient implements HttpClientInterface
|
||||
{
|
||||
use BearerAuthorizationTrait;
|
||||
|
||||
private HttpClientInterface $decoratedClient;
|
||||
private readonly HttpClientInterface $decoratedClient;
|
||||
|
||||
private MachineTokenStorage $machineTokenStorage;
|
||||
|
||||
/**
|
||||
* @param HttpClientInterface $decoratedClient
|
||||
*/
|
||||
public function __construct(MachineTokenStorage $machineTokenStorage, ?HttpClientInterface $decoratedClient = null)
|
||||
public function __construct(private readonly MachineTokenStorage $machineTokenStorage, ?HttpClientInterface $decoratedClient = null)
|
||||
{
|
||||
$this->decoratedClient = $decoratedClient ?? \Symfony\Component\HttpClient\HttpClient::create();
|
||||
$this->machineTokenStorage = $machineTokenStorage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
|
||||
* @throws LogicException if method is not supported
|
||||
* @throws \LogicException if method is not supported
|
||||
*/
|
||||
public function request(string $method, string $url, array $options = []): ResponseInterface
|
||||
{
|
||||
@@ -69,7 +62,7 @@ class MachineHttpClient implements HttpClientInterface
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new LogicException("Method not supported: {$method}");
|
||||
throw new \LogicException("Method not supported: {$method}");
|
||||
}
|
||||
|
||||
return $this->decoratedClient->request($method, $url, $options);
|
||||
|
@@ -29,14 +29,8 @@ class MachineTokenStorage
|
||||
|
||||
private ?AccessTokenInterface $accessToken = null;
|
||||
|
||||
private Azure $azure;
|
||||
|
||||
private ChillRedis $chillRedis;
|
||||
|
||||
public function __construct(Azure $azure, ChillRedis $chillRedis)
|
||||
public function __construct(private readonly Azure $azure, private readonly ChillRedis $chillRedis)
|
||||
{
|
||||
$this->azure = $azure;
|
||||
$this->chillRedis = $chillRedis;
|
||||
}
|
||||
|
||||
public function getToken(): AccessTokenInterface
|
||||
|
@@ -19,46 +19,35 @@ declare(strict_types=1);
|
||||
namespace Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph;
|
||||
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use DateTimeImmutable;
|
||||
use LogicException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
use function array_key_exists;
|
||||
|
||||
/**
|
||||
* Write metadata to user, which allow to find his default calendar.
|
||||
*/
|
||||
class MapCalendarToUser
|
||||
{
|
||||
public const EXPIRATION_SUBSCRIPTION_EVENT = 'subscription_events_expiration';
|
||||
final public const EXPIRATION_SUBSCRIPTION_EVENT = 'subscription_events_expiration';
|
||||
|
||||
public const ID_SUBSCRIPTION_EVENT = 'subscription_events_id';
|
||||
final public const ID_SUBSCRIPTION_EVENT = 'subscription_events_id';
|
||||
|
||||
public const METADATA_KEY = 'msgraph';
|
||||
final public const METADATA_KEY = 'msgraph';
|
||||
|
||||
public const SECRET_SUBSCRIPTION_EVENT = 'subscription_events_secret';
|
||||
final public const SECRET_SUBSCRIPTION_EVENT = 'subscription_events_secret';
|
||||
|
||||
private LoggerInterface $logger;
|
||||
|
||||
private HttpClientInterface $machineHttpClient;
|
||||
|
||||
public function __construct(
|
||||
HttpClientInterface $machineHttpClient,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->machineHttpClient = $machineHttpClient;
|
||||
$this->logger = $logger;
|
||||
public function __construct(private readonly HttpClientInterface $machineHttpClient, private readonly LoggerInterface $logger)
|
||||
{
|
||||
}
|
||||
|
||||
public function getActiveSubscriptionId(User $user): string
|
||||
{
|
||||
if (!array_key_exists(self::METADATA_KEY, $user->getAttributes())) {
|
||||
throw new LogicException('do not contains msgraph metadata');
|
||||
if (!\array_key_exists(self::METADATA_KEY, $user->getAttributes())) {
|
||||
throw new \LogicException('do not contains msgraph metadata');
|
||||
}
|
||||
|
||||
if (!array_key_exists(self::ID_SUBSCRIPTION_EVENT, $user->getAttributes()[self::METADATA_KEY])) {
|
||||
throw new LogicException('do not contains metadata for subscription id');
|
||||
if (!\array_key_exists(self::ID_SUBSCRIPTION_EVENT, $user->getAttributes()[self::METADATA_KEY])) {
|
||||
throw new \LogicException('do not contains metadata for subscription id');
|
||||
}
|
||||
|
||||
return $user->getAttributes()[self::METADATA_KEY][self::ID_SUBSCRIPTION_EVENT];
|
||||
@@ -93,12 +82,12 @@ class MapCalendarToUser
|
||||
|
||||
public function getSubscriptionSecret(User $user): string
|
||||
{
|
||||
if (!array_key_exists(self::METADATA_KEY, $user->getAttributes())) {
|
||||
throw new LogicException('do not contains msgraph metadata');
|
||||
if (!\array_key_exists(self::METADATA_KEY, $user->getAttributes())) {
|
||||
throw new \LogicException('do not contains msgraph metadata');
|
||||
}
|
||||
|
||||
if (!array_key_exists(self::SECRET_SUBSCRIPTION_EVENT, $user->getAttributes()[self::METADATA_KEY])) {
|
||||
throw new LogicException('do not contains secret in msgraph');
|
||||
if (!\array_key_exists(self::SECRET_SUBSCRIPTION_EVENT, $user->getAttributes()[self::METADATA_KEY])) {
|
||||
throw new \LogicException('do not contains secret in msgraph');
|
||||
}
|
||||
|
||||
return $user->getAttributes()[self::METADATA_KEY][self::SECRET_SUBSCRIPTION_EVENT];
|
||||
@@ -124,25 +113,25 @@ class MapCalendarToUser
|
||||
|
||||
public function hasActiveSubscription(User $user): bool
|
||||
{
|
||||
if (!array_key_exists(self::METADATA_KEY, $user->getAttributes())) {
|
||||
if (!\array_key_exists(self::METADATA_KEY, $user->getAttributes())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!array_key_exists(self::EXPIRATION_SUBSCRIPTION_EVENT, $user->getAttributes()[self::METADATA_KEY])) {
|
||||
if (!\array_key_exists(self::EXPIRATION_SUBSCRIPTION_EVENT, $user->getAttributes()[self::METADATA_KEY])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $user->getAttributes()[self::METADATA_KEY][self::EXPIRATION_SUBSCRIPTION_EVENT]
|
||||
>= (new DateTimeImmutable('now'))->getTimestamp();
|
||||
>= (new \DateTimeImmutable('now'))->getTimestamp();
|
||||
}
|
||||
|
||||
public function hasSubscriptionSecret(User $user): bool
|
||||
{
|
||||
if (!array_key_exists(self::METADATA_KEY, $user->getAttributes())) {
|
||||
if (!\array_key_exists(self::METADATA_KEY, $user->getAttributes())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return array_key_exists(self::SECRET_SUBSCRIPTION_EVENT, $user->getAttributes()[self::METADATA_KEY]);
|
||||
return \array_key_exists(self::SECRET_SUBSCRIPTION_EVENT, $user->getAttributes()[self::METADATA_KEY]);
|
||||
}
|
||||
|
||||
public function hasUserId(User $user): bool
|
||||
@@ -151,11 +140,11 @@ class MapCalendarToUser
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!array_key_exists(self::METADATA_KEY, $user->getAttributes())) {
|
||||
if (!\array_key_exists(self::METADATA_KEY, $user->getAttributes())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return array_key_exists('id', $user->getAttributes()[self::METADATA_KEY]);
|
||||
return \array_key_exists('id', $user->getAttributes()[self::METADATA_KEY]);
|
||||
}
|
||||
|
||||
public function writeMetadata(User $user): User
|
||||
|
@@ -19,7 +19,6 @@ declare(strict_types=1);
|
||||
namespace Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph;
|
||||
|
||||
use League\OAuth2\Client\Tool\BearerAuthorizationTrait;
|
||||
use LogicException;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||
use Symfony\Contracts\HttpClient\ResponseStreamInterface;
|
||||
@@ -28,17 +27,11 @@ class OnBehalfOfUserHttpClient
|
||||
{
|
||||
use BearerAuthorizationTrait;
|
||||
|
||||
private HttpClientInterface $decoratedClient;
|
||||
private readonly HttpClientInterface $decoratedClient;
|
||||
|
||||
private OnBehalfOfUserTokenStorage $tokenStorage;
|
||||
|
||||
/**
|
||||
* @param HttpClientInterface $decoratedClient
|
||||
*/
|
||||
public function __construct(OnBehalfOfUserTokenStorage $tokenStorage, ?HttpClientInterface $decoratedClient = null)
|
||||
public function __construct(private readonly OnBehalfOfUserTokenStorage $tokenStorage, ?HttpClientInterface $decoratedClient = null)
|
||||
{
|
||||
$this->decoratedClient = $decoratedClient ?? \Symfony\Component\HttpClient\HttpClient::create();
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
}
|
||||
|
||||
public function request(string $method, string $url, array $options = []): ResponseInterface
|
||||
@@ -64,7 +57,7 @@ class OnBehalfOfUserHttpClient
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new LogicException("Method not supported: {$method}");
|
||||
throw new \LogicException("Method not supported: {$method}");
|
||||
}
|
||||
|
||||
return $this->decoratedClient->request($method, $url, $options);
|
||||
|
@@ -18,7 +18,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph;
|
||||
|
||||
use LogicException;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
use TheNetworg\OAuth2\Client\Provider\Azure;
|
||||
use TheNetworg\OAuth2\Client\Token\AccessToken;
|
||||
@@ -28,16 +27,10 @@ use TheNetworg\OAuth2\Client\Token\AccessToken;
|
||||
*/
|
||||
class OnBehalfOfUserTokenStorage
|
||||
{
|
||||
public const MS_GRAPH_ACCESS_TOKEN = 'msgraph_access_token';
|
||||
final public const MS_GRAPH_ACCESS_TOKEN = 'msgraph_access_token';
|
||||
|
||||
private Azure $azure;
|
||||
|
||||
private SessionInterface $session;
|
||||
|
||||
public function __construct(Azure $azure, SessionInterface $session)
|
||||
public function __construct(private readonly Azure $azure, private readonly SessionInterface $session)
|
||||
{
|
||||
$this->azure = $azure;
|
||||
$this->session = $session;
|
||||
}
|
||||
|
||||
public function getToken(): AccessToken
|
||||
@@ -46,7 +39,7 @@ class OnBehalfOfUserTokenStorage
|
||||
$token = $this->session->get(self::MS_GRAPH_ACCESS_TOKEN, null);
|
||||
|
||||
if (null === $token) {
|
||||
throw new LogicException('unexisting token');
|
||||
throw new \LogicException('unexisting token');
|
||||
}
|
||||
|
||||
if ($token->hasExpired()) {
|
||||
|
@@ -24,11 +24,7 @@ use Chill\CalendarBundle\Entity\Invite;
|
||||
use Chill\CalendarBundle\RemoteCalendar\Model\RemoteEvent;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\PersonBundle\Templating\Entity\PersonRenderInterface;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeZone;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Templating\EngineInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
/**
|
||||
@@ -41,44 +37,29 @@ class RemoteEventConverter
|
||||
* valid when the remote string contains also a timezone, like in
|
||||
* lastModifiedDate.
|
||||
*/
|
||||
public const REMOTE_DATETIMEZONE_FORMAT = 'Y-m-d\\TH:i:s.u?P';
|
||||
final public const REMOTE_DATETIMEZONE_FORMAT = 'Y-m-d\\TH:i:s.u?P';
|
||||
|
||||
/**
|
||||
* Same as above, but sometimes the date is expressed with only 6 milliseconds.
|
||||
*/
|
||||
public const REMOTE_DATETIMEZONE_FORMAT_ALT = 'Y-m-d\\TH:i:s.uP';
|
||||
final public const REMOTE_DATETIMEZONE_FORMAT_ALT = 'Y-m-d\\TH:i:s.uP';
|
||||
|
||||
private const REMOTE_DATE_FORMAT = 'Y-m-d\TH:i:s.u0';
|
||||
|
||||
private const REMOTE_DATETIME_WITHOUT_TZ_FORMAT = 'Y-m-d\TH:i:s.u?';
|
||||
|
||||
private DateTimeZone $defaultDateTimeZone;
|
||||
private readonly \DateTimeZone $defaultDateTimeZone;
|
||||
|
||||
private EngineInterface $engine;
|
||||
|
||||
private LocationConverter $locationConverter;
|
||||
|
||||
private LoggerInterface $logger;
|
||||
|
||||
private PersonRenderInterface $personRender;
|
||||
|
||||
private DateTimeZone $remoteDateTimeZone;
|
||||
|
||||
private TranslatorInterface $translator;
|
||||
private readonly \DateTimeZone $remoteDateTimeZone;
|
||||
|
||||
public function __construct(
|
||||
EngineInterface $engine,
|
||||
LocationConverter $locationConverter,
|
||||
LoggerInterface $logger,
|
||||
PersonRenderInterface $personRender,
|
||||
TranslatorInterface $translator
|
||||
private readonly \Twig\Environment $engine,
|
||||
private readonly LocationConverter $locationConverter,
|
||||
private readonly LoggerInterface $logger,
|
||||
private readonly PersonRenderInterface $personRender,
|
||||
private readonly TranslatorInterface $translator
|
||||
) {
|
||||
$this->engine = $engine;
|
||||
$this->locationConverter = $locationConverter;
|
||||
$this->logger = $logger;
|
||||
$this->translator = $translator;
|
||||
$this->personRender = $personRender;
|
||||
$this->defaultDateTimeZone = (new DateTimeImmutable())->getTimezone();
|
||||
$this->defaultDateTimeZone = (new \DateTimeImmutable())->getTimezone();
|
||||
$this->remoteDateTimeZone = self::getRemoteTimeZone();
|
||||
}
|
||||
|
||||
@@ -118,7 +99,7 @@ class RemoteEventConverter
|
||||
{
|
||||
$result = array_merge(
|
||||
[
|
||||
'subject' => '[Chill] ' .
|
||||
'subject' => '[Chill] '.
|
||||
implode(
|
||||
', ',
|
||||
$calendar->getPersons()->map(fn (Person $p) => $this->personRender->renderString($p, []))->toArray()
|
||||
@@ -134,7 +115,7 @@ class RemoteEventConverter
|
||||
'timeZone' => 'UTC',
|
||||
],
|
||||
'allowNewTimeProposals' => false,
|
||||
'transactionId' => 'calendar_' . $calendar->getId(),
|
||||
'transactionId' => 'calendar_'.$calendar->getId(),
|
||||
'body' => [
|
||||
'contentType' => 'text',
|
||||
'content' => $this->engine->render(
|
||||
@@ -167,45 +148,45 @@ class RemoteEventConverter
|
||||
public function convertAvailabilityToRemoteEvent(array $event): RemoteEvent
|
||||
{
|
||||
$startDate =
|
||||
DateTimeImmutable::createFromFormat(self::REMOTE_DATE_FORMAT, $event['start']['dateTime'], $this->remoteDateTimeZone)
|
||||
\DateTimeImmutable::createFromFormat(self::REMOTE_DATE_FORMAT, $event['start']['dateTime'], $this->remoteDateTimeZone)
|
||||
->setTimezone($this->defaultDateTimeZone);
|
||||
$endDate =
|
||||
DateTimeImmutable::createFromFormat(self::REMOTE_DATE_FORMAT, $event['end']['dateTime'], $this->remoteDateTimeZone)
|
||||
\DateTimeImmutable::createFromFormat(self::REMOTE_DATE_FORMAT, $event['end']['dateTime'], $this->remoteDateTimeZone)
|
||||
->setTimezone($this->defaultDateTimeZone);
|
||||
|
||||
return new RemoteEvent(
|
||||
uniqid('generated_'),
|
||||
$this->translator->trans('remote_ms_graph.freebusy_statuses.' . $event['status']),
|
||||
$this->translator->trans('remote_ms_graph.freebusy_statuses.'.$event['status']),
|
||||
'',
|
||||
$startDate,
|
||||
$endDate
|
||||
);
|
||||
}
|
||||
|
||||
public static function convertStringDateWithoutTimezone(string $date): DateTimeImmutable
|
||||
public static function convertStringDateWithoutTimezone(string $date): \DateTimeImmutable
|
||||
{
|
||||
$d = DateTimeImmutable::createFromFormat(
|
||||
$d = \DateTimeImmutable::createFromFormat(
|
||||
self::REMOTE_DATETIME_WITHOUT_TZ_FORMAT,
|
||||
$date,
|
||||
self::getRemoteTimeZone()
|
||||
);
|
||||
|
||||
if (false === $d) {
|
||||
throw new RuntimeException("could not convert string date to datetime: {$date}");
|
||||
throw new \RuntimeException("could not convert string date to datetime: {$date}");
|
||||
}
|
||||
|
||||
return $d->setTimezone((new DateTimeImmutable())->getTimezone());
|
||||
return $d->setTimezone((new \DateTimeImmutable())->getTimezone());
|
||||
}
|
||||
|
||||
public static function convertStringDateWithTimezone(string $date): DateTimeImmutable
|
||||
public static function convertStringDateWithTimezone(string $date): \DateTimeImmutable
|
||||
{
|
||||
$d = DateTimeImmutable::createFromFormat(self::REMOTE_DATETIMEZONE_FORMAT, $date);
|
||||
$d = \DateTimeImmutable::createFromFormat(self::REMOTE_DATETIMEZONE_FORMAT, $date);
|
||||
|
||||
if (false === $d) {
|
||||
throw new RuntimeException("could not convert string date to datetime: {$date}");
|
||||
throw new \RuntimeException("could not convert string date to datetime: {$date}");
|
||||
}
|
||||
|
||||
$d->setTimezone((new DateTimeImmutable())->getTimezone());
|
||||
$d->setTimezone((new \DateTimeImmutable())->getTimezone());
|
||||
|
||||
return $d;
|
||||
}
|
||||
@@ -213,10 +194,10 @@ class RemoteEventConverter
|
||||
public function convertToRemote(array $event): RemoteEvent
|
||||
{
|
||||
$startDate =
|
||||
DateTimeImmutable::createFromFormat(self::REMOTE_DATE_FORMAT, $event['start']['dateTime'], $this->remoteDateTimeZone)
|
||||
\DateTimeImmutable::createFromFormat(self::REMOTE_DATE_FORMAT, $event['start']['dateTime'], $this->remoteDateTimeZone)
|
||||
->setTimezone($this->defaultDateTimeZone);
|
||||
$endDate =
|
||||
DateTimeImmutable::createFromFormat(self::REMOTE_DATE_FORMAT, $event['end']['dateTime'], $this->remoteDateTimeZone)
|
||||
\DateTimeImmutable::createFromFormat(self::REMOTE_DATE_FORMAT, $event['end']['dateTime'], $this->remoteDateTimeZone)
|
||||
->setTimezone($this->defaultDateTimeZone);
|
||||
|
||||
return new RemoteEvent(
|
||||
@@ -229,26 +210,22 @@ class RemoteEventConverter
|
||||
);
|
||||
}
|
||||
|
||||
public function getLastModifiedDate(array $event): DateTimeImmutable
|
||||
public function getLastModifiedDate(array $event): \DateTimeImmutable
|
||||
{
|
||||
$date = DateTimeImmutable::createFromFormat(self::REMOTE_DATETIMEZONE_FORMAT, $event['lastModifiedDateTime']);
|
||||
$date = \DateTimeImmutable::createFromFormat(self::REMOTE_DATETIMEZONE_FORMAT, $event['lastModifiedDateTime']);
|
||||
|
||||
if (false === $date) {
|
||||
$date = DateTimeImmutable::createFromFormat(self::REMOTE_DATETIMEZONE_FORMAT_ALT, $event['lastModifiedDateTime']);
|
||||
$date = \DateTimeImmutable::createFromFormat(self::REMOTE_DATETIMEZONE_FORMAT_ALT, $event['lastModifiedDateTime']);
|
||||
}
|
||||
|
||||
if (false === $date) {
|
||||
$this->logger->error(self::class . ' Could not convert lastModifiedDate', [
|
||||
$this->logger->error(self::class.' Could not convert lastModifiedDate', [
|
||||
'actual' => $event['lastModifiedDateTime'],
|
||||
'format' => self::REMOTE_DATETIMEZONE_FORMAT,
|
||||
'format_alt' => self::REMOTE_DATETIMEZONE_FORMAT_ALT,
|
||||
]);
|
||||
|
||||
throw new RuntimeException(sprintf(
|
||||
'could not convert lastModifiedDate: %s, expected format: %s',
|
||||
$event['lastModifiedDateTime'],
|
||||
self::REMOTE_DATETIMEZONE_FORMAT . ' and ' . self::REMOTE_DATETIMEZONE_FORMAT_ALT
|
||||
));
|
||||
throw new \RuntimeException(sprintf('could not convert lastModifiedDate: %s, expected format: %s', $event['lastModifiedDateTime'], self::REMOTE_DATETIMEZONE_FORMAT.' and '.self::REMOTE_DATETIMEZONE_FORMAT_ALT));
|
||||
}
|
||||
|
||||
return $date;
|
||||
@@ -262,9 +239,9 @@ class RemoteEventConverter
|
||||
return 'Y-m-d\TH:i:s';
|
||||
}
|
||||
|
||||
public static function getRemoteTimeZone(): DateTimeZone
|
||||
public static function getRemoteTimeZone(): \DateTimeZone
|
||||
{
|
||||
return new DateTimeZone('UTC');
|
||||
return new \DateTimeZone('UTC');
|
||||
}
|
||||
|
||||
private function buildInviteToAttendee(Invite $invite): array
|
||||
|
@@ -24,29 +24,16 @@ use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\RemoteEventConverter;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use RuntimeException;
|
||||
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
class CalendarRangeSyncer
|
||||
{
|
||||
private EntityManagerInterface $em;
|
||||
|
||||
private LoggerInterface $logger;
|
||||
|
||||
private HttpClientInterface $machineHttpClient;
|
||||
|
||||
/**
|
||||
* @param MachineHttpClient $machineHttpClient
|
||||
*/
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
LoggerInterface $logger,
|
||||
HttpClientInterface $machineHttpClient
|
||||
) {
|
||||
$this->em = $em;
|
||||
$this->logger = $logger;
|
||||
$this->machineHttpClient = $machineHttpClient;
|
||||
public function __construct(private readonly EntityManagerInterface $em, private readonly LoggerInterface $logger, private readonly HttpClientInterface $machineHttpClient)
|
||||
{
|
||||
}
|
||||
|
||||
public function handleCalendarRangeSync(CalendarRange $calendarRange, array $notification, User $user): void
|
||||
@@ -59,7 +46,7 @@ class CalendarRangeSyncer
|
||||
}
|
||||
$calendarRange->preventEnqueueChanges = true;
|
||||
|
||||
$this->logger->info(self::class . ' remove a calendar range because deleted on remote calendar');
|
||||
$this->logger->info(self::class.' remove a calendar range because deleted on remote calendar');
|
||||
$this->em->remove($calendarRange);
|
||||
|
||||
break;
|
||||
@@ -71,7 +58,7 @@ class CalendarRangeSyncer
|
||||
$notification['resource']
|
||||
)->toArray();
|
||||
} catch (ClientExceptionInterface $clientException) {
|
||||
$this->logger->warning(self::class . ' could not retrieve event from ms graph. Already deleted ?', [
|
||||
$this->logger->warning(self::class.' could not retrieve event from ms graph. Already deleted ?', [
|
||||
'calendarRangeId' => $calendarRange->getId(),
|
||||
'remoteEventId' => $notification['resource'],
|
||||
]);
|
||||
@@ -82,7 +69,7 @@ class CalendarRangeSyncer
|
||||
$lastModified = RemoteEventConverter::convertStringDateWithTimezone($new['lastModifiedDateTime']);
|
||||
|
||||
if ($calendarRange->getRemoteAttributes()['lastModifiedDateTime'] === $lastModified->getTimestamp()) {
|
||||
$this->logger->info(self::class . ' change key is equals. Source is probably a local update', [
|
||||
$this->logger->info(self::class.' change key is equals. Source is probably a local update', [
|
||||
'calendarRangeId' => $calendarRange->getId(),
|
||||
'remoteEventId' => $notification['resource'],
|
||||
]);
|
||||
@@ -104,7 +91,7 @@ class CalendarRangeSyncer
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new RuntimeException('This changeType is not suppored: ' . $notification['changeType']);
|
||||
throw new \RuntimeException('This changeType is not suppored: '.$notification['changeType']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -23,44 +23,23 @@ 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)
|
||||
public function __construct(private readonly LoggerInterface $logger, private readonly HttpClientInterface $machineHttpClient, private readonly 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']);
|
||||
}
|
||||
match ($notification['changeType']) {
|
||||
'deleted' => $this->handleDeleteCalendar($calendar, $notification, $user),
|
||||
'updated' => $this->handleUpdateCalendar($calendar, $notification, $user),
|
||||
default => throw new \RuntimeException('this change type is not supported: '.$notification['changeType']),
|
||||
};
|
||||
}
|
||||
|
||||
private function handleDeleteCalendar(Calendar $calendar, array $notification, User $user): void
|
||||
@@ -79,7 +58,7 @@ class CalendarSyncer
|
||||
$notification['resource']
|
||||
)->toArray();
|
||||
} catch (ClientExceptionInterface $clientException) {
|
||||
$this->logger->warning(self::class . ' could not retrieve event from ms graph. Already deleted ?', [
|
||||
$this->logger->warning(self::class.' could not retrieve event from ms graph. Already deleted ?', [
|
||||
'calendarId' => $calendar->getId(),
|
||||
'remoteEventId' => $notification['resource'],
|
||||
]);
|
||||
@@ -96,7 +75,7 @@ class CalendarSyncer
|
||||
);
|
||||
|
||||
if ($calendar->getRemoteAttributes()['lastModifiedDateTime'] === $lastModified->getTimestamp()) {
|
||||
$this->logger->info(self::class . ' change key is equals. Source is probably a local update', [
|
||||
$this->logger->info(self::class.' change key is equals. Source is probably a local update', [
|
||||
'calendarRangeId' => $calendar->getId(),
|
||||
'remoteEventId' => $notification['resource'],
|
||||
]);
|
||||
@@ -137,7 +116,7 @@ class CalendarSyncer
|
||||
}
|
||||
|
||||
$email = $attendee['emailAddress']['address'];
|
||||
$emails[] = strtolower($email);
|
||||
$emails[] = strtolower((string) $email);
|
||||
$user = $this->userRepository->findOneByUsernameOrEmail($email);
|
||||
|
||||
if (null === $user) {
|
||||
@@ -150,38 +129,17 @@ class CalendarSyncer
|
||||
|
||||
$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;
|
||||
}
|
||||
match ($status) {
|
||||
'none', 'notResponded' => $invite->setStatus(Invite::PENDING),
|
||||
'tentativelyAccepted' => $invite->setStatus(Invite::TENTATIVELY_ACCEPTED),
|
||||
'accepted' => $invite->setStatus(Invite::ACCEPTED),
|
||||
'declined' => $invite->setStatus(Invite::DECLINED),
|
||||
default => throw new \LogicException('should not happens, not implemented: '.$status),
|
||||
};
|
||||
}
|
||||
|
||||
foreach ($calendar->getUsers() as $user) {
|
||||
if (!in_array(strtolower($user->getEmailCanonical()), $emails, true)) {
|
||||
if (!\in_array(strtolower($user->getEmailCanonical()), $emails, true)) {
|
||||
$calendar->removeUser($user);
|
||||
}
|
||||
}
|
||||
|
@@ -28,8 +28,6 @@ use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\RemoteEventConverter;
|
||||
use Chill\CalendarBundle\Repository\CalendarRangeRepository;
|
||||
use Chill\CalendarBundle\Repository\CalendarRepository;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use DateTimeImmutable;
|
||||
use Exception;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
@@ -38,62 +36,16 @@ use Symfony\Component\Security\Core\Security;
|
||||
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
use function array_key_exists;
|
||||
use function count;
|
||||
|
||||
class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
{
|
||||
private array $cacheScheduleTimeForUser = [];
|
||||
|
||||
private CalendarRangeRepository $calendarRangeRepository;
|
||||
|
||||
private CalendarRepository $calendarRepository;
|
||||
|
||||
private LoggerInterface $logger;
|
||||
|
||||
private HttpClientInterface $machineHttpClient;
|
||||
|
||||
private MapCalendarToUser $mapCalendarToUser;
|
||||
|
||||
private RemoteEventConverter $remoteEventConverter;
|
||||
|
||||
private OnBehalfOfUserTokenStorage $tokenStorage;
|
||||
|
||||
private TranslatorInterface $translator;
|
||||
|
||||
private UrlGeneratorInterface $urlGenerator;
|
||||
|
||||
private OnBehalfOfUserHttpClient $userHttpClient;
|
||||
|
||||
private Security $security;
|
||||
|
||||
public function __construct(
|
||||
CalendarRepository $calendarRepository,
|
||||
CalendarRangeRepository $calendarRangeRepository,
|
||||
HttpClientInterface $machineHttpClient,
|
||||
MapCalendarToUser $mapCalendarToUser,
|
||||
LoggerInterface $logger,
|
||||
OnBehalfOfUserTokenStorage $tokenStorage,
|
||||
OnBehalfOfUserHttpClient $userHttpClient,
|
||||
RemoteEventConverter $remoteEventConverter,
|
||||
TranslatorInterface $translator,
|
||||
UrlGeneratorInterface $urlGenerator,
|
||||
Security $security
|
||||
) {
|
||||
$this->calendarRepository = $calendarRepository;
|
||||
$this->calendarRangeRepository = $calendarRangeRepository;
|
||||
$this->machineHttpClient = $machineHttpClient;
|
||||
$this->mapCalendarToUser = $mapCalendarToUser;
|
||||
$this->logger = $logger;
|
||||
$this->remoteEventConverter = $remoteEventConverter;
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->translator = $translator;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->userHttpClient = $userHttpClient;
|
||||
$this->security = $security;
|
||||
public function __construct(private readonly CalendarRepository $calendarRepository, private readonly CalendarRangeRepository $calendarRangeRepository, private readonly HttpClientInterface $machineHttpClient, private readonly MapCalendarToUser $mapCalendarToUser, private readonly LoggerInterface $logger, private readonly OnBehalfOfUserTokenStorage $tokenStorage, private readonly OnBehalfOfUserHttpClient $userHttpClient, private readonly RemoteEventConverter $remoteEventConverter, private readonly TranslatorInterface $translator, private readonly UrlGeneratorInterface $urlGenerator, private readonly Security $security)
|
||||
{
|
||||
}
|
||||
|
||||
public function countEventsForUser(User $user, DateTimeImmutable $startDate, DateTimeImmutable $endDate): int
|
||||
public function countEventsForUser(User $user, \DateTimeImmutable $startDate, \DateTimeImmutable $endDate): int
|
||||
{
|
||||
$userId = $this->mapCalendarToUser->getUserId($user);
|
||||
|
||||
@@ -104,7 +56,7 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
try {
|
||||
$data = $this->userHttpClient->request(
|
||||
'GET',
|
||||
'users/' . $userId . '/calendarView',
|
||||
'users/'.$userId.'/calendarView',
|
||||
[
|
||||
'query' => [
|
||||
'startDateTime' => $startDate->setTimezone(RemoteEventConverter::getRemoteTimeZone())->format(RemoteEventConverter::getRemoteDateTimeSimpleFormat()),
|
||||
@@ -116,7 +68,7 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
)->toArray();
|
||||
} catch (ClientExceptionInterface $e) {
|
||||
if (403 === $e->getResponse()->getStatusCode()) {
|
||||
return count($this->getScheduleTimesForUser($user, $startDate, $endDate));
|
||||
return \count($this->getScheduleTimesForUser($user, $startDate, $endDate));
|
||||
}
|
||||
|
||||
$this->logger->error('Could not get list of event on MSGraph', [
|
||||
@@ -153,6 +105,7 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
$this->logger->debug('mark user ready for msgraph calendar as he does not have any mapping', [
|
||||
'userId' => $user->getId(),
|
||||
]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -160,14 +113,14 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|\Chill\CalendarBundle\RemoteCalendar\Model\RemoteEvent[]
|
||||
*
|
||||
* @throws \Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface
|
||||
* @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
|
||||
* @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
|
||||
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
|
||||
*
|
||||
* @return array|\Chill\CalendarBundle\RemoteCalendar\Model\RemoteEvent[]
|
||||
*/
|
||||
public function listEventsForUser(User $user, DateTimeImmutable $startDate, DateTimeImmutable $endDate, ?int $offset = 0, ?int $limit = 50): array
|
||||
public function listEventsForUser(User $user, \DateTimeImmutable $startDate, \DateTimeImmutable $endDate, ?int $offset = 0, ?int $limit = 50): array
|
||||
{
|
||||
$userId = $this->mapCalendarToUser->getUserId($user);
|
||||
|
||||
@@ -178,7 +131,7 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
try {
|
||||
$bareEvents = $this->userHttpClient->request(
|
||||
'GET',
|
||||
'users/' . $userId . '/calendarView',
|
||||
'users/'.$userId.'/calendarView',
|
||||
[
|
||||
'query' => [
|
||||
'startDateTime' => $startDate->setTimezone(RemoteEventConverter::getRemoteTimeZone())->format(RemoteEventConverter::getRemoteDateTimeSimpleFormat()),
|
||||
@@ -268,7 +221,7 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
$calendar->getRemoteId(),
|
||||
$this->translator->trans('remote_ms_graph.cancel_event_because_main_user_is_%label%', ['%label%' => $calendar->getMainUser()]),
|
||||
$previousMainUser,
|
||||
'calendar_' . $calendar->getRemoteId()
|
||||
'calendar_'.$calendar->getRemoteId()
|
||||
);
|
||||
$this->createCalendarOnRemote($calendar);
|
||||
} else {
|
||||
@@ -346,7 +299,7 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception('not supported');
|
||||
throw new \Exception('not supported');
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -359,7 +312,7 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
$this->logger->warning('could not update calendar range to remote', [
|
||||
'exception' => $e->getTraceAsString(),
|
||||
'content' => $e->getResponse()->getContent(),
|
||||
'calendarRangeId' => 'invite_' . $invite->getId(),
|
||||
'calendarRangeId' => 'invite_'.$invite->getId(),
|
||||
]);
|
||||
|
||||
throw $e;
|
||||
@@ -401,7 +354,7 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
'id' => $id,
|
||||
'lastModifiedDateTime' => $lastModified,
|
||||
'changeKey' => $changeKey
|
||||
] = $this->createOnRemote($eventData, $calendar->getMainUser(), 'calendar_' . $calendar->getId());
|
||||
] = $this->createOnRemote($eventData, $calendar->getMainUser(), 'calendar_'.$calendar->getId());
|
||||
|
||||
if (null === $id) {
|
||||
return;
|
||||
@@ -436,7 +389,7 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
try {
|
||||
$event = $this->machineHttpClient->request(
|
||||
'POST',
|
||||
'users/' . $userId . '/calendar/events',
|
||||
'users/'.$userId.'/calendar/events',
|
||||
[
|
||||
'json' => $eventData,
|
||||
]
|
||||
@@ -480,7 +433,7 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
] = $this->createOnRemote(
|
||||
$eventData,
|
||||
$calendarRange->getUser(),
|
||||
'calendar_range_' . $calendarRange->getId()
|
||||
'calendar_range_'.$calendarRange->getId()
|
||||
);
|
||||
|
||||
$calendarRange->setRemoteId($id)
|
||||
@@ -503,7 +456,7 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
$userId = $this->mapCalendarToUser->getUserId($user);
|
||||
|
||||
if ('' === $iCalUid = ($event['iCalUId'] ?? '')) {
|
||||
throw new Exception('no iCalUid for this event');
|
||||
throw new \Exception('no iCalUid for this event');
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -521,8 +474,8 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
throw $clientException;
|
||||
}
|
||||
|
||||
if (1 !== count($events['value'])) {
|
||||
throw new Exception('multiple events found with same iCalUid');
|
||||
if (1 !== \count($events['value'])) {
|
||||
throw new \Exception('multiple events found with same iCalUid');
|
||||
}
|
||||
|
||||
return $events['value'][0]['id'];
|
||||
@@ -533,19 +486,13 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
$userId = $this->mapCalendarToUser->getUserId($user);
|
||||
|
||||
if (null === $userId) {
|
||||
throw new Exception(
|
||||
sprintf(
|
||||
'no remote calendar for this user: %s, remoteid: %s',
|
||||
$user->getId(),
|
||||
$remoteId
|
||||
)
|
||||
);
|
||||
throw new \Exception(sprintf('no remote calendar for this user: %s, remoteid: %s', $user->getId(), $remoteId));
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->machineHttpClient->request(
|
||||
'GET',
|
||||
'users/' . $userId . '/calendar/events/' . $remoteId
|
||||
'users/'.$userId.'/calendar/events/'.$remoteId
|
||||
)->toArray();
|
||||
} catch (ClientExceptionInterface $e) {
|
||||
$this->logger->warning('Could not get event from calendar', [
|
||||
@@ -556,11 +503,11 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
}
|
||||
}
|
||||
|
||||
private function getScheduleTimesForUser(User $user, DateTimeImmutable $startDate, DateTimeImmutable $endDate): array
|
||||
private function getScheduleTimesForUser(User $user, \DateTimeImmutable $startDate, \DateTimeImmutable $endDate): array
|
||||
{
|
||||
$userId = $this->mapCalendarToUser->getUserId($user);
|
||||
|
||||
if (array_key_exists($userId, $this->cacheScheduleTimeForUser)) {
|
||||
if (\array_key_exists($userId, $this->cacheScheduleTimeForUser)) {
|
||||
return $this->cacheScheduleTimeForUser[$userId];
|
||||
}
|
||||
|
||||
@@ -575,17 +522,17 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
$body = [
|
||||
'schedules' => [$user->getEmailCanonical()],
|
||||
'startTime' => [
|
||||
'dateTime' => ($startDate->setTimezone(RemoteEventConverter::getRemoteTimeZone())->format(RemoteEventConverter::getRemoteDateTimeSimpleFormat())),
|
||||
'dateTime' => $startDate->setTimezone(RemoteEventConverter::getRemoteTimeZone())->format(RemoteEventConverter::getRemoteDateTimeSimpleFormat()),
|
||||
'timeZone' => 'UTC',
|
||||
],
|
||||
'endTime' => [
|
||||
'dateTime' => ($endDate->setTimezone(RemoteEventConverter::getRemoteTimeZone())->format(RemoteEventConverter::getRemoteDateTimeSimpleFormat())),
|
||||
'dateTime' => $endDate->setTimezone(RemoteEventConverter::getRemoteTimeZone())->format(RemoteEventConverter::getRemoteDateTimeSimpleFormat()),
|
||||
'timeZone' => 'UTC',
|
||||
],
|
||||
];
|
||||
|
||||
try {
|
||||
$response = $this->userHttpClient->request('POST', 'users/' . $userId . '/calendar/getSchedule', [
|
||||
$response = $this->userHttpClient->request('POST', 'users/'.$userId.'/calendar/getSchedule', [
|
||||
'json' => $body,
|
||||
])->toArray();
|
||||
} catch (ClientExceptionInterface $e) {
|
||||
@@ -610,7 +557,7 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
$eventDatas = [];
|
||||
$eventDatas[] = $this->remoteEventConverter->calendarToEvent($calendar);
|
||||
|
||||
if (0 < count($newInvites)) {
|
||||
if (0 < \count($newInvites)) {
|
||||
// it seems that invitaiton are always send, even if attendee changes are mixed with other datas
|
||||
// $eventDatas[] = $this->remoteEventConverter->calendarToEventAttendeesOnly($calendar);
|
||||
}
|
||||
@@ -624,7 +571,7 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
$calendar->getRemoteId(),
|
||||
$eventData,
|
||||
$calendar->getMainUser(),
|
||||
'calendar_' . $calendar->getId()
|
||||
'calendar_'.$calendar->getId()
|
||||
);
|
||||
|
||||
$calendar->addRemoteAttributes([
|
||||
@@ -655,7 +602,7 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
try {
|
||||
$event = $this->machineHttpClient->request(
|
||||
'PATCH',
|
||||
'users/' . $userId . '/calendar/events/' . $remoteId,
|
||||
'users/'.$userId.'/calendar/events/'.$remoteId,
|
||||
[
|
||||
'json' => $eventData,
|
||||
]
|
||||
@@ -683,9 +630,9 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
try {
|
||||
$this->machineHttpClient->request(
|
||||
'DELETE',
|
||||
'users/' . $userId . '/calendar/events/' . $remoteId
|
||||
'users/'.$userId.'/calendar/events/'.$remoteId
|
||||
);
|
||||
} catch (ClientExceptionInterface $e) {
|
||||
} catch (ClientExceptionInterface) {
|
||||
$this->logger->warning('could not remove event from calendar', [
|
||||
'event_remote_id' => $remoteId,
|
||||
'user_id' => $user->getId(),
|
||||
@@ -710,7 +657,7 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
try {
|
||||
$event = $this->machineHttpClient->request(
|
||||
'GET',
|
||||
'users/' . $userId . '/calendar/events/' . $calendarRange->getRemoteId()
|
||||
'users/'.$userId.'/calendar/events/'.$calendarRange->getRemoteId()
|
||||
)->toArray();
|
||||
} catch (ClientExceptionInterface $e) {
|
||||
$this->logger->warning('Could not get event from calendar', [
|
||||
@@ -737,7 +684,7 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
try {
|
||||
$event = $this->machineHttpClient->request(
|
||||
'PATCH',
|
||||
'users/' . $userId . '/calendar/events/' . $calendarRange->getRemoteId(),
|
||||
'users/'.$userId.'/calendar/events/'.$calendarRange->getRemoteId(),
|
||||
[
|
||||
'json' => $eventData,
|
||||
]
|
||||
|
@@ -22,20 +22,18 @@ use Chill\CalendarBundle\Entity\Calendar;
|
||||
use Chill\CalendarBundle\Entity\CalendarRange;
|
||||
use Chill\CalendarBundle\Entity\Invite;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use DateTimeImmutable;
|
||||
use LogicException;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class NullRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
{
|
||||
public function countEventsForUser(User $user, DateTimeImmutable $startDate, DateTimeImmutable $endDate): int
|
||||
public function countEventsForUser(User $user, \DateTimeImmutable $startDate, \DateTimeImmutable $endDate): int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getMakeReadyResponse(string $returnPath): Response
|
||||
{
|
||||
throw new LogicException('As this connector is always ready, this method should not be called');
|
||||
throw new \LogicException('As this connector is always ready, this method should not be called');
|
||||
}
|
||||
|
||||
public function isReady(): bool
|
||||
@@ -43,7 +41,7 @@ class NullRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
return true;
|
||||
}
|
||||
|
||||
public function listEventsForUser(User $user, DateTimeImmutable $startDate, DateTimeImmutable $endDate, ?int $offset = 0, ?int $limit = 50): array
|
||||
public function listEventsForUser(User $user, \DateTimeImmutable $startDate, \DateTimeImmutable $endDate, ?int $offset = 0, ?int $limit = 50): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
@@ -23,12 +23,11 @@ use Chill\CalendarBundle\Entity\CalendarRange;
|
||||
use Chill\CalendarBundle\Entity\Invite;
|
||||
use Chill\CalendarBundle\RemoteCalendar\Model\RemoteEvent;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use DateTimeImmutable;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
interface RemoteCalendarConnectorInterface
|
||||
{
|
||||
public function countEventsForUser(User $user, DateTimeImmutable $startDate, DateTimeImmutable $endDate): int;
|
||||
public function countEventsForUser(User $user, \DateTimeImmutable $startDate, \DateTimeImmutable $endDate): int;
|
||||
|
||||
/**
|
||||
* Return a response, more probably a RedirectResponse, where the user
|
||||
@@ -46,7 +45,7 @@ interface RemoteCalendarConnectorInterface
|
||||
/**
|
||||
* @return array|RemoteEvent[]
|
||||
*/
|
||||
public function listEventsForUser(User $user, DateTimeImmutable $startDate, DateTimeImmutable $endDate, ?int $offset = 0, ?int $limit = 50): array;
|
||||
public function listEventsForUser(User $user, \DateTimeImmutable $startDate, \DateTimeImmutable $endDate, ?int $offset = 0, ?int $limit = 50): array;
|
||||
|
||||
public function removeCalendar(string $remoteId, array $remoteAttributes, User $user, ?CalendarRange $associatedCalendarRange = null): void;
|
||||
|
||||
|
@@ -28,7 +28,6 @@ use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\MSUserAbsenceSync;
|
||||
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraphRemoteCalendarConnector;
|
||||
use Chill\CalendarBundle\RemoteCalendar\Connector\NullRemoteCalendarConnector;
|
||||
use Chill\CalendarBundle\RemoteCalendar\Connector\RemoteCalendarConnectorInterface;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
@@ -43,7 +42,7 @@ class RemoteCalendarCompilerPass implements CompilerPassInterface
|
||||
if (true === $config['remote_calendars_sync']['microsoft_graph']['enabled']) {
|
||||
$connector = MSGraphRemoteCalendarConnector::class;
|
||||
|
||||
$container->setAlias(HttpClientInterface::class . ' $machineHttpClient', MachineHttpClient::class);
|
||||
$container->setAlias(HttpClientInterface::class.' $machineHttpClient', MachineHttpClient::class);
|
||||
} else {
|
||||
$connector = NullRemoteCalendarConnector::class;
|
||||
// remove services which cannot be loaded
|
||||
|
@@ -18,45 +18,32 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\CalendarBundle\RemoteCalendar\Model;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||
|
||||
class RemoteEvent
|
||||
{
|
||||
public string $description;
|
||||
|
||||
/**
|
||||
* @Serializer\Groups({"read"})
|
||||
*/
|
||||
public DateTimeImmutable $endDate;
|
||||
|
||||
/**
|
||||
* @Serializer\Groups({"read"})
|
||||
*/
|
||||
public string $id;
|
||||
|
||||
/**
|
||||
* @Serializer\Groups({"read"})
|
||||
*/
|
||||
public bool $isAllDay;
|
||||
|
||||
/**
|
||||
* @Serializer\Groups({"read"})
|
||||
*/
|
||||
public DateTimeImmutable $startDate;
|
||||
|
||||
/**
|
||||
* @Serializer\Groups({"read"})
|
||||
*/
|
||||
public string $title;
|
||||
|
||||
public function __construct(string $id, string $title, string $description, DateTimeImmutable $startDate, DateTimeImmutable $endDate, bool $isAllDay = false)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->title = $title;
|
||||
$this->description = $description;
|
||||
$this->startDate = $startDate;
|
||||
$this->endDate = $endDate;
|
||||
$this->isAllDay = $isAllDay;
|
||||
public function __construct(
|
||||
/**
|
||||
* @Serializer\Groups({"read"})
|
||||
*/
|
||||
public string $id,
|
||||
/**
|
||||
* @Serializer\Groups({"read"})
|
||||
*/
|
||||
public string $title,
|
||||
public string $description,
|
||||
/**
|
||||
* @Serializer\Groups({"read"})
|
||||
*/
|
||||
public \DateTimeImmutable $startDate,
|
||||
/**
|
||||
* @Serializer\Groups({"read"})
|
||||
*/
|
||||
public \DateTimeImmutable $endDate,
|
||||
/**
|
||||
* @Serializer\Groups({"read"})
|
||||
*/
|
||||
public bool $isAllDay = false
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
@@ -23,25 +23,16 @@ use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\PersonBundle\Repository\AccompanyingPeriodACLAwareRepositoryInterface;
|
||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
|
||||
class CalendarACLAwareRepository implements CalendarACLAwareRepositoryInterface
|
||||
{
|
||||
private AccompanyingPeriodACLAwareRepositoryInterface $accompanyingPeriodACLAwareRepository;
|
||||
|
||||
private EntityManagerInterface $em;
|
||||
|
||||
public function __construct(
|
||||
AccompanyingPeriodACLAwareRepositoryInterface $accompanyingPeriodACLAwareRepository,
|
||||
EntityManagerInterface $em
|
||||
) {
|
||||
$this->accompanyingPeriodACLAwareRepository = $accompanyingPeriodACLAwareRepository;
|
||||
$this->em = $em;
|
||||
public function __construct(private readonly AccompanyingPeriodACLAwareRepositoryInterface $accompanyingPeriodACLAwareRepository, private readonly EntityManagerInterface $em)
|
||||
{
|
||||
}
|
||||
|
||||
public function buildQueryByAccompanyingPeriod(AccompanyingPeriod $period, ?DateTimeImmutable $startDate, ?DateTimeImmutable $endDate): QueryBuilder
|
||||
public function buildQueryByAccompanyingPeriod(AccompanyingPeriod $period, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate): QueryBuilder
|
||||
{
|
||||
$qb = $this->em->createQueryBuilder();
|
||||
$qb->from(Calendar::class, 'c');
|
||||
@@ -64,7 +55,7 @@ class CalendarACLAwareRepository implements CalendarACLAwareRepositoryInterface
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function buildQueryByAccompanyingPeriodIgnoredByDates(AccompanyingPeriod $period, ?DateTimeImmutable $startDate, ?DateTimeImmutable $endDate): QueryBuilder
|
||||
public function buildQueryByAccompanyingPeriodIgnoredByDates(AccompanyingPeriod $period, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate): QueryBuilder
|
||||
{
|
||||
$qb = $this->em->createQueryBuilder();
|
||||
$qb->from(Calendar::class, 'c');
|
||||
@@ -90,7 +81,7 @@ class CalendarACLAwareRepository implements CalendarACLAwareRepositoryInterface
|
||||
/**
|
||||
* Base implementation. The list of allowed accompanying period is retrieved "manually" from @see{AccompanyingPeriodACLAwareRepository}.
|
||||
*/
|
||||
public function buildQueryByPerson(Person $person, ?DateTimeImmutable $startDate, ?DateTimeImmutable $endDate): QueryBuilder
|
||||
public function buildQueryByPerson(Person $person, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate): QueryBuilder
|
||||
{
|
||||
$qb = $this->em->createQueryBuilder()
|
||||
->from(Calendar::class, 'c');
|
||||
@@ -114,7 +105,7 @@ class CalendarACLAwareRepository implements CalendarACLAwareRepositoryInterface
|
||||
/**
|
||||
* Base implementation. The list of allowed accompanying period is retrieved "manually" from @see{AccompanyingPeriodACLAwareRepository}.
|
||||
*/
|
||||
public function buildQueryByPersonIgnoredByDates(Person $person, ?DateTimeImmutable $startDate, ?DateTimeImmutable $endDate): QueryBuilder
|
||||
public function buildQueryByPersonIgnoredByDates(Person $person, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate): QueryBuilder
|
||||
{
|
||||
$qb = $this->em->createQueryBuilder()
|
||||
->from(Calendar::class, 'c');
|
||||
@@ -135,14 +126,14 @@ class CalendarACLAwareRepository implements CalendarACLAwareRepositoryInterface
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function countByAccompanyingPeriod(AccompanyingPeriod $period, ?DateTimeImmutable $startDate, ?DateTimeImmutable $endDate): int
|
||||
public function countByAccompanyingPeriod(AccompanyingPeriod $period, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate): int
|
||||
{
|
||||
$qb = $this->buildQueryByAccompanyingPeriod($period, $startDate, $endDate)->select('count(c)');
|
||||
|
||||
return $qb->getQuery()->getSingleScalarResult();
|
||||
}
|
||||
|
||||
public function countByPerson(Person $person, ?DateTimeImmutable $startDate, ?DateTimeImmutable $endDate): int
|
||||
public function countByPerson(Person $person, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate): int
|
||||
{
|
||||
return $this->buildQueryByPerson($person, $startDate, $endDate)
|
||||
->select('COUNT(c)')
|
||||
@@ -150,14 +141,14 @@ class CalendarACLAwareRepository implements CalendarACLAwareRepositoryInterface
|
||||
->getSingleScalarResult();
|
||||
}
|
||||
|
||||
public function countIgnoredByAccompanyingPeriod(AccompanyingPeriod $period, ?DateTimeImmutable $startDate, ?DateTimeImmutable $endDate): int
|
||||
public function countIgnoredByAccompanyingPeriod(AccompanyingPeriod $period, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate): int
|
||||
{
|
||||
$qb = $this->buildQueryByAccompanyingPeriodIgnoredByDates($period, $startDate, $endDate)->select('count(c)');
|
||||
|
||||
return $qb->getQuery()->getSingleScalarResult();
|
||||
}
|
||||
|
||||
public function countIgnoredByPerson(Person $person, ?DateTimeImmutable $startDate, ?DateTimeImmutable $endDate): int
|
||||
public function countIgnoredByPerson(Person $person, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate): int
|
||||
{
|
||||
return $this->buildQueryByPersonIgnoredByDates($person, $startDate, $endDate)
|
||||
->select('COUNT(c)')
|
||||
@@ -168,12 +159,12 @@ class CalendarACLAwareRepository implements CalendarACLAwareRepositoryInterface
|
||||
/**
|
||||
* @return array|Calendar[]
|
||||
*/
|
||||
public function findByAccompanyingPeriod(AccompanyingPeriod $period, ?DateTimeImmutable $startDate, ?DateTimeImmutable $endDate, ?array $orderBy = [], ?int $offset = null, ?int $limit = null): array
|
||||
public function findByAccompanyingPeriod(AccompanyingPeriod $period, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate, ?array $orderBy = [], ?int $offset = null, ?int $limit = null): array
|
||||
{
|
||||
$qb = $this->buildQueryByAccompanyingPeriod($period, $startDate, $endDate)->select('c');
|
||||
|
||||
foreach ($orderBy as $sort => $order) {
|
||||
$qb->addOrderBy('c.' . $sort, $order);
|
||||
$qb->addOrderBy('c.'.$sort, $order);
|
||||
}
|
||||
|
||||
if (null !== $offset) {
|
||||
@@ -187,13 +178,13 @@ class CalendarACLAwareRepository implements CalendarACLAwareRepositoryInterface
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
|
||||
public function findByPerson(Person $person, ?DateTimeImmutable $startDate, ?DateTimeImmutable $endDate, ?array $orderBy = [], ?int $offset = null, ?int $limit = null): array
|
||||
public function findByPerson(Person $person, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate, ?array $orderBy = [], ?int $offset = null, ?int $limit = null): array
|
||||
{
|
||||
$qb = $this->buildQueryByPerson($person, $startDate, $endDate)
|
||||
->select('c');
|
||||
|
||||
foreach ($orderBy as $sort => $order) {
|
||||
$qb->addOrderBy('c.' . $sort, $order);
|
||||
$qb->addOrderBy('c.'.$sort, $order);
|
||||
}
|
||||
|
||||
if (null !== $offset) {
|
||||
|
@@ -21,33 +21,32 @@ namespace Chill\CalendarBundle\Repository;
|
||||
use Chill\CalendarBundle\Entity\Calendar;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use DateTimeImmutable;
|
||||
|
||||
interface CalendarACLAwareRepositoryInterface
|
||||
{
|
||||
public function countByAccompanyingPeriod(AccompanyingPeriod $period, ?DateTimeImmutable $startDate, ?DateTimeImmutable $endDate): int;
|
||||
public function countByAccompanyingPeriod(AccompanyingPeriod $period, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate): int;
|
||||
|
||||
/**
|
||||
* Return the number or calendars associated with a person. See condition on @see{self::findByPerson}.
|
||||
*/
|
||||
public function countByPerson(Person $person, ?DateTimeImmutable $startDate, ?DateTimeImmutable $endDate): int;
|
||||
public function countByPerson(Person $person, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate): int;
|
||||
|
||||
/**
|
||||
* Return the number or calendars associated with an accompanyign period which **does not** match the date conditions.
|
||||
*/
|
||||
public function countIgnoredByAccompanyingPeriod(AccompanyingPeriod $period, ?DateTimeImmutable $startDate, ?DateTimeImmutable $endDate): int;
|
||||
public function countIgnoredByAccompanyingPeriod(AccompanyingPeriod $period, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate): int;
|
||||
|
||||
/**
|
||||
* Return the number or calendars associated with a person which **does not** match the date conditions.
|
||||
*
|
||||
* See condition on @see{self::findByPerson}.
|
||||
*/
|
||||
public function countIgnoredByPerson(Person $person, ?DateTimeImmutable $startDate, ?DateTimeImmutable $endDate): int;
|
||||
public function countIgnoredByPerson(Person $person, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate): int;
|
||||
|
||||
/**
|
||||
* @return array|Calendar[]
|
||||
*/
|
||||
public function findByAccompanyingPeriod(AccompanyingPeriod $period, ?DateTimeImmutable $startDate, ?DateTimeImmutable $endDate, ?array $orderBy = [], ?int $offset = null, ?int $limit = null): array;
|
||||
public function findByAccompanyingPeriod(AccompanyingPeriod $period, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate, ?array $orderBy = [], ?int $offset = null, ?int $limit = null): array;
|
||||
|
||||
/**
|
||||
* Return all the calendars which are associated with a person, either on @see{Calendar::person} or within.
|
||||
@@ -59,5 +58,5 @@ interface CalendarACLAwareRepositoryInterface
|
||||
*
|
||||
* @return array|Calendar[]
|
||||
*/
|
||||
public function findByPerson(Person $person, ?DateTimeImmutable $startDate, ?DateTimeImmutable $endDate, ?array $orderBy = [], ?int $offset = null, ?int $limit = null): array;
|
||||
public function findByPerson(Person $person, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate, ?array $orderBy = [], ?int $offset = null, ?int $limit = null): array;
|
||||
}
|
||||
|
@@ -18,7 +18,7 @@ use Doctrine\Persistence\ObjectRepository;
|
||||
|
||||
class CalendarDocRepository implements ObjectRepository, CalendarDocRepositoryInterface
|
||||
{
|
||||
private EntityRepository $repository;
|
||||
private readonly EntityRepository $repository;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager)
|
||||
{
|
||||
|
@@ -13,28 +13,23 @@ namespace Chill\CalendarBundle\Repository;
|
||||
|
||||
use Chill\CalendarBundle\Entity\CalendarRange;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
use function count;
|
||||
|
||||
class CalendarRangeRepository implements ObjectRepository
|
||||
{
|
||||
private EntityManagerInterface $em;
|
||||
private readonly EntityRepository $repository;
|
||||
|
||||
private EntityRepository $repository;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager)
|
||||
public function __construct(private readonly EntityManagerInterface $em)
|
||||
{
|
||||
$this->em = $entityManager;
|
||||
$this->repository = $entityManager->getRepository(CalendarRange::class);
|
||||
$this->repository = $em->getRepository(CalendarRange::class);
|
||||
}
|
||||
|
||||
public function countByAvailableRangesForUser(User $user, DateTimeImmutable $from, DateTimeImmutable $to): int
|
||||
public function countByAvailableRangesForUser(User $user, \DateTimeImmutable $from, \DateTimeImmutable $to): int
|
||||
{
|
||||
return $this->buildQueryAvailableRangesForUser($user, $from, $to)
|
||||
->select('COUNT(cr)')
|
||||
@@ -67,8 +62,8 @@ class CalendarRangeRepository implements ObjectRepository
|
||||
*/
|
||||
public function findByAvailableRangesForUser(
|
||||
User $user,
|
||||
DateTimeImmutable $from,
|
||||
DateTimeImmutable $to,
|
||||
\DateTimeImmutable $from,
|
||||
\DateTimeImmutable $to,
|
||||
?int $limit = null,
|
||||
?int $offset = null
|
||||
): array {
|
||||
@@ -101,7 +96,7 @@ class CalendarRangeRepository implements ObjectRepository
|
||||
*/
|
||||
public function findRemoteIdsPresent(array $remoteIds): array
|
||||
{
|
||||
if (0 === count($remoteIds)) {
|
||||
if (0 === \count($remoteIds)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -116,7 +111,7 @@ class CalendarRangeRepository implements ObjectRepository
|
||||
|
||||
$remoteIdsStr = implode(
|
||||
', ',
|
||||
array_fill(0, count($remoteIds), '((?))')
|
||||
array_fill(0, \count($remoteIds), '((?))')
|
||||
);
|
||||
|
||||
$rsm = new ResultSetMapping();
|
||||
@@ -146,7 +141,7 @@ class CalendarRangeRepository implements ObjectRepository
|
||||
return CalendarRange::class;
|
||||
}
|
||||
|
||||
private function buildQueryAvailableRangesForUser(User $user, DateTimeImmutable $from, DateTimeImmutable $to): QueryBuilder
|
||||
private function buildQueryAvailableRangesForUser(User $user, \DateTimeImmutable $from, \DateTimeImmutable $to): QueryBuilder
|
||||
{
|
||||
$qb = $this->repository->createQueryBuilder('cr');
|
||||
|
||||
|
@@ -14,20 +14,18 @@ namespace Chill\CalendarBundle\Repository;
|
||||
use Chill\CalendarBundle\Entity\Calendar;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
use function count;
|
||||
|
||||
class CalendarRepository implements ObjectRepository
|
||||
{
|
||||
private EntityManagerInterface $em;
|
||||
private readonly EntityManagerInterface $em;
|
||||
|
||||
private EntityRepository $repository;
|
||||
private readonly EntityRepository $repository;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager)
|
||||
{
|
||||
@@ -40,7 +38,7 @@ class CalendarRepository implements ObjectRepository
|
||||
return $this->repository->count(['accompanyingPeriod' => $period]);
|
||||
}
|
||||
|
||||
public function countByUser(User $user, DateTimeImmutable $from, DateTimeImmutable $to): int
|
||||
public function countByUser(User $user, \DateTimeImmutable $from, \DateTimeImmutable $to): int
|
||||
{
|
||||
return $this->buildQueryByUser($user, $from, $to)
|
||||
->select('COUNT(c)')
|
||||
@@ -89,7 +87,7 @@ class CalendarRepository implements ObjectRepository
|
||||
);
|
||||
}
|
||||
|
||||
public function findByNotificationAvailable(DateTimeImmutable $startDate, DateTimeImmutable $endDate, ?int $limit = null, ?int $offset = null): array
|
||||
public function findByNotificationAvailable(\DateTimeImmutable $startDate, \DateTimeImmutable $endDate, ?int $limit = null, ?int $offset = null): array
|
||||
{
|
||||
$qb = $this->queryByNotificationAvailable($startDate, $endDate)->select('c');
|
||||
|
||||
@@ -107,7 +105,7 @@ class CalendarRepository implements ObjectRepository
|
||||
/**
|
||||
* @return array|Calendar[]
|
||||
*/
|
||||
public function findByUser(User $user, DateTimeImmutable $from, DateTimeImmutable $to, ?int $limit = null, ?int $offset = null): array
|
||||
public function findByUser(User $user, \DateTimeImmutable $from, \DateTimeImmutable $to, ?int $limit = null, ?int $offset = null): array
|
||||
{
|
||||
$qb = $this->buildQueryByUser($user, $from, $to)->select('c');
|
||||
|
||||
@@ -138,13 +136,13 @@ class CalendarRepository implements ObjectRepository
|
||||
*/
|
||||
public function findRemoteIdsPresent(array $remoteIds): array
|
||||
{
|
||||
if (0 === count($remoteIds)) {
|
||||
if (0 === \count($remoteIds)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$remoteIdsStr = implode(
|
||||
', ',
|
||||
array_fill(0, count($remoteIds), '((?))')
|
||||
array_fill(0, \count($remoteIds), '((?))')
|
||||
);
|
||||
|
||||
$sql = "SELECT
|
||||
@@ -183,7 +181,7 @@ class CalendarRepository implements ObjectRepository
|
||||
return Calendar::class;
|
||||
}
|
||||
|
||||
private function buildQueryByUser(User $user, DateTimeImmutable $from, DateTimeImmutable $to): QueryBuilder
|
||||
private function buildQueryByUser(User $user, \DateTimeImmutable $from, \DateTimeImmutable $to): QueryBuilder
|
||||
{
|
||||
$qb = $this->repository->createQueryBuilder('c');
|
||||
|
||||
@@ -202,7 +200,7 @@ class CalendarRepository implements ObjectRepository
|
||||
]);
|
||||
}
|
||||
|
||||
private function queryByNotificationAvailable(DateTimeImmutable $startDate, DateTimeImmutable $endDate): QueryBuilder
|
||||
private function queryByNotificationAvailable(\DateTimeImmutable $startDate, \DateTimeImmutable $endDate): QueryBuilder
|
||||
{
|
||||
$qb = $this->repository->createQueryBuilder('c');
|
||||
|
||||
|
@@ -18,7 +18,7 @@ use Doctrine\Persistence\ObjectRepository;
|
||||
|
||||
class InviteRepository implements ObjectRepository
|
||||
{
|
||||
private EntityRepository $entityRepository;
|
||||
private readonly EntityRepository $entityRepository;
|
||||
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
|
@@ -1,13 +1,10 @@
|
||||
---
|
||||
services:
|
||||
Chill\CalendarBundle\DataFixtures\ORM\LoadCancelReason:
|
||||
tags:
|
||||
- { 'name': doctrine.fixture.orm }
|
||||
Chill\CalendarBundle\DataFixtures\ORM\LoadInvite:
|
||||
tags:
|
||||
- { 'name': doctrine.fixture.orm }
|
||||
Chill\CalendarBundle\DataFixtures\ORM\LoadCalendarRange:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
tags:
|
||||
- { 'name': doctrine.fixture.orm }
|
||||
_defaults:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
|
||||
Chill\CalendarBundle\DataFixtures\ORM\:
|
||||
resource: './../../../DataFixtures/ORM'
|
||||
tags:
|
||||
- { 'name': doctrine.fixture.orm }
|
||||
|
@@ -69,7 +69,7 @@
|
||||
or calendar.users|length > 0 %}
|
||||
<div class="item-row details separator">
|
||||
<div class="item-col">
|
||||
{% include 'ChillActivityBundle:Activity:concernedGroups.html.twig' with {
|
||||
{% include '@ChillActivity/Activity/concernedGroups.html.twig' with {
|
||||
'context': calendar.context == 'person' ? 'calendar_person' : 'calendar_accompanyingCourse',
|
||||
'render': 'wrap-list',
|
||||
'entity': calendar
|
||||
|
@@ -7,7 +7,7 @@
|
||||
{% block content %}
|
||||
<div class="calendar-edit">
|
||||
|
||||
{% include 'ChillCalendarBundle:Calendar:edit.html.twig' with {'context': 'accompanyingCourse'} %}
|
||||
{% include '@ChillCalendar/Calendar/edit.html.twig' with {'context': 'accompanyingCourse'} %}
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@@ -7,7 +7,7 @@
|
||||
{% block content %}
|
||||
<div class="calendar-edit">
|
||||
|
||||
{% include 'ChillCalendarBundle:Calendar:edit.html.twig' with {'context': 'person'} %}
|
||||
{% include '@ChillCalendar/Calendar/edit.html.twig' with {'context': 'person'} %}
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@@ -6,7 +6,7 @@
|
||||
<div class="calendar-edit">
|
||||
|
||||
<div id="calendar"></div> {# <=== vue component #}
|
||||
{% include 'ChillCalendarBundle:Calendar:edit.html.twig' with {'context': 'user'} %}
|
||||
{% include '@ChillCalendar/Calendar/edit.html.twig' with {'context': 'user'} %}
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@@ -8,7 +8,7 @@
|
||||
<div class="calendar-new">
|
||||
|
||||
<div id="calendar"></div> {# <=== vue component #}
|
||||
{% include 'ChillCalendarBundle:Calendar:new.html.twig' with {'context': 'accompanyingCourse'} %}
|
||||
{% include '@ChillCalendar/Calendar/new.html.twig' with {'context': 'accompanyingCourse'} %}
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@@ -8,7 +8,7 @@
|
||||
<div class="calendar-new">
|
||||
|
||||
<div id="calendar"></div> {# <=== vue component #}
|
||||
{% include 'ChillCalendarBundle:Calendar:new.html.twig' with {'context': 'person'} %}
|
||||
{% include '@ChillCalendar/Calendar/new.html.twig' with {'context': 'person'} %}
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@@ -15,7 +15,7 @@
|
||||
</dl>
|
||||
|
||||
<h2 class="chill-red">{{ 'Concerned groups calendar'|trans }}</h2>
|
||||
{% include 'ChillActivityBundle:Activity:concernedGroups.html.twig' with {'context': 'calendar_' ~ context, 'render': 'bloc' } %}
|
||||
{% include '@ChillActivity/Activity/concernedGroups.html.twig' with {'context': 'calendar_' ~ context, 'render': 'bloc' } %}
|
||||
|
||||
|
||||
<h2 class="chill-red">{{ 'Calendar data'|trans }}</h2>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
{% block content -%}
|
||||
<div class="calendar-show">
|
||||
|
||||
{% include 'ChillCalendarBundle:Calendar:show.html.twig' with {'context': 'accompanyingCourse'} %}
|
||||
{% include '@ChillCalendar/Calendar/show.html.twig' with {'context': 'accompanyingCourse'} %}
|
||||
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
@@ -5,7 +5,7 @@
|
||||
{% block content -%}
|
||||
<div class="calendar-show">
|
||||
|
||||
{% include 'ChillCalendarBundle:Calendar:show.html.twig' with {'context': 'user'} %}
|
||||
{% include '@ChillCalendar/Calendar/show.html.twig' with {'context': 'user'} %}
|
||||
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
@@ -15,47 +15,36 @@ use Chill\CalendarBundle\Entity\CalendarDoc;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use UnexpectedValueException;
|
||||
use function in_array;
|
||||
|
||||
class CalendarDocVoter extends Voter
|
||||
{
|
||||
public const EDIT = 'CHILL_CALENDAR_DOC_EDIT';
|
||||
final public const EDIT = 'CHILL_CALENDAR_DOC_EDIT';
|
||||
|
||||
public const SEE = 'CHILL_CALENDAR_DOC_SEE';
|
||||
final public const SEE = 'CHILL_CALENDAR_DOC_SEE';
|
||||
|
||||
private const ALL = [
|
||||
'CHILL_CALENDAR_DOC_EDIT',
|
||||
'CHILL_CALENDAR_DOC_SEE',
|
||||
];
|
||||
|
||||
private Security $security;
|
||||
|
||||
public function __construct(Security $security)
|
||||
public function __construct(private readonly Security $security)
|
||||
{
|
||||
$this->security = $security;
|
||||
}
|
||||
|
||||
protected function supports($attribute, $subject): bool
|
||||
{
|
||||
return in_array($attribute, self::ALL, true) && $subject instanceof CalendarDoc;
|
||||
return \in_array($attribute, self::ALL, true) && $subject instanceof CalendarDoc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CalendarDoc $subject
|
||||
* @param mixed $attribute
|
||||
*/
|
||||
protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool
|
||||
{
|
||||
switch ($attribute) {
|
||||
case self::EDIT:
|
||||
return $this->security->isGranted(CalendarVoter::EDIT, $subject->getCalendar());
|
||||
|
||||
case self::SEE:
|
||||
return $this->security->isGranted(CalendarVoter::SEE, $subject->getCalendar());
|
||||
|
||||
default:
|
||||
throw new UnexpectedValueException('Attribute not supported: ' . $attribute);
|
||||
}
|
||||
return match ($attribute) {
|
||||
self::EDIT => $this->security->isGranted(CalendarVoter::EDIT, $subject->getCalendar()),
|
||||
self::SEE => $this->security->isGranted(CalendarVoter::SEE, $subject->getCalendar()),
|
||||
default => throw new \UnexpectedValueException('Attribute not supported: '.$attribute),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user