Evolving Bits

JavaScript. iOS.

Captchas: A Spam Prevention Feature for Your Plone Forms

Spam leaves no stone unturned. How does one protect those Plone web forms that are open for anonymous web users to spam, such as the Plone contact form?

I found a straight-forward and effective solution offered by the PloneCaptcha’s product. Here are the steps to add this feature to your default Plone contact form.

Example of PloneCaptchas in action

Getting Started

As the product site mentions, you just need a free captchas.net account, and some tweaks to your CMFFormController form template and tweak to your .metadata file to include a new validator.

PloneCaptchas document errata: The site mentions adding your captchas.net captcha_username and captcha_password to config.py, but you add to PloneCaptcha.py

How-To

For Plone’s Contact form, I copied the core templates to my own product’s skin folder so they could be customized for adding the captcha:

contact-info.cpt

Here I added the field, and included PloneCaptcha’s template:

<div class="field"
  tal:define="error errors/captcha|nothing"
  tal:attributes="class python:test(error, 'field error', 'field')">
  <label for="subject">
    Captcha
  </label>
  <span class="fieldRequired" title="Required"
          i18n:attributes="title title_required;"
          i18n:translate="label_required">(Required)</span>

  <div class="formHelp">
    To reduce automated spamming, please enter the letters in the box below so we know you're a genuine human.
  </div>

  <div tal:content="error">Validation error output</div>            

  <div metal:use-macro="here/captcha/macros/edit" />
</div>

contact-info.cpt.metadata

The only change here is in the validators section:

[validators]
validators=validate_captcha, validate_site_feedback

validate_site_feedback.vpy

I also had to tweak this existing form validator so it only returned the customary “please correct the below errors” once – and not one from the PloneCaptcha validator, and one from mine. Since I put the captcha validator first in the list, I just checked to see if the state.errors object already has a captcha error, and if yes, it don’t send another portal message:

if state.getErrors():
    # don't display two portal messages if the captcha validation fails
    if not state.errors.has_key('captcha'):
        context.plone_utils.addPortalMessage(_(u'Please correct the indicated errors.'))
    return state.set(status='failure')
else:
    return state

Build Your Own Remember-based Content With Sampleremember Plone Product

Back in March, Andrew Burkhalter and I wrote a tutorial for creating new content-types based on remember, and as part of that created the sampleremember Plone product. Since then, I’ve had a couple of live project opportunities to put sampleremember through its paces.

By September, I fixed bugs in sampleremember and added some unit tests, so feel this is now a solid working example of how to create your own remember-based content types.

What is remember (and membrane)?

The membrane product allows you to create Plone users (and groups) that are actually content-types - so you can workflow them, add attributes to them, etc. remember is based on membrane and also adds the replacement Plone templates and functionality so that you can manipulate, reset passwords, login, etc using these new content types. Martin Aspeli uses membrane in his b-org tutorial if you want more info.

You can find the sampleremember product in the /examples folder inside of remember as well as a walk-through tutorial in the /docs folder of remember. Note that the tutorial is a bit-dated, so the most up-to-date implementation is in sampleremember.

How do I automate setup of sampleremember to use portal_quickinstaller?

One final issue I ran into that I didn’t solve was trying to make my remember-based products quickinstall the three profiles it needs: membrane, remember, and its own. I discovered that remember didn’t like to be uninstalled then installed again. If you don’t uninstall, but just reinstall, there isn’t a problem – but then an accidental uninstall seems like a time bomb waiting to happen.

So the best solution seems to be manually installing membrane and remember via portal_setup only once for a site and then add an Install.py script that simply runs my own product’s generic setup profile.

Removing Existing Users After Migrating a Plone Site to ‘Remember’

Existing users on a Plone 2.5 site (before migration to remember 1.0) can’t be deleted via the User and Group Administrator form.  You’ll see ‘Runtime Error: No adapter found for user’ when you try to delete one.

You can delete manually though via ‘zopectl’ or Clouseau.

$ ./bin/zopectl debug
>>> source_users = app.YOURPLONESITE_ID_HERE.acl_users.source_users
>>> # view all users:
>>> source_users.getUsers()
>>> [source_users.doDeleteUser(m.getName()) for m in source_users.getUsers()]
>>> import transaction; transaction.get().commit()

Note: the getUsers() function doesn’t return new remember users so conveniently you don’t kill those new users during this process (but you’ll want to double-check first!)

Blogging on Plone 3: Looking Forward to Quills 1.6

Quills definitely seems the way to go for blogging in Plone 3 - it’s nicely engineered in a Zope 3 style and much work has gone into it recently during the Quills development via Google Summer of Code.

I had planned to create this blog using the latest Quills 1.6 trunk to learn both about blogging and “blogging on Plone” – so downloaded and gave it a try. It installed ok on Plone 3, but I ran into errors posting blogs and playing with the portlets – to be expected during early beta testing.

I’m also intrigued with QuillsEnabled (currently in alpha) - which leverages the Quills family of products, but takes the approach of adding blog functionality to ordinary Plone content. This pattern is also used in Plone getpaid to allow ordinary Plone content to be marked Payable so that it then takes on additional functionality such as a price and a way to add the item to your shopping cart.

I’m looking forward to following the progress of Quills (nice work Tim Hicks!), and as things become more stable I envision my next blog projects using Quills.

In the meantime, I look forward to learning more about blogging and blogging software through Wordpress, which is an impressive and fun blogging solution.