Preconfigured iCal Subscriptions deprecated
This article describes how to provide read-only calendars from iCal feeds that are preconfigured by the administrator to the users of a deployment, e.g. public or school holidays, company-wide events, or the weekly canteen menu.
Overview
Users can already subscribe to iCal feeds on their own. Preconfigured iCal subscriptions complement this with calendars that are defined once by the administrator in a configuration file, and enabled for users through the Config Cascade, i.e. for all users of the deployment, for groups of contexts, single contexts or single users. The same definition serves any number of contexts, across database schemas.
For each enabled subscription, a user automatically gets a read-only calendar in the public calendars section of the folder tree. The events of a feed are retrieved periodically and cached once per context, and are then processed like any other calendar data, including search, CalDAV synchronization and free/busy lookups. Each user keeps own settings for the calendar: color, whether it is subscribed, whether it is considered in free/busy data and conflict checks (schedule transparency), whether it is synchronized via CalDAV, and personal alarms, including reminders by mail or SMS. Except for the alarms, the administrator can also fix these settings for all users.
Configuration
The configuration consists of the definition of the available subscriptions in the file calendar-provider-preconfiguredical.yml, and their assignment to users via the config-cascade-enabled property com.openexchange.calendar.preconfiguredical.subscriptions. Both are reloadable.
Define Subscriptions
The subscriptions are defined in /opt/open-xchange/etc/calendar-provider-preconfiguredical.yml, with one section per subscription. The name of the section is the subscription's key, which is used to enable it for users and must not contain commas. A template with all options is available in the core repository.
With the core-mw Helm chart, the file is provided through yamlFiles, with the file name as key and the subscriptions as its content, or through secretYAMLFiles if a definition holds credentials. The property enabling them, see below, goes to properties next to it:
properties:
com.openexchange.calendar.preconfiguredical.subscriptions: holidays
yamlFiles:
calendar-provider-preconfiguredical.yml:
holidays:
name: Public Holidays
uri: https://calendar.example.org/holidays.ics
| Option | Mandatory | Default | Description |
|---|---|---|---|
name | yes | The display name of the calendar. | |
uri | yes | The URI of the iCal feed. | |
description | no | An optional description of the calendar. | |
login, password | no | Credentials for basic authentication. Quote the values, e.g. password: "0123", as YAML would otherwise interpret some of them as numbers or booleans. | |
refreshInterval | no | see Retrieval and Caching | The interval in minutes after which the feed is retrieved again. |
color | no | The color of a user's calendar, e.g. "#6a8d2f". | |
scheduleTransp | no | transparent | Whether the appointments block the user's time in free/busy data and conflict checks (opaque), or not (transparent). |
shownInTree | no | true | Whether a user's calendar is subscribed, i.e. shown in the folder tree. |
usedForSync | no | true | Whether a user's calendar is synchronized via CalDAV. |
sharedCache | no | false | Whether the retrieved feed is shared across all contexts, see Large Deployments. |
The per-user settings color, scheduleTransp, shownInTree and usedForSync are either defined as plain value, which is the initial setting that each user may change afterwards, or as section with defaultValue and protected, similar to the LDAP contacts provider. A protected setting cannot be changed by the users, and a changed value applies to all existing calendars as well:
holidays:
name: Public Holidays
uri: https://calendar.example.org/holidays.ics
usedForSync:
defaultValue: false
protected: true
Name and description are always taken from the definition, so renaming a subscription applies to all users immediately. Changing the key, on the other hand, is the same as removing the subscription and adding a new one, so the users lose their personal settings and alarms for it. Synchronization of all preconfigured subscriptions via CalDAV can also be prevented through com.openexchange.calendar.preconfiguredical.usedForSync.
Enable Subscriptions for Users
The property com.openexchange.calendar.preconfiguredical.subscriptions takes a comma-separated list of subscription keys, and can be defined through all scopes of the config cascade. For all users of the deployment, it is defined in any .properties file below /opt/open-xchange/etc:
com.openexchange.calendar.preconfiguredical.subscriptions=holidays
For a group of contexts, e.g. all contexts tagged with acme, a context set can be used, e.g. in /opt/open-xchange/etc/contextSets/preconfiguredical.yml:
acme_subscriptions:
withTags: acme
com.openexchange.calendar.preconfiguredical.subscriptions: holidays,acme-canteen
For a single context or user, the property is set as context or user attribute:
$ changecontext -A oxadminmaster -P secret -c 42 --config/com.openexchange.calendar.preconfiguredical.subscriptions=holidays,acme-canteen
$ changeuser -A oxadmin -P secret -c 42 -i 7 --config/com.openexchange.calendar.preconfiguredical.subscriptions=holidays
A value on a more specific scope replaces the one of a less specific scope as a whole, so it needs to repeat all subscriptions that should remain enabled. Keys without a definition are ignored. The provider can be disabled altogether through com.openexchange.calendar.preconfiguredical.enabled; users with at least one enabled subscription get the capability calendar_preconfiguredical.
Behavior
Calendars of the Users
The calendars are provisioned when a user's calendar folders are listed, e.g. upon login to App Suite or when a CalDAV client discovers the calendars. Guest users do not get them. The calendars are read-only, and cannot be renamed, moved, shared or deleted by the users.
When a subscription is no longer enabled for a user, the calendar is hidden with the next listing, and not considered in free/busy data, conflict checks, reminders or searches anymore. The user's settings and alarms are kept, so the calendar comes back unchanged if the subscription is enabled again. Only when a subscription is removed from the configuration file, its calendars and cached data are removed by a daily clean-up job, after a grace period configured through com.openexchange.calendar.preconfiguredical.cleanup.gracePeriod (seven days by default). When a user or context is deleted, the calendars and cached data are removed along with all other data.
When upgrading a cluster, define and enable subscriptions only once all middleware nodes run a version that supports them, as nodes without the provider would show the calendars as calendars of an unknown provider. Likewise, to remove preconfigured subscriptions entirely, e.g. prior to a downgrade to a version without this provider, remove all sections from the configuration file and set com.openexchange.calendar.preconfiguredical.enabled to false on server level, then wait for the clean-up job. A configuration file without any subscription alone removes nothing, as it is more likely a deployment error.
If a section of the configuration file cannot be read, e.g. due to a typo, the previous definition remains in effect and an error is logged. If the whole file cannot be read when a node starts, the calendars are hidden on that node until it can be read again; nothing is removed then. When the uri of a subscription is changed, the cached data is updated from the new source with the next retrieval; appointments are matched by their UID, so the users keep their alarms for appointments that are still contained.
Alarms
Users can set personal alarms for the appointments, which are only visible to themselves. Alarms contained in the feed and the user's default alarms are not applied. Besides display alarms, alarms of type mail and SMS are delivered as for any other appointment, provided that their delivery is configured. Via CalDAV, the personal alarms are included in the calendar data, but cannot be changed.
Retrieval and Caching
A feed is retrieved again when its cached data is read in a context and the refresh interval has elapsed; there is no background job, and feeds that are not accessed in a context are not retrieved there at all. The refresh interval is taken from the refreshInterval of the definition, otherwise from the feed itself (REFRESH-INTERVAL or X-PUBLISHED-TTL), and finally from com.openexchange.calendar.ical.refreshInterval, which defaults to one week. Feeds are retrieved with conditional requests, and only once per context at a time.
If a retrieval fails, the previously cached data is still served, and an error is indicated with the calendar folder, without revealing the uri. The next attempt is made after com.openexchange.calendar.ical.retryAfterErrorInterval, one hour by default. A feed that suddenly contains no appointments at all is only taken over once the next retrieval confirms it, so that a short glitch of the source does not remove the users' alarms.
Large Deployments
As the data is cached per context, each context retrieves a feed on its own by default, i.e. the source receives up to one request per active context and refresh interval. In deployments with many contexts, this can easily add up to millions of requests per day, and run into rate limits of public sources.
With sharedCache: true, the retrieved feed is shared across all contexts and middleware nodes through the cache service instead:
- The source is only retrieved by one node at a time, once the shared copy is older than the refresh interval, so it receives about one request per refresh interval for the whole deployment.
- A context whose refresh is due only reads a small entry with the version of the shared copy first, and the feed itself only if its version differs from the cached one.
- Failed retrievals, e.g. due to too many requests, defer further retrievals for the whole deployment, honoring a
Retry-After, and increasingly up to six hours; in the meantime, the previously retrieved copy is served. - Without the cache service, the feed is retrieved per context.
Further recommendations are to choose a refresh interval matching how often a feed actually changes, e.g. a day or a week for holidays, and to prefer a copy of a public feed on a web server of the own infrastructure over the public source itself.
Feed Sources
As the URIs of preconfigured subscriptions are defined by the administrator, the restrictions that protect the internal network from requests on behalf of users do not apply to them: they may also point to hosts with private or loopback addresses, or to hosts listed in com.openexchange.calendar.ical.blacklistedHosts, e.g. a self-maintained .ics file on an internal web server. Redirects are only followed to the same host, and never from https to http.
As for personal subscriptions, the scheme needs to be one of com.openexchange.calendar.ical.schemes, and feeds are limited in size through com.openexchange.calendar.ical.maxFileSize and in the number of appointments through com.openexchange.import.ical.limit. Feeds are retrieved with an own HTTP client preconfiguredical, whose timeouts can be adjusted through the general HTTP client properties, e.g. com.openexchange.httpclient.preconfiguredical.readTimeout.
Shared Calendars of This Deployment
The source can also be a calendar maintained in App Suite itself and published through an anonymous share link, i.e. anyone with the link can view, without password. This way, e.g. the canteen menu can be maintained by a few editors in one context, and distributed to all others. The link is used as uri as is, and may also point to an internal address of the middleware, so that the requests do not need to pass the external load balancer. As the share link only exports the appointments from two weeks in the past up to one year in the future by default, com.openexchange.share.handler.iCal.pastInterval and com.openexchange.share.handler.iCal.futureInterval may need to be widened, e.g. for holidays maintained for several years. In large deployments, prefer sharedCache, as each retrieval is otherwise served by the middleware itself.
Examples
Holidays for All Users
Public holidays retrieved once a day for the whole deployment, and school holidays from an internal web server retrieved once a week, which is also the default:
holidays:
name: Public Holidays
uri: https://calendar.example.org/holidays/de.ics
refreshInterval: 1440
color: "#6a8d2f"
sharedCache: true
school-holidays:
name: School Holidays
uri: http://calendars.internal.example.org/school-holidays.ics
color: "#e6a23c"
com.openexchange.calendar.preconfiguredical.subscriptions=holidays,school-holidays
Company Closing Days That Block the Users' Time
Closing days that users cannot unsubscribe from, and that always block their time, so that no meetings are scheduled on these days. The feed is protected with basic authentication:
acme-closing-days:
name: Closing Days
uri: https://intranet.acme.example.com/calendars/closing-days.ics
login: calendar-feeds
password: "secret"
refreshInterval: 720
scheduleTransp:
defaultValue: opaque
protected: true
shownInTree:
defaultValue: true
protected: true
Canteen Menu Maintained in App Suite
A canteen menu maintained in a calendar folder of the facility management's context, only meant for App Suite and never synchronized via CalDAV. The uri is the folder's link from Share, for anyone with the link, read-only and without password; its path is kept, while scheme and host are replaced by the internal address of the middleware:
acme-canteen:
name: Canteen Menu
description: The weekly menu of the canteen
uri: http://<internal address of the middleware>/<path of the anonymous link>
refreshInterval: 30
usedForSync:
defaultValue: false
protected: true
Catalog of Optional Calendars
With shownInTree: false, the calendars are provisioned for the users, but not subscribed initially. This way, a catalog of useful calendars can be offered, e.g. holidays of other countries, sports schedules or regional events, which the users can pick on their own via Subscribe to shared calendars in App Suite, and unsubscribe again later:
holidays-fr:
name: Public Holidays France
uri: https://calendar.example.org/holidays/fr.ics
refreshInterval: 10080
sharedCache: true
shownInTree: false
holidays-it:
name: Public Holidays Italy
uri: https://calendar.example.org/holidays/it.ics
refreshInterval: 10080
sharedCache: true
shownInTree: false
com.openexchange.calendar.preconfiguredical.subscriptions=holidays,school-holidays,holidays-fr,holidays-it
As a feed is only retrieved in a context once its calendar is read there, e.g. after a user picked it, calendars that nobody picks hardly cause any requests to their source. Keep the schedule transparency of such calendars at transparent: as for other subscribed calendars, free/busy data and conflict checks only consider the schedule transparency and not whether a calendar is subscribed, so an opaque calendar would block the users' time even while not picked.
Troubleshooting
If a subscription does not show up for a user, check that it is defined, that com.openexchange.calendar.preconfiguredical.subscriptions resolves to a value containing its key for the user, and that the user has the capability calendar_preconfiguredical.
The following loggers help to follow the processing:
com.openexchange.chronos.provider.ical.preconfigured.PreconfiguredICalSubscriptionRegistry: reading the definitions (Successfully initialized preconfigured iCal subscription "<key>",Error reading section "<key>") at levelINFOcom.openexchange.chronos.provider.ical.preconfigured.PreconfiguredICalDataAccounts: the first access of a subscription in a context, and changes of itsuri, at levelINFOcom.openexchange.chronos.provider.ical.preconfigured.PreconfiguredICalAccountReconciler: provisioning and hiding of the users' calendars at levelDEBUGcom.openexchange.chronos.provider.ical.preconfigured.PreconfiguredICalFeedClient: retrievals and back-off of shared copiescom.openexchange.chronos.provider.ical.preconfigured.PreconfiguredICalCleanUpExecution: the clean-up job, removals at levelINFOcom.openexchange.chronos.provider.caching.basic.BasicCachingCalendarAccessandcom.openexchange.chronos.provider.ical.BasicICalCalendarAccess: the retrieval of feeds in general, as for personal iCal subscriptions