Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fe5b5a7

Browse files
committed
fix(dav): allow multiple organizers if possible
This is very hacky! However, we want to allow saving events with multiple organizers. Those events are not RFC compliant, but sometimes imported from major external calendar services (e.g. Google). If the current user is not an organizer of the event we ignore the exception as no scheduling messages will be sent anyway. Signed-off-by: Richard Steinmetz <[email protected]>
1 parent 725585f commit fe5b5a7

File tree

1 file changed

+67
-1
lines changed

1 file changed

+67
-1
lines changed

apps/dav/lib/CalDAV/Schedule/Plugin.php

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,14 @@
3636
use OCP\IConfig;
3737
use Psr\Log\LoggerInterface;
3838
use Sabre\CalDAV\ICalendar;
39+
use Sabre\CalDAV\ICalendarObject;
40+
use Sabre\CalDAV\Schedule\ISchedulingObject;
3941
use Sabre\DAV\INode;
4042
use Sabre\DAV\IProperties;
4143
use Sabre\DAV\PropFind;
4244
use Sabre\DAV\Server;
4345
use Sabre\DAV\Xml\Property\LocalHref;
46+
use Sabre\DAVACL\IACL;
4447
use Sabre\DAVACL\IPrincipal;
4548
use Sabre\HTTP\RequestInterface;
4649
use Sabre\HTTP\ResponseInterface;
@@ -50,6 +53,7 @@
5053
use Sabre\VObject\DateTimeParser;
5154
use Sabre\VObject\FreeBusyGenerator;
5255
use Sabre\VObject\ITip;
56+
use Sabre\VObject\ITip\SameOrganizerForAllComponentsException;
5357
use Sabre\VObject\Parameter;
5458
use Sabre\VObject\Property;
5559
use Sabre\VObject\Reader;
@@ -161,7 +165,29 @@ public function calendarObjectChange(RequestInterface $request, ResponseInterfac
161165
$this->pathOfCalendarObjectChange = $request->getPath();
162166
}
163167

164-
parent::calendarObjectChange($request, $response, $vCal, $calendarPath, $modified, $isNew);
168+
try {
169+
parent::calendarObjectChange($request, $response, $vCal, $calendarPath, $modified, $isNew);
170+
} catch (SameOrganizerForAllComponentsException $e) {
171+
$this->handleSameOrganizerException($e, $vCal, $calendarPath);
172+
}
173+
}
174+
175+
/**
176+
* @inheritDoc
177+
*/
178+
public function beforeUnbind($path): void {
179+
try {
180+
parent::beforeUnbind($path);
181+
} catch (SameOrganizerForAllComponentsException $e) {
182+
$node = $this->server->tree->getNodeForPath($path);
183+
if (!$node instanceof ICalendarObject || $node instanceof ISchedulingObject) {
184+
throw $e;
185+
}
186+
187+
/** @var VCalendar $vCal */
188+
$vCal = Reader::read($node->get());
189+
$this->handleSameOrganizerException($e, $vCal, $path);
190+
}
165191
}
166192

167193
/**
@@ -630,4 +656,44 @@ private function createCalendar(CalendarHome $calendarHome, string $principalUri
630656
'{DAV:}displayname' => $displayName,
631657
]);
632658
}
659+
660+
/**
661+
* Try to handle the given exception gracefully or throw it if necessary.
662+
*
663+
* @throws SameOrganizerForAllComponentsException If the exception should not be ignored
664+
*/
665+
private function handleSameOrganizerException(
666+
SameOrganizerForAllComponentsException $e,
667+
VCalendar $vCal,
668+
string $calendarPath,
669+
): void {
670+
// This is very hacky! However, we want to allow saving events with multiple
671+
// organizers. Those events are not RFC compliant, but sometimes imported from major
672+
// external calendar services (e.g. Google). If the current user is not an organizer of
673+
// the event we ignore the exception as no scheduling messages will be sent anyway.
674+
675+
// It would be cleaner to patch Sabre to validate organizers *after* checking if
676+
// scheduling messages are necessary. Currently, organizers are validated first and
677+
// afterwards the broker checks if messages should be scheduled. So the code will throw
678+
// even if the organizers are not relevant. This is to ensure compliance with RFCs but
679+
// a bit too strict for real world usage.
680+
681+
if (!isset($vCal->VEVENT)) {
682+
throw $e;
683+
}
684+
685+
$calendarNode = $this->server->tree->getNodeForPath($calendarPath);
686+
if (!($calendarNode instanceof IACL)) {
687+
// Should always be an instance of IACL but just to be sure
688+
throw $e;
689+
}
690+
691+
$addresses = $this->getAddressesForPrincipal($calendarNode->getOwner());
692+
foreach ($vCal->VEVENT as $vevent) {
693+
if (in_array($vevent->ORGANIZER->getNormalizedValue(), $addresses, true)) {
694+
// User is an organizer => throw the exception
695+
throw $e;
696+
}
697+
}
698+
}
633699
}

0 commit comments

Comments
 (0)