Merge pull request #3044 from nextcloud/dav-email-reminders
Calendar events email reminders
This commit is contained in:
commit
6ef7ba2000
2
3rdparty
2
3rdparty
|
@ -1 +1 @@
|
||||||
Subproject commit ef289bc27eae0cdfc3f74f419ace8dda8dd84ef0
|
Subproject commit 49ccfbb28661b9ef7743c1725cd2571259215929
|
|
@ -108,3 +108,6 @@ $calendarManager->register(function() use ($calendarManager, $app) {
|
||||||
$app->setupCalendarProvider($calendarManager, $user->getUID());
|
$app->setupCalendarProvider($calendarManager, $user->getUID());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$app->registerNotifier();
|
||||||
|
$app->registerCalendarReminders();
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<name>WebDAV</name>
|
<name>WebDAV</name>
|
||||||
<summary>WebDAV endpoint</summary>
|
<summary>WebDAV endpoint</summary>
|
||||||
<description>WebDAV endpoint</description>
|
<description>WebDAV endpoint</description>
|
||||||
<version>1.11.1</version>
|
<version>1.13.0</version>
|
||||||
<licence>agpl</licence>
|
<licence>agpl</licence>
|
||||||
<author>owncloud.org</author>
|
<author>owncloud.org</author>
|
||||||
<namespace>DAV</namespace>
|
<namespace>DAV</namespace>
|
||||||
|
@ -23,6 +23,7 @@
|
||||||
<job>OCA\DAV\BackgroundJob\CleanupDirectLinksJob</job>
|
<job>OCA\DAV\BackgroundJob\CleanupDirectLinksJob</job>
|
||||||
<job>OCA\DAV\BackgroundJob\UpdateCalendarResourcesRoomsBackgroundJob</job>
|
<job>OCA\DAV\BackgroundJob\UpdateCalendarResourcesRoomsBackgroundJob</job>
|
||||||
<job>OCA\DAV\BackgroundJob\CleanupInvitationTokenJob</job>
|
<job>OCA\DAV\BackgroundJob\CleanupInvitationTokenJob</job>
|
||||||
|
<job>OCA\DAV\BackgroundJob\EventReminderJob</job>
|
||||||
</background-jobs>
|
</background-jobs>
|
||||||
|
|
||||||
<repair-steps>
|
<repair-steps>
|
||||||
|
@ -32,6 +33,7 @@
|
||||||
<step>OCA\DAV\Migration\CalDAVRemoveEmptyValue</step>
|
<step>OCA\DAV\Migration\CalDAVRemoveEmptyValue</step>
|
||||||
<step>OCA\DAV\Migration\BuildCalendarSearchIndex</step>
|
<step>OCA\DAV\Migration\BuildCalendarSearchIndex</step>
|
||||||
<step>OCA\DAV\Migration\RefreshWebcalJobRegistrar</step>
|
<step>OCA\DAV\Migration\RefreshWebcalJobRegistrar</step>
|
||||||
|
<step>OCA\DAV\Migration\RegisterBuildReminderIndexBackgroundJob</step>
|
||||||
<step>OCA\DAV\Migration\RemoveOrphanEventsAndContacts</step>
|
<step>OCA\DAV\Migration\RemoveOrphanEventsAndContacts</step>
|
||||||
<step>OCA\DAV\Migration\RemoveClassifiedEventActivity</step>
|
<step>OCA\DAV\Migration\RemoveClassifiedEventActivity</step>
|
||||||
</post-migration>
|
</post-migration>
|
||||||
|
@ -45,6 +47,7 @@
|
||||||
<command>OCA\DAV\Command\CreateCalendar</command>
|
<command>OCA\DAV\Command\CreateCalendar</command>
|
||||||
<command>OCA\DAV\Command\MoveCalendar</command>
|
<command>OCA\DAV\Command\MoveCalendar</command>
|
||||||
<command>OCA\DAV\Command\ListCalendars</command>
|
<command>OCA\DAV\Command\ListCalendars</command>
|
||||||
|
<command>OCA\DAV\Command\SendEventReminders</command>
|
||||||
<command>OCA\DAV\Command\SyncBirthdayCalendar</command>
|
<command>OCA\DAV\Command\SyncBirthdayCalendar</command>
|
||||||
<command>OCA\DAV\Command\SyncSystemAddressBook</command>
|
<command>OCA\DAV\Command\SyncSystemAddressBook</command>
|
||||||
<command>OCA\DAV\Command\RemoveInvalidShares</command>
|
<command>OCA\DAV\Command\RemoveInvalidShares</command>
|
||||||
|
|
|
@ -11,8 +11,10 @@ return array(
|
||||||
'OCA\\DAV\\Avatars\\AvatarHome' => $baseDir . '/../lib/Avatars/AvatarHome.php',
|
'OCA\\DAV\\Avatars\\AvatarHome' => $baseDir . '/../lib/Avatars/AvatarHome.php',
|
||||||
'OCA\\DAV\\Avatars\\AvatarNode' => $baseDir . '/../lib/Avatars/AvatarNode.php',
|
'OCA\\DAV\\Avatars\\AvatarNode' => $baseDir . '/../lib/Avatars/AvatarNode.php',
|
||||||
'OCA\\DAV\\Avatars\\RootCollection' => $baseDir . '/../lib/Avatars/RootCollection.php',
|
'OCA\\DAV\\Avatars\\RootCollection' => $baseDir . '/../lib/Avatars/RootCollection.php',
|
||||||
|
'OCA\\DAV\\BackgroundJob\\BuildReminderIndexBackgroundJob' => $baseDir . '/../lib/BackgroundJob/BuildReminderIndexBackgroundJob.php',
|
||||||
'OCA\\DAV\\BackgroundJob\\CleanupDirectLinksJob' => $baseDir . '/../lib/BackgroundJob/CleanupDirectLinksJob.php',
|
'OCA\\DAV\\BackgroundJob\\CleanupDirectLinksJob' => $baseDir . '/../lib/BackgroundJob/CleanupDirectLinksJob.php',
|
||||||
'OCA\\DAV\\BackgroundJob\\CleanupInvitationTokenJob' => $baseDir . '/../lib/BackgroundJob/CleanupInvitationTokenJob.php',
|
'OCA\\DAV\\BackgroundJob\\CleanupInvitationTokenJob' => $baseDir . '/../lib/BackgroundJob/CleanupInvitationTokenJob.php',
|
||||||
|
'OCA\\DAV\\BackgroundJob\\EventReminderJob' => $baseDir . '/../lib/BackgroundJob/EventReminderJob.php',
|
||||||
'OCA\\DAV\\BackgroundJob\\GenerateBirthdayCalendarBackgroundJob' => $baseDir . '/../lib/BackgroundJob/GenerateBirthdayCalendarBackgroundJob.php',
|
'OCA\\DAV\\BackgroundJob\\GenerateBirthdayCalendarBackgroundJob' => $baseDir . '/../lib/BackgroundJob/GenerateBirthdayCalendarBackgroundJob.php',
|
||||||
'OCA\\DAV\\BackgroundJob\\RefreshWebcalJob' => $baseDir . '/../lib/BackgroundJob/RefreshWebcalJob.php',
|
'OCA\\DAV\\BackgroundJob\\RefreshWebcalJob' => $baseDir . '/../lib/BackgroundJob/RefreshWebcalJob.php',
|
||||||
'OCA\\DAV\\BackgroundJob\\RegisterRegenerateBirthdayCalendars' => $baseDir . '/../lib/BackgroundJob/RegisterRegenerateBirthdayCalendars.php',
|
'OCA\\DAV\\BackgroundJob\\RegisterRegenerateBirthdayCalendars' => $baseDir . '/../lib/BackgroundJob/RegisterRegenerateBirthdayCalendars.php',
|
||||||
|
@ -51,6 +53,17 @@ return array(
|
||||||
'OCA\\DAV\\CalDAV\\PublicCalendarRoot' => $baseDir . '/../lib/CalDAV/PublicCalendarRoot.php',
|
'OCA\\DAV\\CalDAV\\PublicCalendarRoot' => $baseDir . '/../lib/CalDAV/PublicCalendarRoot.php',
|
||||||
'OCA\\DAV\\CalDAV\\Publishing\\PublishPlugin' => $baseDir . '/../lib/CalDAV/Publishing/PublishPlugin.php',
|
'OCA\\DAV\\CalDAV\\Publishing\\PublishPlugin' => $baseDir . '/../lib/CalDAV/Publishing/PublishPlugin.php',
|
||||||
'OCA\\DAV\\CalDAV\\Publishing\\Xml\\Publisher' => $baseDir . '/../lib/CalDAV/Publishing/Xml/Publisher.php',
|
'OCA\\DAV\\CalDAV\\Publishing\\Xml\\Publisher' => $baseDir . '/../lib/CalDAV/Publishing/Xml/Publisher.php',
|
||||||
|
'OCA\\DAV\\CalDAV\\Reminder\\Backend' => $baseDir . '/../lib/CalDAV/Reminder/Backend.php',
|
||||||
|
'OCA\\DAV\\CalDAV\\Reminder\\INotificationProvider' => $baseDir . '/../lib/CalDAV/Reminder/INotificationProvider.php',
|
||||||
|
'OCA\\DAV\\CalDAV\\Reminder\\NotificationProviderManager' => $baseDir . '/../lib/CalDAV/Reminder/NotificationProviderManager.php',
|
||||||
|
'OCA\\DAV\\CalDAV\\Reminder\\NotificationProvider\\AbstractProvider' => $baseDir . '/../lib/CalDAV/Reminder/NotificationProvider/AbstractProvider.php',
|
||||||
|
'OCA\\DAV\\CalDAV\\Reminder\\NotificationProvider\\AudioProvider' => $baseDir . '/../lib/CalDAV/Reminder/NotificationProvider/AudioProvider.php',
|
||||||
|
'OCA\\DAV\\CalDAV\\Reminder\\NotificationProvider\\EmailProvider' => $baseDir . '/../lib/CalDAV/Reminder/NotificationProvider/EmailProvider.php',
|
||||||
|
'OCA\\DAV\\CalDAV\\Reminder\\NotificationProvider\\ProviderNotAvailableException' => $baseDir . '/../lib/CalDAV/Reminder/NotificationProvider/ProviderNotAvailableException.php',
|
||||||
|
'OCA\\DAV\\CalDAV\\Reminder\\NotificationProvider\\PushProvider' => $baseDir . '/../lib/CalDAV/Reminder/NotificationProvider/PushProvider.php',
|
||||||
|
'OCA\\DAV\\CalDAV\\Reminder\\NotificationTypeDoesNotExistException' => $baseDir . '/../lib/CalDAV/Reminder/NotificationTypeDoesNotExistException.php',
|
||||||
|
'OCA\\DAV\\CalDAV\\Reminder\\Notifier' => $baseDir . '/../lib/CalDAV/Reminder/Notifier.php',
|
||||||
|
'OCA\\DAV\\CalDAV\\Reminder\\ReminderService' => $baseDir . '/../lib/CalDAV/Reminder/ReminderService.php',
|
||||||
'OCA\\DAV\\CalDAV\\ResourceBooking\\AbstractPrincipalBackend' => $baseDir . '/../lib/CalDAV/ResourceBooking/AbstractPrincipalBackend.php',
|
'OCA\\DAV\\CalDAV\\ResourceBooking\\AbstractPrincipalBackend' => $baseDir . '/../lib/CalDAV/ResourceBooking/AbstractPrincipalBackend.php',
|
||||||
'OCA\\DAV\\CalDAV\\ResourceBooking\\ResourcePrincipalBackend' => $baseDir . '/../lib/CalDAV/ResourceBooking/ResourcePrincipalBackend.php',
|
'OCA\\DAV\\CalDAV\\ResourceBooking\\ResourcePrincipalBackend' => $baseDir . '/../lib/CalDAV/ResourceBooking/ResourcePrincipalBackend.php',
|
||||||
'OCA\\DAV\\CalDAV\\ResourceBooking\\RoomPrincipalBackend' => $baseDir . '/../lib/CalDAV/ResourceBooking/RoomPrincipalBackend.php',
|
'OCA\\DAV\\CalDAV\\ResourceBooking\\RoomPrincipalBackend' => $baseDir . '/../lib/CalDAV/ResourceBooking/RoomPrincipalBackend.php',
|
||||||
|
@ -86,6 +99,7 @@ return array(
|
||||||
'OCA\\DAV\\Command\\ListCalendars' => $baseDir . '/../lib/Command/ListCalendars.php',
|
'OCA\\DAV\\Command\\ListCalendars' => $baseDir . '/../lib/Command/ListCalendars.php',
|
||||||
'OCA\\DAV\\Command\\MoveCalendar' => $baseDir . '/../lib/Command/MoveCalendar.php',
|
'OCA\\DAV\\Command\\MoveCalendar' => $baseDir . '/../lib/Command/MoveCalendar.php',
|
||||||
'OCA\\DAV\\Command\\RemoveInvalidShares' => $baseDir . '/../lib/Command/RemoveInvalidShares.php',
|
'OCA\\DAV\\Command\\RemoveInvalidShares' => $baseDir . '/../lib/Command/RemoveInvalidShares.php',
|
||||||
|
'OCA\\DAV\\Command\\SendEventReminders' => $baseDir . '/../lib/Command/SendEventReminders.php',
|
||||||
'OCA\\DAV\\Command\\SyncBirthdayCalendar' => $baseDir . '/../lib/Command/SyncBirthdayCalendar.php',
|
'OCA\\DAV\\Command\\SyncBirthdayCalendar' => $baseDir . '/../lib/Command/SyncBirthdayCalendar.php',
|
||||||
'OCA\\DAV\\Command\\SyncSystemAddressBook' => $baseDir . '/../lib/Command/SyncSystemAddressBook.php',
|
'OCA\\DAV\\Command\\SyncSystemAddressBook' => $baseDir . '/../lib/Command/SyncSystemAddressBook.php',
|
||||||
'OCA\\DAV\\Comments\\CommentNode' => $baseDir . '/../lib/Comments/CommentNode.php',
|
'OCA\\DAV\\Comments\\CommentNode' => $baseDir . '/../lib/Comments/CommentNode.php',
|
||||||
|
@ -166,6 +180,7 @@ return array(
|
||||||
'OCA\\DAV\\Migration\\FixBirthdayCalendarComponent' => $baseDir . '/../lib/Migration/FixBirthdayCalendarComponent.php',
|
'OCA\\DAV\\Migration\\FixBirthdayCalendarComponent' => $baseDir . '/../lib/Migration/FixBirthdayCalendarComponent.php',
|
||||||
'OCA\\DAV\\Migration\\RefreshWebcalJobRegistrar' => $baseDir . '/../lib/Migration/RefreshWebcalJobRegistrar.php',
|
'OCA\\DAV\\Migration\\RefreshWebcalJobRegistrar' => $baseDir . '/../lib/Migration/RefreshWebcalJobRegistrar.php',
|
||||||
'OCA\\DAV\\Migration\\RegenerateBirthdayCalendars' => $baseDir . '/../lib/Migration/RegenerateBirthdayCalendars.php',
|
'OCA\\DAV\\Migration\\RegenerateBirthdayCalendars' => $baseDir . '/../lib/Migration/RegenerateBirthdayCalendars.php',
|
||||||
|
'OCA\\DAV\\Migration\\RegisterBuildReminderIndexBackgroundJob' => $baseDir . '/../lib/Migration/RegisterBuildReminderIndexBackgroundJob.php',
|
||||||
'OCA\\DAV\\Migration\\RemoveClassifiedEventActivity' => $baseDir . '/../lib/Migration/RemoveClassifiedEventActivity.php',
|
'OCA\\DAV\\Migration\\RemoveClassifiedEventActivity' => $baseDir . '/../lib/Migration/RemoveClassifiedEventActivity.php',
|
||||||
'OCA\\DAV\\Migration\\RemoveOrphanEventsAndContacts' => $baseDir . '/../lib/Migration/RemoveOrphanEventsAndContacts.php',
|
'OCA\\DAV\\Migration\\RemoveOrphanEventsAndContacts' => $baseDir . '/../lib/Migration/RemoveOrphanEventsAndContacts.php',
|
||||||
'OCA\\DAV\\Migration\\Version1004Date20170825134824' => $baseDir . '/../lib/Migration/Version1004Date20170825134824.php',
|
'OCA\\DAV\\Migration\\Version1004Date20170825134824' => $baseDir . '/../lib/Migration/Version1004Date20170825134824.php',
|
||||||
|
@ -184,6 +199,7 @@ return array(
|
||||||
'OCA\\DAV\\Migration\\Version1008Date20181114084440' => $baseDir . '/../lib/Migration/Version1008Date20181114084440.php',
|
'OCA\\DAV\\Migration\\Version1008Date20181114084440' => $baseDir . '/../lib/Migration/Version1008Date20181114084440.php',
|
||||||
'OCA\\DAV\\Migration\\Version1011Date20190725113607' => $baseDir . '/../lib/Migration/Version1011Date20190725113607.php',
|
'OCA\\DAV\\Migration\\Version1011Date20190725113607' => $baseDir . '/../lib/Migration/Version1011Date20190725113607.php',
|
||||||
'OCA\\DAV\\Migration\\Version1011Date20190806104428' => $baseDir . '/../lib/Migration/Version1011Date20190806104428.php',
|
'OCA\\DAV\\Migration\\Version1011Date20190806104428' => $baseDir . '/../lib/Migration/Version1011Date20190806104428.php',
|
||||||
|
'OCA\\DAV\\Migration\\Version1012Date20190808122342' => $baseDir . '/../lib/Migration/Version1012Date20190808122342.php',
|
||||||
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningNode' => $baseDir . '/../lib/Provisioning/Apple/AppleProvisioningNode.php',
|
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningNode' => $baseDir . '/../lib/Provisioning/Apple/AppleProvisioningNode.php',
|
||||||
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningPlugin' => $baseDir . '/../lib/Provisioning/Apple/AppleProvisioningPlugin.php',
|
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningPlugin' => $baseDir . '/../lib/Provisioning/Apple/AppleProvisioningPlugin.php',
|
||||||
'OCA\\DAV\\RootCollection' => $baseDir . '/../lib/RootCollection.php',
|
'OCA\\DAV\\RootCollection' => $baseDir . '/../lib/RootCollection.php',
|
||||||
|
|
|
@ -26,8 +26,10 @@ class ComposerStaticInitDAV
|
||||||
'OCA\\DAV\\Avatars\\AvatarHome' => __DIR__ . '/..' . '/../lib/Avatars/AvatarHome.php',
|
'OCA\\DAV\\Avatars\\AvatarHome' => __DIR__ . '/..' . '/../lib/Avatars/AvatarHome.php',
|
||||||
'OCA\\DAV\\Avatars\\AvatarNode' => __DIR__ . '/..' . '/../lib/Avatars/AvatarNode.php',
|
'OCA\\DAV\\Avatars\\AvatarNode' => __DIR__ . '/..' . '/../lib/Avatars/AvatarNode.php',
|
||||||
'OCA\\DAV\\Avatars\\RootCollection' => __DIR__ . '/..' . '/../lib/Avatars/RootCollection.php',
|
'OCA\\DAV\\Avatars\\RootCollection' => __DIR__ . '/..' . '/../lib/Avatars/RootCollection.php',
|
||||||
|
'OCA\\DAV\\BackgroundJob\\BuildReminderIndexBackgroundJob' => __DIR__ . '/..' . '/../lib/BackgroundJob/BuildReminderIndexBackgroundJob.php',
|
||||||
'OCA\\DAV\\BackgroundJob\\CleanupDirectLinksJob' => __DIR__ . '/..' . '/../lib/BackgroundJob/CleanupDirectLinksJob.php',
|
'OCA\\DAV\\BackgroundJob\\CleanupDirectLinksJob' => __DIR__ . '/..' . '/../lib/BackgroundJob/CleanupDirectLinksJob.php',
|
||||||
'OCA\\DAV\\BackgroundJob\\CleanupInvitationTokenJob' => __DIR__ . '/..' . '/../lib/BackgroundJob/CleanupInvitationTokenJob.php',
|
'OCA\\DAV\\BackgroundJob\\CleanupInvitationTokenJob' => __DIR__ . '/..' . '/../lib/BackgroundJob/CleanupInvitationTokenJob.php',
|
||||||
|
'OCA\\DAV\\BackgroundJob\\EventReminderJob' => __DIR__ . '/..' . '/../lib/BackgroundJob/EventReminderJob.php',
|
||||||
'OCA\\DAV\\BackgroundJob\\GenerateBirthdayCalendarBackgroundJob' => __DIR__ . '/..' . '/../lib/BackgroundJob/GenerateBirthdayCalendarBackgroundJob.php',
|
'OCA\\DAV\\BackgroundJob\\GenerateBirthdayCalendarBackgroundJob' => __DIR__ . '/..' . '/../lib/BackgroundJob/GenerateBirthdayCalendarBackgroundJob.php',
|
||||||
'OCA\\DAV\\BackgroundJob\\RefreshWebcalJob' => __DIR__ . '/..' . '/../lib/BackgroundJob/RefreshWebcalJob.php',
|
'OCA\\DAV\\BackgroundJob\\RefreshWebcalJob' => __DIR__ . '/..' . '/../lib/BackgroundJob/RefreshWebcalJob.php',
|
||||||
'OCA\\DAV\\BackgroundJob\\RegisterRegenerateBirthdayCalendars' => __DIR__ . '/..' . '/../lib/BackgroundJob/RegisterRegenerateBirthdayCalendars.php',
|
'OCA\\DAV\\BackgroundJob\\RegisterRegenerateBirthdayCalendars' => __DIR__ . '/..' . '/../lib/BackgroundJob/RegisterRegenerateBirthdayCalendars.php',
|
||||||
|
@ -66,6 +68,17 @@ class ComposerStaticInitDAV
|
||||||
'OCA\\DAV\\CalDAV\\PublicCalendarRoot' => __DIR__ . '/..' . '/../lib/CalDAV/PublicCalendarRoot.php',
|
'OCA\\DAV\\CalDAV\\PublicCalendarRoot' => __DIR__ . '/..' . '/../lib/CalDAV/PublicCalendarRoot.php',
|
||||||
'OCA\\DAV\\CalDAV\\Publishing\\PublishPlugin' => __DIR__ . '/..' . '/../lib/CalDAV/Publishing/PublishPlugin.php',
|
'OCA\\DAV\\CalDAV\\Publishing\\PublishPlugin' => __DIR__ . '/..' . '/../lib/CalDAV/Publishing/PublishPlugin.php',
|
||||||
'OCA\\DAV\\CalDAV\\Publishing\\Xml\\Publisher' => __DIR__ . '/..' . '/../lib/CalDAV/Publishing/Xml/Publisher.php',
|
'OCA\\DAV\\CalDAV\\Publishing\\Xml\\Publisher' => __DIR__ . '/..' . '/../lib/CalDAV/Publishing/Xml/Publisher.php',
|
||||||
|
'OCA\\DAV\\CalDAV\\Reminder\\Backend' => __DIR__ . '/..' . '/../lib/CalDAV/Reminder/Backend.php',
|
||||||
|
'OCA\\DAV\\CalDAV\\Reminder\\INotificationProvider' => __DIR__ . '/..' . '/../lib/CalDAV/Reminder/INotificationProvider.php',
|
||||||
|
'OCA\\DAV\\CalDAV\\Reminder\\NotificationProviderManager' => __DIR__ . '/..' . '/../lib/CalDAV/Reminder/NotificationProviderManager.php',
|
||||||
|
'OCA\\DAV\\CalDAV\\Reminder\\NotificationProvider\\AbstractProvider' => __DIR__ . '/..' . '/../lib/CalDAV/Reminder/NotificationProvider/AbstractProvider.php',
|
||||||
|
'OCA\\DAV\\CalDAV\\Reminder\\NotificationProvider\\AudioProvider' => __DIR__ . '/..' . '/../lib/CalDAV/Reminder/NotificationProvider/AudioProvider.php',
|
||||||
|
'OCA\\DAV\\CalDAV\\Reminder\\NotificationProvider\\EmailProvider' => __DIR__ . '/..' . '/../lib/CalDAV/Reminder/NotificationProvider/EmailProvider.php',
|
||||||
|
'OCA\\DAV\\CalDAV\\Reminder\\NotificationProvider\\ProviderNotAvailableException' => __DIR__ . '/..' . '/../lib/CalDAV/Reminder/NotificationProvider/ProviderNotAvailableException.php',
|
||||||
|
'OCA\\DAV\\CalDAV\\Reminder\\NotificationProvider\\PushProvider' => __DIR__ . '/..' . '/../lib/CalDAV/Reminder/NotificationProvider/PushProvider.php',
|
||||||
|
'OCA\\DAV\\CalDAV\\Reminder\\NotificationTypeDoesNotExistException' => __DIR__ . '/..' . '/../lib/CalDAV/Reminder/NotificationTypeDoesNotExistException.php',
|
||||||
|
'OCA\\DAV\\CalDAV\\Reminder\\Notifier' => __DIR__ . '/..' . '/../lib/CalDAV/Reminder/Notifier.php',
|
||||||
|
'OCA\\DAV\\CalDAV\\Reminder\\ReminderService' => __DIR__ . '/..' . '/../lib/CalDAV/Reminder/ReminderService.php',
|
||||||
'OCA\\DAV\\CalDAV\\ResourceBooking\\AbstractPrincipalBackend' => __DIR__ . '/..' . '/../lib/CalDAV/ResourceBooking/AbstractPrincipalBackend.php',
|
'OCA\\DAV\\CalDAV\\ResourceBooking\\AbstractPrincipalBackend' => __DIR__ . '/..' . '/../lib/CalDAV/ResourceBooking/AbstractPrincipalBackend.php',
|
||||||
'OCA\\DAV\\CalDAV\\ResourceBooking\\ResourcePrincipalBackend' => __DIR__ . '/..' . '/../lib/CalDAV/ResourceBooking/ResourcePrincipalBackend.php',
|
'OCA\\DAV\\CalDAV\\ResourceBooking\\ResourcePrincipalBackend' => __DIR__ . '/..' . '/../lib/CalDAV/ResourceBooking/ResourcePrincipalBackend.php',
|
||||||
'OCA\\DAV\\CalDAV\\ResourceBooking\\RoomPrincipalBackend' => __DIR__ . '/..' . '/../lib/CalDAV/ResourceBooking/RoomPrincipalBackend.php',
|
'OCA\\DAV\\CalDAV\\ResourceBooking\\RoomPrincipalBackend' => __DIR__ . '/..' . '/../lib/CalDAV/ResourceBooking/RoomPrincipalBackend.php',
|
||||||
|
@ -101,6 +114,7 @@ class ComposerStaticInitDAV
|
||||||
'OCA\\DAV\\Command\\ListCalendars' => __DIR__ . '/..' . '/../lib/Command/ListCalendars.php',
|
'OCA\\DAV\\Command\\ListCalendars' => __DIR__ . '/..' . '/../lib/Command/ListCalendars.php',
|
||||||
'OCA\\DAV\\Command\\MoveCalendar' => __DIR__ . '/..' . '/../lib/Command/MoveCalendar.php',
|
'OCA\\DAV\\Command\\MoveCalendar' => __DIR__ . '/..' . '/../lib/Command/MoveCalendar.php',
|
||||||
'OCA\\DAV\\Command\\RemoveInvalidShares' => __DIR__ . '/..' . '/../lib/Command/RemoveInvalidShares.php',
|
'OCA\\DAV\\Command\\RemoveInvalidShares' => __DIR__ . '/..' . '/../lib/Command/RemoveInvalidShares.php',
|
||||||
|
'OCA\\DAV\\Command\\SendEventReminders' => __DIR__ . '/..' . '/../lib/Command/SendEventReminders.php',
|
||||||
'OCA\\DAV\\Command\\SyncBirthdayCalendar' => __DIR__ . '/..' . '/../lib/Command/SyncBirthdayCalendar.php',
|
'OCA\\DAV\\Command\\SyncBirthdayCalendar' => __DIR__ . '/..' . '/../lib/Command/SyncBirthdayCalendar.php',
|
||||||
'OCA\\DAV\\Command\\SyncSystemAddressBook' => __DIR__ . '/..' . '/../lib/Command/SyncSystemAddressBook.php',
|
'OCA\\DAV\\Command\\SyncSystemAddressBook' => __DIR__ . '/..' . '/../lib/Command/SyncSystemAddressBook.php',
|
||||||
'OCA\\DAV\\Comments\\CommentNode' => __DIR__ . '/..' . '/../lib/Comments/CommentNode.php',
|
'OCA\\DAV\\Comments\\CommentNode' => __DIR__ . '/..' . '/../lib/Comments/CommentNode.php',
|
||||||
|
@ -181,6 +195,7 @@ class ComposerStaticInitDAV
|
||||||
'OCA\\DAV\\Migration\\FixBirthdayCalendarComponent' => __DIR__ . '/..' . '/../lib/Migration/FixBirthdayCalendarComponent.php',
|
'OCA\\DAV\\Migration\\FixBirthdayCalendarComponent' => __DIR__ . '/..' . '/../lib/Migration/FixBirthdayCalendarComponent.php',
|
||||||
'OCA\\DAV\\Migration\\RefreshWebcalJobRegistrar' => __DIR__ . '/..' . '/../lib/Migration/RefreshWebcalJobRegistrar.php',
|
'OCA\\DAV\\Migration\\RefreshWebcalJobRegistrar' => __DIR__ . '/..' . '/../lib/Migration/RefreshWebcalJobRegistrar.php',
|
||||||
'OCA\\DAV\\Migration\\RegenerateBirthdayCalendars' => __DIR__ . '/..' . '/../lib/Migration/RegenerateBirthdayCalendars.php',
|
'OCA\\DAV\\Migration\\RegenerateBirthdayCalendars' => __DIR__ . '/..' . '/../lib/Migration/RegenerateBirthdayCalendars.php',
|
||||||
|
'OCA\\DAV\\Migration\\RegisterBuildReminderIndexBackgroundJob' => __DIR__ . '/..' . '/../lib/Migration/RegisterBuildReminderIndexBackgroundJob.php',
|
||||||
'OCA\\DAV\\Migration\\RemoveClassifiedEventActivity' => __DIR__ . '/..' . '/../lib/Migration/RemoveClassifiedEventActivity.php',
|
'OCA\\DAV\\Migration\\RemoveClassifiedEventActivity' => __DIR__ . '/..' . '/../lib/Migration/RemoveClassifiedEventActivity.php',
|
||||||
'OCA\\DAV\\Migration\\RemoveOrphanEventsAndContacts' => __DIR__ . '/..' . '/../lib/Migration/RemoveOrphanEventsAndContacts.php',
|
'OCA\\DAV\\Migration\\RemoveOrphanEventsAndContacts' => __DIR__ . '/..' . '/../lib/Migration/RemoveOrphanEventsAndContacts.php',
|
||||||
'OCA\\DAV\\Migration\\Version1004Date20170825134824' => __DIR__ . '/..' . '/../lib/Migration/Version1004Date20170825134824.php',
|
'OCA\\DAV\\Migration\\Version1004Date20170825134824' => __DIR__ . '/..' . '/../lib/Migration/Version1004Date20170825134824.php',
|
||||||
|
@ -199,6 +214,7 @@ class ComposerStaticInitDAV
|
||||||
'OCA\\DAV\\Migration\\Version1008Date20181114084440' => __DIR__ . '/..' . '/../lib/Migration/Version1008Date20181114084440.php',
|
'OCA\\DAV\\Migration\\Version1008Date20181114084440' => __DIR__ . '/..' . '/../lib/Migration/Version1008Date20181114084440.php',
|
||||||
'OCA\\DAV\\Migration\\Version1011Date20190725113607' => __DIR__ . '/..' . '/../lib/Migration/Version1011Date20190725113607.php',
|
'OCA\\DAV\\Migration\\Version1011Date20190725113607' => __DIR__ . '/..' . '/../lib/Migration/Version1011Date20190725113607.php',
|
||||||
'OCA\\DAV\\Migration\\Version1011Date20190806104428' => __DIR__ . '/..' . '/../lib/Migration/Version1011Date20190806104428.php',
|
'OCA\\DAV\\Migration\\Version1011Date20190806104428' => __DIR__ . '/..' . '/../lib/Migration/Version1011Date20190806104428.php',
|
||||||
|
'OCA\\DAV\\Migration\\Version1012Date20190808122342' => __DIR__ . '/..' . '/../lib/Migration/Version1012Date20190808122342.php',
|
||||||
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningNode' => __DIR__ . '/..' . '/../lib/Provisioning/Apple/AppleProvisioningNode.php',
|
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningNode' => __DIR__ . '/..' . '/../lib/Provisioning/Apple/AppleProvisioningNode.php',
|
||||||
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningPlugin' => __DIR__ . '/..' . '/../lib/Provisioning/Apple/AppleProvisioningPlugin.php',
|
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningPlugin' => __DIR__ . '/..' . '/../lib/Provisioning/Apple/AppleProvisioningPlugin.php',
|
||||||
'OCA\\DAV\\RootCollection' => __DIR__ . '/..' . '/../lib/RootCollection.php',
|
'OCA\\DAV\\RootCollection' => __DIR__ . '/..' . '/../lib/RootCollection.php',
|
||||||
|
|
|
@ -36,3 +36,9 @@ $('#caldavGenerateBirthdayCalendar').change(function() {
|
||||||
$.post(OC.generateUrl('/apps/dav/disableBirthdayCalendar'));
|
$.post(OC.generateUrl('/apps/dav/disableBirthdayCalendar'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#caldavSendRemindersNotifications').change(function() {
|
||||||
|
var val = $(this)[0].checked;
|
||||||
|
|
||||||
|
OCP.AppConfig.setValue('dav', 'sendEventReminders', val ? 'yes' : 'no');
|
||||||
|
});
|
||||||
|
|
|
@ -30,6 +30,13 @@ use OCA\DAV\CalDAV\Activity\Backend;
|
||||||
use OCA\DAV\CalDAV\Activity\Provider\Event;
|
use OCA\DAV\CalDAV\Activity\Provider\Event;
|
||||||
use OCA\DAV\CalDAV\BirthdayService;
|
use OCA\DAV\CalDAV\BirthdayService;
|
||||||
use OCA\DAV\CalDAV\CalendarManager;
|
use OCA\DAV\CalDAV\CalendarManager;
|
||||||
|
use OCA\DAV\CalDAV\Reminder\Backend as ReminderBackend;
|
||||||
|
use OCA\DAV\CalDAV\Reminder\NotificationProvider\AudioProvider;
|
||||||
|
use OCA\DAV\CalDAV\Reminder\NotificationProvider\EmailProvider;
|
||||||
|
use OCA\DAV\CalDAV\Reminder\NotificationProvider\PushProvider;
|
||||||
|
use OCA\DAV\CalDAV\Reminder\NotificationProviderManager;
|
||||||
|
use OCA\DAV\CalDAV\Reminder\Notifier;
|
||||||
|
use OCA\DAV\CalDAV\Reminder\ReminderService;
|
||||||
use OCA\DAV\Capabilities;
|
use OCA\DAV\Capabilities;
|
||||||
use OCA\DAV\CardDAV\ContactsManager;
|
use OCA\DAV\CardDAV\ContactsManager;
|
||||||
use OCA\DAV\CardDAV\PhotoCache;
|
use OCA\DAV\CardDAV\PhotoCache;
|
||||||
|
@ -43,6 +50,8 @@ use Symfony\Component\EventDispatcher\GenericEvent;
|
||||||
|
|
||||||
class Application extends App {
|
class Application extends App {
|
||||||
|
|
||||||
|
const APP_ID = 'dav';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Application constructor.
|
* Application constructor.
|
||||||
*/
|
*/
|
||||||
|
@ -109,8 +118,7 @@ class Application extends App {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// carddav/caldav sync event setup
|
$birthdayListener = function ($event) {
|
||||||
$listener = function($event) {
|
|
||||||
if ($event instanceof GenericEvent) {
|
if ($event instanceof GenericEvent) {
|
||||||
/** @var BirthdayService $b */
|
/** @var BirthdayService $b */
|
||||||
$b = $this->getContainer()->query(BirthdayService::class);
|
$b = $this->getContainer()->query(BirthdayService::class);
|
||||||
|
@ -122,9 +130,9 @@ class Application extends App {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$dispatcher->addListener('\OCA\DAV\CardDAV\CardDavBackend::createCard', $listener);
|
$dispatcher->addListener('\OCA\DAV\CardDAV\CardDavBackend::createCard', $birthdayListener);
|
||||||
$dispatcher->addListener('\OCA\DAV\CardDAV\CardDavBackend::updateCard', $listener);
|
$dispatcher->addListener('\OCA\DAV\CardDAV\CardDavBackend::updateCard', $birthdayListener);
|
||||||
$dispatcher->addListener('\OCA\DAV\CardDAV\CardDavBackend::deleteCard', function($event) {
|
$dispatcher->addListener('\OCA\DAV\CardDAV\CardDavBackend::deleteCard', function ($event) {
|
||||||
if ($event instanceof GenericEvent) {
|
if ($event instanceof GenericEvent) {
|
||||||
/** @var BirthdayService $b */
|
/** @var BirthdayService $b */
|
||||||
$b = $this->getContainer()->query(BirthdayService::class);
|
$b = $this->getContainer()->query(BirthdayService::class);
|
||||||
|
@ -177,6 +185,11 @@ class Application extends App {
|
||||||
$event->getArgument('calendarData'),
|
$event->getArgument('calendarData'),
|
||||||
$event->getArgument('shares')
|
$event->getArgument('shares')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$reminderBackend = $this->getContainer()->query(ReminderBackend::class);
|
||||||
|
$reminderBackend->cleanRemindersForCalendar(
|
||||||
|
$event->getArgument('calendarId')
|
||||||
|
);
|
||||||
});
|
});
|
||||||
$dispatcher->addListener('\OCA\DAV\CalDAV\CalDavBackend::updateShares', function(GenericEvent $event) {
|
$dispatcher->addListener('\OCA\DAV\CalDAV\CalDavBackend::updateShares', function(GenericEvent $event) {
|
||||||
/** @var Backend $backend */
|
/** @var Backend $backend */
|
||||||
|
@ -187,6 +200,8 @@ class Application extends App {
|
||||||
$event->getArgument('add'),
|
$event->getArgument('add'),
|
||||||
$event->getArgument('remove')
|
$event->getArgument('remove')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Here we should recalculate if reminders should be sent to new or old sharees
|
||||||
});
|
});
|
||||||
|
|
||||||
$dispatcher->addListener('\OCA\DAV\CalDAV\CalDavBackend::publishCalendar', function(GenericEvent $event) {
|
$dispatcher->addListener('\OCA\DAV\CalDAV\CalDavBackend::publishCalendar', function(GenericEvent $event) {
|
||||||
|
@ -214,6 +229,14 @@ class Application extends App {
|
||||||
$event->getArgument('shares'),
|
$event->getArgument('shares'),
|
||||||
$event->getArgument('objectData')
|
$event->getArgument('objectData')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/** @var ReminderService $reminderBackend */
|
||||||
|
$reminderService = $this->getContainer()->query(ReminderService::class);
|
||||||
|
|
||||||
|
$reminderService->onTouchCalendarObject(
|
||||||
|
$eventName,
|
||||||
|
$event->getArgument('objectData')
|
||||||
|
);
|
||||||
};
|
};
|
||||||
$dispatcher->addListener('\OCA\DAV\CalDAV\CalDavBackend::createCalendarObject', $listener);
|
$dispatcher->addListener('\OCA\DAV\CalDAV\CalDavBackend::createCalendarObject', $listener);
|
||||||
$dispatcher->addListener('\OCA\DAV\CalDAV\CalDavBackend::updateCalendarObject', $listener);
|
$dispatcher->addListener('\OCA\DAV\CalDAV\CalDavBackend::updateCalendarObject', $listener);
|
||||||
|
@ -224,4 +247,23 @@ class Application extends App {
|
||||||
return $this->getContainer()->query(SyncService::class);
|
return $this->getContainer()->query(SyncService::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function registerNotifier():void {
|
||||||
|
$this->getContainer()
|
||||||
|
->getServer()
|
||||||
|
->getNotificationManager()
|
||||||
|
->registerNotifierService(Notifier::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function registerCalendarReminders():void {
|
||||||
|
try {
|
||||||
|
/** @var NotificationProviderManager $notificationProviderManager */
|
||||||
|
$notificationProviderManager = $this->getContainer()->query(NotificationProviderManager::class);
|
||||||
|
$notificationProviderManager->registerProvider(AudioProvider::class);
|
||||||
|
$notificationProviderManager->registerProvider(EmailProvider::class);
|
||||||
|
$notificationProviderManager->registerProvider(PushProvider::class);
|
||||||
|
} catch(\Exception $ex) {
|
||||||
|
$this->getContainer()->getServer()->getLogger()->logException($ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* @copyright 2019 Georg Ehrke <oc.list@georgehrke.com>
|
||||||
|
*
|
||||||
|
* @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\BackgroundJob;
|
||||||
|
|
||||||
|
use OCP\BackgroundJob\QueuedJob;
|
||||||
|
use OCA\DAV\CalDAV\Reminder\ReminderService;
|
||||||
|
use OCP\AppFramework\Utility\ITimeFactory;
|
||||||
|
use OCP\BackgroundJob\IJobList;
|
||||||
|
use OCP\IDBConnection;
|
||||||
|
use OCP\ILogger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class BuildReminderIndexBackgroundJob
|
||||||
|
*
|
||||||
|
* @package OCA\DAV\BackgroundJob
|
||||||
|
*/
|
||||||
|
class BuildReminderIndexBackgroundJob extends QueuedJob {
|
||||||
|
|
||||||
|
/** @var IDBConnection */
|
||||||
|
private $db;
|
||||||
|
|
||||||
|
/** @var ReminderService */
|
||||||
|
private $reminderService;
|
||||||
|
|
||||||
|
/** @var ILogger */
|
||||||
|
private $logger;
|
||||||
|
|
||||||
|
/** @var IJobList */
|
||||||
|
private $jobList;
|
||||||
|
|
||||||
|
/** @var ITimeFactory */
|
||||||
|
private $timeFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BuildReminderIndexBackgroundJob constructor.
|
||||||
|
*
|
||||||
|
* @param IDBConnection $db
|
||||||
|
* @param ReminderService $reminderService
|
||||||
|
* @param ILogger $logger
|
||||||
|
* @param IJobList $jobList
|
||||||
|
* @param ITimeFactory $timeFactory
|
||||||
|
*/
|
||||||
|
public function __construct(IDBConnection $db,
|
||||||
|
ReminderService $reminderService,
|
||||||
|
ILogger $logger,
|
||||||
|
IJobList $jobList,
|
||||||
|
ITimeFactory $timeFactory) {
|
||||||
|
$this->db = $db;
|
||||||
|
$this->reminderService = $reminderService;
|
||||||
|
$this->logger = $logger;
|
||||||
|
$this->jobList = $jobList;
|
||||||
|
$this->timeFactory = $timeFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $arguments
|
||||||
|
*/
|
||||||
|
public function run($arguments) {
|
||||||
|
$offset = (int) $arguments['offset'];
|
||||||
|
$stopAt = (int) $arguments['stopAt'];
|
||||||
|
|
||||||
|
$this->logger->info('Building calendar reminder index (' . $offset .'/' . $stopAt . ')');
|
||||||
|
|
||||||
|
$offset = $this->buildIndex($offset, $stopAt);
|
||||||
|
|
||||||
|
if ($offset >= $stopAt) {
|
||||||
|
$this->logger->info('Building calendar reminder index done');
|
||||||
|
} else {
|
||||||
|
$this->jobList->add(self::class, [
|
||||||
|
'offset' => $offset,
|
||||||
|
'stopAt' => $stopAt
|
||||||
|
]);
|
||||||
|
$this->logger->info('Scheduled a new BuildReminderIndexBackgroundJob with offset ' . $offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $offset
|
||||||
|
* @param int $stopAt
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
private function buildIndex(int $offset, int $stopAt):int {
|
||||||
|
$startTime = $this->timeFactory->getTime();
|
||||||
|
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$query->select('*')
|
||||||
|
->from('calendarobjects')
|
||||||
|
->where($query->expr()->lte('id', $query->createNamedParameter($stopAt)))
|
||||||
|
->andWhere($query->expr()->gt('id', $query->createNamedParameter($offset)))
|
||||||
|
->orderBy('id', 'ASC');
|
||||||
|
|
||||||
|
$stmt = $query->execute();
|
||||||
|
while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||||
|
$offset = $row['id'];
|
||||||
|
if (is_resource($row['calendardata'])) {
|
||||||
|
$row['calendardata'] = stream_get_contents($row['calendardata']);
|
||||||
|
}
|
||||||
|
$row['component'] = $row['componenttype'];
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->reminderService->onTouchCalendarObject('\OCA\DAV\CalDAV\CalDavBackend::createCalendarObject', $row);
|
||||||
|
} catch(\Exception $ex) {
|
||||||
|
$this->logger->logException($ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($this->timeFactory->getTime() - $startTime) > 15) {
|
||||||
|
return $offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $stopAt;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Thomas Citharel <tcit@tcit.fr>
|
||||||
|
*
|
||||||
|
* @license AGPL-3.0
|
||||||
|
*
|
||||||
|
* This code is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* 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, version 3,
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace OCA\DAV\BackgroundJob;
|
||||||
|
|
||||||
|
use OC\BackgroundJob\TimedJob;
|
||||||
|
use OCA\DAV\CalDAV\Reminder\ReminderService;
|
||||||
|
use OCP\IConfig;
|
||||||
|
|
||||||
|
class EventReminderJob extends TimedJob {
|
||||||
|
|
||||||
|
/** @var ReminderService */
|
||||||
|
private $reminderService;
|
||||||
|
|
||||||
|
/** @var IConfig */
|
||||||
|
private $config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EventReminderJob constructor.
|
||||||
|
*
|
||||||
|
* @param ReminderService $reminderService
|
||||||
|
* @param IConfig $config
|
||||||
|
*/
|
||||||
|
public function __construct(ReminderService $reminderService, IConfig $config) {
|
||||||
|
$this->reminderService = $reminderService;
|
||||||
|
$this->config = $config;
|
||||||
|
/** Run every 5 minutes */
|
||||||
|
$this->setInterval(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $arg
|
||||||
|
* @throws \OCA\DAV\CalDAV\Reminder\NotificationProvider\ProviderNotAvailableException
|
||||||
|
* @throws \OCA\DAV\CalDAV\Reminder\NotificationTypeDoesNotExistException
|
||||||
|
* @throws \OC\User\NoUserException
|
||||||
|
*/
|
||||||
|
public function run($arg):void {
|
||||||
|
if ($this->config->getAppValue('dav', 'sendEventReminders', 'yes') !== 'yes') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->config->getAppValue('dav', 'sendEventRemindersMode', 'backgroundjob') !== 'backgroundjob') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->reminderService->processReminders();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1135,7 +1135,6 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
|
||||||
*/
|
*/
|
||||||
function updateCalendarObject($calendarId, $objectUri, $calendarData, $calendarType=self::CALENDAR_TYPE_CALENDAR) {
|
function updateCalendarObject($calendarId, $objectUri, $calendarData, $calendarType=self::CALENDAR_TYPE_CALENDAR) {
|
||||||
$extraData = $this->getDenormalizedData($calendarData);
|
$extraData = $this->getDenormalizedData($calendarData);
|
||||||
|
|
||||||
$query = $this->db->getQueryBuilder();
|
$query = $this->db->getQueryBuilder();
|
||||||
$query->update('calendarobjects')
|
$query->update('calendarobjects')
|
||||||
->set('calendardata', $query->createNamedParameter($calendarData, IQueryBuilder::PARAM_LOB))
|
->set('calendardata', $query->createNamedParameter($calendarData, IQueryBuilder::PARAM_LOB))
|
||||||
|
|
|
@ -0,0 +1,219 @@
|
||||||
|
<?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;
|
||||||
|
|
||||||
|
use OCP\IDBConnection;
|
||||||
|
use OCP\AppFramework\Utility\ITimeFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Backend
|
||||||
|
*
|
||||||
|
* @package OCA\DAV\CalDAV\Reminder
|
||||||
|
*/
|
||||||
|
class Backend {
|
||||||
|
|
||||||
|
/** @var IDBConnection */
|
||||||
|
protected $db;
|
||||||
|
|
||||||
|
/** @var ITimeFactory */
|
||||||
|
private $timeFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backend constructor.
|
||||||
|
*
|
||||||
|
* @param IDBConnection $db
|
||||||
|
* @param ITimeFactory $timeFactory
|
||||||
|
*/
|
||||||
|
public function __construct(IDBConnection $db,
|
||||||
|
ITimeFactory $timeFactory) {
|
||||||
|
$this->db = $db;
|
||||||
|
$this->timeFactory = $timeFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all reminders with a notification date before now
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function getRemindersToProcess():array {
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$query->select(['cr.*', 'co.calendardata', 'c.displayname', 'c.principaluri'])
|
||||||
|
->from('calendar_reminders', 'cr')
|
||||||
|
->where($query->expr()->lte('cr.notification_date', $query->createNamedParameter($this->timeFactory->getTime())))
|
||||||
|
->leftJoin('cr', 'calendarobjects', 'co', $query->expr()->eq('cr.object_id', 'co.id'))
|
||||||
|
->leftJoin('cr', 'calendars', 'c', $query->expr()->eq('cr.calendar_id', 'c.id'));
|
||||||
|
$stmt = $query->execute();
|
||||||
|
|
||||||
|
return array_map(
|
||||||
|
[$this, 'fixRowTyping'],
|
||||||
|
$stmt->fetchAll()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all scheduled reminders for an event
|
||||||
|
*
|
||||||
|
* @param int $objectId
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAllScheduledRemindersForEvent(int $objectId):array {
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$query->select('*')
|
||||||
|
->from('calendar_reminders')
|
||||||
|
->where($query->expr()->eq('object_id', $query->createNamedParameter($objectId)));
|
||||||
|
$stmt = $query->execute();
|
||||||
|
|
||||||
|
return array_map(
|
||||||
|
[$this, 'fixRowTyping'],
|
||||||
|
$stmt->fetchAll()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a new reminder into the database
|
||||||
|
*
|
||||||
|
* @param int $calendarId
|
||||||
|
* @param int $objectId
|
||||||
|
* @param string $uid
|
||||||
|
* @param bool $isRecurring
|
||||||
|
* @param int $recurrenceId
|
||||||
|
* @param bool $isRecurrenceException
|
||||||
|
* @param string $eventHash
|
||||||
|
* @param string $alarmHash
|
||||||
|
* @param string $type
|
||||||
|
* @param bool $isRelative
|
||||||
|
* @param int $notificationDate
|
||||||
|
* @param bool $isRepeatBased
|
||||||
|
* @return int The insert id
|
||||||
|
*/
|
||||||
|
public function insertReminder(int $calendarId,
|
||||||
|
int $objectId,
|
||||||
|
string $uid,
|
||||||
|
bool $isRecurring,
|
||||||
|
int $recurrenceId,
|
||||||
|
bool $isRecurrenceException,
|
||||||
|
string $eventHash,
|
||||||
|
string $alarmHash,
|
||||||
|
string $type,
|
||||||
|
bool $isRelative,
|
||||||
|
int $notificationDate,
|
||||||
|
bool $isRepeatBased):int {
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$query->insert('calendar_reminders')
|
||||||
|
->values([
|
||||||
|
'calendar_id' => $query->createNamedParameter($calendarId),
|
||||||
|
'object_id' => $query->createNamedParameter($objectId),
|
||||||
|
'uid' => $query->createNamedParameter($uid),
|
||||||
|
'is_recurring' => $query->createNamedParameter($isRecurring ? 1 : 0),
|
||||||
|
'recurrence_id' => $query->createNamedParameter($recurrenceId),
|
||||||
|
'is_recurrence_exception' => $query->createNamedParameter($isRecurrenceException ? 1 : 0),
|
||||||
|
'event_hash' => $query->createNamedParameter($eventHash),
|
||||||
|
'alarm_hash' => $query->createNamedParameter($alarmHash),
|
||||||
|
'type' => $query->createNamedParameter($type),
|
||||||
|
'is_relative' => $query->createNamedParameter($isRelative ? 1 : 0),
|
||||||
|
'notification_date' => $query->createNamedParameter($notificationDate),
|
||||||
|
'is_repeat_based' => $query->createNamedParameter($isRepeatBased ? 1 : 0),
|
||||||
|
])
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
return $query->getLastInsertId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a new notificationDate on an existing reminder
|
||||||
|
*
|
||||||
|
* @param int $reminderId
|
||||||
|
* @param int $newNotificationDate
|
||||||
|
*/
|
||||||
|
public function updateReminder(int $reminderId,
|
||||||
|
int $newNotificationDate):void {
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$query->update('calendar_reminders')
|
||||||
|
->set('notification_date', $query->createNamedParameter($newNotificationDate))
|
||||||
|
->where($query->expr()->eq('id', $query->createNamedParameter($reminderId)))
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a reminder by it's id
|
||||||
|
*
|
||||||
|
* @param integer $reminderId
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function removeReminder(int $reminderId):void {
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
|
||||||
|
$query->delete('calendar_reminders')
|
||||||
|
->where($query->expr()->eq('id', $query->createNamedParameter($reminderId)))
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans reminders in database
|
||||||
|
*
|
||||||
|
* @param int $objectId
|
||||||
|
*/
|
||||||
|
public function cleanRemindersForEvent(int $objectId):void {
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
|
||||||
|
$query->delete('calendar_reminders')
|
||||||
|
->where($query->expr()->eq('object_id', $query->createNamedParameter($objectId)))
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all reminders for a calendar
|
||||||
|
*
|
||||||
|
* @param int $calendarId
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function cleanRemindersForCalendar(int $calendarId):void {
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
|
||||||
|
$query->delete('calendar_reminders')
|
||||||
|
->where($query->expr()->eq('calendar_id', $query->createNamedParameter($calendarId)))
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $row
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function fixRowTyping(array $row): array {
|
||||||
|
$row['id'] = (int) $row['id'];
|
||||||
|
$row['calendar_id'] = (int) $row['calendar_id'];
|
||||||
|
$row['object_id'] = (int) $row['object_id'];
|
||||||
|
$row['is_recurring'] = (bool) $row['is_recurring'];
|
||||||
|
$row['recurrence_id'] = (int) $row['recurrence_id'];
|
||||||
|
$row['is_recurrence_exception'] = (bool) $row['is_recurrence_exception'];
|
||||||
|
$row['is_relative'] = (bool) $row['is_relative'];
|
||||||
|
$row['notification_date'] = (int) $row['notification_date'];
|
||||||
|
$row['is_repeat_based'] = (bool) $row['is_repeat_based'];
|
||||||
|
|
||||||
|
return $row;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2019, Georg Ehrke
|
||||||
|
*
|
||||||
|
* @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;
|
||||||
|
|
||||||
|
use OCP\IUser;
|
||||||
|
use Sabre\VObject\Component\VEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface INotificationProvider
|
||||||
|
*
|
||||||
|
* @package OCA\DAV\CalDAV\Reminder
|
||||||
|
*/
|
||||||
|
interface INotificationProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send notification
|
||||||
|
*
|
||||||
|
* @param VEvent $vevent
|
||||||
|
* @param string $calendarDisplayName
|
||||||
|
* @param IUser[] $users
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function send(VEvent $vevent,
|
||||||
|
string $calendarDisplayName,
|
||||||
|
array $users=[]): void;
|
||||||
|
}
|
|
@ -0,0 +1,188 @@
|
||||||
|
<?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 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\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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2019, Georg Ehrke
|
||||||
|
*
|
||||||
|
* @author Georg Ehrke <oc.list@georgehrke.com>
|
||||||
|
*
|
||||||
|
* @license AGPL-3.0
|
||||||
|
*
|
||||||
|
* This code is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* 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, version 3,
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace OCA\DAV\CalDAV\Reminder\NotificationProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class AudioProvider
|
||||||
|
*
|
||||||
|
* This class only extends PushProvider at the moment. It does not provide true
|
||||||
|
* audio-alarms yet, but it's better than no alarm at all right now.
|
||||||
|
*
|
||||||
|
* @package OCA\DAV\CalDAV\Reminder\NotificationProvider
|
||||||
|
*/
|
||||||
|
class AudioProvider extends PushProvider {
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
public const NOTIFICATION_TYPE = 'AUDIO';
|
||||||
|
}
|
|
@ -0,0 +1,503 @@
|
||||||
|
<?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 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\VEvent;
|
||||||
|
use Sabre\VObject;
|
||||||
|
use Sabre\VObject\Parameter;
|
||||||
|
use Sabre\VObject\Property;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* @param ILogger $logger
|
||||||
|
* @param L10NFactory $l10nFactory
|
||||||
|
* @param IUrlGenerator $urlGenerator
|
||||||
|
*/
|
||||||
|
public function __construct(IConfig $config,
|
||||||
|
IMailer $mailer,
|
||||||
|
ILogger $logger,
|
||||||
|
L10NFactory $l10nFactory,
|
||||||
|
IURLGenerator $urlGenerator) {
|
||||||
|
parent::__construct($logger, $l10nFactory, $urlGenerator, $config);
|
||||||
|
$this->mailer = $mailer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send out notification via email
|
||||||
|
*
|
||||||
|
* @param VEvent $vevent
|
||||||
|
* @param string $calendarDisplayName
|
||||||
|
* @param array $users
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function send(VEvent $vevent,
|
||||||
|
string $calendarDisplayName,
|
||||||
|
array $users=[]):void {
|
||||||
|
$fallbackLanguage = $this->getFallbackLanguage();
|
||||||
|
|
||||||
|
$emailAddressesOfSharees = $this->getEMailAddressesOfAllUsersWithWriteAccessToCalendar($users);
|
||||||
|
$emailAddressesOfAttendees = $this->getAllEMailAddressesFromEvent($vevent);
|
||||||
|
|
||||||
|
// 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
|
||||||
|
);
|
||||||
|
|
||||||
|
$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');
|
||||||
|
$template->addHeader();
|
||||||
|
$this->addSubjectAndHeading($template, $l10n, $vevent);
|
||||||
|
$this->addBulletList($template, $l10n, $calendarDisplayName, $vevent);
|
||||||
|
$template->addFooter();
|
||||||
|
|
||||||
|
foreach ($emailAddresses as $emailAddress) {
|
||||||
|
$message = $this->mailer->createMessage();
|
||||||
|
$message->setFrom([$fromEMail]);
|
||||||
|
if ($organizer) {
|
||||||
|
$message->setReplyTo($organizer);
|
||||||
|
}
|
||||||
|
$message->setTo([$emailAddress]);
|
||||||
|
$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)]);
|
||||||
|
}
|
||||||
|
} catch (\Exception $ex) {
|
||||||
|
$this->logger->logException($ex, ['app' => 'dav']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param IEMailTemplate $template
|
||||||
|
* @param IL10N $l10n
|
||||||
|
* @param VEvent $vevent
|
||||||
|
*/
|
||||||
|
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 IL10N $l10n
|
||||||
|
* @param string $calendarDisplayName
|
||||||
|
* @param array $eventData
|
||||||
|
*/
|
||||||
|
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($this->generateDateString($l10n, $vevent), $l10n->t('Date:'),
|
||||||
|
$this->getAbsoluteImagePath('places/calendar.svg'));
|
||||||
|
|
||||||
|
if (isset($vevent->LOCATION)) {
|
||||||
|
$template->addBodyListItem((string) $vevent->LOCATION, $l10n->t('Where:'),
|
||||||
|
$this->getAbsoluteImagePath('actions/address.svg'));
|
||||||
|
}
|
||||||
|
if (isset($vevent->DESCRIPTION)) {
|
||||||
|
$template->addBodyListItem((string) $vevent->DESCRIPTION, $l10n->t('Description:'),
|
||||||
|
$this->getAbsoluteImagePath('actions/more.svg'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $path
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function getAbsoluteImagePath(string $path):string {
|
||||||
|
return $this->urlGenerator->getAbsoluteURL(
|
||||||
|
$this->urlGenerator->imagePath('core', $path)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param VEvent $vevent
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
|
private function getOrganizerEMailAndNameFromEvent(VEvent $vevent):?array {
|
||||||
|
if (!$vevent->ORGANIZER) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$organizer = $vevent->ORGANIZER;
|
||||||
|
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 $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) && $this->hasAttendeeMailURI($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 stripos($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 $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);
|
||||||
|
|
||||||
|
/** @phan-suppress-next-line PhanUndeclaredClassMethod */
|
||||||
|
$dtstartDt = new \DateTime($dtstartDt->format(\DateTime::ATOM));
|
||||||
|
/** @phan-suppress-next-line PhanUndeclaredClassMethod */
|
||||||
|
$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()) {
|
||||||
|
/** @phan-suppress-next-line PhanUndeclaredClassMethod */
|
||||||
|
$startTimezone = $vevent->DTSTART->getDateTime()->getTimezone()->getName();
|
||||||
|
/** @phan-suppress-next-line PhanUndeclaredClassMethod */
|
||||||
|
$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');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2018 Thomas Citharel <tcit@tcit.fr>
|
||||||
|
*
|
||||||
|
* @author Thomas Citharel <tcit@tcit.fr>
|
||||||
|
*
|
||||||
|
* @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;
|
||||||
|
|
||||||
|
class ProviderNotAvailableException extends \Exception {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ProviderNotAvailableException constructor.
|
||||||
|
*
|
||||||
|
* @since 16.0.0
|
||||||
|
*
|
||||||
|
* @param string $type ReminderType
|
||||||
|
*/
|
||||||
|
public function __construct(string $type) {
|
||||||
|
parent::__construct("No notification provider for type $type available");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,139 @@
|
||||||
|
<?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 OCA\DAV\AppInfo\Application;
|
||||||
|
use OCP\IConfig;
|
||||||
|
use OCP\ILogger;
|
||||||
|
use OCP\IURLGenerator;
|
||||||
|
use OCP\L10N\IFactory as L10NFactory;
|
||||||
|
use OCP\Notification\IManager;
|
||||||
|
use OCP\IUser;
|
||||||
|
use OCP\Notification\INotification;
|
||||||
|
use OCP\AppFramework\Utility\ITimeFactory;
|
||||||
|
use Sabre\VObject\Component\VEvent;
|
||||||
|
use Sabre\VObject\Property;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class PushProvider
|
||||||
|
*
|
||||||
|
* @package OCA\DAV\CalDAV\Reminder\NotificationProvider
|
||||||
|
*/
|
||||||
|
class PushProvider extends AbstractProvider {
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
public const NOTIFICATION_TYPE = 'DISPLAY';
|
||||||
|
|
||||||
|
/** @var IManager */
|
||||||
|
private $manager;
|
||||||
|
|
||||||
|
/** @var ITimeFactory */
|
||||||
|
private $timeFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param IConfig $config
|
||||||
|
* @param IManager $manager
|
||||||
|
* @param ILogger $logger
|
||||||
|
* @param L10NFactory $l10nFactory
|
||||||
|
* @param IUrlGenerator $urlGenerator
|
||||||
|
* @param ITimeFactory $timeFactory
|
||||||
|
*/
|
||||||
|
public function __construct(IConfig $config,
|
||||||
|
IManager $manager,
|
||||||
|
ILogger $logger,
|
||||||
|
L10NFactory $l10nFactory,
|
||||||
|
IURLGenerator $urlGenerator,
|
||||||
|
ITimeFactory $timeFactory) {
|
||||||
|
parent::__construct($logger, $l10nFactory, $urlGenerator, $config);
|
||||||
|
$this->manager = $manager;
|
||||||
|
$this->timeFactory = $timeFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send push notification to all users.
|
||||||
|
*
|
||||||
|
* @param VEvent $vevent
|
||||||
|
* @param string $calendarDisplayName
|
||||||
|
* @param IUser[] $users
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function send(VEvent $vevent,
|
||||||
|
string $calendarDisplayName=null,
|
||||||
|
array $users=[]):void {
|
||||||
|
$eventDetails = $this->extractEventDetails($vevent);
|
||||||
|
$eventDetails['calendar_displayname'] = $calendarDisplayName;
|
||||||
|
|
||||||
|
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,
|
||||||
|
/** @phan-suppress-next-line PhanUndeclaredClassMethod */
|
||||||
|
'start_atom' => $start->getDateTime()->format(\DateTime::ATOM),
|
||||||
|
'start_is_floating' => $start->isFloating(),
|
||||||
|
/** @phan-suppress-next-line PhanUndeclaredClassMethod */
|
||||||
|
'start_timezone' => $start->getDateTime()->getTimezone()->getName(),
|
||||||
|
/** @phan-suppress-next-line PhanUndeclaredClassMethod */
|
||||||
|
'end_atom' => $end->getDateTime()->format(\DateTime::ATOM),
|
||||||
|
'end_is_floating' => $end->isFloating(),
|
||||||
|
/** @phan-suppress-next-line PhanUndeclaredClassMethod */
|
||||||
|
'end_timezone' => $end->getDateTime()->getTimezone()->getName(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
<?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 AGPL-3.0
|
||||||
|
*
|
||||||
|
* This code is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* 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, version 3,
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace OCA\DAV\CalDAV\Reminder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class NotificationProviderManager
|
||||||
|
*
|
||||||
|
* @package OCA\DAV\CalDAV\Reminder
|
||||||
|
*/
|
||||||
|
class NotificationProviderManager {
|
||||||
|
|
||||||
|
/** @var INotificationProvider[] */
|
||||||
|
private $providers = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a provider for a given ACTION exists
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasProvider(string $type):bool {
|
||||||
|
return (\in_array($type, ReminderService::REMINDER_TYPES, true)
|
||||||
|
&& isset($this->providers[$type]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get provider for a given ACTION
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
* @return INotificationProvider
|
||||||
|
* @throws NotificationProvider\ProviderNotAvailableException
|
||||||
|
* @throws NotificationTypeDoesNotExistException
|
||||||
|
*/
|
||||||
|
public function getProvider(string $type):INotificationProvider {
|
||||||
|
if (in_array($type, ReminderService::REMINDER_TYPES, true)) {
|
||||||
|
if (isset($this->providers[$type])) {
|
||||||
|
return $this->providers[$type];
|
||||||
|
}
|
||||||
|
throw new NotificationProvider\ProviderNotAvailableException($type);
|
||||||
|
}
|
||||||
|
throw new NotificationTypeDoesNotExistException($type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a new provider
|
||||||
|
*
|
||||||
|
* @param string $providerClassName
|
||||||
|
* @throws \OCP\AppFramework\QueryException
|
||||||
|
*/
|
||||||
|
public function registerProvider(string $providerClassName):void {
|
||||||
|
$provider = \OC::$server->query($providerClassName);
|
||||||
|
|
||||||
|
if (!$provider instanceof INotificationProvider) {
|
||||||
|
throw new \InvalidArgumentException('Invalid notification provider registered');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->providers[$provider::NOTIFICATION_TYPE] = $provider;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2019, Thomas Citharel
|
||||||
|
*
|
||||||
|
* @author Thomas Citharel <tcit@tcit.fr>
|
||||||
|
*
|
||||||
|
* @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;
|
||||||
|
|
||||||
|
class NotificationTypeDoesNotExistException extends \Exception {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NotificationTypeDoesNotExistException constructor.
|
||||||
|
*
|
||||||
|
* @since 16.0.0
|
||||||
|
*
|
||||||
|
* @param string $type ReminderType
|
||||||
|
*/
|
||||||
|
public function __construct(string $type) {
|
||||||
|
parent::__construct("Type $type is not an accepted type of notification");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,316 @@
|
||||||
|
<?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 AGPL-3.0
|
||||||
|
*
|
||||||
|
* This code is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* 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, version 3,
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
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 IFactory */
|
||||||
|
private $l10nFactory;
|
||||||
|
|
||||||
|
/** @var IURLGenerator */
|
||||||
|
private $urlGenerator;
|
||||||
|
|
||||||
|
/** @var IL10N */
|
||||||
|
private $l10n;
|
||||||
|
|
||||||
|
/** @var ITimeFactory */
|
||||||
|
private $timeFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifier of the notifier, only use [a-z0-9_]
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* @since 17.0.0
|
||||||
|
*/
|
||||||
|
public function getID():string {
|
||||||
|
return Application::APP_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Human readable name describing the notifier
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* @since 17.0.0
|
||||||
|
*/
|
||||||
|
public function getName():string {
|
||||||
|
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 {
|
||||||
|
if ($notification->getApp() !== Application::APP_ID) {
|
||||||
|
throw new \InvalidArgumentException('Notification not from this app');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the language from the notification
|
||||||
|
$this->l10n = $this->l10nFactory->get('dav', $languageCode);
|
||||||
|
|
||||||
|
// Handle notifier subjects
|
||||||
|
switch($notification->getSubject()) {
|
||||||
|
case 'calendar_reminder':
|
||||||
|
return $this->prepareReminderNotification($notification);
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new \InvalidArgumentException('Unknown subject');
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param INotification $notification
|
||||||
|
* @return INotification
|
||||||
|
*/
|
||||||
|
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 INotification $notification
|
||||||
|
*/
|
||||||
|
private function prepareNotificationSubject(INotification $notification): void {
|
||||||
|
$parameters = $notification->getSubjectParameters();
|
||||||
|
|
||||||
|
$startTime = \DateTime::createFromFormat(\DateTime::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]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$notification->setParsedSubject($title);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the notification message based on the parameters set in PushProvider
|
||||||
|
*
|
||||||
|
* @param INotification $notification
|
||||||
|
*/
|
||||||
|
private function prepareNotificationMessage(INotification $notification): void {
|
||||||
|
$parameters = $notification->getMessageParameters();
|
||||||
|
|
||||||
|
$description = [
|
||||||
|
$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');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $parameters
|
||||||
|
* @return string
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
private function generateDateString(array $parameters):string {
|
||||||
|
$startDateTime = DateTime::createFromFormat(\DateTime::ATOM, $parameters['start_atom']);
|
||||||
|
$endDateTime = DateTime::createFromFormat(\DateTime::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),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$startTimezone = $endTimezone = null;
|
||||||
|
if (!$parameters['start_is_floating']) {
|
||||||
|
$startTimezone = $parameters['start_timezone'];
|
||||||
|
$endTimezone = $parameters['end_timezone'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$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']);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,761 @@
|
||||||
|
<?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 AGPL-3.0
|
||||||
|
*
|
||||||
|
* This code is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* 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, version 3,
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace OCA\DAV\CalDAV\Reminder;
|
||||||
|
|
||||||
|
use \DateTimeImmutable;
|
||||||
|
use OCA\DAV\CalDAV\CalDavBackend;
|
||||||
|
use OCP\AppFramework\Utility\ITimeFactory;
|
||||||
|
use OCP\IGroup;
|
||||||
|
use OCP\IGroupManager;
|
||||||
|
use OCP\IUser;
|
||||||
|
use OCP\IUserManager;
|
||||||
|
use Sabre\VObject;
|
||||||
|
use Sabre\VObject\Component\VAlarm;
|
||||||
|
use Sabre\VObject\Component\VEvent;
|
||||||
|
use Sabre\VObject\ParseException;
|
||||||
|
use Sabre\VObject\Recur\EventIterator;
|
||||||
|
use Sabre\VObject\Recur\NoInstancesException;
|
||||||
|
|
||||||
|
class ReminderService {
|
||||||
|
|
||||||
|
/** @var Backend */
|
||||||
|
private $backend;
|
||||||
|
|
||||||
|
/** @var NotificationProviderManager */
|
||||||
|
private $notificationProviderManager;
|
||||||
|
|
||||||
|
/** @var IUserManager */
|
||||||
|
private $userManager;
|
||||||
|
|
||||||
|
/** @var IGroupManager */
|
||||||
|
private $groupManager;
|
||||||
|
|
||||||
|
/** @var CalDavBackend */
|
||||||
|
private $caldavBackend;
|
||||||
|
|
||||||
|
/** @var ITimeFactory */
|
||||||
|
private $timeFactory;
|
||||||
|
|
||||||
|
public const REMINDER_TYPE_EMAIL = 'EMAIL';
|
||||||
|
public const REMINDER_TYPE_DISPLAY = 'DISPLAY';
|
||||||
|
public const REMINDER_TYPE_AUDIO = 'AUDIO';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var String[]
|
||||||
|
*
|
||||||
|
* Official RFC5545 reminder types
|
||||||
|
*/
|
||||||
|
public const REMINDER_TYPES = [
|
||||||
|
self::REMINDER_TYPE_EMAIL,
|
||||||
|
self::REMINDER_TYPE_DISPLAY,
|
||||||
|
self::REMINDER_TYPE_AUDIO
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ReminderService constructor.
|
||||||
|
*
|
||||||
|
* @param Backend $backend
|
||||||
|
* @param NotificationProviderManager $notificationProviderManager
|
||||||
|
* @param IUserManager $userManager
|
||||||
|
* @param IGroupManager $groupManager
|
||||||
|
* @param CalDavBackend $caldavBackend
|
||||||
|
* @param ITimeFactory $timeFactory
|
||||||
|
*/
|
||||||
|
public function __construct(Backend $backend,
|
||||||
|
NotificationProviderManager $notificationProviderManager,
|
||||||
|
IUserManager $userManager,
|
||||||
|
IGroupManager $groupManager,
|
||||||
|
CalDavBackend $caldavBackend,
|
||||||
|
ITimeFactory $timeFactory) {
|
||||||
|
$this->backend = $backend;
|
||||||
|
$this->notificationProviderManager = $notificationProviderManager;
|
||||||
|
$this->userManager = $userManager;
|
||||||
|
$this->groupManager = $groupManager;
|
||||||
|
$this->caldavBackend = $caldavBackend;
|
||||||
|
$this->timeFactory = $timeFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process reminders to activate
|
||||||
|
*
|
||||||
|
* @throws NotificationProvider\ProviderNotAvailableException
|
||||||
|
* @throws NotificationTypeDoesNotExistException
|
||||||
|
*/
|
||||||
|
public function processReminders():void {
|
||||||
|
$reminders = $this->backend->getRemindersToProcess();
|
||||||
|
|
||||||
|
foreach($reminders as $reminder) {
|
||||||
|
$vcalendar = $this->parseCalendarData($reminder['calendardata']);
|
||||||
|
if (!$vcalendar) {
|
||||||
|
$this->backend->removeReminder($reminder['id']);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$vevent = $this->getVEventByRecurrenceId($vcalendar, $reminder['recurrence_id'], $reminder['is_recurrence_exception']);
|
||||||
|
if (!$vevent) {
|
||||||
|
$this->backend->removeReminder($reminder['id']);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->wasEventCancelled($vevent)) {
|
||||||
|
$this->deleteOrProcessNext($reminder, $vevent);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->notificationProviderManager->hasProvider($reminder['type'])) {
|
||||||
|
$this->deleteOrProcessNext($reminder, $vevent);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$users = $this->getAllUsersWithWriteAccessToCalendar($reminder['calendar_id']);
|
||||||
|
$user = $this->getUserFromPrincipalURI($reminder['principaluri']);
|
||||||
|
if ($user) {
|
||||||
|
$users[] = $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
$notificationProvider = $this->notificationProviderManager->getProvider($reminder['type']);
|
||||||
|
$notificationProvider->send($vevent, $reminder['displayname'], $users);
|
||||||
|
|
||||||
|
$this->deleteOrProcessNext($reminder, $vevent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $action
|
||||||
|
* @param array $objectData
|
||||||
|
* @throws VObject\InvalidDataException
|
||||||
|
*/
|
||||||
|
public function onTouchCalendarObject(string $action,
|
||||||
|
array $objectData):void {
|
||||||
|
// We only support VEvents for now
|
||||||
|
if (strcasecmp($objectData['component'], 'vevent') !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch($action) {
|
||||||
|
case '\OCA\DAV\CalDAV\CalDavBackend::createCalendarObject':
|
||||||
|
$this->onCalendarObjectCreate($objectData);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\OCA\DAV\CalDAV\CalDavBackend::updateCalendarObject':
|
||||||
|
$this->onCalendarObjectEdit($objectData);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\OCA\DAV\CalDAV\CalDavBackend::deleteCalendarObject':
|
||||||
|
$this->onCalendarObjectDelete($objectData);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $objectData
|
||||||
|
*/
|
||||||
|
private function onCalendarObjectCreate(array $objectData):void {
|
||||||
|
/** @var VObject\Component\VCalendar $vcalendar */
|
||||||
|
$vcalendar = $this->parseCalendarData($objectData['calendardata']);
|
||||||
|
if (!$vcalendar) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$vevents = $this->getAllVEventsFromVCalendar($vcalendar);
|
||||||
|
if (count($vevents) === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$uid = (string) $vevents[0]->UID;
|
||||||
|
$recurrenceExceptions = $this->getRecurrenceExceptionFromListOfVEvents($vevents);
|
||||||
|
$masterItem = $this->getMasterItemFromListOfVEvents($vevents);
|
||||||
|
$now = $this->timeFactory->getDateTime();
|
||||||
|
$isRecurring = $masterItem ? $this->isRecurring($masterItem) : false;
|
||||||
|
|
||||||
|
foreach($recurrenceExceptions as $recurrenceException) {
|
||||||
|
$eventHash = $this->getEventHash($recurrenceException);
|
||||||
|
|
||||||
|
foreach($recurrenceException->VALARM as $valarm) {
|
||||||
|
/** @var VAlarm $valarm */
|
||||||
|
$alarmHash = $this->getAlarmHash($valarm);
|
||||||
|
$triggerTime = $valarm->getEffectiveTriggerTime();
|
||||||
|
$diff = $now->diff($triggerTime);
|
||||||
|
if ($diff->invert === 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$alarms = $this->getRemindersForVAlarm($valarm, $objectData,
|
||||||
|
$eventHash, $alarmHash, true, true);
|
||||||
|
$this->writeRemindersToDatabase($alarms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($masterItem) {
|
||||||
|
$processedAlarms = [];
|
||||||
|
$masterAlarms = [];
|
||||||
|
$masterHash = $this->getEventHash($masterItem);
|
||||||
|
|
||||||
|
foreach($masterItem->VALARM as $valarm) {
|
||||||
|
$masterAlarms[] = $this->getAlarmHash($valarm);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$iterator = new EventIterator($vevents, $uid);
|
||||||
|
} catch (NoInstancesException $e) {
|
||||||
|
// This event is recurring, but it doesn't have a single
|
||||||
|
// instance. We are skipping this event from the output
|
||||||
|
// entirely.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while($iterator->valid() && count($processedAlarms) < count($masterAlarms)) {
|
||||||
|
$event = $iterator->getEventObject();
|
||||||
|
|
||||||
|
// Recurrence-exceptions are handled separately, so just ignore them here
|
||||||
|
if (\in_array($event, $recurrenceExceptions, true)) {
|
||||||
|
$iterator->next();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($event->VALARM as $valarm) {
|
||||||
|
/** @var VAlarm $valarm */
|
||||||
|
$alarmHash = $this->getAlarmHash($valarm);
|
||||||
|
if (\in_array($alarmHash, $processedAlarms, true)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!\in_array((string) $valarm->ACTION, self::REMINDER_TYPES, true)) {
|
||||||
|
// Action allows x-name, we don't insert reminders
|
||||||
|
// into the database if they are not standard
|
||||||
|
$processedAlarms[] = $alarmHash;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$triggerTime = $valarm->getEffectiveTriggerTime();
|
||||||
|
|
||||||
|
// If effective trigger time is in the past
|
||||||
|
// just skip and generate for next event
|
||||||
|
$diff = $now->diff($triggerTime);
|
||||||
|
if ($diff->invert === 1) {
|
||||||
|
// If an absolute alarm is in the past,
|
||||||
|
// just add it to processedAlarms, so
|
||||||
|
// we don't extend till eternity
|
||||||
|
if (!$this->isAlarmRelative($valarm)) {
|
||||||
|
$processedAlarms[] = $alarmHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$alarms = $this->getRemindersForVAlarm($valarm, $objectData, $masterHash, $alarmHash, $isRecurring, false);
|
||||||
|
$this->writeRemindersToDatabase($alarms);
|
||||||
|
$processedAlarms[] = $alarmHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
$iterator->next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $objectData
|
||||||
|
*/
|
||||||
|
private function onCalendarObjectEdit(array $objectData):void {
|
||||||
|
// TODO - this can be vastly improved
|
||||||
|
// - get cached reminders
|
||||||
|
// - ...
|
||||||
|
|
||||||
|
$this->onCalendarObjectDelete($objectData);
|
||||||
|
$this->onCalendarObjectCreate($objectData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $objectData
|
||||||
|
*/
|
||||||
|
private function onCalendarObjectDelete(array $objectData):void {
|
||||||
|
$this->backend->cleanRemindersForEvent((int) $objectData['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param VAlarm $valarm
|
||||||
|
* @param array $objectData
|
||||||
|
* @param string|null $eventHash
|
||||||
|
* @param string|null $alarmHash
|
||||||
|
* @param bool $isRecurring
|
||||||
|
* @param bool $isRecurrenceException
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getRemindersForVAlarm(VAlarm $valarm,
|
||||||
|
array $objectData,
|
||||||
|
string $eventHash=null,
|
||||||
|
string $alarmHash=null,
|
||||||
|
bool $isRecurring=false,
|
||||||
|
bool $isRecurrenceException=false):array {
|
||||||
|
if ($eventHash === null) {
|
||||||
|
$eventHash = $this->getEventHash($valarm->parent);
|
||||||
|
}
|
||||||
|
if ($alarmHash === null) {
|
||||||
|
$alarmHash = $this->getAlarmHash($valarm);
|
||||||
|
}
|
||||||
|
|
||||||
|
$recurrenceId = $this->getEffectiveRecurrenceIdOfVEvent($valarm->parent);
|
||||||
|
$isRelative = $this->isAlarmRelative($valarm);
|
||||||
|
/** @var DateTimeImmutable $notificationDate */
|
||||||
|
$notificationDate = $valarm->getEffectiveTriggerTime();
|
||||||
|
$clonedNotificationDate = new \DateTime('now', $notificationDate->getTimezone());
|
||||||
|
$clonedNotificationDate->setTimestamp($notificationDate->getTimestamp());
|
||||||
|
|
||||||
|
$alarms = [];
|
||||||
|
|
||||||
|
$alarms[] = [
|
||||||
|
'calendar_id' => $objectData['calendarid'],
|
||||||
|
'object_id' => $objectData['id'],
|
||||||
|
'uid' => (string) $valarm->parent->UID,
|
||||||
|
'is_recurring' => $isRecurring,
|
||||||
|
'recurrence_id' => $recurrenceId,
|
||||||
|
'is_recurrence_exception' => $isRecurrenceException,
|
||||||
|
'event_hash' => $eventHash,
|
||||||
|
'alarm_hash' => $alarmHash,
|
||||||
|
'type' => (string) $valarm->ACTION,
|
||||||
|
'is_relative' => $isRelative,
|
||||||
|
'notification_date' => $notificationDate->getTimestamp(),
|
||||||
|
'is_repeat_based' => false,
|
||||||
|
];
|
||||||
|
|
||||||
|
$repeat = isset($valarm->REPEAT) ? (int) $valarm->REPEAT->getValue() : 0;
|
||||||
|
for($i = 0; $i < $repeat; $i++) {
|
||||||
|
if ($valarm->DURATION === null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$clonedNotificationDate->add($valarm->DURATION->getDateInterval());
|
||||||
|
$alarms[] = [
|
||||||
|
'calendar_id' => $objectData['calendarid'],
|
||||||
|
'object_id' => $objectData['id'],
|
||||||
|
'uid' => (string) $valarm->parent->UID,
|
||||||
|
'is_recurring' => $isRecurring,
|
||||||
|
'recurrence_id' => $recurrenceId,
|
||||||
|
'is_recurrence_exception' => $isRecurrenceException,
|
||||||
|
'event_hash' => $eventHash,
|
||||||
|
'alarm_hash' => $alarmHash,
|
||||||
|
'type' => (string) $valarm->ACTION,
|
||||||
|
'is_relative' => $isRelative,
|
||||||
|
'notification_date' => $clonedNotificationDate->getTimestamp(),
|
||||||
|
'is_repeat_based' => true,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $alarms;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $reminders
|
||||||
|
*/
|
||||||
|
private function writeRemindersToDatabase(array $reminders): void {
|
||||||
|
foreach($reminders as $reminder) {
|
||||||
|
$this->backend->insertReminder(
|
||||||
|
(int) $reminder['calendar_id'],
|
||||||
|
(int) $reminder['object_id'],
|
||||||
|
$reminder['uid'],
|
||||||
|
$reminder['is_recurring'],
|
||||||
|
(int) $reminder['recurrence_id'],
|
||||||
|
$reminder['is_recurrence_exception'],
|
||||||
|
$reminder['event_hash'],
|
||||||
|
$reminder['alarm_hash'],
|
||||||
|
$reminder['type'],
|
||||||
|
$reminder['is_relative'],
|
||||||
|
(int) $reminder['notification_date'],
|
||||||
|
$reminder['is_repeat_based']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $reminder
|
||||||
|
* @param VEvent $vevent
|
||||||
|
*/
|
||||||
|
private function deleteOrProcessNext(array $reminder,
|
||||||
|
VObject\Component\VEvent $vevent):void {
|
||||||
|
if ($reminder['is_repeat_based'] ||
|
||||||
|
!$reminder['is_recurring'] ||
|
||||||
|
!$reminder['is_relative'] ||
|
||||||
|
$reminder['is_recurrence_exception']) {
|
||||||
|
|
||||||
|
$this->backend->removeReminder($reminder['id']);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$vevents = $this->getAllVEventsFromVCalendar($vevent->parent);
|
||||||
|
$recurrenceExceptions = $this->getRecurrenceExceptionFromListOfVEvents($vevents);
|
||||||
|
$now = $this->timeFactory->getDateTime();
|
||||||
|
|
||||||
|
try {
|
||||||
|
$iterator = new EventIterator($vevents, $reminder['uid']);
|
||||||
|
} catch (NoInstancesException $e) {
|
||||||
|
// This event is recurring, but it doesn't have a single
|
||||||
|
// instance. We are skipping this event from the output
|
||||||
|
// entirely.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while($iterator->valid()) {
|
||||||
|
$event = $iterator->getEventObject();
|
||||||
|
|
||||||
|
// Recurrence-exceptions are handled separately, so just ignore them here
|
||||||
|
if (\in_array($event, $recurrenceExceptions, true)) {
|
||||||
|
$iterator->next();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$recurrenceId = $this->getEffectiveRecurrenceIdOfVEvent($event);
|
||||||
|
if ($reminder['recurrence_id'] >= $recurrenceId) {
|
||||||
|
$iterator->next();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($event->VALARM as $valarm) {
|
||||||
|
/** @var VAlarm $valarm */
|
||||||
|
$alarmHash = $this->getAlarmHash($valarm);
|
||||||
|
if ($alarmHash !== $reminder['alarm_hash']) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$triggerTime = $valarm->getEffectiveTriggerTime();
|
||||||
|
|
||||||
|
// If effective trigger time is in the past
|
||||||
|
// just skip and generate for next event
|
||||||
|
$diff = $now->diff($triggerTime);
|
||||||
|
if ($diff->invert === 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->backend->removeReminder($reminder['id']);
|
||||||
|
$alarms = $this->getRemindersForVAlarm($valarm, [
|
||||||
|
'calendarid' => $reminder['calendar_id'],
|
||||||
|
'id' => $reminder['object_id'],
|
||||||
|
], $reminder['event_hash'], $alarmHash, true, false);
|
||||||
|
$this->writeRemindersToDatabase($alarms);
|
||||||
|
|
||||||
|
// Abort generating reminders after creating one successfully
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$iterator->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->backend->removeReminder($reminder['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $calendarId
|
||||||
|
* @return IUser[]
|
||||||
|
*/
|
||||||
|
private function getAllUsersWithWriteAccessToCalendar(int $calendarId):array {
|
||||||
|
$shares = $this->caldavBackend->getShares($calendarId);
|
||||||
|
|
||||||
|
$users = [];
|
||||||
|
$userIds = [];
|
||||||
|
$groups = [];
|
||||||
|
foreach ($shares as $share) {
|
||||||
|
// Only consider writable shares
|
||||||
|
if ($share['readOnly']) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$principal = explode('/', $share['{http://owncloud.org/ns}principal']);
|
||||||
|
if ($principal[1] === 'users') {
|
||||||
|
$user = $this->userManager->get($principal[2]);
|
||||||
|
if ($user) {
|
||||||
|
$users[] = $user;
|
||||||
|
$userIds[] = $principal[2];
|
||||||
|
}
|
||||||
|
} else if ($principal[1] === 'groups') {
|
||||||
|
$groups[] = $principal[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($groups as $gid) {
|
||||||
|
$group = $this->groupManager->get($gid);
|
||||||
|
if ($group instanceof IGroup) {
|
||||||
|
foreach ($group->getUsers() as $user) {
|
||||||
|
if (!\in_array($user->getUID(), $userIds, true)) {
|
||||||
|
$users[] = $user;
|
||||||
|
$userIds[] = $user->getUID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $users;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a hash of the event.
|
||||||
|
* If the hash changes, we have to update all relative alarms.
|
||||||
|
*
|
||||||
|
* @param VEvent $vevent
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function getEventHash(VEvent $vevent):string {
|
||||||
|
$properties = [
|
||||||
|
(string) $vevent->DTSTART->serialize(),
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($vevent->DTEND) {
|
||||||
|
$properties[] = (string) $vevent->DTEND->serialize();
|
||||||
|
}
|
||||||
|
if ($vevent->DURATION) {
|
||||||
|
$properties[] = (string) $vevent->DURATION->serialize();
|
||||||
|
}
|
||||||
|
if ($vevent->{'RECURRENCE-ID'}) {
|
||||||
|
$properties[] = (string) $vevent->{'RECURRENCE-ID'}->serialize();
|
||||||
|
}
|
||||||
|
if ($vevent->RRULE) {
|
||||||
|
$properties[] = (string) $vevent->RRULE->serialize();
|
||||||
|
}
|
||||||
|
if ($vevent->EXDATE) {
|
||||||
|
$properties[] = (string) $vevent->EXDATE->serialize();
|
||||||
|
}
|
||||||
|
if ($vevent->RDATE) {
|
||||||
|
$properties[] = (string) $vevent->RDATE->serialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
return md5(implode('::', $properties));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a hash of the alarm.
|
||||||
|
* If the hash changes, we have to update oc_dav_reminders.
|
||||||
|
*
|
||||||
|
* @param VAlarm $valarm
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function getAlarmHash(VAlarm $valarm):string {
|
||||||
|
$properties = [
|
||||||
|
(string) $valarm->ACTION->serialize(),
|
||||||
|
(string) $valarm->TRIGGER->serialize(),
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($valarm->DURATION) {
|
||||||
|
$properties[] = (string) $valarm->DURATION->serialize();
|
||||||
|
}
|
||||||
|
if ($valarm->REPEAT) {
|
||||||
|
$properties[] = (string) $valarm->REPEAT->serialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
return md5(implode('::', $properties));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param VObject\Component\VCalendar $vcalendar
|
||||||
|
* @param int $recurrenceId
|
||||||
|
* @param bool $isRecurrenceException
|
||||||
|
* @return VEvent|null
|
||||||
|
*/
|
||||||
|
private function getVEventByRecurrenceId(VObject\Component\VCalendar $vcalendar,
|
||||||
|
int $recurrenceId,
|
||||||
|
bool $isRecurrenceException):?VEvent {
|
||||||
|
$vevents = $this->getAllVEventsFromVCalendar($vcalendar);
|
||||||
|
if (count($vevents) === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$uid = (string) $vevents[0]->UID;
|
||||||
|
$recurrenceExceptions = $this->getRecurrenceExceptionFromListOfVEvents($vevents);
|
||||||
|
$masterItem = $this->getMasterItemFromListOfVEvents($vevents);
|
||||||
|
|
||||||
|
// Handle recurrence-exceptions first, because recurrence-expansion is expensive
|
||||||
|
if ($isRecurrenceException) {
|
||||||
|
foreach($recurrenceExceptions as $recurrenceException) {
|
||||||
|
if ($this->getEffectiveRecurrenceIdOfVEvent($recurrenceException) === $recurrenceId) {
|
||||||
|
return $recurrenceException;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($masterItem) {
|
||||||
|
try {
|
||||||
|
$iterator = new EventIterator($vevents, $uid);
|
||||||
|
} catch (NoInstancesException $e) {
|
||||||
|
// This event is recurring, but it doesn't have a single
|
||||||
|
// instance. We are skipping this event from the output
|
||||||
|
// entirely.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ($iterator->valid()) {
|
||||||
|
$event = $iterator->getEventObject();
|
||||||
|
|
||||||
|
// Recurrence-exceptions are handled separately, so just ignore them here
|
||||||
|
if (\in_array($event, $recurrenceExceptions, true)) {
|
||||||
|
$iterator->next();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->getEffectiveRecurrenceIdOfVEvent($event) === $recurrenceId) {
|
||||||
|
return $event;
|
||||||
|
}
|
||||||
|
|
||||||
|
$iterator->next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 VObject\Component\VEvent $vevent
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function wasEventCancelled(VObject\Component\VEvent $vevent):bool {
|
||||||
|
return $this->getStatusOfEvent($vevent) === 'CANCELLED';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $calendarData
|
||||||
|
* @return VObject\Component\VCalendar|null
|
||||||
|
*/
|
||||||
|
private function parseCalendarData(string $calendarData):?VObject\Component\VCalendar {
|
||||||
|
try {
|
||||||
|
return VObject\Reader::read($calendarData,
|
||||||
|
VObject\Reader::OPTION_FORGIVING);
|
||||||
|
} catch(ParseException $ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $principalUri
|
||||||
|
* @return IUser|null
|
||||||
|
*/
|
||||||
|
private function getUserFromPrincipalURI(string $principalUri):?IUser {
|
||||||
|
if (!$principalUri) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stripos($principalUri, 'principals/users/') !== 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$userId = substr($principalUri, 17);
|
||||||
|
return $this->userManager->get($userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param VObject\Component\VCalendar $vcalendar
|
||||||
|
* @return VObject\Component\VEvent[]
|
||||||
|
*/
|
||||||
|
private function getAllVEventsFromVCalendar(VObject\Component\VCalendar $vcalendar):array {
|
||||||
|
$vevents = [];
|
||||||
|
|
||||||
|
foreach($vcalendar->children() as $child) {
|
||||||
|
if (!($child instanceof VObject\Component)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($child->name !== 'VEVENT') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$vevents[] = $child;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $vevents;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $vevents
|
||||||
|
* @return VObject\Component\VEvent[]
|
||||||
|
*/
|
||||||
|
private function getRecurrenceExceptionFromListOfVEvents(array $vevents):array {
|
||||||
|
return array_values(array_filter($vevents, function(VEvent $vevent) {
|
||||||
|
return $vevent->{'RECURRENCE-ID'} !== null;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $vevents
|
||||||
|
* @return VEvent|null
|
||||||
|
*/
|
||||||
|
private function getMasterItemFromListOfVEvents(array $vevents):?VEvent {
|
||||||
|
$elements = array_values(array_filter($vevents, function(VEvent $vevent) {
|
||||||
|
return $vevent->{'RECURRENCE-ID'} === null;
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (count($elements) === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (count($elements) > 1) {
|
||||||
|
throw new \TypeError('Multiple master objects');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $elements[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param VAlarm $valarm
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function isAlarmRelative(VAlarm $valarm):bool {
|
||||||
|
$trigger = $valarm->TRIGGER;
|
||||||
|
return $trigger instanceof VObject\Property\ICalendar\Duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param VEvent $vevent
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
private function getEffectiveRecurrenceIdOfVEvent(VEvent $vevent):int {
|
||||||
|
if (isset($vevent->{'RECURRENCE-ID'})) {
|
||||||
|
return $vevent->{'RECURRENCE-ID'}->getDateTime()->getTimestamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $vevent->DTSTART->getDateTime()->getTimestamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param VEvent $vevent
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function isRecurring(VEvent $vevent):bool {
|
||||||
|
return isset($vevent->RRULE) || isset($vevent->RDATE);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2019, Georg Ehrke
|
||||||
|
*
|
||||||
|
* @author Georg Ehrke <oc.list@georgehrke.com>
|
||||||
|
*
|
||||||
|
* @license AGPL-3.0
|
||||||
|
*
|
||||||
|
* This code is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* 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, version 3,
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace OCA\DAV\Command;
|
||||||
|
|
||||||
|
use OCA\DAV\CalDAV\Reminder\ReminderService;
|
||||||
|
use OCP\IConfig;
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class SendEventReminders
|
||||||
|
*
|
||||||
|
* @package OCA\DAV\Command
|
||||||
|
*/
|
||||||
|
class SendEventReminders extends Command {
|
||||||
|
|
||||||
|
/** @var ReminderService */
|
||||||
|
protected $reminderService;
|
||||||
|
|
||||||
|
/** @var IConfig */
|
||||||
|
protected $config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ReminderService $reminderService
|
||||||
|
* @param IConfig $config
|
||||||
|
*/
|
||||||
|
public function __construct(ReminderService $reminderService,
|
||||||
|
IConfig $config) {
|
||||||
|
parent::__construct();
|
||||||
|
$this->reminderService = $reminderService;
|
||||||
|
$this->config = $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
protected function configure():void {
|
||||||
|
$this
|
||||||
|
->setName('dav:send-event-reminders')
|
||||||
|
->setDescription('Sends event reminders');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param InputInterface $input
|
||||||
|
* @param OutputInterface $output
|
||||||
|
*/
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output):void {
|
||||||
|
if ($this->config->getAppValue('dav', 'sendEventReminders', 'yes') !== 'yes') {
|
||||||
|
$output->writeln('<error>Sending event reminders disabled!</error>');
|
||||||
|
$output->writeln('<info>Please run "php occ config:app:set dav sendEventReminders --value yes"');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->config->getAppValue('dav', 'sendEventRemindersMode', 'backgroundjob') !== 'occ') {
|
||||||
|
$output->writeln('<error>Sending event reminders mode set to background-job!</error>');
|
||||||
|
$output->writeln('<info>Please run "php occ config:app:set dav sendEventRemindersMode --value occ"');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->reminderService->processReminders();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* @copyright 2019 Georg Ehrke <oc.list@georgehrke.com>
|
||||||
|
*
|
||||||
|
* @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\Migration;
|
||||||
|
|
||||||
|
use OCA\DAV\BackgroundJob\BuildReminderIndexBackgroundJob;
|
||||||
|
use OCP\BackgroundJob\IJobList;
|
||||||
|
use OCP\IConfig;
|
||||||
|
use OCP\IDBConnection;
|
||||||
|
use OCP\Migration\IOutput;
|
||||||
|
use OCP\Migration\IRepairStep;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class RegisterBuildReminderIndexBackgroundJob
|
||||||
|
*
|
||||||
|
* @package OCA\DAV\Migration
|
||||||
|
*/
|
||||||
|
class RegisterBuildReminderIndexBackgroundJob implements IRepairStep {
|
||||||
|
|
||||||
|
/** @var IDBConnection */
|
||||||
|
private $db;
|
||||||
|
|
||||||
|
/** @var IJobList */
|
||||||
|
private $jobList;
|
||||||
|
|
||||||
|
/** @var IConfig */
|
||||||
|
private $config;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private const CONFIG_KEY = 'buildCalendarReminderIndex';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param IDBConnection $db
|
||||||
|
* @param IJobList $jobList
|
||||||
|
* @param IConfig $config
|
||||||
|
*/
|
||||||
|
public function __construct(IDBConnection $db,
|
||||||
|
IJobList $jobList,
|
||||||
|
IConfig $config) {
|
||||||
|
$this->db = $db;
|
||||||
|
$this->jobList = $jobList;
|
||||||
|
$this->config = $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getName() {
|
||||||
|
return 'Registering building of calendar reminder index as background job';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param IOutput $output
|
||||||
|
*/
|
||||||
|
public function run(IOutput $output) {
|
||||||
|
// only run once
|
||||||
|
if ($this->config->getAppValue('dav', self::CONFIG_KEY) === 'yes') {
|
||||||
|
$output->info('Repair step already executed');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = $this->db->getQueryBuilder();
|
||||||
|
$query->select($query->createFunction('MAX(' . $query->getColumnName('id') . ')'))
|
||||||
|
->from('calendarobjects');
|
||||||
|
$maxId = (int)$query->execute()->fetchColumn();
|
||||||
|
|
||||||
|
$output->info('Add background job');
|
||||||
|
$this->jobList->add(BuildReminderIndexBackgroundJob::class, [
|
||||||
|
'offset' => 0,
|
||||||
|
'stopAt' => $maxId
|
||||||
|
]);
|
||||||
|
|
||||||
|
// if all were done, no need to redo the repair during next upgrade
|
||||||
|
$this->config->setAppValue('dav', self::CONFIG_KEY, 'yes');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,116 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* @copyright 2019, Georg Ehrke <oc.list@georgehrke.com>
|
||||||
|
*
|
||||||
|
* @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\Migration;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Types\Type;
|
||||||
|
use OCP\DB\ISchemaWrapper;
|
||||||
|
use OCP\Migration\SimpleMigrationStep;
|
||||||
|
use OCP\Migration\IOutput;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated migration step: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
class Version1012Date20190808122342 extends SimpleMigrationStep {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param IOutput $output
|
||||||
|
* @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
|
||||||
|
* @param array $options
|
||||||
|
* @return null|ISchemaWrapper
|
||||||
|
* @since 13.0.0
|
||||||
|
*/
|
||||||
|
public function changeSchema(IOutput $output,
|
||||||
|
\Closure $schemaClosure,
|
||||||
|
array $options):?ISchemaWrapper {
|
||||||
|
/** @var ISchemaWrapper $schema */
|
||||||
|
$schema = $schemaClosure();
|
||||||
|
|
||||||
|
if (!$schema->hasTable('calendar_reminders')) {
|
||||||
|
$table = $schema->createTable('calendar_reminders');
|
||||||
|
|
||||||
|
$table->addColumn('id', Type::BIGINT, [
|
||||||
|
'autoincrement' => true,
|
||||||
|
'notnull' => true,
|
||||||
|
'length' => 11,
|
||||||
|
'unsigned' => true,
|
||||||
|
]);
|
||||||
|
$table->addColumn('calendar_id', Type::BIGINT, [
|
||||||
|
'notnull' => true,
|
||||||
|
'length' => 11,
|
||||||
|
]);
|
||||||
|
$table->addColumn('object_id', Type::BIGINT, [
|
||||||
|
'notnull' => true,
|
||||||
|
'length' => 11,
|
||||||
|
]);
|
||||||
|
$table->addColumn('is_recurring', Type::SMALLINT, [
|
||||||
|
'notnull' => true,
|
||||||
|
'length' => 1,
|
||||||
|
]);
|
||||||
|
$table->addColumn('uid', Type::STRING, [
|
||||||
|
'notnull' => true,
|
||||||
|
'length' => 255,
|
||||||
|
]);
|
||||||
|
$table->addColumn('recurrence_id', Type::BIGINT, [
|
||||||
|
'notnull' => false,
|
||||||
|
'length' => 11,
|
||||||
|
'unsigned' => true,
|
||||||
|
]);
|
||||||
|
$table->addColumn('is_recurrence_exception', Type::SMALLINT, [
|
||||||
|
'notnull' => true,
|
||||||
|
'length' => 1,
|
||||||
|
]);
|
||||||
|
$table->addColumn('event_hash', Type::STRING, [
|
||||||
|
'notnull' => true,
|
||||||
|
'length' => 255,
|
||||||
|
]);
|
||||||
|
$table->addColumn('alarm_hash', Type::STRING, [
|
||||||
|
'notnull' => true,
|
||||||
|
'length' => 255,
|
||||||
|
]);
|
||||||
|
$table->addColumn('type', Type::STRING, [
|
||||||
|
'notnull' => true,
|
||||||
|
'length' => 255,
|
||||||
|
]);
|
||||||
|
$table->addColumn('is_relative', Type::SMALLINT, [
|
||||||
|
'notnull' => true,
|
||||||
|
'length' => 1,
|
||||||
|
]);
|
||||||
|
$table->addColumn('notification_date', Type::BIGINT, [
|
||||||
|
'notnull' => true,
|
||||||
|
'length' => 11,
|
||||||
|
'unsigned' => true,
|
||||||
|
]);
|
||||||
|
$table->addColumn('is_repeat_based', Type::SMALLINT, [
|
||||||
|
'notnull' => true,
|
||||||
|
'length' => 1,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$table->setPrimaryKey(['id']);
|
||||||
|
$table->addIndex(['object_id'], 'calendar_reminder_objid');
|
||||||
|
$table->addIndex(['uid', 'recurrence_id'], 'calendar_reminder_uidrec');
|
||||||
|
|
||||||
|
return $schema;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -48,6 +48,7 @@ class CalDAVSettings implements ISettings {
|
||||||
$parameters = [
|
$parameters = [
|
||||||
'send_invitations' => $this->config->getAppValue('dav', 'sendInvitations', 'yes'),
|
'send_invitations' => $this->config->getAppValue('dav', 'sendInvitations', 'yes'),
|
||||||
'generate_birthday_calendar' => $this->config->getAppValue('dav', 'generateBirthdayCalendar', 'yes'),
|
'generate_birthday_calendar' => $this->config->getAppValue('dav', 'generateBirthdayCalendar', 'yes'),
|
||||||
|
'send_reminders_notifications' => $this->config->getAppValue('dav', 'sendEventReminders', 'yes'),
|
||||||
];
|
];
|
||||||
|
|
||||||
return new TemplateResponse('dav', 'settings-admin-caldav', $parameters);
|
return new TemplateResponse('dav', 'settings-admin-caldav', $parameters);
|
||||||
|
|
|
@ -72,4 +72,25 @@ script('dav', [
|
||||||
<em><?php p($l->t('Birthday calendars will be generated by a background job.')); ?></em><br>
|
<em><?php p($l->t('Birthday calendars will be generated by a background job.')); ?></em><br>
|
||||||
<em><?php p($l->t('Hence they will not be available immediately after enabling but will show up after some time.')); ?></em>
|
<em><?php p($l->t('Hence they will not be available immediately after enabling but will show up after some time.')); ?></em>
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
<input type="checkbox" name="caldav_send_reminders_notifications" id="caldavSendRemindersNotifications" class="checkbox"
|
||||||
|
<?php ($_['send_reminders_notifications'] === 'yes') ? print_unescaped('checked="checked"') : null ?>/>
|
||||||
|
<label for="caldavSendRemindersNotifications"><?php p($l->t('Send notifications for events')); ?></label>
|
||||||
|
<br>
|
||||||
|
<em>
|
||||||
|
<?php print_unescaped(str_replace(
|
||||||
|
[
|
||||||
|
'{emailopen}',
|
||||||
|
'{linkclose}',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'<a href="../admin#mail_general_settings">',
|
||||||
|
'</a>',
|
||||||
|
],
|
||||||
|
$l->t('Please make sure to properly set up {emailopen}the email server{linkclose}.')
|
||||||
|
)); ?>
|
||||||
|
</em>
|
||||||
|
<br>
|
||||||
|
<em><?php p($l->t('Notifications will be send through background jobs, so these need to happen often enough.')); ?></em>
|
||||||
|
</p>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* @copyright 2018, Thomas Citharel <tcit@tcit.fr>
|
||||||
|
*
|
||||||
|
* @author Thomas Citharel <tcit@tcit.fr>
|
||||||
|
*
|
||||||
|
* @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\Tests\unit\BackgroundJob;
|
||||||
|
|
||||||
|
use OCA\DAV\BackgroundJob\EventReminderJob;
|
||||||
|
use OCA\DAV\CalDAV\Reminder\ReminderService;
|
||||||
|
use OCP\IConfig;
|
||||||
|
use Test\TestCase;
|
||||||
|
|
||||||
|
class EventReminderJobTest extends TestCase {
|
||||||
|
|
||||||
|
/** @var ReminderService|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
private $reminderService;
|
||||||
|
|
||||||
|
/** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
private $config;
|
||||||
|
|
||||||
|
/** @var EventReminderJob|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
private $backgroundJob;
|
||||||
|
|
||||||
|
protected function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->reminderService = $this->createMock(ReminderService::class);
|
||||||
|
$this->config = $this->createMock(IConfig::class);
|
||||||
|
|
||||||
|
$this->backgroundJob = new EventReminderJob($this->reminderService, $this->config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function data(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[true, true, true],
|
||||||
|
[true, false, false],
|
||||||
|
[false, true, false],
|
||||||
|
[false, false, false],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider data
|
||||||
|
*
|
||||||
|
* @param bool $sendEventReminders
|
||||||
|
* @param bool $sendEventRemindersMode
|
||||||
|
* @param bool $expectCall
|
||||||
|
*/
|
||||||
|
public function testRun(bool $sendEventReminders, bool $sendEventRemindersMode, bool $expectCall): void {
|
||||||
|
$this->config->expects($this->at(0))
|
||||||
|
->method('getAppValue')
|
||||||
|
->with('dav', 'sendEventReminders', 'yes')
|
||||||
|
->willReturn($sendEventReminders ? 'yes' : 'no');
|
||||||
|
|
||||||
|
if ($sendEventReminders) {
|
||||||
|
$this->config->expects($this->at(1))
|
||||||
|
->method('getAppValue')
|
||||||
|
->with('dav', 'sendEventRemindersMode', 'backgroundjob')
|
||||||
|
->willReturn($sendEventRemindersMode ? 'backgroundjob' : 'cron');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($expectCall) {
|
||||||
|
$this->reminderService->expects($this->once())
|
||||||
|
->method('processReminders');
|
||||||
|
} else {
|
||||||
|
$this->reminderService->expects($this->never())
|
||||||
|
->method('processReminders');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->backgroundJob->run([]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,397 @@
|
||||||
|
<?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 AGPL-3.0
|
||||||
|
*
|
||||||
|
* This code is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* 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, version 3,
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace OCA\DAV\Tests\unit\CalDAV\Reminder;
|
||||||
|
|
||||||
|
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||||
|
use OCP\AppFramework\Utility\ITimeFactory;
|
||||||
|
use OCA\DAV\CalDAV\Reminder\Backend as ReminderBackend;
|
||||||
|
use Test\TestCase;
|
||||||
|
|
||||||
|
class BackendTest extends TestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reminder Backend
|
||||||
|
*
|
||||||
|
* @var ReminderBackend|\PHPUnit\Framework\MockObject\MockObject
|
||||||
|
*/
|
||||||
|
private $reminderBackend;
|
||||||
|
|
||||||
|
/** @var ITimeFactory|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
private $timeFactory;
|
||||||
|
|
||||||
|
public function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$query = self::$realDatabase->getQueryBuilder();
|
||||||
|
$query->delete('calendar_reminders')->execute();
|
||||||
|
$query->delete('calendarobjects')->execute();
|
||||||
|
$query->delete('calendars')->execute();
|
||||||
|
|
||||||
|
$this->timeFactory = $this->createMock(ITimeFactory::class);
|
||||||
|
$this->reminderBackend = new ReminderBackend(self::$realDatabase, $this->timeFactory);
|
||||||
|
|
||||||
|
$this->createRemindersTestSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown() {
|
||||||
|
$query = self::$realDatabase->getQueryBuilder();
|
||||||
|
$query->delete('calendar_reminders')->execute();
|
||||||
|
$query->delete('calendarobjects')->execute();
|
||||||
|
$query->delete('calendars')->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function testCleanRemindersForEvent(): void {
|
||||||
|
$query = self::$realDatabase->getQueryBuilder();
|
||||||
|
$rows = $query->select('*')
|
||||||
|
->from('calendar_reminders')
|
||||||
|
->execute()
|
||||||
|
->fetchAll();
|
||||||
|
|
||||||
|
$this->assertCount(4, $rows);
|
||||||
|
|
||||||
|
$this->reminderBackend->cleanRemindersForEvent(1);
|
||||||
|
|
||||||
|
$query = self::$realDatabase->getQueryBuilder();
|
||||||
|
$rows = $query->select('*')
|
||||||
|
->from('calendar_reminders')
|
||||||
|
->execute()
|
||||||
|
->fetchAll();
|
||||||
|
|
||||||
|
$this->assertCount(2, $rows);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCleanRemindersForCalendar(): void {
|
||||||
|
$query = self::$realDatabase->getQueryBuilder();
|
||||||
|
$rows = $query->select('*')
|
||||||
|
->from('calendar_reminders')
|
||||||
|
->execute()
|
||||||
|
->fetchAll();
|
||||||
|
|
||||||
|
$this->assertCount(4, $rows);
|
||||||
|
|
||||||
|
$this->reminderBackend->cleanRemindersForCalendar(1);
|
||||||
|
|
||||||
|
$query = self::$realDatabase->getQueryBuilder();
|
||||||
|
$rows = $query->select('*')
|
||||||
|
->from('calendar_reminders')
|
||||||
|
->execute()
|
||||||
|
->fetchAll();
|
||||||
|
|
||||||
|
$this->assertCount(1, $rows);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRemoveReminder(): void {
|
||||||
|
$query = self::$realDatabase->getQueryBuilder();
|
||||||
|
$rows = $query->select('*')
|
||||||
|
->from('calendar_reminders')
|
||||||
|
->execute()
|
||||||
|
->fetchAll();
|
||||||
|
|
||||||
|
$this->assertCount(4, $rows);
|
||||||
|
|
||||||
|
$this->reminderBackend->removeReminder((int) $rows[3]['id']);
|
||||||
|
|
||||||
|
$query = self::$realDatabase->getQueryBuilder();
|
||||||
|
$rows = $query->select('*')
|
||||||
|
->from('calendar_reminders')
|
||||||
|
->execute()
|
||||||
|
->fetchAll();
|
||||||
|
|
||||||
|
$this->assertCount(3, $rows);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetRemindersToProcess(): void {
|
||||||
|
$this->timeFactory->expects($this->exactly(1))
|
||||||
|
->method('getTime')
|
||||||
|
->with()
|
||||||
|
->willReturn(123457);
|
||||||
|
|
||||||
|
$rows = $this->reminderBackend->getRemindersToProcess();
|
||||||
|
|
||||||
|
$this->assertCount(2, $rows);
|
||||||
|
unset($rows[0]['id']);
|
||||||
|
unset($rows[1]['id']);
|
||||||
|
|
||||||
|
$this->assertEquals($rows[0], [
|
||||||
|
'calendar_id' => 1,
|
||||||
|
'object_id' => 1,
|
||||||
|
'uid' => 'asd',
|
||||||
|
'is_recurring' => false,
|
||||||
|
'recurrence_id' => 123458,
|
||||||
|
'is_recurrence_exception' => false,
|
||||||
|
'event_hash' => 'asd123',
|
||||||
|
'alarm_hash' => 'asd567',
|
||||||
|
'type' => 'EMAIL',
|
||||||
|
'is_relative' => true,
|
||||||
|
'notification_date' => 123456,
|
||||||
|
'is_repeat_based' => false,
|
||||||
|
'calendardata' => 'Calendar data 123',
|
||||||
|
'displayname' => 'Displayname 123',
|
||||||
|
'principaluri' => 'principals/users/user001',
|
||||||
|
]);
|
||||||
|
$this->assertEquals($rows[1], [
|
||||||
|
'calendar_id' => 1,
|
||||||
|
'object_id' => 1,
|
||||||
|
'uid' => 'asd',
|
||||||
|
'is_recurring' => false,
|
||||||
|
'recurrence_id' => 123458,
|
||||||
|
'is_recurrence_exception' => false,
|
||||||
|
'event_hash' => 'asd123',
|
||||||
|
'alarm_hash' => 'asd567',
|
||||||
|
'type' => 'AUDIO',
|
||||||
|
'is_relative' => true,
|
||||||
|
'notification_date' => 123456,
|
||||||
|
'is_repeat_based' => false,
|
||||||
|
'calendardata' => 'Calendar data 123',
|
||||||
|
'displayname' => 'Displayname 123',
|
||||||
|
'principaluri' => 'principals/users/user001',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetAllScheduledRemindersForEvent(): void {
|
||||||
|
$rows = $this->reminderBackend->getAllScheduledRemindersForEvent(1);
|
||||||
|
|
||||||
|
$this->assertCount(2, $rows);
|
||||||
|
unset($rows[0]['id']);
|
||||||
|
unset($rows[1]['id']);
|
||||||
|
|
||||||
|
$this->assertEquals($rows[0], [
|
||||||
|
'calendar_id' => 1,
|
||||||
|
'object_id' => 1,
|
||||||
|
'uid' => 'asd',
|
||||||
|
'is_recurring' => false,
|
||||||
|
'recurrence_id' => 123458,
|
||||||
|
'is_recurrence_exception' => false,
|
||||||
|
'event_hash' => 'asd123',
|
||||||
|
'alarm_hash' => 'asd567',
|
||||||
|
'type' => 'EMAIL',
|
||||||
|
'is_relative' => true,
|
||||||
|
'notification_date' => 123456,
|
||||||
|
'is_repeat_based' => false,
|
||||||
|
]);
|
||||||
|
$this->assertEquals($rows[1], [
|
||||||
|
'calendar_id' => 1,
|
||||||
|
'object_id' => 1,
|
||||||
|
'uid' => 'asd',
|
||||||
|
'is_recurring' => false,
|
||||||
|
'recurrence_id' => 123458,
|
||||||
|
'is_recurrence_exception' => false,
|
||||||
|
'event_hash' => 'asd123',
|
||||||
|
'alarm_hash' => 'asd567',
|
||||||
|
'type' => 'AUDIO',
|
||||||
|
'is_relative' => true,
|
||||||
|
'notification_date' => 123456,
|
||||||
|
'is_repeat_based' => false,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInsertReminder(): void {
|
||||||
|
$query = self::$realDatabase->getQueryBuilder();
|
||||||
|
$rows = $query->select('*')
|
||||||
|
->from('calendar_reminders')
|
||||||
|
->execute()
|
||||||
|
->fetchAll();
|
||||||
|
|
||||||
|
$this->assertCount(4, $rows);
|
||||||
|
|
||||||
|
$this->reminderBackend->insertReminder(42, 1337, 'uid99', true, 12345678,
|
||||||
|
true, 'hash99', 'hash42', 'AUDIO', false, 12345670, false);
|
||||||
|
|
||||||
|
$query = self::$realDatabase->getQueryBuilder();
|
||||||
|
$rows = $query->select('*')
|
||||||
|
->from('calendar_reminders')
|
||||||
|
->execute()
|
||||||
|
->fetchAll();
|
||||||
|
|
||||||
|
$this->assertCount(5, $rows);
|
||||||
|
|
||||||
|
unset($rows[4]['id']);
|
||||||
|
|
||||||
|
$this->assertEquals($rows[4], [
|
||||||
|
'calendar_id' => '42',
|
||||||
|
'object_id' => '1337',
|
||||||
|
'is_recurring' => '1',
|
||||||
|
'uid' => 'uid99',
|
||||||
|
'recurrence_id' => '12345678',
|
||||||
|
'is_recurrence_exception' => '1',
|
||||||
|
'event_hash' => 'hash99',
|
||||||
|
'alarm_hash' => 'hash42',
|
||||||
|
'type' => 'AUDIO',
|
||||||
|
'is_relative' => '0',
|
||||||
|
'notification_date' => '12345670',
|
||||||
|
'is_repeat_based' => '0',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUpdateReminder() {
|
||||||
|
$query = self::$realDatabase->getQueryBuilder();
|
||||||
|
$rows = $query->select('*')
|
||||||
|
->from('calendar_reminders')
|
||||||
|
->execute()
|
||||||
|
->fetchAll();
|
||||||
|
|
||||||
|
$this->assertCount(4, $rows);
|
||||||
|
|
||||||
|
$this->assertEquals($rows[3]['notification_date'], 123600);
|
||||||
|
|
||||||
|
$reminderId = (int) $rows[3]['id'];
|
||||||
|
$newNotificationDate = 123700;
|
||||||
|
|
||||||
|
$this->reminderBackend->updateReminder($reminderId, $newNotificationDate);
|
||||||
|
|
||||||
|
$query = self::$realDatabase->getQueryBuilder();
|
||||||
|
$row = $query->select('notification_date')
|
||||||
|
->from('calendar_reminders')
|
||||||
|
->where($query->expr()->eq('id', $query->createNamedParameter($reminderId)))
|
||||||
|
->execute()
|
||||||
|
->fetch();
|
||||||
|
|
||||||
|
$this->assertEquals((int) $row['notification_date'], 123700);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function createRemindersTestSet(): void {
|
||||||
|
$query = self::$realDatabase->getQueryBuilder();
|
||||||
|
$query->insert('calendars')
|
||||||
|
->values([
|
||||||
|
'id' => $query->createNamedParameter(1),
|
||||||
|
'principaluri' => $query->createNamedParameter('principals/users/user001'),
|
||||||
|
'displayname' => $query->createNamedParameter('Displayname 123'),
|
||||||
|
])
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$query = self::$realDatabase->getQueryBuilder();
|
||||||
|
$query->insert('calendars')
|
||||||
|
->values([
|
||||||
|
'id' => $query->createNamedParameter(99),
|
||||||
|
'principaluri' => $query->createNamedParameter('principals/users/user002'),
|
||||||
|
'displayname' => $query->createNamedParameter('Displayname 99'),
|
||||||
|
])
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$query = self::$realDatabase->getQueryBuilder();
|
||||||
|
$query->insert('calendarobjects')
|
||||||
|
->values([
|
||||||
|
'id' => $query->createNamedParameter(1),
|
||||||
|
'calendardata' => $query->createNamedParameter('Calendar data 123'),
|
||||||
|
'calendarid' => $query->createNamedParameter(1),
|
||||||
|
'size' => $query->createNamedParameter(42),
|
||||||
|
])
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$query = self::$realDatabase->getQueryBuilder();
|
||||||
|
$query->insert('calendarobjects')
|
||||||
|
->values([
|
||||||
|
'id' => $query->createNamedParameter(2),
|
||||||
|
'calendardata' => $query->createNamedParameter('Calendar data 456'),
|
||||||
|
'calendarid' => $query->createNamedParameter(1),
|
||||||
|
'size' => $query->createNamedParameter(42),
|
||||||
|
])
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$query = self::$realDatabase->getQueryBuilder();
|
||||||
|
$query->insert('calendarobjects')
|
||||||
|
->values([
|
||||||
|
'id' => $query->createNamedParameter(10),
|
||||||
|
'calendardata' => $query->createNamedParameter('Calendar data 789'),
|
||||||
|
'calendarid' => $query->createNamedParameter(99),
|
||||||
|
'size' => $query->createNamedParameter(42),
|
||||||
|
])
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$query = self::$realDatabase->getQueryBuilder();
|
||||||
|
$query->insert('calendar_reminders')
|
||||||
|
->values([
|
||||||
|
'calendar_id' => $query->createNamedParameter(1),
|
||||||
|
'object_id' => $query->createNamedParameter(1),
|
||||||
|
'uid' => $query->createNamedParameter('asd'),
|
||||||
|
'is_recurring' => $query->createNamedParameter(0),
|
||||||
|
'recurrence_id' => $query->createNamedParameter(123458),
|
||||||
|
'is_recurrence_exception' => $query->createNamedParameter(0),
|
||||||
|
'event_hash' => $query->createNamedParameter('asd123'),
|
||||||
|
'alarm_hash' => $query->createNamedParameter('asd567'),
|
||||||
|
'type' => $query->createNamedParameter('EMAIL'),
|
||||||
|
'is_relative' => $query->createNamedParameter(1),
|
||||||
|
'notification_date' => $query->createNamedParameter(123456),
|
||||||
|
'is_repeat_based' => $query->createNamedParameter(0),
|
||||||
|
])
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$query = self::$realDatabase->getQueryBuilder();
|
||||||
|
$query->insert('calendar_reminders')
|
||||||
|
->values([
|
||||||
|
'calendar_id' => $query->createNamedParameter(1),
|
||||||
|
'object_id' => $query->createNamedParameter(1),
|
||||||
|
'uid' => $query->createNamedParameter('asd'),
|
||||||
|
'is_recurring' => $query->createNamedParameter(0),
|
||||||
|
'recurrence_id' => $query->createNamedParameter(123458),
|
||||||
|
'is_recurrence_exception' => $query->createNamedParameter(0),
|
||||||
|
'event_hash' => $query->createNamedParameter('asd123'),
|
||||||
|
'alarm_hash' => $query->createNamedParameter('asd567'),
|
||||||
|
'type' => $query->createNamedParameter('AUDIO'),
|
||||||
|
'is_relative' => $query->createNamedParameter(1),
|
||||||
|
'notification_date' => $query->createNamedParameter(123456),
|
||||||
|
'is_repeat_based' => $query->createNamedParameter(0),
|
||||||
|
])
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$query = self::$realDatabase->getQueryBuilder();
|
||||||
|
$query->insert('calendar_reminders')
|
||||||
|
->values([
|
||||||
|
'calendar_id' => $query->createNamedParameter(1),
|
||||||
|
'object_id' => $query->createNamedParameter(2),
|
||||||
|
'uid' => $query->createNamedParameter('asd'),
|
||||||
|
'is_recurring' => $query->createNamedParameter(0),
|
||||||
|
'recurrence_id' => $query->createNamedParameter(123900),
|
||||||
|
'is_recurrence_exception' => $query->createNamedParameter(0),
|
||||||
|
'event_hash' => $query->createNamedParameter('asd123'),
|
||||||
|
'alarm_hash' => $query->createNamedParameter('asd567'),
|
||||||
|
'type' => $query->createNamedParameter('EMAIL'),
|
||||||
|
'is_relative' => $query->createNamedParameter(1),
|
||||||
|
'notification_date' => $query->createNamedParameter(123499),
|
||||||
|
'is_repeat_based' => $query->createNamedParameter(0),
|
||||||
|
])
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$query = self::$realDatabase->getQueryBuilder();
|
||||||
|
$query->insert('calendar_reminders')
|
||||||
|
->values([
|
||||||
|
'calendar_id' => $query->createNamedParameter(99),
|
||||||
|
'object_id' => $query->createNamedParameter(10),
|
||||||
|
'uid' => $query->createNamedParameter('asd'),
|
||||||
|
'is_recurring' => $query->createNamedParameter(0),
|
||||||
|
'recurrence_id' => $query->createNamedParameter(123900),
|
||||||
|
'is_recurrence_exception' => $query->createNamedParameter(0),
|
||||||
|
'event_hash' => $query->createNamedParameter('asd123'),
|
||||||
|
'alarm_hash' => $query->createNamedParameter('asd567'),
|
||||||
|
'type' => $query->createNamedParameter('DISPLAY'),
|
||||||
|
'is_relative' => $query->createNamedParameter(1),
|
||||||
|
'notification_date' => $query->createNamedParameter(123600),
|
||||||
|
'is_repeat_based' => $query->createNamedParameter(0),
|
||||||
|
])
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2019, Thomas Citharel
|
||||||
|
*
|
||||||
|
* @author Thomas Citharel <tcit@tcit.fr>
|
||||||
|
*
|
||||||
|
* @license AGPL-3.0
|
||||||
|
*
|
||||||
|
* This code is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* 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, version 3,
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace OCA\DAV\Tests\unit\CalDAV\Reminder\NotificationProvider;
|
||||||
|
|
||||||
|
use OCA\DAV\CalDAV\Reminder\NotificationProvider\AbstractProvider;
|
||||||
|
use OCP\IConfig;
|
||||||
|
use OCP\IL10N;
|
||||||
|
use OCP\ILogger;
|
||||||
|
use OCP\IURLGenerator;
|
||||||
|
use OCP\L10N\IFactory as L10NFactory;
|
||||||
|
use OCP\IUser;
|
||||||
|
use Test\TestCase;
|
||||||
|
use Sabre\VObject\Component\VCalendar;
|
||||||
|
|
||||||
|
abstract class AbstractNotificationProviderTest extends TestCase {
|
||||||
|
|
||||||
|
/** @var ILogger|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
protected $logger;
|
||||||
|
|
||||||
|
/** @var L10NFactory|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
protected $l10nFactory;
|
||||||
|
|
||||||
|
/** @var IL10N|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
protected $l10n;
|
||||||
|
|
||||||
|
/** @var IURLGenerator|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
protected $urlGenerator;
|
||||||
|
|
||||||
|
/** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
protected $config;
|
||||||
|
|
||||||
|
/** @var AbstractProvider|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
protected $provider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var VCalendar
|
||||||
|
*/
|
||||||
|
protected $vcalendar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $calendarDisplayName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var IUser|\PHPUnit\Framework\MockObject\MockObject
|
||||||
|
*/
|
||||||
|
protected $user;
|
||||||
|
|
||||||
|
public function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->logger = $this->createMock(ILogger::class);
|
||||||
|
$this->l10nFactory = $this->createMock(L10NFactory::class);
|
||||||
|
$this->l10n = $this->createMock(IL10N::class);
|
||||||
|
$this->urlGenerator = $this->createMock(IURLGenerator::class);
|
||||||
|
$this->config = $this->createMock(IConfig::class);
|
||||||
|
|
||||||
|
$this->vcalendar = new VCalendar();
|
||||||
|
$this->vcalendar->add('VEVENT', [
|
||||||
|
'SUMMARY' => 'Fellowship meeting',
|
||||||
|
'DTSTART' => new \DateTime('2017-01-01 00:00:00+00:00'), // 1483228800,
|
||||||
|
'UID' => 'uid1234',
|
||||||
|
]);
|
||||||
|
$this->calendarDisplayName = 'Personal';
|
||||||
|
|
||||||
|
$this->user = $this->createMock(IUser::class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2019, Georg Ehrke
|
||||||
|
*
|
||||||
|
* @author Georg Ehrke <oc.list@georgehrke.com>
|
||||||
|
*
|
||||||
|
* @license AGPL-3.0
|
||||||
|
*
|
||||||
|
* This code is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* 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, version 3,
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace OCA\DAV\Tests\unit\CalDAV\Reminder\NotificationProvider;
|
||||||
|
|
||||||
|
use OCA\DAV\CalDAV\Reminder\NotificationProvider\AudioProvider;
|
||||||
|
|
||||||
|
class AudioProviderTest extends PushProviderTest {
|
||||||
|
|
||||||
|
public function testNotificationType():void {
|
||||||
|
$this->assertEquals(AudioProvider::NOTIFICATION_TYPE, 'AUDIO');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,546 @@
|
||||||
|
<?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 AGPL-3.0
|
||||||
|
*
|
||||||
|
* This code is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* 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, version 3,
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace OCA\DAV\Tests\unit\CalDAV\Reminder\NotificationProvider;
|
||||||
|
|
||||||
|
use OCA\DAV\CalDAV\Reminder\NotificationProvider\EmailProvider;
|
||||||
|
use OCP\IConfig;
|
||||||
|
use OCP\IL10N;
|
||||||
|
use OCP\ILogger;
|
||||||
|
use OCP\IURLGenerator;
|
||||||
|
use OCP\L10N\IFactory as L10NFactory;
|
||||||
|
use OCP\IUser;
|
||||||
|
use OCP\Mail\IEMailTemplate;
|
||||||
|
use OCP\Mail\IMailer;
|
||||||
|
use OCP\Mail\IAttachment;
|
||||||
|
use OCP\Mail\IMessage;
|
||||||
|
use Sabre\VObject\Component\VCalendar;
|
||||||
|
use Test\TestCase;
|
||||||
|
|
||||||
|
class EmailProviderTest extends AbstractNotificationProviderTest {
|
||||||
|
|
||||||
|
const USER_EMAIL = 'frodo@hobb.it';
|
||||||
|
|
||||||
|
/** @var ILogger|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
protected $logger;
|
||||||
|
|
||||||
|
/** @var L10NFactory|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
protected $l10nFactory;
|
||||||
|
|
||||||
|
/** @var IL10N|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
protected $l10n;
|
||||||
|
|
||||||
|
/** @var IURLGenerator|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
protected $urlGenerator;
|
||||||
|
|
||||||
|
/** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
protected $config;
|
||||||
|
|
||||||
|
/** @var IMailer|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
private $mailer;
|
||||||
|
|
||||||
|
public function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->mailer = $this->createMock(IMailer::class);
|
||||||
|
|
||||||
|
$this->provider = new EmailProvider(
|
||||||
|
$this->config,
|
||||||
|
$this->mailer,
|
||||||
|
$this->logger,
|
||||||
|
$this->l10nFactory,
|
||||||
|
$this->urlGenerator
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSendWithoutAttendees():void {
|
||||||
|
$user1 = $this->createMock(IUser::class);
|
||||||
|
$user1->method('getUID')
|
||||||
|
->willReturn('uid1');
|
||||||
|
$user1->method('getEMailAddress')
|
||||||
|
->willReturn('uid1@example.com');
|
||||||
|
$user2 = $this->createMock(IUser::class);
|
||||||
|
$user2->method('getUID')
|
||||||
|
->willReturn('uid2');
|
||||||
|
$user2->method('getEMailAddress')
|
||||||
|
->willReturn('uid2@example.com');
|
||||||
|
$user3 = $this->createMock(IUser::class);
|
||||||
|
$user3->method('getUID')
|
||||||
|
->willReturn('uid3');
|
||||||
|
$user3->method('getEMailAddress')
|
||||||
|
->willReturn('uid3@example.com');
|
||||||
|
$user4 = $this->createMock(IUser::class);
|
||||||
|
$user4->method('getUID')
|
||||||
|
->willReturn('uid4');
|
||||||
|
$user4->method('getEMailAddress')
|
||||||
|
->willReturn(null);
|
||||||
|
|
||||||
|
$users = [$user1, $user2, $user3, $user4];
|
||||||
|
|
||||||
|
$this->config->expects($this->at(0))
|
||||||
|
->method('getUserValue')
|
||||||
|
->with('uid1', 'core', 'lang', null)
|
||||||
|
->willReturn(null);
|
||||||
|
$this->config->expects($this->at(1))
|
||||||
|
->method('getUserValue')
|
||||||
|
->with('uid2', 'core', 'lang', null)
|
||||||
|
->willReturn('de');
|
||||||
|
$this->config->expects($this->at(2))
|
||||||
|
->method('getUserValue')
|
||||||
|
->with('uid3', 'core', 'lang', null)
|
||||||
|
->willReturn('de');
|
||||||
|
|
||||||
|
$enL10N = $this->createMock(IL10N::class);
|
||||||
|
$enL10N->method('t')
|
||||||
|
->will($this->returnArgument(0));
|
||||||
|
$enL10N->method('l')
|
||||||
|
->will($this->returnArgument(0));
|
||||||
|
|
||||||
|
$deL10N = $this->createMock(IL10N::class);
|
||||||
|
$deL10N->method('t')
|
||||||
|
->will($this->returnArgument(0));
|
||||||
|
$deL10N->method('l')
|
||||||
|
->will($this->returnArgument(0));
|
||||||
|
|
||||||
|
$this->l10nFactory->expects($this->at(0))
|
||||||
|
->method('findLanguage')
|
||||||
|
->with()
|
||||||
|
->willReturn('en');
|
||||||
|
|
||||||
|
$this->l10nFactory->expects($this->at(1))
|
||||||
|
->method('languageExists')
|
||||||
|
->with('dav', 'en')
|
||||||
|
->willReturn(true);
|
||||||
|
|
||||||
|
$this->l10nFactory->expects($this->at(2))
|
||||||
|
->method('get')
|
||||||
|
->with('dav', 'en')
|
||||||
|
->willReturn($enL10N);
|
||||||
|
|
||||||
|
$this->l10nFactory->expects($this->at(3))
|
||||||
|
->method('languageExists')
|
||||||
|
->with('dav', 'de')
|
||||||
|
->willReturn(true);
|
||||||
|
|
||||||
|
$this->l10nFactory->expects($this->at(4))
|
||||||
|
->method('get')
|
||||||
|
->with('dav', 'de')
|
||||||
|
->willReturn($deL10N);
|
||||||
|
|
||||||
|
$template1 = $this->getTemplateMock();
|
||||||
|
$message11 = $this->getMessageMock('uid1@example.com', $template1);
|
||||||
|
$template2 = $this->getTemplateMock();
|
||||||
|
$message21 = $this->getMessageMock('uid2@example.com', $template2);
|
||||||
|
$message22 = $this->getMessageMock('uid3@example.com', $template2);
|
||||||
|
|
||||||
|
$this->mailer->expects($this->at(0))
|
||||||
|
->method('createEMailTemplate')
|
||||||
|
->with('dav.calendarReminder')
|
||||||
|
->willReturn($template1);
|
||||||
|
|
||||||
|
$this->mailer->expects($this->at(1))
|
||||||
|
->method('createMessage')
|
||||||
|
->with()
|
||||||
|
->willReturn($message11);
|
||||||
|
$this->mailer->expects($this->at(2))
|
||||||
|
->method('send')
|
||||||
|
->with($message11)
|
||||||
|
->willReturn([]);
|
||||||
|
|
||||||
|
$this->mailer->expects($this->at(3))
|
||||||
|
->method('createEMailTemplate')
|
||||||
|
->with('dav.calendarReminder')
|
||||||
|
->willReturn($template2);
|
||||||
|
|
||||||
|
$this->mailer->expects($this->at(4))
|
||||||
|
->method('createMessage')
|
||||||
|
->with()
|
||||||
|
->willReturn($message21);
|
||||||
|
$this->mailer->expects($this->at(5))
|
||||||
|
->method('send')
|
||||||
|
->with($message21)
|
||||||
|
->willReturn([]);
|
||||||
|
$this->mailer->expects($this->at(6))
|
||||||
|
->method('createMessage')
|
||||||
|
->with()
|
||||||
|
->willReturn($message22);
|
||||||
|
$this->mailer->expects($this->at(7))
|
||||||
|
->method('send')
|
||||||
|
->with($message22)
|
||||||
|
->willReturn([]);
|
||||||
|
|
||||||
|
$this->setupURLGeneratorMock(2);
|
||||||
|
|
||||||
|
$vcalendar = $this->getNoAttendeeVCalendar();
|
||||||
|
$this->provider->send($vcalendar->VEVENT, $this->calendarDisplayName, $users);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSendWithAttendees(): void {
|
||||||
|
$user1 = $this->createMock(IUser::class);
|
||||||
|
$user1->method('getUID')
|
||||||
|
->willReturn('uid1');
|
||||||
|
$user1->method('getEMailAddress')
|
||||||
|
->willReturn('uid1@example.com');
|
||||||
|
$user2 = $this->createMock(IUser::class);
|
||||||
|
$user2->method('getUID')
|
||||||
|
->willReturn('uid2');
|
||||||
|
$user2->method('getEMailAddress')
|
||||||
|
->willReturn('uid2@example.com');
|
||||||
|
$user3 = $this->createMock(IUser::class);
|
||||||
|
$user3->method('getUID')
|
||||||
|
->willReturn('uid3');
|
||||||
|
$user3->method('getEMailAddress')
|
||||||
|
->willReturn('uid3@example.com');
|
||||||
|
$user4 = $this->createMock(IUser::class);
|
||||||
|
$user4->method('getUID')
|
||||||
|
->willReturn('uid4');
|
||||||
|
$user4->method('getEMailAddress')
|
||||||
|
->willReturn(null);
|
||||||
|
|
||||||
|
$users = [$user1, $user2, $user3, $user4];
|
||||||
|
|
||||||
|
$this->config->expects($this->at(0))
|
||||||
|
->method('getUserValue')
|
||||||
|
->with('uid1', 'core', 'lang', null)
|
||||||
|
->willReturn(null);
|
||||||
|
$this->config->expects($this->at(1))
|
||||||
|
->method('getUserValue')
|
||||||
|
->with('uid2', 'core', 'lang', null)
|
||||||
|
->willReturn('de');
|
||||||
|
$this->config->expects($this->at(2))
|
||||||
|
->method('getUserValue')
|
||||||
|
->with('uid3', 'core', 'lang', null)
|
||||||
|
->willReturn('de');
|
||||||
|
|
||||||
|
$enL10N = $this->createMock(IL10N::class);
|
||||||
|
$enL10N->method('t')
|
||||||
|
->will($this->returnArgument(0));
|
||||||
|
$enL10N->method('l')
|
||||||
|
->will($this->returnArgument(0));
|
||||||
|
|
||||||
|
$deL10N = $this->createMock(IL10N::class);
|
||||||
|
$deL10N->method('t')
|
||||||
|
->will($this->returnArgument(0));
|
||||||
|
$deL10N->method('l')
|
||||||
|
->will($this->returnArgument(0));
|
||||||
|
|
||||||
|
$this->l10nFactory->expects($this->at(0))
|
||||||
|
->method('findLanguage')
|
||||||
|
->with()
|
||||||
|
->willReturn('en');
|
||||||
|
|
||||||
|
$this->l10nFactory->expects($this->at(1))
|
||||||
|
->method('languageExists')
|
||||||
|
->with('dav', 'de')
|
||||||
|
->willReturn(true);
|
||||||
|
|
||||||
|
$this->l10nFactory->expects($this->at(2))
|
||||||
|
->method('get')
|
||||||
|
->with('dav', 'de')
|
||||||
|
->willReturn($enL10N);
|
||||||
|
|
||||||
|
$this->l10nFactory->expects($this->at(3))
|
||||||
|
->method('languageExists')
|
||||||
|
->with('dav', 'en')
|
||||||
|
->willReturn(true);
|
||||||
|
|
||||||
|
$this->l10nFactory->expects($this->at(4))
|
||||||
|
->method('get')
|
||||||
|
->with('dav', 'en')
|
||||||
|
->willReturn($deL10N);
|
||||||
|
|
||||||
|
$template1 = $this->getTemplateMock();
|
||||||
|
$message11 = $this->getMessageMock('foo1@example.org', $template1);
|
||||||
|
$message12 = $this->getMessageMock('uid2@example.com', $template1);
|
||||||
|
$message13 = $this->getMessageMock('uid3@example.com', $template1);
|
||||||
|
$template2 = $this->getTemplateMock();
|
||||||
|
$message21 = $this->getMessageMock('foo3@example.org', $template2);
|
||||||
|
$message22 = $this->getMessageMock('foo4@example.org', $template2);
|
||||||
|
$message23 = $this->getMessageMock('uid1@example.com', $template2);
|
||||||
|
|
||||||
|
$this->mailer->expects($this->at(0))
|
||||||
|
->method('createEMailTemplate')
|
||||||
|
->with('dav.calendarReminder')
|
||||||
|
->willReturn($template1);
|
||||||
|
|
||||||
|
$this->mailer->expects($this->at(1))
|
||||||
|
->method('createMessage')
|
||||||
|
->with()
|
||||||
|
->willReturn($message11);
|
||||||
|
$this->mailer->expects($this->at(2))
|
||||||
|
->method('send')
|
||||||
|
->with($message11)
|
||||||
|
->willReturn([]);
|
||||||
|
$this->mailer->expects($this->at(3))
|
||||||
|
->method('createMessage')
|
||||||
|
->with()
|
||||||
|
->willReturn($message12);
|
||||||
|
$this->mailer->expects($this->at(4))
|
||||||
|
->method('send')
|
||||||
|
->with($message12)
|
||||||
|
->willReturn([]);
|
||||||
|
$this->mailer->expects($this->at(5))
|
||||||
|
->method('createMessage')
|
||||||
|
->with()
|
||||||
|
->willReturn($message13);
|
||||||
|
$this->mailer->expects($this->at(6))
|
||||||
|
->method('send')
|
||||||
|
->with($message13)
|
||||||
|
->willReturn([]);
|
||||||
|
|
||||||
|
$this->mailer->expects($this->at(7))
|
||||||
|
->method('createEMailTemplate')
|
||||||
|
->with('dav.calendarReminder')
|
||||||
|
->willReturn($template2);
|
||||||
|
|
||||||
|
$this->mailer->expects($this->at(8))
|
||||||
|
->method('createMessage')
|
||||||
|
->with()
|
||||||
|
->willReturn($message21);
|
||||||
|
$this->mailer->expects($this->at(9))
|
||||||
|
->method('send')
|
||||||
|
->with($message21)
|
||||||
|
->willReturn([]);
|
||||||
|
$this->mailer->expects($this->at(10))
|
||||||
|
->method('createMessage')
|
||||||
|
->with()
|
||||||
|
->willReturn($message22);
|
||||||
|
$this->mailer->expects($this->at(11))
|
||||||
|
->method('send')
|
||||||
|
->with($message22)
|
||||||
|
->willReturn([]);
|
||||||
|
$this->mailer->expects($this->at(12))
|
||||||
|
->method('createMessage')
|
||||||
|
->with()
|
||||||
|
->willReturn($message23);
|
||||||
|
$this->mailer->expects($this->at(13))
|
||||||
|
->method('send')
|
||||||
|
->with($message23)
|
||||||
|
->willReturn([]);
|
||||||
|
|
||||||
|
$this->setupURLGeneratorMock(2);
|
||||||
|
|
||||||
|
$vcalendar = $this->getAttendeeVCalendar();
|
||||||
|
$this->provider->send($vcalendar->VEVENT, $this->calendarDisplayName, $users);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return IEMailTemplate
|
||||||
|
*/
|
||||||
|
private function getTemplateMock():IEMailTemplate {
|
||||||
|
$template = $this->createMock(IEMailTemplate::class);
|
||||||
|
|
||||||
|
$template->expects($this->at(0))
|
||||||
|
->method('addHeader')
|
||||||
|
->with()
|
||||||
|
->willReturn($template);
|
||||||
|
|
||||||
|
$template->expects($this->at(1))
|
||||||
|
->method('setSubject')
|
||||||
|
->with()
|
||||||
|
->willReturn($template);
|
||||||
|
|
||||||
|
$template->expects($this->at(2))
|
||||||
|
->method('addHeading')
|
||||||
|
->with()
|
||||||
|
->willReturn($template);
|
||||||
|
|
||||||
|
$template->expects($this->at(3))
|
||||||
|
->method('addBodyListItem')
|
||||||
|
->with()
|
||||||
|
->willReturn($template);
|
||||||
|
|
||||||
|
$template->expects($this->at(4))
|
||||||
|
->method('addBodyListItem')
|
||||||
|
->with()
|
||||||
|
->willReturn($template);
|
||||||
|
|
||||||
|
$template->expects($this->at(5))
|
||||||
|
->method('addBodyListItem')
|
||||||
|
->with()
|
||||||
|
->willReturn($template);
|
||||||
|
|
||||||
|
$template->expects($this->at(6))
|
||||||
|
->method('addBodyListItem')
|
||||||
|
->with()
|
||||||
|
->willReturn($template);
|
||||||
|
|
||||||
|
$template->expects($this->at(7))
|
||||||
|
->method('addFooter')
|
||||||
|
->with()
|
||||||
|
->willReturn($template);
|
||||||
|
|
||||||
|
return $template;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $toMail
|
||||||
|
* @param IEMailTemplate $templateMock
|
||||||
|
* @param array $replyTo
|
||||||
|
* @return IMessage
|
||||||
|
*/
|
||||||
|
private function getMessageMock(string $toMail, IEMailTemplate $templateMock, array $replyTo=null):IMessage {
|
||||||
|
$message = $this->createMock(IMessage::class);
|
||||||
|
$i = 0;
|
||||||
|
|
||||||
|
$message->expects($this->at($i++))
|
||||||
|
->method('setFrom')
|
||||||
|
->with([\OCP\Util::getDefaultEmailAddress('reminders-noreply')])
|
||||||
|
->willReturn($message);
|
||||||
|
|
||||||
|
if ($replyTo) {
|
||||||
|
$message->expects($this->at($i++))
|
||||||
|
->method('setReplyTo')
|
||||||
|
->with($replyTo)
|
||||||
|
->willReturn($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
$message->expects($this->at($i++))
|
||||||
|
->method('setTo')
|
||||||
|
->with([$toMail])
|
||||||
|
->willReturn($message);
|
||||||
|
|
||||||
|
$message->expects($this->at($i++))
|
||||||
|
->method('useTemplate')
|
||||||
|
->with($templateMock)
|
||||||
|
->willReturn($message);
|
||||||
|
|
||||||
|
return $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getNoAttendeeVCalendar():VCalendar {
|
||||||
|
$vcalendar = new VCalendar();
|
||||||
|
$vcalendar->add('VEVENT', [
|
||||||
|
'SUMMARY' => 'Fellowship meeting',
|
||||||
|
'DTSTART' => new \DateTime('2017-01-01 00:00:00+00:00'), // 1483228800,
|
||||||
|
'UID' => 'uid1234',
|
||||||
|
'LOCATION' => 'Location 123',
|
||||||
|
'DESCRIPTION' => 'DESCRIPTION 456',
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $vcalendar;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getAttendeeVCalendar():VCalendar {
|
||||||
|
$vcalendar = new VCalendar();
|
||||||
|
$vcalendar->add('VEVENT', [
|
||||||
|
'SUMMARY' => 'Fellowship meeting',
|
||||||
|
'DTSTART' => new \DateTime('2017-01-01 00:00:00+00:00'), // 1483228800,
|
||||||
|
'UID' => 'uid1234',
|
||||||
|
'LOCATION' => 'Location 123',
|
||||||
|
'DESCRIPTION' => 'DESCRIPTION 456',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$vcalendar->VEVENT->add(
|
||||||
|
'ATTENDEE',
|
||||||
|
'mailto:foo1@example.org',
|
||||||
|
[
|
||||||
|
'LANG' => 'de',
|
||||||
|
'PARTSTAT' => 'NEEDS-ACTION',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$vcalendar->VEVENT->add(
|
||||||
|
'ATTENDEE',
|
||||||
|
'mailto:foo2@example.org',
|
||||||
|
[
|
||||||
|
'LANG' => 'de',
|
||||||
|
'PARTSTAT' => 'DECLINED',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$vcalendar->VEVENT->add(
|
||||||
|
'ATTENDEE',
|
||||||
|
'mailto:foo3@example.org',
|
||||||
|
[
|
||||||
|
'LANG' => 'en',
|
||||||
|
'PARTSTAT' => 'CONFIRMED',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$vcalendar->VEVENT->add(
|
||||||
|
'ATTENDEE',
|
||||||
|
'mailto:foo4@example.org'
|
||||||
|
);
|
||||||
|
|
||||||
|
$vcalendar->VEVENT->add(
|
||||||
|
'ATTENDEE',
|
||||||
|
'tomail:foo5@example.org'
|
||||||
|
);
|
||||||
|
|
||||||
|
return $vcalendar;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function setupURLGeneratorMock(int $times=1):void {
|
||||||
|
for ($i = 0; $i < $times; $i++) {
|
||||||
|
$this->urlGenerator
|
||||||
|
->expects($this->at(8 * $i))
|
||||||
|
->method('imagePath')
|
||||||
|
->with('core', 'actions/info.svg')
|
||||||
|
->willReturn('imagePath1');
|
||||||
|
|
||||||
|
$this->urlGenerator
|
||||||
|
->expects($this->at(8 * $i + 1))
|
||||||
|
->method('getAbsoluteURL')
|
||||||
|
->with('imagePath1')
|
||||||
|
->willReturn('AbsURL1');
|
||||||
|
|
||||||
|
$this->urlGenerator
|
||||||
|
->expects($this->at(8 * $i + 2))
|
||||||
|
->method('imagePath')
|
||||||
|
->with('core', 'places/calendar.svg')
|
||||||
|
->willReturn('imagePath2');
|
||||||
|
|
||||||
|
$this->urlGenerator
|
||||||
|
->expects($this->at(8 * $i + 3))
|
||||||
|
->method('getAbsoluteURL')
|
||||||
|
->with('imagePath2')
|
||||||
|
->willReturn('AbsURL2');
|
||||||
|
|
||||||
|
$this->urlGenerator
|
||||||
|
->expects($this->at(8 * $i + 4))
|
||||||
|
->method('imagePath')
|
||||||
|
->with('core', 'actions/address.svg')
|
||||||
|
->willReturn('imagePath3');
|
||||||
|
|
||||||
|
$this->urlGenerator
|
||||||
|
->expects($this->at(8 * $i + 5))
|
||||||
|
->method('getAbsoluteURL')
|
||||||
|
->with('imagePath3')
|
||||||
|
->willReturn('AbsURL3');
|
||||||
|
|
||||||
|
$this->urlGenerator
|
||||||
|
->expects($this->at(8 * $i + 6))
|
||||||
|
->method('imagePath')
|
||||||
|
->with('core', 'actions/more.svg')
|
||||||
|
->willReturn('imagePath4');
|
||||||
|
|
||||||
|
$this->urlGenerator
|
||||||
|
->expects($this->at(8 * $i + 7))
|
||||||
|
->method('getAbsoluteURL')
|
||||||
|
->with('imagePath4')
|
||||||
|
->willReturn('AbsURL4');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,186 @@
|
||||||
|
<?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 AGPL-3.0
|
||||||
|
*
|
||||||
|
* This code is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* 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, version 3,
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace OCA\DAV\Tests\unit\CalDAV\Reminder\NotificationProvider;
|
||||||
|
|
||||||
|
use OCA\DAV\AppInfo\Application;
|
||||||
|
use OCA\DAV\CalDAV\Reminder\NotificationProvider\PushProvider;
|
||||||
|
use OCP\IConfig;
|
||||||
|
use OCP\IL10N;
|
||||||
|
use OCP\ILogger;
|
||||||
|
use OCP\IURLGenerator;
|
||||||
|
use OCP\L10N\IFactory as L10NFactory;
|
||||||
|
use OCP\IUser;
|
||||||
|
use OCP\Notification\IManager;
|
||||||
|
use OCP\Notification\INotification;
|
||||||
|
use OCP\AppFramework\Utility\ITimeFactory;
|
||||||
|
use Test\TestCase;
|
||||||
|
|
||||||
|
class PushProviderTest extends AbstractNotificationProviderTest {
|
||||||
|
|
||||||
|
/** @var ILogger|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
protected $logger;
|
||||||
|
|
||||||
|
/** @var L10NFactory|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
protected $l10nFactory;
|
||||||
|
|
||||||
|
/** @var IL10N|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
protected $l10n;
|
||||||
|
|
||||||
|
/** @var IURLGenerator|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
protected $urlGenerator;
|
||||||
|
|
||||||
|
/** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
protected $config;
|
||||||
|
|
||||||
|
/** @var IManager|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
private $manager;
|
||||||
|
|
||||||
|
/** @var ITimeFactory|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
private $timeFactory;
|
||||||
|
|
||||||
|
public function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->manager = $this->createMock(IManager::class);
|
||||||
|
$this->timeFactory = $this->createMock(ITimeFactory::class);
|
||||||
|
|
||||||
|
$this->provider = new PushProvider(
|
||||||
|
$this->config,
|
||||||
|
$this->manager,
|
||||||
|
$this->logger,
|
||||||
|
$this->l10nFactory,
|
||||||
|
$this->urlGenerator,
|
||||||
|
$this->timeFactory
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNotificationType():void {
|
||||||
|
$this->assertEquals(PushProvider::NOTIFICATION_TYPE, 'DISPLAY');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSend(): void {
|
||||||
|
$user1 = $this->createMock(IUser::class);
|
||||||
|
$user1->method('getUID')
|
||||||
|
->willReturn('uid1');
|
||||||
|
$user2 = $this->createMock(IUser::class);
|
||||||
|
$user2->method('getUID')
|
||||||
|
->willReturn('uid2');
|
||||||
|
$user3 = $this->createMock(IUser::class);
|
||||||
|
$user3->method('getUID')
|
||||||
|
->willReturn('uid3');
|
||||||
|
|
||||||
|
$users = [$user1, $user2, $user3];
|
||||||
|
|
||||||
|
$dateTime = new \DateTime('@946684800');
|
||||||
|
$this->timeFactory->method('getDateTime')
|
||||||
|
->with()
|
||||||
|
->willReturn($dateTime);
|
||||||
|
|
||||||
|
$notification1 = $this->createNotificationMock('uid1', $dateTime);
|
||||||
|
$notification2 = $this->createNotificationMock('uid2', $dateTime);
|
||||||
|
$notification3 = $this->createNotificationMock('uid3', $dateTime);
|
||||||
|
|
||||||
|
$this->manager->expects($this->at(0))
|
||||||
|
->method('createNotification')
|
||||||
|
->with()
|
||||||
|
->willReturn($notification1);
|
||||||
|
$this->manager->expects($this->at(2))
|
||||||
|
->method('createNotification')
|
||||||
|
->with()
|
||||||
|
->willReturn($notification2);
|
||||||
|
$this->manager->expects($this->at(4))
|
||||||
|
->method('createNotification')
|
||||||
|
->with()
|
||||||
|
->willReturn($notification3);
|
||||||
|
|
||||||
|
$this->manager->expects($this->at(1))
|
||||||
|
->method('notify')
|
||||||
|
->with($notification1);
|
||||||
|
$this->manager->expects($this->at(3))
|
||||||
|
->method('notify')
|
||||||
|
->with($notification2);
|
||||||
|
$this->manager->expects($this->at(5))
|
||||||
|
->method('notify')
|
||||||
|
->with($notification3);
|
||||||
|
|
||||||
|
$this->provider->send($this->vcalendar->VEVENT, $this->calendarDisplayName, $users);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $uid
|
||||||
|
* @param \DateTime $dt
|
||||||
|
*/
|
||||||
|
private function createNotificationMock(string $uid, \DateTime $dt):INotification {
|
||||||
|
$notification = $this->createMock(INotification::class);
|
||||||
|
$notification
|
||||||
|
->expects($this->once())
|
||||||
|
->method('setApp')
|
||||||
|
->with('dav')
|
||||||
|
->willReturn($notification);
|
||||||
|
|
||||||
|
$notification->expects($this->once())
|
||||||
|
->method('setUser')
|
||||||
|
->with($uid)
|
||||||
|
->willReturn($notification);
|
||||||
|
|
||||||
|
$notification->expects($this->once())
|
||||||
|
->method('setDateTime')
|
||||||
|
->with($dt)
|
||||||
|
->willReturn($notification);
|
||||||
|
|
||||||
|
$notification->expects($this->once())
|
||||||
|
->method('setObject')
|
||||||
|
->with('dav', 'uid1234')
|
||||||
|
->willReturn($notification);
|
||||||
|
|
||||||
|
$notification->expects($this->once())
|
||||||
|
->method('setSubject')
|
||||||
|
->with('calendar_reminder', [
|
||||||
|
'title' => 'Fellowship meeting',
|
||||||
|
'start_atom' => '2017-01-01T00:00:00+00:00',
|
||||||
|
])
|
||||||
|
->willReturn($notification);
|
||||||
|
|
||||||
|
$notification
|
||||||
|
->expects($this->once())
|
||||||
|
->method('setMessage')
|
||||||
|
->with('calendar_reminder', [
|
||||||
|
'title' => 'Fellowship meeting',
|
||||||
|
'start_atom' => '2017-01-01T00:00:00+00:00',
|
||||||
|
'description' => null,
|
||||||
|
'location' => null,
|
||||||
|
'all_day' => false,
|
||||||
|
'start_is_floating' => false,
|
||||||
|
'start_timezone' => 'UTC',
|
||||||
|
'end_atom' => '2017-01-01T00:00:00+00:00',
|
||||||
|
'end_is_floating' => false,
|
||||||
|
'end_timezone' => 'UTC',
|
||||||
|
'calendar_displayname' => 'Personal',
|
||||||
|
])
|
||||||
|
->willReturn($notification);
|
||||||
|
|
||||||
|
return $notification;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
<?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 AGPL-3.0
|
||||||
|
*
|
||||||
|
* This code is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* 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, version 3,
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace OCA\DAV\Tests\unit\CalDAV\Reminder;
|
||||||
|
|
||||||
|
use OCA\DAV\CalDAV\Reminder\NotificationProvider\EmailProvider;
|
||||||
|
use OCA\DAV\CalDAV\Reminder\NotificationProvider\ProviderNotAvailableException;
|
||||||
|
use OCA\DAV\CalDAV\Reminder\NotificationProvider\PushProvider;
|
||||||
|
use OCA\DAV\CalDAV\Reminder\NotificationProviderManager;
|
||||||
|
use OCA\DAV\CalDAV\Reminder\NotificationTypeDoesNotExistException;
|
||||||
|
use OCA\DAV\Capabilities;
|
||||||
|
use Test\TestCase;
|
||||||
|
|
||||||
|
class NotificationProviderManagerTest extends TestCase {
|
||||||
|
|
||||||
|
/** @var NotificationProviderManager|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
private $providerManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \OCP\AppFramework\QueryException
|
||||||
|
*/
|
||||||
|
public function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->providerManager = new NotificationProviderManager();
|
||||||
|
$this->providerManager->registerProvider(EmailProvider::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException OCA\DAV\CalDAV\Reminder\NotificationTypeDoesNotExistException
|
||||||
|
* @expectedExceptionMessage Type NOT EXISTENT is not an accepted type of notification
|
||||||
|
* @throws ProviderNotAvailableException
|
||||||
|
* @throws NotificationTypeDoesNotExistException
|
||||||
|
*/
|
||||||
|
public function testGetProviderForUnknownType(): void{
|
||||||
|
$this->providerManager->getProvider('NOT EXISTENT');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException OCA\DAV\CalDAV\Reminder\NotificationProvider\ProviderNotAvailableException
|
||||||
|
* @expectedExceptionMessage No notification provider for type AUDIO available
|
||||||
|
* @throws NotificationTypeDoesNotExistException
|
||||||
|
* @throws ProviderNotAvailableException
|
||||||
|
*/
|
||||||
|
public function testGetProviderForUnRegisteredType(): void{
|
||||||
|
$this->providerManager->getProvider('AUDIO');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetProvider(): void{
|
||||||
|
$provider = $this->providerManager->getProvider('EMAIL');
|
||||||
|
$this->assertInstanceOf(EmailProvider::class, $provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRegisterProvider(): void{
|
||||||
|
$this->providerManager->registerProvider(PushProvider::class);
|
||||||
|
$provider = $this->providerManager->getProvider('DISPLAY');
|
||||||
|
$this->assertInstanceOf(PushProvider::class, $provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedExceptionMessage Invalid notification provider registered
|
||||||
|
* @expectedException \InvalidArgumentException
|
||||||
|
* @throws \OCP\AppFramework\QueryException
|
||||||
|
*/
|
||||||
|
public function testRegisterBadProvider(): void{
|
||||||
|
$this->providerManager->registerProvider(Capabilities::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testHasProvider(): void {
|
||||||
|
$this->assertTrue($this->providerManager->hasProvider('EMAIL'));
|
||||||
|
$this->assertFalse($this->providerManager->hasProvider('EMAIL123'));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,220 @@
|
||||||
|
<?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 AGPL-3.0
|
||||||
|
*
|
||||||
|
* This code is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* 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, version 3,
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace OCA\DAV\Tests\unit\CalDAV\Reminder;
|
||||||
|
|
||||||
|
use OCA\DAV\AppInfo\Application;
|
||||||
|
use OCA\DAV\CalDAV\Reminder\Notifier;
|
||||||
|
use OCP\AppFramework\Utility\ITimeFactory;
|
||||||
|
use OCP\IL10N;
|
||||||
|
use OCP\IURLGenerator;
|
||||||
|
use OCP\L10N\IFactory;
|
||||||
|
use OCP\Notification\INotification;
|
||||||
|
use Test\TestCase;
|
||||||
|
|
||||||
|
class NotifierTest extends TestCase {
|
||||||
|
/** @var Notifier */
|
||||||
|
protected $notifier;
|
||||||
|
|
||||||
|
/** @var IFactory|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
protected $factory;
|
||||||
|
|
||||||
|
/** @var IURLGenerator|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
protected $urlGenerator;
|
||||||
|
|
||||||
|
/** @var IL10N|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
protected $l10n;
|
||||||
|
|
||||||
|
/** @var ITimeFactory|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
protected $timeFactory;
|
||||||
|
|
||||||
|
protected function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->urlGenerator = $this->createMock(IURLGenerator::class);
|
||||||
|
$this->l10n = $this->createMock(IL10N::class);
|
||||||
|
$this->l10n->expects($this->any())
|
||||||
|
->method('t')
|
||||||
|
->willReturnCallback(function($string, $args) {
|
||||||
|
return vsprintf($string, $args);
|
||||||
|
});
|
||||||
|
$this->l10n->expects($this->any())
|
||||||
|
->method('l')
|
||||||
|
->willReturnCallback(function($string, $args) {
|
||||||
|
/** \DateTime $args */
|
||||||
|
return $args->format(\DateTime::ATOM);
|
||||||
|
});
|
||||||
|
$this->l10n->expects($this->any())
|
||||||
|
->method('n')
|
||||||
|
->willReturnCallback(function($textSingular, $textPlural, $count, $args) {
|
||||||
|
$text = $count === 1 ? $textSingular : $textPlural;
|
||||||
|
$text = str_replace('%n', (string)$count, $text);
|
||||||
|
return vsprintf($text, $args);
|
||||||
|
});
|
||||||
|
$this->factory = $this->createMock(IFactory::class);
|
||||||
|
$this->factory->expects($this->any())
|
||||||
|
->method('get')
|
||||||
|
->willReturn($this->l10n);
|
||||||
|
|
||||||
|
$this->timeFactory = $this->createMock(ITimeFactory::class);
|
||||||
|
$this->timeFactory
|
||||||
|
->method('getDateTime')
|
||||||
|
->willReturn(\DateTime::createFromFormat(\DateTime::ATOM, '2005-08-15T14:00:00+02:00'));
|
||||||
|
|
||||||
|
$this->notifier = new Notifier(
|
||||||
|
$this->factory,
|
||||||
|
$this->urlGenerator,
|
||||||
|
$this->timeFactory
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetId():void {
|
||||||
|
$this->assertEquals($this->notifier->getID(), 'dav');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetName():void {
|
||||||
|
$this->assertEquals($this->notifier->getName(), 'Calendar');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \InvalidArgumentException
|
||||||
|
* @expectedExceptionMessage Notification not from this app
|
||||||
|
*/
|
||||||
|
public function testPrepareWrongApp(): void
|
||||||
|
{
|
||||||
|
/** @var INotification|\PHPUnit\Framework\MockObject\MockObject $notification */
|
||||||
|
$notification = $this->createMock(INotification::class);
|
||||||
|
|
||||||
|
$notification->expects($this->once())
|
||||||
|
->method('getApp')
|
||||||
|
->willReturn('notifications');
|
||||||
|
$notification->expects($this->never())
|
||||||
|
->method('getSubject');
|
||||||
|
|
||||||
|
$this->notifier->prepare($notification, 'en');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \InvalidArgumentException
|
||||||
|
* @expectedExceptionMessage Unknown subject
|
||||||
|
*/
|
||||||
|
public function testPrepareWrongSubject() {
|
||||||
|
/** @var INotification|\PHPUnit\Framework\MockObject\MockObject $notification */
|
||||||
|
$notification = $this->createMock(INotification::class);
|
||||||
|
|
||||||
|
$notification->expects($this->once())
|
||||||
|
->method('getApp')
|
||||||
|
->willReturn(Application::APP_ID);
|
||||||
|
$notification->expects($this->once())
|
||||||
|
->method('getSubject')
|
||||||
|
->willReturn('wrong subject');
|
||||||
|
|
||||||
|
$this->notifier->prepare($notification, 'en');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dataPrepare(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
'calendar_reminder',
|
||||||
|
[
|
||||||
|
'title' => 'Title of this event',
|
||||||
|
'start_atom' => '2005-08-15T15:52:01+02:00'
|
||||||
|
],
|
||||||
|
'Title of this event (in 1 hour, 52 minutes)',
|
||||||
|
[
|
||||||
|
'title' => 'Title of this event',
|
||||||
|
'description' => null,
|
||||||
|
'location' => 'NC Headquarters',
|
||||||
|
'all_day' => false,
|
||||||
|
'start_atom' => '2005-08-15T15:52:01+02:00',
|
||||||
|
'start_is_floating' => false,
|
||||||
|
'start_timezone' => 'Europe/Berlin',
|
||||||
|
'end_atom' => '2005-08-15T17:52:01+02:00',
|
||||||
|
'end_is_floating' => false,
|
||||||
|
'end_timezone' => 'Europe/Berlin',
|
||||||
|
'calendar_displayname' => 'Personal',
|
||||||
|
],
|
||||||
|
"Calendar: Personal\r\nDate: 2005-08-15T15:52:01+02:00, 2005-08-15T15:52:01+02:00 - 2005-08-15T17:52:01+02:00 (Europe/Berlin)\r\nWhere: NC Headquarters"
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider dataPrepare
|
||||||
|
*
|
||||||
|
* @param string $subjectType
|
||||||
|
* @param array $subjectParams
|
||||||
|
* @param string $subject
|
||||||
|
* @param array $messageParams
|
||||||
|
* @param string $message
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function testPrepare(string $subjectType, array $subjectParams, string $subject, array $messageParams, string $message): void
|
||||||
|
{
|
||||||
|
/** @var INotification|\PHPUnit\Framework\MockObject\MockObject $notification */
|
||||||
|
$notification = $this->createMock(INotification::class);
|
||||||
|
|
||||||
|
$notification->expects($this->once())
|
||||||
|
->method('getApp')
|
||||||
|
->willReturn(Application::APP_ID);
|
||||||
|
$notification->expects($this->once())
|
||||||
|
->method('getSubject')
|
||||||
|
->willReturn($subjectType);
|
||||||
|
$notification->expects($this->once())
|
||||||
|
->method('getSubjectParameters')
|
||||||
|
->willReturn($subjectParams);
|
||||||
|
$notification->expects($this->once())
|
||||||
|
->method('getMessageParameters')
|
||||||
|
->willReturn($messageParams);
|
||||||
|
|
||||||
|
$notification->expects($this->once())
|
||||||
|
->method('setParsedSubject')
|
||||||
|
->with($subject)
|
||||||
|
->willReturnSelf();
|
||||||
|
|
||||||
|
$notification->expects($this->once())
|
||||||
|
->method('setParsedMessage')
|
||||||
|
->with($message)
|
||||||
|
->willReturnSelf();
|
||||||
|
|
||||||
|
$this->urlGenerator->expects($this->once())
|
||||||
|
->method('imagePath')
|
||||||
|
->with('core', 'places/calendar.svg')
|
||||||
|
->willReturn('icon-url');
|
||||||
|
$this->urlGenerator->expects($this->once())
|
||||||
|
->method('getAbsoluteURL')
|
||||||
|
->with('icon-url')
|
||||||
|
->willReturn('absolute-icon-url');
|
||||||
|
$notification->expects($this->once())
|
||||||
|
->method('setIcon')
|
||||||
|
->with('absolute-icon-url')
|
||||||
|
->willReturnSelf();
|
||||||
|
|
||||||
|
$return = $this->notifier->prepare($notification, 'en');
|
||||||
|
|
||||||
|
$this->assertEquals($notification, $return);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,555 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2019, Thomas Citharel
|
||||||
|
*
|
||||||
|
* @author Thomas Citharel <tcit@tcit.fr>
|
||||||
|
*
|
||||||
|
* @license AGPL-3.0
|
||||||
|
*
|
||||||
|
* This code is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* 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, version 3,
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace OCA\DAV\Tests\unit\CalDAV\Reminder;
|
||||||
|
|
||||||
|
use OCA\DAV\CalDAV\CalDavBackend;
|
||||||
|
use OCA\DAV\CalDAV\Reminder\AbstractNotificationProvider;
|
||||||
|
use OCA\DAV\CalDAV\Reminder\Backend;
|
||||||
|
use OCA\DAV\CalDAV\Reminder\INotificationProvider;
|
||||||
|
use OCA\DAV\CalDAV\Reminder\NotificationProviderManager;
|
||||||
|
use OCA\DAV\CalDAV\Reminder\NotificationProvider\EmailProvider;
|
||||||
|
use OCA\DAV\CalDAV\Reminder\NotificationProvider\PushProvider;
|
||||||
|
use OCA\DAV\CalDAV\Reminder\ReminderService;
|
||||||
|
use OCP\AppFramework\Utility\ITimeFactory;
|
||||||
|
use OCP\IGroup;
|
||||||
|
use OCP\IGroupManager;
|
||||||
|
use OCP\IUser;
|
||||||
|
use OCP\IUserManager;
|
||||||
|
use OCP\IUserSession;
|
||||||
|
use Test\TestCase;
|
||||||
|
|
||||||
|
class ReminderServiceTest extends TestCase {
|
||||||
|
|
||||||
|
/** @var Backend|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
private $backend;
|
||||||
|
|
||||||
|
/** @var NotificationProviderManager|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
private $notificationProviderManager;
|
||||||
|
|
||||||
|
/** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
private $userManager;
|
||||||
|
|
||||||
|
/** @var IGroupManager|\PHPUnit\Framework\MockObject\MockObject*/
|
||||||
|
private $groupManager;
|
||||||
|
|
||||||
|
/** @var IUserSession|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
private $userSession;
|
||||||
|
|
||||||
|
/** @var CalDavBackend|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
private $caldavBackend;
|
||||||
|
|
||||||
|
/** @var ITimeFactory|\PHPUnit\Framework\MockObject\MockObject */
|
||||||
|
private $timeFactory;
|
||||||
|
|
||||||
|
/** @var ReminderService */
|
||||||
|
private $reminderService;
|
||||||
|
|
||||||
|
public const CALENDAR_DATA = <<<EOD
|
||||||
|
BEGIN:VCALENDAR
|
||||||
|
PRODID:-//Nextcloud calendar v1.6.4
|
||||||
|
BEGIN:VEVENT
|
||||||
|
CREATED:20160602T133732
|
||||||
|
DTSTAMP:20160602T133732
|
||||||
|
LAST-MODIFIED:20160602T133732
|
||||||
|
UID:wej2z68l9h
|
||||||
|
SUMMARY:Test Event
|
||||||
|
LOCATION:Somewhere ...
|
||||||
|
DESCRIPTION:maybe ....
|
||||||
|
DTSTART;TZID=Europe/Berlin;VALUE=DATE:20160609
|
||||||
|
DTEND;TZID=Europe/Berlin;VALUE=DATE:20160610
|
||||||
|
BEGIN:VALARM
|
||||||
|
ACTION:EMAIL
|
||||||
|
TRIGGER:-PT15M
|
||||||
|
END:VALARM
|
||||||
|
BEGIN:VALARM
|
||||||
|
ACTION:DISPLAY
|
||||||
|
TRIGGER;VALUE=DATE-TIME:20160608T000000Z
|
||||||
|
END:VALARM
|
||||||
|
END:VEVENT
|
||||||
|
END:VCALENDAR
|
||||||
|
EOD;
|
||||||
|
|
||||||
|
public const CALENDAR_DATA_REPEAT = <<<EOD
|
||||||
|
BEGIN:VCALENDAR
|
||||||
|
PRODID:-//Nextcloud calendar v1.6.4
|
||||||
|
BEGIN:VEVENT
|
||||||
|
CREATED:20160602T133732
|
||||||
|
DTSTAMP:20160602T133732
|
||||||
|
LAST-MODIFIED:20160602T133732
|
||||||
|
UID:wej2z68l9h
|
||||||
|
SUMMARY:Test Event
|
||||||
|
LOCATION:Somewhere ...
|
||||||
|
DESCRIPTION:maybe ....
|
||||||
|
DTSTART;TZID=Europe/Berlin;VALUE=DATE:20160609
|
||||||
|
DTEND;TZID=Europe/Berlin;VALUE=DATE:20160610
|
||||||
|
BEGIN:VALARM
|
||||||
|
ACTION:EMAIL
|
||||||
|
TRIGGER:-PT15M
|
||||||
|
REPEAT:4
|
||||||
|
DURATION:PT2M
|
||||||
|
END:VALARM
|
||||||
|
END:VEVENT
|
||||||
|
END:VCALENDAR
|
||||||
|
EOD;
|
||||||
|
|
||||||
|
public const CALENDAR_DATA_RECURRING = <<<EOD
|
||||||
|
BEGIN:VCALENDAR
|
||||||
|
PRODID:-//Nextcloud calendar v1.6.4
|
||||||
|
BEGIN:VEVENT
|
||||||
|
CREATED:20160602T133732
|
||||||
|
DTSTAMP:20160602T133732
|
||||||
|
LAST-MODIFIED:20160602T133732
|
||||||
|
UID:wej2z68l9h
|
||||||
|
SUMMARY:Test Event
|
||||||
|
LOCATION:Somewhere ...
|
||||||
|
DESCRIPTION:maybe ....
|
||||||
|
DTSTART;TZID=Europe/Berlin;VALUE=DATE:20160609
|
||||||
|
DTEND;TZID=Europe/Berlin;VALUE=DATE:20160610
|
||||||
|
RRULE:FREQ=WEEKLY
|
||||||
|
BEGIN:VALARM
|
||||||
|
ACTION:EMAIL
|
||||||
|
TRIGGER:-PT15M
|
||||||
|
END:VALARM
|
||||||
|
BEGIN:VALARM
|
||||||
|
ACTION:EMAIL
|
||||||
|
TRIGGER:-P8D
|
||||||
|
END:VALARM
|
||||||
|
END:VEVENT
|
||||||
|
END:VCALENDAR
|
||||||
|
EOD;
|
||||||
|
|
||||||
|
public const CALENDAR_DATA_RECURRING_REPEAT = <<<EOD
|
||||||
|
BEGIN:VCALENDAR
|
||||||
|
PRODID:-//Nextcloud calendar v1.6.4
|
||||||
|
BEGIN:VEVENT
|
||||||
|
CREATED:20160602T133732
|
||||||
|
DTSTAMP:20160602T133732
|
||||||
|
LAST-MODIFIED:20160602T133732
|
||||||
|
UID:wej2z68l9h
|
||||||
|
SUMMARY:Test Event
|
||||||
|
LOCATION:Somewhere ...
|
||||||
|
DESCRIPTION:maybe ....
|
||||||
|
DTSTART;TZID=Europe/Berlin;VALUE=DATE:20160609
|
||||||
|
DTEND;TZID=Europe/Berlin;VALUE=DATE:20160610
|
||||||
|
RRULE:FREQ=WEEKLY
|
||||||
|
BEGIN:VALARM
|
||||||
|
ACTION:EMAIL
|
||||||
|
TRIGGER:-PT15M
|
||||||
|
REPEAT:4
|
||||||
|
DURATION:PT2M
|
||||||
|
END:VALARM
|
||||||
|
BEGIN:VALARM
|
||||||
|
ACTION:EMAIL
|
||||||
|
TRIGGER:-P8D
|
||||||
|
END:VALARM
|
||||||
|
END:VEVENT
|
||||||
|
END:VCALENDAR
|
||||||
|
EOD;
|
||||||
|
|
||||||
|
public function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->backend = $this->createMock(Backend::class);
|
||||||
|
$this->notificationProviderManager = $this->createMock(NotificationProviderManager::class);
|
||||||
|
$this->userManager = $this->createMock(IUserManager::class);
|
||||||
|
$this->groupManager = $this->createMock(IGroupManager::class);
|
||||||
|
$this->caldavBackend = $this->createMock(CalDavBackend::class);
|
||||||
|
$this->timeFactory = $this->createMock(ITimeFactory::class);
|
||||||
|
|
||||||
|
$this->caldavBackend->method('getShares')->willReturn([]);
|
||||||
|
|
||||||
|
$this->reminderService = new ReminderService($this->backend,
|
||||||
|
$this->notificationProviderManager,
|
||||||
|
$this->userManager,
|
||||||
|
$this->groupManager,
|
||||||
|
$this->caldavBackend,
|
||||||
|
$this->timeFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOnCalendarObjectDelete():void {
|
||||||
|
$this->backend->expects($this->once())
|
||||||
|
->method('cleanRemindersForEvent')
|
||||||
|
->with(44);
|
||||||
|
|
||||||
|
$action = '\OCA\DAV\CalDAV\CalDavBackend::deleteCalendarObject';
|
||||||
|
$objectData = [
|
||||||
|
'id' => '44',
|
||||||
|
'component' => 'vevent',
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->reminderService->onTouchCalendarObject($action, $objectData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOnCalendarObjectCreateSingleEntry():void {
|
||||||
|
$action = '\OCA\DAV\CalDAV\CalDavBackend::createCalendarObject';
|
||||||
|
$objectData = [
|
||||||
|
'calendardata' => self::CALENDAR_DATA,
|
||||||
|
'id' => '42',
|
||||||
|
'calendarid' => '1337',
|
||||||
|
'component' => 'vevent',
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->backend->expects($this->exactly(2))
|
||||||
|
->method('insertReminder')
|
||||||
|
->withConsecutive(
|
||||||
|
[1337, 42, 'wej2z68l9h', false, 1465430400, false, '5c70531aab15c92b52518ae10a2f78a4', 'de919af7429d3b5c11e8b9d289b411a6', 'EMAIL', true, 1465429500, false],
|
||||||
|
[1337, 42, 'wej2z68l9h', false, 1465430400, false, '5c70531aab15c92b52518ae10a2f78a4', '35b3eae8e792aa2209f0b4e1a302f105', 'DISPLAY', false, 1465344000, false]
|
||||||
|
)
|
||||||
|
->willReturn(1);
|
||||||
|
|
||||||
|
$this->timeFactory->expects($this->once())
|
||||||
|
->method('getDateTime')
|
||||||
|
->with()
|
||||||
|
->willReturn(\DateTime::createFromFormat(\DateTime::ATOM, '2016-06-08T00:00:00+00:00'));
|
||||||
|
|
||||||
|
$this->reminderService->onTouchCalendarObject($action, $objectData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOnCalendarObjectCreateSingleEntryWithRepeat(): void {
|
||||||
|
$action = '\OCA\DAV\CalDAV\CalDavBackend::createCalendarObject';
|
||||||
|
$objectData = [
|
||||||
|
'calendardata' => self::CALENDAR_DATA_REPEAT,
|
||||||
|
'id' => '42',
|
||||||
|
'calendarid' => '1337',
|
||||||
|
'component' => 'vevent',
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->backend->expects($this->exactly(5))
|
||||||
|
->method('insertReminder')
|
||||||
|
->withConsecutive(
|
||||||
|
[1337, 42, 'wej2z68l9h', false, 1465430400, false, '5c70531aab15c92b52518ae10a2f78a4', 'ecacbf07d413c3c78d1ac7ad8c469602', 'EMAIL', true, 1465429500, false],
|
||||||
|
[1337, 42, 'wej2z68l9h', false, 1465430400, false, '5c70531aab15c92b52518ae10a2f78a4', 'ecacbf07d413c3c78d1ac7ad8c469602', 'EMAIL', true, 1465429620, true],
|
||||||
|
[1337, 42, 'wej2z68l9h', false, 1465430400, false, '5c70531aab15c92b52518ae10a2f78a4', 'ecacbf07d413c3c78d1ac7ad8c469602', 'EMAIL', true, 1465429740, true],
|
||||||
|
[1337, 42, 'wej2z68l9h', false, 1465430400, false, '5c70531aab15c92b52518ae10a2f78a4', 'ecacbf07d413c3c78d1ac7ad8c469602', 'EMAIL', true, 1465429860, true],
|
||||||
|
[1337, 42, 'wej2z68l9h', false, 1465430400, false, '5c70531aab15c92b52518ae10a2f78a4', 'ecacbf07d413c3c78d1ac7ad8c469602', 'EMAIL', true, 1465429980, true]
|
||||||
|
)
|
||||||
|
->willReturn(1);
|
||||||
|
|
||||||
|
$this->timeFactory->expects($this->once())
|
||||||
|
->method('getDateTime')
|
||||||
|
->with()
|
||||||
|
->willReturn(\DateTime::createFromFormat(\DateTime::ATOM, '2016-06-08T00:00:00+00:00'));
|
||||||
|
|
||||||
|
$this->reminderService->onTouchCalendarObject($action, $objectData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOnCalendarObjectCreateRecurringEntry(): void {
|
||||||
|
$action = '\OCA\DAV\CalDAV\CalDavBackend::createCalendarObject';
|
||||||
|
$objectData = [
|
||||||
|
'calendardata' => self::CALENDAR_DATA_RECURRING,
|
||||||
|
'id' => '42',
|
||||||
|
'calendarid' => '1337',
|
||||||
|
'component' => 'vevent',
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->backend->expects($this->exactly(2))
|
||||||
|
->method('insertReminder')
|
||||||
|
->withConsecutive(
|
||||||
|
[1337, 42, 'wej2z68l9h', true, 1467244800, false, 'fbdb2726bc0f7dfacac1d881c1453e20', 'de919af7429d3b5c11e8b9d289b411a6', 'EMAIL', true, 1467243900, false],
|
||||||
|
[1337, 42, 'wej2z68l9h', true, 1467849600, false, 'fbdb2726bc0f7dfacac1d881c1453e20', '8996992118817f9f311ac5cc56d1cc97', 'EMAIL', true, 1467158400, false]
|
||||||
|
)
|
||||||
|
->willReturn(1);
|
||||||
|
|
||||||
|
$this->timeFactory->expects($this->once())
|
||||||
|
->method('getDateTime')
|
||||||
|
->with()
|
||||||
|
->willReturn(\DateTime::createFromFormat(\DateTime::ATOM, '2016-06-29T00:00:00+00:00'));
|
||||||
|
|
||||||
|
$this->reminderService->onTouchCalendarObject($action, $objectData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOnCalendarObjectCreateRecurringEntryWithRepeat():void {
|
||||||
|
$action = '\OCA\DAV\CalDAV\CalDavBackend::createCalendarObject';
|
||||||
|
$objectData = [
|
||||||
|
'calendardata' => self::CALENDAR_DATA_RECURRING_REPEAT,
|
||||||
|
'id' => '42',
|
||||||
|
'calendarid' => '1337',
|
||||||
|
'component' => 'vevent',
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->backend->expects($this->exactly(6))
|
||||||
|
->method('insertReminder')
|
||||||
|
->withConsecutive(
|
||||||
|
[1337, 42, 'wej2z68l9h', true, 1467244800, false, 'fbdb2726bc0f7dfacac1d881c1453e20', 'ecacbf07d413c3c78d1ac7ad8c469602', 'EMAIL', true, 1467243900, false],
|
||||||
|
[1337, 42, 'wej2z68l9h', true, 1467244800, false, 'fbdb2726bc0f7dfacac1d881c1453e20', 'ecacbf07d413c3c78d1ac7ad8c469602', 'EMAIL', true, 1467244020, true],
|
||||||
|
[1337, 42, 'wej2z68l9h', true, 1467244800, false, 'fbdb2726bc0f7dfacac1d881c1453e20', 'ecacbf07d413c3c78d1ac7ad8c469602', 'EMAIL', true, 1467244140, true],
|
||||||
|
[1337, 42, 'wej2z68l9h', true, 1467244800, false, 'fbdb2726bc0f7dfacac1d881c1453e20', 'ecacbf07d413c3c78d1ac7ad8c469602', 'EMAIL', true, 1467244260, true],
|
||||||
|
[1337, 42, 'wej2z68l9h', true, 1467244800, false, 'fbdb2726bc0f7dfacac1d881c1453e20', 'ecacbf07d413c3c78d1ac7ad8c469602', 'EMAIL', true, 1467244380, true],
|
||||||
|
[1337, 42, 'wej2z68l9h', true, 1467849600, false, 'fbdb2726bc0f7dfacac1d881c1453e20', '8996992118817f9f311ac5cc56d1cc97', 'EMAIL', true, 1467158400, false]
|
||||||
|
)
|
||||||
|
->willReturn(1);
|
||||||
|
|
||||||
|
$this->timeFactory->expects($this->once())
|
||||||
|
->method('getDateTime')
|
||||||
|
->with()
|
||||||
|
->willReturn(\DateTime::createFromFormat(\DateTime::ATOM, '2016-06-29T00:00:00+00:00'));
|
||||||
|
|
||||||
|
$this->reminderService->onTouchCalendarObject($action, $objectData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProcessReminders():void {
|
||||||
|
$this->backend->expects($this->at(0))
|
||||||
|
->method('getRemindersToProcess')
|
||||||
|
->with()
|
||||||
|
->willReturn([
|
||||||
|
[
|
||||||
|
'id' => 1,
|
||||||
|
'calendar_id' => 1337,
|
||||||
|
'object_id' => 42,
|
||||||
|
'uid' => 'wej2z68l9h',
|
||||||
|
'is_recurring' => false,
|
||||||
|
'recurrence_id' => 1465430400,
|
||||||
|
'is_recurrence_exception' => false,
|
||||||
|
'event_hash' => '5c70531aab15c92b52518ae10a2f78a4',
|
||||||
|
'alarm_hash' => 'de919af7429d3b5c11e8b9d289b411a6',
|
||||||
|
'type' => 'EMAIL',
|
||||||
|
'is_relative' => true,
|
||||||
|
'notification_date' => 1465429500,
|
||||||
|
'is_repeat_based' => false,
|
||||||
|
'calendardata' => self::CALENDAR_DATA,
|
||||||
|
'displayname' => 'Displayname 123',
|
||||||
|
'principaluri' => 'principals/users/user001',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 2,
|
||||||
|
'calendar_id' => 1337,
|
||||||
|
'object_id' => 42,
|
||||||
|
'uid' => 'wej2z68l9h',
|
||||||
|
'is_recurring' => false,
|
||||||
|
'recurrence_id' => 1465430400,
|
||||||
|
'is_recurrence_exception' => false,
|
||||||
|
'event_hash' => '5c70531aab15c92b52518ae10a2f78a4',
|
||||||
|
'alarm_hash' => 'ecacbf07d413c3c78d1ac7ad8c469602',
|
||||||
|
'type' => 'EMAIL',
|
||||||
|
'is_relative' => true,
|
||||||
|
'notification_date' => 1465429740,
|
||||||
|
'is_repeat_based' => true,
|
||||||
|
'calendardata' => self::CALENDAR_DATA_REPEAT,
|
||||||
|
'displayname' => 'Displayname 123',
|
||||||
|
'principaluri' => 'principals/users/user001',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 3,
|
||||||
|
'calendar_id' => 1337,
|
||||||
|
'object_id' => 42,
|
||||||
|
'uid' => 'wej2z68l9h',
|
||||||
|
'is_recurring' => false,
|
||||||
|
'recurrence_id' => 1465430400,
|
||||||
|
'is_recurrence_exception' => false,
|
||||||
|
'event_hash' => '5c70531aab15c92b52518ae10a2f78a4',
|
||||||
|
'alarm_hash' => '35b3eae8e792aa2209f0b4e1a302f105',
|
||||||
|
'type' => 'DISPLAY',
|
||||||
|
'is_relative' => false,
|
||||||
|
'notification_date' => 1465344000,
|
||||||
|
'is_repeat_based' => false,
|
||||||
|
'calendardata' => self::CALENDAR_DATA,
|
||||||
|
'displayname' => 'Displayname 123',
|
||||||
|
'principaluri' => 'principals/users/user001',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 4,
|
||||||
|
'calendar_id' => 1337,
|
||||||
|
'object_id' => 42,
|
||||||
|
'uid' => 'wej2z68l9h',
|
||||||
|
'is_recurring' => true,
|
||||||
|
'recurrence_id' => 1467244800,
|
||||||
|
'is_recurrence_exception' => false,
|
||||||
|
'event_hash' => 'fbdb2726bc0f7dfacac1d881c1453e20',
|
||||||
|
'alarm_hash' => 'ecacbf07d413c3c78d1ac7ad8c469602',
|
||||||
|
'type' => 'EMAIL',
|
||||||
|
'is_relative' => true,
|
||||||
|
'notification_date' => 1467243900,
|
||||||
|
'is_repeat_based' => false,
|
||||||
|
'calendardata' => self::CALENDAR_DATA_RECURRING_REPEAT,
|
||||||
|
'displayname' => 'Displayname 123',
|
||||||
|
'principaluri' => 'principals/users/user001',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 5,
|
||||||
|
'calendar_id' => 1337,
|
||||||
|
'object_id' => 42,
|
||||||
|
'uid' => 'wej2z68l9h',
|
||||||
|
'is_recurring' => true,
|
||||||
|
'recurrence_id' => 1467849600,
|
||||||
|
'is_recurrence_exception' => false,
|
||||||
|
'event_hash' => 'fbdb2726bc0f7dfacac1d881c1453e20',
|
||||||
|
'alarm_hash' => '8996992118817f9f311ac5cc56d1cc97',
|
||||||
|
'type' => 'EMAIL',
|
||||||
|
'is_relative' => true,
|
||||||
|
'notification_date' => 1467158400,
|
||||||
|
'is_repeat_based' => false,
|
||||||
|
'calendardata' => self::CALENDAR_DATA_RECURRING,
|
||||||
|
'displayname' => 'Displayname 123',
|
||||||
|
'principaluri' => 'principals/users/user001',
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->notificationProviderManager->expects($this->at(0))
|
||||||
|
->method('hasProvider')
|
||||||
|
->with('EMAIL')
|
||||||
|
->willReturn(true);
|
||||||
|
|
||||||
|
$provider1 = $this->createMock(INotificationProvider::class);
|
||||||
|
$this->notificationProviderManager->expects($this->at(1))
|
||||||
|
->method('getProvider')
|
||||||
|
->with('EMAIL')
|
||||||
|
->willReturn($provider1);
|
||||||
|
|
||||||
|
$this->notificationProviderManager->expects($this->at(2))
|
||||||
|
->method('hasProvider')
|
||||||
|
->with('EMAIL')
|
||||||
|
->willReturn(true);
|
||||||
|
|
||||||
|
$provider2 = $this->createMock(INotificationProvider::class);
|
||||||
|
$this->notificationProviderManager->expects($this->at(3))
|
||||||
|
->method('getProvider')
|
||||||
|
->with('EMAIL')
|
||||||
|
->willReturn($provider2);
|
||||||
|
|
||||||
|
$this->notificationProviderManager->expects($this->at(4))
|
||||||
|
->method('hasProvider')
|
||||||
|
->with('DISPLAY')
|
||||||
|
->willReturn(true);
|
||||||
|
|
||||||
|
$provider3 = $this->createMock(INotificationProvider::class);
|
||||||
|
$this->notificationProviderManager->expects($this->at(5))
|
||||||
|
->method('getProvider')
|
||||||
|
->with('DISPLAY')
|
||||||
|
->willReturn($provider3);
|
||||||
|
|
||||||
|
$this->notificationProviderManager->expects($this->at(6))
|
||||||
|
->method('hasProvider')
|
||||||
|
->with('EMAIL')
|
||||||
|
->willReturn(true);
|
||||||
|
|
||||||
|
$provider4 = $this->createMock(INotificationProvider::class);
|
||||||
|
$this->notificationProviderManager->expects($this->at(7))
|
||||||
|
->method('getProvider')
|
||||||
|
->with('EMAIL')
|
||||||
|
->willReturn($provider4);
|
||||||
|
|
||||||
|
$this->notificationProviderManager->expects($this->at(8))
|
||||||
|
->method('hasProvider')
|
||||||
|
->with('EMAIL')
|
||||||
|
->willReturn(true);
|
||||||
|
|
||||||
|
$provider5 = $this->createMock(INotificationProvider::class);
|
||||||
|
$this->notificationProviderManager->expects($this->at(9))
|
||||||
|
->method('getProvider')
|
||||||
|
->with('EMAIL')
|
||||||
|
->willReturn($provider5);
|
||||||
|
|
||||||
|
$user = $this->createMock(IUser::class);
|
||||||
|
$this->userManager->expects($this->exactly(5))
|
||||||
|
->method('get')
|
||||||
|
->with('user001')
|
||||||
|
->willReturn($user);
|
||||||
|
|
||||||
|
$provider1->expects($this->once())
|
||||||
|
->method('send')
|
||||||
|
->with($this->callback(function($vevent) {
|
||||||
|
if ($vevent->DTSTART->getDateTime()->format(\DateTime::ATOM) !== '2016-06-09T00:00:00+00:00') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}, 'Displayname 123', $user));
|
||||||
|
$provider2->expects($this->once())
|
||||||
|
->method('send')
|
||||||
|
->with($this->callback(function($vevent) {
|
||||||
|
if ($vevent->DTSTART->getDateTime()->format(\DateTime::ATOM) !== '2016-06-09T00:00:00+00:00') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}, 'Displayname 123', $user));
|
||||||
|
$provider3->expects($this->once())
|
||||||
|
->method('send')
|
||||||
|
->with($this->callback(function($vevent) {
|
||||||
|
if ($vevent->DTSTART->getDateTime()->format(\DateTime::ATOM) !== '2016-06-09T00:00:00+00:00') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}, 'Displayname 123', $user));
|
||||||
|
$provider4->expects($this->once())
|
||||||
|
->method('send')
|
||||||
|
->with($this->callback(function($vevent) {
|
||||||
|
if ($vevent->DTSTART->getDateTime()->format(\DateTime::ATOM) !== '2016-06-30T00:00:00+00:00') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}, 'Displayname 123', $user));
|
||||||
|
$provider5->expects($this->once())
|
||||||
|
->method('send')
|
||||||
|
->with($this->callback(function($vevent) {
|
||||||
|
if ($vevent->DTSTART->getDateTime()->format(\DateTime::ATOM) !== '2016-07-07T00:00:00+00:00') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}, 'Displayname 123', $user));
|
||||||
|
|
||||||
|
$this->backend->expects($this->at(1))
|
||||||
|
->method('removeReminder')
|
||||||
|
->with(1);
|
||||||
|
$this->backend->expects($this->at(2))
|
||||||
|
->method('removeReminder')
|
||||||
|
->with(2);
|
||||||
|
$this->backend->expects($this->at(3))
|
||||||
|
->method('removeReminder')
|
||||||
|
->with(3);
|
||||||
|
$this->backend->expects($this->at(4))
|
||||||
|
->method('removeReminder')
|
||||||
|
->with(4);
|
||||||
|
$this->backend->expects($this->at(5))
|
||||||
|
->method('insertReminder')
|
||||||
|
->with(1337, 42, 'wej2z68l9h', true, 1467849600, false, 'fbdb2726bc0f7dfacac1d881c1453e20', 'ecacbf07d413c3c78d1ac7ad8c469602', 'EMAIL', true, 1467848700, false)
|
||||||
|
->willReturn(99);
|
||||||
|
|
||||||
|
$this->backend->expects($this->at(6))
|
||||||
|
->method('insertReminder')
|
||||||
|
->with(1337, 42, 'wej2z68l9h', true, 1467849600, false, 'fbdb2726bc0f7dfacac1d881c1453e20', 'ecacbf07d413c3c78d1ac7ad8c469602', 'EMAIL', true, 1467848820, true)
|
||||||
|
->willReturn(99);
|
||||||
|
$this->backend->expects($this->at(7))
|
||||||
|
->method('insertReminder')
|
||||||
|
->with(1337, 42, 'wej2z68l9h', true, 1467849600, false, 'fbdb2726bc0f7dfacac1d881c1453e20', 'ecacbf07d413c3c78d1ac7ad8c469602', 'EMAIL', true, 1467848940, true)
|
||||||
|
->willReturn(99);
|
||||||
|
$this->backend->expects($this->at(8))
|
||||||
|
->method('insertReminder')
|
||||||
|
->with(1337, 42, 'wej2z68l9h', true, 1467849600, false, 'fbdb2726bc0f7dfacac1d881c1453e20', 'ecacbf07d413c3c78d1ac7ad8c469602', 'EMAIL', true, 1467849060, true)
|
||||||
|
->willReturn(99);
|
||||||
|
$this->backend->expects($this->at(9))
|
||||||
|
->method('insertReminder')
|
||||||
|
->with(1337, 42, 'wej2z68l9h', true, 1467849600, false, 'fbdb2726bc0f7dfacac1d881c1453e20', 'ecacbf07d413c3c78d1ac7ad8c469602', 'EMAIL', true, 1467849180, true)
|
||||||
|
->willReturn(99);
|
||||||
|
$this->backend->expects($this->at(10))
|
||||||
|
->method('removeReminder')
|
||||||
|
->with(5);
|
||||||
|
$this->backend->expects($this->at(11))
|
||||||
|
->method('insertReminder')
|
||||||
|
->with(1337, 42, 'wej2z68l9h', true, 1468454400, false, 'fbdb2726bc0f7dfacac1d881c1453e20', '8996992118817f9f311ac5cc56d1cc97', 'EMAIL', true, 1467763200, false)
|
||||||
|
->willReturn(99);
|
||||||
|
|
||||||
|
$this->timeFactory->method('getDateTime')
|
||||||
|
->willReturn(\DateTime::createFromFormat(\DateTime::ATOM, '2016-06-08T00:00:00+00:00'));
|
||||||
|
|
||||||
|
$this->reminderService->processReminders();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue