calendarService = $calendarService; $this->gateway = $gateway; $this->service = $service; $this->userConfigService = $userConfigService; $this->converter = $converter; $this->addressService = $addressService; } /** * @param int $addressId * @param int $calendarEventId * * @return bool */ public function canAddressEditEvent(int $addressId, int $calendarEventId): bool { $eventId = $calendarEventId; $event = $this->calendarService->tryGetEventWithoutUsers($eventId); if ($event === null) { return false; } $canEdit = false; $creator = $event->getCreator(); if ($creator !== null && $creator->getAddressId() === $addressId) { $canEdit = true; } $organizer = $event->getOrganizer(); if ($organizer !== null && $organizer->getAddressId() === $addressId) { $canEdit = true; } return $canEdit; } /** * @param GoogleCalendarClientInterface $client * @param mixed $eventId * @param string $action 'added', 'modified' or 'deleted' * * @return void */ public function calendarEventHook(GoogleCalendarClientInterface $client, $eventId, $action): void { try { $eventId = (int)$eventId; switch ($action) { case 'added': //NO BREAK case 'modified': $event = $this->calendarService->tryGetEvent($eventId); if ($event === null) { return; } $this->exportCalendarEvent($client, $event, false); break; case 'deleted': $this->exportDeleteEvent($client, $eventId); break; } } catch (Throwable $e) { $this->logger->error( 'Exception in calendarEventHook: {message}', ['message' => $e->getMessage(), 'exception' => $e] ); } } /** * @param GoogleCalendarClientInterface $client * @param CalendarEvent $event * @param bool $sendUpdates * * @throws GoogleCalendarApiException * * @return void */ public function exportCalendarEvent( GoogleCalendarClientInterface $client, CalendarEvent $event, bool $sendUpdates = false ): void { $sync = $this->gateway->tryGetSyncEntryByEvent($event->getId()); if ($sync === null || $sync->getGoogleId() === '') { $googleEvent = $this->converter->convertToGoogleEvent($event); $sendUpdateMethod = GoogleCalendarClientInterface::SENDUPDATES_DEFAULT; if ($sendUpdates === true) { $sendUpdateMethod = GoogleCalendarClientInterface::SENDUPDATES_ALL; } $insertedEvent = $client->insertEvent($googleEvent, $sendUpdateMethod); $newOrganizer = ''; if ($googleEvent->getOrganizer() !== null) { $newOrganizer = $googleEvent->getOrganizer()->getEmail(); } if ($newOrganizer !== '' && $newOrganizer !== $insertedEvent->getOrganizer()->getEmail()) { try { $insertedEvent = $client->moveEvent($insertedEvent, $newOrganizer); } catch (GoogleCalendarApiException $e) { $this->logger->error('Failed to export calendar event', ['event' => $event->toArray()]); throw new GoogleCalendarApiException($e->getMessage(), $e->getCode(), $e); } } $address = $this->addressService->getAddressByUser($client->getAccount()->getUserId()); $sync = new GoogleCalenderSyncValue( 0, $event->getId(), $insertedEvent->getId(), $address, false, $event->getStart(), $insertedEvent->getHtmlLink() ); } else { $existingEvent = $client->getEvent($sync->getGoogleId()); $googleEvent = $this->converter->convertToGoogleEvent($event, $existingEvent); $updated = $client->updateEvent($googleEvent); $sync->setEventDate($event->getStart()); $sync->setHtmlLink($updated->getHtmlLink()); } $this->service->saveSyncEntry($sync); } /** * @param GoogleCalendarClientInterface $client * @param int $eventId * * @return void */ public function exportDeleteEvent(GoogleCalendarClientInterface $client, int $eventId): void { $sync = $this->gateway->tryGetSyncEntryByEvent($eventId); if ($sync === null || $sync->getGoogleId() === '') { return; } $client->deleteEvent($sync->getGoogleId()); $this->service->deleteSyncEntry($sync->getGoogleId(), $sync->getEventId()); } /** * @param GoogleCalendarClientInterface $client * * @return void */ public function importChangedEvents(GoogleCalendarClientInterface $client): void { $lastSync = $this->userConfigService->tryGet( self::CONFIG_KEY_LAST_SYNC, $client->getAccount()->getUserId() ); if ($lastSync === null) { $now = new DateTime('now'); $lastSyncDate = $now->sub(new DateInterval('P1D')); } else { $lastSyncDate = DateTime::createFromFormat('Y-m-d H:i:s', $lastSync); } $importEvents = $client->getModifiedEvents('primary', $lastSyncDate); $userAddress = $this->addressService->getAddressByUser($client->getAccount()->getUserId()); try { $colors = $client->getAvailableColors(); } catch (Exception $e) { $colors = null; } try { $this->importGoogleEvents($importEvents, $userAddress, $colors); } catch (Exception $e) { throw new GoogleCalendarSyncException('Error during Google Calender Sync.', $e->getCode(), $e); } $now = new DateTime('now'); $this->userConfigService->set( self::CONFIG_KEY_LAST_SYNC, $now->format('Y-m-d H:i:s'), $client->getAccount()->getUserId() ); } /** * @param GoogleCalendarClientInterface $client * @param DateTimeInterface|null $from * @param DateTimeInterface|null $to * * @throws GoogleCalendarSyncException * * @return void */ public function importAbsoluteEvents( GoogleCalendarClientInterface $client, DateTimeInterface $from = null, DateTimeInterface $to = null ): void { $now = new DateTimeImmutable('now'); if ($from === null) { /** @noinspection CallableParameterUseCaseInTypeContextInspection */ $from = $now->sub(new DateInterval('P1W')); } if ($to === null) { $to = $now->add(new DateInterval('P3W')); } $importEvents = $client->getAbsoluteEvents('primary', $from, $to); $this->logger->debug( 'Google responded with {count} events to import for "user_id={user}"', ['count' => count($importEvents), 'user' => $client->getAccount()->getUserId()] ); try { $colors = $client->getAvailableColors(); } catch (Exception $e) { $colors = null; } $userAddress = $this->addressService->getAddressByUser($client->getAccount()->getUserId()); try { $this->importGoogleEvents($importEvents, $userAddress, $colors); } catch (Exception $e) { $this->logger->error('Exception ' . $e->getMessage(), ['exception' => $e]); throw new GoogleCalendarSyncException('Error during Google Calender Sync.', $e->getCode(), $e); } } /** * @param GoogleCalendarEventData $googleEvent * @param int $addressId * @param GoogleCalendarColorCollection|null $colors * * @return void */ public function importGoogleEvent( GoogleCalendarEventData $googleEvent, int $addressId, GoogleCalendarColorCollection $colors = null ): void { if (strtolower($googleEvent->getStatus()) === 'cancelled') { $this->importDeletedGoogleEvent($googleEvent, $addressId); return; } $creator = $googleEvent->getCreator(); $owner = 0; if ($creator !== null) { $owner = $this->addressService->findAddressByEmail($creator->getEmail()); } $sync = $this->gateway->tryGetSyncEntryByGoogleEvent($googleEvent->getId()); if ($sync === null) { $sync = new GoogleCalenderSyncValue( 0, 0, $googleEvent->getId(), $owner, true, $googleEvent->getTime()->getBeginning(), $googleEvent->getHtmlLink() ); } $existingEvent = null; if ($sync->getEventId() > 0) { $existingEvent = $this->calendarService->tryGetEventWithoutUsers($sync->getEventId()); } $event = $this->converter->convertToEvent($googleEvent, $existingEvent); if ($colors !== null) { $color = $colors->getEventColorById($googleEvent->getColorId()); if ($color === null) { $color = $colors->getDefaultColor(); } if ($color !== null) { $event->setColor($color->getBackground()); } } $id = $this->calendarService->saveEvent($event); $sync->setEventId($id); $sync->setEventDate($event->getStart()); $sync->setOwner($owner); $this->service->saveSyncEntry($sync); } /** * @param GoogleCalendarEventData $googleEvent * @param int $addressId * * @return void */ public function importDeletedGoogleEvent( GoogleCalendarEventData $googleEvent, int $addressId = 0 ): void { $sync = $this->gateway->tryGetSyncEntryByGoogleEvent($googleEvent->getId()); if ($sync === null) { return; //event has never been synced } $event = $this->calendarService->tryGetEventWithoutUsers($sync->getEventId()); if ($event === null) { return; //event was already deleted } $owner = 0; if ($event->getCreator() !== null) { $owner = $event->getCreator()->getAddressId(); } $editor = 0; if ($event->getOrganizer() !== null) { $editor = $event->getOrganizer()->getAddressId(); } if ($owner === $addressId || $editor === $addressId) { $this->calendarService->deleteEvent($sync->getEventId()); $this->service->deleteSyncEntry($sync->getGoogleId(), $sync->getEventId()); } else { $userId = $this->addressService->getUserByAddress($addressId); $this->calendarService->removeUserFromEvent($sync->getEventId(), $userId); } } /** * * @param array $googleEvents * @param int $addressId * @param GoogleCalendarColorCollection|null $colors * * @return void */ public function importGoogleEvents( array $googleEvents, int $addressId, GoogleCalendarColorCollection $colors = null ): void { $this->logger->debug( 'import {count} events on addressId {address}', ['count' => count($googleEvents), 'address' => $addressId,] ); foreach ($googleEvents as $googleEvent) { try { $this->importGoogleEvent($googleEvent, $addressId, $colors); } catch (Exception $e) { $this->logger->error( 'failed to import Google event {event}', ['event' => $googleEvent->getHtmlLink(), 'exception' => $e] ); continue; } } } }