diff options
Diffstat (limited to 'apps/dav/lib/CalDAV/Reminder/NotificationProvider')
5 files changed, 700 insertions, 97 deletions
diff --git a/apps/dav/lib/CalDAV/Reminder/NotificationProvider/AbstractProvider.php b/apps/dav/lib/CalDAV/Reminder/NotificationProvider/AbstractProvider.php new file mode 100644 index 00000000000..6b2364c8022 --- /dev/null +++ b/apps/dav/lib/CalDAV/Reminder/NotificationProvider/AbstractProvider.php @@ -0,0 +1,191 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2019, Thomas Citharel + * @copyright Copyright (c) 2019, Georg Ehrke + * + * @author Thomas Citharel <tcit@tcit.fr> + * @author Georg Ehrke <oc.list@georgehrke.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCA\DAV\CalDAV\Reminder\NotificationProvider; + +use \DateTime; +use \DateTimeImmutable; +use OCA\DAV\CalDAV\Reminder\INotificationProvider; +use OCP\IConfig; +use OCP\IL10N; +use OCP\ILogger; +use OCP\IURLGenerator; +use OCP\L10N\IFactory as L10NFactory; +use OCP\IUser; +use Sabre\VObject\Component\VEvent; +use Sabre\VObject\DateTimeParser; +use Sabre\VObject\Parameter; +use Sabre\VObject\Property; + +/** + * Class AbstractProvider + * + * @package OCA\DAV\CalDAV\Reminder\NotificationProvider + */ +abstract class AbstractProvider implements INotificationProvider { + + /** @var string */ + public const NOTIFICATION_TYPE = ''; + + /** @var ILogger */ + protected $logger; + + /** @var L10NFactory */ + private $l10nFactory; + + /** @var IL10N[] */ + private $l10ns; + + /** @var string */ + private $fallbackLanguage; + + /** @var IURLGenerator */ + protected $urlGenerator; + + /** @var IConfig */ + protected $config; + + /** + * @param ILogger $logger + * @param L10NFactory $l10nFactory + * @param IConfig $config + * @param IUrlGenerator $urlGenerator + */ + public function __construct(ILogger $logger, + L10NFactory $l10nFactory, + IURLGenerator $urlGenerator, + IConfig $config) { + $this->logger = $logger; + $this->l10nFactory = $l10nFactory; + $this->urlGenerator = $urlGenerator; + $this->config = $config; + } + + /** + * Send notification + * + * @param VEvent $vevent + * @param string $calendarDisplayName + * @param IUser[] $users + * @return void + */ + abstract public function send(VEvent $vevent, + string $calendarDisplayName, + array $users=[]): void; + + /** + * @return string + */ + protected function getFallbackLanguage():string { + if ($this->fallbackLanguage) { + return $this->fallbackLanguage; + } + + $fallbackLanguage = $this->l10nFactory->findLanguage(); + $this->fallbackLanguage = $fallbackLanguage; + + return $fallbackLanguage; + } + + /** + * @param string $lang + * @return bool + */ + protected function hasL10NForLang(string $lang):bool { + return $this->l10nFactory->languageExists('dav', $lang); + } + + /** + * @param string $lang + * @return IL10N + */ + protected function getL10NForLang(string $lang):IL10N { + if (isset($this->l10ns[$lang])) { + return $this->l10ns[$lang]; + } + + $l10n = $this->l10nFactory->get('dav', $lang); + $this->l10ns[$lang] = $l10n; + + return $l10n; + } + + /** + * @param VEvent $vevent + * @return string + */ + private function getStatusOfEvent(VEvent $vevent):string { + if ($vevent->STATUS) { + return (string) $vevent->STATUS; + } + + // Doesn't say so in the standard, + // but we consider events without a status + // to be confirmed + return 'CONFIRMED'; + } + + /** + * @param VEvent $vevent + * @return bool + */ + protected function isEventTentative(VEvent $vevent):bool { + return $this->getStatusOfEvent($vevent) === 'TENTATIVE'; + } + + /** + * @param VEvent $vevent + * @return Property\ICalendar\DateTime + */ + protected function getDTEndFromEvent(VEvent $vevent):Property\ICalendar\DateTime { + if (isset($vevent->DTEND)) { + return $vevent->DTEND; + } + + if (isset($vevent->DURATION)) { + $isFloating = $vevent->DTSTART->isFloating(); + /** @var Property\ICalendar\DateTime $end */ + $end = clone $vevent->DTSTART; + $endDateTime = $end->getDateTime(); + $endDateTime = $endDateTime->add(DateTimeParser::parse($vevent->DURATION->getValue())); + $end->setDateTime($endDateTime, $isFloating); + + return $end; + } + + if (!$vevent->DTSTART->hasTime()) { + $isFloating = $vevent->DTSTART->isFloating(); + /** @var Property\ICalendar\DateTime $end */ + $end = clone $vevent->DTSTART; + $endDateTime = $end->getDateTime(); + $endDateTime = $endDateTime->modify('+1 day'); + $end->setDateTime($endDateTime, $isFloating); + + return $end; + } + + return clone $vevent->DTSTART; + } +} diff --git a/apps/dav/lib/CalDAV/Reminder/NotificationProvider/AudioProvider.php b/apps/dav/lib/CalDAV/Reminder/NotificationProvider/AudioProvider.php index 6e702bcacaa..ad4ac342f66 100644 --- a/apps/dav/lib/CalDAV/Reminder/NotificationProvider/AudioProvider.php +++ b/apps/dav/lib/CalDAV/Reminder/NotificationProvider/AudioProvider.php @@ -1,4 +1,5 @@ <?php +declare(strict_types=1); /** * @copyright Copyright (c) 2019, Georg Ehrke * diff --git a/apps/dav/lib/CalDAV/Reminder/NotificationProvider/EmailProvider.php b/apps/dav/lib/CalDAV/Reminder/NotificationProvider/EmailProvider.php index f05439932b6..2a7eb2a4032 100644 --- a/apps/dav/lib/CalDAV/Reminder/NotificationProvider/EmailProvider.php +++ b/apps/dav/lib/CalDAV/Reminder/NotificationProvider/EmailProvider.php @@ -1,8 +1,11 @@ <?php +declare(strict_types=1); /** - * @copyright Copyright (c) 2018 Thomas Citharel <tcit@tcit.fr> + * @copyright Copyright (c) 2019, Thomas Citharel + * @copyright Copyright (c) 2019, Georg Ehrke * * @author Thomas Citharel <tcit@tcit.fr> + * @author Georg Ehrke <oc.list@georgehrke.com> * * @license GNU AGPL version 3 or any later version * @@ -20,27 +23,36 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ - namespace OCA\DAV\CalDAV\Reminder\NotificationProvider; -use OCA\DAV\CalDAV\Reminder\AbstractNotificationProvider; +use DateTime; +use DateTimeImmutable; use OCP\IConfig; +use OCP\IL10N; use OCP\ILogger; use OCP\IURLGenerator; use OCP\L10N\IFactory as L10NFactory; use OCP\Mail\IEMailTemplate; use OCP\Mail\IMailer; use OCP\IUser; -use Sabre\VObject\Component\VCalendar; - -class EmailProvider extends AbstractNotificationProvider { +use Sabre\VObject\Component\VEvent; +use Sabre\VObject; +use Sabre\VObject\Parameter; +use Sabre\VObject\Property; - /** @var IMailer */ - private $mailer; +/** + * Class EmailProvider + * + * @package OCA\DAV\CalDAV\Reminder\NotificationProvider + */ +class EmailProvider extends AbstractProvider { /** @var string */ public const NOTIFICATION_TYPE = 'EMAIL'; + /** @var IMailer */ + private $mailer; + /** * @param IConfig $config * @param IMailer $mailer @@ -48,7 +60,9 @@ class EmailProvider extends AbstractNotificationProvider { * @param L10NFactory $l10nFactory * @param IUrlGenerator $urlGenerator */ - public function __construct(IConfig $config, IMailer $mailer, ILogger $logger, + public function __construct(IConfig $config, + IMailer $mailer, + ILogger $logger, L10NFactory $l10nFactory, IURLGenerator $urlGenerator) { parent::__construct($logger, $l10nFactory, $urlGenerator, $config); @@ -56,90 +70,100 @@ class EmailProvider extends AbstractNotificationProvider { } /** - * Send notification + * Send out notification via email * - * @param VCalendar $vcalendar + * @param VEvent $vevent * @param string $calendarDisplayName - * @param IUser $user - * @return void + * @param array $users * @throws \Exception */ - public function send(VCalendar $vcalendar, string $calendarDisplayName, IUser $user):void { - if ($user->getEMailAddress() === null) { - return; - } + public function send(VEvent $vevent, + string $calendarDisplayName, + array $users=[]):void { + $fallbackLanguage = $this->getFallbackLanguage(); - $lang = $this->config->getUserValue($user->getUID(), 'core', 'lang', $this->l10nFactory->findLanguage()); - $this->l10n = $this->l10nFactory->get('dav', $lang); + $emailAddressesOfSharees = $this->getEMailAddressesOfAllUsersWithWriteAccessToCalendar($users); + $emailAddressesOfAttendees = $this->getAllEMailAddressesFromEvent($vevent); - $event = $this->extractEventDetails($vcalendar); - $fromEMail = \OCP\Util::getDefaultEmailAddress('invitations-noreply'); + // Quote from php.net: + // If the input arrays have the same string keys, then the later value for that key will overwrite the previous one. + // => if there are duplicate email addresses, it will always take the system value + $emailAddresses = array_merge( + $emailAddressesOfAttendees, + $emailAddressesOfSharees + ); - $message = $this->mailer->createMessage() - ->setFrom([$fromEMail => 'Nextcloud']) - // TODO: Set reply to from event creator - // ->setReplyTo([$sender => $senderName]) - ->setTo([$user->getEMailAddress() => $user->getDisplayName()]); + $sortedByLanguage = $this->sortEMailAddressesByLanguage($emailAddresses, $fallbackLanguage); + $organizer = $this->getOrganizerEMailAndNameFromEvent($vevent); + + foreach($sortedByLanguage as $lang => $emailAddresses) { + if ($this->hasL10NForLang($lang)) { + $lang = $fallbackLanguage; + } + $l10n = $this->getL10NForLang($lang); + $fromEMail = \OCP\Util::getDefaultEmailAddress('reminders-noreply'); - $template = $this->mailer->createEMailTemplate('dav.calendarReminder', $event); - $template->addHeader(); + $message = $this->mailer->createMessage(); + $message->setFrom([$fromEMail]); + if ($organizer) { + $message->setReplyTo($organizer); + } + $message->setBcc($emailAddresses); - $this->addSubjectAndHeading($template, $event['title']); - $this->addBulletList($template, $event, $calendarDisplayName); + $template = $this->mailer->createEMailTemplate('dav.calendarReminder'); + $template->addHeader(); - $template->addFooter(); - $message->useTemplate($template); + $this->addSubjectAndHeading($template, $l10n, $vevent); + $this->addBulletList($template, $l10n, $calendarDisplayName, $vevent); - $attachment = $this->mailer->createAttachment( - $vcalendar->serialize(), - $event['uid'].'.ics',// TODO(leon): Make file name unique, e.g. add event id - 'text/calendar' - ); - $message->attach($attachment); + $template->addFooter(); + $message->useTemplate($template); - try { - $failed = $this->mailer->send($message); - if ($failed) { - $this->logger->error('Unable to deliver message to {failed}', ['app' => 'dav', 'failed' => implode(', ', $failed)]); + try { + $failed = $this->mailer->send($message); + if ($failed) { + $this->logger->error('Unable to deliver message to {failed}', ['app' => 'dav', 'failed' => implode(', ', $failed)]); + } + } catch (\Exception $ex) { + $this->logger->logException($ex, ['app' => 'dav']); } - } catch(\Exception $ex) { - $this->logger->logException($ex, ['app' => 'dav']); } } /** * @param IEMailTemplate $template - * @param string $summary + * @param IL10N $l10n + * @param VEvent $vevent */ - private function addSubjectAndHeading(IEMailTemplate $template, string $summary):void { - $template->setSubject('Notification: ' . $summary); - $template->addHeading($summary); + private function addSubjectAndHeading(IEMailTemplate $template, IL10N $l10n, VEvent $vevent):void { + $template->setSubject('Notification: ' . $this->getTitleFromVEvent($vevent, $l10n)); + $template->addHeading($this->getTitleFromVEvent($vevent, $l10n)); } /** * @param IEMailTemplate $template - * @param array $eventData + * @param IL10N $l10n * @param string $calendarDisplayName + * @param array $eventData */ - private function addBulletList(IEMailTemplate $template, array $eventData, string $calendarDisplayName):void { - $template->addBodyListItem($calendarDisplayName, $this->l10n->t('Calendar:'), + private function addBulletList(IEMailTemplate $template, + IL10N $l10n, + string $calendarDisplayName, + VEvent $vevent):void { + $template->addBodyListItem($calendarDisplayName, $l10n->t('Calendar:'), $this->getAbsoluteImagePath('actions/info.svg')); - $template->addBodyListItem($eventData['when'], $this->l10n->t('Date:'), + $template->addBodyListItem($this->generateDateString($l10n, $vevent), $l10n->t('Date:'), $this->getAbsoluteImagePath('places/calendar.svg')); - if ($eventData['location']) { - $template->addBodyListItem((string) $eventData['location'], $this->l10n->t('Where:'), + if (isset($vevent->LOCATION)) { + $template->addBodyListItem((string) $vevent->LOCATION, $l10n->t('Where:'), $this->getAbsoluteImagePath('actions/address.svg')); } - if ($eventData['description']) { - $template->addBodyListItem((string) $eventData['description'], $this->l10n->t('Description:'), + if (isset($vevent->DESCRIPTION)) { + $template->addBodyListItem((string) $vevent->DESCRIPTION, $l10n->t('Description:'), $this->getAbsoluteImagePath('actions/more.svg')); } - if ($eventData['url']) { - $template->addBodyListItem((string) $eventData['url'], $this->l10n->t('Link:'), - $this->getAbsoluteImagePath('places/link.svg')); - } } /** @@ -151,4 +175,355 @@ class EmailProvider extends AbstractNotificationProvider { $this->urlGenerator->imagePath('core', $path) ); } + + /** + * @param VEvent $vevent + * @return array|null + */ + private function getOrganizerEMailAndNameFromEvent(VEvent $vevent):?array { + if (!$vevent->ORGANIZER) { + return null; + } + + $organizer = $vevent->ORGANZIER; + if (strcasecmp($organizer->getValue(), 'mailto:') !== 0) { + return null; + } + + $organizerEMail = substr($organizer->getValue(), 7); + + $name = $organizer->offsetGet('CN'); + if ($name instanceof Parameter) { + return [$organizerEMail => $name]; + } + + return [$organizerEMail]; + } + + /** + * @param array $sortedByLanguage + * @param IUser[] $users + * @param string $defaultLanguage + */ + private function sortUsersByLanguage(array &$sortedByLanguage, + array $users, + string $defaultLanguage):void { + /** + * @var array $sortedByLanguage + * [ + * 'de' => ['a@b.com', 'c@d.com'], + * ... + * ] + */ + foreach($users as $user) { + /** @var IUser $user */ + $emailAddress = $user->getEMailAddress(); + $lang = $this->config->getUserValue($user->getUID(), + 'core', 'lang', $defaultLanguage); + + if (!isset($sortedByLanguage[$lang])) { + $sortedByLanguage[$lang] = []; + } + + $sortedByLanguage[$lang][] = $emailAddress; + } + } + + /** + * @param array $emails + * @param string $defaultLanguage + * @return array + */ + private function sortEMailAddressesByLanguage(array $emails, + string $defaultLanguage):array { + $sortedByLanguage = []; + + foreach($emails as $emailAddress => $parameters) { + if (isset($parameters['LANG'])) { + $lang = $parameters['LANG']; + } else { + $lang = $defaultLanguage; + } + + if (!isset($sortedByLanguage[$lang])) { + $sortedByLanguage[$lang] = []; + } + + $sortedByLanguage[$lang][] = $emailAddress; + } + + return $sortedByLanguage; + } + + /** + * @param VEvent $vevent + * @return array + */ + private function getAllEMailAddressesFromEvent(VEvent $vevent):array { + $emailAddresses = []; + + if (isset($vevent->ATTENDEE)) { + foreach ($vevent->ATTENDEE as $attendee) { + if (!($attendee instanceof VObject\Property)) { + continue; + } + + $cuType = $this->getCUTypeOfAttendee($attendee); + if (\in_array($cuType, ['RESOURCE', 'ROOM', 'UNKNOWN'])) { + // Don't send emails to things + continue; + } + + $partstat = $this->getPartstatOfAttendee($attendee); + if ($partstat === 'DECLINED') { + // Don't send out emails to people who declined + continue; + } + if ($partstat === 'DELEGATED') { + $delegates = $attendee->offsetGet('DELEGATED-TO'); + if (!($delegates instanceof VObject\Parameter)) { + continue; + } + + $emailAddressesOfDelegates = $delegates->getParts(); + foreach($emailAddressesOfDelegates as $addressesOfDelegate) { + if (strcasecmp($addressesOfDelegate, 'mailto:') === 0) { + $emailAddresses[substr($addressesOfDelegate, 7)] = []; + } + } + + continue; + } + + $emailAddressOfAttendee = $this->getEMailAddressOfAttendee($attendee); + if ($emailAddressOfAttendee !== null) { + $properties = []; + + $langProp = $attendee->offsetGet('LANG'); + if ($langProp instanceof VObject\Parameter) { + $properties['LANG'] = $langProp->getValue(); + } + + $emailAddresses[$emailAddressOfAttendee] = $properties; + } + } + } + + if (isset($vevent->ORGANIZER)) { + $emailAddresses[$this->getEMailAddressOfAttendee($vevent->ORGANIZER)] = []; + } + + return $emailAddresses; + } + + + + /** + * @param VObject\Property $attendee + * @return string + */ + private function getCUTypeOfAttendee(VObject\Property $attendee):string { + $cuType = $attendee->offsetGet('CUTYPE'); + if ($cuType instanceof VObject\Parameter) { + return strtoupper($cuType->getValue()); + } + + return 'INDIVIDUAL'; + } + + /** + * @param VObject\Property $attendee + * @return string + */ + private function getPartstatOfAttendee(VObject\Property $attendee):string { + $partstat = $attendee->offsetGet('PARTSTAT'); + if ($partstat instanceof VObject\Parameter) { + return strtoupper($partstat->getValue()); + } + + return 'NEEDS-ACTION'; + } + + /** + * @param VObject\Property $attendee + * @return bool + */ + private function hasAttendeeMailURI(VObject\Property $attendee):bool { + return strcasecmp($attendee->getValue(), 'mailto:') === 0; + } + + /** + * @param VObject\Property $attendee + * @return string|null + */ + private function getEMailAddressOfAttendee(VObject\Property $attendee):?string { + if (!$this->hasAttendeeMailURI($attendee)) { + return null; + } + + return substr($attendee->getValue(), 7); + } + + /** + * @param array $users + * @return array + */ + private function getEMailAddressesOfAllUsersWithWriteAccessToCalendar(array $users):array { + $emailAddresses = []; + + foreach($users as $user) { + $emailAddress = $user->getEMailAddress(); + if ($emailAddress) { + $lang = $this->getLangForUser($user); + if ($lang) { + $emailAddresses[$emailAddress] = [ + 'LANG' => $lang, + ]; + } else { + $emailAddresses[$emailAddress] = []; + } + } + } + + return array_unique($emailAddresses); + } + + /** + * @param IUser $user + * @return string + */ + private function getLangForUser(IUser $user): ?string { + return $this->config->getUserValue($user->getUID(), 'core', 'lang', null); + } + + /** + * @param IL10N $l10n + * @param VEvent $vevent + * @return string + * @throws \Exception + */ + private function generateDateString(IL10N $l10n, VEvent $vevent):string { + $isAllDay = $vevent->DTSTART instanceof Property\ICalendar\Date; + + /** @var Property\ICalendar\Date | Property\ICalendar\DateTime $dtstart */ + /** @var Property\ICalendar\Date | Property\ICalendar\DateTime $dtend */ + /** @var \DateTimeImmutable $dtstartDt */ + $dtstartDt = $vevent->DTSTART->getDateTime(); + /** @var \DateTimeImmutable $dtendDt */ + $dtendDt = $this->getDTEndFromEvent($vevent)->getDateTime(); + + $diff = $dtstartDt->diff($dtendDt); + + $dtstartDt = new \DateTime($dtstartDt->format(\DateTime::ATOM)); + $dtendDt = new \DateTime($dtendDt->format(\DateTime::ATOM)); + + if ($isAllDay) { + // One day event + if ($diff->days === 1) { + return $this->getDateString($l10n, $dtstartDt); + } + + return implode(' - ', [ + $this->getDateString($l10n, $dtstartDt), + $this->getDateString($l10n, $dtendDt), + ]); + } + + $startTimezone = $endTimezone = null; + if (!$vevent->DTSTART->isFloating()) { + $startTimezone = $vevent->DTSTART->getDateTime()->getTimezone()->getName(); + $endTimezone = $this->getDTEndFromEvent($vevent)->getDateTime()->getTimezone()->getName(); + } + + $localeStart = implode(', ', [ + $this->getWeekDayName($l10n, $dtstartDt), + $this->getDateTimeString($l10n, $dtstartDt) + ]); + + // always show full date with timezone if timezones are different + if ($startTimezone !== $endTimezone) { + $localeEnd = implode(', ', [ + $this->getWeekDayName($l10n, $dtendDt), + $this->getDateTimeString($l10n, $dtendDt) + ]); + + return $localeStart + . ' (' . $startTimezone . ') ' + . ' - ' + . $localeEnd + . ' (' . $endTimezone . ')'; + } + + // Show only the time if the day is the same + $localeEnd = $this->isDayEqual($dtstartDt, $dtendDt) + ? $this->getTimeString($l10n, $dtendDt) + : implode(', ', [ + $this->getWeekDayName($l10n, $dtendDt), + $this->getDateTimeString($l10n, $dtendDt) + ]); + + return $localeStart + . ' - ' + . $localeEnd + . ' (' . $startTimezone . ')'; + } + + /** + * @param DateTime $dtStart + * @param DateTime $dtEnd + * @return bool + */ + private function isDayEqual(DateTime $dtStart, + DateTime $dtEnd):bool { + return $dtStart->format('Y-m-d') === $dtEnd->format('Y-m-d'); + } + + /** + * @param IL10N $l10n + * @param DateTime $dt + * @return string + */ + private function getWeekDayName(IL10N $l10n, DateTime $dt):string { + return $l10n->l('weekdayName', $dt, ['width' => 'abbreviated']); + } + + /** + * @param IL10N $l10n + * @param DateTime $dt + * @return string + */ + private function getDateString(IL10N $l10n, DateTime $dt):string { + return $l10n->l('date', $dt, ['width' => 'medium']); + } + + /** + * @param IL10N $l10n + * @param DateTime $dt + * @return string + */ + private function getDateTimeString(IL10N $l10n, DateTime $dt):string { + return $l10n->l('datetime', $dt, ['width' => 'medium|short']); + } + + /** + * @param IL10N $l10n + * @param DateTime $dt + * @return string + */ + private function getTimeString(IL10N $l10n, DateTime $dt):string { + return $l10n->l('time', $dt, ['width' => 'short']); + } + + /** + * @param VEvent $vevent + * @param IL10N $l10n + * @return string + */ + private function getTitleFromVEvent(VEvent $vevent, IL10N $l10n):string { + if (isset($vevent->SUMMARY)) { + return (string)$vevent->SUMMARY; + } + + return $l10n->t('Untitled event'); + } } diff --git a/apps/dav/lib/CalDAV/Reminder/NotificationProvider/ProviderNotAvailableException.php b/apps/dav/lib/CalDAV/Reminder/NotificationProvider/ProviderNotAvailableException.php index bf736db8a34..bfa6db95852 100644 --- a/apps/dav/lib/CalDAV/Reminder/NotificationProvider/ProviderNotAvailableException.php +++ b/apps/dav/lib/CalDAV/Reminder/NotificationProvider/ProviderNotAvailableException.php @@ -1,4 +1,5 @@ <?php +declare(strict_types=1); /** * @copyright Copyright (c) 2018 Thomas Citharel <tcit@tcit.fr> * @@ -20,7 +21,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ - namespace OCA\DAV\CalDAV\Reminder\NotificationProvider; class ProviderNotAvailableException extends \Exception { diff --git a/apps/dav/lib/CalDAV/Reminder/NotificationProvider/PushProvider.php b/apps/dav/lib/CalDAV/Reminder/NotificationProvider/PushProvider.php index f04b8e4c45a..2e580fd78a3 100644 --- a/apps/dav/lib/CalDAV/Reminder/NotificationProvider/PushProvider.php +++ b/apps/dav/lib/CalDAV/Reminder/NotificationProvider/PushProvider.php @@ -1,8 +1,11 @@ <?php +declare(strict_types=1); /** - * @copyright Copyright (c) 2018 Thomas Citharel <tcit@tcit.fr> + * @copyright Copyright (c) 2019, Thomas Citharel + * @copyright Copyright (c) 2019, Georg Ehrke * * @author Thomas Citharel <tcit@tcit.fr> + * @author Georg Ehrke <oc.list@georgehrke.com> * * @license GNU AGPL version 3 or any later version * @@ -20,11 +23,9 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ - namespace OCA\DAV\CalDAV\Reminder\NotificationProvider; use OCA\DAV\AppInfo\Application; -use OCA\DAV\CalDAV\Reminder\AbstractNotificationProvider; use OCP\IConfig; use OCP\ILogger; use OCP\IURLGenerator; @@ -32,22 +33,24 @@ use OCP\L10N\IFactory as L10NFactory; use OCP\Notification\IManager; use OCP\IUser; use OCP\Notification\INotification; -use Sabre\VObject\Component\VCalendar; use OCP\AppFramework\Utility\ITimeFactory; +use Sabre\VObject\Component\VEvent; +use Sabre\VObject\Property; -class PushProvider extends AbstractNotificationProvider { +/** + * Class PushProvider + * + * @package OCA\DAV\CalDAV\Reminder\NotificationProvider + */ +class PushProvider extends AbstractProvider { /** @var string */ public const NOTIFICATION_TYPE = 'DISPLAY'; - /** - * @var IManager - */ + /** @var IManager */ private $manager; - /** - * @var ITimeFactory - */ + /** @var ITimeFactory */ private $timeFactory; /** @@ -58,42 +61,75 @@ class PushProvider extends AbstractNotificationProvider { * @param IUrlGenerator $urlGenerator * @param ITimeFactory $timeFactory */ - public function __construct(IConfig $config, IManager $manager, ILogger $logger, + public function __construct(IConfig $config, + IManager $manager, + ILogger $logger, L10NFactory $l10nFactory, - IURLGenerator $urlGenerator, ITimeFactory $timeFactory) { + IURLGenerator $urlGenerator, + ITimeFactory $timeFactory) { parent::__construct($logger, $l10nFactory, $urlGenerator, $config); $this->manager = $manager; $this->timeFactory = $timeFactory; } /** - * Send notification + * Send push notification to all users. * - * @param VCalendar $vcalendar + * @param VEvent $vevent * @param string $calendarDisplayName - * @param IUser $user - * @return void + * @param IUser[] $users * @throws \Exception */ - public function send(VCalendar $vcalendar, string $calendarDisplayName, IUser $user):void { - $lang = $this->config->getUserValue($user->getUID(), 'core', 'lang', $this->l10nFactory->findLanguage()); - $this->l10n = $this->l10nFactory->get('dav', $lang); + public function send(VEvent $vevent, + string $calendarDisplayName=null, + array $users=[]):void { + $eventDetails = $this->extractEventDetails($vevent); + $eventDetails['calendar_displayname'] = $calendarDisplayName; - $event = $this->extractEventDetails($vcalendar); - /** @var INotification $notification */ - $notification = $this->manager->createNotification(); - $notification->setApp(Application::APP_ID) - ->setUser($user->getUID()) - ->setDateTime($this->timeFactory->getDateTime()) - ->setObject(Application::APP_ID, $event['uid']) // $type and $id - ->setSubject('calendar_reminder', ['title' => $event['title'], 'start' => $event['start']->getTimestamp()]) // $subject and $parameters - ->setMessage('calendar_reminder', [ - 'when' => $event['when'], - 'description' => $event['description'], - 'location' => $event['location'], - 'calendar' => $calendarDisplayName - ]) - ; - $this->manager->notify($notification); + foreach($users as $user) { + /** @var INotification $notification */ + $notification = $this->manager->createNotification(); + $notification->setApp(Application::APP_ID) + ->setUser($user->getUID()) + ->setDateTime($this->timeFactory->getDateTime()) + ->setObject(Application::APP_ID, (string) $vevent->UID) + ->setSubject('calendar_reminder', [ + 'title' => $eventDetails['title'], + 'start_atom' => $eventDetails['start_atom'] + ]) + ->setMessage('calendar_reminder', $eventDetails); + + $this->manager->notify($notification); + } } + + /** + * @var VEvent $vevent + * @return array + * @throws \Exception + */ + protected function extractEventDetails(VEvent $vevent):array { + /** @var Property\ICalendar\DateTime $start */ + $start = $vevent->DTSTART; + $end = $this->getDTEndFromEvent($vevent); + + return [ + 'title' => isset($vevent->SUMMARY) + ? ((string) $vevent->SUMMARY) + : null, + 'description' => isset($vevent->DESCRIPTION) + ? ((string) $vevent->DESCRIPTION) + : null, + 'location' => isset($vevent->LOCATION) + ? ((string) $vevent->LOCATION) + : null, + 'all_day' => $start instanceof Property\ICalendar\Date, + 'start_atom' => $start->getDateTime()->format(\DateTime::ATOM), + 'start_is_floating' => $start->isFloating(), + 'start_timezone' => $start->getDateTime()->getTimezone()->getName(), + 'end_atom' => $end->getDateTime()->format(\DateTime::ATOM), + 'end_is_floating' => $end->isFloating(), + 'end_timezone' => $end->getDateTime()->getTimezone()->getName(), + ]; + } } |