aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/dav/lib/CalDAV/CachedSubscriptionImpl.php13
-rw-r--r--apps/dav/lib/CalDAV/CalendarImpl.php19
-rw-r--r--lib/composer/composer/autoload_classmap.php2
-rw-r--r--lib/composer/composer/autoload_static.php2
-rw-r--r--lib/private/Calendar/Manager.php83
-rw-r--r--lib/public/Calendar/ICalendar.php3
-rw-r--r--lib/public/Calendar/ICalendarIsShared.php25
-rw-r--r--lib/public/Calendar/ICalendarIsWritable.php25
-rw-r--r--lib/public/Calendar/IManager.php7
-rw-r--r--tests/lib/Calendar/ManagerTest.php346
10 files changed, 512 insertions, 13 deletions
diff --git a/apps/dav/lib/CalDAV/CachedSubscriptionImpl.php b/apps/dav/lib/CalDAV/CachedSubscriptionImpl.php
index 00fa90f5d20..4d25f5bb501 100644
--- a/apps/dav/lib/CalDAV/CachedSubscriptionImpl.php
+++ b/apps/dav/lib/CalDAV/CachedSubscriptionImpl.php
@@ -9,9 +9,12 @@ declare(strict_types=1);
namespace OCA\DAV\CalDAV;
use OCP\Calendar\ICalendar;
+use OCP\Calendar\ICalendarIsShared;
+use OCP\Calendar\ICalendarIsWritable;
use OCP\Constants;
-class CachedSubscriptionImpl implements ICalendar {
+class CachedSubscriptionImpl implements ICalendar, ICalendarIsShared, ICalendarIsWritable {
+
public function __construct(
private CachedSubscription $calendar,
/** @var array<string, mixed> */
@@ -83,10 +86,18 @@ class CachedSubscriptionImpl implements ICalendar {
return $result;
}
+ public function isWritable(): bool {
+ return false;
+ }
+
public function isDeleted(): bool {
return false;
}
+ public function isShared(): bool {
+ return true;
+ }
+
public function getSource(): string {
return $this->calendarInfo['source'];
}
diff --git a/apps/dav/lib/CalDAV/CalendarImpl.php b/apps/dav/lib/CalDAV/CalendarImpl.php
index 85ca7f78ca4..919b08eefce 100644
--- a/apps/dav/lib/CalDAV/CalendarImpl.php
+++ b/apps/dav/lib/CalDAV/CalendarImpl.php
@@ -128,6 +128,13 @@ class CalendarImpl implements ICreateFromString, IHandleImipMessage {
}
/**
+ * @since 31.0.0
+ */
+ public function isWritable(): bool {
+ return $this->calendar->canWrite();
+ }
+
+ /**
* @since 26.0.0
*/
public function isDeleted(): bool {
@@ -135,6 +142,13 @@ class CalendarImpl implements ICreateFromString, IHandleImipMessage {
}
/**
+ * @since 31.0.0
+ */
+ public function isShared(): bool {
+ return $this->calendar->isShared();
+ }
+
+ /**
* Create a new calendar event for this calendar
* by way of an ICS string
*
@@ -215,7 +229,10 @@ class CalendarImpl implements ICreateFromString, IHandleImipMessage {
$attendee = $vEvent->{'ATTENDEE'}->getValue();
$iTipMessage->method = $vObject->{'METHOD'}->getValue();
- if ($iTipMessage->method === 'REPLY') {
+ if ($iTipMessage->method === 'REQUEST') {
+ $iTipMessage->sender = $organizer;
+ $iTipMessage->recipient = $attendee;
+ } elseif ($iTipMessage->method === 'REPLY') {
if ($server->isExternalAttendee($vEvent->{'ATTENDEE'}->getValue())) {
$iTipMessage->recipient = $organizer;
} else {
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index 7265edfe95f..352c3c11a9e 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -163,6 +163,8 @@ return array(
'OCP\\Calendar\\BackendTemporarilyUnavailableException' => $baseDir . '/lib/public/Calendar/BackendTemporarilyUnavailableException.php',
'OCP\\Calendar\\Exceptions\\CalendarException' => $baseDir . '/lib/public/Calendar/Exceptions/CalendarException.php',
'OCP\\Calendar\\ICalendar' => $baseDir . '/lib/public/Calendar/ICalendar.php',
+ 'OCP\\Calendar\\ICalendarIsShared' => $baseDir . '/lib/public/Calendar/ICalendarIsShared.php',
+ 'OCP\\Calendar\\ICalendarIsWritable' => $baseDir . '/lib/public/Calendar/ICalendarIsWritable.php',
'OCP\\Calendar\\ICalendarProvider' => $baseDir . '/lib/public/Calendar/ICalendarProvider.php',
'OCP\\Calendar\\ICalendarQuery' => $baseDir . '/lib/public/Calendar/ICalendarQuery.php',
'OCP\\Calendar\\ICreateFromString' => $baseDir . '/lib/public/Calendar/ICreateFromString.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index 4bac34425ac..890c778da1d 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -196,6 +196,8 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\Calendar\\BackendTemporarilyUnavailableException' => __DIR__ . '/../../..' . '/lib/public/Calendar/BackendTemporarilyUnavailableException.php',
'OCP\\Calendar\\Exceptions\\CalendarException' => __DIR__ . '/../../..' . '/lib/public/Calendar/Exceptions/CalendarException.php',
'OCP\\Calendar\\ICalendar' => __DIR__ . '/../../..' . '/lib/public/Calendar/ICalendar.php',
+ 'OCP\\Calendar\\ICalendarIsShared' => __DIR__ . '/../../..' . '/lib/public/Calendar/ICalendarIsShared.php',
+ 'OCP\\Calendar\\ICalendarIsWritable' => __DIR__ . '/../../..' . '/lib/public/Calendar/ICalendarIsWritable.php',
'OCP\\Calendar\\ICalendarProvider' => __DIR__ . '/../../..' . '/lib/public/Calendar/ICalendarProvider.php',
'OCP\\Calendar\\ICalendarQuery' => __DIR__ . '/../../..' . '/lib/public/Calendar/ICalendarQuery.php',
'OCP\\Calendar\\ICreateFromString' => __DIR__ . '/../../..' . '/lib/public/Calendar/ICreateFromString.php',
diff --git a/lib/private/Calendar/Manager.php b/lib/private/Calendar/Manager.php
index fa324273f5c..ba2124a5c23 100644
--- a/lib/private/Calendar/Manager.php
+++ b/lib/private/Calendar/Manager.php
@@ -12,6 +12,8 @@ use OC\AppFramework\Bootstrap\Coordinator;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Calendar\Exceptions\CalendarException;
use OCP\Calendar\ICalendar;
+use OCP\Calendar\ICalendarIsShared;
+use OCP\Calendar\ICalendarIsWritable;
use OCP\Calendar\ICalendarProvider;
use OCP\Calendar\ICalendarQuery;
use OCP\Calendar\ICreateFromString;
@@ -205,6 +207,87 @@ class Manager implements IManager {
}
/**
+ * @since 31.0.0
+ * @throws \OCP\DB\Exception
+ */
+ public function handleIMipRequest(
+ string $principalUri,
+ string $sender,
+ string $recipient,
+ string $calendarData,
+ ): bool {
+
+ $userCalendars = $this->getCalendarsForPrincipal($principalUri);
+ if (empty($userCalendars)) {
+ $this->logger->warning('iMip message could not be processed because user has no calendars');
+ return false;
+ }
+
+ /** @var VCalendar $vObject|null */
+ $calendarObject = Reader::read($calendarData);
+
+ if (!isset($calendarObject->METHOD) || $calendarObject->METHOD->getValue() !== 'REQUEST') {
+ $this->logger->warning('iMip message contains an incorrect or invalid method');
+ return false;
+ }
+
+ if (!isset($calendarObject->VEVENT)) {
+ $this->logger->warning('iMip message contains no event');
+ return false;
+ }
+
+ $eventObject = $calendarObject->VEVENT;
+
+ if (!isset($eventObject->UID)) {
+ $this->logger->warning('iMip message event dose not contains a UID');
+ return false;
+ }
+
+ if (!isset($eventObject->ATTENDEE)) {
+ $this->logger->warning('iMip message event dose not contains any attendees');
+ return false;
+ }
+
+ foreach ($eventObject->ATTENDEE as $entry) {
+ $address = trim(str_replace('mailto:', '', $entry->getValue()));
+ if ($address === $recipient) {
+ $attendee = $address;
+ break;
+ }
+ }
+ if (!isset($attendee)) {
+ $this->logger->warning('iMip message event does not contain a attendee that matches the recipient');
+ return false;
+ }
+
+ foreach ($userCalendars as $calendar) {
+
+ if (!$calendar instanceof ICalendarIsWritable && !$calendar instanceof ICalendarIsShared) {
+ continue;
+ }
+
+ if ($calendar->isDeleted() || !$calendar->isWritable() || $calendar->isShared()) {
+ continue;
+ }
+
+ if (!empty($calendar->search($recipient, ['ATTENDEE'], ['uid' => $eventObject->UID->getValue()]))) {
+ try {
+ if ($calendar instanceof IHandleImipMessage) {
+ $calendar->handleIMipMessage('', $calendarData);
+ }
+ return true;
+ } catch (CalendarException $e) {
+ $this->logger->error('An error occurred while processing the iMip message event', ['exception' => $e]);
+ return false;
+ }
+ }
+ }
+
+ $this->logger->warning('iMip message event could not be processed because the no corresponding event was found in any calendar');
+ return false;
+ }
+
+ /**
* @throws \OCP\DB\Exception
*/
public function handleIMipReply(
diff --git a/lib/public/Calendar/ICalendar.php b/lib/public/Calendar/ICalendar.php
index 2f74d329119..f29d6f30176 100644
--- a/lib/public/Calendar/ICalendar.php
+++ b/lib/public/Calendar/ICalendar.php
@@ -59,7 +59,8 @@ interface ICalendar {
public function getPermissions(): int;
/**
- * Whether the calendar is deleted
+ * Indicates whether the calendar is in the trash bin
+ *
* @since 26.0.0
*/
public function isDeleted(): bool;
diff --git a/lib/public/Calendar/ICalendarIsShared.php b/lib/public/Calendar/ICalendarIsShared.php
new file mode 100644
index 00000000000..8121c826f4e
--- /dev/null
+++ b/lib/public/Calendar/ICalendarIsShared.php
@@ -0,0 +1,25 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar;
+
+/**
+ * ICalendar Interface Extension
+ *
+ * @since 31.0.0
+ */
+interface ICalendarIsShared {
+
+ /**
+ * Indicates whether the calendar is shared with the current user
+ *
+ * @since 31.0.0
+ */
+ public function isShared(): bool;
+
+}
diff --git a/lib/public/Calendar/ICalendarIsWritable.php b/lib/public/Calendar/ICalendarIsWritable.php
new file mode 100644
index 00000000000..f80769e9033
--- /dev/null
+++ b/lib/public/Calendar/ICalendarIsWritable.php
@@ -0,0 +1,25 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar;
+
+/**
+ * ICalendar Interface Extension
+ *
+ * @since 31.0.0
+ */
+interface ICalendarIsWritable {
+
+ /**
+ * Indicates whether the calendar can be modified
+ *
+ * @since 31.0.0
+ */
+ public function isWritable(): bool;
+
+}
diff --git a/lib/public/Calendar/IManager.php b/lib/public/Calendar/IManager.php
index 8a9fe485871..bb3808f133c 100644
--- a/lib/public/Calendar/IManager.php
+++ b/lib/public/Calendar/IManager.php
@@ -138,6 +138,13 @@ interface IManager {
public function newQuery(string $principalUri) : ICalendarQuery;
/**
+ * Handle a iMip REQUEST message
+ *
+ * @since 31.0.0
+ */
+ public function handleIMipRequest(string $principalUri, string $sender, string $recipient, string $calendarData): bool;
+
+ /**
* Handle a iMip REPLY message
*
* @since 25.0.0
diff --git a/tests/lib/Calendar/ManagerTest.php b/tests/lib/Calendar/ManagerTest.php
index 3d1a46d3f2a..f0ca278f352 100644
--- a/tests/lib/Calendar/ManagerTest.php
+++ b/tests/lib/Calendar/ManagerTest.php
@@ -10,11 +10,14 @@ use OC\AppFramework\Bootstrap\Coordinator;
use OC\Calendar\Manager;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Calendar\ICalendar;
+use OCP\Calendar\ICalendarIsShared;
+use OCP\Calendar\ICalendarIsWritable;
use OCP\Calendar\ICreateFromString;
use OCP\Calendar\IHandleImipMessage;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
+use Sabre\VObject\Component\VCalendar;
use Sabre\VObject\Document;
use Sabre\VObject\Reader;
use Test\TestCase;
@@ -22,25 +25,27 @@ use Test\TestCase;
/*
* This allows us to create Mock object supporting both interfaces
*/
-interface ICreateFromStringAndHandleImipMessage extends ICreateFromString, IHandleImipMessage {
+interface ITestCalendar extends ICreateFromString, IHandleImipMessage, ICalendarIsShared, ICalendarIsWritable {
}
class ManagerTest extends TestCase {
- /** @var Coordinator|MockObject */
+ /** @var Coordinator&MockObject */
private $coordinator;
- /** @var MockObject|ContainerInterface */
+ /** @var ContainerInterface&MockObject */
private $container;
- /** @var MockObject|LoggerInterface */
+ /** @var LoggerInterface&MockObject */
private $logger;
/** @var Manager */
private $manager;
- /** @var ITimeFactory|ITimeFactory&MockObject|MockObject */
+ /** @var ITimeFactory&MockObject */
private $time;
+ private VCalendar $vCalendar1a;
+
protected function setUp(): void {
parent::setUp();
@@ -55,6 +60,23 @@ class ManagerTest extends TestCase {
$this->logger,
$this->time,
);
+
+ // construct calendar with a 1 hour event and same start/end time zones
+ $this->vCalendar1a = new VCalendar();
+ /** @var VEvent $vEvent */
+ $vEvent = $this->vCalendar1a->add('VEVENT', []);
+ $vEvent->UID->setValue('96a0e6b1-d886-4a55-a60d-152b31401dcc');
+ $vEvent->add('DTSTART', '20240701T080000', ['TZID' => 'America/Toronto']);
+ $vEvent->add('DTEND', '20240701T090000', ['TZID' => 'America/Toronto']);
+ $vEvent->add('SUMMARY', 'Test Event');
+ $vEvent->add('ORGANIZER', 'mailto:organizer@testing.com', ['CN' => 'Organizer']);
+ $vEvent->add('ATTENDEE', 'mailto:attendee1@testing.com', [
+ 'CN' => 'Attendee One',
+ 'CUTYPE' => 'INDIVIDUAL',
+ 'PARTSTAT' => 'NEEDS-ACTION',
+ 'ROLE' => 'REQ-PARTICIPANT',
+ 'RSVP' => 'TRUE'
+ ]);
}
/**
@@ -230,6 +252,310 @@ class ManagerTest extends TestCase {
$this->assertTrue($isEnabled);
}
+ public function testHandleImipRequestWithNoCalendars(): void {
+ // construct calendar manager returns
+ /** @var Manager&MockObject $manager */
+ $manager = $this->getMockBuilder(Manager::class)
+ ->setConstructorArgs([
+ $this->coordinator,
+ $this->container,
+ $this->logger,
+ $this->time
+ ])
+ ->onlyMethods(['getCalendarsForPrincipal'])
+ ->getMock();
+ $manager->expects(self::once())
+ ->method('getCalendarsForPrincipal')
+ ->willReturn([]);
+ // construct logger returns
+ $this->logger->expects(self::once())->method('warning')
+ ->with('iMip message could not be processed because user has no calendars');
+ // construct parameters
+ $principalUri = 'principals/user/attendee1';
+ $sender = 'organizer@testing.com';
+ $recipient = 'attendee1@testing.com';
+ $calendar = $this->vCalendar1a;
+ $calendar->add('METHOD', 'REQUEST');
+ // test method
+ $result = $manager->handleIMipRequest($principalUri, $sender, $recipient, $calendar->serialize());
+ $this->assertFalse($result);
+ }
+
+ public function testHandleImipRequestWithNoMethod(): void {
+ // construct mock user calendar
+ $userCalendar = $this->createMock(ITestCalendar::class);
+ // construct mock calendar manager and returns
+ /** @var Manager&MockObject $manager */
+ $manager = $this->getMockBuilder(Manager::class)
+ ->setConstructorArgs([
+ $this->coordinator,
+ $this->container,
+ $this->logger,
+ $this->time
+ ])
+ ->onlyMethods(['getCalendarsForPrincipal'])
+ ->getMock();
+ $manager->expects(self::once())
+ ->method('getCalendarsForPrincipal')
+ ->willReturn([$userCalendar]);
+ // construct logger returns
+ $this->logger->expects(self::once())->method('warning')
+ ->with('iMip message contains an incorrect or invalid method');
+ // construct parameters
+ $principalUri = 'principals/user/attendee1';
+ $sender = 'organizer@testing.com';
+ $recipient = 'attendee1@testing.com';
+ $calendar = $this->vCalendar1a;
+ // test method
+ $result = $manager->handleIMipRequest($principalUri, $sender, $recipient, $calendar->serialize());
+ $this->assertFalse($result);
+ }
+
+ public function testHandleImipRequestWithInvalidMethod(): void {
+ // construct mock user calendar
+ $userCalendar = $this->createMock(ITestCalendar::class);
+ // construct mock calendar manager and returns
+ /** @var Manager&MockObject $manager */
+ $manager = $this->getMockBuilder(Manager::class)
+ ->setConstructorArgs([
+ $this->coordinator,
+ $this->container,
+ $this->logger,
+ $this->time
+ ])
+ ->onlyMethods(['getCalendarsForPrincipal'])
+ ->getMock();
+ $manager->expects(self::once())
+ ->method('getCalendarsForPrincipal')
+ ->willReturn([$userCalendar]);
+ // construct logger returns
+ $this->logger->expects(self::once())->method('warning')
+ ->with('iMip message contains an incorrect or invalid method');
+ // construct parameters
+ $principalUri = 'principals/user/attendee1';
+ $sender = 'organizer@testing.com';
+ $recipient = 'attendee1@testing.com';
+ $calendar = $this->vCalendar1a;
+ $calendar->add('METHOD', 'CANCEL');
+ // test method
+ $result = $manager->handleIMipRequest($principalUri, $sender, $recipient, $calendar->serialize());
+ $this->assertFalse($result);
+ }
+
+ public function testHandleImipRequestWithNoEvent(): void {
+ // construct mock user calendar
+ $userCalendar = $this->createMock(ITestCalendar::class);
+ // construct mock calendar manager and returns
+ /** @var Manager&MockObject $manager */
+ $manager = $this->getMockBuilder(Manager::class)
+ ->setConstructorArgs([
+ $this->coordinator,
+ $this->container,
+ $this->logger,
+ $this->time
+ ])
+ ->onlyMethods(['getCalendarsForPrincipal'])
+ ->getMock();
+ $manager->expects(self::once())
+ ->method('getCalendarsForPrincipal')
+ ->willReturn([$userCalendar]);
+ // construct logger returns
+ $this->logger->expects(self::once())->method('warning')
+ ->with('iMip message contains no event');
+ // construct parameters
+ $principalUri = 'principals/user/attendee1';
+ $sender = 'organizer@testing.com';
+ $recipient = 'attendee1@testing.com';
+ $calendar = $this->vCalendar1a;
+ $calendar->add('METHOD', 'REQUEST');
+ $calendar->remove('VEVENT');
+ // test method
+ $result = $manager->handleIMipRequest($principalUri, $sender, $recipient, $calendar->serialize());
+ $this->assertFalse($result);
+ }
+
+ public function testHandleImipRequestWithNoUid(): void {
+ // construct mock user calendar
+ $userCalendar = $this->createMock(ITestCalendar::class);
+ // construct mock calendar manager and returns
+ /** @var Manager&MockObject $manager */
+ $manager = $this->getMockBuilder(Manager::class)
+ ->setConstructorArgs([
+ $this->coordinator,
+ $this->container,
+ $this->logger,
+ $this->time
+ ])
+ ->onlyMethods(['getCalendarsForPrincipal'])
+ ->getMock();
+ $manager->expects(self::once())
+ ->method('getCalendarsForPrincipal')
+ ->willReturn([$userCalendar]);
+ // construct logger returns
+ $this->logger->expects(self::once())->method('warning')
+ ->with('iMip message event dose not contains a UID');
+ // construct parameters
+ $principalUri = 'principals/user/attendee1';
+ $sender = 'organizer@testing.com';
+ $recipient = 'attendee1@testing.com';
+ $calendar = $this->vCalendar1a;
+ $calendar->add('METHOD', 'REQUEST');
+ $calendar->VEVENT->remove('UID');
+ // test method
+ $result = $manager->handleIMipRequest($principalUri, $sender, $recipient, $calendar->serialize());
+ $this->assertFalse($result);
+ }
+
+ public function testHandleImipRequestWithNoAttendee(): void {
+ // construct mock user calendar
+ $userCalendar = $this->createMock(ITestCalendar::class);
+ // construct mock calendar manager and returns
+ /** @var Manager&MockObject $manager */
+ $manager = $this->getMockBuilder(Manager::class)
+ ->setConstructorArgs([
+ $this->coordinator,
+ $this->container,
+ $this->logger,
+ $this->time
+ ])
+ ->onlyMethods(['getCalendarsForPrincipal'])
+ ->getMock();
+ $manager->expects(self::once())
+ ->method('getCalendarsForPrincipal')
+ ->willReturn([$userCalendar]);
+ // construct logger returns
+ $this->logger->expects(self::once())->method('warning')
+ ->with('iMip message event dose not contains any attendees');
+ // construct parameters
+ $principalUri = 'principals/user/attendee1';
+ $sender = 'organizer@testing.com';
+ $recipient = 'attendee1@testing.com';
+ $calendar = $this->vCalendar1a;
+ $calendar->add('METHOD', 'REQUEST');
+ $calendar->VEVENT->remove('ATTENDEE');
+ // test method
+ $result = $manager->handleIMipRequest($principalUri, $sender, $recipient, $calendar->serialize());
+ $this->assertFalse($result);
+ }
+
+ public function testHandleImipRequestWithInvalidAttendee(): void {
+ // construct mock user calendar
+ $userCalendar = $this->createMock(ITestCalendar::class);
+ // construct mock calendar manager and returns
+ /** @var Manager&MockObject $manager */
+ $manager = $this->getMockBuilder(Manager::class)
+ ->setConstructorArgs([
+ $this->coordinator,
+ $this->container,
+ $this->logger,
+ $this->time
+ ])
+ ->onlyMethods(['getCalendarsForPrincipal'])
+ ->getMock();
+ $manager->expects(self::once())
+ ->method('getCalendarsForPrincipal')
+ ->willReturn([$userCalendar]);
+ // construct logger returns
+ $this->logger->expects(self::once())->method('warning')
+ ->with('iMip message event does not contain a attendee that matches the recipient');
+ // construct parameters
+ $principalUri = 'principals/user/attendee1';
+ $sender = 'organizer@testing.com';
+ $recipient = 'attendee2@testing.com';
+ $calendar = $this->vCalendar1a;
+ $calendar->add('METHOD', 'REQUEST');
+ // test method
+ $result = $manager->handleIMipRequest($principalUri, $sender, $recipient, $calendar->serialize());
+ $this->assertFalse($result);
+ }
+
+ public function testHandleImipRequestWithNoMatch(): void {
+ // construct mock user calendar
+ $userCalendar = $this->createMock(ITestCalendar::class);
+ $userCalendar->expects(self::once())
+ ->method('isDeleted')
+ ->willReturn(false);
+ $userCalendar->expects(self::once())
+ ->method('isWritable')
+ ->willReturn(true);
+ $userCalendar->expects(self::once())
+ ->method('isShared')
+ ->willReturn(false);
+ $userCalendar->expects(self::once())
+ ->method('search')
+ ->willReturn([]);
+ // construct mock calendar manager and returns
+ /** @var Manager&MockObject $manager */
+ $manager = $this->getMockBuilder(Manager::class)
+ ->setConstructorArgs([
+ $this->coordinator,
+ $this->container,
+ $this->logger,
+ $this->time
+ ])
+ ->onlyMethods(['getCalendarsForPrincipal'])
+ ->getMock();
+ $manager->expects(self::once())
+ ->method('getCalendarsForPrincipal')
+ ->willReturn([$userCalendar]);
+ // construct logger returns
+ $this->logger->expects(self::once())->method('warning')
+ ->with('iMip message event could not be processed because the no corresponding event was found in any calendar');
+ // construct parameters
+ $principalUri = 'principals/user/attendee1';
+ $sender = 'organizer@testing.com';
+ $recipient = 'attendee1@testing.com';
+ $calendar = $this->vCalendar1a;
+ $calendar->add('METHOD', 'REQUEST');
+ // test method
+ $result = $manager->handleIMipRequest($principalUri, $sender, $recipient, $calendar->serialize());
+ $this->assertFalse($result);
+ }
+
+ public function testHandleImipRequest(): void {
+ // construct mock user calendar
+ $userCalendar = $this->createMock(ITestCalendar::class);
+ $userCalendar->expects(self::once())
+ ->method('isDeleted')
+ ->willReturn(false);
+ $userCalendar->expects(self::once())
+ ->method('isWritable')
+ ->willReturn(true);
+ $userCalendar->expects(self::once())
+ ->method('isShared')
+ ->willReturn(false);
+ $userCalendar->expects(self::once())
+ ->method('search')
+ ->willReturn([['uri' => 'principals/user/attendee1/personal']]);
+ // construct mock calendar manager and returns
+ /** @var Manager&MockObject $manager */
+ $manager = $this->getMockBuilder(Manager::class)
+ ->setConstructorArgs([
+ $this->coordinator,
+ $this->container,
+ $this->logger,
+ $this->time
+ ])
+ ->onlyMethods(['getCalendarsForPrincipal'])
+ ->getMock();
+ $manager->expects(self::once())
+ ->method('getCalendarsForPrincipal')
+ ->willReturn([$userCalendar]);
+ // construct parameters
+ $principalUri = 'principals/user/attendee1';
+ $sender = 'organizer@testing.com';
+ $recipient = 'attendee1@testing.com';
+ $calendar = $this->vCalendar1a;
+ $calendar->add('METHOD', 'REQUEST');
+ // construct user calendar returns
+ $userCalendar->expects(self::once())
+ ->method('handleIMipMessage')
+ ->with('', $calendar->serialize());
+ // test method
+ $result = $manager->handleIMipRequest($principalUri, $sender, $recipient, $calendar->serialize());
+ $this->assertTrue($result);
+ }
+
public function testHandleImipReplyWrongMethod(): void {
$principalUri = 'principals/user/linus';
$sender = 'pierre@general-store.com';
@@ -323,7 +649,7 @@ class ManagerTest extends TestCase {
'getCalendarsForPrincipal'
])
->getMock();
- $calendar = $this->createMock(ICreateFromStringAndHandleImipMessage::class);
+ $calendar = $this->createMock(ITestCalendar::class);
$principalUri = 'principals/user/linus';
$sender = 'pierre@general-store.com';
$recipient = 'linus@stardew-tent-living.com';
@@ -360,7 +686,7 @@ class ManagerTest extends TestCase {
'getCalendarsForPrincipal'
])
->getMock();
- $calendar = $this->createMock(ICreateFromStringAndHandleImipMessage::class);
+ $calendar = $this->createMock(ITestCalendar::class);
$principalUri = 'principals/user/linus';
$sender = 'pierre@general-store.com';
$recipient = 'linus@stardew-tent-living.com';
@@ -484,7 +810,7 @@ class ManagerTest extends TestCase {
$sender = 'clint@stardew-blacksmiths.com';
$recipient = 'pierre@general-store.com';
$replyTo = 'linus@stardew-tent-living.com';
- $calendar = $this->createMock(ICreateFromStringAndHandleImipMessage::class);
+ $calendar = $this->createMock(ITestCalendar::class);
$calendarData = $this->getVCalendarCancel();
$this->time->expects(self::once())
@@ -521,7 +847,7 @@ class ManagerTest extends TestCase {
$sender = 'linus@stardew-tent-living.com';
$recipient = 'pierre@general-store.com';
$replyTo = null;
- $calendar = $this->createMock(ICreateFromStringAndHandleImipMessage::class);
+ $calendar = $this->createMock(ITestCalendar::class);
$calendarData = $this->getVCalendarCancel();
$this->time->expects(self::once())
@@ -540,7 +866,7 @@ class ManagerTest extends TestCase {
$result = $manager->handleIMipCancel($principalUri, $sender, $replyTo, $recipient, $calendarData->serialize());
$this->assertTrue($result);
}
-
+
private function getVCalendarReply(): Document {
$data = <<<EOF
BEGIN:VCALENDAR