From dc17113d73de633919931de15e0d21fb52126062 Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Mon, 7 Nov 2022 12:29:23 +0100 Subject: Moved calendar provider to its own section Signed-off-by: Christian Wolf # Conflicts: # developer_manual/digging_deeper/groupware/calendar.rst --- .../digging_deeper/groupware/calendar.rst | 78 --- .../digging_deeper/groupware/calendar_provider.rst | 637 +++++++++++++++++++++ .../digging_deeper/groupware/index.rst | 1 + 3 files changed, 638 insertions(+), 78 deletions(-) create mode 100644 developer_manual/digging_deeper/groupware/calendar_provider.rst diff --git a/developer_manual/digging_deeper/groupware/calendar.rst b/developer_manual/digging_deeper/groupware/calendar.rst index 437e59290..ed1ec86ee 100644 --- a/developer_manual/digging_deeper/groupware/calendar.rst +++ b/developer_manual/digging_deeper/groupware/calendar.rst @@ -104,84 +104,6 @@ The returned objects implement ``\OCP\Calendar\ICalendar``. Study the interface .. note:: All calendars are by default only readable, therefore ``ICalendar`` does not offer methods for mutation. Some of the calendars are mutable, however, and they may further extend the interface ``\OCP\Calendar\ICreateFromString``. -.. _calendar-providers: - -Calendar providers ------------------- - -Nextcloud apps can register calendars in addition to the internal calendars of the Nextcloud CalDAV back end. Calendars are only loaded on demand, therefore a lazy provider mechanism is used. - -To provide calendar(s) you have to write a class that implements the ``ICalendarProvider`` interface. - -.. code-block:: php - - ` with ``$context->registerCalendarProvider(CalendarProvider::class);``. - - -Write support -~~~~~~~~~~~~~ - -Calendars that only return `ICalendar` are implicitly read-only. If your app's calendars can be written to, you may implement the ``ICreateFromString``. It will allow other apps to write calendar objects to the calendar by passing the raw iCalendar data as string. - -.. code-block:: php - - `_ - -.. code-block:: php - - calendar = $calendar; + $this->name = $name; + } + + // Implement all remaining functions here ... + } + +The ``Calendar`` class is the class as defined in the next section representing a complete calendar. + +The calendar object as well as the name of the entry is given as arguments of the constructor by the calendar class. For now, they are saved into attributes for later usage. + +Basic event information -- INode +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There are some basic methods that need to be implemented on each calendar object instance. These are defined ``\Sabre\DAV\INode``. + +.. code-block:: php + + name; + } + +The name of the event can be obtained using the ``getName`` method. Here, the saved name in the attributes is just returned. + +.. code-block:: php + + get()); + } + +One helper function is the ``getSize`` method to get the number of bytes that represent this calendar entry's representation. Nothing fancy is done in this method. + +.. code-block:: php + + get()) . '"'; + } + +The calculation of an E-Tag can be calculated using the ``getETag`` method. Note, that the returned E-Tag must have the double quotes as part of the returned string. + +One can also return ``null`` to indicate that the E-Tag cannot be calculated effectively. + +.. code-block:: php + + getName(); + return <<calendar->getACL(); + } + +The real access rules can be obtained by ``getACL``. In this example, we assume that the ACLs are inherited from the calendar. Thus, we delegate the calculation to the calendar class. + +.. code-block:: php + + principalUri = $principalUri; + $this->calendarUri = $calendarUri; + } + + // The other methods come here ... + } + +This is the basic constructor for the class and some attributes that are stored. We store some provided uris internally for later use. + +The parent constructor needs the name of the app as the first parameter. It is thus called explicitly in the first line of the constructor with the correct app name (``yourappname`` in this example). + +Some of the methods that need to be implemented are similar to the ones above for the calendar entity class. However, there are different implementations required, so all methods are revisited once in the next paragraphs. + +Basic Calendar information -- INode +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The interface ``\Sabre\DAV\INode`` has two methods that need to be implemented by the app's code. The other methods in the interface are already implemented in the ``\OCA\DAV\CalDAV\Integration\ExternalCalendar`` class. + +.. code-block:: php + + childExists($name)) { + return new CalendarObject($this, $name); + } + } + +This will pack an calendar entry into its own object as described earlier. + +The method allows to request a specific entry and extract it from the calendar. + +.. code-block:: php + + getChild($childName); }); + + return $children; + } + +Finally, there is a class to fetch all appointments of a calendar. + +.. note:: For the sake of simplicity, here only a static array is used. One could however query a database or the file system for a variable number of entries in the calendar. + +Querying the calendar -- ICalendarObjectContainer +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For calendar entries it makes little sense to query all and sort on the client the relevant ones. Instead, the client requests a certain set of objects (like the last 90 days) and the server will do the filtering. This can be achieved by the ``\Sabre\CalDAV\ICalendarObjectContainer`` interface. + +.. code-block:: php + + principalUri; + } + +Get the principal's uri. Here the stored value provided in the constructor is used. + +.. code-block:: php + + '{DAV:}read', + 'principal' => $this->getOwner(), + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}read', + 'principal' => $this->getOwner() . '/calendar-proxy-write', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}read', + 'principal' => $this->getOwner() . '/calendar-proxy-read', + 'protected' => true, + ], + ]; + } + +The ACL defined for this calendar are returned. For the exact definitions, see the documentation of Sabre. At the time of writing this was: + +============= =============================== ===================================================== +entry values description +============= =============================== ===================================================== +``principal`` uri of principal The role or person trying to access the calendar +``privilege`` ``{DAV:}read``, ``{DAV:}write`` Is the role allowed to read or to write +``protected`` ``true``, ``false`` if ``true``, this rule is not allowed to change +============= =============================== ===================================================== + +.. code-block:: php + + 'Dav Example Calendar: ' . $this->calendarUri, + '{http://apple.com/ns/ical/}calendar-color' => '#565656', + '{' . Plugin::NS_CALDAV . '}supported-calendar-component-set' => new SupportedCalendarComponentSet(['VTODO', 'VEVENT']), + ]; + } + +Here a basic stub of calendar properties are provided. It is a basic name, a color and the setting to allow both appointments (``VEVENT``) and tasks (``VTODO``) in the calendar. + +.. code-block:: php + + hasCalendarInCalendarHome($principalUri, $calendarUri)) { + return new Calendar($principalUri, $calendarUri); + } + + return null; + } + } + +The calendar plugin class needs to implement the interface ``\OCA\DAV\CalDAV\Integration\ICalendarProvider`` that defines some methods to query the list of calendars an app can provide. + +The method ``getAppId`` is mainly for accounting and returns the name of the app. + +The method ``fetchAllForCalendarHome`` returns a list of all calendars class instance that the app knows of. In this example only one calendar is registered. By adding further entries to the array, more calendars can be made available. + +Note the ``principalUri`` is passed by the caller while the ``calendarUri`` in the constructor of the calendar instance is just some (relative) uri (string) that identifies the calender uniquely. It can then be used in the calendar class to extract the appropriate entries that should be present in the calendar. + +Again, there is a function ``hasCalendarInCalendarHome`` that checks if a certain combination of ``principalUri`` and ``calendarUri`` are existing. Here, it is just hard-coded to exactly one calendar. + +Finally, there is a function to query for a single calendar instance using ``getCalendarInCalendarHome``. It returns a single calendar instance or ``null`` if no matching calendar is found. + +Register the calender provider +------------------------------ + +As a last step, you must register the calendar provider in your ``info.xml`` by adding + +.. code-block:: xml + + + + OCA\YourAppName\DAV\CalendarPlugin + + + +With all these steps done, you should be able to see the calender(s) in the calendar app and the CalDAV interface of the core. + +Appendix: Registering the calendar with the PHP API interface +------------------------------------------------------------- + +Additionally to the registration in the DAV app, the core provides another way to register a calendar. + +.. note:: Currently, the PHP API is not used by the DAV app. Any registered calendar will not automatically show up in the calendar's view or the CalDAV list. This might change in the future, thus it might be a good idea to provide this interface as well. + +Read-only support +~~~~~~~~~~~~~~~~~ + +To provide calendar(s) you have to write a class that implements the ``OCP\Calendar\ICalendarProvider`` interface. + +.. code-block:: php + + ` with ``$context->registerCalendarProvider(CalendarProvider::class);``. + + +Write support +~~~~~~~~~~~~~ + +Calendars that only return `ICalendar` are implicitly read-only. If your app's calendars can be written to, you may implement the ``ICreateFromString``. It will allow other apps to write calendar objects to the calendar by passing the raw iCalendar data as string. + +.. code-block:: php + + `_ + +.. code-block:: php + +