aboutsummaryrefslogtreecommitdiffstats
path: root/lib/public/Calendar
diff options
context:
space:
mode:
Diffstat (limited to 'lib/public/Calendar')
-rw-r--r--lib/public/Calendar/BackendTemporarilyUnavailableException.php15
-rw-r--r--lib/public/Calendar/CalendarEventStatus.php17
-rw-r--r--lib/public/Calendar/CalendarExportOptions.php68
-rw-r--r--lib/public/Calendar/Events/AbstractCalendarObjectEvent.php79
-rw-r--r--lib/public/Calendar/Events/CalendarObjectCreatedEvent.php15
-rw-r--r--lib/public/Calendar/Events/CalendarObjectDeletedEvent.php15
-rw-r--r--lib/public/Calendar/Events/CalendarObjectMovedEvent.php104
-rw-r--r--lib/public/Calendar/Events/CalendarObjectMovedToTrashEvent.php15
-rw-r--r--lib/public/Calendar/Events/CalendarObjectRestoredEvent.php15
-rw-r--r--lib/public/Calendar/Events/CalendarObjectUpdatedEvent.php15
-rw-r--r--lib/public/Calendar/Exceptions/CalendarException.php16
-rw-r--r--lib/public/Calendar/IAvailabilityResult.php32
-rw-r--r--lib/public/Calendar/ICalendar.php125
-rw-r--r--lib/public/Calendar/ICalendarEventBuilder.php117
-rw-r--r--lib/public/Calendar/ICalendarExport.php31
-rw-r--r--lib/public/Calendar/ICalendarIsEnabled.php24
-rw-r--r--lib/public/Calendar/ICalendarIsShared.php25
-rw-r--r--lib/public/Calendar/ICalendarIsWritable.php25
-rw-r--r--lib/public/Calendar/ICalendarProvider.php25
-rw-r--r--lib/public/Calendar/ICalendarQuery.php121
-rw-r--r--lib/public/Calendar/ICreateFromString.php47
-rw-r--r--lib/public/Calendar/IHandleImipMessage.php30
-rw-r--r--lib/public/Calendar/IManager.php187
-rw-r--r--lib/public/Calendar/IMetadataProvider.php46
-rw-r--r--lib/public/Calendar/Resource/IBackend.php52
-rw-r--r--lib/public/Calendar/Resource/IManager.php64
-rw-r--r--lib/public/Calendar/Resource/IResource.php61
-rw-r--r--lib/public/Calendar/Resource/IResourceMetadata.php99
-rw-r--r--lib/public/Calendar/Room/IBackend.php52
-rw-r--r--lib/public/Calendar/Room/IManager.php64
-rw-r--r--lib/public/Calendar/Room/IRoom.php61
-rw-r--r--lib/public/Calendar/Room/IRoomMetadata.php76
32 files changed, 1738 insertions, 0 deletions
diff --git a/lib/public/Calendar/BackendTemporarilyUnavailableException.php b/lib/public/Calendar/BackendTemporarilyUnavailableException.php
new file mode 100644
index 00000000000..c2bbb1417ee
--- /dev/null
+++ b/lib/public/Calendar/BackendTemporarilyUnavailableException.php
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar;
+
+/**
+ * Class BackendTemporarilyUnavailableException
+ *
+ * @since 14.0.0
+ */
+class BackendTemporarilyUnavailableException extends \Exception {
+}
diff --git a/lib/public/Calendar/CalendarEventStatus.php b/lib/public/Calendar/CalendarEventStatus.php
new file mode 100644
index 00000000000..fd735150578
--- /dev/null
+++ b/lib/public/Calendar/CalendarEventStatus.php
@@ -0,0 +1,17 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar;
+
+use OCP\AppFramework\Attribute\Listenable;
+
+#[Listenable(since: '32.0.0')]
+enum CalendarEventStatus: string {
+ case TENTATIVE = 'TENTATIVE';
+ case CONFIRMED = 'CONFIRMED';
+ case CANCELLED = 'CANCELLED';
+};
diff --git a/lib/public/Calendar/CalendarExportOptions.php b/lib/public/Calendar/CalendarExportOptions.php
new file mode 100644
index 00000000000..bf21dd85ae4
--- /dev/null
+++ b/lib/public/Calendar/CalendarExportOptions.php
@@ -0,0 +1,68 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar;
+
+/**
+ * Calendar Export Options
+ *
+ * @since 32.0.0
+ */
+final class CalendarExportOptions {
+
+ /** @var 'ical'|'jcal'|'xcal' */
+ private string $format = 'ical';
+ private ?string $rangeStart = null;
+ private ?int $rangeCount = null;
+
+ /**
+ * Gets the export format
+ *
+ * @return 'ical'|'jcal'|'xcal' (defaults to ical)
+ */
+ public function getFormat(): string {
+ return $this->format;
+ }
+
+ /**
+ * Sets the export format
+ *
+ * @param 'ical'|'jcal'|'xcal' $format
+ */
+ public function setFormat(string $format): void {
+ $this->format = $format;
+ }
+
+ /**
+ * Gets the start of the range to export
+ */
+ public function getRangeStart(): ?string {
+ return $this->rangeStart;
+ }
+
+ /**
+ * Sets the start of the range to export
+ */
+ public function setRangeStart(?string $rangeStart): void {
+ $this->rangeStart = $rangeStart;
+ }
+
+ /**
+ * Gets the number of objects to export
+ */
+ public function getRangeCount(): ?int {
+ return $this->rangeCount;
+ }
+
+ /**
+ * Sets the number of objects to export
+ */
+ public function setRangeCount(?int $rangeCount): void {
+ $this->rangeCount = $rangeCount;
+ }
+}
diff --git a/lib/public/Calendar/Events/AbstractCalendarObjectEvent.php b/lib/public/Calendar/Events/AbstractCalendarObjectEvent.php
new file mode 100644
index 00000000000..111ed096f78
--- /dev/null
+++ b/lib/public/Calendar/Events/AbstractCalendarObjectEvent.php
@@ -0,0 +1,79 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar\Events;
+
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IWebhookCompatibleEvent;
+
+/**
+ * @since 32.0.0
+ */
+abstract class AbstractCalendarObjectEvent extends Event implements IWebhookCompatibleEvent {
+
+ /**
+ * @param int $calendarId
+ * @param array $calendarData
+ * @param array $shares
+ * @param array $objectData
+ * @since 32.0.0
+ */
+ public function __construct(
+ private int $calendarId,
+ private array $calendarData,
+ private array $shares,
+ private array $objectData,
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * @return int
+ * @since 32.0.0
+ */
+ public function getCalendarId(): int {
+ return $this->calendarId;
+ }
+
+ /**
+ * @return array
+ * @since 32.0.0
+ */
+ public function getCalendarData(): array {
+ return $this->calendarData;
+ }
+
+ /**
+ * @return array
+ * @since 32.0.0
+ */
+ public function getShares(): array {
+ return $this->shares;
+ }
+
+ /**
+ * @return array
+ * @since 32.0.0
+ */
+ public function getObjectData(): array {
+ return $this->objectData;
+ }
+
+ /**
+ * @return array
+ * @since 32.0.0
+ */
+ public function getWebhookSerializable(): array {
+ return [
+ 'calendarId' => $this->getCalendarId(),
+ 'calendarData' => $this->getCalendarData(),
+ 'shares' => $this->getShares(),
+ 'objectData' => $this->getObjectData(),
+ ];
+ }
+}
diff --git a/lib/public/Calendar/Events/CalendarObjectCreatedEvent.php b/lib/public/Calendar/Events/CalendarObjectCreatedEvent.php
new file mode 100644
index 00000000000..a4d0f40ec55
--- /dev/null
+++ b/lib/public/Calendar/Events/CalendarObjectCreatedEvent.php
@@ -0,0 +1,15 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar\Events;
+
+/**
+ * @since 32.0.0
+ */
+class CalendarObjectCreatedEvent extends AbstractCalendarObjectEvent {
+}
diff --git a/lib/public/Calendar/Events/CalendarObjectDeletedEvent.php b/lib/public/Calendar/Events/CalendarObjectDeletedEvent.php
new file mode 100644
index 00000000000..5466213584e
--- /dev/null
+++ b/lib/public/Calendar/Events/CalendarObjectDeletedEvent.php
@@ -0,0 +1,15 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar\Events;
+
+/**
+ * @since 32.0.0
+ */
+class CalendarObjectDeletedEvent extends AbstractCalendarObjectEvent {
+}
diff --git a/lib/public/Calendar/Events/CalendarObjectMovedEvent.php b/lib/public/Calendar/Events/CalendarObjectMovedEvent.php
new file mode 100644
index 00000000000..1c7df0e1ed5
--- /dev/null
+++ b/lib/public/Calendar/Events/CalendarObjectMovedEvent.php
@@ -0,0 +1,104 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar\Events;
+
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IWebhookCompatibleEvent;
+
+/**
+ * @since 32.0.0
+ */
+class CalendarObjectMovedEvent extends Event implements IWebhookCompatibleEvent {
+ /**
+ * @since 32.0.0
+ */
+ public function __construct(
+ private int $sourceCalendarId,
+ private array $sourceCalendarData,
+ private int $targetCalendarId,
+ private array $targetCalendarData,
+ private array $sourceShares,
+ private array $targetShares,
+ private array $objectData,
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * @return int
+ * @since 32.0.0
+ */
+ public function getSourceCalendarId(): int {
+ return $this->sourceCalendarId;
+ }
+
+ /**
+ * @return array
+ * @since 32.0.0
+ */
+ public function getSourceCalendarData(): array {
+ return $this->sourceCalendarData;
+ }
+
+ /**
+ * @return int
+ * @since 32.0.0
+ */
+ public function getTargetCalendarId(): int {
+ return $this->targetCalendarId;
+ }
+
+ /**
+ * @return array
+ * @since 32.0.0
+ */
+ public function getTargetCalendarData(): array {
+ return $this->targetCalendarData;
+ }
+
+ /**
+ * @return array
+ * @since 32.0.0
+ */
+ public function getSourceShares(): array {
+ return $this->sourceShares;
+ }
+
+ /**
+ * @return array
+ * @since 32.0.0
+ */
+ public function getTargetShares(): array {
+ return $this->targetShares;
+ }
+
+ /**
+ * @return array
+ * @since 32.0.0
+ */
+ public function getObjectData(): array {
+ return $this->objectData;
+ }
+
+ /**
+ * @return array
+ * @since 32.0.0
+ */
+ public function getWebhookSerializable(): array {
+ return [
+ 'sourceCalendarId' => $this->getSourceCalendarId(),
+ 'sourceCalendarData' => $this->getSourceCalendarData(),
+ 'targetCalendarId' => $this->getTargetCalendarId(),
+ 'targetCalendarData' => $this->getTargetCalendarData(),
+ 'sourceShares' => $this->getSourceShares(),
+ 'targetShares' => $this->getTargetShares(),
+ 'objectData' => $this->getObjectData(),
+ ];
+ }
+}
diff --git a/lib/public/Calendar/Events/CalendarObjectMovedToTrashEvent.php b/lib/public/Calendar/Events/CalendarObjectMovedToTrashEvent.php
new file mode 100644
index 00000000000..ffbd7b0375a
--- /dev/null
+++ b/lib/public/Calendar/Events/CalendarObjectMovedToTrashEvent.php
@@ -0,0 +1,15 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar\Events;
+
+/**
+ * @since 32.0.0
+ */
+class CalendarObjectMovedToTrashEvent extends AbstractCalendarObjectEvent {
+}
diff --git a/lib/public/Calendar/Events/CalendarObjectRestoredEvent.php b/lib/public/Calendar/Events/CalendarObjectRestoredEvent.php
new file mode 100644
index 00000000000..7890e3ca5b3
--- /dev/null
+++ b/lib/public/Calendar/Events/CalendarObjectRestoredEvent.php
@@ -0,0 +1,15 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar\Events;
+
+/**
+ * @since 32.0.0
+ */
+class CalendarObjectRestoredEvent extends AbstractCalendarObjectEvent {
+}
diff --git a/lib/public/Calendar/Events/CalendarObjectUpdatedEvent.php b/lib/public/Calendar/Events/CalendarObjectUpdatedEvent.php
new file mode 100644
index 00000000000..c06b2b8198f
--- /dev/null
+++ b/lib/public/Calendar/Events/CalendarObjectUpdatedEvent.php
@@ -0,0 +1,15 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar\Events;
+
+/**
+ * @since 32.0.0
+ */
+class CalendarObjectUpdatedEvent extends AbstractCalendarObjectEvent {
+}
diff --git a/lib/public/Calendar/Exceptions/CalendarException.php b/lib/public/Calendar/Exceptions/CalendarException.php
new file mode 100644
index 00000000000..27fea75bf14
--- /dev/null
+++ b/lib/public/Calendar/Exceptions/CalendarException.php
@@ -0,0 +1,16 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar\Exceptions;
+
+use Exception;
+
+/**
+ * @since 23.0.0
+ */
+class CalendarException extends Exception {
+}
diff --git a/lib/public/Calendar/IAvailabilityResult.php b/lib/public/Calendar/IAvailabilityResult.php
new file mode 100644
index 00000000000..d437a5da047
--- /dev/null
+++ b/lib/public/Calendar/IAvailabilityResult.php
@@ -0,0 +1,32 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCP\Calendar;
+
+/**
+ * DTO for the availability check results.
+ * Holds information about whether an attendee is available or not during the request time slot.
+ *
+ * @since 31.0.0
+ */
+interface IAvailabilityResult {
+ /**
+ * Get the attendee's email address.
+ *
+ * @since 31.0.0
+ */
+ public function getAttendeeEmail(): string;
+
+ /**
+ * Whether the attendee is available during the requested time slot.
+ *
+ * @since 31.0.0
+ */
+ public function isAvailable(): bool;
+}
diff --git a/lib/public/Calendar/ICalendar.php b/lib/public/Calendar/ICalendar.php
new file mode 100644
index 00000000000..50152d1240b
--- /dev/null
+++ b/lib/public/Calendar/ICalendar.php
@@ -0,0 +1,125 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar;
+
+use DateTimeInterface;
+
+/**
+ * Interface ICalendar
+ *
+ * @since 13.0.0
+ *
+ * @psalm-type CalendarSearchOptions = array{
+ * timerange?: array{start?: DateTimeInterface, end?: DateTimeInterface},
+ * uid?: string,
+ * types?: string[],
+ * }
+ */
+interface ICalendar {
+ /**
+ * @return string defining the technical unique key
+ * @since 13.0.0
+ */
+ public function getKey(): string;
+
+ /**
+ * In comparison to getKey() this function returns a unique uri within the scope of the principal
+ * @since 24.0.0
+ */
+ public function getUri(): string;
+
+ /**
+ * In comparison to getKey() this function returns a human readable (maybe translated) name
+ * @return null|string
+ * @since 13.0.0
+ */
+ public function getDisplayName(): ?string;
+
+ /**
+ * Calendar color
+ * @return null|string
+ * @since 13.0.0
+ */
+ public function getDisplayColor(): ?string;
+
+ /**
+ * Search the current calendar for matching events.
+ *
+ * This method searches for events in the calendar that match a given pattern within specified properties.
+ * The search is case-insensitive. It supports optional parameters such as a time range, limit, and offset.
+ * The results are sorted by start date, with the closest events appearing first.
+ *
+ * @param string $pattern A string to search for within the events. The search is done case-insensitive.
+ * @param array $searchProperties Defines the properties within which the pattern should match.
+ * @param array $options Optional parameters for the search:
+ * - 'timerange' element that can have 'start' (DateTimeInterface), 'end' (DateTimeInterface), or both.
+ * - 'uid' element to look for events with a given uid.
+ * - 'types' element to only return events for a given type (e.g. VEVENT or VTODO)
+ * @psalm-param CalendarSearchOptions $options
+ * @param int|null $limit Limit the number of search results.
+ * @param int|null $offset For paging of search results.
+ * @return array An array of events/journals/todos which are arrays of key-value-pairs. The events are sorted by start date (closest first, furthest last).
+ *
+ * Implementation Details:
+ *
+ * An event can consist of many sub-events, typically the case for events with recurrence rules. On a database level,
+ * there's only one event stored (with a matching first occurrence and last occurrence timestamp). Expanding an event
+ * into sub-events is done on the backend level. Using limit, offset, and timerange comes with some drawbacks.
+ * When asking the database for events, the result is ordered by the primary key to guarantee a stable order.
+ * After expanding the events into sub-events, they are sorted by the date (closest to furthest).
+ *
+ * Usage Examples:
+ *
+ * 1) Find 7 events within the next two weeks:
+ *
+ * $dateTime = (new DateTimeImmutable())->setTimestamp($this->timeFactory->getTime());
+ * $inTwoWeeks = $dateTime->add(new DateInterval('P14D'));
+ *
+ * $calendar->search(
+ * '',
+ * [],
+ * ['timerange' => ['start' => $dateTime, 'end' => $inTwoWeeks]],
+ * 7
+ * );
+ *
+ * Note: When combining timerange and limit, it's possible that the expected outcome is not in the order you would expect.
+ *
+ * Example: Create 7 events for tomorrow, starting from 11:00, 30 minutes each. Then create an 8th event for tomorrow at 10:00.
+ * The above code will list the event at 11:00 first, missing the event at 10:00. The reason is the ordering by the primary key
+ * and expanding on the backend level. This is a technical limitation. The easiest workaround is to fetch more events
+ * than you actually need, with the downside of needing more resources.
+ *
+ * Related:
+ * - https://github.com/nextcloud/server/pull/45222
+ * - https://github.com/nextcloud/server/issues/53002
+ *
+ * 2) Find all events where the location property contains the string 'Berlin':
+ *
+ * $calendar->search(
+ * 'Berlin',
+ * ['LOCATION']
+ * );
+ *
+ * @since 13.0.0
+ */
+ public function search(string $pattern, array $searchProperties = [], array $options = [], ?int $limit = null, ?int $offset = null): array;
+
+ /**
+ * @return int build up using {@see \OCP\Constants}
+ * @since 13.0.0
+ */
+ public function getPermissions(): int;
+
+ /**
+ * Indicates whether the calendar is in the trash bin
+ *
+ * @since 26.0.0
+ */
+ public function isDeleted(): bool;
+}
diff --git a/lib/public/Calendar/ICalendarEventBuilder.php b/lib/public/Calendar/ICalendarEventBuilder.php
new file mode 100644
index 00000000000..c99dc60cc8c
--- /dev/null
+++ b/lib/public/Calendar/ICalendarEventBuilder.php
@@ -0,0 +1,117 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCP\Calendar;
+
+use DateTimeInterface;
+use InvalidArgumentException;
+use OCP\Calendar\Exceptions\CalendarException;
+
+/**
+ * The calendar event builder can be used to conveniently build a calendar event and then serialize
+ * it to a ICS string. The ICS string can be submitted to calendar instances implementing the
+ * {@see \OCP\Calendar\ICreateFromString} interface.
+ *
+ * Also note this class can not be injected directly with dependency injection.
+ * Instead, inject {@see \OCP\Calendar\IManager} and use
+ * {@see \OCP\Calendar\IManager::createEventBuilder()} afterwards.
+ *
+ * All setters return self to allow chaining method calls.
+ *
+ * @since 31.0.0
+ */
+interface ICalendarEventBuilder {
+ /**
+ * Set the start date, time and time zone.
+ * This property is required!
+ *
+ * @since 31.0.0
+ */
+ public function setStartDate(DateTimeInterface $start): self;
+
+ /**
+ * Set the end date, time and time zone.
+ * This property is required!
+ *
+ * @since 31.0.0
+ */
+ public function setEndDate(DateTimeInterface $end): self;
+
+ /**
+ * Set the event summary or title.
+ * This property is required!
+ *
+ * @since 31.0.0
+ */
+ public function setSummary(string $summary): self;
+
+ /**
+ * Set the event description.
+ *
+ * @since 31.0.0
+ */
+ public function setDescription(string $description): self;
+
+ /**
+ * Set the event location. It can either be a physical address or a URL.
+ *
+ * @since 31.0.0
+ */
+ public function setLocation(string $location): self;
+
+ /**
+ * Set the event status.
+ *
+ * @since 32.0.0
+ */
+ public function setStatus(CalendarEventStatus $status): static;
+
+ /**
+ * Set the event organizer.
+ * This property is required if attendees are added!
+ *
+ * The "mailto:" prefix is optional and will be added automatically if it is missing.
+ *
+ * @since 31.0.0
+ */
+ public function setOrganizer(string $email, ?string $commonName = null): self;
+
+ /**
+ * Add a new attendee to the event.
+ * Adding at least one attendee requires also setting the organizer!
+ *
+ * The "mailto:" prefix is optional and will be added automatically if it is missing.
+ *
+ * @since 31.0.0
+ */
+ public function addAttendee(string $email, ?string $commonName = null): self;
+
+ /**
+ * Serialize the built event to an ICS string if all required properties set.
+ *
+ * @since 31.0.0
+ *
+ * @return string The serialized ICS string
+ *
+ * @throws InvalidArgumentException If required properties were not set
+ */
+ public function toIcs(): string;
+
+ /**
+ * Create the event in the given calendar.
+ *
+ * @since 31.0.0
+ *
+ * @return string The filename of the created event
+ *
+ * @throws InvalidArgumentException If required properties were not set
+ * @throws CalendarException If writing the event to the calendar fails
+ */
+ public function createInCalendar(ICreateFromString $calendar): string;
+}
diff --git a/lib/public/Calendar/ICalendarExport.php b/lib/public/Calendar/ICalendarExport.php
new file mode 100644
index 00000000000..d884c104a4a
--- /dev/null
+++ b/lib/public/Calendar/ICalendarExport.php
@@ -0,0 +1,31 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar;
+
+use Generator;
+
+/**
+ * ICalendar Interface Extension to export data
+ *
+ * @since 32.0.0
+ */
+interface ICalendarExport {
+
+ /**
+ * Export objects
+ *
+ * @since 32.0.0
+ *
+ * @param CalendarExportOptions|null $options
+ *
+ * @return Generator<\Sabre\VObject\Component\VCalendar>
+ */
+ public function export(?CalendarExportOptions $options): Generator;
+
+}
diff --git a/lib/public/Calendar/ICalendarIsEnabled.php b/lib/public/Calendar/ICalendarIsEnabled.php
new file mode 100644
index 00000000000..6bcb487e3dc
--- /dev/null
+++ b/lib/public/Calendar/ICalendarIsEnabled.php
@@ -0,0 +1,24 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar;
+
+/**
+ * ICalendar Interface Extension
+ *
+ * @since 32.0.0
+ */
+interface ICalendarIsEnabled {
+
+ /**
+ * Indicates whether the calendar is enabled
+ *
+ * @since 32.0.0
+ */
+ public function isEnabled(): bool;
+
+}
diff --git a/lib/public/Calendar/ICalendarIsShared.php b/lib/public/Calendar/ICalendarIsShared.php
new file mode 100644
index 00000000000..6f63c6eefd0
--- /dev/null
+++ b/lib/public/Calendar/ICalendarIsShared.php
@@ -0,0 +1,25 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar;
+
+/**
+ * ICalendar Interface Extension
+ *
+ * @since 31.0.0
+ */
+interface ICalendarIsShared {
+
+ /**
+ * Indicates whether the calendar is shared with the current user
+ *
+ * @since 31.0.0
+ */
+ public function isShared(): bool;
+
+}
diff --git a/lib/public/Calendar/ICalendarIsWritable.php b/lib/public/Calendar/ICalendarIsWritable.php
new file mode 100644
index 00000000000..5bf08a25cdc
--- /dev/null
+++ b/lib/public/Calendar/ICalendarIsWritable.php
@@ -0,0 +1,25 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar;
+
+/**
+ * ICalendar Interface Extension
+ *
+ * @since 31.0.0
+ */
+interface ICalendarIsWritable {
+
+ /**
+ * Indicates whether the calendar can be modified
+ *
+ * @since 31.0.0
+ */
+ public function isWritable(): bool;
+
+}
diff --git a/lib/public/Calendar/ICalendarProvider.php b/lib/public/Calendar/ICalendarProvider.php
new file mode 100644
index 00000000000..95090b1c377
--- /dev/null
+++ b/lib/public/Calendar/ICalendarProvider.php
@@ -0,0 +1,25 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar;
+
+/**
+ * This interface defines a lazy loading mechanism for
+ * calendars for Public Consumption
+ *
+ * @since 23.0.0
+ */
+interface ICalendarProvider {
+ /**
+ * @param string $principalUri URI of the principal
+ * @param string[] $calendarUris optionally specify which calendars to load, or all if this array is empty
+ * @return ICalendar[]
+ * @since 23.0.0
+ */
+ public function getCalendars(string $principalUri, array $calendarUris = []): array;
+}
diff --git a/lib/public/Calendar/ICalendarQuery.php b/lib/public/Calendar/ICalendarQuery.php
new file mode 100644
index 00000000000..c927fc42efa
--- /dev/null
+++ b/lib/public/Calendar/ICalendarQuery.php
@@ -0,0 +1,121 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCP\Calendar;
+
+use DateTimeImmutable;
+
+/**
+ * Build a flexible, extendable query to the CalDAV backend
+ *
+ * @since 23.0.0
+ */
+interface ICalendarQuery {
+ /**
+ * @since 24.0.0
+ */
+ public const SEARCH_PROPERTY_CATEGORIES = 'CATEGORIES';
+
+ /**
+ * @since 24.0.0
+ */
+ public const SEARCH_PROPERTY_COMMENT = 'COMMENT';
+
+ /**
+ * @since 24.0.0
+ */
+ public const SEARCH_PROPERTY_DESCRIPTION = 'DESCRIPTION';
+
+ /**
+ * @since 24.0.0
+ */
+ public const SEARCH_PROPERTY_LOCATION = 'LOCATION';
+
+ /**
+ * @since 24.0.0
+ */
+ public const SEARCH_PROPERTY_RESOURCES = 'RESOURCES';
+
+ /**
+ * @since 24.0.0
+ */
+ public const SEARCH_PROPERTY_STATUS = 'STATUS';
+
+ /**
+ * @since 24.0.0
+ */
+ public const SEARCH_PROPERTY_SUMMARY = 'SUMMARY';
+
+ /**
+ * @since 24.0.0
+ */
+ public const SEARCH_PROPERTY_ATTENDEE = 'ATTENDEE';
+
+ /**
+ * @since 24.0.0
+ */
+ public const SEARCH_PROPERTY_CONTACT = 'CONTACT';
+
+ /**
+ * @since 24.0.0
+ */
+ public const SEARCH_PROPERTY_ORGANIZER = 'ORGANIZER';
+
+ /**
+ * Limit the results to the calendar uri(s)
+ *
+ * @since 23.0.0
+ */
+ public function addSearchCalendar(string $calendarUri): void;
+
+ /**
+ * Search the property values
+ *
+ * @since 23.0.0
+ */
+ public function setSearchPattern(string $pattern): void;
+
+ /**
+ * Define the property name(s) to search for
+ *
+ * Note: Nextcloud only indexes *some* properties. You can not search for
+ * arbitrary properties.
+ *
+ * @param string $value any of the ICalendarQuery::SEARCH_PROPERTY_* values
+ * @psalm-param ICalendarQuery::SEARCH_PROPERTY_* $value
+ *
+ * @since 23.0.0
+ */
+ public function addSearchProperty(string $value): void;
+
+ /**
+ * @since 23.0.0
+ */
+ public function addType(string $value): void;
+
+ /**
+ * @since 23.0.0
+ */
+ public function setTimerangeStart(DateTimeImmutable $startTime): void;
+
+ /**
+ * @since 23.0.0
+ */
+ public function setTimerangeEnd(DateTimeImmutable $endTime): void;
+
+ /**
+ * @since 23.0.0
+ */
+ public function setLimit(int $limit): void;
+
+ /**
+ * @since 23.0.0
+ */
+ public function setOffset(int $offset): void;
+}
diff --git a/lib/public/Calendar/ICreateFromString.php b/lib/public/Calendar/ICreateFromString.php
new file mode 100644
index 00000000000..2bb0f2ffa20
--- /dev/null
+++ b/lib/public/Calendar/ICreateFromString.php
@@ -0,0 +1,47 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar;
+
+use OCP\Calendar\Exceptions\CalendarException;
+
+/**
+ * Extends the current ICalendar interface
+ * to add a public write method
+ *
+ * @since 23.0.0
+ */
+interface ICreateFromString extends ICalendar {
+ /**
+ * Create an event in this calendar from an ICS string.
+ *
+ * @param string $name the file name - needs to contain the .ics ending
+ * @param string $calendarData a string containing a valid VEVENT ics
+ *
+ * @throws CalendarException
+ *
+ * @since 23.0.0
+ *
+ */
+ public function createFromString(string $name, string $calendarData): void;
+
+ /**
+ * Create an event in this calendar from an ICS string using a minimal CalDAV server.
+ * Usually, the createFromString() method should be preferred.
+ *
+ * However, in some cases it is useful to not set up a full CalDAV server.
+ * Missing features include no iMIP plugin, no invitation emails amongst others.
+ *
+ * @param string $name the file name - needs to contain the .ics ending
+ * @param string $calendarData a string containing a valid VEVENT ics
+ *
+ * @throws CalendarException
+ *
+ * @since 32.0.0
+ */
+ public function createFromStringMinimal(string $name, string $calendarData): void;
+}
diff --git a/lib/public/Calendar/IHandleImipMessage.php b/lib/public/Calendar/IHandleImipMessage.php
new file mode 100644
index 00000000000..27190f93f24
--- /dev/null
+++ b/lib/public/Calendar/IHandleImipMessage.php
@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar;
+
+use OCP\Calendar\Exceptions\CalendarException;
+
+/**
+ * Extends the current ICalendar interface
+ * to add a public write method to handle
+ * iMIP data
+ *
+ * @link https://www.rfc-editor.org/rfc/rfc6047
+ *
+ * @since 26.0.0
+ */
+interface IHandleImipMessage extends ICalendar {
+ /**
+ * Handle an iMIP VEvent for validation and processing
+ *
+ * @since 26.0.0
+ *
+ * @throws CalendarException on validation failure or calendar write error
+ */
+ public function handleIMipMessage(string $name, string $calendarData): void;
+}
diff --git a/lib/public/Calendar/IManager.php b/lib/public/Calendar/IManager.php
new file mode 100644
index 00000000000..124dc65f5f6
--- /dev/null
+++ b/lib/public/Calendar/IManager.php
@@ -0,0 +1,187 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar;
+
+use DateTimeInterface;
+use OCP\IUser;
+
+/**
+ * This class provides access to the Nextcloud CalDAV backend.
+ * Use this class exclusively if you want to access calendars.
+ *
+ * Events/Journals/Todos in general will be expressed as an array of key-value-pairs.
+ * The keys will match the property names defined in https://tools.ietf.org/html/rfc5545
+ *
+ * [
+ * 'id' => 123,
+ * 'type' => 'VEVENT',
+ * 'calendar-key' => 42,
+ * 'objects' => [
+ * [
+ * 'SUMMARY' => ['FooBar', []],
+ * 'DTSTART' => ['20171001T123456', ['TZID' => 'EUROPE/BERLIN']],
+ * 'DURATION' => ['P1D', []],
+ * 'ATTENDEE' => [
+ * ['mailto:bla@blub.com', ['CN' => 'Mr. Bla Blub']]
+ * ],
+ * 'VALARM' => [
+ * [
+ * 'TRIGGER' => ['19980101T050000Z', ['VALUE' => DATE-TIME]]
+ * ]
+ * ]
+ * ],
+ * ]
+ * ]
+ *
+ * @since 13.0.0
+ */
+interface IManager {
+ /**
+ * This function is used to search and find objects within the user's calendars.
+ * In case $pattern is empty all events/journals/todos will be returned.
+ *
+ * @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 integer|null $limit - limit number of search results
+ * @param integer|null $offset - offset for paging of search results
+ * @return array an array of events/journals/todos which are arrays of arrays of key-value-pairs
+ * @since 13.0.0
+ * @deprecated 23.0.0 use \OCP\Calendar\IManager::searchForPrincipal
+ */
+ public function search($pattern, array $searchProperties = [], array $options = [], $limit = null, $offset = null);
+
+ /**
+ * Check if calendars are available
+ *
+ * @return bool true if enabled, false if not
+ * @since 13.0.0
+ * @deprecated 23.0.0
+ */
+ public function isEnabled();
+
+ /**
+ * Registers a calendar
+ *
+ * @param ICalendar $calendar
+ * @return void
+ * @since 13.0.0
+ * @deprecated 23.0.0 use \OCP\AppFramework\Bootstrap\IRegistrationContext::registerCalendarProvider
+ */
+ public function registerCalendar(ICalendar $calendar);
+
+ /**
+ * Unregisters a calendar
+ *
+ * @param ICalendar $calendar
+ * @return void
+ * @since 13.0.0
+ * @deprecated 23.0.0
+ */
+ public function unregisterCalendar(ICalendar $calendar);
+
+ /**
+ * In order to improve lazy loading a closure can be registered which will be called in case
+ * calendars are actually requested
+ *
+ * @param \Closure $callable
+ * @return void
+ * @since 13.0.0
+ * @deprecated 23.0.0 use \OCP\AppFramework\Bootstrap\IRegistrationContext::registerCalendarProvider
+ */
+ public function register(\Closure $callable);
+
+ /**
+ * @return ICalendar[]
+ * @since 13.0.0
+ * @deprecated 23.0.0 use \OCP\Calendar\IManager::getCalendarsForPrincipal
+ */
+ public function getCalendars();
+
+ /**
+ * removes all registered calendar instances
+ *
+ * @return void
+ * @since 13.0.0
+ * @deprecated 23.0.0
+ */
+ public function clear();
+
+ /**
+ * @param string $principalUri URI of the principal
+ * @param string[] $calendarUris optionally specify which calendars to load, or all if this array is empty
+ *
+ * @return ICalendar[]
+ * @since 23.0.0
+ */
+ public function getCalendarsForPrincipal(string $principalUri, array $calendarUris = []): array;
+
+ /**
+ * Query a principals calendar(s)
+ *
+ * @param ICalendarQuery $query
+ * @return array[]
+ * @since 23.0.0
+ */
+ public function searchForPrincipal(ICalendarQuery $query): array;
+
+ /**
+ * Build a new query for searchForPrincipal
+ *
+ * @return ICalendarQuery
+ * @since 23.0.0
+ */
+ public function newQuery(string $principalUri) : ICalendarQuery;
+
+ /**
+ * Handle a iMip REQUEST message
+ *
+ * @since 31.0.0
+ */
+ public function handleIMipRequest(string $principalUri, string $sender, string $recipient, string $calendarData): bool;
+
+ /**
+ * Handle a iMip REPLY message
+ *
+ * @since 25.0.0
+ */
+ public function handleIMipReply(string $principalUri, string $sender, string $recipient, string $calendarData): bool;
+
+ /**
+ * Handle a iMip CANCEL message
+ *
+ * @since 25.0.0
+ */
+ public function handleIMipCancel(string $principalUri, string $sender, ?string $replyTo, string $recipient, string $calendarData): bool;
+
+ /**
+ * Create a new event builder instance. Please have a look at its documentation and the
+ * \OCP\Calendar\ICreateFromString interface on how to use it.
+ *
+ * @since 31.0.0
+ */
+ public function createEventBuilder(): ICalendarEventBuilder;
+
+ /**
+ * Check the availability of the given organizer and attendees in the given time range.
+ *
+ * @since 31.0.0
+ *
+ * @param IUser $organizer The organizing user from whose perspective to do the availability check.
+ * @param string[] $attendees Email addresses of attendees to check for (with or without a "mailto:" prefix). Only users on this instance can be checked. The rest will be silently ignored.
+ * @return IAvailabilityResult[] Availabilities of the organizer and all attendees which are also users on this instance. As such, the array might not contain an entry for each given attendee.
+ */
+ public function checkAvailability(
+ DateTimeInterface $start,
+ DateTimeInterface $end,
+ IUser $organizer,
+ array $attendees,
+ ): array;
+}
diff --git a/lib/public/Calendar/IMetadataProvider.php b/lib/public/Calendar/IMetadataProvider.php
new file mode 100644
index 00000000000..acacf7efdaf
--- /dev/null
+++ b/lib/public/Calendar/IMetadataProvider.php
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar;
+
+/**
+ * Interface IMetadataProvider
+ *
+ * Provider for metadata of a resource or a room
+ *
+ * @since 17.0.0
+ */
+interface IMetadataProvider {
+ /**
+ * Get a list of all metadata keys available for this room
+ *
+ * Room backends are allowed to return custom keys, beyond the ones
+ * defined in this class. If they do, they should make sure to use their
+ * own namespace.
+ *
+ * @return String[] - A list of available keys
+ * @since 17.0.0
+ */
+ public function getAllAvailableMetadataKeys():array;
+
+ /**
+ * Get whether or not a metadata key is set for this room
+ *
+ * @param string $key - The key to check for
+ * @return bool - Whether or not key is available
+ * @since 17.0.0
+ */
+ public function hasMetadataForKey(string $key):bool;
+
+ /**
+ * Get the value for a metadata key
+ *
+ * @param string $key - The key to check for
+ * @return string|null - The value stored for the key, null if no value stored
+ * @since 17.0.0
+ */
+ public function getMetadataForKey(string $key):?string;
+}
diff --git a/lib/public/Calendar/Resource/IBackend.php b/lib/public/Calendar/Resource/IBackend.php
new file mode 100644
index 00000000000..23d37c102f2
--- /dev/null
+++ b/lib/public/Calendar/Resource/IBackend.php
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar\Resource;
+
+use OCP\Calendar\BackendTemporarilyUnavailableException;
+
+/**
+ * Interface IBackend
+ *
+ * @since 14.0.0
+ */
+interface IBackend {
+ /**
+ * get a list of all resources in this backend
+ *
+ * @throws BackendTemporarilyUnavailableException
+ * @return IResource[]
+ * @since 14.0.0
+ */
+ public function getAllResources():array;
+
+ /**
+ * get a list of all resource identifiers in this backend
+ *
+ * @throws BackendTemporarilyUnavailableException
+ * @return string[]
+ * @since 14.0.0
+ */
+ public function listAllResources():array;
+
+ /**
+ * get a resource by it's id
+ *
+ * @param string $id
+ * @throws BackendTemporarilyUnavailableException
+ * @return IResource|null
+ * @since 14.0.0
+ */
+ public function getResource($id);
+
+ /**
+ * Get unique identifier of the backend
+ *
+ * @return string
+ * @since 14.0.0
+ */
+ public function getBackendIdentifier():string;
+}
diff --git a/lib/public/Calendar/Resource/IManager.php b/lib/public/Calendar/Resource/IManager.php
new file mode 100644
index 00000000000..d3a6b2449e3
--- /dev/null
+++ b/lib/public/Calendar/Resource/IManager.php
@@ -0,0 +1,64 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar\Resource;
+
+/**
+ * @since 14.0.0
+ */
+interface IManager {
+ /**
+ * Registers a resource backend
+ *
+ * @param string $backendClass
+ * @return void
+ * @since 14.0.0
+ * @deprecated 24.0.0 use \OCP\AppFramework\Bootstrap\IRegistrationContext::registerCalendarResourceBackend
+ */
+ public function registerBackend(string $backendClass);
+
+ /**
+ * Unregisters a resource backend
+ *
+ * @param string $backendClass
+ * @return void
+ * @since 14.0.0
+ * @deprecated 24.0.0
+ */
+ public function unregisterBackend(string $backendClass);
+
+ /**
+ * @return IBackend[]
+ * @since 14.0.0
+ * @deprecated 24.0.0
+ */
+ public function getBackends():array;
+
+ /**
+ * @param string $backendId
+ * @return IBackend|null
+ * @since 14.0.0
+ * @deprecated 24.0.0
+ */
+ public function getBackend($backendId);
+
+ /**
+ * removes all registered backend instances
+ * @return void
+ * @since 14.0.0
+ * @deprecated 24.0.0
+ */
+ public function clear();
+
+ /**
+ * Update all resources from all backends right now.
+ *
+ * @since 30.0.0
+ */
+ public function update(): void;
+}
diff --git a/lib/public/Calendar/Resource/IResource.php b/lib/public/Calendar/Resource/IResource.php
new file mode 100644
index 00000000000..15abe4e2d0f
--- /dev/null
+++ b/lib/public/Calendar/Resource/IResource.php
@@ -0,0 +1,61 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar\Resource;
+
+/**
+ * Interface IResource
+ *
+ * @since 14.0.0
+ */
+interface IResource {
+ /**
+ * get the resource id
+ *
+ * This id has to be unique within the backend
+ *
+ * @return string
+ * @since 14.0.0
+ */
+ public function getId():string;
+
+ /**
+ * get the display name for a resource
+ *
+ * @return string
+ * @since 14.0.0
+ */
+ public function getDisplayName():string;
+
+ /**
+ * Get a list of groupIds that are allowed to access this resource
+ *
+ * If an empty array is returned, no group restrictions are
+ * applied.
+ *
+ * @return string[]
+ * @since 14.0.0
+ */
+ public function getGroupRestrictions():array;
+
+ /**
+ * get email-address for resource
+ *
+ * The email address has to be globally unique
+ *
+ * @return string
+ * @since 14.0.0
+ */
+ public function getEMail():string;
+
+ /**
+ * Get corresponding backend object
+ *
+ * @return IBackend
+ * @since 14.0.0
+ */
+ public function getBackend():IBackend;
+}
diff --git a/lib/public/Calendar/Resource/IResourceMetadata.php b/lib/public/Calendar/Resource/IResourceMetadata.php
new file mode 100644
index 00000000000..29f628d6f7f
--- /dev/null
+++ b/lib/public/Calendar/Resource/IResourceMetadata.php
@@ -0,0 +1,99 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar\Resource;
+
+/**
+ * Interface IResourceMetadata
+ *
+ * This interface provides keys for common metadata.
+ * Resource Backends are not limited to this list and can provide
+ * any metadata they want.
+ *
+ * @since 17.0.0
+ */
+interface IResourceMetadata {
+ /**
+ * Type of resource
+ *
+ * Allowed values for this key include:
+ * - projector
+ * - tv
+ * - vehicle
+ * - other
+ *
+ * @since 17.0.0
+ */
+ public const RESOURCE_TYPE = '{http://nextcloud.com/ns}resource-type';
+
+ /**
+ * If resource is of type vehicle, this describes the type of vehicle
+ *
+ * Allowed values:
+ * - bicycle
+ * - scooter
+ * - motorbike
+ * - car
+ * - plane
+ * - helicopter
+ * - other
+ *
+ * @since 17.0.0
+ */
+ public const VEHICLE_TYPE = '{http://nextcloud.com/ns}resource-vehicle-type';
+
+ /**
+ * Make of the vehicle
+ *
+ * @since 17.0.0
+ */
+ public const VEHICLE_MAKE = '{http://nextcloud.com/ns}resource-vehicle-make';
+
+ /**
+ * Model of the vehicle
+ *
+ * @since 17.0.0
+ */
+ public const VEHICLE_MODEL = '{http://nextcloud.com/ns}resource-vehicle-model';
+
+ /**
+ * Whether or not the car is electric
+ *
+ * use '1' for electric, '0' for non-electric
+ *
+ * @since 17.0.0
+ */
+ public const VEHICLE_IS_ELECTRIC = '{http://nextcloud.com/ns}resource-vehicle-is-electric';
+
+ /**
+ * Range of vehicle with a full tank
+ *
+ * @since 17.0.0
+ */
+ public const VEHICLE_RANGE = '{http://nextcloud.com/ns}resource-vehicle-range';
+
+ /**
+ * Seating capacity of the vehicle
+ *
+ * @since 17.0.0
+ */
+ public const VEHICLE_SEATING_CAPACITY = '{http://nextcloud.com/ns}resource-vehicle-seating-capacity';
+
+ /**
+ * Contact information about the person who is responsible to administer / maintain this resource
+ * This key stores a textual description of name and possible ways to contact the person
+ *
+ * @since 17.0.0
+ */
+ public const CONTACT_PERSON = '{http://nextcloud.com/ns}resource-contact-person';
+
+ /**
+ * Link to the vcard of the contact person
+ *
+ * @since 17.0.0
+ */
+ public const CONTACT_PERSON_VCARD = '{http://nextcloud.com/ns}resource-contact-person-vcard';
+}
diff --git a/lib/public/Calendar/Room/IBackend.php b/lib/public/Calendar/Room/IBackend.php
new file mode 100644
index 00000000000..c99f5fbdb72
--- /dev/null
+++ b/lib/public/Calendar/Room/IBackend.php
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar\Room;
+
+use OCP\Calendar\BackendTemporarilyUnavailableException;
+
+/**
+ * Interface IBackend
+ *
+ * @since 14.0.0
+ */
+interface IBackend {
+ /**
+ * get a list of all rooms in this backend
+ *
+ * @throws BackendTemporarilyUnavailableException
+ * @return IRoom[]
+ * @since 14.0.0
+ */
+ public function getAllRooms():array;
+
+ /**
+ * get a list of all room identifiers in this backend
+ *
+ * @throws BackendTemporarilyUnavailableException
+ * @return string[]
+ * @since 14.0.0
+ */
+ public function listAllRooms():array;
+
+ /**
+ * get a room by it's id
+ *
+ * @param string $id
+ * @throws BackendTemporarilyUnavailableException
+ * @return IRoom|null
+ * @since 14.0.0
+ */
+ public function getRoom($id);
+
+ /**
+ * Get unique identifier of the backend
+ *
+ * @return string
+ * @since 14.0.0
+ */
+ public function getBackendIdentifier():string;
+}
diff --git a/lib/public/Calendar/Room/IManager.php b/lib/public/Calendar/Room/IManager.php
new file mode 100644
index 00000000000..b1136ede3fe
--- /dev/null
+++ b/lib/public/Calendar/Room/IManager.php
@@ -0,0 +1,64 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar\Room;
+
+/**
+ * @since 14.0.0
+ */
+interface IManager {
+ /**
+ * Registers a room backend
+ *
+ * @param string $backendClass
+ * @return void
+ * @since 14.0.0
+ * @deprecated 24.0.0 use \OC\AppFramework\Bootstrap\::registerCalendarRoomBackend
+ */
+ public function registerBackend(string $backendClass);
+
+ /**
+ * Unregisters a room backend
+ *
+ * @param string $backendClass
+ * @return void
+ * @since 14.0.0
+ * @deprecated 24.0.0
+ */
+ public function unregisterBackend(string $backendClass);
+
+ /**
+ * @return IBackend[]
+ * @since 14.0.0
+ * @deprecated 24.0.0
+ */
+ public function getBackends():array;
+
+ /**
+ * @param string $backendId
+ * @return IBackend|null
+ * @since 14.0.0
+ * @deprecated 24.0.0
+ */
+ public function getBackend($backendId);
+
+ /**
+ * removes all registered backend instances
+ * @return void
+ * @since 14.0.0
+ * @deprecated 24.0.0
+ */
+ public function clear();
+
+ /**
+ * Update all rooms from all backends right now.
+ *
+ * @since 30.0.0
+ */
+ public function update(): void;
+}
diff --git a/lib/public/Calendar/Room/IRoom.php b/lib/public/Calendar/Room/IRoom.php
new file mode 100644
index 00000000000..526e65b8f5f
--- /dev/null
+++ b/lib/public/Calendar/Room/IRoom.php
@@ -0,0 +1,61 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar\Room;
+
+/**
+ * Interface IRoom
+ *
+ * @since 14.0.0
+ */
+interface IRoom {
+ /**
+ * Get a unique ID for the room
+ *
+ * This id has to be unique within the backend
+ *
+ * @return string
+ * @since 14.0.0
+ */
+ public function getId():string;
+
+ /**
+ * Get the display name for the room
+ *
+ * @return string
+ * @since 14.0.0
+ */
+ public function getDisplayName():string;
+
+ /**
+ * Get a list of groupIds that are allowed to access this room
+ *
+ * If an empty array is returned, no group restrictions are
+ * applied.
+ *
+ * @return string[]
+ * @since 14.0.0
+ */
+ public function getGroupRestrictions():array;
+
+ /**
+ * Get the email-address for the room
+ *
+ * The email-address has to be globally unique
+ *
+ * @return string
+ * @since 14.0.0
+ */
+ public function getEMail():string;
+
+ /**
+ * Get corresponding backend object
+ *
+ * @return IBackend
+ * @since 14.0.0
+ */
+ public function getBackend():IBackend;
+}
diff --git a/lib/public/Calendar/Room/IRoomMetadata.php b/lib/public/Calendar/Room/IRoomMetadata.php
new file mode 100644
index 00000000000..15d4b501e12
--- /dev/null
+++ b/lib/public/Calendar/Room/IRoomMetadata.php
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar\Room;
+
+/**
+ * Interface IRoomMetadata
+ *
+ * This interface provides keys for common metadata.
+ * Room Backends are not limited to this list and can provide
+ * any metadata they want.
+ *
+ * @since 17.0.0
+ */
+interface IRoomMetadata {
+ /**
+ * Type of room
+ *
+ * Allowed values for this key are:
+ * - meeting-room
+ * - lecture-hall
+ * - seminar-room
+ * - other
+ *
+ * @since 17.0.0
+ */
+ public const ROOM_TYPE = '{http://nextcloud.com/ns}room-type';
+
+ /**
+ * Seating capacity of the room
+ *
+ * @since 17.0.0
+ */
+ public const CAPACITY = '{http://nextcloud.com/ns}room-seating-capacity';
+
+ /**
+ * The physical address of the building this room is located in
+ *
+ * @since 17.0.0
+ */
+ public const BUILDING_ADDRESS = '{http://nextcloud.com/ns}room-building-address';
+
+ /**
+ * The story of the building this rooms is located in
+ *
+ * @since 17.0.0
+ */
+ public const BUILDING_STORY = '{http://nextcloud.com/ns}room-building-story';
+
+ /**
+ * The room-number
+ *
+ * @since 17.0.0
+ */
+ public const BUILDING_ROOM_NUMBER = '{http://nextcloud.com/ns}room-building-room-number';
+
+ /**
+ * Features provided by the room.
+ * This is a stringified list of features.
+ * Example: "PHONE,VIDEO-CONFERENCING"
+ *
+ * Standard features include:
+ * - PHONE: This room is fitted with a phone
+ * - VIDEO-CONFERENCING: This room is fitted with a video-conferencing system
+ * - TV: This room is fitted with a TV
+ * - PROJECTOR: This room is fitted with a projector
+ * - WHITEBOARD: This room is fitted with a whiteboard
+ * - WHEELCHAIR-ACCESSIBLE: This room is wheelchair-accessible
+ *
+ * @since 17.0.0
+ */
+ public const FEATURES = '{http://nextcloud.com/ns}room-features';
+}