Merge pull request #5304 from nextcloud/bugfix/2855/dont_send_invitations_for_past_events
don't send invitation emails for past events
This commit is contained in:
commit
8e6d86a862
|
@ -84,7 +84,7 @@ if ($debugging) {
|
||||||
$server->addPlugin(new \Sabre\DAV\Sync\Plugin());
|
$server->addPlugin(new \Sabre\DAV\Sync\Plugin());
|
||||||
$server->addPlugin(new \Sabre\CalDAV\ICSExportPlugin());
|
$server->addPlugin(new \Sabre\CalDAV\ICSExportPlugin());
|
||||||
$server->addPlugin(new \OCA\DAV\CalDAV\Schedule\Plugin());
|
$server->addPlugin(new \OCA\DAV\CalDAV\Schedule\Plugin());
|
||||||
$server->addPlugin(new \OCA\DAV\CalDAV\Schedule\IMipPlugin( \OC::$server->getMailer(), \OC::$server->getLogger()));
|
$server->addPlugin(new \OCA\DAV\CalDAV\Schedule\IMipPlugin( \OC::$server->getMailer(), \OC::$server->getLogger(), new \OC\AppFramework\Utility\TimeFactory()));
|
||||||
$server->addPlugin(new ExceptionLoggerPlugin('caldav', \OC::$server->getLogger()));
|
$server->addPlugin(new ExceptionLoggerPlugin('caldav', \OC::$server->getLogger()));
|
||||||
|
|
||||||
// And off we go!
|
// And off we go!
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* @copyright Copyright (c) 2016, ownCloud, Inc.
|
* @copyright Copyright (c) 2016, ownCloud, Inc.
|
||||||
|
* @copyright Copyright (c) 2017, Georg Ehrke
|
||||||
*
|
*
|
||||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||||
|
* @author Georg Ehrke <oc.list@georgehrke.com>
|
||||||
*
|
*
|
||||||
* @license AGPL-3.0
|
* @license AGPL-3.0
|
||||||
*
|
*
|
||||||
|
@ -21,10 +23,15 @@
|
||||||
*/
|
*/
|
||||||
namespace OCA\DAV\CalDAV\Schedule;
|
namespace OCA\DAV\CalDAV\Schedule;
|
||||||
|
|
||||||
|
use OCP\AppFramework\Utility\ITimeFactory;
|
||||||
use OCP\ILogger;
|
use OCP\ILogger;
|
||||||
use OCP\Mail\IMailer;
|
use OCP\Mail\IMailer;
|
||||||
|
use Sabre\VObject\Component\VCalendar;
|
||||||
|
use Sabre\VObject\DateTimeParser;
|
||||||
use Sabre\VObject\ITip;
|
use Sabre\VObject\ITip;
|
||||||
use Sabre\CalDAV\Schedule\IMipPlugin as SabreIMipPlugin;
|
use Sabre\CalDAV\Schedule\IMipPlugin as SabreIMipPlugin;
|
||||||
|
use Sabre\VObject\Recur\EventIterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* iMIP handler.
|
* iMIP handler.
|
||||||
*
|
*
|
||||||
|
@ -47,15 +54,23 @@ class IMipPlugin extends SabreIMipPlugin {
|
||||||
/** @var ILogger */
|
/** @var ILogger */
|
||||||
private $logger;
|
private $logger;
|
||||||
|
|
||||||
|
/** @var ITimeFactory */
|
||||||
|
private $timeFactory;
|
||||||
|
|
||||||
|
const MAX_DATE = '2038-01-01';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the email handler.
|
* Creates the email handler.
|
||||||
*
|
*
|
||||||
* @param IMailer $mailer
|
* @param IMailer $mailer
|
||||||
|
* @param ILogger $logger
|
||||||
|
* @param ITimeFactory $timeFactory
|
||||||
*/
|
*/
|
||||||
function __construct(IMailer $mailer, ILogger $logger) {
|
function __construct(IMailer $mailer, ILogger $logger, ITimeFactory $timeFactory) {
|
||||||
parent::__construct('');
|
parent::__construct('');
|
||||||
$this->mailer = $mailer;
|
$this->mailer = $mailer;
|
||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
|
$this->timeFactory = $timeFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -85,6 +100,11 @@ class IMipPlugin extends SabreIMipPlugin {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// don't send out mails for events that already took place
|
||||||
|
if ($this->isEventInThePast($iTipMessage->message)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$sender = substr($iTipMessage->sender, 7);
|
$sender = substr($iTipMessage->sender, 7);
|
||||||
$recipient = substr($iTipMessage->recipient, 7);
|
$recipient = substr($iTipMessage->recipient, 7);
|
||||||
|
|
||||||
|
@ -125,4 +145,49 @@ class IMipPlugin extends SabreIMipPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check if event took place in the past already
|
||||||
|
* @param VCalendar $vObject
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function isEventInThePast(VCalendar $vObject) {
|
||||||
|
$component = $vObject->VEVENT;
|
||||||
|
|
||||||
|
$firstOccurrence = $component->DTSTART->getDateTime()->getTimeStamp();
|
||||||
|
// Finding the last occurrence is a bit harder
|
||||||
|
if (!isset($component->RRULE)) {
|
||||||
|
if (isset($component->DTEND)) {
|
||||||
|
$lastOccurrence = $component->DTEND->getDateTime()->getTimeStamp();
|
||||||
|
} elseif (isset($component->DURATION)) {
|
||||||
|
$endDate = clone $component->DTSTART->getDateTime();
|
||||||
|
// $component->DTEND->getDateTime() returns DateTimeImmutable
|
||||||
|
$endDate = $endDate->add(DateTimeParser::parse($component->DURATION->getValue()));
|
||||||
|
$lastOccurrence = $endDate->getTimeStamp();
|
||||||
|
} elseif (!$component->DTSTART->hasTime()) {
|
||||||
|
$endDate = clone $component->DTSTART->getDateTime();
|
||||||
|
// $component->DTSTART->getDateTime() returns DateTimeImmutable
|
||||||
|
$endDate = $endDate->modify('+1 day');
|
||||||
|
$lastOccurrence = $endDate->getTimeStamp();
|
||||||
|
} else {
|
||||||
|
$lastOccurrence = $firstOccurrence;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$it = new EventIterator($vObject, (string)$component->UID);
|
||||||
|
$maxDate = new \DateTime(self::MAX_DATE);
|
||||||
|
if ($it->isInfinite()) {
|
||||||
|
$lastOccurrence = $maxDate->getTimestamp();
|
||||||
|
} else {
|
||||||
|
$end = $it->getDtEnd();
|
||||||
|
while($it->valid() && $end < $maxDate) {
|
||||||
|
$end = $it->getDtEnd();
|
||||||
|
$it->next();
|
||||||
|
|
||||||
|
}
|
||||||
|
$lastOccurrence = $end->getTimestamp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentTime = $this->timeFactory->getTime();
|
||||||
|
return $lastOccurrence < $currentTime;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
*/
|
*/
|
||||||
namespace OCA\DAV;
|
namespace OCA\DAV;
|
||||||
|
|
||||||
|
use OC\AppFramework\Utility\TimeFactory;
|
||||||
use OCA\DAV\CalDAV\Schedule\IMipPlugin;
|
use OCA\DAV\CalDAV\Schedule\IMipPlugin;
|
||||||
use OCA\DAV\CardDAV\ImageExportPlugin;
|
use OCA\DAV\CardDAV\ImageExportPlugin;
|
||||||
use OCA\DAV\CardDAV\PhotoCache;
|
use OCA\DAV\CardDAV\PhotoCache;
|
||||||
|
@ -74,6 +75,7 @@ class Server {
|
||||||
$logger = \OC::$server->getLogger();
|
$logger = \OC::$server->getLogger();
|
||||||
$mailer = \OC::$server->getMailer();
|
$mailer = \OC::$server->getMailer();
|
||||||
$dispatcher = \OC::$server->getEventDispatcher();
|
$dispatcher = \OC::$server->getEventDispatcher();
|
||||||
|
$timezone = new TimeFactory();
|
||||||
|
|
||||||
$root = new RootCollection();
|
$root = new RootCollection();
|
||||||
$this->server = new \OCA\DAV\Connector\Sabre\Server(new CachingTree($root));
|
$this->server = new \OCA\DAV\Connector\Sabre\Server(new CachingTree($root));
|
||||||
|
@ -135,7 +137,7 @@ class Server {
|
||||||
$this->server->addPlugin(new \OCA\DAV\CalDAV\Plugin());
|
$this->server->addPlugin(new \OCA\DAV\CalDAV\Plugin());
|
||||||
$this->server->addPlugin(new \Sabre\CalDAV\ICSExportPlugin());
|
$this->server->addPlugin(new \Sabre\CalDAV\ICSExportPlugin());
|
||||||
$this->server->addPlugin(new \OCA\DAV\CalDAV\Schedule\Plugin());
|
$this->server->addPlugin(new \OCA\DAV\CalDAV\Schedule\Plugin());
|
||||||
$this->server->addPlugin(new IMipPlugin($mailer, $logger));
|
$this->server->addPlugin(new IMipPlugin($mailer, $logger, $timezone));
|
||||||
$this->server->addPlugin(new \Sabre\CalDAV\Subscriptions\Plugin());
|
$this->server->addPlugin(new \Sabre\CalDAV\Subscriptions\Plugin());
|
||||||
$this->server->addPlugin(new \Sabre\CalDAV\Notifications\Plugin());
|
$this->server->addPlugin(new \Sabre\CalDAV\Notifications\Plugin());
|
||||||
$this->server->addPlugin(new DAV\Sharing\Plugin($authBackend, \OC::$server->getRequest()));
|
$this->server->addPlugin(new DAV\Sharing\Plugin($authBackend, \OC::$server->getRequest()));
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* @copyright Copyright (c) 2016, ownCloud, Inc.
|
* @copyright Copyright (c) 2016, ownCloud, Inc.
|
||||||
|
* @copyright Copyright (c) 2017, Georg Ehrke
|
||||||
*
|
*
|
||||||
* @author Joas Schilling <coding@schilljs.com>
|
* @author Joas Schilling <coding@schilljs.com>
|
||||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||||
|
* @author Georg Ehrke <oc.list@georgehrke.com>
|
||||||
*
|
*
|
||||||
* @license AGPL-3.0
|
* @license AGPL-3.0
|
||||||
*
|
*
|
||||||
|
@ -25,6 +27,7 @@ namespace OCA\DAV\Tests\unit\CalDAV\Schedule;
|
||||||
|
|
||||||
use OC\Mail\Mailer;
|
use OC\Mail\Mailer;
|
||||||
use OCA\DAV\CalDAV\Schedule\IMipPlugin;
|
use OCA\DAV\CalDAV\Schedule\IMipPlugin;
|
||||||
|
use OCP\AppFramework\Utility\ITimeFactory;
|
||||||
use OCP\ILogger;
|
use OCP\ILogger;
|
||||||
use Sabre\VObject\Component\VCalendar;
|
use Sabre\VObject\Component\VCalendar;
|
||||||
use Sabre\VObject\ITip\Message;
|
use Sabre\VObject\ITip\Message;
|
||||||
|
@ -40,8 +43,10 @@ class IMipPluginTest extends TestCase {
|
||||||
$mailer->expects($this->once())->method('send');
|
$mailer->expects($this->once())->method('send');
|
||||||
/** @var ILogger | \PHPUnit_Framework_MockObject_MockObject $logger */
|
/** @var ILogger | \PHPUnit_Framework_MockObject_MockObject $logger */
|
||||||
$logger = $this->getMockBuilder('OC\Log')->disableOriginalConstructor()->getMock();
|
$logger = $this->getMockBuilder('OC\Log')->disableOriginalConstructor()->getMock();
|
||||||
|
$timeFactory = $this->getMockBuilder(ITimeFactory::class)->disableOriginalConstructor()->getMock();
|
||||||
|
$timeFactory->method('getTime')->willReturn(1);
|
||||||
|
|
||||||
$plugin = new IMipPlugin($mailer, $logger);
|
$plugin = new IMipPlugin($mailer, $logger, $timeFactory);
|
||||||
$message = new Message();
|
$message = new Message();
|
||||||
$message->method = 'REQUEST';
|
$message->method = 'REQUEST';
|
||||||
$message->message = new VCalendar();
|
$message->message = new VCalendar();
|
||||||
|
@ -49,6 +54,7 @@ class IMipPluginTest extends TestCase {
|
||||||
'UID' => $message->uid,
|
'UID' => $message->uid,
|
||||||
'SEQUENCE' => $message->sequence,
|
'SEQUENCE' => $message->sequence,
|
||||||
'SUMMARY' => 'Fellowship meeting',
|
'SUMMARY' => 'Fellowship meeting',
|
||||||
|
'DTSTART' => new \DateTime('2017-01-01 00:00:00') // 1483228800
|
||||||
]);
|
]);
|
||||||
$message->sender = 'mailto:gandalf@wiz.ard';
|
$message->sender = 'mailto:gandalf@wiz.ard';
|
||||||
$message->recipient = 'mailto:frodo@hobb.it';
|
$message->recipient = 'mailto:frodo@hobb.it';
|
||||||
|
@ -69,8 +75,10 @@ class IMipPluginTest extends TestCase {
|
||||||
$mailer->method('send')->willThrowException(new \Exception());
|
$mailer->method('send')->willThrowException(new \Exception());
|
||||||
/** @var ILogger | \PHPUnit_Framework_MockObject_MockObject $logger */
|
/** @var ILogger | \PHPUnit_Framework_MockObject_MockObject $logger */
|
||||||
$logger = $this->getMockBuilder('OC\Log')->disableOriginalConstructor()->getMock();
|
$logger = $this->getMockBuilder('OC\Log')->disableOriginalConstructor()->getMock();
|
||||||
|
$timeFactory = $this->getMockBuilder(ITimeFactory::class)->disableOriginalConstructor()->getMock();
|
||||||
|
$timeFactory->method('getTime')->willReturn(1);
|
||||||
|
|
||||||
$plugin = new IMipPlugin($mailer, $logger);
|
$plugin = new IMipPlugin($mailer, $logger, $timeFactory);
|
||||||
$message = new Message();
|
$message = new Message();
|
||||||
$message->method = 'REQUEST';
|
$message->method = 'REQUEST';
|
||||||
$message->message = new VCalendar();
|
$message->message = new VCalendar();
|
||||||
|
@ -78,6 +86,7 @@ class IMipPluginTest extends TestCase {
|
||||||
'UID' => $message->uid,
|
'UID' => $message->uid,
|
||||||
'SEQUENCE' => $message->sequence,
|
'SEQUENCE' => $message->sequence,
|
||||||
'SUMMARY' => 'Fellowship meeting',
|
'SUMMARY' => 'Fellowship meeting',
|
||||||
|
'DTSTART' => new \DateTime('2017-01-01 00:00:00') // 1483228800
|
||||||
]);
|
]);
|
||||||
$message->sender = 'mailto:gandalf@wiz.ard';
|
$message->sender = 'mailto:gandalf@wiz.ard';
|
||||||
$message->recipient = 'mailto:frodo@hobb.it';
|
$message->recipient = 'mailto:frodo@hobb.it';
|
||||||
|
@ -90,4 +99,57 @@ class IMipPluginTest extends TestCase {
|
||||||
$this->assertEquals('text/calendar; charset=UTF-8; method=REQUEST', $mailMessage->getSwiftMessage()->getContentType());
|
$this->assertEquals('text/calendar; charset=UTF-8; method=REQUEST', $mailMessage->getSwiftMessage()->getContentType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider dataNoMessageSendForPastEvents
|
||||||
|
*/
|
||||||
|
public function testNoMessageSendForPastEvents($veventParams, $expectsMail) {
|
||||||
|
$mailMessage = new \OC\Mail\Message(new \Swift_Message());
|
||||||
|
/** @var Mailer | \PHPUnit_Framework_MockObject_MockObject $mailer */
|
||||||
|
$mailer = $this->getMockBuilder('OC\Mail\Mailer')->disableOriginalConstructor()->getMock();
|
||||||
|
$mailer->method('createMessage')->willReturn($mailMessage);
|
||||||
|
if ($expectsMail) {
|
||||||
|
$mailer->expects($this->once())->method('send');
|
||||||
|
} else {
|
||||||
|
$mailer->expects($this->never())->method('send');
|
||||||
|
}
|
||||||
|
/** @var ILogger | \PHPUnit_Framework_MockObject_MockObject $logger */
|
||||||
|
$logger = $this->getMockBuilder('OC\Log')->disableOriginalConstructor()->getMock();
|
||||||
|
$timeFactory = $this->getMockBuilder(ITimeFactory::class)->disableOriginalConstructor()->getMock();
|
||||||
|
$timeFactory->method('getTime')->willReturn(1496912528);
|
||||||
|
|
||||||
|
$plugin = new IMipPlugin($mailer, $logger, $timeFactory);
|
||||||
|
$message = new Message();
|
||||||
|
$message->method = 'REQUEST';
|
||||||
|
$message->message = new VCalendar();
|
||||||
|
$message->message->add('VEVENT', array_merge([
|
||||||
|
'UID' => 'uid1337',
|
||||||
|
'SEQUENCE' => 42,
|
||||||
|
'SUMMARY' => 'Fellowship meeting',
|
||||||
|
], $veventParams));
|
||||||
|
$message->sender = 'mailto:gandalf@wiz.ard';
|
||||||
|
$message->recipient = 'mailto:frodo@hobb.it';
|
||||||
|
|
||||||
|
$plugin->schedule($message);
|
||||||
|
|
||||||
|
if ($expectsMail) {
|
||||||
|
$this->assertEquals('1.1', $message->getScheduleStatus());
|
||||||
|
} else {
|
||||||
|
$this->assertEquals(false, $message->getScheduleStatus());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dataNoMessageSendForPastEvents() {
|
||||||
|
return [
|
||||||
|
[['DTSTART' => new \DateTime('2017-01-01 00:00:00')], false],
|
||||||
|
[['DTSTART' => new \DateTime('2017-01-01 00:00:00'), 'DTEND' => new \DateTime('2017-01-01 00:00:00')], false],
|
||||||
|
[['DTSTART' => new \DateTime('2017-01-01 00:00:00'), 'DTEND' => new \DateTime('2017-12-31 00:00:00')], true],
|
||||||
|
[['DTSTART' => new \DateTime('2017-01-01 00:00:00'), 'DURATION' => 'P1D'], false],
|
||||||
|
[['DTSTART' => new \DateTime('2017-01-01 00:00:00'), 'DURATION' => 'P52W'], true],
|
||||||
|
[['DTSTART' => new \DateTime('2017-01-01 00:00:00'), 'DTEND' => new \DateTime('2017-01-01 00:00:00'), 'RRULE' => 'FREQ=WEEKLY'], true],
|
||||||
|
[['DTSTART' => new \DateTime('2017-01-01 00:00:00'), 'DTEND' => new \DateTime('2017-01-01 00:00:00'), 'RRULE' => 'FREQ=WEEKLY;COUNT=3'], false],
|
||||||
|
[['DTSTART' => new \DateTime('2017-01-01 00:00:00'), 'DTEND' => new \DateTime('2017-01-01 00:00:00'), 'RRULE' => 'FREQ=WEEKLY;UNTIL=20170301T000000Z'], false],
|
||||||
|
[['DTSTART' => new \DateTime('2017-01-01 00:00:00'), 'DTEND' => new \DateTime('2017-01-01 00:00:00'), 'RRULE' => 'FREQ=WEEKLY;COUNT=33'], true],
|
||||||
|
[['DTSTART' => new \DateTime('2017-01-01 00:00:00'), 'DTEND' => new \DateTime('2017-01-01 00:00:00'), 'RRULE' => 'FREQ=WEEKLY;UNTIL=20171001T000000Z'], true],
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue