Organizing a competition with Plone

The following story is an attempt to show an example of how one can work with Plone in real world project. It’s based on a real product whose development I contributed to: acentoweb.competition.

The requisites

The client wanted a system to manage and organize online photo and video competitions. The competitions’ announcements and rules would be published in the site. The people who wanted to participate in a certain competition would register on it, entering their personal data, and then be able to submit photos and videos to be evaluated for the competition.

Participants should only be able to see their own submissions, and never the ones from the other participants, until the submission time is finished. The judge of every competition, a group of designed people, should be able to see all the submited items, but not their owners. The members of the judge should also be able to rate or reject each submission.

The participants shouldn’t be able to edit or add elements in the rest of the site, only in the competions they had signed up, and the sign-up form should look like if they were signing up for a competition, not like if they were creating an account for a normal Plone site.

The proposed solution

This is how we decided to implement the product in Plone. Surely there might be smarter ways, so comments to improve the product are appreciated. :)

First, we decided to create a folderish Archetypes content-type to represent a Competition, with classic title and description, and rules. Folderish because it would hold photos and videos. The photos would be just a copy of the Image type, and the videos of the File type, perhaps including some integration with p4a. Having special Photo and Video content-types ensures we can assign a custom workflow to them, as we actually need.

To ensure that the participants can only see their own submissions during the competition submission period, we create a special workflow for them, competition_item_workflow, with three states:

  • Private: The participant is still preparing the item. Only he can see and modify it.
  • Pending: The item is waiting for the judge evaluation. The participant can’t modify the item anymore. The judge can see and evaluate it now.
  • Published: The competition has ended and the items is marked for public display.

Only the participant (the owner) can trigger the submission of an item, and the judge can publish it later, which is implemented using role guards in the respective transitions.

Competitions themselves also have a dedicated workflow, competition_workflow, with states:

  • Private: In preparation. Can only be seen by the owner and the users he/she allows manually.
  • Open: The rules are published and participants can sign-up and submit their works.
  • Closed: The competition doesn’t accept new work submissions and the results are published.

Since a single person can participate in more than one competition, we decided to make the participants create a user in the site and sign-up later in each competition individually. To do so we:

  • Create a customized copy of the Plone join_form, with fields for location, phone number, and other personal data they need to enter when they sign-up.
  • Customize the Competition view to include a “Sign-up for this competition!” button, which would grant the “Competitor” local role to the user, which in turn would grant him rights to create and submit items for the competition.

To hide the author info from the judge, we customize the plone.documentbyline viewlet to hide it for users without the Modify portal content permission over an object. It’s not the most optimal solution perhaps, but it just works for now.

The judge for each competition is assigned manually for the managers of the site, assigning the “Reviewer” local role to individual users via the Sharing tab.

The rating is implemented via plone.contentratings. We created a custom category with a custom rating manager, since the default one wasn’t working properly with the permission settings we set for rating and reading the ratings: competitors and the judge can’t see the ratings of submissions before the competition is closed, and the judge can only rate works while the competition is open.

On Deco and Tiles – the big picture

I’ve been working these months in a Google Summer of Code project entitled Core tiles development. One thing I wanted to do is to write some documentation about how the whole Deco/Blocks/Tiles system works together – the reason is that there are a lot of packages and moving pieces involved and it’s easy to get lost trying to understand what does what and in which order. I won’t try to explain in detail how does each package do its work (read each package documentation if you’re interested) but to introduce the different packages involved.

In short, Deco is a page composition system based on semantic HTML and a grid system. Instead of using custom XML namespaces and a templating language (like METAL), Deco uses plain (strategic) HTML.

To add this feature to a Dexterity content-type you just have to add the Dexterity behavior to it. This behavior adds two fields to the content-type: layout, to select the site layout you want to use, and content. This last field will contain all the tile-related HTML markup, and is populated by default with two field tiles: title and description. The Dexterity type with the cited behavior we’re currently using is named Page and lives into

If the Deco UI package,, is installed, it will detect the presence of the content field and activate. The Deco UI allows you to insert, drag-and-drop, edit and delete tiles inside the content field of a type.

To position the tiles in the screen, the Deco UI makes use of the so-called Deco Grid System, a bunch of carefully crafted CSS classes that, when applied to div elements, position them in the page with the appropiate dimensions.

Tiles are little more than browser views with associated configuration data, and their base classes live in plone.tiles. We have transient tiles, which store the configuration data in a querystring in the tile HTML, like:

and persistent tiles, for config data not encodeable into querystrings (e.g. a large file), which store the data in the ZODB as annotations in the content object. Note the expected ‘@@’ for browser views — when this URL is accessed, it will return an HTML page with headers and a body, like:

    <link rel="stylesheet" type="text/css" href="names.css" />
    <p class="aName">Hello Israel!</p>

The (notice the “app” namespace) package registers the helper views @@add-tile, @@edit-tile and @@delete-tile to do exactly what their names say, the two first ones using a form generated from the tile data schema via plone.autoform.

So how are tiles actually rendered into a page? The answer resides in This package is in charge of loading the page layout (remember the “layout” field added by, merging in the contents of the page and “expanding” the tiles, merging the head of the tile into the head of the resulting page and putting its body where the placeholder for the tile was, as detailed in the documentation.

Finally, the basic tiles to be inserted, including image, video, attachment, navigation tree and searchbox among others, live in

Muchas gracias por vuestras respuestas.

Finalmente vamos a intentar quedar días antes de empezar el mes de alquiler para firmar el contrato, pagar la fianza en metálico y recibir las llaves: todo a la vez.

Además, vamos a pedir a nuestro (futuro) casero que nos envíe una copia del texto del contrato antes, para poder tener tiempo de discutirlo si no estuviésemos de acuerdo en algo.

Por otra parte, buscando información por la Red he encontrado este par de enlaces, bastante útiles: