25. Turn talks into eventsΒΆ

We forgot something: A list of talks is great especially if you can sort it by your preferences. But if a visitor decides he wants to see a talk he needs to know when it will take place.

We need a schedule and for this we need to store the information when a talk will happen.

Luckily the type Event is based on reusable behaviors from the package plone.app.event.

In this chapter we will

  • enable this behavior for talks
  • write an upgrade step to work around a bug in plone.app.event
  • display the date in the talkview

First we enable the behavior IEventBasic for talks in profiles/default/types/talk.xml

1
2
3
4
5
6
7
<property name="behaviors">
  <element value="plone.app.dexterity.behaviors.metadata.IDublinCore"/>
  <element value="plone.app.content.interfaces.INameFromTitle"/>
  <element value="ploneconf.site.behavior.social.ISocial"/>
  <element value="ploneconf.site.interfaces.ITalk"/>
  <element value="plone.app.event.dx.behaviors.IEventBasic"/>
</property>

After we activate the behavior by hand or reinstalled the addon we could add new talks with new field for start and end.

But because of a bug in plone.app.event does not expect existing objects to get the behavior. Since existing types have no values in the fields start and end we would get a traceback on inline-validation when we edit these. To work around this we create an upgrade-step that sets some an initial date.

Register the new upgrade step in upgrades.zcml

1
2
3
4
5
6
7
8
9
<genericsetup:upgradeStep
  title="Add event-behavior to talks"
  description=""
  source="1001"
  destination="1002"
  handler="ploneconf.site.upgrades.turn_talks_to_events"
  sortkey="1"
  profile="ploneconf.site:default"
  />

Bump the profile-version to 1002 in profiles/default/metadata.xml

Write the upgrade-step in upgrades.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# -*- coding: UTF-8 -*-
from plone import api

import datetime
import logging
import pytz


default_profile = 'profile-ploneconf.site:default'

logger = logging.getLogger('ploneconf.site')

def upgrade_site(setup):
    setup.runImportStepFromProfile(default_profile, 'typeinfo')
    catalog = api.portal.get_tool('portal_catalog')
    portal = api.portal.get()
    if 'the-event' not in portal:
        theevent = api.content.create(
            container=portal,
            type='Folder',
            id='the-event',
            title='The event')
    else:
        theevent = portal['the-event']
    if 'talks' not in theevent:
        talks = api.content.create(
            container=theevent,
            type='Folder',
            id='talks',
            title='Talks')
    else:
        talks = theevent['talks']
    talks_url = talks.absolute_url()
    brains = catalog(portal_type='talk')
    for brain in brains:
        if talks_url in brain.getURL():
            continue
        obj = brain.getObject()
        logger.info('Moving %s to %s' % (obj.absolute_url(), talks.absolute_url()))
        api.content.move(
            source=obj,
            target=talks,
            safe_id=True)

def turn_talks_to_events(setup):
    """Set a start- and end-date for old events to work around a
    bug in plone.app.event 1.1.1
    """
    api.portal.set_registry_record(
        'plone.app.event.portal_timezone',
        'Europe/London')
    setup.runImportStepFromProfile(default_profile, 'typeinfo')

    tz = pytz.timezone("Europe/London")
    now = tz.localize(datetime.datetime.now())
    date = now + datetime.timedelta(days=30)
    date = date.replace(minute=0, second=0, microsecond=0)

    catalog = api.portal.get_tool('portal_catalog')
    brains = catalog(portal_type='talk')
    for brain in brains:
        obj = brain.getObject()
        if not getattr(obj, 'start', False):
            obj.start = obj.end = date
            obj.timezone = "Europe/London"

After we ran the upgrade-step we can now add a time to existing events. To display this we reuse a default event-summary view as documented in http://ploneappevent.readthedocs.io/en/latest/development.html#reusing-the-event-summary-view-to-list-basic-event-information

Edit browser/templates/talkview.pt

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
      metal:use-macro="context/main_template/macros/master"
      i18n:domain="ploneconf.site">
<body>
    <metal:content-core fill-slot="content-core" tal:define="widgets view/w">

        <tal:eventsummary replace="structure context/@@event_summary"/>

        <p>
            <span tal:content="context/type_of_talk">
                Talk
            </span>
            suitable for
            <span tal:replace="structure widgets/audience/render">
                Audience
            </span>
        </p>

        <div tal:content="structure widgets/details/render">
            Details
        </div>

        <div class="newsImageContainer">
            <img tal:condition="python:getattr(context, 'image', None)"
                 tal:attributes="src string:${context/absolute_url}/@@images/image/thumb" />
        </div>

        <div>
            <a class="email-link" tal:attributes="href string:mailto:${context/email}">
                <strong tal:content="context/speaker">
                    Jane Doe
                </strong>
            </a>
            <div tal:content="structure widgets/speaker_biography/render">
                Biography
            </div>
        </div>

    </metal:content-core>
</body>
</html>