summaryrefslogtreecommitdiffstats
path: root/apps/dav/lib/CalDAV/Reminder/Notifier.php
diff options
context:
space:
mode:
authorGeorg Ehrke <developer@georgehrke.com>2019-08-09 20:25:21 +0200
committerRoeland Jago Douma <roeland@famdouma.nl>2019-08-15 20:03:51 +0200
commitbcce568c6d892ccacc598c5d5bfa6b24c3284741 (patch)
tree5ecf26f407ac71ef7b97e99a9f3f026c3ec6974e /apps/dav/lib/CalDAV/Reminder/Notifier.php
parent7c4a8a3bdf6d8c0c12cf7cab93cc465c83c4ec8f (diff)
downloadnextcloud-server-bcce568c6d892ccacc598c5d5bfa6b24c3284741.tar.gz
nextcloud-server-bcce568c6d892ccacc598c5d5bfa6b24c3284741.zip
Support recurring events + repeating alarms
Signed-off-by: Georg Ehrke <developer@georgehrke.com>
Diffstat (limited to 'apps/dav/lib/CalDAV/Reminder/Notifier.php')
-rw-r--r--apps/dav/lib/CalDAV/Reminder/Notifier.php292
1 files changed, 226 insertions, 66 deletions
diff --git a/apps/dav/lib/CalDAV/Reminder/Notifier.php b/apps/dav/lib/CalDAV/Reminder/Notifier.php
index 3718d5b29a6..4bad9841787 100644
--- a/apps/dav/lib/CalDAV/Reminder/Notifier.php
+++ b/apps/dav/lib/CalDAV/Reminder/Notifier.php
@@ -1,8 +1,11 @@
<?php
+declare(strict_types=1);
/**
- * @copyright Copyright (c) 2019 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 AGPL-3.0
*
@@ -22,37 +25,47 @@
namespace OCA\DAV\CalDAV\Reminder;
+use DateTime;
use OCA\DAV\AppInfo\Application;
+use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IL10N;
use OCP\L10N\IFactory;
use OCP\Notification\INotification;
use OCP\Notification\INotifier;
use OCP\IURLGenerator;
+/**
+ * Class Notifier
+ *
+ * @package OCA\DAV\CalDAV\Reminder
+ */
class Notifier implements INotifier {
- /** @var array */
- public static $units = [
- 'y' => 'year',
- 'm' => 'month',
- 'd' => 'day',
- 'h' => 'hour',
- 'i' => 'minute',
- 's' => 'second',
- ];
-
/** @var IFactory */
- protected $factory;
+ private $l10nFactory;
/** @var IURLGenerator */
- protected $urlGenerator;
+ private $urlGenerator;
/** @var IL10N */
- protected $l;
+ private $l10n;
+
+ /** @var ITimeFactory */
+ private $timeFactory;
- public function __construct(IFactory $factory, IURLGenerator $urlGenerator) {
- $this->factory = $factory;
+ /**
+ * Notifier constructor.
+ *
+ * @param IFactory $factory
+ * @param IURLGenerator $urlGenerator
+ * @param ITimeFactory $timeFactory
+ */
+ public function __construct(IFactory $factory,
+ IURLGenerator $urlGenerator,
+ ITimeFactory $timeFactory) {
+ $this->l10nFactory = $factory;
$this->urlGenerator = $urlGenerator;
+ $this->timeFactory = $timeFactory;
}
/**
@@ -62,7 +75,7 @@ class Notifier implements INotifier {
* @since 17.0.0
*/
public function getID():string {
- return 'dav';
+ return Application::APP_ID;
}
/**
@@ -72,89 +85,236 @@ class Notifier implements INotifier {
* @since 17.0.0
*/
public function getName():string {
- return $this->factory->get('dav')->t('Calendar');
+ if ($this->l10n) {
+ return $this->l10n->t('Calendar');
+ }
+
+ return $this->l10nFactory->get('dav')->t('Calendar');
}
/**
+ * Prepare sending the notification
+ *
* @param INotification $notification
* @param string $languageCode The code of the language that should be used to prepare the notification
* @return INotification
* @throws \Exception
*/
- public function prepare(INotification $notification, string $languageCode):INotification {
+ public function prepare(INotification $notification,
+ string $languageCode):INotification {
if ($notification->getApp() !== Application::APP_ID) {
throw new \InvalidArgumentException('Notification not from this app');
}
// Read the language from the notification
- $this->l = $this->factory->get('dav', $languageCode);
+ $this->l10n = $this->l10nFactory->get('dav', $languageCode);
- if ($notification->getSubject() === 'calendar_reminder') {
- $subjectParameters = $notification->getSubjectParameters();
- $notification->setParsedSubject($this->processEventTitle($subjectParameters));
+ // Handle notifier subjects
+ switch($notification->getSubject()) {
+ case 'calendar_reminder':
+ return $this->prepareReminderNotification($notification);
+
+ default:
+ throw new \InvalidArgumentException('Unknown subject');
- $messageParameters = $notification->getMessageParameters();
- $notification->setParsedMessage($this->processEventDescription($messageParameters));
- $notification->setIcon($this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'places/calendar.svg')));
- return $notification;
}
- // Unknown subject => Unknown notification => throw
- throw new \InvalidArgumentException('Unknown subject');
}
/**
- * @param array $event
- * @return string
- * @throws \Exception
+ * @param INotification $notification
+ * @return INotification
*/
- private function processEventTitle(array $event):string {
- $event_datetime = new \DateTime();
- $event_datetime->setTimestamp($event['start']);
- $now = new \DateTime();
-
- $diff = $event_datetime->diff($now);
-
- foreach (self::$units as $attribute => $unit) {
- $count = $diff->$attribute;
- if (0 !== $count) {
- return $this->getPluralizedTitle($count, $diff->invert, $unit, $event['title']);
- }
- }
- return '';
+ private function prepareReminderNotification(INotification $notification):INotification {
+ $imagePath = $this->urlGenerator->imagePath('core', 'places/calendar.svg');
+ $iconUrl = $this->urlGenerator->getAbsoluteURL($imagePath);
+ $notification->setIcon($iconUrl);
+
+ $this->prepareNotificationSubject($notification);
+ $this->prepareNotificationMessage($notification);
+
+ return $notification;
}
/**
+ * Sets the notification subject based on the parameters set in PushProvider
*
- * @param int $count
- * @param int $invert
- * @param string $unit
- * @param string $title
- * @return string
+ * @param INotification $notification
*/
- private function getPluralizedTitle(int $count, int $invert, string $unit, string $title):string {
- if ($invert) {
- return $this->l->n('%s (in one %s)', '%s (in %n %ss)', $count, [$title, $unit]);
+ private function prepareNotificationSubject(INotification $notification): void {
+ $parameters = $notification->getSubjectParameters();
+
+ $startTime = \DateTime::createFromFormat(\DateTimeInterface::ATOM, $parameters['start_atom']);
+ $now = $this->timeFactory->getDateTime();
+ $title = $this->getTitleFromParameters($parameters);
+
+ $diff = $startTime->diff($now);
+ if ($diff === false) {
+ return;
+ }
+
+ $components = [];
+ if ($diff->y) {
+ $components[] = $this->l10n->n('%n year', '%n years', $diff->y);
+ }
+ if ($diff->m) {
+ $components[] = $this->l10n->n('%n month', '%n months', $diff->m);
+ }
+ if ($diff->d) {
+ $components[] = $this->l10n->n('%n day', '%n days', $diff->d);
+ }
+ if ($diff->h) {
+ $components[] = $this->l10n->n('%n hour', '%n hours', $diff->h);
+ }
+ if ($diff->i) {
+ $components[] = $this->l10n->n('%n minute', '%n minutes', $diff->i);
+ }
+
+ // Limiting to the first three components to prevent
+ // the string from getting too long
+ $firstThreeComponents = array_slice($components, 0, 2);
+ $diffLabel = implode(', ', $firstThreeComponents);
+
+ if ($diff->invert) {
+ $title = $this->l10n->t('%s (in %s)', [$title, $diffLabel]);
+ } else {
+ $title = $this->l10n->t('%s (%s ago)', [$title, $diffLabel]);
}
- // This should probably not show up
- return $this->l->n('%s (one %s ago)', '%s (%n %ss ago)', $count, [$title, $unit]);
+
+ $notification->setParsedSubject($title);
}
/**
- * @param array $event
- * @return string
+ * Sets the notification message based on the parameters set in PushProvider
+ *
+ * @param INotification $notification
*/
- private function processEventDescription(array $event):string {
+ private function prepareNotificationMessage(INotification $notification): void {
+ $parameters = $notification->getMessageParameters();
+
$description = [
- $this->l->t('Calendar: %s', $event['calendar']),
- $this->l->t('Date: %s', $event['when']),
+ $this->l10n->t('Calendar: %s', $parameters['calendar_displayname']),
+ $this->l10n->t('Date: %s', $this->generateDateString($parameters)),
];
+ if ($parameters['description']) {
+ $description[] = $this->l10n->t('Description: %s', $parameters['description']);
+ }
+ if ($parameters['location']) {
+ $description[] = $this->l10n->t('Where: %s', $parameters['location']);
+ }
+
+ $message = implode("\r\n", $description);
+ $notification->setParsedMessage($message);
+ }
+
+ /**
+ * @param array $parameters
+ * @return string
+ */
+ private function getTitleFromParameters(array $parameters):string {
+ return $parameters['title'] ?? $this->l10n->t('Untitled event');
+ }
- if ($event['description']) {
- $description[] = $this->l->t('Description: %s', $event['description']);
+ /**
+ * @param array $parameters
+ * @return string
+ * @throws \Exception
+ */
+ private function generateDateString(array $parameters):string {
+ $startDateTime = DateTime::createFromFormat(DATE_ATOM, $parameters['start_atom']);
+ $endDateTime = DateTime::createFromFormat(DATE_ATOM, $parameters['end_atom']);
+ $isAllDay = $parameters['all_day'];
+ $diff = $startDateTime->diff($endDateTime);
+
+ if ($isAllDay) {
+ // One day event
+ if ($diff->days === 1) {
+ return $this->getDateString($startDateTime);
+ }
+
+ return implode(' - ', [
+ $this->getDateString($startDateTime),
+ $this->getDateString($endDateTime),
+ ]);
}
- if ($event['location']) {
- $description[] = $this->l->t('Where: %s', $event['location']);
+
+ $startTimezone = $endTimezone = null;
+ if (!$parameters['start_is_floating']) {
+ $startTimezone = $parameters['start_timezone'];
+ $endTimezone = $parameters['end_timezone'];
}
- return implode('<br>', $description);
+
+ $localeStart = implode(', ', [
+ $this->getWeekDayName($startDateTime),
+ $this->getDateTimeString($startDateTime)
+ ]);
+
+ // always show full date with timezone if timezones are different
+ if ($startTimezone !== $endTimezone) {
+ $localeEnd = implode(', ', [
+ $this->getWeekDayName($endDateTime),
+ $this->getDateTimeString($endDateTime)
+ ]);
+
+ return $localeStart
+ . ' (' . $startTimezone . ') '
+ . ' - '
+ . $localeEnd
+ . ' (' . $endTimezone . ')';
+ }
+
+ // Show only the time if the day is the same
+ $localeEnd = $this->isDayEqual($startDateTime, $endDateTime)
+ ? $this->getTimeString($endDateTime)
+ : implode(', ', [
+ $this->getWeekDayName($endDateTime),
+ $this->getDateTimeString($endDateTime)
+ ]);
+
+ 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 DateTime $dt
+ * @return string
+ */
+ private function getWeekDayName(DateTime $dt):string {
+ return $this->l10n->l('weekdayName', $dt, ['width' => 'abbreviated']);
+ }
+
+ /**
+ * @param DateTime $dt
+ * @return string
+ */
+ private function getDateString(DateTime $dt):string {
+ return $this->l10n->l('date', $dt, ['width' => 'medium']);
+ }
+
+ /**
+ * @param DateTime $dt
+ * @return string
+ */
+ private function getDateTimeString(DateTime $dt):string {
+ return $this->l10n->l('datetime', $dt, ['width' => 'medium|short']);
+ }
+
+ /**
+ * @param DateTime $dt
+ * @return string
+ */
+ private function getTimeString(DateTime $dt):string {
+ return $this->l10n->l('time', $dt, ['width' => 'short']);
}
}