diff --git a/src/Bundle/ChillCalendarBundle/Entity/Calendar.php b/src/Bundle/ChillCalendarBundle/Entity/Calendar.php index b1a6f8850..c0168ab74 100644 --- a/src/Bundle/ChillCalendarBundle/Entity/Calendar.php +++ b/src/Bundle/ChillCalendarBundle/Entity/Calendar.php @@ -84,7 +84,7 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface public ?User $previousMainUser = null; /** - * @ORM\ManyToOne(targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod") + * @ORM\ManyToOne(targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod", inversedBy="calendars") * @Serializer\Groups({"read"}) */ private AccompanyingPeriod $accompanyingPeriod; @@ -153,7 +153,7 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface private ?User $mainUser = null; /** - * @ORM\ManyToMany(targetEntity="Chill\PersonBundle\Entity\Person") + * @ORM\ManyToMany(targetEntity="Chill\PersonBundle\Entity\Person", inversedBy="calendars") * @ORM\JoinTable(name="chill_calendar.calendar_to_persons") * @Serializer\Groups({"calendar:read", "read"}) * @Assert\Count(min=1, minMessage="calendar.At least {{ limit }} person is required.") diff --git a/src/Bundle/ChillCalendarBundle/RemoteCalendar/Connector/MSGraphRemoteCalendarConnector.php b/src/Bundle/ChillCalendarBundle/RemoteCalendar/Connector/MSGraphRemoteCalendarConnector.php index fb81de14b..9f83e6ebd 100644 --- a/src/Bundle/ChillCalendarBundle/RemoteCalendar/Connector/MSGraphRemoteCalendarConnector.php +++ b/src/Bundle/ChillCalendarBundle/RemoteCalendar/Connector/MSGraphRemoteCalendarConnector.php @@ -458,13 +458,10 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface } try { - $v = $this->machineHttpClient->request( + return $this->machineHttpClient->request( 'GET', 'users/' . $userId . '/calendar/events/' . $remoteId )->toArray(); - dump($v); - - return $v; } catch (ClientExceptionInterface $e) { $this->logger->warning('Could not get event from calendar', [ 'remoteId' => $remoteId, diff --git a/src/Bundle/ChillCalendarBundle/Security/Voter/CalendarVoter.php b/src/Bundle/ChillCalendarBundle/Security/Voter/CalendarVoter.php index eca4fe437..54bdcb5fb 100644 --- a/src/Bundle/ChillCalendarBundle/Security/Voter/CalendarVoter.php +++ b/src/Bundle/ChillCalendarBundle/Security/Voter/CalendarVoter.php @@ -11,6 +11,7 @@ declare(strict_types=1); namespace Chill\CalendarBundle\Security\Voter; +use Chill\CalendarBundle\Entity\Calendar; use Chill\MainBundle\Security\Authorization\AbstractChillVoter; use Chill\MainBundle\Security\Authorization\VoterHelperFactoryInterface; use Chill\MainBundle\Security\Authorization\VoterHelperInterface; @@ -23,6 +24,12 @@ use Symfony\Component\Security\Core\Security; class CalendarVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface { + public const CREATE = 'CHILL_CALENDAR_CALENDAR_CREATE'; + + public const DELETE = 'CHILL_CALENDAR_CALENDAR_DELETE'; + + public const EDIT = 'CHILL_CALENDAR_CALENDAR_EDIT'; + public const SEE = 'CHILL_CALENDAR_CALENDAR_SEE'; private Security $security; @@ -37,6 +44,7 @@ class CalendarVoter extends AbstractChillVoter implements ProvideRoleHierarchyIn $this->voterHelper = $voterHelperFactory ->generate(self::class) ->addCheckFor(AccompanyingPeriod::class, [self::SEE]) + ->addCheckFor(Calendar::class, [self::SEE, self::CREATE, self::EDIT, self::DELETE]) ->build(); } @@ -77,6 +85,18 @@ class CalendarVoter extends AbstractChillVoter implements ProvideRoleHierarchyIn default: throw new LogicException('subject not implemented'); } + } elseif ($subject instanceof Calendar) { + if (null !== $period = $subject->getAccompanyingPeriod()) { + switch ($attribute) { + case self::SEE: + case self::EDIT: + case self::CREATE: + return $this->security->isGranted(AccompanyingPeriodVoter::SEE, $period); + + case self::DELETE: + return $this->security->isGranted(AccompanyingPeriodVoter::EDIT, $period); + } + } } throw new LogicException('attribute not implemented'); diff --git a/src/Bundle/ChillCalendarBundle/translations/messages.fr.yml b/src/Bundle/ChillCalendarBundle/translations/messages.fr.yml index 681e0cd69..9efe99b79 100644 --- a/src/Bundle/ChillCalendarBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillCalendarBundle/translations/messages.fr.yml @@ -49,6 +49,7 @@ chill_calendar: start date filter: Début du rendez-vous From: Du To: Au + Next calendars: Prochains rendez-vous remote_ms_graph: freebusy_statuses: diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php index ab51bbf85..1872c9e79 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php @@ -129,6 +129,11 @@ class AccompanyingPeriod implements */ private ?Location $administrativeLocation = null; + /** + * @ORM\OneToMany(targetEntity="Chill\CalendarBundle\Entity\Calendar", mappedBy="accompanyingPeriod") + */ + private Collection $calendars; + /** * @var DateTime * @@ -389,6 +394,7 @@ class AccompanyingPeriod implements public function __construct(?DateTime $dateOpening = null) { $this->setOpeningDate($dateOpening ?? new DateTime('now')); + $this->calendars = new ArrayCollection(); $this->participations = new ArrayCollection(); $this->scopes = new ArrayCollection(); $this->socialIssues = new ArrayCollection(); @@ -612,6 +618,11 @@ class AccompanyingPeriod implements ); } + public function getCalendars(): Collection + { + return $this->calendars; + } + public function getCenter(): ?Center { if ($this->getPersons()->count() === 0) { @@ -765,6 +776,24 @@ class AccompanyingPeriod implements return 'none'; } + public function getNextCalendarsForPerson(Person $person, $limit = 5): Collection + { + $today = new DateTimeImmutable('today'); + $criteria = Criteria::create() + ->where(Criteria::expr()->gte('startDate', $today)) + //->andWhere(Criteria::expr()->memberOf('persons', $person)) + ->orderBy(['startDate' => 'DESC']) + ->setMaxResults($limit * 2); + + return $this->calendars->matching($criteria) + ->matching( + // due to a bug, filter two times + Criteria::create() + ->where(Criteria::expr()->memberOf('persons', $person)) + ->setMaxResults($limit) + ); + } + /** * Get openingDate. * diff --git a/src/Bundle/ChillPersonBundle/Entity/Person.php b/src/Bundle/ChillPersonBundle/Entity/Person.php index 7da08d740..53aea86fd 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Person.php +++ b/src/Bundle/ChillPersonBundle/Entity/Person.php @@ -176,6 +176,14 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI */ private Collection $budgetResources; + /** + * @ORM\ManyToMany( + * targetEntity="Chill\CalendarBundle\Entity\Calendar", + * mappedBy="persons" + * ) + */ + private Collection $calendars; + /** * The person's center. * diff --git a/src/Bundle/ChillPersonBundle/Resources/views/Person/list_with_period.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/Person/list_with_period.html.twig index c407b6c57..e9df78a8f 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/Person/list_with_period.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/Person/list_with_period.html.twig @@ -149,6 +149,24 @@ {% endif %} {% endif %} + {% set calendars = [] -%} + {% for c in acp.nextCalendarsForPerson(person, 10) -%} + {% if is_granted('CHILL_CALENDAR_CALENDAR_SEE', c) -%} + {% set calendars = calendars|merge([c]) -%} + {% endif -%} + {% endfor -%} + {% if calendars|length > 0 %} +
+
+

{{ 'chill_calendar.Next calendars'|trans }}

+
+
+ {% for c in calendars %}{{ c.startDate|format_datetime('long', 'short') }}{% if not loop.last %}, {% endif %}{% endfor %} +
+
+ + {% endif %} + {% if acp.step == 'CLOSED' and acp.closingMotive is not null %}