src/EventSubscriber/CreateZoomMeetingSubscriber.php line 138

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Harmonizely\EventSubscriber;
  4. use DateTimeZone;
  5. use Doctrine\ORM\EntityManagerInterface;
  6. use Harmonizely\CalendarEvents;
  7. use Harmonizely\EventTypes\LocationTypeProvider;
  8. use Harmonizely\Integration\Provider\ZoomClientProviderInterface;
  9. use Harmonizely\Integration\Zoom\Exception\CouldNotUpdateZoomMeetingException;
  10. use Harmonizely\Model\EventInterface;
  11. use Harmonizely\Model\EventTypeInterface;
  12. use Harmonizely\Model\Integration;
  13. use Harmonizely\Model\IntegrationInterface;
  14. use Harmonizely\Model\UserInterface;
  15. use Harmonizely\Types\Company\IntegrationType;
  16. use Psr\Log\LoggerInterface;
  17. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  18. use Symfony\Component\EventDispatcher\GenericEvent;
  19. use Symfony\Contracts\Translation\TranslatorInterface;
  20. use Webmozart\Assert\Assert;
  21. final class CreateZoomMeetingSubscriber implements EventSubscriberInterface
  22. {
  23.     private $zoomClientProvider;
  24.     private $entityManager;
  25.     private $logger;
  26.     private LocationTypeProvider $locationTypeProvider;
  27.     private TranslatorInterface $translator;
  28.     public function __construct(
  29.         ZoomClientProviderInterface $zoomClientProvider,
  30.         EntityManagerInterface $entityManager,
  31.         LoggerInterface $logger,
  32.         LocationTypeProvider $locationTypeProvider,
  33.         TranslatorInterface $translator
  34.     ) {
  35.         $this->zoomClientProvider $zoomClientProvider;
  36.         $this->entityManager $entityManager;
  37.         $this->logger $logger;
  38.         $this->locationTypeProvider $locationTypeProvider;
  39.         $this->translator $translator;
  40.     }
  41.     public static function getSubscribedEvents(): array
  42.     {
  43.         return [
  44.             CalendarEvents::EVENT_PRE_CREATE => 'createMeeting',
  45.             CalendarEvents::EVENT_POST_CANCEL => 'cancelMeeting',
  46.             CalendarEvents::EVENT_POST_RESCHEDULE => 'updateMeeting',
  47.         ];
  48.     }
  49.     public function createMeeting(GenericEvent $event): void
  50.     {
  51.         /** @var EventInterface $event */
  52.         $event $event->getSubject();
  53.         Assert::isInstanceOf($eventEventInterface::class);
  54.         $eventType $event->getEventType();
  55.         $user $event->getUser();
  56.         $locationType $this->locationTypeProvider->provideFor($eventType$user$event);
  57.         $integration $this->findIntegration($user);
  58.         if (null === $integration || EventTypeInterface::LOCATION_TYPE_ZOOM !== $locationType) {
  59.             return;
  60.         }
  61.         if (!$integration->isEnabled()) {
  62.             return;
  63.         }
  64.         if ($eventType->isGroupMeetingType() && $event->getLocation()) {
  65.             return;
  66.         }
  67.         if ($event->isRecurring() && $event->getLocation()) {
  68.             return;
  69.         }
  70.         try {
  71.             $zoomClientAdapter $this->zoomClientProvider->getZoomClient($integration);
  72.             $zoomMeeting $zoomClientAdapter->createMeeting($event);
  73.         } catch (\Exception $e) {
  74.             $this->logger->critical($e->getMessage());
  75.             return;
  76.         }
  77.         $event->setLocation($zoomMeeting['join_url']);
  78.     }
  79.     public function cancelMeeting(GenericEvent $genericEvent): void
  80.     {
  81.         /** @var EventInterface $event */
  82.         $event $genericEvent->getSubject();
  83.         Assert::isInstanceOf($eventEventInterface::class);
  84.         $eventType $event->getEventType();
  85.         $user $genericEvent->hasArgument('previousUser')
  86.             ? $genericEvent->getArgument('previousUser')
  87.             : $event->getUser();
  88.         $locationType $this->locationTypeProvider->provideFor($eventType$user$event);
  89.         $integration $this->findIntegration($user);
  90.         if (null === $integration || EventTypeInterface::LOCATION_TYPE_ZOOM !== $locationType) {
  91.             return;
  92.         }
  93.         if (!$integration->isEnabled()) {
  94.             return;
  95.         }
  96.         if ($eventType->isGroupMeetingType() && $event->getLocation()) {
  97.             return;
  98.         }
  99.         if ($event->isRecurring() && $event->getLocation()) {
  100.             return;
  101.         }
  102.         try {
  103.             $zoomClientAdapter $this->zoomClientProvider->getZoomClient($integration);
  104.             $zoomClientAdapter->cancelMeeting($event);
  105.         } catch (\Exception $e) {
  106.             $this->logger->critical('Zoom meeting cancellation failed.', [
  107.                 'message' => $e->getMessage(),
  108.                 'user_email' => $user->getEmail(),
  109.                 'invitee_email' => $event->getInvitee()->getEmail(),
  110.             ]);
  111.         }
  112.     }
  113.     public function updateMeeting(GenericEvent $genericEvent): void
  114.     {
  115.         /** @var EventInterface $event */
  116.         $event $genericEvent->getSubject();
  117.         Assert::isInstanceOf($eventEventInterface::class);
  118.         /** @var EventTypeInterface $eventType */
  119.         $eventType $event->getEventType();
  120.         $user $event->getUser();
  121.         if ($event->isRecurring() && $event->getLocation()) {
  122.             return;
  123.         }
  124.         if ($event->getRescheduling()->getPreviousUser()) {
  125.             $genericEvent->setArgument('previousUser'$event->getRescheduling()->getPreviousUser());
  126.             $this->cancelMeeting($genericEvent);
  127.             $this->createMeeting($genericEvent);
  128.         } else {
  129.             $locationType $this->locationTypeProvider->provideFor($eventType$user$event);
  130.             $integration $this->findIntegration($user);
  131.             if (null === $integration || EventTypeInterface::LOCATION_TYPE_ZOOM !== $locationType) {
  132.                 return;
  133.             }
  134.             if (!$integration->isEnabled()) {
  135.                 return;
  136.             }
  137.             $eventType $event->getEventType();
  138.             $startTimeInUserTimezone = clone $event->getScheduledAt();
  139.             $startTimeInUserTimezone->setTimezone(new DateTimeZone($eventType->getUser()->getTimezone()));
  140.             $startsAt $startTimeInUserTimezone->format('Y-m-d\\TH:i:s');
  141.             $invitee $event->getInvitee();
  142.             $inviteeFullName $eventType->isGroupMeetingType()
  143.                 ? $this->translator->trans('Group meeting', [], 'messages'$event->getUser()->getLocale())
  144.                 : $invitee->getFullName();
  145.             $topic $event->getVisibleEventName().' - '.$inviteeFullName;
  146.             $duration $event->getDuration();
  147.             if (null === ($zoomLink $event->getLocation())) {
  148.                 return;
  149.             }
  150.             $zoomMeetingId = (int) basename($zoomLink);
  151.             try {
  152.                 $zoomClientAdapter $this->zoomClientProvider->getZoomClient($integration);
  153.                 $zoomClientAdapter->updateMeeting($zoomMeetingId$topic$duration$startsAt);
  154.             } catch (CouldNotUpdateZoomMeetingException $e) {
  155.                 $this->logger->critical($e->getMessage());
  156.                 return;
  157.             }
  158.         }
  159.     }
  160.     private function findIntegration(UserInterface $user): ?IntegrationInterface
  161.     {
  162.         $integrationRepository $this->entityManager->getRepository(Integration::class);
  163.         return $integrationRepository->findOneBy([
  164.             'type' => IntegrationType::TYPE_ZOOM,
  165.             'user' => $user,
  166.         ]);
  167.     }
  168. }