def test_event_accessor__sync_uid(self):
        self.request.set('HTTP_HOST', 'nohost')

        e1 = createContentInContainer(
            self.portal,
            'plone.app.event.dx.event',
            title='event1'
        )
        acc = IEventAccessor(e1)

        # setting no sync uid will automatically generate one
        self.assertTrue(acc.sync_uid, IUUID(e1) + '@nohost')
        # it's not stored on the object though
        self.assertEqual(e1.sync_uid, None)
        # but it's indexed
        result = self.portal.portal_catalog(sync_uid=IUUID(e1) + '@nohost')
        self.assertEqual(len(result), 1)

        # Setting the sync_uid
        acc.sync_uid = 'okay'
        e1.reindexObject()
        self.assertEqual(acc.sync_uid, 'okay')
        # Now, it's also stored on the object itself
        self.assertEqual(e1.sync_uid, 'okay')
        # and indexed
        result = self.portal.portal_catalog(sync_uid='okay')
        self.assertEqual(len(result), 1)
Esempio n. 2
0
    def test_event_accessor(self):
        obj = MockObject()
        tz = pytz.timezone('Europe/Vienna')
        obj.start = datetime(2012, 12, 12, 10, 0, tzinfo=tz)
        obj.end = datetime(2012, 12, 12, 12, 0, tzinfo=tz)
        zope.interface.alsoProvides(obj, IEvent)

        # Create accessor
        acc = IEventAccessor(obj)

        # Accessor getters
        self.assertEqual(acc.start, obj.start)
        self.assertEqual(acc.end, obj.end)
        self.assertEqual(acc.duration, obj.end - obj.start)

        # Accessor setters
        start = datetime(2013, 4, 5, 16, 31, tzinfo=tz)
        end = datetime(2013, 4, 5, 16, 35, tzinfo=tz)
        acc.start = start
        acc.end = end
        self.assertTrue(acc.start == obj.start == start)
        self.assertTrue(acc.end == obj.end == end)

        # Accessor deletor
        acc.something = True
        self.assertTrue(acc.something == obj.something is True)
        del acc.something
        self.assertTrue(hasattr(acc, 'something') is False)
        self.assertTrue(hasattr(obj, 'something') is False)

        del acc.start
        self.assertTrue(hasattr(acc, 'start') is False)
        self.assertTrue(hasattr(obj, 'start') is False)
    def migrate_schema_fields(self):
        newacc = IEventAccessor(self.new)
        newacc.start = self.old.start_date
        newacc.end = self.old.end_date
        newacc.timezone = str(self.old.start_date.tzinfo) \
            if self.old.start_date.tzinfo \
            else default_timezone(fallback='UTC')

        if hasattr(self.old, 'location'):
            newacc.location = self.old.location
        if hasattr(self.old, 'attendees'):
            newacc.attendees = tuple(self.old.attendees.splitlines())
        if hasattr(self.old, 'event_url'):
            newacc.event_url = self.old.event_url
        if hasattr(self.old, 'contact_name'):
            newacc.contact_name = self.old.contact_name
        if hasattr(self.old, 'contact_email'):
            newacc.contact_email = self.old.contact_email
        if hasattr(self.old, 'contact_phone'):
            newacc.contact_phone = self.old.contact_phone
        if hasattr(self.old, 'text'):
            # Copy the entire richtext object, not just it's representation
            IEventSummary(self.new).text = self.old.text

        # Trigger ObjectModified, so timezones can be fixed up.
        notify(ObjectModifiedEvent(self.new))
Esempio n. 4
0
    def test_import_from_ics__no_sync(self):
        """SYNC_NONE and importing the same file again should create new event
        objects and give them each a new sync_uid.
        """
        self.portal.invokeFactory('Folder', 'impfolder2')
        impfolder = self.portal.impfolder2

        directory = os.path.dirname(__file__)
        icsfile = open(os.path.join(directory, 'icaltest.ics'), 'rb').read()

        res = ical_import(impfolder, icsfile, self.event_type)
        self.assertEqual(res['count'], 5)

        e11 = impfolder['e1']
        suid1 = IEventAccessor(e11).sync_uid

        res = ical_import(impfolder,
                          icsfile,
                          self.event_type,
                          sync_strategy=base.SYNC_NONE)
        self.assertEqual(res['count'], 5)

        e12 = impfolder['e1-1']
        suid2 = IEventAccessor(e12).sync_uid

        self.assertEqual(len(impfolder.contentIds()), 10)
        self.assertNotEqual(suid1, suid2)
Esempio n. 5
0
    def test_event_accessor(self):
        utc = pytz.utc
        self.portal.invokeFactory('plone.app.event.dx.event', 'event1',
                start=datetime(2011, 11, 11, 11, 0, tzinfo=utc),
                end=datetime(2011, 11, 11, 12, 0, tzinfo=utc),
                timezone='UTC',
                whole_day=False)
        e1 = self.portal['event1']

        # setting attributes via the accessor
        acc = IEventAccessor(e1)
        acc.end = datetime(2011, 11, 13, 10, 0)
        acc.timezone = TZNAME

        tz = pytz.timezone(TZNAME)

        # accessor should return end datetime in the event's timezone
        self.assertTrue(acc.end == datetime(2011, 11, 13, 11, 0, tzinfo=tz))

        # the behavior's end datetime is stored in utc on the content object
        self.assertTrue(e1.end == datetime(2011, 11, 13, 10, 0, tzinfo=utc))

        # accessing the end property via the behavior adapter, returns the
        # value converted to the event's timezone
        self.assertTrue(IEventBasic(e1).end ==
                datetime(2011, 11, 13, 11, 0, tzinfo=tz))

        # timezone should be the same on the event object and accessor
        self.assertTrue(e1.timezone == acc.timezone)

        self.portal.manage_delObjects(['event1'])
Esempio n. 6
0
    def test_event_accessor__sync_uid(self):
        self.request.set('HTTP_HOST', 'nohost')

        e1 = createContentInContainer(
            self.portal,
            'plone.app.event.dx.event',
            title=u'event1'
        )
        acc = IEventAccessor(e1)

        # setting no sync uid will automatically generate one
        self.assertTrue(acc.sync_uid, IUUID(e1) + '@nohost')
        # it's not stored on the object though
        self.assertEqual(e1.sync_uid, None)
        # but it's indexed
        result = self.portal.portal_catalog(sync_uid=IUUID(e1) + '@nohost')
        self.assertEqual(len(result), 1)

        # Setting the sync_uid
        acc.sync_uid = 'okay'
        e1.reindexObject()
        self.assertEqual(acc.sync_uid, 'okay')
        # Now, it's also stored on the object itself
        self.assertEqual(e1.sync_uid, 'okay')
        # and indexed
        result = self.portal.portal_catalog(sync_uid='okay')
        self.assertEqual(len(result), 1)
Esempio n. 7
0
    def test_import_from_ics__sync_keep_mine(self):
        """SYNC_KEEP_MINE and importing the same file again should do nothing.
        """
        self.portal.invokeFactory('Folder', 'impfolder3')
        impfolder = self.portal.impfolder3

        directory = os.path.dirname(__file__)
        icsfile = open(os.path.join(directory, 'icaltest.ics'), 'rb').read()

        res = ical_import(impfolder, icsfile, self.event_type)
        self.assertEqual(res['count'], 5)

        e1a = IEventAccessor(impfolder.e1)
        mod1 = e1a.last_modified
        suid1 = e1a.sync_uid

        res = ical_import(impfolder,
                          icsfile,
                          self.event_type,
                          sync_strategy=base.SYNC_KEEP_MINE)
        self.assertEqual(res['count'], 0)
        e1a = IEventAccessor(impfolder.e1)
        mod2 = e1a.last_modified
        suid2 = e1a.sync_uid

        self.assertEqual(len(impfolder.contentIds()), 5)

        self.assertEqual(mod1, mod2)
        self.assertEqual(suid1, suid2)
Esempio n. 8
0
    def test_event_accessor(self):
        utc = pytz.utc
        self.portal.invokeFactory(
            'plone.app.event.dx.event',
            'event1',
            start=datetime(2011, 11, 11, 11, 0, tzinfo=utc),
            end=datetime(2011, 11, 11, 12, 0, tzinfo=utc),
            timezone='UTC',
            whole_day=False
        )
        e1 = self.portal['event1']

        # setting attributes via the accessor
        acc = IEventAccessor(e1)
        acc.end = datetime(2011, 11, 13, 10, 0)
        acc.timezone = TZNAME

        tz = pytz.timezone(TZNAME)

        # accessor should return end datetime in the event's timezone
        self.assertTrue(acc.end == datetime(2011, 11, 13, 11, 0, tzinfo=tz))

        # the behavior's end datetime is stored in utc on the content object
        self.assertTrue(e1.end == datetime(2011, 11, 13, 10, 0, tzinfo=utc))

        # accessing the end property via the behavior adapter, returns the
        # value converted to the event's timezone
        self.assertTrue(
            IEventBasic(e1).end == datetime(2011, 11, 13, 11, 0, tzinfo=tz)
        )

        # timezone should be the same on the event object and accessor
        self.assertTrue(e1.timezone == acc.timezone)
Esempio n. 9
0
    def test_event_accessor__start_end(self):
        e1 = createContentInContainer(
            self.portal,
            'plone.app.event.dx.event',
            title=u'event1'
        )

        dt = datetime(2161, 1, 1)  # United Federation of Planets
        DT = DateTime('2161/01/01 00:00:00 UTC')

        acc = IEventAccessor(e1)

        # Setting a timezone-naive datetime should convert it to UTC
        acc.start = dt
        self.assertEqual(acc.start, utils.utc(dt))
        self.assertEqual(e1.start, utils.utc(dt))
        # Setting a DateTime should convert it to datetime
        acc.start = DT
        self.assertEqual(acc.start, utils.utc(dt))
        self.assertEqual(e1.start, utils.utc(dt))

        # Same goes for acc.end
        # Setting a timezone-naive datetime should convert it to UTC
        acc.end = dt
        self.assertEqual(acc.end, utils.utc(dt))
        self.assertEqual(e1.end, utils.utc(dt))
        # Setting a DateTime should convert it to datetime
        acc.end = DT
        self.assertEqual(acc.end, utils.utc(dt))
        self.assertEqual(e1.end, utils.utc(dt))
    def test_import_from_ics(self):
        # Ical import unit test.
        self.portal.invokeFactory('Folder', 'impfolder1')
        impfolder = self.portal.impfolder1

        directory = os.path.dirname(__file__)
        icsfile = open(os.path.join(directory, 'icaltest.ics'), 'rb').read()
        res = ical_import(impfolder, icsfile, self.event_type)

        self.assertEqual(res['count'], 5)
        self.assertEqual(len(impfolder.contentIds()), 5)

        at = pytz.timezone('Europe/Vienna')
        utc = pytz.utc

        # Use pydt to normalize for DST times.

        # TODO: test for attendees. see note in
        # plone.app.event.ical.importer.ical_import
        e1 = IEventAccessor(impfolder.e1)
        self.assertEqual(e1.start, at.localize(datetime(2013, 7, 19, 12, 0)))
        self.assertEqual(e1.end, at.localize(datetime(2013, 7, 20, 13, 0)))
        self.assertEqual(e1.description, 'A basic event with many properties.')
        self.assertEqual(e1.whole_day, False)
        self.assertEqual(e1.open_end, False)
        self.assertEqual(
            e1.sync_uid,
            u'48f1a7ad64e847568d860cd092344970',
        )

        e2 = IEventAccessor(impfolder.e2)
        self.assertEqual(e2.start, utc.localize(datetime(1996, 4, 1, 1, 0)))
        self.assertEqual(e2.end, utc.localize(datetime(1996, 4, 1, 2, 0)))
        self.assertEqual(
            e2.recurrence,
            u'RRULE:FREQ=DAILY;COUNT=100\nEXDATE:19960402T010000Z,'
            u'19960403T010000Z,19960404T010000Z')

        e3 = IEventAccessor(impfolder.e3)
        self.assertEqual(e3.start, at.localize(datetime(2012, 3, 27, 10, 0)))
        self.assertEqual(e3.end, at.localize(datetime(2012, 3, 27, 18, 0)))
        self.assertEqual(
            e3.recurrence,
            u'RRULE:FREQ=WEEKLY;UNTIL=20120703T080000Z;BYDAY=TU\n'
            u'EXDATE:20120529T100000,20120403T100000,20120410T100000,'
            u'20120501T100000,20120417T100000')

        e4 = IEventAccessor(impfolder.e4)
        self.assertEqual(e4.start, utc.localize(datetime(2013, 4, 4, 0, 0)))
        self.assertEqual(e4.end, utc.localize(datetime(2013, 4, 4, 23, 59,
                                                       59)))
        self.assertEqual(e4.whole_day, True)
        self.assertEqual(e4.open_end, False)

        e5 = IEventAccessor(impfolder.e5)
        self.assertEqual(e5.start, utc.localize(datetime(2013, 4, 2, 12, 0)))
        self.assertEqual(e5.end, utc.localize(datetime(2013, 4, 2, 23, 59,
                                                       59)))
        self.assertEqual(e5.whole_day, False)
        self.assertEqual(e5.open_end, True)
Esempio n. 11
0
    def updateObject(self, context, v):

        # Get the accessor object
        acc = IEventAccessor(context)

        # Establish the input arguments
        kwargs = self.getRequestDataAsArguments(v)

        # Pass the arguments into the object
        acc.edit(**kwargs)

        # Update any arguments that are not part of the default event schema
        acc.update(**kwargs)

        # Update complex fields (text, event agenda)
        self.updateComplexFields(acc.context, v)

        # Reindex the object
        acc.context.reindexObject()

        # Ref: http://docs.plone.org/external/plone.app.event/docs/development.html#accessing-event-objects-via-an-unified-accessor-object
        # Throw ObjectModifiedEvent after setting properties to call an event subscriber which does some timezone related post calculations
        notify(ObjectModifiedEvent(acc.context))

        # Return object that was updated
        return acc.context
Esempio n. 12
0
    def test_event_accessor(self):
        utc = pytz.utc
        self.portal.invokeFactory('Event', 'event1',
                description='a description',
                start=datetime(2011,11,11,11,0, tzinfo=utc),
                end=datetime(2011,11,11,12,0, tzinfo=utc),
                timezone='UTC',
                wholeDay=False)
        e1 = self.portal['event1']

        # setting attributes via the accessor
        acc = IEventAccessor(e1)
        acc.end = datetime(2011,11,13,10,0, tzinfo=utc)
        acc.timezone = 'Europe/Vienna'

        vienna = pytz.timezone('Europe/Vienna')

        # test description
        self.assertTrue(acc.description == 'a description')
        acc.description = 'another desc'
        self.assertTrue(acc.description == 'another desc')

        # accessor should return end datetime in the event's timezone
        self.assertTrue(acc.end == datetime(2011,11,13,11,0, tzinfo=vienna))

        # start/end dates are stored in UTC zone on the context, but converted
        # to event's timezone via the attribute getter.
        self.assertTrue(e1.end() ==
                DateTime('2011/11/13 11:00:00 Europe/Vienna'))

        # timezone should be the same on the event object and accessor
        self.assertTrue(e1.getTimezone() == acc.timezone)

        self.portal.manage_delObjects(['event1'])
Esempio n. 13
0
 def create(
     cls,
     container,
     content_id,
     title,
     description=None,
     start=None,
     end=None,
     timezone=None,
     whole_day=None,
     open_end=None,
     **kwargs
 ):
     container.invokeFactory(
         cls.event_type,
         id=content_id,
         title=title,
         description=description,
         startDate=start,
         endDate=end,
         wholeDay=whole_day,
         open_end=open_end,
         timezone=timezone,
     )
     content = container[content_id]
     acc = IEventAccessor(content)
     acc.edit(**kwargs)
     return acc
Esempio n. 14
0
    def test_data_postprocessing(self):
        # Addressing bug #62
        self.portal.invokeFactory(
            'plone.app.event.dx.event',
            'event1',
            start=datetime(2012, 10, 19, 0, 30),
            end=datetime(2012, 10, 19, 1, 30),
            timezone="Europe/Vienna",
            whole_day=False
        )
        e1 = self.portal['event1']
        e1.reindexObject()

        # Prepare reference objects
        tzname_1 = "Europe/Vienna"
        tz_1 = pytz.timezone(tzname_1)
        dt_1 = tz_1.localize(datetime(2012, 10, 19, 0, 30))
        dt_1_1 = tz_1.localize(datetime(2012, 10, 19, 0, 0))
        dt_1_2 = tz_1.localize(datetime(2012, 10, 19, 23, 59, 59))

        tzname_2 = "Hongkong"
        tz_2 = pytz.timezone(tzname_2)
        dt_2 = tz_2.localize(datetime(2012, 10, 19, 0, 30))
        dt_2_1 = tz_2.localize(datetime(2012, 10, 19, 0, 0))
        dt_2_2 = tz_2.localize(datetime(2012, 10, 19, 23, 59, 59))

        # See, if start isn't moved by timezone offset. Addressing issue #62
        self.assertTrue(IEventBasic(e1).start == dt_1)
        notify(ObjectModifiedEvent(e1))
        self.assertTrue(IEventBasic(e1).start == dt_1)

        # After timezone changes, only the timezone should be applied, but the
        # date and time values not converted.
        IEventAccessor(e1).timezone = tzname_2
        notify(ObjectModifiedEvent(e1))
        self.assertTrue(IEventBasic(e1).start == dt_2)

        # Test open_end events
        # For open_end events, setting the end date has no effect
        IEventAccessor(e1).edit(
            timezone=tzname_1,
            open_end=True,
            end=datetime(2012, 11, 11, 10, 10, 0),
        )
        notify(ObjectModifiedEvent(e1))
        self.assertTrue(IEventBasic(e1).start == dt_1)
        self.assertTrue(IEventBasic(e1).end == dt_1_2)

        # Likewise with whole_day events. If values were converted, the days
        # would drift apart.
        IEventAccessor(e1).whole_day = True
        notify(ObjectModifiedEvent(e1))
        self.assertTrue(IEventBasic(e1).start == dt_1_1)
        self.assertTrue(IEventBasic(e1).end == dt_1_2)

        IEventAccessor(e1).timezone = tzname_2
        notify(ObjectModifiedEvent(e1))
        self.assertTrue(IEventBasic(e1).start == dt_2_1)
        self.assertTrue(IEventBasic(e1).end == dt_2_2)
Esempio n. 15
0
 def set_allDay(self, v):
     v = bool(v)
     if HAS_PAE:
         if IEvent.providedBy(self.context):
             acc = IEventAccessor(self.context)
             acc.whole_day = v
             return
     self._all_day = v
Esempio n. 16
0
 def set_allDay(self, v):
     v = bool(v)
     if HAS_PAE:
         if IEvent.providedBy(self.context):
             acc = IEventAccessor(self.context)
             acc.whole_day = v
             return
     self._all_day = v
Esempio n. 17
0
 def test_occurrence_accessor(self):
     start = self.now
     end = self.future
     occ = Occurrence('ignored', start, end)
     occ = occ.__of__(self.now_event)
     acc_occ = IEventAccessor(occ)
     acc_ctx = IEventAccessor(self.now_event)
     self.assertEqual(acc_occ.start, acc_ctx.start)
     self.assertEqual(acc_occ.url, 'http://nohost/plone/now/ignored')
Esempio n. 18
0
def onEventsFolderCreate(context, event, sample=True):

    # restrict what this folder can contain
    behavior = ISelectableConstrainTypes(context)
    behavior.setConstrainTypesMode(constrains.ENABLED)
    behavior.setImmediatelyAddableTypes(['Event'])
    behavior.setLocallyAllowedTypes(['Event', 'Collection'])

    # Create sample event and set publishing date to 01-01-YYYY
    if sample:

        # Calculate dates
        now = DateTime()
        start_date = DateTime() + 30
        end_date = start_date + 1.0 / 24

        item = createContentInContainer(context,
                                        "Event",
                                        id="sample",
                                        title="Sample Event",
                                        description="This is a sample Event",
                                        checkConstraints=False)

        item.text = RichTextValue(raw='<p>You may delete this item</p>',
                                  mimeType=u'text/html',
                                  outputMimeType='text/x-html-safe')

        item.setEffectiveDate(now)

        acc = IEventAccessor(item)
        acc.start = localize(start_date)
        acc.end = localize(end_date)

    # create 'upcoming' collection
    if 'upcoming' not in context.objectIds():
        item = createContentInContainer(
            context,
            "Collection",
            id="upcoming",
            title='Upcoming Events',
        )

        item.setQuery([{
            u'i': u'path',
            u'o': u'plone.app.querystring.operation.string.absolutePath',
            u'v': u'%s::1' % context.UID()
        }, {
            u'i': u'portal_type',
            u'o': u'plone.app.querystring.operation.selection.any',
            u'v': [u'Event']
        }])

        item.setSort_on('start')

    # Set default page to the latest news collection
    context.setDefaultPage('upcoming')
Esempio n. 19
0
    def test_data_postprocessing(self):
        # TODO: since we use an IEventAccessor here, this is a possible
        # canditate for merging with
        # the test_dxevent.TestDXIntegration.test_data_postprocessing test.

        # Addressing bug #62
        self.portal.invokeFactory('Event', 'ate1',
                startDate=DateTime(2012,10,19,0,30),
                endDate=DateTime(2012,10,19,1,30),
                timezone="Europe/Vienna",
                wholeDay=False)
        e1 = self.portal['ate1']
        e1.reindexObject()

        acc = IEventAccessor(e1)

        # Prepare reference objects
        tzname_1 = "Europe/Vienna"
        tz_1 = pytz.timezone(tzname_1)
        dt_1 = tz_1.localize(datetime(2012,10,19,0,30))
        dt_1_1 = tz_1.localize(datetime(2012,10,19,0,0))
        dt_1_2 = tz_1.localize(datetime(2012,10,19,23,59,59))

        tzname_2 = "Hongkong"
        tz_2 = pytz.timezone(tzname_2)
        dt_2 = tz_2.localize(datetime(2012,10,19,0,30))
        dt_2_1 = tz_2.localize(datetime(2012,10,19,0,0))
        dt_2_2 = tz_2.localize(datetime(2012,10,19,23,59,59))

        # See, if start isn't moved by timezone offset.
        self.assertTrue(acc.start == dt_1)
        notify(ObjectModifiedEvent(e1))
        self.assertTrue(acc.start == dt_1)

        # After timezone changes, only the timezone should be applied, but the
        # date and time values not converted.
        acc.timezone = tzname_2
        notify(ObjectModifiedEvent(e1))
        self.assertTrue(acc.start == dt_2)

        # Likewise with wholeDay events. If values were converted, the days
        # would drift apart.
        acc.whole_day = True
        acc.timezone = tzname_1
        notify(ObjectModifiedEvent(e1))
        self.assertTrue(acc.start == dt_1_1)
        self.assertTrue(acc.end == dt_1_2)

        acc.timezone = tzname_2
        notify(ObjectModifiedEvent(e1))
        self.assertTrue(acc.start == dt_2_1)
        self.assertTrue(acc.end == dt_2_2)

        self.portal.manage_delObjects(['ate1'])
Esempio n. 20
0
    def setUp(self):
        self.request = self.layer['request']
        portal = self.layer['portal']
        setRoles(portal, TEST_USER_ID, ['Manager'])

        portal.invokeFactory('Folder',
                id='events', title=u"Events",
                Description=u"The portal's Events")

        portal.events.invokeFactory('Event',
            id='ploneconf2007', title='Plone Conf 2007',
            startDate='2007/10/10', endDate='2007/10/12',
            location='Naples',
            eventUrl='http://plone.org/events/conferences/2007-naples',
            attendees=['anne','bob','cesar'])

        portal.events.invokeFactory('Event',
            id='ploneconf2008', title='Plone Conf 2008',
            startDate='2008/10/08', endDate='2008/10/10', location='DC',
            recurrence=u'RRULE:FREQ=DAILY;COUNT=5\r\nEXDATE:20081011T000000,20081012T000000\r\nRDATE:20081007T000000',
            eventUrl='http://plone.org/events/conferences/2008-washington-dc')

        portal.events.invokeFactory('plone.app.event.dx.event',
            id='ploneconf2012', title='Plone Conf 2012',
            recurrence=u'RRULE:FREQ=DAILY;COUNT=5\r\nEXDATE:20121013T000000,20121014T000000\r\nRDATE:20121009T000000',
            start=datetime(2012,10,10,8,0),
            end=datetime(2012,10,10,18,0),
            timezone='Europe/Amsterdam')
        pc12 = IEventAccessor(portal.events.ploneconf2012)
        pc12.location='Arnhem'
        pc12.contact_name='Four Digits'
        pc12.contact_email='*****@*****.**'
        notify(ObjectModifiedEvent(pc12))

        portal.events.invokeFactory('plone.app.event.dx.event',
            id='artsprint2013', title='Artsprint 2013',
            start=datetime(2013,2,18),
            end=datetime(2012,2,22),
            whole_day=True,
            timezone='Europe/Vienna')

        portal.invokeFactory("Collection",
                             "collection",
                             title="New Collection",
                             sort_on='start')
        portal['collection'].setQuery([{
            'i': 'Type',
            'o': 'plone.app.querystring.operation.string.is',
            'v': 'Event',
        }, ])

        self.portal = portal
def setup_event(site):
    """Set the default start and end event properties."""
    folder = site['institucional']['eventos']
    event = folder['1o-ano-do-site']
    acc = IEventAccessor(event)
    future = datetime.now() + relativedelta(years=1)
    year = future.year
    month = future.month
    day = future.day
    acc.start = datetime(year, month, day, 0, 0, 0)
    acc.end = datetime(year, month, day, 23, 59, 59)
    notify(ObjectModifiedEvent(event))
    event.reindexObject()
    logger.debug(u'Evento padrao configurado')
Esempio n. 22
0
    def validate_dates(self, performance, performance_data):
        startDateTime = performance_data.get('startDateTime', '')
        endDateTime = performance_data.get('endDateTime', '')

        if startDateTime and not endDateTime:
            performance_date_fields = IEventAccessor(performance)
            performance_date_fields.end = performance_date_fields.start
            return True

        if not startDateTime and not endDateTime:
            logger("[Error] There are no dates for the performance. ",
                   "Performance dates cannot be found.")
            return False

        return True
Esempio n. 23
0
def get_location(accessor):
    """Return the location.
    This method can be overwritten by external packages, for example to provide
    a reference to a Location object as done by collective.venue.

    :param accessor: Event, Occurrence or IEventAccessor object.
    :type accessor: IEvent, IOccurrence or IEventAccessor

    :returns: A location string. Possibly a HTML structure to link to another
              object, representing the location.
    :rtype: string
    """
    if not IEventAccessor.providedBy(accessor):
        accessor = IEventAccessor(accessor)
    return accessor.location
Esempio n. 24
0
    def test_pact_1_0_dxevent_is_migrated(self):
        def getNewEventDetail(obj):
            acc = IEventAccessor(obj)
            return [
                obj.id, [acc.start.year, acc.start.month, acc.start.day],
                [acc.end.year, acc.end.month, acc.end.day], acc.location,
                acc.attendees
            ]

        # Create some 1.0 Event objects
        create1_0EventType(self.portal)
        self.portal.invokeFactory('Folder', 'event-folder')
        self.createOldEvent(
            self.portal,
            'eventa',
            start_date=datetime(2012, 1, 1, 15, 20),
            end_date=datetime(2015, 9, 2, 16, 20),
        )
        self.createOldEvent(
            self.portal['event-folder'],
            'eventb',
            start_date=datetime(2013, 3, 3, 15, 20),
            end_date=datetime(2019, 5, 6, 16, 20),
        )

        # IEventAccessor? What's that?
        with self.assertRaisesRegexp(TypeError, 'IEventAccessor'):
            IEventAccessor(self.portal['eventa'])

        # Run upgrade step
        self.doUpgradeStep('1001', '1100')
Esempio n. 25
0
    def valuesTable(self):
        acc = IEventAccessor(self.context)
        if acc.start:
            horaInici = acc.start.strftime('%d/%m/%Y %H:%M')
            year = acc.start.strftime('%Y') + '/'
        else:
            horaInici = ''
            year = ''
        if acc.end:
            horaFi = acc.end.strftime('%d/%m/%Y %H:%M')
        else:
            horaFi = ''
        if self.context.llocConvocatoria is None:
            llocConvocatoria = ''
        else:
            llocConvocatoria = self.context.llocConvocatoria

        session = self.context.numSessio
        organ = self.context.aq_parent.acronim
        sessionNumber = str(organ) + '/' + str(year) + str(session)

        value = api.content.get_state(obj=self.context)
        lang = self.context.language
        status = translate(msgid=value, domain='genweb', target_language=lang)

        values = dict(
            horaInici=horaInici,
            horaFi=horaFi,
            llocConvocatoria=llocConvocatoria,
            organTitle=self.OrganTitle(),
            sessionNumber=sessionNumber,
            status=status,
        )
        return values
Esempio n. 26
0
    def test_event_summary_occurrences_next_upcoming(self):
        event = IEventAccessor(self.portal['daily'])

        date = patched_now()
        with mock.patch('plone.app.event.dx.behaviors.localized_now',
                        return_value=date):
            view = zope.component.getMultiAdapter(
                (self.portal['daily'], self.request), name='event_summary')
            # altogether 4 occurrences, start occurrence is included
            self.assertEqual(4, len(view.next_occurrences))
            self.assertEqual(event.start, date)
            self.assertEqual(event.end, date + datetime.timedelta(hours=1))

        IAnnotations(self.request).clear()  # clear cache
        next_date = patched_now() + datetime.timedelta(hours=24)
        with mock.patch('plone.app.event.dx.behaviors.localized_now',
                        return_value=next_date):
            view = zope.component.getMultiAdapter(
                (self.portal['daily'], self.request), name='event_summary')
            # 3 occurrences remaining
            self.assertEqual(3, len(view.next_occurrences))
            self.assertEqual(event.start, next_date)
            next_end_date = next_date + datetime.timedelta(hours=1)
            self.assertEqual(event.end, next_end_date)

        IAnnotations(self.request).clear()  # clear cache
        next_date = patched_now() + datetime.timedelta(days=10)
        with mock.patch('plone.app.event.dx.behaviors.localized_now',
                        return_value=next_date):
            view = zope.component.getMultiAdapter(
                (self.portal['daily'], self.request), name='event_summary')
            # no occurrences remaining, show all original 4
            self.assertEqual(4, len(view.next_occurrences))
            self.assertEqual(event.start, date)
            self.assertEqual(event.end, date + datetime.timedelta(hours=1))
Esempio n. 27
0
def get_location(context):
    """Return the location.
    This method can be used to be overwritten by external packages, for example
    to provide a reference to a Location object as done by collective.venue.
    """
    data = IEventAccessor(context)
    return data.location
Esempio n. 28
0
    def test_event_accessor_whole_day__open_end(self):

        at = pytz.timezone("Europe/Vienna")

        start = at.localize(datetime(2012, 10, 19, 0, 30))
        end = at.localize(datetime(2012, 10, 19, 1, 30))

        start_start = at.localize(datetime(2012, 10, 19, 0, 0, 0))
        end_end = at.localize(datetime(2012, 10, 19, 23, 59, 59))

        e1 = createContentInContainer(self.portal,
                                      'plone.app.event.dx.event',
                                      title='event1',
                                      start=start,
                                      end=end)
        acc = IEventAccessor(e1)

        # check set
        self.assertEqual(e1.start, start)
        self.assertEqual(e1.end, end)

        # Setting open end
        e1.open_end = True
        self.assertEqual(e1.start, start)
        self.assertEqual(e1.end, end)
        self.assertEqual(acc.start, start)
        self.assertEqual(acc.end, end_end)

        # Setting whole day
        e1.whole_day = True
        self.assertEqual(e1.start, start)
        self.assertEqual(e1.end, end)
        self.assertEqual(acc.start, start_start)
        self.assertEqual(acc.end, end_end)
Esempio n. 29
0
 def create(cls, container, content_id, title, description=None,
            start=None, end=None, timezone=None, whole_day=None,
            open_end=None, **kwargs):
     container.invokeFactory(cls.event_type,
                             id=content_id,
                             title=title,
                             description=description,
                             startDate=start,
                             endDate=end,
                             wholeDay=whole_day,
                             open_end=open_end,
                             timezone=timezone)
     content = container[content_id]
     acc = IEventAccessor(content)
     acc.edit(**kwargs)
     return acc
Esempio n. 30
0
 def getNewEventDetail(obj):
     acc = IEventAccessor(obj)
     return [
         obj.id, [acc.start.year, acc.start.month, acc.start.day],
         [acc.end.year, acc.end.month, acc.end.day], acc.location,
         acc.attendees
     ]
Esempio n. 31
0
def construct_calendar(events, start=None, end=None):
    """Return a dictionary with dates in a given timeframe as keys and the
    actual occurrences for that date for building calendars.
    Long lasting events will occur on every day until their end.

    :param events: List of IEvent and/or IOccurrence objects, to construct a
                   calendar data structure from.
    :type events: list

    :param start: An optional start range date.
    :type start: Python datetime or date

    :param end: An optional start range date.
    :type end: Python datetime or date

    :returns: Dictionary with isoformat date strings as keys and event
              occurrences as values.
    :rtype: dict

    """
    if start:
        if is_datetime(start):
            start = start.date()
        assert is_date(start)
    if end:
        if is_datetime(end):
            end = end.date()
        assert is_date(end)

    cal = {}

    def _add_to_cal(cal_data, event, date):
        date_str = date.isoformat()
        if date_str not in cal_data:
            cal_data[date_str] = [event]
        else:
            cal_data[date_str].append(event)
        return cal_data

    for event in events:
        acc = IEventAccessor(event)
        start_date = acc.start.date()
        end_date = acc.end.date()

        # day span between start and end + 1 for the initial date
        range_days = (end_date - start_date).days + 1
        for add_day in range(range_days):
            next_start_date = start_date + timedelta(add_day)  # initial = 0

            # avoid long loops
            if start and end_date < start:
                break  # if the date is completly outside the range
            if start and next_start_date < start:
                continue  # if start_date is outside but end reaches into range
            if end and next_start_date > end:
                break  # if date is outside range

            _add_to_cal(cal, event, next_start_date)
    return cal
Esempio n. 32
0
 def _get_context(self, name):
     # TODO: save parent context on self, so it must not be called every
     #       time
     oa = self._own_attr
     if name in oa:
         return self.context
     else:
         return IEventAccessor(aq_parent(self.context))
Esempio n. 33
0
 def __init__(self, context, request):
     self.context = context
     self.request = request
     self.data = IEventAccessor(context)
     self.max_occurrences = 6
     self.excludes = [
         'title',
     ]
Esempio n. 34
0
    def test_import_from_ics__sync_drop_older(self):
        """SYNC_KEEP_NEWER and importing the same file again should update only
        newer and on equal modified date but drop the change when it is older.
        """
        self.portal.invokeFactory('Folder', 'impfolder4')
        impfolder = self.portal.impfolder4

        directory = os.path.dirname(__file__)
        with open(os.path.join(directory, 'icaltest.ics'), 'rb') as icsfile:
            icsdata1 = icsfile.read()

        with open(os.path.join(directory, 'icaltest2.ics'), 'rb') as icsfile:
            icsdata2 = icsfile.read()

        res = ical_import(impfolder, icsdata1, self.event_type)
        self.assertEqual(res['count'], 5)

        e1a = IEventAccessor(impfolder.e1)
        mod1 = e1a.last_modified
        suid1 = e1a.sync_uid
        title1 = e1a.title
        desc1 = e1a.description
        start1 = e1a.start
        end1 = e1a.end

        res = ical_import(impfolder,
                          icsdata2,
                          self.event_type,
                          sync_strategy=base.SYNC_KEEP_NEWER)
        self.assertEqual(res['count'], 4)
        e1a = IEventAccessor(impfolder.e1)
        mod2 = e1a.last_modified
        suid2 = e1a.sync_uid
        title2 = e1a.title
        desc2 = e1a.description
        start2 = e1a.start
        end2 = e1a.end

        self.assertEqual(len(impfolder.contentIds()), 5)

        self.assertTrue(mod1 < mod2)
        self.assertEqual(suid1, suid2)
        self.assertNotEqual(title1, title2)
        self.assertNotEqual(desc1, desc2)
        self.assertTrue(start1 < start2)
        self.assertTrue(end1 < end2)
    def migrate_schema_fields(self):
        oldacc = IEventAccessor(self.old)
        newacc = IEventAccessor(self.new)
        newacc.start = oldacc.start
        newacc.end = oldacc.end
        newacc.timezone = oldacc.timezone
        newacc.location = oldacc.location
        newacc.attendees = oldacc.attendees
        newacc.event_url = oldacc.event_url
        newacc.contact_name = oldacc.contact_name
        newacc.contact_email = oldacc.contact_email
        newacc.contact_phone = oldacc.contact_phone
        # Copy the entire richtext object, not just it's representation
        IEventSummary(self.new).text = IEventSummary(self.old).text

        # Trigger ObjectModified, so timezones can be fixed up.
        notify(ObjectModifiedEvent(self.new))
Esempio n. 36
0
 def _allDay(self):
     if HAS_PAE:
         if IEvent.providedBy(self.context):
             acc = IEventAccessor(self.context)
             return acc.whole_day or False
     if self._all_day is not None:
         return bool(self._all_day)
     return False
Esempio n. 37
0
def construct_icalendar(context, events):
    """Returns an icalendar.Calendar object.

    :param context: A content object, which is used for calendar details like
                    Title and Description. Usually a container, collection or
                    the event itself.

    :param events: The list of event objects, which are included in this
                   calendar.
    """
    cal = icalendar.Calendar()
    cal.add('prodid', PRODID)
    cal.add('version', VERSION)

    cal_tz = default_timezone(context)
    if cal_tz:
        cal.add('x-wr-timezone', cal_tz)

    tzmap = {}
    if not hasattr(events, '__getslice__'):  # LazyMap doesn't have __iter__
        events = [events]
    for event in events:
        if ICatalogBrain.providedBy(event) or\
                IContentListingObject.providedBy(event):
            event = event.getObject()
        acc = IEventAccessor(event)
        tz = acc.timezone
        # TODO: the standard wants each recurrence to have a valid timezone
        # definition. sounds decent, but not realizable.
        if not acc.whole_day:  # whole day events are exported as dates without
            # timezone information
            tzmap = add_to_zones_map(tzmap, tz, acc.start)
            tzmap = add_to_zones_map(tzmap, tz, acc.end)
        cal.add_component(IICalendarEventComponent(event).to_ical())

    for (tzid, transitions) in tzmap.items():
        cal_tz = icalendar.Timezone()
        cal_tz.add('tzid', tzid)
        cal_tz.add('x-lic-location', tzid)

        for (transition, tzinfo) in transitions.items():

            if tzinfo['dst']:
                cal_tz_sub = icalendar.TimezoneDaylight()
            else:
                cal_tz_sub = icalendar.TimezoneStandard()

            cal_tz_sub.add('tzname', tzinfo['name'])
            cal_tz_sub.add('dtstart', transition)
            cal_tz_sub.add('tzoffsetfrom', tzinfo['tzoffsetfrom'])
            cal_tz_sub.add('tzoffsetto', tzinfo['tzoffsetto'])
            # TODO: add rrule
            # tzi.add('rrule',
            #         {'freq': 'yearly', 'bymonth': 10, 'byday': '-1su'})
            cal_tz.add_component(cal_tz_sub)
        cal.add_component(cal_tz)

    return cal
Esempio n. 38
0
    def test_get_occurrences(self):
        result = get_occurrences(self.portal,
                                 get_portal_events(self.portal))
        self.assertTrue(len(result) == 9)

        result = get_occurrences(self.portal,
                                 get_portal_events(self.portal), limit=5)
        self.assertTrue(len(result) == 5)
        self.assertTrue(IEventAccessor.providedBy(result[0]))
Esempio n. 39
0
def ticket_title_generator(obj):
    """Generate a title for the ticket, also using event information.
    """

    event = obj
    ret = {
        'title': obj.title,
        'eventtitle': '',
        'eventstart': '',
        'eventend': ''
    }

    if ITicketOccurrence.providedBy(event):
        event = aq_parent(aq_parent(event))
        # Traverse to the Occurrence object
        if IATEvent.providedBy(event):
            # get the request out of thin air to be able to publishTraverse to
            # the transient Occurrence object.
            traverser = OccTravAT(event, getRequest())
        elif IDXEvent.providedBy(event):
            # TODO
            traverser = OccTravDX(event, getRequest())
        else:
            raise NotImplementedError(
                u"There is no event occurrence traverser implementation for "
                u"this kind of object.")
        try:
            event = traverser.publishTraverse(getRequest(), obj.id)
        except KeyError:
            # Maybe the ticket occurrence isn't valid anymore because the
            # event occurence doesn't exist anymore.
            # Just ignore that case.
            return ret

    elif ITicket.providedBy(event):
        event = aq_parent(event)

    if IEvent.providedBy(event) or IOccurrence.providedBy(event):
        acc = IEventAccessor(event)
        lstart = ulocalized_time(DT(acc.start),
                                 long_format=True,
                                 context=event)
        lend = ulocalized_time(DT(acc.start), long_format=True, context=event)
        # XXX: no unicode, store as utf-8 encoded string instead
        ret = dict(
            title=u'%s - %s (%s - %s)' % (
                safe_unicode(acc.title),
                safe_unicode(obj.title),
                lstart,
                lend,
            ),
            eventtitle=acc.title,
            eventstart=acc.start,
            eventend=acc.end,
        )
    return ret
Esempio n. 40
0
 def publishTraverse(self, request, name):
     context = self.context
     dateobj = guess_date_from(name, context)
     if dateobj:
         occurrence = IRecurrenceSupport(context).occurrences(
             range_start=dateobj)[0]
         occ_acc = IEventAccessor(occurrence)
         if is_same_day(dateobj, occ_acc.start):
             return occurrence
     return self.fallbackTraverse(request, name)
Esempio n. 41
0
def _obj_or_acc(obj, ret_mode):
    """Return the content object or an IEventAccessor wrapper, depending on
    ret_mode. ret_mode 2 returns objects, ret_mode 3 returns IEventAccessor
    object wrapper. ret_mode 1 is not supported.
    """
    assert (ret_mode is not RET_MODE_BRAINS)
    if ret_mode == RET_MODE_OBJECTS:
        return obj
    elif ret_mode == RET_MODE_ACCESSORS:
        return IEventAccessor(obj)
Esempio n. 42
0
    def test_event_summary_occurrences_whole_day(self):
        self.portal['daily'].whole_day = True

        date = patched_now()
        with mock.patch('plone.app.event.dx.behaviors.localized_now',
                        return_value=date):
            view = zope.component.getMultiAdapter(
                (self.portal['daily'], self.request), name='event_summary')
            # altogether 4 occurrences, start occurrence is included
            self.assertEqual(4, len(view.next_occurrences))
            for occurrence in view.next_occurrences:
                event_occ = IEventAccessor(occurrence)
                self.assertEqual(event_occ.start.hour, 0)
                self.assertEqual(event_occ.end.hour, 23)
                self.assertEqual(event_occ.start.day, event_occ.end.day)

        IAnnotations(self.request).clear()  # clear cache
        next_date = patched_now() + datetime.timedelta(hours=24)
        with mock.patch('plone.app.event.dx.behaviors.localized_now',
                        return_value=next_date):
            view = zope.component.getMultiAdapter(
                (self.portal['daily'], self.request), name='event_summary')
            # 3 occurrences remaining
            self.assertEqual(3, len(view.next_occurrences))
            for occurrence in view.next_occurrences:
                event_occ = IEventAccessor(occurrence)
                self.assertEqual(event_occ.start.hour, 0)
                self.assertEqual(event_occ.end.hour, 23)
                self.assertEqual(event_occ.start.day, event_occ.end.day)

        IAnnotations(self.request).clear()  # clear cache
        next_date = patched_now() + datetime.timedelta(days=10)
        with mock.patch('plone.app.event.dx.behaviors.localized_now',
                        return_value=next_date):
            view = zope.component.getMultiAdapter(
                (self.portal['daily'], self.request), name='event_summary')
            # no occurrences remaining, show all original 4
            self.assertEqual(4, len(view.next_occurrences))
            for occurrence in view.next_occurrences:
                event_occ = IEventAccessor(occurrence)
                self.assertEqual(event_occ.start.hour, 0)
                self.assertEqual(event_occ.end.hour, 23)
                self.assertEqual(event_occ.start.day, event_occ.end.day)
Esempio n. 43
0
    def test_get_occurrences(self):
        res = get_events(self.portal, ret_mode=3, expand=True)
        self.assertTrue(len(res) == 9)

        res = get_events(self.portal, start=self.now, ret_mode=3, expand=True)
        self.assertTrue(len(res) == 9)

        res = get_events(self.portal, ret_mode=3, expand=True, limit=5)
        self.assertTrue(len(res) == 5)
        self.assertTrue(IEventAccessor.providedBy(res[0]))
Esempio n. 44
0
    def test_event_accessor(self):
        tz = pytz.timezone("Europe/Vienna")
        e1 = createContentInContainer(
            self.portal,
            'plone.app.event.dx.event',
            title=u'event1',
            start=tz.localize(datetime(2011, 11, 11, 11, 0)),
            end=tz.localize(datetime(2011, 11, 11, 12, 0)),
        )

        # setting attributes via the accessor
        acc = IEventAccessor(e1)
        new_end = tz.localize(datetime(2011, 11, 13, 10, 0))
        acc.end = new_end

        # context's end should be set to new_end
        self.assertEqual(e1.end, new_end)

        # accessor's and context datetime should be the same
        self.assertEqual(acc.end, e1.end)
Esempio n. 45
0
    def test_get_occurrences(self):
        res = get_events(self.portal, ret_mode=RET_MODE_ACCESSORS,
                         expand=True)
        self.assertEqual(len(res), 9)
        res = get_events(self.portal, start=self.now,
                         ret_mode=RET_MODE_ACCESSORS, expand=True)
        self.assertEqual(len(res), 8)

        res = get_events(self.portal, ret_mode=RET_MODE_ACCESSORS,
                         expand=True, limit=5)
        self.assertEqual(len(res), 5)
        self.assertTrue(IEventAccessor.providedBy(res[0]))
Esempio n. 46
0
    def test_get_occurrences(self):
        brains = get_portal_events(self.portal)

        result = get_occurrences_from_brains(self.portal, brains)
        self.assertTrue(len(result) == 9)

        result = get_occurrences_from_brains(self.portal, brains,
                range_start=self.now)
        self.assertTrue(len(result) == 9)

        result = get_occurrences_from_brains(self.portal, brains, limit=5)
        self.assertTrue(len(result) == 5)
        self.assertTrue(IEventAccessor.providedBy(result[0]))
Esempio n. 47
0
    def migrate_schema_fields(self):
        from plone.app.event.dx.behaviors import IEventSummary

        old_start = self.old.getField('startDate').get(self.old)
        old_end = self.old.getField('endDate').get(self.old)
        old_location = self.old.getField('location').get(self.old)
        old_attendees = self.old.getField('attendees').get(self.old)
        old_eventurl = self.old.getField('eventUrl').get(self.old)
        old_contactname = self.old.getField('contactName').get(self.old)
        old_contactemail = self.old.getField('contactEmail').get(self.old)
        old_contactphone = self.old.getField('contactPhone').get(self.old)
        old_text_field = self.old.getField('text')
        raw_text = safe_unicode(old_text_field.getRaw(self.old))
        mime_type = old_text_field.getContentType(self.old)
        if raw_text.strip() == '':
            raw_text = ''
        old_richtext = RichTextValue(raw=raw_text, mimeType=mime_type,
                                     outputMimeType='text/x-html-safe')
        if self.old.getField('timezone'):
            old_timezone = self.old.getField('timezone').get(self.old)
        else:
            old_timezone = default_timezone(fallback='UTC')

        acc = IEventAccessor(self.new)
        acc.start = old_start.asdatetime()  # IEventBasic
        acc.end = old_end.asdatetime()  # IEventBasic
        acc.timezone = old_timezone  # IEventBasic
        acc.location = old_location  # IEventLocation
        acc.attendees = old_attendees  # IEventAttendees
        acc.event_url = old_eventurl  # IEventContact
        acc.contact_name = old_contactname  # IEventContact
        acc.contact_email = old_contactemail  # IEventContact
        acc.contact_phone = old_contactphone  # IEventContact
        # Copy the entire richtext object, not just it's representation
        IEventSummary(self.new).text = old_richtext

        # Trigger ObjectModified, so timezones can be fixed up.
        notify(ObjectModifiedEvent(self.new))
Esempio n. 48
0
def get_location(accessor):
    """Return the location.
    This method can be overwritten by external packages, for example to provide
    a reference to a Location object as done by collective.venue.

    :param accessor: Event, Occurrence or IEventAccessor object.
    :type accessor: IEvent, IOccurrence or IEventAccessor

    :returns: A location string. Possibly a HTML structure to link to another
              object, representing the location.
    :rtype: string
    """
    if not IEventAccessor.providedBy(accessor):
        accessor = IEventAccessor(accessor)
    return accessor.location
    def test_pae_dxevent_is_migrated(self):
        from datetime import datetime
        from plone.app.contenttypes.migration.migration import migrate_events
        from plone.app.textfield.value import RichTextValue
        from plone.app.event.dx.behaviors import IEventSummary

        # Enable plone.app.event.dx
        from plone.app.testing import applyProfile
        applyProfile(self.portal, 'plone.app.event.dx:default')

        old_event = self.portal[self.portal.invokeFactory(
            'plone.app.event.dx.event',
            'dx-event',
            start=datetime(2011, 11, 11, 11, 0),
            end=datetime(2011, 11, 11, 12, 0),
            timezone="Asia/Tbilisi",
            whole_day=False,
        )]
        old_event_acc = IEventAccessor(old_event)
        old_event_acc.contact_name = 'George'
        old_event_acc.contact_email = '*****@*****.**'
        old_event_acc.contact_phone = '+99512345'
        old_event_acc.event_url = 'http://geor.ge/event'
        old_event_acc.text = RichTextValue(
            raw='Woo, yeah',
            mimeType='text/plain',
            outputMimeType='text/x-html-safe'
        )

        # migrate
        applyProfile(self.portal, 'plone.app.contenttypes:default')
        migrate_events(self.portal)

        # Compare new and old events
        new_event = self.portal['dx-event']
        new_event_acc = IEventAccessor(new_event)
        self.assertEqual(False, old_event.exclude_from_nav)
        self.assertEqual('Event', new_event.portal_type)
        self.assertEqual(2011, new_event_acc.start.year)
        self.assertEqual(11, new_event_acc.start.month)
        self.assertEqual(11, new_event_acc.start.day)
        self.assertEqual(11, new_event_acc.start.hour)
        self.assertEqual('Asia/Tbilisi', str(new_event_acc.start.tzinfo))
        self.assertEqual(2011, new_event_acc.end.year)
        self.assertEqual(11, new_event_acc.end.month)
        self.assertEqual(11, new_event_acc.end.day)
        self.assertEqual(12, new_event_acc.end.hour)
        self.assertEqual('Asia/Tbilisi', str(new_event_acc.end.tzinfo))
        self.assertEqual(u'Asia/Tbilisi', new_event_acc.timezone)
        self.assertEqual(u'George', new_event_acc.contact_name)
        self.assertEqual(u'*****@*****.**', new_event_acc.contact_email)
        self.assertEqual(u'+99512345', new_event_acc.contact_phone)
        self.assertEqual(u'http://geor.ge/event', new_event_acc.event_url)
        self.assertEqual(u'<p>Woo, yeah</p>', new_event_acc.text)
        self.assertEqual('Woo, yeah', IEventSummary(new_event).text.raw)
        self.assertEqual(False, new_event.exclude_from_nav)
Esempio n. 50
0
    def importContent(self):

        # Create new content importer object
        v = AtlasProductImporter(uid=self.uid, domain=self.domain)

        # Additional fields
        kwargs = {}

        # Add a Webinar Group
        webinar_group = self.addWebinarGroup(self.import_path, v, **kwargs)

        # Add the Webinar
        webinar = self.addWebinar(webinar_group, v,
                                  **kwargs)

        # Set the webinar start/end dates to publish date of imported object
        webinar_date_start = v.data.start
        webinar_date_start = DateTime(webinar_date_start).asdatetime()

        webinar_date_end = v.data.end
        webinar_date_end = DateTime(webinar_date_end).asdatetime()

        acc = IEventAccessor(webinar)
        acc.edit(start=webinar_date_start, end=webinar_date_end)
        acc.update(start=webinar_date_start, end=webinar_date_end)

        # Initialize webinar_url variable
        webinar_url = v.data.event_url

        # If we have a 'webinar_url', set that on the Webinar Product
        if webinar_url:
            acc.edit(webinar_url=webinar_url)
            acc.update(webinar_url=webinar_url)

        # Finalize items
        self.finalize(webinar)
        self.finalize(webinar_group)

        # Return JSON output
        return self.getJSON(webinar_group)
Esempio n. 51
0
def _last_migrate_time_zone(self):
    acc = IEventAccessor(self.new)
    acc.timezone = 'Europe/Berlin'
    notify(ObjectModifiedEvent(self.new))
Esempio n. 52
0
def ical_import(container, ics_resource, event_type,
                sync_strategy=base.SYNC_KEEP_NEWER):
    cal = icalendar.Calendar.from_ical(ics_resource)
    events = cal.walk('VEVENT')

    cat = getToolByName(container, 'portal_catalog')
    container_path = '/'.join(container.getPhysicalPath())

    def _get_by_sync_uid(uid):
        return cat(
            sync_uid=uid,
            path={'query': container_path, 'depth': 1}
        )

    def _get_prop(prop, item, default=None):
        ret = default
        if prop in item:
            ret = safe_unicode(item.decoded(prop))
        return ret

    def _from_list(ical, prop):
        """For EXDATE and RDATE recurrence component properties, the dates can
        be defined within one EXDATE/RDATE line or for each date an individual
        line.
        In the latter case, icalendar creates a list.
        This method handles this case.

        TODO: component property parameters like TZID are not used here.
        """
        val = prop in ical and ical[prop] or []
        if not isinstance(val, list):
            val = [val]
        #ret = ''
        #for item in val:
        #    ret = ret and '%s\n' % ret or ret  # insert linebreak
        #    ret = '%s%s:%s' % (ret, prop, item.to_ical())
        #return ret

        # Zip multiple lines into one, since jquery.recurrenceinput.js does
        # not support multiple lines here
        # https://github.com/collective/jquery.recurrenceinput.js/issues/15
        ret = ''
        for item in val:
            ret = ret and '%s,' % ret or ret  # insert linebreak
            ret = '%s%s' % (ret, item.to_ical())
        return ret and '%s:%s' % (prop, ret) or None

    count = 0
    for item in events:
        start = _get_prop('DTSTART', item)
        end = _get_prop('DTEND', item)
        if not end:
            duration = _get_prop('DURATION', item)
            if duration:
                end = start + duration
            # else: whole day or open end

        timezone = getattr(getattr(start, 'tzinfo', None), 'zone', None) or\
            base.default_timezone(container)

        whole_day = False
        open_end = False
        if is_date(start) and (is_date(end) or end is None):
            # All day / whole day events
            # End must be same type as start (RFC5545, 3.8.2.2)
            whole_day = True
            if end is None:
                end = start
            if start < end:
                # RFC5545 doesn't define clearly, if all day events should have
                # a end date one day after the start day at 0:00.
                # Internally, we handle all day events with start=0:00,
                # end=:23:59:59, so we substract one day here.
                end = end - datetime.timedelta(days=1)
            start = base.dt_start_of_day(date_to_datetime(start))
            end = base.dt_end_of_day(date_to_datetime(end))
        elif is_datetime(start) and end is None:
            # Open end event, see RFC 5545, 3.6.1
            open_end = True
            end = base.dt_end_of_day(date_to_datetime(start))
        assert(is_datetime(start))
        assert(is_datetime(end))

        title = _get_prop('SUMMARY', item)
        description = _get_prop('DESCRIPTION', item)
        location = _get_prop('LOCATION', item)

        url = _get_prop('URL', item)

        rrule = _get_prop('RRULE', item)
        rrule = rrule and 'RRULE:%s' % rrule.to_ical() or ''
        rdates = _from_list(item, 'RDATE')
        exdates = _from_list(item, 'EXDATE')
        rrule = '\n'.join([it for it in [rrule, rdates, exdates] if it])

        # TODO: attendee-lists are not decoded properly and contain only
        # vCalAddress values
        attendees = item.get('ATTENDEE', ())

        contact = _get_prop('CONTACT', item)
        categories = item.get('CATEGORIES', ())
        if hasattr(categories, '__iter__'):
            categories = [safe_unicode(it) for it in categories]

        ext_modified = utc(_get_prop('LAST-MODIFIED', item))

        # TODO: better use plone.api for content creation, from which some of
        # the code here is copied

        content = None
        new_content_id = None
        existing_event = None
        sync_uid = _get_prop('UID', item)
        if sync_strategy != base.SYNC_NONE and sync_uid:
            existing_event = _get_by_sync_uid(sync_uid)
        if existing_event:
            if sync_strategy == base.SYNC_KEEP_MINE:
                # On conflict, keep mine
                continue

            exist_event = existing_event[0].getObject()
            acc = IEventAccessor(exist_event)

            if sync_strategy == base.SYNC_KEEP_NEWER and\
                    (not ext_modified or acc.last_modified >= ext_modified):
                # Update only, if newer, if ext_modified exists
                continue

            # Else: update
            content = exist_event
        else:
            # TODO: if AT had the same attrs like IDXEventBase, we could set
            # everything within this invokeFactory call.
            new_content_id = str(random.randint(0, 99999999))
            container.invokeFactory(event_type,
                                    id=new_content_id,
                                    title=title,
                                    description=description)
            content = container[new_content_id]

        assert(content)  # At this point, a content must be available.

        event = IEventAccessor(content)
        event.title = title
        event.description = description
        event.start = start
        event.end = end
        event.timezone = timezone
        event.whole_day = whole_day
        event.open_end = open_end
        event.location = location
        event.event_url = url
        event.recurrence = rrule
        event.attendees = attendees
        event.contact_name = contact
        event.subjects = categories
        if sync_strategy != base.SYNC_NONE:
            # Don't import the sync_uid, if no sync strategy is chosen. Let the
            # sync_uid be autogenerated then.
            event.sync_uid = sync_uid
        notify(ObjectModifiedEvent(content))

        # Archetypes specific code
        if getattr(content, 'processForm', False):
            # Will finish Archetypes content item creation process,
            # rename-after-creation and such
            content.processForm()

        # Use commits instead of savepoints to avoid "FileStorageError:
        # description too long" on large imports.
        transaction.get().commit()  # Commit before rename

        if new_content_id and new_content_id in container:
            # Rename with new id from title, if processForm didn't do it.
            chooser = INameChooser(container)
            new_id = chooser.chooseName(title, content)
            content.aq_parent.manage_renameObject(new_content_id, new_id)

        # Do this at the end, otherwise it's overwritten
        if ext_modified:
            event.last_modified = ext_modified

        count += 1

    return {'count': count}
Esempio n. 53
0
 def load_loc(self):
     context = self.context
     loc = IEventAccessor(context).location
     if loc:
         self.request['loc'] = loc.strip()
         self.has_loc = True
Esempio n. 54
0
    def test_event_accessor(self):
        utc = pytz.utc
        vienna = pytz.timezone('Europe/Vienna')

        self.portal.invokeFactory('Event', 'event1',
                description='a description',
                startDate=datetime(2011, 11, 11, 11, 0, tzinfo=utc),
                endDate=datetime(2011, 11, 11, 12, 0, tzinfo=utc),
                timezone='UTC',
                wholeDay=False)
        e1 = self.portal['event1']
        acc = IEventAccessor(e1)

        # TEST DATES
        self.assertEqual(acc.start, datetime(2011, 11, 11, 11, 0, tzinfo=utc))
        self.assertEqual(acc.end, datetime(2011, 11, 11, 12, 0, tzinfo=utc))

        acc.start = datetime(2011, 11, 13, 9, 0)  # tzinfo does not matter,
        acc.end = datetime(2011, 11, 13, 10, 0)  # it's set by subscription
                                                # adapter

        # If using EventAccessor's edit method, calling notify isn't needed
        acc.edit(timezone=u'Europe/Vienna')

        # accessor should return start/end datetimes in the event's timezone
        self.assertEqual(
            acc.start,
            datetime(2011, 11, 13, 9, 0, tzinfo=vienna))
        self.assertEqual(
            acc.end,
            datetime(2011, 11, 13, 10, 0, tzinfo=vienna))

        # start/end dates are stored in UTC zone on the context, but converted
        # to event's timezone via the attribute getter.
        self.assertEqual(
            e1.end(),
            DateTime('2011/11/13 10:00:00 Europe/Vienna')
        )

        # timezone should be the same on the event object and accessor
        self.assertEqual(e1.getTimezone(), acc.timezone)

        # Open End Test
        acc.edit(open_end=True)
        self.assertEqual(
            acc.start,
            datetime(2011, 11, 13, 9, 0, tzinfo=vienna))
        self.assertEqual(
            acc.end,
            datetime(2011, 11, 13, 23, 59, 59, tzinfo=vienna))

        # Whole Day Test
        acc.edit(whole_day=True, open_end=False)
        self.assertEqual(
            acc.start,
            datetime(2011, 11, 13, 0, 0, tzinfo=vienna))
        self.assertEqual(
            acc.end,
            datetime(2011, 11, 13, 23, 59, 59, tzinfo=vienna))

        # TEST DESCRIPTION
        self.assertTrue(acc.description == 'a description')
        acc.description = 'another desc'
        self.assertTrue(acc.description == 'another desc')

        # TEST OTHER PROPERTIES
        acc.title = u"An Event"
        acc.recurrence = u'RRULE:FREQ=DAILY;COUNT=5'
        acc.location = u"Home"
        acc.attendees = [u'me', u'you']
        acc.contact_name = u"Max Mustermann"
        acc.contact_email = u"*****@*****.**"
        acc.contact_phone = u"+1234567890"
        acc.event_url = u"http://plone.org/"
        acc.subjects = [u"tag1", u"tag2"]
        acc.text = u"body text with <b>html</b> formating."

        # If not using EventAccessor's edit method, call notify manually
        notify(ObjectModifiedEvent(acc.context))

        self.assertEqual(acc.recurrence, u'RRULE:FREQ=DAILY;COUNT=5')
        self.assertEqual(acc.location, u'Home')
        self.assertEqual(acc.attendees, (u'me', u'you'))
        self.assertEqual(acc.contact_name, u"Max Mustermann")
        self.assertEqual(acc.contact_email, u'*****@*****.**')
        self.assertEqual(acc.contact_phone, u"+1234567890")
        self.assertEqual(acc.event_url, u"http://plone.org/")
        self.assertEqual(acc.subjects, (u"tag1", u"tag2"))
        self.assertEqual(acc.text, u"body text with <b>html</b> formating.")

        # CLEANUP
        self.portal.manage_delObjects(['event1'])
Esempio n. 55
0
def dates_for_display(occurrence):
    """ Return a dictionary containing pre-calculated information for building
    <start>-<end> date strings.

    Keys are:
        'start_date' - date string of the start date
        'start_time' - time string of the start date
        'end_date'   - date string of the end date
        'end_time'   - time string of the end date
        'start_iso'  - start date in iso format
        'end_iso'    - end date in iso format
        'same_day'   - event ends on the same day
        'same_time'  - event ends at same time
        'whole_day'  - whole day events
        'open_end'   - events without end time

    :param occurrence: Event or occurrence object.
    :type occurrence: IEvent, IOccurrence or IEventAccessor based object.
    :returns: Dictionary with date strings.
    :rtype: dict


    The behavior os ulocalized_time() with time_only is odd.
    Setting time_only=False should return the date part only and *not*
    the time

    NOTE: these tests are not run, but serve as documentation.
    TODO: remove.
    >>> from DateTime import DateTime
    >>> start = DateTime(2010,3,16,14,40)
    >>> from zope.component.hooks import getSite
    >>> site = getSite()
    >>> ulocalized_time(start, False,  time_only=True, context=site)
    u'14:40'
    >>> ulocalized_time(start, False,  time_only=False, context=site)
    u'14:40'
    >>> ulocalized_time(start, False,  time_only=None, context=site)
    u'16.03.2010'

    """
    if IEventAccessor.providedBy(occurrence):
        acc = occurrence
        occurrence = occurrence.context
    else:
        acc = IEventAccessor(occurrence)

    # this needs to separate date and time as ulocalized_time does
    DT_start = DT(acc.start)
    DT_end = DT(acc.end)
    start_date = ulocalized_time(
        DT_start, long_format=False, time_only=None, context=occurrence
    )
    start_time = ulocalized_time(
        DT_start, long_format=False, time_only=True, context=occurrence
    )
    end_date = ulocalized_time(
        DT_end, long_format=False, time_only=None, context=occurrence
    )
    end_time = ulocalized_time(
        DT_end, long_format=False, time_only=True, context=occurrence
    )

    same_day = is_same_day(acc.start, acc.end)
    same_time = is_same_time(acc.start, acc.end)

    # set time fields to None for whole day events
    if acc.whole_day:
        start_time = end_time = None
    if acc.open_end:
        end_time = None

    start_iso = acc.whole_day and acc.start.date().isoformat()\
        or acc.start.isoformat()
    end_iso = acc.whole_day and acc.end.date().isoformat()\
        or acc.end.isoformat()

    return dict(
        # Start
        start_date=start_date,
        start_time=start_time,
        start_iso=start_iso,

        # End
        end_date=end_date,
        end_time=end_time,
        end_iso=end_iso,

        # Meta
        same_day=same_day,
        same_time=same_time,
        whole_day=acc.whole_day,
        open_end=acc.open_end,
    )
Esempio n. 56
0
    def test_get_events(self):

        # whole range
        res = get_events(self.portal)
        self.assertEqual(len(res), 4)

        res = get_events(self.portal,
                         start=self.past,
                         end=self.future)
        self.assertEqual(len(res), 4)

        res = get_events(self.portal,
                         end=self.future)
        self.assertEqual(len(res), 4)

        res = get_events(self.portal,
                         start=self.past)
        self.assertEqual(len(res), 4)

        # Limit
        res = get_events(self.portal, limit=2)
        self.assertEqual(len(res), 2)

        # Return objects
        res = get_events(self.portal, ret_mode=RET_MODE_OBJECTS)
        self.assertTrue(IEvent.providedBy(res[0]))

        # Return IEventAccessor
        res = get_events(self.portal, ret_mode=RET_MODE_ACCESSORS)
        self.assertTrue(IEventAccessor.providedBy(res[0]))
        # Test sorting
        self.assertTrue(res[0].start < res[-1].start)

        # Test reversed sorting
        res = get_events(self.portal, ret_mode=RET_MODE_ACCESSORS,
                         sort_reverse=True)
        self.assertTrue(res[0].start > res[-1].start)

        # Test sort_on
        res = get_events(self.portal, ret_mode=RET_MODE_ACCESSORS,
                         sort="start")
        self.assertEqual(
            [it.title for it in res][2:],
            [u'Now Event', u'Future Event']
        )
        res = get_events(self.portal, ret_mode=RET_MODE_ACCESSORS, sort="end")
        self.assertEqual(
            [it.title for it in res],
            [u'Past Event', u'Now Event', u'Future Event', u'Long Event']
        )

        # Test expansion
        res = get_events(self.portal, ret_mode=RET_MODE_OBJECTS, expand=True)
        self.assertEqual(len(res), 8)

        res = get_events(self.portal, ret_mode=RET_MODE_ACCESSORS, expand=True)
        self.assertEqual(len(res), 8)
        # Test sorting
        self.assertTrue(res[0].start < res[-1].start)

        res = get_events(self.portal, ret_mode=RET_MODE_ACCESSORS,
                         expand=True, sort_reverse=True)
        # Test sorting
        self.assertTrue(res[0].start > res[-1].start)

        # only on now-date
        res = get_events(self.portal,
                         start=self.now,
                         end=self.now)
        self.assertEqual(len(res), 2)

        # only on now-date as date
        # NOTE: converting self.now to python datetime to allow testing also
        # with dates as Zope DateTime objects.
        res = get_events(self.portal,
                         start=pydt(self.now).date(),
                         end=pydt(self.now).date())
        self.assertEqual(len(res), 2)

        # only on past date
        res = get_events(self.portal,
                         start=self.past,
                         end=self.past)
        self.assertEqual(len(res), 2)

        # one recurrence occurrence in far future
        res = get_events(self.portal,
                         start=self.far,
                         end=self.far)
        self.assertEqual(len(res), 1)

        # from now on
        res = get_events(self.portal,
                         start=self.now)
        self.assertEqual(len(res), 3)

        # until now
        res = get_events(self.portal,
                         end=self.now)
        self.assertEqual(len(res), 3)

        # in subfolder
        path = '/'.join(self.portal.sub.getPhysicalPath())
        res = get_events(self.portal, path=path)
        self.assertEqual(len(res), 1)
Esempio n. 57
0
def ical_import(container, ics_resource, event_type):
    cal = icalendar.Calendar.from_ical(ics_resource)
    events = cal.walk('VEVENT')

    def _get_prop(prop, item):
        ret = None
        if prop in item:
            ret = safe_unicode(item.decoded(prop))
        return ret

    def _from_list(ical, prop):
        """For EXDATE and RDATE recurrence component properties, the dates can
        be defined within one EXDATE/RDATE line or for each date an individual
        line.
        In the latter case, icalendar creates a list.
        This method handles this case.

        TODO: component property parameters like TZID are not used here.
        """
        val = prop in ical and ical[prop] or []
        if not isinstance(val, list):
            val = [val]
        #ret = ''
        #for item in val:
        #    ret = ret and '%s\n' % ret or ret  # insert linebreak
        #    ret = '%s%s:%s' % (ret, prop, item.to_ical())
        #return ret

        # Zip multiple lines into one, since jquery.recurrenceinput.js does
        # not support multiple lines here
        # https://github.com/collective/jquery.recurrenceinput.js/issues/15
        ret = ''
        for item in val:
            ret = ret and '%s,' % ret or ret  # insert linebreak
            ret = '%s%s' % (ret, item.to_ical())
        return ret and '%s:%s' % (prop, ret) or None

    count = 0
    for item in events:
        start = _get_prop('DTSTART', item)
        end = _get_prop('DTEND', item)
        if not end:
            duration = _get_prop('DURATION', item)
            if duration:
                end = start + duration
            # else: whole day or open end

        timezone = getattr(getattr(start, 'tzinfo', None), 'zone', None) or\
            base.default_timezone(container)

        whole_day = False
        open_end = False
        if is_date(start) and (is_date(end) or end is None):
            # All day / whole day events
            # End must be same type as start (RFC5545, 3.8.2.2)
            whole_day = True
            if end is None:
                end = start
            if start < end:
                # RFC5545 doesn't define clearly, if all day events should have
                # a end date one day after the start day at 0:00.
                # Internally, we handle all day events with start=0:00,
                # end=:23:59:59, so we substract one day here.
                end = end - datetime.timedelta(days=1)
            start = base.dt_start_of_day(date_to_datetime(start))
            end = base.dt_end_of_day(date_to_datetime(end))
        elif is_datetime(start) and end is None:
            # Open end event, see RFC 5545, 3.6.1
            open_end = True
            end = base.dt_end_of_day(date_to_datetime(start))
        assert(is_datetime(start))
        assert(is_datetime(end))

        title = _get_prop('SUMMARY', item)
        description = _get_prop('DESCRIPTION', item)
        location = _get_prop('LOCATION', item)

        url = _get_prop('URL', item)

        rrule = _get_prop('RRULE', item)
        rrule = rrule and 'RRULE:%s' % rrule.to_ical() or ''
        rdates = _from_list(item, 'RDATE')
        exdates = _from_list(item, 'EXDATE')
        rrule = '\n'.join([it for it in [rrule, rdates, exdates] if it])

        # TODO: attendee-lists are not decoded properly and contain only
        # vCalAddress values
        attendees = _get_prop('ATTENDEE', item)

        contact = _get_prop('CONTACT', item)
        categories = _get_prop('CATEGORIES', item)
        if hasattr(categories, '__iter__'):
            categories = [safe_unicode(it) for it in categories]

        ## for sync
        #created = _get_prop('CREATED', item)
        #modified = _get_prop('LAST-MODIFIED', item)

        # TODO: better use plone.api, from which some of the code here is
        # copied
        content_id = str(random.randint(0, 99999999))

        # TODO: if AT had the same attrs like IDXEventBase, we could set
        # everything within this invokeFactory call.
        container.invokeFactory(event_type,
                                id=content_id,
                                title=title,
                                description=description)
        content = container[content_id]

        event = IEventAccessor(content)
        event.start = start
        event.end = end
        event.timezone = timezone
        event.whole_day = whole_day
        event.open_end = open_end
        event.location = location
        event.event_url = url
        event.recurrence = rrule
        event.attendees = attendees
        event.contact_name = contact
        event.subjects = categories
        notify(ObjectModifiedEvent(content))

        # Archetypes specific code
        if getattr(content, 'processForm', False):
            # Will finish Archetypes content item creation process,
            # rename-after-creation and such
            content.processForm()

        if content_id in container:
            # Rename with new id from title, if processForm didn't do it.
            chooser = INameChooser(container)
            new_id = chooser.chooseName(title, content)
            transaction.savepoint(optimistic=True)  # Commit before renaming
            content.aq_parent.manage_renameObject(content_id, new_id)
        else:
            transaction.savepoint(optimistic=True)

        count += 1

    return {'count': count}
Esempio n. 58
0
def ical_import(container, ics_resource, event_type):
    cal = icalendar.Calendar.from_ical(ics_resource)
    events = cal.walk('VEVENT')

    def _get_prop(prop, item):
        ret = None
        if prop in item:
            ret = safe_unicode(item.decoded(prop))
        return ret

    count = 0
    for item in events:
        start = _get_prop('DTSTART', item)
        end = _get_prop('DTEND', item)
        if not end:
            duration = _get_prop('DURATION', item)
            if duration:
                end = start + duration
            # else: whole day or open end

        timezone = getattr(getattr(start, 'tzinfo', None), 'zone', None) or\
                base.default_timezone(container)

        whole_day = False
        open_end = False
        if is_date(start) and (is_date(end) or end is None):
            # All day / whole day events
            # End must be same type as start (RFC5545, 3.8.2.2)
            whole_day = True
            if end is None: end = start
            if start < end:
                # RFC5545 doesn't define clearly, if all day events should have
                # a end date one day after the start day at 0:00.
                # Internally, we handle all day events with start=0:00,
                # end=:23:59:59, so we substract one day here.
                end = end - datetime.timedelta(days=1)
            start = base.dt_start_of_day(date_to_datetime(start))
            end = base.dt_end_of_day(date_to_datetime(end))
        elif is_datetime(start) and end is None:
            # Open end event, see RFC 5545, 3.6.1
            open_end = True
            end = base.dt_end_of_day(date_to_datetime(start))
        assert(is_datetime(start))
        assert(is_datetime(end))

        title = _get_prop('SUMMARY', item)
        description = _get_prop('DESCRIPTION', item)
        location = _get_prop('LOCATION', item)

        url = _get_prop('URL', item)

        rrule = _get_prop('RRULE', item)
        rrule = rrule and 'RRULE:%s' % rrule.to_ical() or ''
        rdate = _get_prop('RDATE', item)
        rrule = rdate and '%s\nRDATE:%s' % (rrule, rdate.to_ical()) or ''
        exdate = _get_prop('EXDATE', item)
        rrule = exdate and '%s\nEXDATE:%s' % (rrule, exdate.to_ical()) or ''

        attendees = _get_prop('ATTENDEE', item)
        contact = _get_prop('CONTACT', item)
        categories = _get_prop('CATEGORIES', item)
        if hasattr(categories, '__iter__'):
            categories = [safe_unicode(it) for it in categories]

        # for sync
        created = _get_prop('CREATED', item)
        modified = _get_prop('LAST-MODIFIED', item)

        # TODO: better use plone.api, from which some of the code here is
        # copied
        content_id = str(random.randint(0, 99999999))

        # TODO: if AT had the same attrs like IDXEventBase, we could set
        # everything within this invokeFactory call.
        container.invokeFactory(event_type,
                                id=content_id,
                                title=title,
                                description=description)
        content = container[content_id]

        event = IEventAccessor(content)
        event.start = start
        event.end = end
        event.timezone = timezone
        event.whole_day = whole_day
        event.open_end = open_end
        event.location = location
        event.event_url = url
        event.recurrence = rrule
        event.attendees = attendees
        event.contact_name = contact
        event.subjects = categories
        notify(ObjectModifiedEvent(content))

        # Archetypes specific code
        if getattr(content, 'processForm', False):
            # Will finish Archetypes content item creation process,
            # rename-after-creation and such
            content.processForm()

        if content_id in container:
            # Rename with new id from title, if processForm didn't do it.
            chooser = INameChooser(container)
            new_id = chooser.chooseName(title, content)
            transaction.savepoint(optimistic=True)  # Commit before renaming
            content.aq_parent.manage_renameObject(content_id, new_id)
        else:
            transaction.savepoint(optimistic=True)

        count += 1

    return {'count': count}