diff options
author | SebastianKrupinski <krupinskis05@gmail.com> | 2025-05-12 14:43:35 -0400 |
---|---|---|
committer | SebastianKrupinski <krupinskis05@gmail.com> | 2025-05-12 15:44:07 -0400 |
commit | ebd80bc142f5f26032a88e461870dcaf14e18263 (patch) | |
tree | 92708211d54f7a8f4f0410f435737c7b9d7dbc3a | |
parent | 0eb530ecdedb3cd11e0eb3cb8c3de466ca3d74a3 (diff) | |
download | nextcloud-server-fix/noid-check-for-properties-before-processing.tar.gz nextcloud-server-fix/noid-check-for-properties-before-processing.zip |
fix: check if properties exist before using themfix/noid-check-for-properties-before-processing
Signed-off-by: SebastianKrupinski <krupinskis05@gmail.com>
-rw-r--r-- | lib/private/Calendar/Manager.php | 137 | ||||
-rw-r--r-- | tests/lib/Calendar/ManagerTest.php | 980 |
2 files changed, 899 insertions, 218 deletions
diff --git a/lib/private/Calendar/Manager.php b/lib/private/Calendar/Manager.php index e86e0e1d410..21370e74d54 100644 --- a/lib/private/Calendar/Manager.php +++ b/lib/private/Calendar/Manager.php @@ -33,6 +33,7 @@ use Sabre\HTTP\Response; use Sabre\VObject\Component\VCalendar; use Sabre\VObject\Component\VEvent; use Sabre\VObject\Component\VFreeBusy; +use Sabre\VObject\ParseException; use Sabre\VObject\Property\VCard\DateTime; use Sabre\VObject\Reader; use Throwable; @@ -235,9 +236,14 @@ class Manager implements IManager { $this->logger->warning('iMip message could not be processed because user has no calendars'); return false; } - - /** @var VCalendar $vObject|null */ - $calendarObject = Reader::read($calendarData); + + try { + /** @var VCalendar $vObject|null */ + $calendarObject = Reader::read($calendarData); + } catch (ParseException $e) { + $this->logger->error('iMip message could not be processed because an error occurred while parsing the iMip message', ['exception' => $e]); + return false; + } if (!isset($calendarObject->METHOD) || $calendarObject->METHOD->getValue() !== 'REQUEST') { $this->logger->warning('iMip message contains an incorrect or invalid method'); @@ -249,6 +255,7 @@ class Manager implements IManager { return false; } + /** @var VEvent|null $vEvent */ $eventObject = $calendarObject->VEVENT; if (!isset($eventObject->UID)) { @@ -256,6 +263,11 @@ class Manager implements IManager { return false; } + if (!isset($eventObject->ORGANIZER)) { + $this->logger->warning('iMip message event dose not contains an organizer'); + return false; + } + if (!isset($eventObject->ATTENDEE)) { $this->logger->warning('iMip message event dose not contains any attendees'); return false; @@ -296,7 +308,7 @@ class Manager implements IManager { } } - $this->logger->warning('iMip message event could not be processed because the no corresponding event was found in any calendar'); + $this->logger->warning('iMip message event could not be processed because no corresponding event was found in any calendar'); return false; } @@ -309,23 +321,51 @@ class Manager implements IManager { string $recipient, string $calendarData, ): bool { - /** @var VCalendar $vObject|null */ - $vObject = Reader::read($calendarData); + + $calendars = $this->getCalendarsForPrincipal($principalUri); + if (empty($calendars)) { + $this->logger->warning('iMip message could not be processed because user has no calendars'); + return false; + } + + try { + /** @var VCalendar $vObject|null */ + $vObject = Reader::read($calendarData); + } catch (ParseException $e) { + $this->logger->error('iMip message could not be processed because an error occurred while parsing the iMip message', ['exception' => $e]); + return false; + } if ($vObject === null) { + $this->logger->warning('iMip message contains an invalid calendar object'); + return false; + } + + if (!isset($vObject->METHOD) || $vObject->METHOD->getValue() !== 'REPLY') { + $this->logger->warning('iMip message contains an incorrect or invalid method'); + return false; + } + + if (!isset($vObject->VEVENT)) { + $this->logger->warning('iMip message contains no event'); return false; } /** @var VEvent|null $vEvent */ - $vEvent = $vObject->{'VEVENT'}; + $vEvent = $vObject->VEVENT; + + if (!isset($vEvent->UID)) { + $this->logger->warning('iMip message event dose not contains a UID'); + return false; + } - if ($vEvent === null) { + if (!isset($vEvent->ORGANIZER)) { + $this->logger->warning('iMip message event dose not contains an organizer'); return false; } - // First, we check if the correct method is passed to us - if (strcasecmp('REPLY', $vObject->{'METHOD'}->getValue()) !== 0) { - $this->logger->warning('Wrong method provided for processing'); + if (!isset($vEvent->ATTENDEE)) { + $this->logger->warning('iMip message event dose not contains any attendees'); return false; } @@ -333,7 +373,7 @@ class Manager implements IManager { $organizer = substr($vEvent->{'ORGANIZER'}->getValue(), 7); if (strcasecmp($recipient, $organizer) !== 0) { - $this->logger->warning('Recipient and ORGANIZER must be identical'); + $this->logger->warning('iMip message event could not be processed because recipient and ORGANIZER must be identical'); return false; } @@ -341,13 +381,7 @@ class Manager implements IManager { /** @var DateTime $eventTime */ $eventTime = $vEvent->{'DTSTART'}; if ($eventTime->getDateTime()->getTimeStamp() < $this->timeFactory->getTime()) { // this might cause issues with recurrences - $this->logger->warning('Only events in the future are processed'); - return false; - } - - $calendars = $this->getCalendarsForPrincipal($principalUri); - if (empty($calendars)) { - $this->logger->warning('Could not find any calendars for principal ' . $principalUri); + $this->logger->warning('iMip message event could not be processed because the event is in the past'); return false; } @@ -369,14 +403,14 @@ class Manager implements IManager { } if (empty($found)) { - $this->logger->info('Event not found in any calendar for principal ' . $principalUri . 'and UID' . $vEvent->{'UID'}->getValue()); + $this->logger->warning('iMip message event could not be processed because no corresponding event was found in any calendar ' . $principalUri . 'and UID' . $vEvent->{'UID'}->getValue()); return false; } try { $found->handleIMipMessage($name, $calendarData); // sabre will handle the scheduling behind the scenes } catch (CalendarException $e) { - $this->logger->error('Could not update calendar for iMIP processing', ['exception' => $e]); + $this->logger->error('An error occurred while processing the iMip message event', ['exception' => $e]); return false; } return true; @@ -393,29 +427,57 @@ class Manager implements IManager { string $recipient, string $calendarData, ): bool { - /** @var VCalendar $vObject|null */ - $vObject = Reader::read($calendarData); + + $calendars = $this->getCalendarsForPrincipal($principalUri); + if (empty($calendars)) { + $this->logger->warning('iMip message could not be processed because user has no calendars'); + return false; + } + + try { + /** @var VCalendar $vObject|null */ + $vObject = Reader::read($calendarData); + } catch (ParseException $e) { + $this->logger->error('iMip message could not be processed because an error occurred while parsing the iMip message', ['exception' => $e]); + return false; + } if ($vObject === null) { + $this->logger->warning('iMip message contains an invalid calendar object'); + return false; + } + + if (!isset($vObject->METHOD) || $vObject->METHOD->getValue() !== 'CANCEL') { + $this->logger->warning('iMip message contains an incorrect or invalid method'); + return false; + } + + if (!isset($vObject->VEVENT)) { + $this->logger->warning('iMip message contains no event'); return false; } /** @var VEvent|null $vEvent */ $vEvent = $vObject->{'VEVENT'}; - if ($vEvent === null) { + if (!isset($vEvent->UID)) { + $this->logger->warning('iMip message event dose not contains a UID'); + return false; + } + + if (!isset($vEvent->ORGANIZER)) { + $this->logger->warning('iMip message event dose not contains an organizer'); return false; } - // First, we check if the correct method is passed to us - if (strcasecmp('CANCEL', $vObject->{'METHOD'}->getValue()) !== 0) { - $this->logger->warning('Wrong method provided for processing'); + if (!isset($vEvent->ATTENDEE)) { + $this->logger->warning('iMip message event dose not contains any attendees'); return false; } $attendee = substr($vEvent->{'ATTENDEE'}->getValue(), 7); if (strcasecmp($recipient, $attendee) !== 0) { - $this->logger->warning('Recipient must be an ATTENDEE of this event'); + $this->logger->warning('iMip message event could not be processed because recipient must be an ATTENDEE of this event'); return false; } @@ -426,7 +488,7 @@ class Manager implements IManager { $organizer = substr($vEvent->{'ORGANIZER'}->getValue(), 7); $isNotOrganizer = ($replyTo !== null) ? (strcasecmp($sender, $organizer) !== 0 && strcasecmp($replyTo, $organizer) !== 0) : (strcasecmp($sender, $organizer) !== 0); if ($isNotOrganizer) { - $this->logger->warning('Sender must be the ORGANIZER of this event'); + $this->logger->warning('iMip message event could not be processed because sender must be the ORGANIZER of this event'); return false; } @@ -434,14 +496,7 @@ class Manager implements IManager { /** @var DateTime $eventTime */ $eventTime = $vEvent->{'DTSTART'}; if ($eventTime->getDateTime()->getTimeStamp() < $this->timeFactory->getTime()) { // this might cause issues with recurrences - $this->logger->warning('Only events in the future are processed'); - return false; - } - - // Check if we have a calendar to work with - $calendars = $this->getCalendarsForPrincipal($principalUri); - if (empty($calendars)) { - $this->logger->warning('Could not find any calendars for principal ' . $principalUri); + $this->logger->warning('iMip message event could not be processed because the event is in the past'); return false; } @@ -463,17 +518,15 @@ class Manager implements IManager { } if (empty($found)) { - $this->logger->info('Event not found in any calendar for principal ' . $principalUri . 'and UID' . $vEvent->{'UID'}->getValue()); - // this is a safe operation - // we can ignore events that have been cancelled but were not in the calendar anyway - return true; + $this->logger->warning('iMip message event could not be processed because no corresponding event was found in any calendar ' . $principalUri . 'and UID' . $vEvent->{'UID'}->getValue()); + return false; } try { $found->handleIMipMessage($name, $calendarData); // sabre will handle the scheduling behind the scenes return true; } catch (CalendarException $e) { - $this->logger->error('Could not update calendar for iMIP processing', ['exception' => $e]); + $this->logger->error('An error occurred while processing the iMip message event', ['exception' => $e]); return false; } } diff --git a/tests/lib/Calendar/ManagerTest.php b/tests/lib/Calendar/ManagerTest.php index 6c01cd90811..cecebcfc4cf 100644 --- a/tests/lib/Calendar/ManagerTest.php +++ b/tests/lib/Calendar/ManagerTest.php @@ -27,8 +27,6 @@ use Psr\Log\LoggerInterface; use Sabre\HTTP\RequestInterface; use Sabre\HTTP\ResponseInterface; use Sabre\VObject\Component\VCalendar; -use Sabre\VObject\Document; -use Sabre\VObject\Reader; use Test\TestCase; /* @@ -60,6 +58,8 @@ class ManagerTest extends TestCase { private ServerFactory&MockObject $serverFactory; private VCalendar $vCalendar1a; + private VCalendar $vCalendar2a; + private VCalendar $vCalendar3a; protected function setUp(): void { parent::setUp(); @@ -90,6 +90,9 @@ class ManagerTest extends TestCase { $vEvent->add('DTSTART', '20240701T080000', ['TZID' => 'America/Toronto']); $vEvent->add('DTEND', '20240701T090000', ['TZID' => 'America/Toronto']); $vEvent->add('SUMMARY', 'Test Event'); + $vEvent->add('SEQUENCE', 3); + $vEvent->add('STATUS', 'CONFIRMED'); + $vEvent->add('TRANSP', 'OPAQUE'); $vEvent->add('ORGANIZER', 'mailto:organizer@testing.com', ['CN' => 'Organizer']); $vEvent->add('ATTENDEE', 'mailto:attendee1@testing.com', [ 'CN' => 'Attendee One', @@ -98,6 +101,45 @@ class ManagerTest extends TestCase { 'ROLE' => 'REQ-PARTICIPANT', 'RSVP' => 'TRUE' ]); + + // construct calendar with a event for reply + $this->vCalendar2a = new VCalendar(); + /** @var VEvent $vEvent */ + $vEvent = $this->vCalendar2a->add('VEVENT', []); + $vEvent->UID->setValue('dcc733bf-b2b2-41f2-a8cf-550ae4b67aff'); + $vEvent->add('DTSTART', '20210820'); + $vEvent->add('DTEND', '20220821'); + $vEvent->add('SUMMARY', 'berry basket'); + $vEvent->add('SEQUENCE', 3); + $vEvent->add('STATUS', 'CONFIRMED'); + $vEvent->add('TRANSP', 'OPAQUE'); + $vEvent->add('ORGANIZER', 'mailto:linus@stardew-tent-living.com', ['CN' => 'admin']); + $vEvent->add('ATTENDEE', 'mailto:pierre@general-store.com', [ + 'CN' => 'pierre@general-store.com', + 'CUTYPE' => 'INDIVIDUAL', + 'ROLE' => 'REQ-PARTICIPANT', + 'PARTSTAT' => 'ACCEPTED', + ]); + + // construct calendar with a event for reply + $this->vCalendar3a = new VCalendar(); + /** @var VEvent $vEvent */ + $vEvent = $this->vCalendar3a->add('VEVENT', []); + $vEvent->UID->setValue('dcc733bf-b2b2-41f2-a8cf-550ae4b67aff'); + $vEvent->add('DTSTART', '20210820'); + $vEvent->add('DTEND', '20220821'); + $vEvent->add('SUMMARY', 'berry basket'); + $vEvent->add('SEQUENCE', 3); + $vEvent->add('STATUS', 'CANCELLED'); + $vEvent->add('TRANSP', 'OPAQUE'); + $vEvent->add('ORGANIZER', 'mailto:linus@stardew-tent-living.com', ['CN' => 'admin']); + $vEvent->add('ATTENDEE', 'mailto:pierre@general-store.com', [ + 'CN' => 'pierre@general-store.com', + 'CUTYPE' => 'INDIVIDUAL', + 'ROLE' => 'REQ-PARTICIPANT', + 'PARTSTAT' => 'ACCEPTED', + ]); + } /** @@ -300,8 +342,42 @@ class ManagerTest extends TestCase { $recipient = 'attendee1@testing.com'; $calendar = $this->vCalendar1a; $calendar->add('METHOD', 'REQUEST'); - // test method + // Act $result = $manager->handleIMipRequest($principalUri, $sender, $recipient, $calendar->serialize()); + // Assert + $this->assertFalse($result); + } + + public function testHandleImipRequestWithInvalidData(): 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, + $this->secureRandom, + $this->userManager, + $this->serverFactory, + ]) + ->onlyMethods(['getCalendarsForPrincipal']) + ->getMock(); + $manager->expects(self::once()) + ->method('getCalendarsForPrincipal') + ->willReturn([$userCalendar]); + // construct logger returns + $this->logger->expects(self::once())->method('error') + ->with('iMip message could not be processed because an error occurred while parsing the iMip message'); + // construct parameters + $principalUri = 'principals/user/attendee1'; + $sender = 'organizer@testing.com'; + $recipient = 'attendee1@testing.com'; + // Act + $result = $manager->handleIMipRequest($principalUri, $sender, $recipient, 'Invalid data'); + // Assert $this->assertFalse($result); } @@ -333,8 +409,9 @@ class ManagerTest extends TestCase { $sender = 'organizer@testing.com'; $recipient = 'attendee1@testing.com'; $calendar = $this->vCalendar1a; - // test method + // Act $result = $manager->handleIMipRequest($principalUri, $sender, $recipient, $calendar->serialize()); + // Assert $this->assertFalse($result); } @@ -367,8 +444,9 @@ class ManagerTest extends TestCase { $recipient = 'attendee1@testing.com'; $calendar = $this->vCalendar1a; $calendar->add('METHOD', 'CANCEL'); - // test method + // Act $result = $manager->handleIMipRequest($principalUri, $sender, $recipient, $calendar->serialize()); + // Assert $this->assertFalse($result); } @@ -402,8 +480,9 @@ class ManagerTest extends TestCase { $calendar = $this->vCalendar1a; $calendar->add('METHOD', 'REQUEST'); $calendar->remove('VEVENT'); - // test method + // Act $result = $manager->handleIMipRequest($principalUri, $sender, $recipient, $calendar->serialize()); + // Assert $this->assertFalse($result); } @@ -437,8 +516,45 @@ class ManagerTest extends TestCase { $calendar = $this->vCalendar1a; $calendar->add('METHOD', 'REQUEST'); $calendar->VEVENT->remove('UID'); - // test method + // Act + $result = $manager->handleIMipRequest($principalUri, $sender, $recipient, $calendar->serialize()); + // Assert + $this->assertFalse($result); + } + + public function testHandleImipRequestWithNoOrganizer(): 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, + $this->secureRandom, + $this->userManager, + $this->serverFactory, + ]) + ->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 an organizer'); + // construct parameters + $principalUri = 'principals/user/attendee1'; + $sender = 'organizer@testing.com'; + $recipient = 'attendee1@testing.com'; + $calendar = $this->vCalendar1a; + $calendar->add('METHOD', 'REQUEST'); + $calendar->VEVENT->remove('ORGANIZER'); + // Act $result = $manager->handleIMipRequest($principalUri, $sender, $recipient, $calendar->serialize()); + // Assert $this->assertFalse($result); } @@ -472,8 +588,9 @@ class ManagerTest extends TestCase { $calendar = $this->vCalendar1a; $calendar->add('METHOD', 'REQUEST'); $calendar->VEVENT->remove('ATTENDEE'); - // test method + // Act $result = $manager->handleIMipRequest($principalUri, $sender, $recipient, $calendar->serialize()); + // Assert $this->assertFalse($result); } @@ -506,8 +623,9 @@ class ManagerTest extends TestCase { $recipient = 'attendee2@testing.com'; $calendar = $this->vCalendar1a; $calendar->add('METHOD', 'REQUEST'); - // test method + // Act $result = $manager->handleIMipRequest($principalUri, $sender, $recipient, $calendar->serialize()); + // Assert $this->assertFalse($result); } @@ -545,15 +663,16 @@ class ManagerTest extends TestCase { ->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'); + ->with('iMip message event could not be processed because 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 + // Act $result = $manager->handleIMipRequest($principalUri, $sender, $recipient, $calendar->serialize()); + // Assert $this->assertFalse($result); } @@ -599,62 +718,152 @@ class ManagerTest extends TestCase { $userCalendar->expects(self::once()) ->method('handleIMipMessage') ->with('', $calendar->serialize()); - // test method + // Act $result = $manager->handleIMipRequest($principalUri, $sender, $recipient, $calendar->serialize()); + // Assert $this->assertTrue($result); } - public function testHandleImipReplyWrongMethod(): void { + public function testHandleImipReplyWithNoCalendars(): void { + // construct calendar manager returns + /** @var Manager&MockObject $manager */ + $manager = $this->getMockBuilder(Manager::class) + ->setConstructorArgs([ + $this->coordinator, + $this->container, + $this->logger, + $this->time, + $this->secureRandom, + $this->userManager, + $this->serverFactory, + ]) + ->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/linus'; $sender = 'pierre@general-store.com'; $recipient = 'linus@stardew-tent-living.com'; - $calendarData = $this->getVCalendarReply(); - $calendarData->METHOD = 'REQUEST'; - - $this->logger->expects(self::once()) - ->method('warning'); - $this->time->expects(self::never()) - ->method('getTime'); + $calendar = $this->vCalendar2a; + $calendar->add('METHOD', 'REPLY'); + // Act + $result = $manager->handleIMipReply($principalUri, $sender, $recipient, $calendar->serialize()); + // Assert + $this->assertFalse($result); + } - $result = $this->manager->handleIMipReply($principalUri, $sender, $recipient, $calendarData->serialize()); + public function testHandleImipReplyWithInvalidData(): 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, + $this->secureRandom, + $this->userManager, + $this->serverFactory, + ]) + ->onlyMethods(['getCalendarsForPrincipal']) + ->getMock(); + $manager->expects(self::once()) + ->method('getCalendarsForPrincipal') + ->willReturn([$userCalendar]); + // construct logger returns + $this->logger->expects(self::once())->method('error') + ->with('iMip message could not be processed because an error occurred while parsing the iMip message'); + // construct parameters + $principalUri = 'principals/user/attendee1'; + $sender = 'organizer@testing.com'; + $recipient = 'attendee1@testing.com'; + // Act + $result = $manager->handleIMipReply($principalUri, $sender, $recipient, 'Invalid data'); + // Assert $this->assertFalse($result); } - public function testHandleImipReplyOrganizerNotRecipient(): void { + public function testHandleImipReplyWithNoMethod(): 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, + $this->secureRandom, + $this->userManager, + $this->serverFactory, + ]) + ->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/linus'; - $recipient = 'pierre@general-store.com'; - $sender = 'linus@stardew-tent-living.com'; - $calendarData = $this->getVCalendarReply(); - - $this->logger->expects(self::once()) - ->method('warning'); - $this->time->expects(self::never()) - ->method('getTime'); - - $result = $this->manager->handleIMipReply($principalUri, $sender, $recipient, $calendarData->serialize()); + $sender = 'pierre@general-store.com'; + $recipient = 'linus@stardew-tent-living.com'; + $calendar = $this->vCalendar2a; + // Act + $result = $manager->handleIMipReply($principalUri, $sender, $recipient, $calendar->serialize()); + // Assert $this->assertFalse($result); } - public function testHandleImipReplyDateInThePast(): void { + public function testHandleImipReplyWithInvalidMethod(): 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, + $this->secureRandom, + $this->userManager, + $this->serverFactory, + ]) + ->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/linus'; $sender = 'pierre@general-store.com'; $recipient = 'linus@stardew-tent-living.com'; - $calendarData = $this->getVCalendarReply(); - $calendarData->VEVENT->DTSTART = new \DateTime('2013-04-07'); // set to in the past - - $this->time->expects(self::once()) - ->method('getTime') - ->willReturn(time()); - - $this->logger->expects(self::once()) - ->method('warning'); - - $result = $this->manager->handleIMipReply($principalUri, $sender, $recipient, $calendarData->serialize()); + $calendar = $this->vCalendar2a; + $calendar->add('METHOD', 'UNKNOWN'); + // Act + $result = $manager->handleIMipReply($principalUri, $sender, $recipient, $calendar->serialize()); + // Assert $this->assertFalse($result); } - public function testHandleImipReplyNoCalendars(): void { - /** @var Manager | \PHPUnit\Framework\MockObject\MockObject $manager */ + public function testHandleImipReplyWithNoEvent(): 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, @@ -665,30 +874,68 @@ class ManagerTest extends TestCase { $this->userManager, $this->serverFactory, ]) - ->setMethods([ - 'getCalendarsForPrincipal' - ]) + ->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/linus'; $sender = 'pierre@general-store.com'; $recipient = 'linus@stardew-tent-living.com'; - $calendarData = $this->getVCalendarReply(); + $calendar = $this->vCalendar2a; + $calendar->add('METHOD', 'REPLY'); + $calendar->remove('VEVENT'); + // Act + $result = $manager->handleIMipReply($principalUri, $sender, $recipient, $calendar->serialize()); + // Assert + $this->assertFalse($result); + } - $this->time->expects(self::once()) - ->method('getTime') - ->willReturn(1628374233); + public function testHandleImipReplyWithNoUid(): 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, + $this->secureRandom, + $this->userManager, + $this->serverFactory, + ]) + ->onlyMethods(['getCalendarsForPrincipal']) + ->getMock(); $manager->expects(self::once()) ->method('getCalendarsForPrincipal') - ->willReturn([]); - $this->logger->expects(self::once()) - ->method('warning'); - - $result = $manager->handleIMipReply($principalUri, $sender, $recipient, $calendarData->serialize()); + ->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/linus'; + $sender = 'pierre@general-store.com'; + $recipient = 'linus@stardew-tent-living.com'; + $calendar = $this->vCalendar2a; + $calendar->add('METHOD', 'REPLY'); + $calendar->VEVENT->remove('UID'); + // Act + $result = $manager->handleIMipReply($principalUri, $sender, $recipient, $calendar->serialize()); + // Assert $this->assertFalse($result); } - public function testHandleImipReplyEventNotFound(): void { - /** @var Manager | \PHPUnit\Framework\MockObject\MockObject $manager */ + public function testHandleImipReplyWithNoOrganizer(): 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, @@ -699,31 +946,141 @@ class ManagerTest extends TestCase { $this->userManager, $this->serverFactory, ]) - ->setMethods([ - 'getCalendarsForPrincipal' + ->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 an organizer'); + // construct parameters + $principalUri = 'principals/user/linus'; + $sender = 'pierre@general-store.com'; + $recipient = 'linus@stardew-tent-living.com'; + $calendar = $this->vCalendar2a; + $calendar->add('METHOD', 'REPLY'); + $calendar->VEVENT->remove('ORGANIZER'); + // Act + $result = $manager->handleIMipReply($principalUri, $sender, $recipient, $calendar->serialize()); + // Assert + $this->assertFalse($result); + } + + public function testHandleImipReplyWithNoAttendee(): 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, + $this->secureRandom, + $this->userManager, + $this->serverFactory, ]) + ->onlyMethods(['getCalendarsForPrincipal']) ->getMock(); - $calendar = $this->createMock(ITestCalendar::class); + $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/linus'; $sender = 'pierre@general-store.com'; $recipient = 'linus@stardew-tent-living.com'; - $calendarData = $this->getVCalendarReply(); + $calendar = $this->vCalendar2a; + $calendar->add('METHOD', 'REPLY'); + $calendar->VEVENT->remove('ATTENDEE'); + // Act + $result = $manager->handleIMipReply($principalUri, $sender, $recipient, $calendar->serialize()); + // Assert + $this->assertFalse($result); + } - $this->time->expects(self::once()) - ->method('getTime') - ->willReturn(1628374233); + public function testHandleImipReplyDateInThePast(): 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, + $this->secureRandom, + $this->userManager, + $this->serverFactory, + ]) + ->onlyMethods(['getCalendarsForPrincipal']) + ->getMock(); $manager->expects(self::once()) ->method('getCalendarsForPrincipal') - ->willReturn([$calendar]); - $calendar->expects(self::once()) + ->willReturn([$userCalendar]); + // construct logger and time returns + $this->logger->expects(self::once())->method('warning') + ->with('iMip message event could not be processed because the event is in the past'); + $this->time->expects(self::once()) + ->method('getTime') + ->willReturn(time()); + // construct parameters + $principalUri = 'principals/user/linus'; + $sender = 'pierre@general-store.com'; + $recipient = 'linus@stardew-tent-living.com'; + $calendarData = clone $this->vCalendar2a; + $calendarData->add('METHOD', 'REPLY'); + $calendarData->VEVENT->DTSTART = new \DateTime('2013-04-07'); // set to in the past + // Act + $result = $manager->handleIMipReply($principalUri, $sender, $recipient, $calendarData->serialize()); + // Assert + $this->assertFalse($result); + } + + public function testHandleImipReplyEventNotFound(): void { + // construct mock user calendar + $userCalendar = $this->createMock(ITestCalendar::class); + $userCalendar->expects(self::once()) ->method('search') ->willReturn([]); - $this->logger->expects(self::once()) - ->method('info'); - $calendar->expects(self::never()) - ->method('handleIMipMessage'); - + // construct mock calendar manager and returns + /** @var Manager&MockObject $manager */ + $manager = $this->getMockBuilder(Manager::class) + ->setConstructorArgs([ + $this->coordinator, + $this->container, + $this->logger, + $this->time, + $this->secureRandom, + $this->userManager, + $this->serverFactory, + ]) + ->onlyMethods(['getCalendarsForPrincipal']) + ->getMock(); + $manager->expects(self::once()) + ->method('getCalendarsForPrincipal') + ->willReturn([$userCalendar]); + // construct time returns + $this->time->expects(self::once()) + ->method('getTime') + ->willReturn(1628374233); + // construct parameters + $principalUri = 'principals/user/linus'; + $sender = 'pierre@general-store.com'; + $recipient = 'linus@stardew-tent-living.com'; + $calendarData = clone $this->vCalendar2a; + $calendarData->add('METHOD', 'REPLY'); + // construct logger return + $this->logger->expects(self::once())->method('warning') + ->with('iMip message event could not be processed because no corresponding event was found in any calendar ' . $principalUri . 'and UID' . $calendarData->VEVENT->UID->getValue()); + // Act $result = $manager->handleIMipReply($principalUri, $sender, $recipient, $calendarData->serialize()); + // Assert $this->assertFalse($result); } @@ -747,7 +1104,8 @@ class ManagerTest extends TestCase { $principalUri = 'principals/user/linus'; $sender = 'pierre@general-store.com'; $recipient = 'linus@stardew-tent-living.com'; - $calendarData = $this->getVCalendarReply(); + $calendarData = clone $this->vCalendar2a; + $calendarData->add('METHOD', 'REPLY'); $this->time->expects(self::once()) ->method('getTime') @@ -761,64 +1119,305 @@ class ManagerTest extends TestCase { $calendar->expects(self::once()) ->method('handleIMipMessage') ->with('testname.ics', $calendarData->serialize()); - + // Act $result = $manager->handleIMipReply($principalUri, $sender, $recipient, $calendarData->serialize()); + // Assert $this->assertTrue($result); } - public function testHandleImipCancelWrongMethod(): void { + public function testHandleImipCancelWithNoCalendars(): void { + // construct calendar manager returns + /** @var Manager&MockObject $manager */ + $manager = $this->getMockBuilder(Manager::class) + ->setConstructorArgs([ + $this->coordinator, + $this->container, + $this->logger, + $this->time, + $this->secureRandom, + $this->userManager, + $this->serverFactory, + ]) + ->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/pierre'; $sender = 'linus@stardew-tent-living.com'; $recipient = 'pierre@general-store.com'; $replyTo = null; - $calendarData = $this->getVCalendarCancel(); - $calendarData->METHOD = 'REQUEST'; - - $this->logger->expects(self::once()) - ->method('warning'); - $this->time->expects(self::never()) - ->method('getTime'); + $calendar = $this->vCalendar3a; + $calendar->add('METHOD', 'CANCEL'); + // Act + $result = $manager->handleIMipCancel($principalUri, $sender, $replyTo, $recipient, $calendar->serialize()); + // Assert + $this->assertFalse($result); + } - $result = $this->manager->handleIMipCancel($principalUri, $sender, $replyTo, $recipient, $calendarData->serialize()); + public function testHandleImipCancelWithInvalidData(): 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, + $this->secureRandom, + $this->userManager, + $this->serverFactory, + ]) + ->onlyMethods(['getCalendarsForPrincipal']) + ->getMock(); + $manager->expects(self::once()) + ->method('getCalendarsForPrincipal') + ->willReturn([$userCalendar]); + // construct logger returns + $this->logger->expects(self::once())->method('error') + ->with('iMip message could not be processed because an error occurred while parsing the iMip message'); + // construct parameters + $principalUri = 'principals/user/attendee1'; + $sender = 'organizer@testing.com'; + $recipient = 'attendee1@testing.com'; + $replyTo = null; + // Act + $result = $manager->handleIMipCancel($principalUri, $sender, $replyTo, $recipient, 'Invalid data'); + // Assert $this->assertFalse($result); } - public function testHandleImipCancelAttendeeNotRecipient(): void { - $principalUri = '/user/admin'; + + public function testHandleImipCancelWithNoMethod(): 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, + $this->secureRandom, + $this->userManager, + $this->serverFactory, + ]) + ->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/pierre'; $sender = 'linus@stardew-tent-living.com'; - $recipient = 'leah@general-store.com'; + $recipient = 'pierre@general-store.com'; $replyTo = null; - $calendarData = $this->getVCalendarCancel(); + $calendar = $this->vCalendar3a; + // Act + $result = $manager->handleIMipCancel($principalUri, $sender, $replyTo, $recipient, $calendar->serialize()); + // Assert + $this->assertFalse($result); + } - $this->logger->expects(self::once()) - ->method('warning'); - $this->time->expects(self::never()) - ->method('getTime'); + public function testHandleImipCancelWithInvalidMethod(): 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, + $this->secureRandom, + $this->userManager, + $this->serverFactory, + ]) + ->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/pierre'; + $sender = 'linus@stardew-tent-living.com'; + $recipient = 'pierre@general-store.com'; + $replyTo = null; + $calendar = $this->vCalendar3a; + $calendar->add('METHOD', 'UNKNOWN'); + // Act + $result = $manager->handleIMipCancel($principalUri, $sender, $replyTo, $recipient, $calendar->serialize()); + // Assert + $this->assertFalse($result); + } - $result = $this->manager->handleIMipCancel($principalUri, $sender, $replyTo, $recipient, $calendarData->serialize()); + public function testHandleImipCancelWithNoEvent(): 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, + $this->secureRandom, + $this->userManager, + $this->serverFactory, + ]) + ->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/pierre'; + $sender = 'linus@stardew-tent-living.com'; + $recipient = 'pierre@general-store.com'; + $replyTo = null; + $calendar = $this->vCalendar3a; + $calendar->add('METHOD', 'CANCEL'); + $calendar->remove('VEVENT'); + // Act + $result = $manager->handleIMipCancel($principalUri, $sender, $replyTo, $recipient, $calendar->serialize()); + // Assert $this->assertFalse($result); } - public function testHandleImipCancelDateInThePast(): void { + public function testHandleImipCancelWithNoUid(): 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, + $this->secureRandom, + $this->userManager, + $this->serverFactory, + ]) + ->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/pierre'; $sender = 'linus@stardew-tent-living.com'; $recipient = 'pierre@general-store.com'; $replyTo = null; - $calendarData = $this->getVCalendarCancel(); - $calendarData->VEVENT->DTSTART = new \DateTime('2013-04-07'); // set to in the past + $calendar = $this->vCalendar3a; + $calendar->add('METHOD', 'CANCEL'); + $calendar->VEVENT->remove('UID'); + // Act + $result = $manager->handleIMipCancel($principalUri, $sender, $replyTo, $recipient, $calendar->serialize()); + // Assert + $this->assertFalse($result); + } - $this->time->expects(self::once()) - ->method('getTime') - ->willReturn(time()); - $this->logger->expects(self::once()) - ->method('warning'); + public function testHandleImipCancelWithNoOrganizer(): 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, + $this->secureRandom, + $this->userManager, + $this->serverFactory, + ]) + ->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 an organizer'); + // construct parameters + $principalUri = 'principals/user/pierre'; + $sender = 'linus@stardew-tent-living.com'; + $recipient = 'pierre@general-store.com'; + $replyTo = null; + $calendar = $this->vCalendar3a; + $calendar->add('METHOD', 'CANCEL'); + $calendar->VEVENT->remove('ORGANIZER'); + // Act + $result = $manager->handleIMipCancel($principalUri, $sender, $replyTo, $recipient, $calendar->serialize()); + // Assert + $this->assertFalse($result); + } - $result = $this->manager->handleIMipCancel($principalUri, $sender, $replyTo, $recipient, $calendarData->serialize()); + public function testHandleImipCancelWithNoAttendee(): 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, + $this->secureRandom, + $this->userManager, + $this->serverFactory, + ]) + ->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/pierre'; + $sender = 'pierre@general-store.com'; + $recipient = 'linus@stardew-tent-living.com'; + $replyTo = null; + $calendar = $this->vCalendar3a; + $calendar->add('METHOD', 'CANCEL'); + $calendar->VEVENT->remove('ATTENDEE'); + // Act + $result = $manager->handleIMipCancel($principalUri, $sender, $replyTo, $recipient, $calendar->serialize()); + // Assert $this->assertFalse($result); } - public function testHandleImipCancelNoCalendars(): void { - /** @var Manager | \PHPUnit\Framework\MockObject\MockObject $manager */ + public function testHandleImipCancelAttendeeNotRecipient(): 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, @@ -829,27 +1428,107 @@ class ManagerTest extends TestCase { $this->userManager, $this->serverFactory, ]) - ->setMethods([ - 'getCalendarsForPrincipal' + ->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 recipient must be an ATTENDEE of this event'); + // construct parameters + $principalUri = 'principals/user/pierre'; + $sender = 'linus@stardew-tent-living.com'; + $recipient = 'leah@general-store.com'; + $replyTo = null; + $calendarData = clone $this->vCalendar3a; + $calendarData->add('METHOD', 'CANCEL'); + // Act + $result = $manager->handleIMipCancel($principalUri, $sender, $replyTo, $recipient, $calendarData->serialize()); + // Assert + $this->assertFalse($result); + } + + public function testHandleImipCancelDateInThePast(): 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, + $this->secureRandom, + $this->userManager, + $this->serverFactory, ]) + ->onlyMethods(['getCalendarsForPrincipal']) ->getMock(); + $manager->expects(self::once()) + ->method('getCalendarsForPrincipal') + ->willReturn([$userCalendar]); + // construct logger and time returns + $this->logger->expects(self::once())->method('warning') + ->with('iMip message event could not be processed because the event is in the past'); + $this->time->expects(self::once()) + ->method('getTime') + ->willReturn(time()); + // construct parameters $principalUri = 'principals/user/pierre'; $sender = 'linus@stardew-tent-living.com'; $recipient = 'pierre@general-store.com'; $replyTo = null; - $calendarData = $this->getVCalendarCancel(); + $calendarData = clone $this->vCalendar3a; + $calendarData->add('METHOD', 'CANCEL'); + $calendarData->VEVENT->DTSTART = new \DateTime('2013-04-07'); // set to in the past + // Act + $result = $manager->handleIMipCancel($principalUri, $sender, $replyTo, $recipient, $calendarData->serialize()); + // Assert + $this->assertFalse($result); + } + public function testHandleImipCancelEventNotFound(): void { + // construct mock user calendar + $userCalendar = $this->createMock(ITestCalendar::class); + $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, + $this->secureRandom, + $this->userManager, + $this->serverFactory, + ]) + ->onlyMethods(['getCalendarsForPrincipal']) + ->getMock(); + $manager->expects(self::once()) + ->method('getCalendarsForPrincipal') + ->willReturn([$userCalendar]); + // construct time returns $this->time->expects(self::once()) ->method('getTime') ->willReturn(1628374233); - $manager->expects(self::once()) - ->method('getCalendarsForPrincipal') - ->with($principalUri) - ->willReturn([]); - $this->logger->expects(self::once()) - ->method('warning'); - + // construct parameters + $principalUri = 'principals/user/pierre'; + $sender = 'linus@stardew-tent-living.com'; + $recipient = 'pierre@general-store.com'; + $replyTo = null; + $calendarData = clone $this->vCalendar3a; + $calendarData->add('METHOD', 'CANCEL'); + // construct logger return + $this->logger->expects(self::once())->method('warning') + ->with('iMip message event could not be processed because no corresponding event was found in any calendar ' . $principalUri . 'and UID' . $calendarData->VEVENT->UID->getValue()); + // Act $result = $manager->handleIMipCancel($principalUri, $sender, $replyTo, $recipient, $calendarData->serialize()); + // Assert $this->assertFalse($result); } @@ -869,12 +1548,14 @@ class ManagerTest extends TestCase { 'getCalendarsForPrincipal' ]) ->getMock(); + $principalUri = 'principals/user/pierre'; - $sender = 'clint@stardew-blacksmiths.com'; + $sender = 'clint@stardew-tent-living.com'; $recipient = 'pierre@general-store.com'; $replyTo = 'linus@stardew-tent-living.com'; $calendar = $this->createMock(ITestCalendar::class); - $calendarData = $this->getVCalendarCancel(); + $calendarData = clone $this->vCalendar3a; + $calendarData->add('METHOD', 'CANCEL'); $this->time->expects(self::once()) ->method('getTime') @@ -889,7 +1570,9 @@ class ManagerTest extends TestCase { $calendar->expects(self::once()) ->method('handleIMipMessage') ->with('testname.ics', $calendarData->serialize()); + // Act $result = $manager->handleIMipCancel($principalUri, $sender, $replyTo, $recipient, $calendarData->serialize()); + // Assert $this->assertTrue($result); } @@ -914,7 +1597,8 @@ class ManagerTest extends TestCase { $recipient = 'pierre@general-store.com'; $replyTo = null; $calendar = $this->createMock(ITestCalendar::class); - $calendarData = $this->getVCalendarCancel(); + $calendarData = clone $this->vCalendar3a; + $calendarData->add('METHOD', 'CANCEL'); $this->time->expects(self::once()) ->method('getTime') @@ -929,68 +1613,12 @@ class ManagerTest extends TestCase { $calendar->expects(self::once()) ->method('handleIMipMessage') ->with('testname.ics', $calendarData->serialize()); + // Act $result = $manager->handleIMipCancel($principalUri, $sender, $replyTo, $recipient, $calendarData->serialize()); + // Assert $this->assertTrue($result); } - private function getVCalendarReply(): Document { - $data = <<<EOF -BEGIN:VCALENDAR -PRODID:-//Nextcloud/Nextcloud CalDAV Server//EN -VERSION:2.0 -CALSCALE:GREGORIAN -METHOD:REPLY -BEGIN:VEVENT -DTSTART;VALUE=DATE:20210820 -DTEND;VALUE=DATE:20220821 -DTSTAMP:20210812T100040Z -ORGANIZER;CN=admin:mailto:linus@stardew-tent-living.com -UID:dcc733bf-b2b2-41f2-a8cf-550ae4b67aff -ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=pierr - e@general-store.com;X-NUM-GUESTS=0:mailto:pierre@general-store.com -CREATED:20220812T100021Z -DESCRIPTION: -LAST-MODIFIED:20220812T100040Z -LOCATION: -SEQUENCE:3 -STATUS:CONFIRMED -SUMMARY:berry basket -TRANSP:OPAQUE -END:VEVENT -END:VCALENDAR -EOF; - return Reader::read($data); - } - - private function getVCalendarCancel(): Document { - $data = <<<EOF -BEGIN:VCALENDAR -PRODID:-//Nextcloud/Nextcloud CalDAV Server//EN -VERSION:2.0 -CALSCALE:GREGORIAN -METHOD:CANCEL -BEGIN:VEVENT -DTSTART;VALUE=DATE:20210820 -DTEND;VALUE=DATE:20220821 -DTSTAMP:20210812T100040Z -ORGANIZER;CN=admin:mailto:linus@stardew-tent-living.com -UID:dcc733bf-b2b2-41f2-a8cf-550ae4b67aff -ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=pierr - e@general-store.com;X-NUM-GUESTS=0:mailto:pierre@general-store.com -CREATED:20220812T100021Z -DESCRIPTION: -LAST-MODIFIED:20220812T100040Z -LOCATION: -SEQUENCE:3 -STATUS:CANCELLED -SUMMARY:berry basket -TRANSP:OPAQUE -END:VEVENT -END:VCALENDAR -EOF; - return Reader::read($data); - } - private function getFreeBusyResponse(): string { return <<<EOF <?xml version="1.0" encoding="utf-8"?> |