Poll

part of the ArsDigita Community System by Mark Dalrymple

The Big Idea

People like to offer their opinions, and one of the easiest ways to do that is to vote in an opinion poll. The Poll module lets you construct polls that are active for a range of dates, specify the choices the users can make, whether to require the voter to be a registered user, and display the current results. Since site designers like to change things, all of the user-accessible portions of the polls use the ACS style mechanism.

Limitation: this system is only useful for asking one question at a time (i.e., if you have N questions to ask, each with M possible answers, you need to create N separate polls).

Under the Hood

Three tables are used. One to hold the polls, one to hold the choices the user can make for each pool, and the actual set of votes users have made.
create table polls (
        poll_id         integer not null primary key,
        name            varchar(100),
        description     varchar(4000),
        start_date      date,
        end_date        date,
        require_registration_p  char(1) default 'f' check (require_registration_p in ('t','f'))
);
Any number of polls can be active at a time. Whether a poll is active depends on the start_date and end_date. To disable a poll, use the admin pages to set the end_date into the past or the start_date into the future. Name is a short name used to label pages and links, while description is a longer description that is displayed with the votes and results.

require_registration_p indicates whether a user has to be a registered user (have an entry in the users table) before they can vote. Making registration required implies that the user can only vote once for each poll.

If registration is not required, we can't distinguish one vote from another, so users can vote any number of times for each poll. In that case, it wouldn't be fair to let unregistered users vote any number of times and registered users vote only once, so we just let them all vote any number of times. Why not restrict by IP address then in this case? IP masquedaring hides many people behind one IP address (meaning we would prevent legal votes), and AOL users get a random IP address (meaning obnoxious folks can vote multiple times)

create table poll_choices (
        choice_id       integer not null primary key,
        poll_id         references polls,
        label           varchar(500)
);
This holds the choices that users can vote on.

create table poll_user_choices (
        poll_id         references polls,
        choice_id       references poll_choices,
        user_id         references users,
        ip_address      varchar(50),
        choice_date     date
);
Each user vote is recorded here. If there is no user ID (meaning that the voter is not a registered user), the user_id in this table is NULL. Even though we don't use the IP address to control user voting, we keep it around in case some obnoxious person stuffs the ballot box. We can go into SQL*Plus and undo the damage.

Templates and Customization

The templates for the user-accessable pages are stored in /template/poll. The templates there are pretty much just examples to use and modify (the "fancy" templates are pretty horrific) The templates are named "template-name.plain.adp" and "template-name.fancy.adp". The ACS style mechanisms choose which template to use.

There are two categories of templates in use: those that display the polls, the choices, and the results; and those that say "you did something wrong".

All templates are passed the page_title, header_image, and context_bar variables. These templates get extra variables:

Customization Functions

Customizing templates for the Poll system are twice as complicted as customizing the templates for the news system. The designers need to know how to invoke functions as well as putting varibles into <%= $variable > units. There are three functions provided that take the database-driven output (e.g. the currently active polls) and some customization information and then return a blob of html for inclusion. Designers would do something like <%= [poll_display -item_start "" -item_end "" -style_start "" -style_end ""  $choices] %>

So why not use ad_register_styletag and include tweakable parameters in the tagset? ADPs have a severe limitation in that html embedded in the styletag cause ADPs to premature end the parsing of the tagset. That is, this:

has a tagset that consists of "foo=, and a content-string of everything else.

To allow customization of each line of database-driven output, say whether to arrange the available choices in an