diff options
author | Anna Larch <anna@nextcloud.com> | 2022-06-23 22:17:53 +0200 |
---|---|---|
committer | Anna Larch <anna@nextcloud.com> | 2022-08-22 22:10:12 +0200 |
commit | 4ca4b0279372cd6fe11f717ed697f905ecb1e4a2 (patch) | |
tree | 6a6c1fbddc1dd6d06e653cd59475a7d4e8be2374 /apps/dav | |
parent | 2576609aac3555da0926c27b879df610a8b0f43c (diff) | |
download | nextcloud-server-4ca4b0279372cd6fe11f717ed697f905ecb1e4a2.tar.gz nextcloud-server-4ca4b0279372cd6fe11f717ed697f905ecb1e4a2.zip |
Support iMIP invitations from Mail
Signed-off-by: Anna Larch <anna@nextcloud.com>
Diffstat (limited to 'apps/dav')
-rw-r--r-- | apps/dav/lib/CalDAV/CalDavBackend.php | 4 | ||||
-rw-r--r-- | apps/dav/lib/CalDAV/CalendarHome.php | 1 | ||||
-rw-r--r-- | apps/dav/lib/CalDAV/CalendarImpl.php | 71 | ||||
-rw-r--r-- | apps/dav/lib/CalDAV/CalendarProvider.php | 1 | ||||
-rw-r--r-- | apps/dav/tests/unit/CalDAV/CalendarImplTest.php | 79 |
5 files changed, 148 insertions, 8 deletions
diff --git a/apps/dav/lib/CalDAV/CalDavBackend.php b/apps/dav/lib/CalDAV/CalDavBackend.php index 2bbdc51f42e..42df838523d 100644 --- a/apps/dav/lib/CalDAV/CalDavBackend.php +++ b/apps/dav/lib/CalDAV/CalDavBackend.php @@ -1864,6 +1864,10 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription } } + if(isset($options['uid'])) { + $outerQuery->andWhere($outerQuery->expr()->eq('uid', $outerQuery->createNamedParameter($options['uid']))); + } + if (!empty($options['types'])) { $or = $outerQuery->expr()->orX(); foreach ($options['types'] as $type) { diff --git a/apps/dav/lib/CalDAV/CalendarHome.php b/apps/dav/lib/CalDAV/CalendarHome.php index ceeba31800e..cd6ae1c2f7f 100644 --- a/apps/dav/lib/CalDAV/CalendarHome.php +++ b/apps/dav/lib/CalDAV/CalendarHome.php @@ -206,7 +206,6 @@ class CalendarHome extends \Sabre\CalDAV\CalendarHome { return $this->caldavBackend->calendarSearch($principalUri, $filters, $limit, $offset); } - public function enableCachedSubscriptionsForThisRequest() { $this->returnCachedSubscriptions = true; } diff --git a/apps/dav/lib/CalDAV/CalendarImpl.php b/apps/dav/lib/CalDAV/CalendarImpl.php index 27a428a4075..a04e520c6bc 100644 --- a/apps/dav/lib/CalDAV/CalendarImpl.php +++ b/apps/dav/lib/CalDAV/CalendarImpl.php @@ -29,10 +29,19 @@ namespace OCA\DAV\CalDAV; use OCA\DAV\CalDAV\Auth\CustomPrincipalPlugin; use OCA\DAV\CalDAV\InvitationResponse\InvitationResponseServer; +use OCP\AppFramework\Utility\ITimeFactory; use OCP\Calendar\Exceptions\CalendarException; use OCP\Calendar\ICreateFromString; use OCP\Constants; +use OCP\Security\ISecureRandom; +use Psr\Log\LoggerInterface; use Sabre\DAV\Exception\Conflict; +use Sabre\VObject\Component\VCalendar; +use Sabre\VObject\Component\VEvent; +use Sabre\VObject\Document; +use Sabre\VObject\ITip\Message; +use Sabre\VObject\Property\VCard\DateTime; +use Sabre\VObject\Reader; use function Sabre\Uri\split as uriSplit; class CalendarImpl implements ICreateFromString { @@ -46,13 +55,6 @@ class CalendarImpl implements ICreateFromString { /** @var array */ private $calendarInfo; - /** - * CalendarImpl constructor. - * - * @param Calendar $calendar - * @param array $calendarInfo - * @param CalDavBackend $backend - */ public function __construct(Calendar $calendar, array $calendarInfo, CalDavBackend $backend) { @@ -177,4 +179,59 @@ class CalendarImpl implements ICreateFromString { fclose($stream); } } + + /** + * @throws CalendarException + */ + public function handleIMipMessage(string $name, string $calendarData): void { + $server = new InvitationResponseServer(false); + + /** @var CustomPrincipalPlugin $plugin */ + $plugin = $server->server->getPlugin('auth'); + // we're working around the previous implementation + // that only allowed the public system principal to be used + // so set the custom principal here + $plugin->setCurrentPrincipal($this->calendar->getPrincipalURI()); + + if (empty($this->calendarInfo['uri'])) { + throw new CalendarException('Could not write to calendar as URI parameter is missing'); + } + // Force calendar change URI + /** @var Schedule\Plugin $schedulingPlugin */ + $schedulingPlugin = $server->server->getPlugin('caldav-schedule'); + // Let sabre handle the rest + $iTipMessage = new Message(); + /** @var VCalendar $vObject */ + $vObject = Reader::read($calendarData); + /** @var VEvent $vEvent */ + $vEvent = $vObject->{'VEVENT'}; + + if($vObject->{'METHOD'} === null) { + throw new CalendarException('No Method provided for scheduling data. Could not process message'); + } + + if(!isset($vEvent->{'ORGANIZER'}) || !isset($vEvent->{'ATTENDEE'})) { + throw new CalendarException('Could not process scheduling data, neccessary data missing from ICAL'); + } + $orgaizer = $vEvent->{'ORGANIZER'}->getValue(); + $attendee = $vEvent->{'ATTENDEE'}->getValue(); + + $iTipMessage->method = $vObject->{'METHOD'}->getValue(); + if($iTipMessage->method === 'REPLY') { + if ($server->isExternalAttendee($vEvent->{'ATTENDEE'}->getValue())) { + $iTipMessage->recipient = $orgaizer; + } else { + $iTipMessage->recipient = $attendee; + } + $iTipMessage->sender = $attendee; + } else if($iTipMessage->method === 'CANCEL') { + $iTipMessage->recipient = $attendee; + $iTipMessage->sender = $orgaizer; + } + $iTipMessage->uid = isset($vEvent->{'UID'}) ? $vEvent->{'UID'}->getValue() : ''; + $iTipMessage->component = 'VEVENT'; + $iTipMessage->sequence = isset($vEvent->{'SEQUENCE'}) ? (int)$vEvent->{'SEQUENCE'}->getValue() : 0; + $iTipMessage->message = $vObject; + $schedulingPlugin->scheduleLocalDelivery($iTipMessage); + } } diff --git a/apps/dav/lib/CalDAV/CalendarProvider.php b/apps/dav/lib/CalDAV/CalendarProvider.php index f29c601db2d..5779111add3 100644 --- a/apps/dav/lib/CalDAV/CalendarProvider.php +++ b/apps/dav/lib/CalDAV/CalendarProvider.php @@ -26,6 +26,7 @@ declare(strict_types=1); namespace OCA\DAV\CalDAV; use OCP\Calendar\ICalendarProvider; +use OCP\Calendar\ICreateFromString; use OCP\IConfig; use OCP\IL10N; use Psr\Log\LoggerInterface; diff --git a/apps/dav/tests/unit/CalDAV/CalendarImplTest.php b/apps/dav/tests/unit/CalDAV/CalendarImplTest.php index af8c056cac7..6842bdadb53 100644 --- a/apps/dav/tests/unit/CalDAV/CalendarImplTest.php +++ b/apps/dav/tests/unit/CalDAV/CalendarImplTest.php @@ -25,9 +25,13 @@ */ namespace OCA\DAV\Tests\unit\CalDAV; +use OCA\DAV\CalDAV\Auth\CustomPrincipalPlugin; use OCA\DAV\CalDAV\CalDavBackend; use OCA\DAV\CalDAV\Calendar; use OCA\DAV\CalDAV\CalendarImpl; +use OCA\DAV\CalDAV\InvitationResponse\InvitationResponseServer; +use OCA\DAV\CalDAV\Schedule\Plugin; +use PHPUnit\Framework\MockObject\MockObject; class CalendarImplTest extends \Test\TestCase { @@ -51,6 +55,7 @@ class CalendarImplTest extends \Test\TestCase { 'id' => 'fancy_id_123', '{DAV:}displayname' => 'user readable name 123', '{http://apple.com/ns/ical/}calendar-color' => '#AABBCC', + 'uri' => '/this/is/a/uri' ]; $this->backend = $this->createMock(CalDavBackend::class); @@ -125,4 +130,78 @@ class CalendarImplTest extends \Test\TestCase { $this->assertEquals(31, $this->calendarImpl->getPermissions()); } + + public function testHandleImipMessage(): void { + $invitationResponseServer = $this->createConfiguredMock(InvitationResponseServer::class, [ + 'server' => $this->createConfiguredMock(CalDavBackend::class, [ + 'getPlugin' => [ + 'auth' => $this->createMock(CustomPrincipalPlugin::class), + 'schedule' => $this->createMock(Plugin::class) + ] + ]) + ]); + + $message = <<<EOF +BEGIN:VCALENDAR +PRODID:-//Nextcloud/Nextcloud CalDAV Server//EN +METHOD:REPLY +VERSION:2.0 +BEGIN:VEVENT +ATTENDEE;PARTSTAT=mailto:lewis@stardew-tent-living.com:ACCEPTED +ORGANIZER:mailto:pierre@generalstore.com +UID:aUniqueUid +SEQUENCE:2 +REQUEST-STATUS:2.0;Success +%sEND:VEVENT +END:VCALENDAR +EOF; + + /** @var CustomPrincipalPlugin|MockObject $authPlugin */ + $authPlugin = $invitationResponseServer->server->getPlugin('auth'); + $authPlugin->expects(self::once()) + ->method('setPrincipalUri') + ->with($this->calendar->getPrincipalURI()); + + /** @var Plugin|MockObject $schedulingPlugin */ + $schedulingPlugin = $invitationResponseServer->server->getPlugin('caldav-schedule'); + $schedulingPlugin->expects(self::once()) + ->method('setPathOfCalendarObjectChange') + ->with('fullcalendarname'); + } + + public function testHandleImipMessageNoCalendarUri(): void { + $invitationResponseServer = $this->createConfiguredMock(InvitationResponseServer::class, [ + 'server' => $this->createConfiguredMock(CalDavBackend::class, [ + 'getPlugin' => [ + 'auth' => $this->createMock(CustomPrincipalPlugin::class), + 'schedule' => $this->createMock(Plugin::class) + ] + ]) + ]); + + $message = <<<EOF +BEGIN:VCALENDAR +PRODID:-//Nextcloud/Nextcloud CalDAV Server//EN +METHOD:REPLY +VERSION:2.0 +BEGIN:VEVENT +ATTENDEE;PARTSTAT=mailto:lewis@stardew-tent-living.com:ACCEPTED +ORGANIZER:mailto:pierre@generalstore.com +UID:aUniqueUid +SEQUENCE:2 +REQUEST-STATUS:2.0;Success +%sEND:VEVENT +END:VCALENDAR +EOF; + + /** @var CustomPrincipalPlugin|MockObject $authPlugin */ + $authPlugin = $invitationResponseServer->server->getPlugin('auth'); + $authPlugin->expects(self::once()) + ->method('setPrincipalUri') + ->with($this->calendar->getPrincipalURI()); + + unset($this->calendarInfo['uri']); + $this->expectException('CalendarException'); + $this->calendarImpl->handleIMipMessage('filename.ics', $message); + } } |