diff --git a/apps/dav/lib/CalDAV/CalDavBackend.php b/apps/dav/lib/CalDAV/CalDavBackend.php index 51eb505124e38..5a284efecfa9c 100644 --- a/apps/dav/lib/CalDAV/CalDavBackend.php +++ b/apps/dav/lib/CalDAV/CalDavBackend.php @@ -356,6 +356,7 @@ public function getCalendarsForUser($principalUri) { '{' . Plugin::NS_CALDAV . '}supported-calendar-component-set' => new SupportedCalendarComponentSet($components), '{' . Plugin::NS_CALDAV . '}schedule-calendar-transp' => new ScheduleCalendarTransp($row['transparent']?'transparent':'opaque'), '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}owner-principal' => $this->convertPrincipal($principalUri, !$this->legacyEndpoint), + ]; $calendar = $this->rowToCalendar($row, $calendar); @@ -1847,7 +1848,24 @@ public function search(array $calendarInfo, $pattern, array $searchProperties, ->from('calendarobjects', 'c') ->where($outerQuery->expr()->isNull('deleted_at')); - if (isset($options['timerange'])) { + if (isset($options['timerange']) && in_array('VTODO', $options['types'])) { + // allow VTODOS in the same query if they are requested in the options. + // they do not have a first / last occurence set and would otherwise not be returned + if (isset($options['timerange']['start']) && $options['timerange']['start'] instanceof DateTimeInterface) { + $or1 = $outerQuery->expr()->orX(); + $or1->add($outerQuery->expr()->gt('lastoccurence', + $outerQuery->createNamedParameter($options['timerange']['start']->getTimeStamp()))); + $or1->add($outerQuery->expr()->isNull('lastoccurence')); + $outerQuery->andWhere($or1); + } + if (isset($options['timerange']['end']) && $options['timerange']['end'] instanceof DateTimeInterface) { + $or2 = $outerQuery->expr()->orX(); + $or2->add($outerQuery->expr()->gt('firstoccurence', + $outerQuery->createNamedParameter($options['timerange']['start']->getTimeStamp()))); + $or2->add($outerQuery->expr()->isNull('firstoccurence')); + $outerQuery->andWhere($or2); + } + } else { if (isset($options['timerange']['start']) && $options['timerange']['start'] instanceof DateTimeInterface) { $outerQuery->andWhere($outerQuery->expr()->gt('lastoccurence', $outerQuery->createNamedParameter($options['timerange']['start']->getTimeStamp()))); @@ -1863,16 +1881,33 @@ public function search(array $calendarInfo, $pattern, array $searchProperties, } if (!empty($options['types'])) { - $or = $outerQuery->expr()->orX(); + $or3 = $outerQuery->expr()->orX(); foreach ($options['types'] as $type) { - $or->add($outerQuery->expr()->eq('componenttype', + $or3->add($outerQuery->expr()->eq('componenttype', $outerQuery->createNamedParameter($type))); } - $outerQuery->andWhere($or); + $outerQuery->andWhere($or3); } $outerQuery->andWhere($outerQuery->expr()->in('c.id', $outerQuery->createFunction($innerQuery->getSQL()))); + $allowedSorts = ['id','calendarid', 'lastmodified', 'firstoccurence', 'lastoccurence']; + if(!empty($options['sort_asc'])) { + foreach($options['sort_asc'] as $sort) { + if(!in_array($sort, $allowedSorts)) { + continue; + } + $outerQuery->orderBy($sort, 'ASC'); + } + } + if(!empty($options['sort_desc'])) { + foreach($options['sort_desc'] as $sort) { + if(!in_array($sort, $allowedSorts)) { + continue; + } + $outerQuery->orderBy($sort, 'DESC'); + } + } if ($offset) { $outerQuery->setFirstResult($offset); } diff --git a/apps/dav/lib/CalDAV/CalendarImpl.php b/apps/dav/lib/CalDAV/CalendarImpl.php index cc57aa3646932..b7b50ef42f658 100644 --- a/apps/dav/lib/CalDAV/CalendarImpl.php +++ b/apps/dav/lib/CalDAV/CalendarImpl.php @@ -32,16 +32,18 @@ use OCA\DAV\CalDAV\InvitationResponse\InvitationResponseServer; use OCP\Calendar\Exceptions\CalendarException; use OCP\Calendar\ICreateFromString; +use OCP\Calendar\IGetTimezone; use OCP\Calendar\IHandleImipMessage; use OCP\Constants; use Sabre\DAV\Exception\Conflict; use Sabre\VObject\Component\VCalendar; use Sabre\VObject\Component\VEvent; +use Sabre\VObject\Component\VTimeZone; use Sabre\VObject\ITip\Message; use Sabre\VObject\Reader; use function Sabre\Uri\split as uriSplit; -class CalendarImpl implements ICreateFromString, IHandleImipMessage { +class CalendarImpl implements ICreateFromString, IHandleImipMessage, IGetTimezone { private CalDavBackend $backend; private Calendar $calendar; /** @var array */ @@ -235,4 +237,14 @@ public function handleIMipMessage(string $name, string $calendarData): void { public function getInvitationResponseServer(): InvitationResponseServer { return new InvitationResponseServer(false); } + + public function getCalendarTimezoneString(): ?string { + $vTimezoneString = $this->calendarInfo['{urn:ietf:params:xml:ns:caldav}calendar-timezone']; + if(empty($vTimezoneString)) { + return null; + } + $cal = Reader::read($vTimezoneString); + $components = $cal->VTIMEZONE; + return $components->TZID->getValue(); + } } diff --git a/lib/public/Calendar/IGetTimezone.php b/lib/public/Calendar/IGetTimezone.php new file mode 100644 index 0000000000000..994a2911e922a --- /dev/null +++ b/lib/public/Calendar/IGetTimezone.php @@ -0,0 +1,41 @@ + + * * + * * @author Anna Larch + * * + * * This library is free software; you can redistribute it and/or + * * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * * License as published by the Free Software Foundation; either + * * version 3 of the License, or any later version. + * * + * * This library is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * * + * * You should have received a copy of the GNU Affero General Public + * * License along with this library. If not, see . + * * + * + */ +namespace OCP\Calendar; + +use OCP\Calendar\Exceptions\CalendarException; +use OCP\Calendar\ICalendar; +use Sabre\VObject\Component\VTimeZone; + +interface IGetTimezone extends ICalendar { + /** + * Get the calendar timezone as a string + * i.e. Europe/Vienna + * as set in the VTIMEZONE->TZID for a calendar + * + * @since 26.0.0 + */ + public function getCalendarTimezoneString(): ?string; +} +