Custom Event type with a registration form?

I would like to create a custom Event type with an optional registration form.
This is to avoid creating an ad-hoc easyform each time a registration form is required.

I noticed a bunch of event behaviors that could augment custom types.
For example I was thinking about a custom Folder type with event behavior(s)
to include a generic registration form made using easyform.
Or maybe a registration form could be made into a behavior to augment a custom Event type?

Any suggestions?

You could create a generic EasyForm with a field would be used as a reference for the related event. From individual events you can link to this particular form an pass the id of the event through an url parameter to the registration forms..more interesting question: where would you store registrations and how would you process them?

Have a look at this easyform plugin to handle registrations https://github.com/collective/collective.easyformplugin.registration

Some brainstorming

  1. You could add a behavior to Event type (or add a new type). This event would let you select a related EasyForm. Then a viewlet would show the form. (Maybe with pat-inject… the approach I use for 'similar stuff'). You will need to modify the "saving of registration" so it saves to "your folder" or maybe use a content rule based on "from what context it was called" ?
    The upside is that it is easy to edit the Easyform when you need to make changes.

  2. You could make a vielet that is registered for a behavior / and "some_field" is enabled. The viewlet shows the form.

  3. You could just change the event type to folderish and make an event rule that copies an easy form "into it" every time you add an event. (and then a viewlet or another browser view to show it

UPDATE: For the users, it might be more 'slick' if you use pat content load to load/show the registration, then you just use a button to load the registration form (like this http://themes.medialog.no/fragments/yy-1 )

@espenmn, I like option 3.
Questions:

  • How to change the event type to folderish?
  • How to create a pre-configured easyform to copy into the folderish event type?
  • How to use "pat content load"?

I think this can be done TTW by going to http://yourserver/Plone/portal_types/Folder/manage_propertiesForm

and change "Content type class" to plone.app.contenttypes.content.Folder

A (probably safer) alternative is to do this in an add-on, so you can replicate what you cid

Just make a standard easyform with all the settings you need (dont publish it). Then you need to program a little.

Your code should look something like:

     <subscriber
    for=".behaviors.IMyBehavior
    zope.lifecycleevent.interfaces.IObjectAddedEvent"
    handler=".events.copyEasyForm
    />

Then, in your file "events.py", (which you have to make), you need to define 'copyEasyForm" and add code to 'copy the form you made', it will be something like

def copyEasyForm(self, context):
    """copy some stuff"""
    plone.api.content.copy(source='my_easyform', target=self)

Please read: https://docs.plone.org/develop/index.html#plone-api (since you need to 'find the source document, too' )

And

https://docs.plone.org/external/plone.app.dexterity/docs/advanced/event-handlers.html

You can use for= to the Event content type instead of 'behaviours' if you prefer that (and dont want to make a behavior"

1 Like

Thanks a lot!

One issue: when changing the Event type to folderish, it does not turn existing event objects into folderish objects, only the new objects are folderish... does it means I'd have to re-import all events (using transmogrifier)?

<div id="content-target">
<button type="button" class="btn btn-primary pat-contentloader"
     data-pat-contentloader="url:${context/getURL}|None}/myeasyform?ajax_load=1;target:#content-target};?ajax_load=1;content:#content">
        <span>Click me</span>
</button>

the url syntax might be incorrect. (hard-code it until you get it working)

This is useful, thanks!

Because I want the handler to be called when an Event is created, I used
for="plone.event.interfaces.IEvent
but it does not seem to work; my copyEasyForm handler contains only a logging call to display the event in the debugging console, and nothing shows.

Any idea how to configure the subscriber?

Also, I added it to the configure.zcml file of my policy package; is it an appropriate place to add it?

Try registering it for something more generic and see if that works
Maybe you can try: for="*"

If it still does not work: where did you put this code ( in configure.zcml ? ) . Did you stop and start you plone site ?

Still nothing shows. Here's what I tried.

In the configure.zcml file (of my policy package):

<subscriber
for="* zope.lifecycleevent.interfaces.IObjectAddedEvent"
handler=".events.modifiedContent"
/>

In events.py (of my policy package):

def modifiedContent(obj, event):
    """Event object was modified, cloned or created."""
    logger.info('added event {}, {}'.format(obj, event))

Could it be that the ObjectAddedEvent is actually for the folder (event was added to the folder) and you should use something else ( `zope.lifecycleevent.interfaces.IObjectCreatedEvent ? )

@espenmn: still no luck with IObjectCreatedEvent

Do you (need to) provide a marker interface?

I have this setup working for a behavior:

    <include package="plone.behavior" file="meta.zcml"/>

    <!-- -*- extra stuff goes here -*- -->

    <plone:behavior
        title="Related Teaser Image Behavior"
        description="A related image field which displays like a leadimage"
        name="collective.behavior.relatedteaserimage"
        provides=".relatedteaserimage.IRelatedTeaserImageBehavior"
        factory=".relatedteaserimage.RelatedTeaserImage"
        marker=".relatedteaserimage.IRelatedTeaserImageMarker"
        for="plone.dexterity.interfaces.IDexterityContent"
        />

  <subscriber
      for=".relatedteaserimage.IRelatedTeaserImageMarker
           zope.lifecycleevent.interfaces.IObjectAddedEvent"
      handler=".relatedteaserimage.addILeadImageInterface"
  />

  <subscriber
      for=".relatedteaserimage.IRelatedTeaserImageMarker
           zope.lifecycleevent.interfaces.IObjectModifiedEvent"
      handler=".relatedteaserimage.addILeadImageInterface"
  />

@implementer(IRelatedTeaserImageBehavior)
@adapter(IRelatedTeaserImageMarker)
class RelatedTeaserImage(object):

    def __init__(self, context):
        self.context = context

    @property
    def related_image(self):
        if hasattr(self.context, 'related_image'):
            return self.context.related_image
        return None

    @property
    def image_caption(self):
        if hasattr(self.context, 'image_caption'):
            return self.context.image_caption
        return None

    @related_image.setter
    def related_image(self, value):
        self.context.related_image = value

    @image_caption.setter
    def image_caption(self, value):
        self.context.image_caption = value

    @ComputedAttribute
    def image(self):
        image_link = getattr(self.context.aq_explicit, 'related_image', False)
        linked_image = image_link and self.context.related_image.to_object.image or ''
        return linked_image


def addILeadImageInterface(context, event):
    context = context.aq_explicit
    has_image = getattr(context, 'related_image', False)

    if has_image and not ILeadImage.providedBy(context):
        alsoProvides(context, ILeadImage)
    elif not has_image:
        noLongerProvides(context, ILeadImage)

Everything I tried failed miserably, as if the "subscriber" tag in my configure.zcml file is simply ignored. Is there a way to list subscribed handlers? How to debug?

As the first argument of a subscriber, is it valid to provide a schema (based on plone.supermodel.model.Schema)?

Here's another test:

<subscriber
    for="plone.app.contenttypes.interfaces.IFolder zope.lifecycleevent.interfaces.IObjectCreatedEvent"
    handler=".events.modified_content"
/>

I was expecting my handler to fire at the creation of a new folder...