Initial xentral_oss_20.3.c9ffacf
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar;
|
||||
|
||||
use Xentral\Core\DependencyInjection\ContainerInterface;
|
||||
use Xentral\Modules\GoogleCalendar\Client\GoogleCalendarClientFactory;
|
||||
use Xentral\Modules\GoogleCalendar\Service\GoogleCalendarSynchronizer;
|
||||
use Xentral\Modules\GoogleCalendar\Service\GoogleEventConverter;
|
||||
use Xentral\Modules\GoogleCalendar\Service\GoogleSyncGateway;
|
||||
use Xentral\Modules\GoogleCalendar\Service\GoogleSyncService;
|
||||
use Xentral\Modules\GoogleCalendar\Wrapper\UserAddressGatewayWrapper;
|
||||
|
||||
final class Bootstrap
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function registerServices(): array
|
||||
{
|
||||
return [
|
||||
'GoogleCalendarClientFactory' => 'onInitGoogleCalendarClientFactory',
|
||||
'GoogleSyncGateway' => 'onInitGoogleSyncEntryGateway',
|
||||
'GoogleSyncService' => 'onInitGoogleSyncEntryService',
|
||||
'GoogleEventConverter' => 'onInitGoogleEventConverter',
|
||||
'GoogleCalendarSynchronizer' => 'onInitGoogleCalendarSynchronizer',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return GoogleCalendarClientFactory
|
||||
*/
|
||||
public static function onInitGoogleCalendarClientFactory(ContainerInterface $container): GoogleCalendarClientFactory
|
||||
{
|
||||
return new GoogleCalendarClientFactory(
|
||||
$container->get('GoogleApiClientFactory'),
|
||||
$container->get('GoogleAccountGateway')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return GoogleSyncGateway
|
||||
*/
|
||||
public static function onInitGoogleSyncEntryGateway(ContainerInterface $container): GoogleSyncGateway
|
||||
{
|
||||
return new GoogleSyncGateway(
|
||||
$container->get('Database')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return GoogleSyncService
|
||||
*/
|
||||
public static function onInitGoogleSyncEntryService(ContainerInterface $container): GoogleSyncService
|
||||
{
|
||||
return new GoogleSyncService(
|
||||
$container->get('Database'),
|
||||
$container->get('GoogleSyncGateway')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return GoogleEventConverter
|
||||
*/
|
||||
public static function onInitGoogleEventConverter(ContainerInterface $container): GoogleEventConverter
|
||||
{
|
||||
return new GoogleEventConverter(
|
||||
self::onInitUserAddressGatewayWrapper($container)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return GoogleCalendarSynchronizer
|
||||
*/
|
||||
public static function onInitGoogleCalendarSynchronizer(ContainerInterface $container): GoogleCalendarSynchronizer
|
||||
{
|
||||
return new GoogleCalendarSynchronizer(
|
||||
$container->get('GoogleSyncGateway'),
|
||||
$container->get('GoogleSyncService'),
|
||||
$container->get('CalendarService'),
|
||||
$container->get('GoogleEventConverter'),
|
||||
self::onInitUserAddressGatewayWrapper($container),
|
||||
$container->get('UserConfigService')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return UserAddressGatewayWrapper
|
||||
*/
|
||||
private static function onInitUserAddressGatewayWrapper(ContainerInterface $container): UserAddressGatewayWrapper
|
||||
{
|
||||
return new UserAddressGatewayWrapper($container->get('Database'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,428 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Client;
|
||||
|
||||
use DateInterval;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
use Exception;
|
||||
use Xentral\Components\HttpClient\Response\ServerResponse;
|
||||
use Xentral\Components\Logger\LoggerAwareTrait;
|
||||
use Xentral\Modules\GoogleApi\Client\GoolgeApiClientInterface;
|
||||
use Xentral\Modules\GoogleApi\Data\GoogleAccountData;
|
||||
use Xentral\Modules\GoogleCalendar\Data\GoogleCalendarColorCollection;
|
||||
use Xentral\Modules\GoogleCalendar\Data\GoogleCalendarEventData;
|
||||
use Xentral\Modules\GoogleCalendar\Data\GoogleCalendarListItem;
|
||||
use Xentral\Modules\GoogleCalendar\Exception\GoogleCalendarApiException;
|
||||
use Xentral\Modules\GoogleCalendar\Exception\GoogleCalendarNotFoundException;
|
||||
use Xentral\Modules\GoogleCalendar\Exception\InvalidArgumentException;
|
||||
|
||||
final class GoogleCalendarClient implements GoogleCalendarClientInterface
|
||||
{
|
||||
use LoggerAwareTrait;
|
||||
|
||||
/** @var string CALENDAR_PRIMARY */
|
||||
public const CALENDAR_PRIMARY = 'primary';
|
||||
|
||||
/** @var string BASE_URL */
|
||||
private const BASE_URL = 'https://www.googleapis.com/calendar/v3';
|
||||
|
||||
/** @var GoolgeApiClientInterface $googleApiClient */
|
||||
private $googleApiClient;
|
||||
|
||||
/**
|
||||
* @param GoolgeApiClientInterface $googleApiClient
|
||||
*/
|
||||
public function __construct(
|
||||
GoolgeApiClientInterface $googleApiClient
|
||||
) {
|
||||
$this->googleApiClient = $googleApiClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $filters
|
||||
*
|
||||
* @throws GoogleCalendarApiException
|
||||
*
|
||||
* @return GoogleCalendarListItem[]
|
||||
*/
|
||||
public function getCalendarList(array $filters = []): array
|
||||
{
|
||||
$uri = $this->createUri('users/me/calendarList', $filters);
|
||||
try {
|
||||
$result = $this->googleApiClient->sendRequest('GET', $uri);
|
||||
} catch (Exception $e) {
|
||||
throw new GoogleCalendarApiException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
$list = [];
|
||||
if (isset($result['items']) && is_array($result['items'])) {
|
||||
foreach ($result['items'] as $item) {
|
||||
$list[] = GoogleCalendarListItem::fromArray($item);
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws GoogleCalendarNotFoundException
|
||||
* @throws GoogleCalendarApiException
|
||||
*
|
||||
* @return GoogleCalendarListItem
|
||||
*/
|
||||
public function getPrimaryCalendar(): GoogleCalendarListItem
|
||||
{
|
||||
$ownedCalendars = $this->getCalendarList(['minAccessRole' => 'owner']);
|
||||
foreach ($ownedCalendars as $calendarListItem) {
|
||||
if ($calendarListItem->isPrimary()) {
|
||||
return $calendarListItem;
|
||||
}
|
||||
}
|
||||
throw new GoogleCalendarNotFoundException(
|
||||
sprintf('Cannot get primary calendar of user "id=%s"', $this->getAccount()->getUserId())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $calendar
|
||||
* @param DateTimeInterface $modifiedSince
|
||||
*
|
||||
* @return GoogleCalendarEventData[]
|
||||
*/
|
||||
public function getModifiedEvents(string $calendar, DateTimeInterface $modifiedSince): array
|
||||
{
|
||||
$modifiedTimestamp = $modifiedSince->format(DateTimeInterface::RFC3339);
|
||||
$filters = [
|
||||
'updatedMin' => $modifiedTimestamp,
|
||||
];
|
||||
$now = new DateTimeImmutable();
|
||||
$now = $now->setTimestamp(time());
|
||||
$from = $now->sub(new DateInterval('P1W'));
|
||||
$to = $now->add(new DateInterval('P3W'));
|
||||
$filters['timeMax'] = $to->format(DateTimeInterface::RFC3339);
|
||||
$filters['timeMin'] = $from->format(DateTimeInterface::RFC3339);
|
||||
|
||||
return $this->getEventList($calendar, $filters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $calendar
|
||||
* @param DateTimeInterface $from
|
||||
* @param DateTimeInterface $to
|
||||
*
|
||||
* @return GoogleCalendarEventData[]
|
||||
*/
|
||||
public function getAbsoluteEvents(string $calendar, DateTimeInterface $from, DateTimeInterface $to): array
|
||||
{
|
||||
$filters = [];
|
||||
$filters['timeMax'] = $to->format(DateTimeInterface::RFC3339);
|
||||
$filters['timeMin'] = $from->format(DateTimeInterface::RFC3339);
|
||||
|
||||
return $this->getEventList($calendar, $filters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $eventId
|
||||
*
|
||||
* @throws GoogleCalendarApiException
|
||||
*
|
||||
* @return GoogleCalendarEventData
|
||||
*/
|
||||
public function getEvent($eventId): GoogleCalendarEventData
|
||||
{
|
||||
$path = sprintf('calendars/%s/events/%s', self::CALENDAR_PRIMARY, $eventId);
|
||||
$url = $this->createUri($path);
|
||||
try {
|
||||
$result = $this->googleApiClient->sendRequest('GET', $url);
|
||||
} catch (Exception $e) {
|
||||
throw new GoogleCalendarApiException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return GoogleCalendarEventData::fromArray($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $calendar calendar identifier
|
||||
* @param array $filters
|
||||
*
|
||||
* @throws GoogleCalendarApiException
|
||||
*
|
||||
* @return GoogleCalendarEventData[]
|
||||
*/
|
||||
public function getEventList(string $calendar, $filters = []): array
|
||||
{
|
||||
$path = sprintf('calendars/%s/events', $calendar);
|
||||
$filters['singleEvents'] = 'true';
|
||||
$url = $this->createUri($path, $filters);
|
||||
try {
|
||||
$result = $this->googleApiClient->sendRequest('GET', $url);
|
||||
} catch (Exception $e) {
|
||||
throw new GoogleCalendarApiException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
$events = [];
|
||||
foreach ($result['items'] as $event) {
|
||||
$events[] = GoogleCalendarEventData::fromArray($event);
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param GoogleCalendarEventData $event
|
||||
* @param string $sendUpdates
|
||||
*
|
||||
* @throws GoogleCalendarApiException
|
||||
*
|
||||
* @return GoogleCalendarEventData
|
||||
*/
|
||||
public function insertEvent(
|
||||
GoogleCalendarEventData $event,
|
||||
$sendUpdates = self::SENDUPDATES_DEFAULT
|
||||
): GoogleCalendarEventData {
|
||||
$this->validateSendUpdatesParam($sendUpdates);
|
||||
$queryParams = [];
|
||||
if ($sendUpdates !== self::SENDUPDATES_DEFAULT) {
|
||||
$queryParams = ['sendUpdates' => $sendUpdates];
|
||||
}
|
||||
$url = $this->createUri(sprintf('calendars/%s/events', self::CALENDAR_PRIMARY), $queryParams);
|
||||
try {
|
||||
$result = $this->googleApiClient->sendRequest('POST', $url, $event->toArray());
|
||||
} catch (Exception $e) {
|
||||
throw new GoogleCalendarApiException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return GoogleCalendarEventData::fromArray($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param GoogleCalendarEventData $event
|
||||
* @param string $sendUpdates
|
||||
*
|
||||
* @throws GoogleCalendarApiException
|
||||
*
|
||||
* @return GoogleCalendarEventData
|
||||
*/
|
||||
public function updateEvent(
|
||||
GoogleCalendarEventData $event,
|
||||
$sendUpdates = self::SENDUPDATES_DEFAULT
|
||||
): GoogleCalendarEventData {
|
||||
$this->validateSendUpdatesParam($sendUpdates);
|
||||
$postData = $event->toArray();
|
||||
$queryParams = [];
|
||||
if ($sendUpdates !== self::SENDUPDATES_DEFAULT) {
|
||||
$queryParams = ['sendUpdates' => $sendUpdates];
|
||||
}
|
||||
$url = $this->createUri(
|
||||
sprintf(
|
||||
'calendars/%s/events/%s',
|
||||
self::CALENDAR_PRIMARY,
|
||||
$event->getId()
|
||||
),
|
||||
$queryParams
|
||||
);
|
||||
try {
|
||||
$result = $this->googleApiClient->sendRequest('PUT', $url, $postData);
|
||||
} catch (Exception $e) {
|
||||
throw new GoogleCalendarApiException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return GoogleCalendarEventData::fromArray($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param GoogleCalendarEventData $event
|
||||
* @param string $targetCalendar
|
||||
* @param string $sendUpdates
|
||||
*
|
||||
* @throws GoogleCalendarApiException
|
||||
*
|
||||
* @return GoogleCalendarEventData
|
||||
*/
|
||||
public function moveEvent(
|
||||
GoogleCalendarEventData $event,
|
||||
$targetCalendar,
|
||||
$sendUpdates = self::SENDUPDATES_DEFAULT
|
||||
): GoogleCalendarEventData {
|
||||
$this->validateSendUpdatesParam($sendUpdates);
|
||||
$queryParams = ['destination' => $targetCalendar];
|
||||
if ($sendUpdates !== self::SENDUPDATES_DEFAULT) {
|
||||
$queryParams['sendUpdates'] = $sendUpdates;
|
||||
}
|
||||
$url = $this->createUri(
|
||||
sprintf('calendars/%s/events/%s/move', self::CALENDAR_PRIMARY, $event->getId()),
|
||||
$queryParams
|
||||
);
|
||||
try {
|
||||
$result = $this->googleApiClient->sendRequest('POST', $url);
|
||||
} catch (Exception $e) {
|
||||
throw new GoogleCalendarApiException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return GoogleCalendarEventData::fromArray($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $eventId
|
||||
* @param string $sendUpdates
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteEvent(
|
||||
$eventId,
|
||||
$sendUpdates = self::SENDUPDATES_DEFAULT
|
||||
): bool {
|
||||
$this->validateSendUpdatesParam($sendUpdates);
|
||||
$queryParams = [];
|
||||
if ($sendUpdates !== self::SENDUPDATES_DEFAULT) {
|
||||
$queryParams = ['sendUpdates' => $sendUpdates];
|
||||
}
|
||||
$url = $this->createUri(
|
||||
sprintf('calendars/%s/events/%s', self::CALENDAR_PRIMARY, $eventId),
|
||||
$queryParams
|
||||
);
|
||||
try {
|
||||
$this->googleApiClient->sendRequest('DELETE', $url, null, []);
|
||||
} catch (Exception $e) {
|
||||
$httpCode = $e->getCode();
|
||||
if ($httpCode> 399 && $httpCode < 500) {
|
||||
return false;
|
||||
}
|
||||
throw new GoogleCalendarApiException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $calendar
|
||||
*
|
||||
* @throws GoogleCalendarApiException
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canAccessCalendar(string $calendar): bool
|
||||
{
|
||||
$url = $this->createUri(sprintf('calendars/%s', $calendar));
|
||||
try {
|
||||
$this->googleApiClient->sendRequest('GET', $url);
|
||||
} catch (Exception $e) {
|
||||
$httpCode = $e->getCode();
|
||||
if ($httpCode > 399 && $httpCode < 500) {
|
||||
return false;
|
||||
}
|
||||
throw new GoogleCalendarApiException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws GoogleCalendarApiException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getUserSettings(): array
|
||||
{
|
||||
$url = $this->createUri('users/me/settings');
|
||||
try {
|
||||
$result = $this->googleApiClient->sendRequest('GET', $url);
|
||||
} catch (Exception $e) {
|
||||
throw new GoogleCalendarApiException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
$settings = [];
|
||||
if (isset($result['items']) && is_array($result['items'])) {
|
||||
foreach ($result['items'] as $setting) {
|
||||
$settings[$setting['id']] = $setting['value'];
|
||||
}
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws GoogleCalendarApiException
|
||||
*
|
||||
* @return GoogleCalendarColorCollection
|
||||
*/
|
||||
public function getAvailableColors(): GoogleCalendarColorCollection
|
||||
{
|
||||
$url = $this->createUri('colors');
|
||||
try {
|
||||
$result = $this->googleApiClient->sendRequest('GET', $url);
|
||||
} catch (Exception $e) {
|
||||
throw new GoogleCalendarApiException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
$colors = GoogleCalendarColorCollection::createFromJsonArray($result);
|
||||
$default = $this->getDefaultColorId();
|
||||
$colors->setDefaultColorId($default);
|
||||
|
||||
return $colors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return GoogleAccountData
|
||||
*/
|
||||
public function getAccount(): GoogleAccountData
|
||||
{
|
||||
return $this->googleApiClient->getAccount();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $uri
|
||||
* @param array $queryParams
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function createUri(string $uri, array $queryParams = []): string
|
||||
{
|
||||
$url = sprintf('%s/%s', self::BASE_URL, $uri);
|
||||
if (!empty($queryParams)) {
|
||||
$url .= '?' . http_build_query($queryParams);
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sendUpdates
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function validateSendUpdatesParam(string $sendUpdates): bool
|
||||
{
|
||||
if (
|
||||
$sendUpdates !== self::SENDUPDATES_DEFAULT
|
||||
&& $sendUpdates !== self::SENDUPDATES_EXTERNALONLY
|
||||
&& $sendUpdates !== self::SENDUPDATES_NONE
|
||||
&& $sendUpdates !== self::SENDUPDATES_ALL
|
||||
) {
|
||||
throw new InvalidArgumentException('Ivalid value for query parameter "sendUpdates".');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws GoogleCalendarApiException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getDefaultColorId(): string
|
||||
{
|
||||
$colorId = '';
|
||||
$filters = [];
|
||||
$filters['minAccessRole'] = 'owner';
|
||||
$calendars = $this->getCalendarList($filters);
|
||||
foreach ($calendars as $calendar) {
|
||||
if ($calendar->isPrimary()) {
|
||||
$colorId = $calendar->getColorId();
|
||||
}
|
||||
}
|
||||
|
||||
return $colorId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Client;
|
||||
|
||||
use Xentral\Components\Logger\LoggerAwareTrait;
|
||||
use Xentral\Modules\GoogleApi\Client\GoogleApiClientFactory;
|
||||
use Xentral\Modules\GoogleApi\Exception\GoogleAccountNotFoundException as AccountNotFoundException;
|
||||
use Xentral\Modules\GoogleApi\Exception\NoRefreshTokenException as AccessException;
|
||||
use Xentral\Modules\GoogleApi\GoogleScope;
|
||||
use Xentral\Modules\GoogleApi\Service\GoogleAccountGateway;
|
||||
use Xentral\Modules\GoogleCalendar\Exception\GoogleAccountNotFoundException;
|
||||
use Xentral\Modules\GoogleCalendar\Exception\GoogleApiAccessException;
|
||||
use Xentral\Modules\GoogleCalendar\Exception\GoogleApiScopeException;
|
||||
|
||||
final class GoogleCalendarClientFactory
|
||||
{
|
||||
use LoggerAwareTrait;
|
||||
|
||||
/** @var GoogleApiClientFactory $clientFactory */
|
||||
private $clientFactory;
|
||||
|
||||
/** @var GoogleAccountGateway $gateway */
|
||||
private $gateway;
|
||||
|
||||
/**
|
||||
* @param GoogleApiClientFactory $clientFactory
|
||||
* @param GoogleAccountGateway $gateway
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct(GoogleApiClientFactory $clientFactory, GoogleAccountGateway $gateway)
|
||||
{
|
||||
$this->clientFactory = $clientFactory;
|
||||
$this->gateway = $gateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $userId
|
||||
*
|
||||
* @throws GoogleAccountNotFoundException
|
||||
* @throws GoogleApiAccessException
|
||||
* @throws GoogleApiScopeException
|
||||
*
|
||||
* @return GoogleCalendarClient
|
||||
*/
|
||||
public function createClient(int $userId): GoogleCalendarClient
|
||||
{
|
||||
try {
|
||||
$apiClient = $this->clientFactory->createClient($userId);
|
||||
} catch (AccountNotFoundException $e) {
|
||||
throw new GoogleAccountNotFoundException($e->getMessage(), $e->getCode(), $e);
|
||||
} catch (AccessException $e) {
|
||||
throw new GoogleApiAccessException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
$account = $apiClient->getAccount();
|
||||
if (!$this->gateway->hasAccountScope($account->getId(), GoogleScope::CALENDAR)) {
|
||||
$this->logger->debug(
|
||||
'User (id={id}) has not granted access to the google calendar API',
|
||||
['id' => $account->getUserId()]
|
||||
);
|
||||
throw new GoogleApiScopeException('Access to Google calendar API scope denied');
|
||||
}
|
||||
$client = new GoogleCalendarClient($apiClient);
|
||||
$client->setLogger($this->logger);
|
||||
|
||||
return $client;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Client;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Xentral\Modules\GoogleApi\Data\GoogleAccountData;
|
||||
use Xentral\Modules\GoogleCalendar\Data\GoogleCalendarColorCollection;
|
||||
use Xentral\Modules\GoogleCalendar\Data\GoogleCalendarEventData;
|
||||
use Xentral\Modules\GoogleCalendar\Data\GoogleCalendarListItem;
|
||||
use Xentral\Modules\GoogleCalendar\Exception\GoogleCalendarApiException;
|
||||
|
||||
interface GoogleCalendarClientInterface
|
||||
{
|
||||
/** @var string SENDUPDATES_DEFAULT */
|
||||
public const SENDUPDATES_DEFAULT = 'default';
|
||||
|
||||
/** @var string SENDUPDATES_ALL */
|
||||
public const SENDUPDATES_ALL = 'all';
|
||||
|
||||
/** @var string SENDUPDATES_EXTERNALONLY */
|
||||
public const SENDUPDATES_EXTERNALONLY = 'externalOnly';
|
||||
|
||||
/** @var string SENDUPDATES_NONE */
|
||||
public const SENDUPDATES_NONE = 'none';
|
||||
|
||||
/**
|
||||
* @return GoogleAccountData
|
||||
*/
|
||||
public function getAccount(): GoogleAccountData;
|
||||
|
||||
/**
|
||||
* @param array $filters
|
||||
*
|
||||
* @return GoogleCalendarListItem[]
|
||||
*/
|
||||
public function getCalendarList(array $filters = []): array;
|
||||
|
||||
/**
|
||||
* @return GoogleCalendarListItem
|
||||
*/
|
||||
public function getPrimaryCalendar(): GoogleCalendarListItem;
|
||||
|
||||
/**
|
||||
* @param string $calendar
|
||||
* @param DateTimeInterface $modifiedSince
|
||||
*
|
||||
* @return GoogleCalendarEventData[]
|
||||
*/
|
||||
public function getModifiedEvents(string $calendar, DateTimeInterface $modifiedSince): array;
|
||||
|
||||
|
||||
/**
|
||||
* @param string $calendar
|
||||
* @param DateTimeInterface $from
|
||||
* @param DateTimeInterface $to
|
||||
*
|
||||
* @return GoogleCalendarEventData[]
|
||||
*/
|
||||
public function getAbsoluteEvents(string $calendar, DateTimeInterface $from, DateTimeInterface $to): array;
|
||||
|
||||
/**
|
||||
* @param string $eventId
|
||||
*
|
||||
* @throws GoogleCalendarApiException
|
||||
*
|
||||
* @return GoogleCalendarEventData
|
||||
*/
|
||||
public function getEvent($eventId): GoogleCalendarEventData;
|
||||
|
||||
/**
|
||||
* @param string $calendar calendar identifier
|
||||
* @param array $filters
|
||||
*
|
||||
* @return GoogleCalendarEventData[]
|
||||
*/
|
||||
public function getEventList(string $calendar, $filters = []): array;
|
||||
|
||||
/**
|
||||
* @param GoogleCalendarEventData $event
|
||||
* @param string $sendUpdates
|
||||
*
|
||||
* @return GoogleCalendarEventData
|
||||
*/
|
||||
public function insertEvent(
|
||||
GoogleCalendarEventData $event,
|
||||
$sendUpdates = self::SENDUPDATES_DEFAULT
|
||||
): GoogleCalendarEventData;
|
||||
|
||||
/**
|
||||
* @param GoogleCalendarEventData $event
|
||||
* @param string $sendUpdates
|
||||
*
|
||||
* @return GoogleCalendarEventData
|
||||
*/
|
||||
public function updateEvent(
|
||||
GoogleCalendarEventData $event,
|
||||
$sendUpdates = self::SENDUPDATES_DEFAULT
|
||||
): GoogleCalendarEventData;
|
||||
|
||||
/**
|
||||
* @param GoogleCalendarEventData $event
|
||||
* @param string $targetCalendar
|
||||
* @param string $sendUpdates
|
||||
*
|
||||
* @return GoogleCalendarEventData
|
||||
*/
|
||||
public function moveEvent(
|
||||
GoogleCalendarEventData $event,
|
||||
$targetCalendar,
|
||||
$sendUpdates = self::SENDUPDATES_DEFAULT
|
||||
): GoogleCalendarEventData;
|
||||
|
||||
/**
|
||||
* @param string $eventId
|
||||
* @param string $sendUpdates
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteEvent(
|
||||
$eventId,
|
||||
$sendUpdates = self::SENDUPDATES_DEFAULT
|
||||
): bool;
|
||||
|
||||
/**
|
||||
* @param string $calendar
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canAccessCalendar(string $calendar): bool;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getUserSettings(): array;
|
||||
|
||||
/**
|
||||
* @return GoogleCalendarColorCollection
|
||||
*/
|
||||
public function getAvailableColors(): GoogleCalendarColorCollection;
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Data;
|
||||
|
||||
use Xentral\Modules\GoogleCalendar\Exception\InvalidArgumentException;
|
||||
|
||||
final class GoogleCalendarColorCollection
|
||||
{
|
||||
/** @var GoogleCalendarColorValue[] $eventColors */
|
||||
private $eventColors;
|
||||
|
||||
/** @var GoogleCalendarColorValue[] $eventColors */
|
||||
private $calendarColors;
|
||||
|
||||
/** @var string $defaultColorId */
|
||||
private $defaultColorId;
|
||||
|
||||
/**
|
||||
* @param GoogleCalendarColorValue[] $eventColors
|
||||
* @param GoogleCalendarColorValue[] $calendarColors
|
||||
*/
|
||||
private function __construct(array $eventColors, array $calendarColors)
|
||||
{
|
||||
$this->eventColors = $eventColors;
|
||||
$this->calendarColors = $calendarColors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @return GoogleCalendarColorCollection
|
||||
*/
|
||||
public static function createFromJsonArray(array $data): GoogleCalendarColorCollection
|
||||
{
|
||||
if (!isset($data['kind'], $data['event'], $data['calendar']) || $data['kind'] !== 'calendar#colors') {
|
||||
throw new InvalidArgumentException('Invalid Json Format for this resource.');
|
||||
}
|
||||
$eventColors = [];
|
||||
foreach ($data['event'] as $index => $ec) {
|
||||
$eventColors[] = new GoogleCalendarColorValue((string)$index, $ec['background'], $ec['foreground']);
|
||||
}
|
||||
$calendarColors = [];
|
||||
foreach ($data['calendar'] as $index => $ec) {
|
||||
$calendarColors[] = new GoogleCalendarColorValue((string)$index, $ec['background'], $ec['foreground']);
|
||||
}
|
||||
|
||||
return new self($eventColors, $calendarColors);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $colorId
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setDefaultColorId(string $colorId): void
|
||||
{
|
||||
$this->defaultColorId = $colorId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return GoogleCalendarColorValue|null
|
||||
*/
|
||||
public function getDefaultColor(): ?GoogleCalendarColorValue
|
||||
{
|
||||
if ($this->defaultColorId === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->getCalendarColorById($this->defaultColorId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $colorId
|
||||
*
|
||||
* @return GoogleCalendarColorValue|null
|
||||
*/
|
||||
public function getEventColorById(string $colorId): ?GoogleCalendarColorValue
|
||||
{
|
||||
foreach ($this->eventColors as $color) {
|
||||
if ($color->getIdentifier() === $colorId) {
|
||||
return $color;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return GoogleCalendarColorValue[]
|
||||
*/
|
||||
public function getAllEventColors(): array
|
||||
{
|
||||
return array_values($this->eventColors);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $colorId
|
||||
*
|
||||
* @return GoogleCalendarColorValue|null
|
||||
*/
|
||||
public function getCalendarColorById(string $colorId): ?GoogleCalendarColorValue
|
||||
{
|
||||
foreach ($this->calendarColors as $color) {
|
||||
if ($color->getIdentifier() === $colorId) {
|
||||
return $color;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return GoogleCalendarColorValue[]
|
||||
*/
|
||||
public function getAllCalendarColors(): array
|
||||
{
|
||||
return array_values($this->calendarColors);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Data;
|
||||
|
||||
final class GoogleCalendarColorValue
|
||||
{
|
||||
/** @var string $identifier */
|
||||
private $identifier;
|
||||
|
||||
/** @var string $background */
|
||||
private $background;
|
||||
|
||||
/** @var string $foregroud */
|
||||
private $foregroud;
|
||||
|
||||
/**
|
||||
* @param string $identifier
|
||||
* @param string $background
|
||||
* @param string $foregroud
|
||||
*/
|
||||
public function __construct(string $identifier, string $background, string $foregroud)
|
||||
{
|
||||
$this->identifier = $identifier;
|
||||
$this->background = $background;
|
||||
$this->foregroud = $foregroud;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier(): string
|
||||
{
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string color hex code
|
||||
*/
|
||||
public function getBackground(): string
|
||||
{
|
||||
return $this->background;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string color hex code
|
||||
*/
|
||||
public function getForegroud(): string
|
||||
{
|
||||
return $this->foregroud;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Data;
|
||||
|
||||
use Xentral\Modules\GoogleCalendar\Exception\InvalidArgumentException;
|
||||
|
||||
final class GoogleCalendarEventAttendeeValue
|
||||
{
|
||||
/** @var string STATUS_ACCEPTED */
|
||||
public const STATUS_ACCEPTED = 'accepted';
|
||||
|
||||
/** @var string STATUS_TENTATIVE */
|
||||
public const STATUS_TENTATIVE = 'tentative';
|
||||
|
||||
/** @var string STATUS_NEEDSACTION */
|
||||
public const STATUS_NEEDSACTION = 'needsAction';
|
||||
|
||||
/** @var string STATUS_DECLINED */
|
||||
public const STATUS_DECLINED = 'declined';
|
||||
|
||||
/** @var string $email */
|
||||
private $email;
|
||||
|
||||
/** @var bool $self */
|
||||
private $self;
|
||||
|
||||
/** @var string $displayName */
|
||||
private $displayName;
|
||||
|
||||
/** @var string $identifier */
|
||||
private $identifier;
|
||||
|
||||
/** @var string $responseStatus */
|
||||
private $responseStatus;
|
||||
|
||||
/** @var bool $optional */
|
||||
private $optional;
|
||||
|
||||
/**
|
||||
* @param string $email
|
||||
* @param string $displayName
|
||||
* @param bool $optional
|
||||
* @param string $identifier
|
||||
* @param string $responseStatus
|
||||
* @param bool $self
|
||||
*/
|
||||
public function __construct(
|
||||
string $email,
|
||||
string $displayName = '',
|
||||
bool $optional = false,
|
||||
string $identifier = '',
|
||||
string $responseStatus = '',
|
||||
bool $self = false
|
||||
) {
|
||||
if ($email === '' || $email === null) {
|
||||
throw new InvalidArgumentException('Email address is required.');
|
||||
}
|
||||
$this->email = $email;
|
||||
$this->self = $self;
|
||||
$this->identifier = $identifier;
|
||||
$this->displayName = $displayName;
|
||||
$this->responseStatus = $responseStatus;
|
||||
$this->optional = $optional;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return GoogleCalendarEventAttendeeValue
|
||||
*/
|
||||
public static function createFromJsonArray(array $data): GoogleCalendarEventAttendeeValue
|
||||
{
|
||||
if (!isset($data['email'])) {
|
||||
throw new InvalidArgumentException('Invalid data format.');
|
||||
}
|
||||
$email = $data['email'];
|
||||
$self = false;
|
||||
if (isset($data['self'])) {
|
||||
$self = (bool)$data['self'];
|
||||
}
|
||||
$displayName = '';
|
||||
if (isset($data['displayName'])) {
|
||||
$displayName = $data['displayName'];
|
||||
}
|
||||
$id = '';
|
||||
if (isset($data['id'])) {
|
||||
$id = $data['id'];
|
||||
}
|
||||
$responseStatus = '';
|
||||
if (isset($data['responseStatus'])) {
|
||||
$responseStatus = $data['responseStatus'];
|
||||
}
|
||||
|
||||
return new self($email, $displayName, false, $id, $responseStatus, $self);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toDataArray(): array
|
||||
{
|
||||
$data = [];
|
||||
$data['email'] = $this->getEmail();
|
||||
$data['displayName'] = $this->getDisplayName();
|
||||
$data['optional'] = $this->isOptional();
|
||||
if ($this->getIdentifier() !== '') {
|
||||
$data['id'] = $this->getIdentifier();
|
||||
}
|
||||
if ($this->responseStatus !== '') {
|
||||
$data['responseStatus'] = $this->responseStatus;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEmail(): string
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isSelf(): bool
|
||||
{
|
||||
return $this->self;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDisplayName(): string
|
||||
{
|
||||
$display = $this->displayName;
|
||||
if ($display === '' || $display === null) {
|
||||
$display = $this->email;
|
||||
}
|
||||
|
||||
return $display;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier(): string
|
||||
{
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isAttending(): bool
|
||||
{
|
||||
return (
|
||||
$this->responseStatus === self::STATUS_ACCEPTED
|
||||
|| $this->responseStatus === self::STATUS_TENTATIVE
|
||||
|| $this->responseStatus === self::STATUS_NEEDSACTION
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isOptional(): bool
|
||||
{
|
||||
return $this->optional;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,781 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Data;
|
||||
|
||||
use DateTime;
|
||||
use DateTimeInterface;
|
||||
use JsonSerializable;
|
||||
use Xentral\Modules\GoogleCalendar\Exception\InvalidArgumentException;
|
||||
|
||||
final class GoogleCalendarEventData implements JsonSerializable
|
||||
{
|
||||
/** @var string STATUS_CONFIRMED */
|
||||
public const STATUS_CONFIRMED = 'confirmed';
|
||||
|
||||
/** @var string STATUS_TENTATIVE */
|
||||
public const STATUS_TENTATIVE = 'tentative';
|
||||
|
||||
/** @var string STATUS_CANCELLED */
|
||||
public const STATUS_CANCELLED = 'cancelled';
|
||||
|
||||
/** @var string VISIBILITY_PUBLIC */
|
||||
public const VISIBILITY_PUBLIC = 'public';
|
||||
|
||||
/** @var string VISIBILITY_PRIVATE */
|
||||
public const VISIBILITY_PRIVATE = 'private';
|
||||
|
||||
/** @var string VISIBILITY_DEFAULT */
|
||||
public const VISIBILITY_DEFAULT = 'default';
|
||||
|
||||
/** @var string TRANSPARENCY_OPAQUE */
|
||||
public const TRANSPARENCY_OPAQUE = 'opaque';
|
||||
|
||||
/** @var string TRANSPARENCY_TRANSPARENT */
|
||||
public const TRANSPARENCY_TRANSPARENT = 'transparent';
|
||||
|
||||
/** @var string $kind */
|
||||
private static $kind = 'calendar#event';
|
||||
|
||||
/** @var string $id */
|
||||
private $id;
|
||||
|
||||
/** @var string $etag */
|
||||
private $etag;
|
||||
|
||||
/** @var string $status */
|
||||
private $status;
|
||||
|
||||
/** @var GoogleCalendarEventTimeValue $time */
|
||||
private $time;
|
||||
|
||||
/** @var string $iCalUid */
|
||||
private $iCalUid;
|
||||
|
||||
/** @var string $summary */
|
||||
private $summary;
|
||||
|
||||
/** @var string $description */
|
||||
private $description;
|
||||
|
||||
/** @var string $location */
|
||||
private $location;
|
||||
|
||||
/** @var string $colorId */
|
||||
private $colorId;
|
||||
|
||||
/** @var DateTime $created */
|
||||
private $created;
|
||||
|
||||
/** @var DateTime $updated */
|
||||
private $updated;
|
||||
|
||||
/** @var GoogleCalendarEventAttendeeValue $creator */
|
||||
private $creator;
|
||||
|
||||
/** @var GoogleCalendarEventAttendeeValue $organizer */
|
||||
private $organizer;
|
||||
|
||||
/** @var GoogleCalendarEventAttendeeValue[] $attendees */
|
||||
private $attendees;
|
||||
|
||||
/** @var string $visibility */
|
||||
private $visibility;
|
||||
|
||||
/** @var string $transparency */
|
||||
private $transparency;
|
||||
|
||||
/** @var GoogleCalendarEventReminderValue[] */
|
||||
private $reminders;
|
||||
|
||||
/** @var int $sequence */
|
||||
private $sequence;
|
||||
|
||||
/** @var string $htmlLink */
|
||||
private $htmlLink;
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param string $etag
|
||||
* @param string $status
|
||||
* @param string $iCalUid
|
||||
* @param DateTimeInterface $created
|
||||
* @param DateTimeInterface $updated
|
||||
* @param GoogleCalendarEventAttendeeValue $creator
|
||||
* @param GoogleCalendarEventAttendeeValue $organizer
|
||||
* @param GoogleCalendarEventTimeValue $time
|
||||
* @param string $summary
|
||||
* @param string $description
|
||||
* @param string $location
|
||||
* @param GoogleCalendarEventAttendeeValue[] $attendees
|
||||
* @param GoogleCalendarEventReminderValue[] $reminders
|
||||
* @param string $visibility
|
||||
* @param string $transparency
|
||||
* @param int $sequence
|
||||
* @param string $colorId
|
||||
* @param string $htmlLink
|
||||
*/
|
||||
public function __construct(
|
||||
string $id,
|
||||
string $etag,
|
||||
string $status,
|
||||
string $iCalUid = '',
|
||||
DateTimeInterface $created = null,
|
||||
DateTimeInterface $updated = null,
|
||||
GoogleCalendarEventAttendeeValue $creator = null,
|
||||
GoogleCalendarEventAttendeeValue $organizer = null,
|
||||
GoogleCalendarEventTimeValue $time = null,
|
||||
string $summary = '',
|
||||
string $description = '',
|
||||
string $location = '',
|
||||
array $attendees = [],
|
||||
array $reminders = [],
|
||||
string $visibility = self::VISIBILITY_DEFAULT,
|
||||
string $transparency = self::TRANSPARENCY_OPAQUE,
|
||||
int $sequence = 0,
|
||||
string $colorId = '',
|
||||
string $htmlLink = ''
|
||||
) {
|
||||
$this->id = $id;
|
||||
$this->etag = $etag;
|
||||
if (
|
||||
$status !== self::STATUS_CONFIRMED
|
||||
&& $status !== self::STATUS_TENTATIVE
|
||||
&& $status !== self::STATUS_CANCELLED
|
||||
) {
|
||||
throw new InvalidArgumentException(
|
||||
'Invalid event status; only "confirmed", "tentative" and "cancelled" are allowed'
|
||||
);
|
||||
}
|
||||
$this->status = $status;
|
||||
$this->iCalUid = $iCalUid;
|
||||
$this->summary = $summary;
|
||||
$this->description = $description;
|
||||
$this->location = $location;
|
||||
$this->colorId = $colorId;
|
||||
$this->created = $created;
|
||||
$this->updated = $updated;
|
||||
$this->creator = $creator;
|
||||
$this->organizer = $organizer;
|
||||
$this->attendees = $attendees;
|
||||
$this->time = $time;
|
||||
if (
|
||||
$visibility !== self::VISIBILITY_DEFAULT
|
||||
&& $visibility !== self::VISIBILITY_PRIVATE
|
||||
&& $visibility !== self::VISIBILITY_PUBLIC
|
||||
) {
|
||||
throw new InvalidArgumentException(
|
||||
'Invalid event visibility; only "default", "private" or "public" are allowed'
|
||||
);
|
||||
}
|
||||
$this->visibility = $visibility;
|
||||
if ($transparency !== self::TRANSPARENCY_OPAQUE && $transparency !== self::TRANSPARENCY_TRANSPARENT) {
|
||||
throw new InvalidArgumentException(
|
||||
'Invalid event transparency; only "opaque" or "transparent" are allowed'
|
||||
);
|
||||
}
|
||||
$this->transparency = $transparency;
|
||||
$this->reminders = $reminders;
|
||||
$this->sequence = $sequence;
|
||||
$this->htmlLink = $htmlLink;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @return GoogleCalendarEventData
|
||||
*/
|
||||
public static function fromArray(array $data): GoogleCalendarEventData
|
||||
{
|
||||
if (!isset($data['kind']) || $data['kind'] !== self::$kind) {
|
||||
throw new InvalidArgumentException('Invalid resource type. Expected: calendar#event');
|
||||
}
|
||||
if (!isset($data['id'])) {
|
||||
throw new InvalidArgumentException('Missing required resorce field "id".');
|
||||
}
|
||||
if (!isset($data['etag'])) {
|
||||
throw new InvalidArgumentException('Missing required resorce field "etag".');
|
||||
}
|
||||
if (!isset($data['status'])) {
|
||||
throw new InvalidArgumentException('Missing required resorce field "etag".');
|
||||
}
|
||||
|
||||
//mandatory
|
||||
$id = $data['id'];
|
||||
$etag = $data['etag'];
|
||||
$status = $data['status'];
|
||||
|
||||
//optional
|
||||
$iCalUid = '';
|
||||
if (isset($data['iCalUID'])) {
|
||||
$iCalUid = $data['iCalUID'];
|
||||
}
|
||||
$created = null;
|
||||
if (isset($data['created'])) {
|
||||
$created = DateTime::createFromFormat('Y-m-d\TH:i:s.uP', $data['created']);
|
||||
if ($created === false) {
|
||||
throw new InvalidArgumentException('Invalid DateTime Format in "created".');
|
||||
}
|
||||
}
|
||||
$updated = null;
|
||||
if (isset($data['updated'])) {
|
||||
$updated = DateTime::createFromFormat('Y-m-d\TH:i:s.uP', $data['updated']);
|
||||
if ($updated === false) {
|
||||
throw new InvalidArgumentException('Invalid DateTime Format in "updated".');
|
||||
}
|
||||
}
|
||||
$creator = null;
|
||||
if (isset($data['creator'])) {
|
||||
$creator = GoogleCalendarEventAttendeeValue::createFromJsonArray($data['creator']);
|
||||
}
|
||||
$organizer = null;
|
||||
if (isset($data['organizer'])) {
|
||||
$organizer = GoogleCalendarEventAttendeeValue::createFromJsonArray($data['organizer']);
|
||||
}
|
||||
$time = null;
|
||||
if (isset($data['start'], $data['end'])) {
|
||||
$time = GoogleCalendarEventTimeValue::createFromJsonArray($data);
|
||||
}
|
||||
$sequence = 0;
|
||||
if (isset($data['sequence'])) {
|
||||
$sequence = $data['sequence'];
|
||||
}
|
||||
$summary = '';
|
||||
if (isset($data['summary'])) {
|
||||
$summary = $data['summary'];
|
||||
}
|
||||
$description = '';
|
||||
if (isset($data['description'])) {
|
||||
$description = $data['description'];
|
||||
}
|
||||
$location = '';
|
||||
if (isset($data['location'])) {
|
||||
$location = $data['location'];
|
||||
}
|
||||
$visibility = self::VISIBILITY_DEFAULT;
|
||||
if (isset($data['visibility'])) {
|
||||
$visibility = $data['visibility'];
|
||||
}
|
||||
$transparency = self::TRANSPARENCY_OPAQUE;
|
||||
if (isset($data['transparency'])) {
|
||||
$transparency = $data['transparency'];
|
||||
}
|
||||
$colorId = '';
|
||||
if (isset($data['colorId'])) {
|
||||
$colorId = $data['colorId'];
|
||||
}
|
||||
$htmlLink = '';
|
||||
if (isset($data['htmlLink'])) {
|
||||
$htmlLink = $data['htmlLink'];
|
||||
}
|
||||
$attendees = [];
|
||||
if (isset($data['attendees']) && is_array($data['attendees'])) {
|
||||
foreach ($data['attendees'] as $attendee) {
|
||||
$attendees[] = GoogleCalendarEventAttendeeValue::createFromJsonArray($attendee);
|
||||
}
|
||||
}
|
||||
$reminders = [];
|
||||
if (isset($data['reminders']['overrides']) && is_array($data['reminders']['overrides'])) {
|
||||
foreach ($data['reminders']['overrides'] as $reminder) {
|
||||
$reminders[] = GoogleCalendarEventReminderValue::fromArray($reminder);
|
||||
}
|
||||
}
|
||||
|
||||
return new self(
|
||||
$id,
|
||||
$etag,
|
||||
$status,
|
||||
$iCalUid,
|
||||
$created,
|
||||
$updated,
|
||||
$creator,
|
||||
$organizer,
|
||||
$time,
|
||||
$summary,
|
||||
$description,
|
||||
$location,
|
||||
$attendees,
|
||||
$reminders,
|
||||
$visibility,
|
||||
$transparency,
|
||||
$sequence,
|
||||
$colorId,
|
||||
$htmlLink
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
$data = [];
|
||||
if ($this->getTime() !== null) {
|
||||
$time = $this->getTime()->toDataArray();
|
||||
$data = array_merge($data, $time);
|
||||
}
|
||||
if ($this->getCreator() !== null) {
|
||||
$data['creator'] = $this->getCreator()->toDataArray();
|
||||
}
|
||||
if ($this->getOrganizer() !== null) {
|
||||
$data['organizer'] = $this->getOrganizer()->toDataArray();
|
||||
}
|
||||
$data['attendees'] = [];
|
||||
foreach ($this->getAttendees() as $attendee) {
|
||||
$data['attendees'][] = $attendee->toDataArray();
|
||||
}
|
||||
$data['reminders']['overrides'] = [];
|
||||
foreach ($this->getReminders() as $reminder) {
|
||||
$data['reminders']['overrides'][] = $reminder->toArray();
|
||||
}
|
||||
if ($this->getColorId() !== '') {
|
||||
$data['colorId'] = $this->getColorId();
|
||||
}
|
||||
//$data['id'] = $this->getId();
|
||||
$data['status'] = $this->getStatus();
|
||||
//$data['iCalUid'] = $this->getICalUid();
|
||||
$data['summary'] = $this->getSummary();
|
||||
$data['description'] = $this->getDescription();
|
||||
$data['location'] = $this->getLocation();
|
||||
$data['visibility'] = $this->getVisibility();
|
||||
$data['transparency'] = $this->getTransparency();
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getId(): string
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEtag(): string
|
||||
{
|
||||
return $this->etag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getStatus(): string
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return GoogleCalendarEventTimeValue
|
||||
*/
|
||||
public function getTime(): GoogleCalendarEventTimeValue
|
||||
{
|
||||
return $this->time;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getICalUid(): string
|
||||
{
|
||||
return $this->iCalUid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSummary(): string
|
||||
{
|
||||
return $this->summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription(): string
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLocation(): string
|
||||
{
|
||||
return $this->location;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getColorId(): string
|
||||
{
|
||||
return $this->colorId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DateTimeInterface
|
||||
*/
|
||||
public function getCreated(): DateTimeInterface
|
||||
{
|
||||
return $this->created;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DateTimeInterface
|
||||
*/
|
||||
public function getUpdated(): DateTimeInterface
|
||||
{
|
||||
return $this->updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return GoogleCalendarEventAttendeeValue|null
|
||||
*/
|
||||
public function getCreator(): ?GoogleCalendarEventAttendeeValue
|
||||
{
|
||||
return $this->creator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return GoogleCalendarEventAttendeeValue|null
|
||||
*/
|
||||
public function getOrganizer(): ?GoogleCalendarEventAttendeeValue
|
||||
{
|
||||
return $this->organizer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return GoogleCalendarEventAttendeeValue[]
|
||||
*/
|
||||
public function getAttendees(): array
|
||||
{
|
||||
return $this->attendees;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getVisibility(): string
|
||||
{
|
||||
return $this->visibility;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTransparency(): string
|
||||
{
|
||||
return $this->transparency;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return GoogleCalendarEventReminderValue[]
|
||||
*/
|
||||
public function getReminders(): array
|
||||
{
|
||||
return $this->reminders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getSequence(): int
|
||||
{
|
||||
return $this->sequence;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getHtmlLink(): string
|
||||
{
|
||||
return $this->htmlLink;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $status
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @return GoogleCalendarEventData
|
||||
*/
|
||||
public function setStatus(string $status): GoogleCalendarEventData
|
||||
{
|
||||
if (
|
||||
$status !== self::STATUS_CONFIRMED
|
||||
&& $status !== self::STATUS_TENTATIVE
|
||||
&& $status !== self::STATUS_CANCELLED
|
||||
) {
|
||||
throw new InvalidArgumentException(
|
||||
'Invalid event status; only "confirmed", "tentative" and "cancelled" are allowed.'
|
||||
);
|
||||
}
|
||||
$eventData = $this->cloneDeep();
|
||||
$eventData->status = $status;
|
||||
|
||||
return $eventData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DateTimeInterface $beginning
|
||||
* @param DateTimeInterface $end
|
||||
* @param bool $wholeday
|
||||
* @param string $timezone
|
||||
*
|
||||
* @return GoogleCalendarEventData
|
||||
*/
|
||||
public function setTime(
|
||||
DateTimeInterface $beginning,
|
||||
DateTimeInterface $end,
|
||||
bool $wholeday = false,
|
||||
string $timezone = ''
|
||||
): GoogleCalendarEventData {
|
||||
$time = new GoogleCalendarEventTimeValue($beginning, $end, $wholeday, $timezone);
|
||||
$eventData = $this->cloneDeep();
|
||||
$eventData->time = $time;
|
||||
|
||||
return $eventData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $summary
|
||||
*
|
||||
* @return GoogleCalendarEventData
|
||||
*/
|
||||
public function setSummary(string $summary): GoogleCalendarEventData
|
||||
{
|
||||
$eventData = $this->cloneDeep();
|
||||
$eventData->summary = $summary;
|
||||
|
||||
return $eventData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $description
|
||||
*
|
||||
* @return GoogleCalendarEventData
|
||||
*/
|
||||
public function setDescription(string $description): GoogleCalendarEventData
|
||||
{
|
||||
$eventData = $this->cloneDeep();
|
||||
$eventData->description = $description;
|
||||
|
||||
return $eventData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $location
|
||||
*
|
||||
* @return GoogleCalendarEventData
|
||||
*/
|
||||
public function setLocation(string $location): GoogleCalendarEventData
|
||||
{
|
||||
$eventData = $this->cloneDeep();
|
||||
$eventData->location = $location;
|
||||
|
||||
return $eventData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $colorId
|
||||
*
|
||||
* @return GoogleCalendarEventData
|
||||
*/
|
||||
public function setColorId(string $colorId): GoogleCalendarEventData
|
||||
{
|
||||
$eventData = $this->cloneDeep();
|
||||
$eventData->colorId = $colorId;
|
||||
|
||||
return $eventData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $visibility
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @return GoogleCalendarEventData
|
||||
*/
|
||||
public function setVisibility(string $visibility): GoogleCalendarEventData
|
||||
{
|
||||
if (
|
||||
$visibility !== self::VISIBILITY_DEFAULT
|
||||
&& $visibility !== self::VISIBILITY_PRIVATE
|
||||
&& $visibility !== self::VISIBILITY_PUBLIC
|
||||
) {
|
||||
throw new InvalidArgumentException(
|
||||
'Invalid event visibility; only "default", "private" or "public" are allowed'
|
||||
);
|
||||
}
|
||||
$eventData = $this->cloneDeep();
|
||||
$eventData->visibility = $visibility;
|
||||
|
||||
return $eventData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $transparency
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @return GoogleCalendarEventData
|
||||
*/
|
||||
public function setTransparency(string $transparency): GoogleCalendarEventData
|
||||
{
|
||||
if ($transparency !== self::TRANSPARENCY_OPAQUE && $transparency !== self::TRANSPARENCY_TRANSPARENT) {
|
||||
throw new InvalidArgumentException(
|
||||
'Invalid event transparency; only "opaque" or "transparent" are allowed'
|
||||
);
|
||||
}
|
||||
$eventData = $this->cloneDeep();
|
||||
$eventData->transparency = $transparency;
|
||||
|
||||
return $eventData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param GoogleCalendarEventAttendeeValue|null $organizer
|
||||
*
|
||||
* @return GoogleCalendarEventData
|
||||
*/
|
||||
public function setOrganizer(GoogleCalendarEventAttendeeValue $organizer = null): GoogleCalendarEventData
|
||||
{
|
||||
$eventData = $this->cloneDeep();
|
||||
$eventData->organizer = $organizer;
|
||||
|
||||
return $eventData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $email
|
||||
* @param string $displayName
|
||||
* @param bool $optional
|
||||
*
|
||||
* @return GoogleCalendarEventData
|
||||
*/
|
||||
public function addAttendee(
|
||||
string $email,
|
||||
string $displayName = '',
|
||||
bool $optional = false
|
||||
): GoogleCalendarEventData {
|
||||
$attendee = new GoogleCalendarEventAttendeeValue($email, $displayName, $optional);
|
||||
$attendees = array_values($this->attendees);
|
||||
$attendees[] = $attendee;
|
||||
|
||||
$eventData = $this->cloneDeep();
|
||||
$eventData->attendees = $attendees;
|
||||
|
||||
return $eventData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return GoogleCalendarEventData
|
||||
*/
|
||||
public function removeAttendees(): GoogleCalendarEventData
|
||||
{
|
||||
$eventData = $this->cloneDeep();
|
||||
$eventData->attendees = [];
|
||||
|
||||
return $eventData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $method
|
||||
* @param int $minutes
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @return GoogleCalendarEventData
|
||||
*/
|
||||
public function addReminder(string $method, int $minutes): GoogleCalendarEventData
|
||||
{
|
||||
$reminder = new GoogleCalendarEventReminderValue($method, $minutes);
|
||||
$reminders = array_values($this->reminders);
|
||||
$reminders[] = $reminder;
|
||||
|
||||
$eventData = $this->cloneDeep();
|
||||
$eventData->reminders = $reminders;
|
||||
|
||||
return $eventData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return GoogleCalendarEventData
|
||||
*/
|
||||
public function removeReminders(): GoogleCalendarEventData
|
||||
{
|
||||
$eventData = $this->cloneDeep();
|
||||
$eventData->reminders = [];
|
||||
|
||||
return $eventData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return $this->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return GoogleCalendarEventData
|
||||
*/
|
||||
private function cloneDeep(): GoogleCalendarEventData
|
||||
{
|
||||
$time = $this->time;
|
||||
if ($this->time !== null) {
|
||||
$time = new GoogleCalendarEventTimeValue(
|
||||
$this->time->getBeginning(),
|
||||
$this->time->getEnd(),
|
||||
$this->time->isWholeday(),
|
||||
$this->time->getTimezone()
|
||||
);
|
||||
}
|
||||
|
||||
$created = null;
|
||||
if ($this->created !== null) {
|
||||
$created = clone $this->created;
|
||||
}
|
||||
$updated = null;
|
||||
if ($this->updated !== null) {
|
||||
$updated = clone $this->updated;
|
||||
}
|
||||
$creator = null;
|
||||
if ($this->creator !== null) {
|
||||
$creator = clone $this->creator;
|
||||
}
|
||||
$organizer = null;
|
||||
if ($this->organizer !== null) {
|
||||
$organizer = clone $this->organizer;
|
||||
}
|
||||
|
||||
return new self(
|
||||
$this->id,
|
||||
$this->etag,
|
||||
$this->status,
|
||||
$this->iCalUid,
|
||||
$created,
|
||||
$updated,
|
||||
$creator,
|
||||
$organizer,
|
||||
$time,
|
||||
$this->summary,
|
||||
$this->description,
|
||||
$this->location,
|
||||
$this->attendees,
|
||||
$this->reminders,
|
||||
$this->visibility,
|
||||
$this->transparency,
|
||||
$this->sequence,
|
||||
$this->colorId,
|
||||
$this->htmlLink
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Data;
|
||||
|
||||
use Xentral\Modules\GoogleCalendar\Exception\InvalidArgumentException;
|
||||
|
||||
final class GoogleCalendarEventReminderValue
|
||||
{
|
||||
/** @var string METHOD_EMAIL */
|
||||
public const METHOD_EMAIL = 'email';
|
||||
|
||||
/** @var string METHOD_POPUP */
|
||||
public const METHOD_POPUP = 'popup';
|
||||
|
||||
/** @var string $method */
|
||||
private $method;
|
||||
|
||||
/** @var int $minutes */
|
||||
private $minutes;
|
||||
|
||||
/**
|
||||
* @param string $method
|
||||
* @param int $minutes
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function __construct(string $method, int $minutes)
|
||||
{
|
||||
if ($method !== self::METHOD_EMAIL && $method !== self::METHOD_POPUP) {
|
||||
throw new InvalidArgumentException(
|
||||
'Invalid notification method; only "email" and "popup" are allowed'
|
||||
);
|
||||
}
|
||||
$this->method = $method;
|
||||
$this->minutes = $minutes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @return GoogleCalendarEventReminderValue
|
||||
*/
|
||||
public static function fromArray(array $data): GoogleCalendarEventReminderValue
|
||||
{
|
||||
if (!isset($data['method'], $data['minutes'])) {
|
||||
throw new InvalidArgumentException('method and minutes required for notification values.');
|
||||
}
|
||||
|
||||
return new self($data['method'], $data['minutes']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
$data = [];
|
||||
$data['method'] = $this->getMethod();
|
||||
$data['minutes'] = $this->getMinutes();
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getMethod(): string
|
||||
{
|
||||
return $this->method;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getMinutes(): int
|
||||
{
|
||||
return $this->minutes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Data;
|
||||
|
||||
use DateInterval;
|
||||
use DateTime;
|
||||
use DateTimeInterface;
|
||||
use Xentral\Modules\GoogleCalendar\Exception\InvalidArgumentException;
|
||||
|
||||
final class GoogleCalendarEventTimeValue
|
||||
{
|
||||
/** @var DateTimeInterface $beginning */
|
||||
private $beginning;
|
||||
|
||||
/** @var DateTimeInterface $end */
|
||||
private $end;
|
||||
|
||||
/** @var bool $wholeday */
|
||||
private $wholeday;
|
||||
|
||||
/** @var string $timezone */
|
||||
private $timezone;
|
||||
|
||||
/**
|
||||
* @param DateTimeInterface $beginning
|
||||
* @param DateTimeInterface $end
|
||||
* @param bool $wholeday
|
||||
* @param string $timezone
|
||||
*/
|
||||
public function __construct(
|
||||
DateTimeInterface $beginning,
|
||||
DateTimeInterface $end,
|
||||
bool $wholeday = false,
|
||||
string $timezone = ''
|
||||
) {
|
||||
$this->beginning = $beginning;
|
||||
$this->end = $end;
|
||||
$this->wholeday = $wholeday;
|
||||
$this->timezone = $timezone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @return GoogleCalendarEventTimeValue
|
||||
*/
|
||||
public static function createFromJsonArray(array $data): GoogleCalendarEventTimeValue
|
||||
{
|
||||
if (!array_key_exists('start', $data) || !array_key_exists('end', $data)) {
|
||||
throw new InvalidArgumentException('Data format invalid.');
|
||||
}
|
||||
|
||||
$begin = null;
|
||||
$end = null;
|
||||
$wholeday = false;
|
||||
$timeZone = '';
|
||||
|
||||
if (isset($data['start']['dateTime'], $data['end']['dateTime'])) {
|
||||
$begin = DateTime::createFromFormat(DateTimeInterface::RFC3339, $data['start']['dateTime']);
|
||||
$end = DateTime::createFromFormat(DateTimeInterface::RFC3339, $data['end']['dateTime']);
|
||||
if (isset($data['start']['timeZone'])) {
|
||||
$timeZone = $data['start']['timeZone'];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($data['start']['date'], $data['end']['date'])) {
|
||||
$formatted = sprintf('%s 00:00:00', $data['start']['date']);
|
||||
$begin = DateTime::createFromFormat('Y-m-d H:i:s', $formatted);
|
||||
$formatted = sprintf('%s 00:00:00', $data['end']['date']);
|
||||
$end = DateTime::createFromFormat('Y-m-d H:i:s',$formatted);
|
||||
$wholeday = true;
|
||||
}
|
||||
|
||||
if (empty($begin) || empty($end)) {
|
||||
throw new InvalidArgumentException('Data format invalid.');
|
||||
}
|
||||
|
||||
return new GoogleCalendarEventTimeValue($begin, $end, $wholeday, $timeZone);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toDataArray(): array
|
||||
{
|
||||
$data = [];
|
||||
|
||||
if ($this->isWholeday()) {
|
||||
$data['start']['date'] = $this->getBeginning()->format('Y-m-d');
|
||||
$data['end']['date'] = $this->getEnd()->format('Y-m-d');
|
||||
} else {
|
||||
$data['start']['dateTime'] = $this->getBeginning()->format(DateTimeInterface::RFC3339);
|
||||
$data['end']['dateTime'] = $this->getEnd()->format(DateTimeInterface::RFC3339);
|
||||
}
|
||||
if ($this->getTimezone() !== '') {
|
||||
$data['start']['timeZone'] = $this->getTimezone();
|
||||
$data['end']['timeZone'] = $this->getTimezone();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DateTimeInterface
|
||||
*/
|
||||
public function getBeginning(): DateTimeInterface
|
||||
{
|
||||
return $this->beginning;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DateTimeInterface
|
||||
*/
|
||||
public function getEnd(): DateTimeInterface
|
||||
{
|
||||
return $this->end;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns duration in seconds
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getDuration(): int
|
||||
{
|
||||
return (int) $this->end->getTimestamp() - $this->beginning->getTimestamp();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DateInterval
|
||||
*/
|
||||
public function getInterval(): DateInterval
|
||||
{
|
||||
return $this->end->diff($this->beginning, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isWholeday(): bool
|
||||
{
|
||||
return $this->wholeday;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTimezone(): string
|
||||
{
|
||||
return $this->timezone;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Data;
|
||||
|
||||
use Xentral\Modules\GoogleCalendar\Exception\InvalidArgumentException;
|
||||
|
||||
final class GoogleCalendarListItem
|
||||
{
|
||||
/** @var string ROLE_READER */
|
||||
public const ROLE_READER = 'reader';
|
||||
|
||||
/** @var string ROLE_OWNER */
|
||||
public const ROLE_OWNER = 'owner';
|
||||
|
||||
/** @var string ROLE_FREEBUSYREADER */
|
||||
public const ROLE_FREEBUSYREADER = 'freeBusyReader';
|
||||
|
||||
/** @var string $kind */
|
||||
private static $kind = 'calendar#calendarListEntry';
|
||||
|
||||
/** @var string $id */
|
||||
private $id;
|
||||
|
||||
/** @var string $summary */
|
||||
private $summary;
|
||||
|
||||
/** @var string $role */
|
||||
private $role;
|
||||
|
||||
/** @var string $timeZone */
|
||||
private $timeZone;
|
||||
|
||||
/** @var string $colorId */
|
||||
private $colorId;
|
||||
|
||||
/** @var bool $selected */
|
||||
private $selected;
|
||||
|
||||
/** @var bool $primary */
|
||||
private $primary;
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param string $summary
|
||||
* @param string $role
|
||||
* @param string $timeZone
|
||||
* @param string $colorId
|
||||
* @param bool $selected
|
||||
* @param bool $primary
|
||||
*/
|
||||
public function __construct($id, $summary, $role, $timeZone, $colorId, $selected = false, $primary = false)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->summary = $summary;
|
||||
if ($role !== self::ROLE_FREEBUSYREADER && $role !== self::ROLE_READER && $role !== self::ROLE_OWNER) {
|
||||
throw new InvalidArgumentException('Invalid calendar Role.');
|
||||
}
|
||||
$this->role = $role;
|
||||
$this->timeZone = $timeZone;
|
||||
$this->colorId = $colorId;
|
||||
$this->selected = $selected;
|
||||
$this->primary = $primary;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
*
|
||||
* @return GoogleCalendarListItem
|
||||
*/
|
||||
public static function fromArray($data)
|
||||
{
|
||||
if (!isset($data['kind']) || $data['kind'] !== self::$kind) {
|
||||
throw new InvalidArgumentException('Invalid resource type. Expected: calendar#event');
|
||||
}
|
||||
if (!isset($data['id'])) {
|
||||
throw new InvalidArgumentException('Missing required resorce field "id".');
|
||||
}
|
||||
$id = $data['id'];
|
||||
$summary = $data['summary'];
|
||||
$role = $data['accessRole'];
|
||||
$timeZone = $data['timeZone'];
|
||||
$colorId = $data['colorId'];
|
||||
$selected = (isset($data['selected']) && $data['selected'] === true);
|
||||
$primary = (isset($data['primary']) && $data['primary'] === true);
|
||||
|
||||
return new self($id, $summary, $role, $timeZone, $colorId, $selected, $primary);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSummary()
|
||||
{
|
||||
return $this->summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getRole()
|
||||
{
|
||||
return $this->role;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTimeZone()
|
||||
{
|
||||
return $this->timeZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getColorId()
|
||||
{
|
||||
return $this->colorId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isSelected()
|
||||
{
|
||||
return $this->selected;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isPrimary()
|
||||
{
|
||||
return $this->primary;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Data;
|
||||
|
||||
use DateTime;
|
||||
use DateTimeInterface;
|
||||
|
||||
final class GoogleCalenderSyncValue
|
||||
{
|
||||
/** @var int $id */
|
||||
private $id;
|
||||
|
||||
/** @var int $eventId */
|
||||
private $eventId;
|
||||
|
||||
/** @var string|null $googleId */
|
||||
private $googleId;
|
||||
|
||||
/** @var bool $isFromGoogle */
|
||||
private $isFromGoogle;
|
||||
|
||||
/** @var DateTimeInterface|null $eventDate */
|
||||
private $eventDate;
|
||||
|
||||
/** @var int $owner */
|
||||
private $owner;
|
||||
|
||||
/** @var string|null $htmlLink */
|
||||
private $htmlLink;
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param int $eventId
|
||||
* @param string|null $googleId
|
||||
* @param int $owner
|
||||
* @param bool $isFromGoogle
|
||||
* @param DateTimeInterface|null $eventDate
|
||||
* @param string|null $htmlLink
|
||||
*/
|
||||
public function __construct(
|
||||
int $id = 0,
|
||||
int $eventId = 0,
|
||||
string $googleId = null,
|
||||
int $owner = 0,
|
||||
bool $isFromGoogle = false,
|
||||
DateTimeInterface $eventDate = null,
|
||||
string $htmlLink = null
|
||||
) {
|
||||
$this->id = $id;
|
||||
$this->eventId = $eventId;
|
||||
$this->googleId = $googleId;
|
||||
$this->isFromGoogle = $isFromGoogle;
|
||||
$this->eventDate = $eventDate;
|
||||
$this->owner = $owner;
|
||||
$this->htmlLink = $htmlLink;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEventDateAsString(): string
|
||||
{
|
||||
if ($this->eventDate === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $this->eventDate->format('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return GoogleCalenderSyncValue
|
||||
*/
|
||||
public static function fromDbState(array $data): GoogleCalenderSyncValue
|
||||
{
|
||||
$instance = new self(
|
||||
$data['id'],
|
||||
$data['event_id'],
|
||||
$data['foreign_id'],
|
||||
$data['owner'],
|
||||
$data['from_google'] === 1,
|
||||
null,
|
||||
$data['html_link']
|
||||
);
|
||||
if ($data['event_date'] !== null) {
|
||||
$instance->setEventDate(DateTime::createFromFormat('Y-m-d H:i:s', $data['event_date']));
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setId(int $id): void
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getEventId(): int
|
||||
{
|
||||
return $this->eventId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $eventId
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setEventId(int $eventId): void
|
||||
{
|
||||
$this->eventId = $eventId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getGoogleId(): string
|
||||
{
|
||||
if ($this->googleId === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $this->googleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $googleId
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setGoogleId(string $googleId): void
|
||||
{
|
||||
$this->googleId = $googleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isFromGoogle(): bool
|
||||
{
|
||||
return $this->isFromGoogle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $isFromGoogle
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setIsFromGoogle(bool $isFromGoogle): void
|
||||
{
|
||||
$this->isFromGoogle = $isFromGoogle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DateTimeInterface|null
|
||||
*/
|
||||
public function getEventDate(): ?DateTimeInterface
|
||||
{
|
||||
return $this->eventDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DateTimeInterface $eventDate
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setEventDate(DateTimeInterface $eventDate): void
|
||||
{
|
||||
$this->eventDate = $eventDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getOwner(): int
|
||||
{
|
||||
return $this->owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $owner
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setOwner(int $owner): void
|
||||
{
|
||||
$this->owner = $owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getHtmlLink(): string
|
||||
{
|
||||
if ($this->htmlLink === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $this->htmlLink;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $htmlLink
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setHtmlLink(string $htmlLink): void
|
||||
{
|
||||
$this->htmlLink = $htmlLink;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class GoogleAccountNotFoundException extends RuntimeException implements GoogleCalendarExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class GoogleApiAccessException extends RuntimeException implements GoogleCalendarExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class GoogleApiScopeException extends RuntimeException implements GoogleCalendarExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class GoogleCalendarAccessException extends RuntimeException implements GoogleCalendarExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class GoogleCalendarApiException extends RuntimeException implements GoogleCalendarExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class GoogleCalendarException extends RuntimeException implements GoogleCalendarExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Exception;
|
||||
|
||||
use Xentral\Core\Exception\ModuleExceptionInterface;
|
||||
|
||||
interface GoogleCalendarExceptionInterface extends ModuleExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class GoogleCalendarImportException extends RuntimeException implements GoogleCalendarExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class GoogleCalendarNotFoundException extends RuntimeException implements GoogleCalendarExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class GoogleCalendarSyncException extends RuntimeException implements GoogleCalendarExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class HttpException extends RuntimeException implements GoogleCalendarExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class InvalidArgumentException extends RuntimeException implements GoogleCalendarExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,417 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Service;
|
||||
|
||||
use DateInterval;
|
||||
use DateTime;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
use Exception;
|
||||
use Throwable;
|
||||
use Xentral\Components\Logger\LoggerAwareTrait;
|
||||
use Xentral\Modules\Calendar\CalendarService;
|
||||
use Xentral\Modules\Calendar\Data\CalendarEvent;
|
||||
use Xentral\Modules\GoogleCalendar\Client\GoogleCalendarClientInterface;
|
||||
use Xentral\Modules\GoogleCalendar\Data\GoogleCalendarColorCollection;
|
||||
use Xentral\Modules\GoogleCalendar\Data\GoogleCalendarEventData;
|
||||
use Xentral\Modules\GoogleCalendar\Data\GoogleCalenderSyncValue;
|
||||
use Xentral\Modules\GoogleCalendar\Exception\GoogleCalendarApiException;
|
||||
use Xentral\Modules\GoogleCalendar\Exception\GoogleCalendarSyncException;
|
||||
use Xentral\Modules\GoogleCalendar\Wrapper\UserAddressGatewayWrapper;
|
||||
use Xentral\Modules\User\Service\UserConfigService;
|
||||
|
||||
final class GoogleCalendarSynchronizer
|
||||
{
|
||||
use LoggerAwareTrait;
|
||||
|
||||
/** @var string CONFIG_KEY_LAST_SYNC */
|
||||
public const CONFIG_KEY_LAST_SYNC = 'last_google_calendar_sync';
|
||||
|
||||
/** @var GoogleSyncGateway $gateway */
|
||||
private $gateway;
|
||||
|
||||
/** @var GoogleSyncService $service */
|
||||
private $service;
|
||||
|
||||
/** @var CalendarService $calendarService */
|
||||
private $calendarService;
|
||||
|
||||
/** @var UserAddressGatewayWrapper $addressService */
|
||||
private $addressService;
|
||||
|
||||
/** @var UserConfigService $userConfigService */
|
||||
private $userConfigService;
|
||||
|
||||
/** @var GoogleEventConverter $converter */
|
||||
private $converter;
|
||||
|
||||
/**
|
||||
* @param GoogleSyncGateway $gateway
|
||||
* @param GoogleSyncService $service
|
||||
* @param CalendarService $calendarService
|
||||
* @param GoogleEventConverter $converter
|
||||
* @param UserAddressGatewayWrapper $addressService
|
||||
* @param UserConfigService $userConfigService
|
||||
*/
|
||||
public function __construct(
|
||||
GoogleSyncGateway $gateway,
|
||||
GoogleSyncService $service,
|
||||
CalendarService $calendarService,
|
||||
GoogleEventConverter $converter,
|
||||
UserAddressGatewayWrapper $addressService,
|
||||
UserConfigService $userConfigService
|
||||
) {
|
||||
$this->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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Service;
|
||||
|
||||
use Xentral\Modules\Calendar\Data\CalendarEvent;
|
||||
use Xentral\Modules\Calendar\Data\CalendarEventUser;
|
||||
use Xentral\Modules\GoogleCalendar\Data\GoogleCalendarEventAttendeeValue;
|
||||
use Xentral\Modules\GoogleCalendar\Data\GoogleCalendarEventData;
|
||||
use Xentral\Modules\GoogleCalendar\Wrapper\UserAddressGatewayWrapper;
|
||||
|
||||
final class GoogleEventConverter
|
||||
{
|
||||
/** @var UserAddressGatewayWrapper $gateway */
|
||||
private $userAddress;
|
||||
|
||||
/**
|
||||
* @param UserAddressGatewayWrapper $userAddress
|
||||
*/
|
||||
public function __construct(UserAddressGatewayWrapper $userAddress)
|
||||
{
|
||||
$this->userAddress = $userAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CalendarEvent $event
|
||||
* @param GoogleCalendarEventData|null $googleEvent
|
||||
*
|
||||
* @return GoogleCalendarEventData
|
||||
*/
|
||||
public function convertToGoogleEvent(CalendarEvent $event, GoogleCalendarEventData $googleEvent = null)
|
||||
{
|
||||
if ($googleEvent === null) {
|
||||
$googleEvent = new GoogleCalendarEventData(0, '', GoogleCalendarEventData::STATUS_CONFIRMED);
|
||||
}
|
||||
|
||||
$visibility = GoogleCalendarEventData::VISIBILITY_PRIVATE;
|
||||
if ($event->isPublic()) {
|
||||
$visibility = GoogleCalendarEventData::VISIBILITY_PUBLIC;
|
||||
}
|
||||
|
||||
$googleEvent = $googleEvent->setSummary($event->getTitle())
|
||||
->setDescription($event->getDescription())
|
||||
->setLocation($event->getLocation())
|
||||
->setTime($event->getStart(), $event->getEnd(), $event->isAllDay())
|
||||
->setVisibility($visibility);
|
||||
|
||||
$organizer = $event->getOrganizer();
|
||||
$organizerAddress = $organizer->getAddressId();
|
||||
$creator = $event->getCreator();
|
||||
$creatorAddress = $creator->getAddressId();
|
||||
|
||||
if ($organizer !== null && $organizerAddress > 0 && $organizerAddress !== $creatorAddress)
|
||||
{
|
||||
$organizerMail = $this->userAddress->getEmailByAddress($organizer->getAddressId());
|
||||
if ($organizerMail !== '') {
|
||||
$orgaAttendee = new GoogleCalendarEventAttendeeValue($organizerMail);
|
||||
$googleEvent = $googleEvent->setOrganizer($orgaAttendee);
|
||||
}
|
||||
}
|
||||
|
||||
$attendees = $event->getAllUsers();
|
||||
foreach ($attendees as $attendee) {
|
||||
$address = $attendee->getAddressId();
|
||||
if ($address === $creator->getAddressId() || $address === $organizer->getAddressId()) {
|
||||
continue;
|
||||
}
|
||||
$attendeeMail = $this->userAddress->getEmailByAddress($attendee->getAddressId());
|
||||
if ($attendeeMail !== '') {
|
||||
$googleEvent = $googleEvent->addAttendee($attendeeMail);
|
||||
}
|
||||
}
|
||||
|
||||
return $googleEvent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param GoogleCalendarEventData $googleEvent
|
||||
* @param CalendarEvent|null $event
|
||||
*
|
||||
* @return CalendarEvent
|
||||
*/
|
||||
public function convertToEvent(
|
||||
GoogleCalendarEventData $googleEvent,
|
||||
CalendarEvent $event = null
|
||||
) {
|
||||
if ($event === null) {
|
||||
$event = new CalendarEvent(0, 0, 'Google Calendar Event');
|
||||
}
|
||||
$event->setTitle($googleEvent->getSummary());
|
||||
$event->setDescription($googleEvent->getDescription());
|
||||
$event->setStart($googleEvent->getTime()->getBeginning());
|
||||
$event->setEnd($googleEvent->getTime()->getEnd());
|
||||
$event->setLocation($googleEvent->getLocation());
|
||||
$public = true;
|
||||
if ($googleEvent->getVisibility() === GoogleCalendarEventData::VISIBILITY_PRIVATE) {
|
||||
$public = false;
|
||||
}
|
||||
$event->setPublic($public);
|
||||
$event->setAllDay($googleEvent->getTime()->isWholeday());
|
||||
|
||||
$creator = $this->transformGoogleEventAttendeeToEventUser($googleEvent->getCreator());
|
||||
$event->setCreator($creator);
|
||||
$organizer = $this->transformGoogleEventAttendeeToEventUser($googleEvent->getOrganizer());
|
||||
$event->setOrganizer($organizer);
|
||||
|
||||
foreach ($googleEvent->getAttendees() as $attendee) {
|
||||
if (!$attendee->isAttending()) {
|
||||
continue;
|
||||
}
|
||||
$user = $this->transformGoogleEventAttendeeToEventUser($attendee);
|
||||
$event->addAttendee($user);
|
||||
}
|
||||
|
||||
return $event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param GoogleCalendarEventAttendeeValue $attendee
|
||||
* @param CalendarEventUser|null $user
|
||||
*
|
||||
* @return CalendarEventUser
|
||||
*/
|
||||
public function transformGoogleEventAttendeeToEventUser(
|
||||
GoogleCalendarEventAttendeeValue $attendee,
|
||||
CalendarEventUser $user = null
|
||||
) {
|
||||
if ($user === null) {
|
||||
$user = new CalendarEventUser();
|
||||
}
|
||||
|
||||
$email = $attendee->getEmail();
|
||||
$addressId = $this->userAddress->findAddressByEmail($email);
|
||||
$userId = $this->userAddress->getUserByAddress($addressId);
|
||||
$user->setUserId($userId);
|
||||
$user->setAddressId($addressId);
|
||||
$user->setEmail($email);
|
||||
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Service;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\GoogleCalendar\Data\GoogleCalenderSyncValue;
|
||||
|
||||
final class GoogleSyncGateway
|
||||
{
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param Database $database
|
||||
*/
|
||||
public function __construct(Database $database)
|
||||
{
|
||||
$this->db = $database;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all sync entries as key-value list.
|
||||
*
|
||||
* @return array key-value pairs ['GoogleEventId' => 'EventId']
|
||||
*/
|
||||
public function getAllSyncEntries(): array
|
||||
{
|
||||
$sql = 'SELECT s.foreign_id, s.event_id
|
||||
FROM `googleapi_calendar_sync` AS `s`
|
||||
ORDER BY s.id DESC
|
||||
LIMIT 30';
|
||||
|
||||
return $this->db->fetchPairs($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $entryId
|
||||
*
|
||||
* @return bool true = entry exists
|
||||
*/
|
||||
public function existsSyncEntry(int $entryId): bool
|
||||
{
|
||||
$sql = 'SELECT `id` FROM `googleapi_calendar_sync` WHERE `id` = :id';
|
||||
|
||||
return $entryId === $this->db->fetchValue($sql, ['id' => $entryId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $eventId
|
||||
*
|
||||
* @return GoogleCalenderSyncValue|null
|
||||
*/
|
||||
public function tryGetSyncEntryByEvent(int $eventId): ?GoogleCalenderSyncValue
|
||||
{
|
||||
if ($eventId < 1) {
|
||||
return null;
|
||||
}
|
||||
$sql = 'SELECT s.id, s.event_id, s.foreign_id, s.owner, s.from_google, s.event_date, s.html_link
|
||||
FROM `googleapi_calendar_sync` AS `s`
|
||||
WHERE s.event_id = :event_id LIMIT 1';
|
||||
$row = $this->db->fetchRow($sql, ['event_id' => $eventId]);
|
||||
if (empty($row)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return GoogleCalenderSyncValue::fromDbState($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $googleId
|
||||
*
|
||||
* @return GoogleCalenderSyncValue|null
|
||||
*/
|
||||
public function tryGetSyncEntryByGoogleEvent(string $googleId): ?GoogleCalenderSyncValue
|
||||
{
|
||||
if ($googleId === '') {
|
||||
return null;
|
||||
}
|
||||
$sql = 'SELECT s.id, s.event_id, s.foreign_id,s.owner, s.from_google, s.event_date, s.html_link
|
||||
FROM `googleapi_calendar_sync` AS `s`
|
||||
WHERE s.foreign_id = :google_id LIMIT 1';
|
||||
$row = $this->db->fetchRow($sql, ['google_id' => $googleId]);
|
||||
if (empty($row)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return GoogleCalenderSyncValue::fromDbState($row);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Service;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\GoogleCalendar\Data\GoogleCalenderSyncValue;
|
||||
|
||||
final class GoogleSyncService
|
||||
{
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/** @var GoogleSyncGateway $gateway */
|
||||
private $gateway;
|
||||
|
||||
/**
|
||||
* @param Database $database
|
||||
* @param GoogleSyncGateway $gateway
|
||||
*/
|
||||
public function __construct(Database $database, GoogleSyncGateway $gateway)
|
||||
{
|
||||
$this->db = $database;
|
||||
$this->gateway = $gateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param GoogleCalenderSyncValue $sync
|
||||
*
|
||||
* @return int new Id
|
||||
*/
|
||||
public function saveSyncEntry(GoogleCalenderSyncValue $sync): int
|
||||
{
|
||||
if ($sync->getId() > 0 && $this->gateway->existsSyncEntry($sync->getId())) {
|
||||
return $this->updateSyncEntry($sync);
|
||||
}
|
||||
|
||||
return $this->insertSyncEntry($sync);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $googleEventId
|
||||
* @param int $calendarEventId
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function deleteSyncEntry(string $googleEventId, int $calendarEventId): void
|
||||
{
|
||||
$sql = 'DELETE FROM `googleapi_calendar_sync` WHERE `foreign_id` = :foreign_id AND `event_id` = :event_id';
|
||||
$values = ['foreign_id' => $googleEventId, 'event_id' => $calendarEventId];
|
||||
$this->db->perform($sql, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param GoogleCalenderSyncValue $sync
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function insertSyncEntry(GoogleCalenderSyncValue $sync): int
|
||||
{
|
||||
$sql = 'INSERT INTO `googleapi_calendar_sync`
|
||||
(`event_id`, `foreign_id`, `owner`, `from_google`, `event_date`, `html_link`) VALUES
|
||||
(:event_id, :foreign_id, :owner, :from_google, :event_date, :html_link)';
|
||||
$values = [
|
||||
'event_id' => $sync->getEventId(),
|
||||
'foreign_id' => $sync->getGoogleId(),
|
||||
'owner' => $sync->getOwner(),
|
||||
'from_google' => (int)$sync->isFromGoogle(),
|
||||
'event_date' => $sync->getEventDateAsString(),
|
||||
'html_link' => $sync->getHtmlLink(),
|
||||
];
|
||||
$this->db->perform($sql, $values);
|
||||
|
||||
return $this->db->lastInsertId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param GoogleCalenderSyncValue $sync
|
||||
*
|
||||
* @return int updated Id
|
||||
*/
|
||||
private function updateSyncEntry(GoogleCalenderSyncValue $sync): int
|
||||
{
|
||||
$sql = 'UPDATE `googleapi_calendar_sync`
|
||||
SET `event_id` = :event_id,
|
||||
`foreign_id` = :foreign_id,
|
||||
`event_date` = :event_date,
|
||||
`owner` = :owner
|
||||
WHERE `id` = :id';
|
||||
$values = [
|
||||
'id' => $sync->getId(),
|
||||
'event_id' => $sync->getEventId(),
|
||||
'foreign_id' => $sync->getGoogleId(),
|
||||
'event_date' => $sync->getEventDateAsString(),
|
||||
'owner' => $sync->getOwner(),
|
||||
];
|
||||
$this->db->fetchAffected($sql, $values);
|
||||
|
||||
return $sync->getId();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Task;
|
||||
|
||||
use DateInterval;
|
||||
use DateTime;
|
||||
use DateTimeImmutable;
|
||||
use Exception;
|
||||
use Xentral\Components\Logger\LoggerAwareTrait;
|
||||
use Xentral\Modules\GoogleApi\GoogleScope;
|
||||
use Xentral\Modules\GoogleApi\Service\GoogleAccountGateway;
|
||||
use Xentral\Modules\GoogleCalendar\Client\GoogleCalendarClientFactory;
|
||||
use Xentral\Modules\GoogleCalendar\Service\GoogleCalendarSynchronizer;
|
||||
use Xentral\Modules\User\Service\UserConfigService;
|
||||
|
||||
/**
|
||||
* Task class for cronjobs/google_calendar_import.php
|
||||
*/
|
||||
final class GoogleCalendarSynchronizerTask
|
||||
{
|
||||
use LoggerAwareTrait;
|
||||
|
||||
/** @var GoogleAccountGateway $gateway */
|
||||
private $gateway;
|
||||
|
||||
/** @var GoogleCalendarClientFactory $factory */
|
||||
private $factory;
|
||||
|
||||
/** @var GoogleCalendarSynchronizer $synchronizer */
|
||||
private $synchronizer;
|
||||
|
||||
/** @var UserConfigService $userConfig */
|
||||
private $userConfig;
|
||||
|
||||
/**
|
||||
* @param GoogleAccountGateway $gateway
|
||||
* @param GoogleCalendarClientFactory $factory
|
||||
* @param GoogleCalendarSynchronizer $synchronizer
|
||||
* @param UserConfigService $userConfig
|
||||
*/
|
||||
public function __construct(
|
||||
GoogleAccountGateway $gateway,
|
||||
GoogleCalendarClientFactory $factory,
|
||||
GoogleCalendarSynchronizer $synchronizer,
|
||||
UserConfigService $userConfig
|
||||
) {
|
||||
$this->gateway = $gateway;
|
||||
$this->factory = $factory;
|
||||
$this->synchronizer = $synchronizer;
|
||||
$this->userConfig = $userConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function execute(): void
|
||||
{
|
||||
$this->logger->notice('Google synchronization jop starts');
|
||||
try {
|
||||
$accounts = $this->gateway->getAccountsByScope(GoogleScope::CALENDAR);
|
||||
if (count($accounts) === 0) {
|
||||
$this->logger->notice(
|
||||
'Google synchronization exit cleanly: No accounts available for import.'
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
$timeNow = new DateTimeImmutable('now');
|
||||
$past = $timeNow->sub(new DateInterval('P1M'));
|
||||
$future = $timeNow->add(new DateInterval('P3M'));
|
||||
foreach ($accounts as $account) {
|
||||
try {
|
||||
$client = $this->factory->createClient($account->getUserId());
|
||||
$this->synchronizer->importAbsoluteEvents($client, $past, $future);
|
||||
$now = new DateTime('now');
|
||||
$this->userConfig->set(
|
||||
GoogleCalendarSynchronizer::CONFIG_KEY_LAST_SYNC,
|
||||
$now->format('Y-m-d H:i:s'),
|
||||
$account->getUserId()
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
$this->logger->debug(
|
||||
'ERROR during import with user "user_id={user}".',
|
||||
['user' => $account->getUserId(), 'exception' => $e]
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->logger->error(
|
||||
'Google synchronization Error: {message}',
|
||||
['exception' => $e, 'message' => $e]
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->logger->notice('Google synchronization finished');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function cleanup(): void
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\GoogleCalendar\Wrapper;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
|
||||
class UserAddressGatewayWrapper
|
||||
{
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param Database $database
|
||||
*/
|
||||
public function __construct(Database $database)
|
||||
{
|
||||
$this->db = $database;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds address id by user id.
|
||||
*
|
||||
* @param int $userId
|
||||
*
|
||||
* @return int address Id
|
||||
*/
|
||||
public function getAddressByUser(int $userId): int
|
||||
{
|
||||
if ($userId < 1) {
|
||||
return 0;
|
||||
}
|
||||
$entry = $this->db->fetchValue(
|
||||
'SELECT u.adresse FROM `user` AS `u` WHERE u.id = :userId',
|
||||
['userId' => (int)$userId]
|
||||
);
|
||||
|
||||
return (int)$entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $addressId
|
||||
*
|
||||
* @return int userId 0=address has no user
|
||||
*/
|
||||
public function getUserByAddress(int $addressId): int
|
||||
{
|
||||
if ($addressId < 1) {
|
||||
return 0;
|
||||
}
|
||||
$entry = $this->db->fetchValue(
|
||||
'SELECT u.id FROM `user` AS u WHERE u.adresse = :addressId',
|
||||
['addressId' => (int)$addressId]
|
||||
);
|
||||
|
||||
return (int)$entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $addressId
|
||||
*
|
||||
* @return string e-mail address
|
||||
*/
|
||||
public function getEmailByAddress(int $addressId): string
|
||||
{
|
||||
if ($addressId < 1) {
|
||||
return '';
|
||||
}
|
||||
$sql = "SELECT a.email AS `email`
|
||||
FROM `adresse` AS `a`
|
||||
WHERE a.id = :addressId AND a.email <> '' AND a.email IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT k.kontakt AS `email`
|
||||
FROM `adresse_kontakte` AS `k`
|
||||
WHERE k.adresse = :addressId AND (k.bezeichnung LIKE 'e%mail' OR k.bezeichnung LIKE '%google%')
|
||||
LIMIT 1";
|
||||
$values = ['addressId' => $addressId];
|
||||
$result = $this->db->fetchRow($sql, $values);
|
||||
if (empty($result) || $result['email'] === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $result['email'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds address Id by e-mail.
|
||||
*
|
||||
* @param string $email
|
||||
*
|
||||
* @return int address id
|
||||
*/
|
||||
public function findAddressByEmail(string $email): int
|
||||
{
|
||||
$values = ['email' => strtolower($email)];
|
||||
$address = $this->db->fetchValue(
|
||||
'SELECT u.adresse
|
||||
FROM `user` AS `u`
|
||||
JOIN `google_account` AS `gc` ON u.id = gc.user_id
|
||||
JOIN `google_account_property` AS `gp` ON gp.google_account_id = gc.id
|
||||
WHERE gp.value LIKE :email',
|
||||
$values
|
||||
);
|
||||
if ($address > 0) {
|
||||
return $address;
|
||||
}
|
||||
|
||||
$address = $this->db->fetchValue(
|
||||
'SELECT a.id
|
||||
FROM `adresse` AS `a`
|
||||
WHERE a.email LIKE :email AND a.geloescht = 0',
|
||||
$values
|
||||
);
|
||||
if ($address > 0) {
|
||||
return $address;
|
||||
}
|
||||
|
||||
$address = $this->db->fetchValue(
|
||||
"SELECT k.adresse
|
||||
FROM `adresse_kontakte` AS `k`
|
||||
WHERE (k.bezeichnung LIKE 'e%mail' OR k.bezeichnung LIKE '%google%') AND k.kontakt LIKE :email",
|
||||
$values
|
||||
);
|
||||
if ($address > 0) {
|
||||
return $address;
|
||||
}
|
||||
|
||||
$address = $this->db->fetchValue(
|
||||
"SELECT ap.adresse
|
||||
FROM `ansprechpartner` AS `ap`
|
||||
WHERE ap.email LIKE :email",
|
||||
$values
|
||||
);
|
||||
if ($address > 0) {
|
||||
return $address;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user