JD Tangney & Associates

Modified: Wednesday, November 28, 2007

Recent Clients

Client: St. Mary Magdalen Parish
Completed: September, 2004
Location: Off-site

JD Tangney and Associates designed the Parish's first web site. Pat Lutynski researched comparable web sites around the world, and came up with a truly unique design. The concept includes the black and white colors of the Dominican Order, the serenity of a darkened church, and also includes the icon-like art that adorns the interior of the church building.

We then went on to create a custom Content Management System to enable staff at the Parish offices to update schedules on their own. The schedules are simple tables with dates and times along the two axes and lists of names in each cell.

To keep the implementation as simple as possible, the CMS is written as a collection of Python CGIs. The pages are generated on the fly from templates. Again, for the sake of simplicity, Python's built-in substitution mechanism was used for the templates.

Since this project was pro bono, we have decided to release it as open source under the GPL. The code is hosted on SourceForge and can be found on the download page.

Schedules are maintained in CSV files by these CGIs. As many schedules as you like can be set up. No database required. The code reads a schedue table, allows the user to add/delete rows/columns and edit cells via CGI, then saves it.

No authentication is provided (I used .htaccess). The final schedule is "published" by writing it to a web-accessible file, to which a link must already exist from the site.

In its present version, the code makes a lot of assumptions about directory structure and so on. In the site for which this was developed, there are two directories of pages, ministries and committees. Each of those contains a bunch of HTML files and each of the HTML files contains a link to the schedule for that ministry/committee.

The lists of schedules available for updating is based on a directory traversal, with some hard-coded files (like index.html and the images directory) omitted. The titles of the ministries and committees are derived from the alt tag of the header graphic. The code is in List._getTitleFrom, in schedules.py. This may be a little fragile for your application, but it's just fine for us.

schedules.py, is the main entry point. The template used by schedules.py is schedules.html. It contains links to editSchedule.py with args describing the schedule to be edited.

editSchedule.py always reads the schedule data from a csv file first. When invoked from the above URLs, it simply generate a display version of the schedule by using editSchedule.html as template. Note that we use hidden fields to "remember" values so that they can be propagated.

The resulting page contains lots of buttons and links. All submit the same form with the same action (editSchedule.py) with the exception of "Publish" which we'll get to. Each button or link invokes a client-side JavaScript function that populates some hidden fields as a way of providing request parameters to the cgi. In particular, the "action" hidden field contains info about which button or link was clicked. In all cases except "edit", the template used is once again editSchedule.html - we come back to the same page after each action.

When the "Edit" link is clicked, we use the people.html template. This page shows a big textarea with a list of people assigned to that cell. The user can edit away, and then hit Save, which invokes the same cgi, editSchedule.py. Here, the data is saved to disk in csv file and the response is the same editSchedule page.

When "Publish" is clicked, editSchedule.py uses the schedule.html template to generate the schedule for publication on the main site. It's put into a file whose name is made by appending "Sched" to the name of the main html file.

The domain model (OK, that's a stretch) is in schedule.py. The object we load from and store to disk is an instance of Table. It has Rows which have Cells (just like an HTML table) but these objects are not part of the public API. (Smell: The proper pythonic way of designating public vs. private needs to be used here.)

A Table loads and saves itself by converting itself to/from a list of Records. A Record is a list of CSV fields.

SourceForge.net Logo