Despite what you might think, it's fairly easy to write MySQL-based Web applications with Zope. In this case study, find out how to do just that by building a Zope-based online poll which uses MySQL to store poll questions and user responses, and DTML Methods to extract and present this information.
The way things are currently set up, a single user can vote for a specific option more than once, thereby contravening one of the basic principles of democracy: one citizen, one vote. Not many users would have the patience or inclination to do this; however, it *is* a hole, and should be plugged.
I've decided to make it slightly more difficult for users to vote more than once by setting a cookie on their system, once their vote has been successfully cast. With the addition of a few lines of script, I can now check for the presence or absence of the cookie, and thereby decide whether or not to accept the vote.
<dtml-var standard_html_header>
<dtml-if expr="REQUEST.has_key('submit')
and
REQUEST.has_key('response')and REQUEST.has_key('qid')">
<dtml-if
expr="REQUEST.has_key('lastpolled') and lastpolled == qid">
You have already
voted, and your vote cannot be accepted again.
Here are the results so far:<p>
<dtml-else>
<dtml-call "RESPONSE.setCookie('lastpolled', qid,
expires='ZopeTime()
+ 2592000')">
<dtml-call insertUserResponse>
Thank you for voting.
Here are the results so far:<p>
</dtml-if>
<dtml-in getPollResults>
<table
border=0 cellspacing=0 cellpadding=5>
<tr><td colspan=3><b><dtml-var
question></b></td></tr> <tr><td><dtml-var
response1></td><td>
<dtml-var votes1> </td></tr> <tr><td><dtml-var
response2></td><td>
<dtml-var votes2> </td></tr> <tr><td><dtml-var
response3></td><td>
<dtml-var votes3> </td></tr> <tr><td><font
size=-2>Posted on
<dtml-var date fmt="%d/%m/%Y"> </font></td><td><font
size=-2><dtml-var
expr="votes1 + votes2 + votes3"> total
votes</font></td></tr>
</table><p>
</dtml-in>
<dtml-else>
<h4><a
href="viewCurrentPoll">Try again!</a></h4>
</dtml-if>
<dtml-var standard_html_footer>
Once the user votes, a cookie is set on the client browser.
<dtml-if expr="REQUEST.has_key('lastpolled') and lastpolled == qid"> You
have already voted, and your vote cannot be accepted again. Here are theresults so far:<p> <dtml-else> <dtml-call "RESPONSE.setCookie('lastpolled', qid,expires='ZopeTime() + 2592000')"> <dtml-call insertUserResponse> Thank you for voting. Here are the results so far:<p> </dtml-if>
Now, on each subsequent vote attempt, the script will first check for the presence of the cookie and, if it exists, the value of the cookie variable "lastpolled". Only if the cookie is absent (indicating that this is a first-time voter) or the value of "lastpolled" is different from the identifier for the current poll question (indicating that the user has voted previously, but in response to a different question) will the vote be accepted.
This is by no means foolproof - any reasonably adept user can delete the cookie from the client's cache and vote more than once - but it does perhaps offer an additional layer of security to the process. The ideal method, of course, is to track voters on the server itself, and deny votes to those who have already voted - and indeed, this is a feasible alternative if your Zope site only allows registered users to access its online polls.