Whats up, plone.app.event?

Copyright: Tango Project, http://tango.freedesktop.org/ Shortly after Plone 4.2 feature freeze announcement, we - Rok Garbas and Johannes Raggam - met up to bring plone.app.event [1] forward and see what's missing to be submitted for the next Plone release. Well, we didn't catch the deadline, but did some amazing work which will ultimately lead in a better event implementation.

Rok and me met up on a sunny Saturday morning in Ljubljana. Since there was no hacker space available to be opened on this weekend - people were on the seaside, which was actually a very good idea - we developed a new sprint-style: bar-driven development. We started in a cafe, discussed all TODOs and began to work on the first couple of tasks. Before we closed the sprint 26 hours later, we have been in 4 more bars, excluding those we visited without our laptops [2]. Our only need was free WIFI, power plugs, cafe and drinks. That worked out very well and was fun too!

Plone.app.event was started at the cologne sprint in march 2010 [3], building upon previous work like vs.event, Dateable, Kalends and Products.DateRecurringIndex. Now, while discussing the left over TODOs from the Artsprint 2011 in Vienna [4], we rethought some design decisions and came to the conclusion, that refactoring of all involved packages is what we need in order to meet plone.app.event's initial goals: An encapsulated and independent [a], archetypes and dexterity aware [b], standards compliant [c], event implementation with support of recurrence [d], a modern dateinput widget [e], with features like whole-day-events [f] and proper timezone support [g].

Encapsulation and Independence

To meet the goal [a] - encapsulation, we moved as much as possible event related code out from the packages Products.CMFCore, plone.app.portlets and Products.ATContentTypes into plone.app.event [5] and plone.rfc5545 [6] (formerly plone.event). Event the catalog index registration via Generic Setup was moved out of Products.CMFCore into plone.app.event, since it's only needed if there are eventish content types with and start and end dates available. The goal is also to remove the dependency of Products.CMFCalendar, which functionality should be provided by plone.app.event then.

Archetypes and Dexterity aware

To support archetypes and at the same time dexterity [b], we factored out generic code into reusable modules. Plone.rfc5545 is generic without dependencies to the Plone core and can thus be used independently of Plone. All Archetypes related code is encapsulated in a submodule of plone.app.event respectively plone.formwidget.dateinput. A dexterity content type is yet not available, but will be provided sometime soon.

Standards compliancy

The standards involved [c] covers compliance with the iCalendar standard - also known as RFC5545 [7], which obsoletes RFC2445. Rok started to create an RFC compatible serializer which utilizes the Zope's component architecture in a very smart way. An deserializer can later be added. This might lead sometime into a (Attention: Utopia!) caldav server which is able to handle subscriptions from calendar clients like Apples iCal or Mozillas Sunbird. Zope even provides an webdav interface, so we can build upon a stable infrastructure. Imagine the awesome capabilities if Plone provides such a functionality!

Recurrence support

The recurrence support [d] is build upon the library python-dateutil [8], which itself is RFC2445 compliant. The difference to RFC5545 is mostly, that RFC5545 does not allow (respectively should not use) more than one recurrence rule definitions and removes the ability to define exclusion rule sets. The library handles the calculations of occurrences of an event and can parse RFC compatible recurrence strings directly. There is also an index, which handles recurring dates - the package Products.DateRecurringIndex [9]. It is production ready and works as a direct and transparent replacement of Zope's DateIndex. If you query for events on a specific date, it will return also Events, which do not have their start date but a recurrence on the queried date. If you need all occurrences of an specific event, you have to use a method on this recurrence-enabled event to get it. The possibility to query the index for that is - yet - not available. Lennart Regebro, who is also a specialist on recurring events, delivered another index for that purpose - the plone.app.eventindex [10]. It does lazy indexing on query time and is an very interesting alternative. Anyway, the discussion about indexing recurring events flared up and some open questions regarding indexing performance and meaningful benchmarks - as well as an still to be polished recurrence input widget [11] - are the reasons why here is still some more work to do.

Dateinput widget

[e] Plone's current dateinput widget has come into its days. There are fresher JQuery based alternatives available, especially the JQueryUI Datepicker [12] and the JQueryTools Dateinput [13]. Since Plone uses JQueryTools we are using the Datepicker. We developed the package archetypes.datetimewidget as a fork of collective.z3cforms.datetimewidget. Those packages share a lot of common functionality, so we merged them into plone.app.dateinput [14]. It's on it's way.

Whole-day events

Plone.app.event will support whole-day events [f]. Not a big deal, but very convenient. Whole-day events are still stored with a time component, which for the start field is set to 0:00 and for the end field to 23:59. The time component is hidden per JavaScript when selecting the whole-day checkbox.

Timezone support

And finally Timezones [g]: Proper timezone support was long missing in Plone, it's planned to land in the 4.x series. With plone.app.event, we can set the Portal's default timezone, a timezone for a specific event (the options are limited through an available timezones property in plone.app.registry), and eventually timezones per user. UTC serves as our reference timezone and all dates are stored in UTC, while the timezone is stored in a separate field. This makes handling of timezones and converting to different zones for display much more predictable, since UTC is not subject to change. Internally we rely on the pytz library instead of Zope-DateTime's own implementation. Pytz [15] is a python implementation of the Olson Database [16], which is updated several times a year. Proper timezone support is necessary, especially for recurring events over Daylight Saving Time changes, where it's necessary to know if or if not a additional offset has to be added. It's mostly implemented except the support of user timezones.

What next?

If you want to try everything out, i suggest to use out the pre-refactored implementation from plone-svn [17]. If you want to try out and test the refactored cutting edge development version, go for this one: [5]. Run buildout, run the tests, start the instance (at least for the pre-refactored version) and start playing.

Vincent Fretin uses the pre-refactored implementation in production. We are now in a state, where the conceptional refactoring and migration to plone.app.testing as base test infrastructure is almost done. We have to get all refactored packages work again and fix all failing tests. The recurrence widget has to be polished and brought into a workable state, including javascript tests. The recurrence indexes have to be benchmarked and further developed. There is still some more work TODO, as you can see here [18].

So come and join in, help with finding and/or fixing bugs, install and test it. Or maybe finance a sprint or the development itself, if you are in need of a working event content type and framework implementation, that might be superior to any calendaring application ever seen on this planet ;).


For more information contact:

Johannes Raggam <johannes@raggam.co.at>
Rok Garbas <rok.garbas@gmail.com>
Vincent Fretin <vincent.fretin@gmail.com>
BlueDynamics Alliance <dev@bluedynamics.com>

Or one of the contributors listed here [19].