Forum OpenACS Development: Making calendar work with any acs_object

Roadmap to calendar mapping any acs_object

I was doing some thinking about the OpenACS calendar last night, trying to wrap my head around what I consider to be the holy grail for OpenACS' calendar: the ability to map any sort of acs_object onto the calendar package's calendar.

I thought about it for a while, and came up with a design and roadmap to get there that would work, provide an upgrade path, and would be quite efficient as well.

Design

The basic idea is that we make a level higher than the current calendar items, and implement some type of service contract (not necessarily acs_service_contracts, but possibly so).

We add to calendar a table which lists other packages which are registered as calendar sources. The calendar package itself, with its current calendar items, would be one such calendar source, but other packages, once they are updated to conform to the new calendar API, would register themselves as calendar sources as well.

The table in the calendar package is the service contract. It keeps track of all the packages that are registered as calendar sources, the the associated Tcl proc to call in order to get the information from those calendar sources (with different views of the data too, if we want to go that far (brief, normal, verbose), and Tcl procs to show filters, create pages, and the like.

The calendar package itself, when hit with a request, goes through these steps:
  • Calls a memoized proc which finds a list of all the packages that are registered (room reservations, calendar items, project task deadlines) and the Tcl procs associated with them (basically, uses the service contract). Show these as options to the user on some part of the screen, with checkboxes next to the ones that are currently selected.
  • Go down the list of currently selected packages, calling each Tcl proc to get the actual data to show on the calendar. The Tcl procs return a list of lists, with the Julian dates and the actual presentation information. We use CSS (and choose some sort of classes that standardize things, so we can change the UI of all the elements at once).
  • We then go down the list and call procs (hopefully memoized) which show filter options as well. For example, you can filter down whose task deadlines you see, what rooms' room reservations you see, etc..

Some more details are available in the IRC log.

Roadmap

  1. Update calendar, adding the service contract (tables?). Make calendar work well with the new format.
  2. Add in another package, such as project-manager, to test how filters, etc.. work with more than one package. Write upgrade scripts.
  3. Create documentation for how to add your data to the calendar package.
  4. Update other packages.

Comments?

Collapse
Posted by Dave Bauer on
Jade,

You can remove most of your design if you utilize acs-service contract:

"We add to calendar a table which lists other packages which are registered as calendar sources." These would be the acs service contract implementations.

"the the associated Tcl proc to call in order to get the information from those calendar sources" acs service contract implementation alias is the name of the tcl procedure.

So you should not need any additional tables.

You just need to define what operations are needed including the input and output parameters for them.

Take a look at the existing service contacts for ideas and post here for feedback.

Collapse
Posted by Matthew Geddert on
I really like where you are going with this, and it would be very helpful. Right now I am doing the same type of thing, but have to do it through plsql on a per package basis, this isn't great for upgrading in the future (since they all call calendar differently). For example. i have integrated room reservations with calendar, buy simply creating a calendar and manually in the room reservation calling on a calendar item insert of the room reservation calendar (where the calendar number is specified by a parameter)... this is tedious, and not very elegant.

What you are basically saying is that calendar would become the way to view any acs-events/activities on a system wide level, if wanted to be seen in calendar... where acs-events are created and presented through a clean tcl api... Maybe, you should consider making this "higher level" calendar service an acs-events service, where calendar simply becomes a way to present acs-events in a nice, easy to see way month/week/day view. That way, if somebody doesn't want the "calendar view" lets say for an event in the events package, they can interface with the individual event display template and use that template within the events package (i.e. displaying info in events and within calendar would be the same since the service contract is with acs-events)... This would allow for multiple display options, that can be selected on a per site basis, or on an extra and intranet differently (where extranet would be a list, and intranet would be within calendar). I'm thinking maybe the acs-event display templates would be stored as cr_templates... And they could then be easily customized on a per site basis... anyways, those are some ideas.

Collapse
Posted by Jade Rubick on
I'm thinking that you could do it on any acs_object.

For example, let's say you have a table like this, in your BARBAR package.

table FOO

  Columns:
  * my_key    integer primary key
  * title          varchar
  * due_date  date

The service contract would register the table FOO, with the column due_date as the date field.

In the BARBAR package, you'd have procs that would pull information, something like:

ad_proc bb_calendar (beginning_date, end_date, format)
----------------------

set return_val [list]

db_foreach my_query get_FOO_stuff {

  if {[string equal $format "brief"]} {
  lappend return_val [list $julian_due_date "<a class="calendar-link" href="somewhere/$my_key">$title</a>"
  } else {
  # do another display format
  }
}

return $return_val

The calendar package thus can query any type of package, regardless of whether it uses acs_events or not.

The Calendar package then looks at all the implementations of the service contract and calls each proc, returning a list of lists, which has display information, and the julian dates. It then assembles them together, and puts them in the calendar.

Then it does similar things to get a list of filters to display below the calendar, to limit the display according to whatever parameters make sense for those packages.

Collapse
Posted by Matthew Geddert on
Tieing to any acs_object makes more sense now... I think you need to consider having a few more pieces of info in this service contract, I would put in:

Julian_Date, Start_Time, End_Time, Title_to_show_in_cal, Url_for_Details, Details

If Start_Time and End_Time aren't provided its an all day event. What if my acs-object has multiple independent dates associated with it, lets say i'm a contact and i have a birthday and anniversary... I can't give your new calendar app a unique ID, I might want both of them to go to /contacts/view/1234 and /contacts/view/1234... Or if i have a multi-day event, i might want any click on an entry in calendar to go to the same page.

I don't know if this would be in the scope of things you want to do in improving calendar, but one feature I really like about calendar.yahoo.com is that it allows for email reminders of the things in your calendar. One day in advance, an hour, whatever i choose. I'm thinking with openacs calendar i would subscribe to lets say 1 week notification on contacts service contract (to have a week to buy a birthday gift if necessary), and 1 day for personal calendar. Would it be possible to have calendar control reminder notifications for any package that contracts with calendar using this scenerio if you didn't have a unique object_id for each item? The service contract would use the title as the subject of the email and the details as the body...

Collapse
Posted by Alfred Werner on
Don't forget recurring events :)
Collapse
Posted by Jade Rubick on
If I remember correctly, the calendar package or the acs-events package does recurring events by adding new calendar items periodically. As long as they are in the table where the service contract is set up, the recurring events should show up on the calendar.
Collapse
Posted by Don Baccus on
We've discussed this before, though not quite in as much detail.

For starters, calendars should just map arbitrary objects to themselves, rather than require mapped objects to be a private calendar object (or child object) type.

Make this change in the datamodel, and part of your scheme just goes away.  It would require significant upgrade scripts but I believe it is definitely the way to go.  OF would've taken this work on for .LRN if they'd had time, but they didn't.

Secondly ... we want general objects to have the same capabilities as CR objects "before long" in regard to being able to map a template to an object, and to autogenerate forms for user input used to build objects.

For the moment the path of least resistance would be to restructure the calendar package to map CR items to the calendar (rather than calendar items), and to make use of the existing CR type template features and form input features to display and input such calendar items.  In this way the calendar package would not need to "know" how to call a proc (or include a template) but would use the general facility that already exists to pick the template to include when displaying a particular item.

Eventually we'd pick this up for arbitrary objects when that capability is extended to them.

Now if we need more display options than the mapped template facility gives now we could add to it (i.e. verbose etc).  I'd rather see this extended in a general model so other packages than calendar could just as easily display arbitrary objects ... provide a set of display templates mapped to an object type which can be used in various circumstances.

All the data regarding the date etc properly belongs in the calendar package itself ... having each packages Tcl API responsible for returning julian date information makes me cringe a bit ... make a mechanism which allows packages to easily map an object to the calendar and keep the date information in the calendar's mapping tables.

The above doesn't address the filter options issues at all, there's currently no mechanism such as this in the toolkit, so you're free to invent one :)

Collapse
Posted by Jade Rubick on
For starters, calendars should just map arbitrary objects to themselves, rather than require mapped objects to be a private calendar object (or child object) type.

Make this change in the datamodel, and part of your scheme just goes away.  It would require significant upgrade scripts but I believe it is definitely the way to go. 

I'm not totally sure what you mean here. My scheme does not require any sort of data structure really. It just requires the existence of procs with the right name, that get data from any object source. It doesn't actually even have to rely on the content repository, or any sort of mapping tables.
...we want general objects to have the same capabilities as CR objects "before long" in regard to being able to map a template to an object, and to autogenerate forms for user input used to build objects.
I'm not exactly sure how this works. I've never used this facility of the CR, and there's no documentation of it. I understand where you talk about moving CR features into general objects (I've followed those discussions), but if you could explain this a little more, I'd appreciate it.
For the moment the path of least resistance would be to restructure the calendar package to map CR items to the calendar (rather than calendar items), and to make use of the existing CR type template features and form input features to display and input such calendar items.  In this way the calendar package would not need to "know" how to call a proc (or include a template) but would use the general facility that already exists to pick the template to include when displaying a particular item.
So you're suggesting adding a field to cr_items or cr_revisions that is a date field? And then depending on the content_type, to display a different CR tempate in the calendar for that information?
All the data regarding the date etc properly belongs in the calendar package itself ... having each packages Tcl API responsible for returning julian date information makes me cringe a bit ... make a mechanism which allows packages to easily map an object to the calendar and keep the date information in the calendar's mapping tables.
I can understand why it makes you cringe. It just seems more flexible to me. But I don't understand the alternative well enough, so I'd love to hear more about what that entails.
Collapse
Posted by Don Baccus on
A major point that underlies my thinking above is that we've talked a lot about automating the display, form building, and other UI aspects of objects so that arbitrary packages can gobble up and attach objects of any type and incorporate their display and form input into their own pages.

The calendar's an obvious example of a package that could greatly benefit from such an approach, but it's not the only one.  A solution that works for calendar only falls short of what we want to accomplish.

Of course, there is that nagging issue of available resources to implement any scheme :)

Collapse
Posted by Dave Bauer on
Jade,

Right now, cal_items has a cal_item_id that is restricted to acs_events. Cal_item is an acs_object type subtyped from acs_event. My idea is to change cal_item_id to reference acs_objects, that way you allow any acs_object to be mapped to a calendar.

I think you actually might need to merge acs_events and cal_items so that you can store the date information along with the object mapping. That is the mapping of acs_object to calendar would be where the date attribute is stored.

Don,

Is this what you were thinking?

Collapse
Posted by Don Baccus on
Yes, that's the point I made when .LRN was first being written, a point Ben agreed with but had insufficient resources to tackle given how far behind schedule they were etc.

Jade, adding a service contract to get display information for an object type would duplicate the template association facility that already exists in the CR and that we want to extend to regular objects.  We don't really want to duplicate such functionality but rather want to 1) publicize the fact it already exists and 2) extend it to regular objects.