Documentation for uwosh.pfg.d2c

Contents:

Configuration and setup

.config module

Common configuration constants

uwosh.pfg.d2c.config.PROJECTNAME
uwosh.pfg.d2c.config.ADD_PERMISSIONS

Interfaces

interface uwosh.pfg.d2c.interfaces.IFormSaveData2ContentEntry
interface uwosh.pfg.d2c.interfaces.IFormSaveData2ContentAdapter
interface uwosh.pfg.d2c.interfaces.IFormSaveData2ContentEntryFinalizedEvent

Extends: zope.component.interfaces.IObjectEvent

an event sent when the entry is completed

Content types

There are two content types defined in modules within the ‘content’ package:

.content.dataentry module

Implements a data content entry type for use by the save data adapter.

class uwosh.pfg.d2c.content.dataentry.FormSaveData2ContentEntry(oid, **kwargs)

Multi-purpose content type used by the save data adapter to store form submissions

Title()
generate custom title from the selected form field or the given TALES expression override
getValue(field)
somewhat a replacement for the get generated methods.

.content.savedataadapter module

Implements a PFG action adapter to save form submissions as content type instances.

class uwosh.pfg.d2c.content.savedataadapter.FormSaveData2ContentAdapter(oid, **kwargs)

PFG save data adapter that saves form data to content objects

entry_types()
get a vocabulary of available FTI clones of FormSaveData2ContentEntry
setEntryType(entry_type)
add the selected entry type to allowed types if it isn’t
createEntry()
create an entry of the chosen type
onSuccess(fields, REQUEST=None, loopstop=False)
Triggered on successful form submission. Creates a data content entry, adds form contents to it, reindexes and sends an event to notify subscribers of the new entry.
fieldVocabulary()
An utility that provides a list of all form field names.

Events

.events module

Custom event implementations.

class uwosh.pfg.d2c.events.FormSaveData2ContentEntryFinalizedEvent(object)
Useful for third-party code that wants to do something with data content entries as soon as they are created. Built-in zope/AT events either fire too early, or fire also upon subsequent content edits. This event is only fired once after each data entry is fully created, making it more useful for the purpose.

Doctest usage examples

Demonstrating using the save content adapter.

  • add adapter
  • select adapter
  • test adapter with all fields
  • test adapter with(out) avoiding security checks
  • test with creating different content types
  • event triggering

Being a doctest, we can tell a story here.

First, we must perform some setup. We use the testbrowser that is shipped with Five, as this provides proper Zope 2 integration. Most of the documentation, though, is in the underlying zope.testbrower package.

>>> from Products.Five.testbrowser import Browser
>>> browser = Browser()
>>> browser.handleErrors = False
>>> portal_url = self.portal.absolute_url()

The following is useful when writing and debugging testbrowser tests. It lets us see all error messages in the error_log.

>>> self.portal.error_log._ignored_exceptions = ()

With that in place, we can go to the portal front page and log in. We will do this using the default user from PloneTestCase:

>>> from Products.PloneTestCase.setup import portal_owner, default_password
>>> browser.open(portal_url + '/login')

We have the login portlet, so let’s use that.

>>> browser.getControl(name='__ac_name').value = portal_owner
>>> browser.getControl(name='__ac_password').value = default_password
>>> browser.getControl(name='submit').click()

And we ensure that we get the friendly logged-in message:

>>> "You are now logged in" in browser.contents
True

Add the form

>>> browser.open(self.portal.absolute_url())
>>> browser.getLink('Form Folder').click()
>>> browser.getControl(name="title").value = "test-form"
>>> browser.getControl(name="actionAdapter:list").value = []
>>> browser.getControl("Save").click()
>>> form = self.portal['test-form']

Add the adapter

>>> browser.getLink('Save Data to Content Adapter').click()
>>> browser.getControl(name="title").value = 'results'
>>> browser.getControl(name="dynamicTitle").value = 'string:hello this is my title'
>>> browser.getControl(name="form.button.save").click()

Enable the adapter

>>> browser.getLink(text="test-form").click()
>>> browser.getLink(text="Edit").click()
>>> browser.getControl(name="actionAdapter:list").value = ['results']
>>> browser.getControl("Save").click()
>>> adapter = form['results']

Now, we’ll add all interesting fields to the form.

Checkbox

>>> browser.open(form.absolute_url())
>>> browser.getLink(text="Checkbox Field").click()
>>> browser.getControl(name="title").value = 'checkbox'
>>> browser.getControl("Save").click()

Date/Time

>>> browser.open(form.absolute_url())
>>> browser.getLink(text="Date/Time Field").click()
>>> browser.getControl(name="title").value = 'datetime'
>>> browser.getControl("Save").click()

Decimal Number

>>> browser.open(form.absolute_url())
>>> browser.getLink(text="Decimal Number Field").click()
>>> browser.getControl(name="title").value = 'decimal'
>>> browser.getControl("Save").click()

Lines Field

>>> browser.open(form.absolute_url())
>>> browser.getLink(text="Lines Field").click()
>>> browser.getControl(name="title").value = 'lines'
>>> browser.getControl("Save").click()

Password

>>> browser.open(form.absolute_url())
>>> browser.getLink(text="Password Field").click()
>>> browser.getControl(name="title").value = 'password'
>>> browser.getControl("Save").click()

Rating

>>> browser.open(form.absolute_url())
>>> browser.getLink(text="Rating-Scale Field").click()
>>> browser.getControl(name="title").value = 'rating'
>>> browser.getControl("Save").click()

Selection Field

>>> browser.open(form.absolute_url())
>>> browser.getLink(text="Selection Field").click()
>>> browser.getControl(name="title").value = 'selection'
>>> browser.getControl(name="fgVocabulary:lines").value = 'one\ntwo\nthree'
>>> browser.getControl("Save").click()

Fill out the fields and make sure they get saved.

>>> browser.open(form.absolute_url())
>>> browser.getLink(text="test-form").click()
>>> browser.getLink(text="View").click()
>>> browser.getControl(name="replyto").value = "foo@bar.com"
>>> browser.getControl(name="topic").value = "Hello"
>>> browser.getControl(name="comments").value = "This is awesome."
>>> browser.getControl(name="checkbox:boolean").value = True
>>> browser.getControl(name="datetime_year").value = ['2010']
>>> browser.getControl(name="datetime_month").value = ['01']
>>> browser.getControl(name="datetime_day").value = ['01']
>>> browser.getControl(name="datetime_hour").value = ['01']
>>> browser.getControl(name="datetime_minute").value = ['00']
>>> browser.getControl(name="datetime_ampm").value = ['PM']
>>> browser.getControl(name="decimal").value = "1.0"
>>> browser.getControl(name="lines:lines").value = "hello"
>>> browser.getControl(name="password").value = "mypassword"
>>> browser.getControl(name="rating.1:record").value = ['Strongly disagree']
>>> browser.getControl(name="rating.2:record").value = ['Strongly agree']
>>> browser.getControl(name="selection").value = ["one"]
>>> browser.getControl("Submit").click()

Check that the results were saved and go to them.

>>> len(adapter.objectIds()) == 1
True
>>> result = adapter.values()[0]
>>> browser.open(result.absolute_url())
>>> 'foo@bar.com' in browser.contents
True
>>> 'Hello' in browser.contents
True
>>> 'This is awesome.' in browser.contents
True
>>> 'hello this is my title' in browser.contents
True
>>> schema = result.Schema()
>>> schema.get('rating').get(result)
{'1': 'Strongly disagree', '2': 'Strongly agree'}

Now let’s make the form public and make sure it still creates the result when not logged in.

>>> browser.open(form.absolute_url())
>>> browser.getLink('Publish').click()
>>> browser.open(self.portal.absolute_url() + '/logout')
>>> browser.open(form.absolute_url())
>>> browser.getControl(name="replyto").value = "foo1@bar1.com"
>>> browser.getControl(name="topic").value = "Hello Again"
>>> browser.getControl(name="comments").value = "This is cool."
>>> browser.getControl("Submit").click()
>>> len(adapter.objectIds()) == 2
True

let’s login and make the adapter not avoid security permissions

>>> browser.open(portal_url + '/login')
>>> browser.getControl(name='__ac_name').value = portal_owner
>>> browser.getControl(name='__ac_password').value = default_password
>>> browser.getControl(name='submit').click()
>>> browser.open(adapter.absolute_url())
>>> browser.getLink("Edit").click()
>>> browser.getControl(name="avoidSecurityChecks:boolean").value = None
>>> browser.getControl(name="form.button.save").click()

We’ll log out again and try submitting the form.

>>> browser.open(self.portal.absolute_url() + '/logout')
>>> browser.open(form.absolute_url())
>>> browser.getControl(name="replyto").value = "foo1@bar1.com"
>>> browser.getControl(name="topic").value = "Hello Again"
>>> browser.getControl(name="comments").value = "This is cool."
>>> browser.getControl("Submit").click()
>>> len(adapter.objectIds()) == 2
True

Let’s try out the functionality of saving as different content types.

Login first...

>>> browser.open(portal_url + '/login')
>>> browser.getControl(name='__ac_name').value = portal_owner
>>> browser.getControl(name='__ac_password').value = default_password
>>> browser.getControl(name='submit').click()

Next, let’s copy the FormSaveData2ContentEntry entry first and use that.

>>> browser.open(self.portal.absolute_url() + '/portal_types/manage_main')
>>> browser.getControl(name="ids:list").value = ['FormSaveData2ContentEntry']
>>> browser.getControl(name="manage_copyObjects:method").click()
>>> browser.getControl(name="manage_pasteObjects:method").click()
>>> browser.open(self.portal.absolute_url() + '/portal_types/copy_of_FormSaveData2ContentEntry/manage_propertiesForm')
>>> browser.getControl(name="title:string").value = "My New D2C Content Type"
>>> browser.getControl(name="manage_editProperties:method").click()

Now go to the save data adapter and see if the option for the new content type is there.

>>> browser.open(adapter.absolute_url())
>>> browser.getLink("Edit").click()
>>> "My New D2C Content Type" in browser.contents
True

FormSaveData2ContentEntry should be the default value.

>>> browser.getControl(name="entryType").value
['FormSaveData2ContentEntry']

Okay, the new type is there. Let’s use it now.

>>> browser.getControl(name="entryType").value = ["copy_of_FormSaveData2ContentEntry"]
>>> browser.getControl(name="form.button.save").click()

Make sure it saved.

>>> "My New D2C Content Type" in browser.contents
True
>>> adapter.getEntryType()
'copy_of_FormSaveData2ContentEntry'

Now that the type is selected, try and submit another form and make sure it is of the same type.

>>> browser.open(form.absolute_url())
>>> browser.getControl(name="replyto").value = "foo2@bar2.com"
>>> browser.getControl(name="topic").value = "Another One! Yay!"
>>> browser.getControl(name="comments").value = "Nice. a new content type"
>>> browser.getControl("Submit").click()
>>> len(adapter.objectIds())
3
>>> entry = adapter[adapter.objectIds()[-1]]
>>> entry.getField('replyto').get(entry)
'foo2@bar2.com'
>>> entry.portal_type
'copy_of_FormSaveData2ContentEntry'

Set up an event subscriber to listen to FormSaveData2ContentEntryFinalizedEvent events.

>>> def entry_added_handler(obj, evt):
...    print "received event: " + evt.__class__.__name__

Add it to subscriber list:

>>> import zope.component
>>> import zope.component.event
>>> gsm = zope.component.getGlobalSiteManager()
>>> from uwosh.pfg.d2c.interfaces import IFormSaveData2ContentEntry
>>> from uwosh.pfg.d2c.interfaces import IFormSaveData2ContentEntryFinalizedEvent
>>> from uwosh.pfg.d2c.events import FormSaveData2ContentEntryFinalizedEvent
>>> zope.component.provideHandler(entry_added_handler, [IFormSaveData2ContentEntry, IFormSaveData2ContentEntryFinalizedEvent])

Fill in yet another entry form to fire an event.

>>> browser.open(form.absolute_url())
>>> browser.getControl(name="replyto").value = "foo3@bar3.com"
>>> browser.getControl(name="topic").value = "..And yet another.."
>>> browser.getControl(name="comments").value = "We want to send an event"

Our handler gets called when we submit it.

>>> browser.getControl("Submit").click()
received event: FormSaveData2ContentEntryFinalizedEvent

Indices and tables