aboutsummaryrefslogtreecommitdiffstats
path: root/apps/dav/lib
diff options
context:
space:
mode:
Diffstat (limited to 'apps/dav/lib')
-rw-r--r--apps/dav/lib/BulkUpload/MultipartRequestParser.php6
-rw-r--r--apps/dav/lib/CalDAV/Activity/Provider/Event.php9
-rw-r--r--apps/dav/lib/CalDAV/CachedSubscriptionImpl.php10
-rw-r--r--apps/dav/lib/CalDAV/CalDavBackend.php31
-rw-r--r--apps/dav/lib/CalDAV/CalendarImpl.php10
-rw-r--r--apps/dav/lib/CalDAV/Schedule/IMipPlugin.php2
-rw-r--r--apps/dav/lib/CalDAV/Schedule/IMipService.php30
-rw-r--r--apps/dav/lib/CalDAV/UpcomingEventsService.php44
-rw-r--r--apps/dav/lib/CardDAV/CardDavBackend.php1
-rw-r--r--apps/dav/lib/Connector/Sabre/File.php4
-rw-r--r--apps/dav/lib/DAV/GroupPrincipalBackend.php8
-rw-r--r--apps/dav/lib/Files/Sharing/FilesDropPlugin.php24
12 files changed, 99 insertions, 80 deletions
diff --git a/apps/dav/lib/BulkUpload/MultipartRequestParser.php b/apps/dav/lib/BulkUpload/MultipartRequestParser.php
index 96a90f82cde..f23aca580cc 100644
--- a/apps/dav/lib/BulkUpload/MultipartRequestParser.php
+++ b/apps/dav/lib/BulkUpload/MultipartRequestParser.php
@@ -57,7 +57,13 @@ class MultipartRequestParser {
*/
private function parseBoundaryFromHeaders(string $contentType): string {
try {
+ if (!str_contains($contentType, ';')) {
+ throw new \InvalidArgumentException('No semicolon in header');
+ }
[$mimeType, $boundary] = explode(';', $contentType);
+ if (!str_contains($boundary, '=')) {
+ throw new \InvalidArgumentException('No equal in boundary header');
+ }
[$boundaryKey, $boundaryValue] = explode('=', $boundary);
} catch (\Exception $e) {
throw new BadRequest('Error while parsing boundary in Content-Type header.', Http::STATUS_BAD_REQUEST, $e);
diff --git a/apps/dav/lib/CalDAV/Activity/Provider/Event.php b/apps/dav/lib/CalDAV/Activity/Provider/Event.php
index 41b610542df..f498a47a0b4 100644
--- a/apps/dav/lib/CalDAV/Activity/Provider/Event.php
+++ b/apps/dav/lib/CalDAV/Activity/Provider/Event.php
@@ -78,14 +78,9 @@ class Event extends Base {
// as seen from the affected user.
$objectId = base64_encode($this->url->getWebroot() . '/remote.php/dav/calendars/' . $affectedUser . '/' . $calendarUri . '_shared_by_' . $linkData['owner'] . '/' . $linkData['object_uri']);
}
- $link = [
- 'view' => 'dayGridMonth',
- 'timeRange' => 'now',
- 'mode' => 'sidebar',
+ $params['link'] = $this->url->linkToRouteAbsolute('calendar.view.indexdirect.edit', [
'objectId' => $objectId,
- 'recurrenceId' => 'next'
- ];
- $params['link'] = $this->url->linkToRouteAbsolute('calendar.view.indexview.timerange.edit', $link);
+ ]);
} catch (\Exception $error) {
// Do nothing
}
diff --git a/apps/dav/lib/CalDAV/CachedSubscriptionImpl.php b/apps/dav/lib/CalDAV/CachedSubscriptionImpl.php
index 74efebb6e2a..cc1bab6d4fc 100644
--- a/apps/dav/lib/CalDAV/CachedSubscriptionImpl.php
+++ b/apps/dav/lib/CalDAV/CachedSubscriptionImpl.php
@@ -55,16 +55,6 @@ class CachedSubscriptionImpl implements ICalendar, ICalendarIsEnabled, ICalendar
return $this->calendarInfo['{http://apple.com/ns/ical/}calendar-color'];
}
- /**
- * @param string $pattern which should match within the $searchProperties
- * @param array $searchProperties defines the properties within the query pattern should match
- * @param array $options - optional parameters:
- * ['timerange' => ['start' => new DateTime(...), 'end' => new DateTime(...)]]
- * @param int|null $limit - limit number of search results
- * @param int|null $offset - offset for paging of search results
- * @return array an array of events/journals/todos which are arrays of key-value-pairs
- * @since 13.0.0
- */
public function search(string $pattern, array $searchProperties = [], array $options = [], $limit = null, $offset = null): array {
return $this->backend->search($this->calendarInfo, $pattern, $searchProperties, $options, $limit, $offset);
}
diff --git a/apps/dav/lib/CalDAV/CalDavBackend.php b/apps/dav/lib/CalDAV/CalDavBackend.php
index 5643e89d797..c49e843d2b9 100644
--- a/apps/dav/lib/CalDAV/CalDavBackend.php
+++ b/apps/dav/lib/CalDAV/CalDavBackend.php
@@ -212,15 +212,13 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
}
/**
- * Return the number of calendars for a principal
+ * Return the number of calendars owned by the given principal.
*
- * By default this excludes the automatically generated birthday calendar
+ * Calendars shared with the given principal are not counted!
*
- * @param $principalUri
- * @param bool $excludeBirthday
- * @return int
+ * By default, this excludes the automatically generated birthday calendar.
*/
- public function getCalendarsForUserCount($principalUri, $excludeBirthday = true) {
+ public function getCalendarsForUserCount(string $principalUri, bool $excludeBirthday = true): int {
$principalUri = $this->convertPrincipal($principalUri, true);
$query = $this->db->getQueryBuilder();
$query->select($query->func()->count('*'))
@@ -1040,7 +1038,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
$rs->closeCursor();
}
}
-
+
/**
* Returns all calendar objects with limited metadata for a calendar
*
@@ -1538,25 +1536,6 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
}, $this->db);
}
-
- /**
- * @param int $calendarObjectId
- * @param int $classification
- */
- public function setClassification($calendarObjectId, $classification) {
- $this->cachedObjects = [];
- if (!in_array($classification, [
- self::CLASSIFICATION_PUBLIC, self::CLASSIFICATION_PRIVATE, self::CLASSIFICATION_CONFIDENTIAL
- ])) {
- throw new \InvalidArgumentException();
- }
- $query = $this->db->getQueryBuilder();
- $query->update('calendarobjects')
- ->set('classification', $query->createNamedParameter($classification))
- ->where($query->expr()->eq('id', $query->createNamedParameter($calendarObjectId)))
- ->executeStatement();
- }
-
/**
* Deletes an existing calendar object.
*
diff --git a/apps/dav/lib/CalDAV/CalendarImpl.php b/apps/dav/lib/CalDAV/CalendarImpl.php
index d36f46df901..b79bf7ea2d0 100644
--- a/apps/dav/lib/CalDAV/CalendarImpl.php
+++ b/apps/dav/lib/CalDAV/CalendarImpl.php
@@ -93,16 +93,6 @@ class CalendarImpl implements ICreateFromString, IHandleImipMessage, ICalendarIs
return $vtimezone;
}
- /**
- * @param string $pattern which should match within the $searchProperties
- * @param array $searchProperties defines the properties within the query pattern should match
- * @param array $options - optional parameters:
- * ['timerange' => ['start' => new DateTime(...), 'end' => new DateTime(...)]]
- * @param int|null $limit - limit number of search results
- * @param int|null $offset - offset for paging of search results
- * @return array an array of events/journals/todos which are arrays of key-value-pairs
- * @since 13.0.0
- */
public function search(string $pattern, array $searchProperties = [], array $options = [], $limit = null, $offset = null): array {
return $this->backend->search($this->calendarInfo, $pattern,
$searchProperties, $options, $limit, $offset);
diff --git a/apps/dav/lib/CalDAV/Schedule/IMipPlugin.php b/apps/dav/lib/CalDAV/Schedule/IMipPlugin.php
index 0ce8e28ab9e..9df7c1cd492 100644
--- a/apps/dav/lib/CalDAV/Schedule/IMipPlugin.php
+++ b/apps/dav/lib/CalDAV/Schedule/IMipPlugin.php
@@ -186,7 +186,7 @@ class IMipPlugin extends SabreIMipPlugin {
switch (strtolower($iTipMessage->method)) {
case self::METHOD_REPLY:
$method = self::METHOD_REPLY;
- $data = $this->imipService->buildBodyData($vEvent, $oldVevent);
+ $data = $this->imipService->buildReplyBodyData($vEvent);
$replyingAttendee = $this->imipService->getReplyingAttendee($iTipMessage);
break;
case self::METHOD_CANCEL:
diff --git a/apps/dav/lib/CalDAV/Schedule/IMipService.php b/apps/dav/lib/CalDAV/Schedule/IMipService.php
index 078b10abd23..42042c45b97 100644
--- a/apps/dav/lib/CalDAV/Schedule/IMipService.php
+++ b/apps/dav/lib/CalDAV/Schedule/IMipService.php
@@ -159,7 +159,35 @@ class IMipService {
if ($eventReaderCurrent->recurs()) {
$data['meeting_occurring'] = $this->generateOccurringString($eventReaderCurrent);
}
-
+ return $data;
+ }
+
+ /**
+ * @param VEvent $vEvent
+ * @return array
+ */
+ public function buildReplyBodyData(VEvent $vEvent): array {
+ // construct event reader
+ $eventReader = new EventReader($vEvent);
+ $defaultVal = '';
+ $data = [];
+ $data['meeting_when'] = $this->generateWhenString($eventReader);
+
+ foreach (self::STRING_DIFF as $key => $property) {
+ $data[$key] = self::readPropertyWithDefault($vEvent, $property, $defaultVal);
+ }
+
+ if (($locationHtml = $this->linkify($data['meeting_location'])) !== null) {
+ $data['meeting_location_html'] = $locationHtml;
+ }
+
+ $data['meeting_url_html'] = $data['meeting_url'] ? sprintf('<a href="%1$s">%1$s</a>', $data['meeting_url']) : '';
+
+ // generate occurring next string
+ if ($eventReader->recurs()) {
+ $data['meeting_occurring'] = $this->generateOccurringString($eventReader);
+ }
+
return $data;
}
diff --git a/apps/dav/lib/CalDAV/UpcomingEventsService.php b/apps/dav/lib/CalDAV/UpcomingEventsService.php
index 9c054deb4e0..6614d937ff7 100644
--- a/apps/dav/lib/CalDAV/UpcomingEventsService.php
+++ b/apps/dav/lib/CalDAV/UpcomingEventsService.php
@@ -47,20 +47,36 @@ class UpcomingEventsService {
$this->userManager->get($userId),
);
- return array_map(fn (array $event) => new UpcomingEvent(
- $event['uri'],
- ($event['objects'][0]['RECURRENCE-ID'][0] ?? null)?->getTimeStamp(),
- $event['calendar-uri'],
- $event['objects'][0]['DTSTART'][0]?->getTimestamp(),
- $event['objects'][0]['SUMMARY'][0] ?? null,
- $event['objects'][0]['LOCATION'][0] ?? null,
- match ($calendarAppEnabled) {
- // TODO: create a named, deep route in calendar
- // TODO: it's a code smell to just assume this route exists, find an abstraction
- true => $this->urlGenerator->linkToRouteAbsolute('calendar.view.index'),
- false => null,
- },
- ), $events);
+ return array_map(function (array $event) use ($userId, $calendarAppEnabled) {
+ $calendarAppUrl = null;
+
+ if ($calendarAppEnabled) {
+ $arguments = [
+ 'objectId' => base64_encode($this->urlGenerator->getWebroot() . '/remote.php/dav/calendars/' . $userId . '/' . $event['calendar-uri'] . '/' . $event['uri']),
+ ];
+
+ if (isset($event['RECURRENCE-ID'])) {
+ $arguments['recurrenceId'] = $event['RECURRENCE-ID'][0];
+ }
+ /**
+ * TODO: create a named, deep route in calendar (it's a code smell to just assume this route exists, find an abstraction)
+ * When changing, also adjust for:
+ * - spreed/lib/Service/CalendarIntegrationService.php#getDashboardEvents
+ * - spreed/lib/Service/CalendarIntegrationService.php#getMutualEvents
+ */
+ $calendarAppUrl = $this->urlGenerator->linkToRouteAbsolute('calendar.view.indexdirect.edit', $arguments);
+ }
+
+ return new UpcomingEvent(
+ $event['uri'],
+ ($event['objects'][0]['RECURRENCE-ID'][0] ?? null)?->getTimeStamp(),
+ $event['calendar-uri'],
+ $event['objects'][0]['DTSTART'][0]?->getTimestamp(),
+ $event['objects'][0]['SUMMARY'][0] ?? null,
+ $event['objects'][0]['LOCATION'][0] ?? null,
+ $calendarAppUrl,
+ );
+ }, $events);
}
}
diff --git a/apps/dav/lib/CardDAV/CardDavBackend.php b/apps/dav/lib/CardDAV/CardDavBackend.php
index de209754ae4..d874ca2ce2b 100644
--- a/apps/dav/lib/CardDAV/CardDavBackend.php
+++ b/apps/dav/lib/CardDAV/CardDavBackend.php
@@ -127,7 +127,6 @@ class CardDavBackend implements BackendInterface, SyncSupport {
// query for shared addressbooks
$principals = $this->principalBackend->getGroupMembership($principalUriOriginal, true);
- $principals = array_merge($principals, $this->principalBackend->getCircleMembership($principalUriOriginal));
$principals[] = $principalUri;
diff --git a/apps/dav/lib/Connector/Sabre/File.php b/apps/dav/lib/Connector/Sabre/File.php
index 98e0f2e9e4b..218d38e1c4b 100644
--- a/apps/dav/lib/Connector/Sabre/File.php
+++ b/apps/dav/lib/Connector/Sabre/File.php
@@ -216,7 +216,9 @@ class File extends Node implements IFile {
try {
/** @var IWriteStreamStorage $partStorage */
$count = $partStorage->writeStream($internalPartPath, $wrappedData);
- } catch (GenericFileException) {
+ } catch (GenericFileException $e) {
+ $logger = Server::get(LoggerInterface::class);
+ $logger->error('Error while writing stream to storage: ' . $e->getMessage(), ['exception' => $e, 'app' => 'webdav']);
$result = $isEOF;
if (is_resource($wrappedData)) {
$result = feof($wrappedData);
diff --git a/apps/dav/lib/DAV/GroupPrincipalBackend.php b/apps/dav/lib/DAV/GroupPrincipalBackend.php
index 143fc7d69f1..ddbd64bdda1 100644
--- a/apps/dav/lib/DAV/GroupPrincipalBackend.php
+++ b/apps/dav/lib/DAV/GroupPrincipalBackend.php
@@ -50,8 +50,10 @@ class GroupPrincipalBackend implements BackendInterface {
$principals = [];
if ($prefixPath === self::PRINCIPAL_PREFIX) {
- foreach ($this->groupManager->search('') as $user) {
- $principals[] = $this->groupToPrincipal($user);
+ foreach ($this->groupManager->search('') as $group) {
+ if (!$group->hideFromCollaboration()) {
+ $principals[] = $this->groupToPrincipal($group);
+ }
}
}
@@ -77,7 +79,7 @@ class GroupPrincipalBackend implements BackendInterface {
$name = urldecode($elements[2]);
$group = $this->groupManager->get($name);
- if (!is_null($group)) {
+ if ($group !== null && !$group->hideFromCollaboration()) {
return $this->groupToPrincipal($group);
}
diff --git a/apps/dav/lib/Files/Sharing/FilesDropPlugin.php b/apps/dav/lib/Files/Sharing/FilesDropPlugin.php
index 9aee5283ea9..3bdd273189f 100644
--- a/apps/dav/lib/Files/Sharing/FilesDropPlugin.php
+++ b/apps/dav/lib/Files/Sharing/FilesDropPlugin.php
@@ -8,6 +8,7 @@ namespace OCA\DAV\Files\Sharing;
use OCP\Files\Folder;
use OCP\Files\NotFoundException;
use OCP\Share\IShare;
+use Sabre\DAV\Exception\BadRequest;
use Sabre\DAV\Exception\MethodNotAllowed;
use Sabre\DAV\ServerPlugin;
use Sabre\HTTP\RequestInterface;
@@ -71,13 +72,12 @@ class FilesDropPlugin extends ServerPlugin {
? trim(urldecode($request->getHeader('X-NC-Nickname')))
: null;
- //
if ($request->getMethod() !== 'PUT') {
// If uploading subfolders we need to ensure they get created
// within the nickname folder
if ($request->getMethod() === 'MKCOL') {
if (!$nickname) {
- throw new MethodNotAllowed('A nickname header is required when uploading subfolders');
+ throw new BadRequest('A nickname header is required when uploading subfolders');
}
} else {
throw new MethodNotAllowed('Only PUT is allowed on files drop');
@@ -113,7 +113,7 @@ class FilesDropPlugin extends ServerPlugin {
// We need a valid nickname for file requests
if ($isFileRequest && !$nickname) {
- throw new MethodNotAllowed('A nickname header is required for file requests');
+ throw new BadRequest('A nickname header is required for file requests');
}
// We're only allowing the upload of
@@ -121,12 +121,24 @@ class FilesDropPlugin extends ServerPlugin {
// This prevents confusion when uploading files and help
// classify them by uploaders.
if (!$nickname && !$isRootUpload) {
- throw new MethodNotAllowed('A nickname header is required when uploading subfolders');
+ throw new BadRequest('A nickname header is required when uploading subfolders');
}
- // If we have a nickname, let's put everything inside
if ($nickname) {
- // Put all files in the subfolder
+ try {
+ $node->verifyPath($nickname);
+ } catch (\Exception $e) {
+ // If the path is not valid, we throw an exception
+ throw new BadRequest('Invalid nickname: ' . $nickname);
+ }
+
+ // Forbid nicknames starting with a dot
+ if (str_starts_with($nickname, '.')) {
+ throw new BadRequest('Invalid nickname: ' . $nickname);
+ }
+
+ // If we have a nickname, let's put
+ // all files in the subfolder
$relativePath = '/' . $nickname . '/' . $relativePath;
$relativePath = str_replace('//', '/', $relativePath);
}