aboutsummaryrefslogtreecommitdiffstats
path: root/apps/dav
diff options
context:
space:
mode:
authorAnna Larch <anna@nextcloud.com>2022-06-23 22:17:53 +0200
committerAnna Larch <anna@nextcloud.com>2022-08-22 22:10:12 +0200
commit4ca4b0279372cd6fe11f717ed697f905ecb1e4a2 (patch)
tree6a6c1fbddc1dd6d06e653cd59475a7d4e8be2374 /apps/dav
parent2576609aac3555da0926c27b879df610a8b0f43c (diff)
downloadnextcloud-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.php4
-rw-r--r--apps/dav/lib/CalDAV/CalendarHome.php1
-rw-r--r--apps/dav/lib/CalDAV/CalendarImpl.php71
-rw-r--r--apps/dav/lib/CalDAV/CalendarProvider.php1
-rw-r--r--apps/dav/tests/unit/CalDAV/CalendarImplTest.php79
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);
+ }
}