def test_occurrence(self): # start date of self.now_event = 2013-05-05, 10:00. # recurrence rule = 'RRULE:FREQ=DAILY;COUNT=3;INTERVAL=2' # Try to traverse to inexistent occurrence self.assertRaises( AttributeError, self.occ_traverser_1.publishTraverse, self.request, '2000-01-01') # Try to traverse to future occurrence self.assertRaises( AttributeError, self.occ_traverser_1.publishTraverse, self.request, '2030-01-01') # Traverse to existent occurrence item = self.occ_traverser_1.publishTraverse(self.request, '2013-05-07') self.assertTrue(IOccurrence.providedBy(item)) self.assertEqual(type(self.now_event), type(item.aq_parent)) # Test attributes of Occurrence self.assertEqual(item.portal_type, 'Occurrence') self.assertEqual(item.id, '2013-05-07') delta = datetime.timedelta(days=2) self.assertEqual(item.start, self.now + delta) self.assertEqual(item.end, self.now + delta + self.duration)
def __call__(self): if IOccurrence.providedBy(self.context): # The transient Occurrence objects cannot be edited. disable the # edit border for them. self.request.set('disable_border', True) self.update() return self.index()
def _get_generation_context(self, helper_view, pod_template): result = super(IDocumentGenerationView, self)._get_generation_context(helper_view, pod_template) # if pod_template.portal_type == 'ConfigurablePODTemplate': if IFacetedNavigable.providedBy(self.context): brains = getDashboardQueryResult(self.context) result['brains'] = brains if len(brains) > 0 and brains[0].portal_type == 'Event': expandevents = expand_events(brains, 2) events = [] for event in expandevents: if IOccurrence.providedBy(event): start = event.start end = event.end parent = zope.copy.copy(event.aq_parent.aq_base) parent.start = start parent.end = end req = event.REQUEST parent.REQUEST = req parent.occurrence = True parent.base_event = event.aq_parent events.append(parent) else: events.append(event) result['brains'] = events return result
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
def _get_generation_context(self, helper_view, pod_template): result = super(IDocumentGenerationView, self)._get_generation_context( helper_view, pod_template) # if pod_template.portal_type == 'ConfigurablePODTemplate': if IFacetedNavigable.providedBy(self.context): brains = getDashboardQueryResult(self.context) result['brains'] = brains if len(brains) > 0 and brains[0].portal_type == 'Event': expandevents = expand_events(brains, 2) events = [] for event in expandevents: if IOccurrence.providedBy(event): start = event.start end = event.end parent = zope.copy.copy(event.aq_parent.aq_base) parent.start = start parent.end = end req = event.REQUEST parent.REQUEST = req parent.occurrence = True parent.base_event = event.aq_parent events.append(parent) else: events.append(event) result['brains'] = events return result
def recurrence(self): if not self.event.recurrence or IOccurrence.providedBy(self.context): return None ret = [] for recdef in self.event.recurrence.split(): prop, val = recdef.split(':') if prop == 'RRULE': ret.append({ 'property': prop, 'value': icalendar.prop.vRecur.from_ical(val) }) elif prop in ('EXDATE', 'RDATE'): factory = icalendar.prop.vDDDLists # localize ex/rdate # TODO: should better already be localized by event object tzid = self.event.timezone if isinstance(tzid, tuple): tzid = tzid[0] # get list of datetime values from ical string try: dtlist = factory.from_ical(val, timezone=tzid) except ValueError: # TODO: caused by a bug in plone.formwidget.recurrence, # where the recurrencewidget or plone.event fails with # COUNT=1 and a extra RDATE. # TODO: REMOVE this workaround, once this failure is # fixed in recurrence widget. continue ret.append({'property': prop, 'value': dtlist}) return ret
def test_recurrence_occurrences_with_range_start_2(self): # Test with range rs = datetime.datetime(2011, 11, 16, 11, 0, tzinfo=self.tz) result = IRecurrenceSupport(self.data).occurrences(range_start=rs) self.assertEqual(3, len(result)) # Only IOccurrence objects in the result set self.assertTrue(IOccurrence.providedBy(result[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
def test_recurrence_occurrences(self): result = IRecurrenceSupport(self.data).occurrences() self.assertEqual(4, len(result)) # First occurrence is an IEvent object self.assertTrue(IEvent.providedBy(result[0])) # Subsequent ones are IOccurrence objects self.assertTrue(IOccurrence.providedBy(result[1]))
def test_occurrence(self): # start date of self.now_event = 2013-05-05, 10:00. # recurrence rule = 'RRULE:FREQ=DAILY;COUNT=3;INTERVAL=2' # Try to traverse to inexistent occurrence self.assertRaises(AttributeError, self.traverser.publishTraverse, self.request, '2000-01-01') # Traverse to existent occurrence item = self.traverser.publishTraverse(self.request, '2013-05-07') self.assertTrue(IOccurrence.providedBy(item)) self.assertEqual(type(self.now_event), type(item.aq_parent))
def test_recurrence_occurrences_with_range_start_1(self): # Test with range rs = datetime.datetime(2011, 11, 15, 11, 0, tzinfo=self.tz) result = IRecurrenceSupport(self.data).occurrences(range_start=rs) self.assertEqual(4, len(result)) # First occurrence is an IEvent object self.assertTrue(IEvent.providedBy(result[0])) # Subsequent ones are IOccurrence objects self.assertTrue(IOccurrence.providedBy(result[1]))
def childsiteForContext(self, item): """Returns the childsite UUID for a context object by looking up it's brain in the catalog. """ childsite = "" if IOccurrence and IOccurrence.providedBy(item): item = aq_parent(item) portal = plone.api.portal.get() cat = getToolByName(self.context, "portal_catalog") res = cat(UID=IUUID(item, None), path=portal.getPhysicalPath()) if res: childsite = res[0].childsite return childsite
def childsiteForContext(self, item): """Returns the childsite UUID for a context object by looking up it's brain in the catalog. """ childsite = '' if IOccurrence and IOccurrence.providedBy(item): item = aq_parent(item) portal = plone.api.portal.get() cat = getToolByName(self.context, 'portal_catalog') res = cat(UID=IUUID(item, None), path=portal.getPhysicalPath()) if res: childsite = res[0].childsite return childsite
def test_occurrence(self): # start date of self.now_event = 2013-05-05, 10:00. # recurrence rule = 'RRULE:FREQ=DAILY;COUNT=3;INTERVAL=2' # Try to traverse to inexistent occurrence self.assertRaises( AttributeError, self.traverser.publishTraverse, self.request, '2000-01-01') # Traverse to existent occurrence item = self.traverser.publishTraverse(self.request, '2013-05-07') self.assertTrue(IOccurrence.providedBy(item)) self.assertEqual(type(self.now_event), type(item.aq_parent))
def test_recurrence_occurrences_with_range_start_and_end(self): # Test with range rs = datetime.datetime(2011, 11, 11, 11, 0, tzinfo=self.tz) re = datetime.datetime(2011, 11, 12, 11, 0, tzinfo=self.tz) result = IRecurrenceSupport(self.data).occurrences(range_start=rs, range_end=re) result = list(result) # cast generator to list self.assertEqual(2, len(result)) # First occurrence is an IEvent object self.assertTrue(IEvent.providedBy(result[0])) # Subsequent ones are IOccurrence objects self.assertTrue(IOccurrence.providedBy(result[1]))
def test_occurrence(self): self.at.setRecurrence('RRULE:FREQ=WEEKLY;COUNT=10') # does not match occurrence date qdate = datetime.date.today() + datetime.timedelta(days=4) self.assertRaises( AttributeError, self.at_traverser.publishTraverse, self.layer['request'], str(qdate)) qdatedt = pydt(self.at.start() + 7) item = self.at_traverser.publishTraverse(self.layer['request'], str(qdatedt.date())) self.assertTrue(IOccurrence.providedBy(item)) self.assertTrue(IATEvent.providedBy(item.aq_parent))
def test_recurrence(self): tz = pytz.timezone('Europe/Vienna') duration = datetime.timedelta(days=4) data = MockEvent() data.start = datetime.datetime(2011, 11, 11, 11, 00, tzinfo=tz) data.end = data.start + duration data.recurrence = 'RRULE:FREQ=DAILY;COUNT=4' zope.interface.alsoProvides(data, IEvent, IEventRecurrence) result = IRecurrenceSupport(data).occurrences() self.assertEqual(4, len(result)) # First occurrence is an IEvent object self.assertTrue(IEvent.providedBy(result[0])) # Subsequent ones are IOccurrence objects self.assertTrue(IOccurrence.providedBy(result[1]))
def attachments(self): context = aq_inner(self.context) if IOccurrence.providedBy(context): # support for related images on event occurrences context = context.aq_parent atts = IRelatedMedia(context).related_attachments _target_blank = api.portal.get_registry_record( 'collective.behavior.relatedmedia.open_attachment_in_new_window') link_target = _target_blank and 'blank' or 'top' for att in atts: att_obj = att.to_object if att_obj: yield dict( url=att_obj.absolute_url(), title=att_obj.Title(), size="{:.1f} MB".format( att_obj.file.getSize() / 1024.0 / 1024.0), icon=att_obj.getIcon(), target=link_target, )
def test_recurrence(self): tz = pytz.timezone('Europe/Vienna') duration = timedelta(days=4) mock = MockEvent() mock.start = tz.localize(datetime(2011, 11, 11, 11, 0)) mock.end = mock.start + duration mock.recurrence = 'RRULE:FREQ=DAILY;COUNT=4' zope.interface.alsoProvides(mock, IEvent, IEventBasic, IEventRecurrence, IDXEvent, IDXEventRecurrence) result = IRecurrenceSupport(mock).occurrences() result = list(result) # cast generator to list self.assertEqual(4, len(result)) # First occurrence is an IEvent object self.assertTrue(IEvent.providedBy(result[0])) # Subsequent ones are IOccurrence objects self.assertTrue(IOccurrence.providedBy(result[1]))
def test_recurrence(self): tz = pytz.timezone('Europe/Vienna') duration = timedelta(days=4) mock = MockEvent() mock.start = tz.localize(datetime(2011, 11, 11, 11, 0)) mock.end = mock.start + duration mock.recurrence = 'RRULE:FREQ=DAILY;COUNT=4' zope.interface.alsoProvides( mock, IEvent, IEventBasic, IEventRecurrence, IDXEvent, IDXEventRecurrence) result = IRecurrenceSupport(mock).occurrences() result = list(result) # cast generator to list self.assertEqual(4, len(result)) # First occurrence is an IEvent object self.assertTrue(IEvent.providedBy(result[0])) # Subsequent ones are IOccurrence objects self.assertTrue(IOccurrence.providedBy(result[1]))
def test_occurrence(self): # start date of self.now_event = 2013-05-05, 10:00. # recurrence rule = 'RRULE:FREQ=DAILY;COUNT=3;INTERVAL=2' # Try to traverse to inexistent occurrence self.assertRaises( AttributeError, self.traverser.publishTraverse, self.request, '2000-01-01') # Traverse to existent occurrence item = self.traverser.publishTraverse(self.request, '2013-05-07') self.assertTrue(IOccurrence.providedBy(item)) self.assertEqual(type(self.now_event), type(item.aq_parent)) # Test attributes of Occurrence self.assertEqual(item.portal_type, 'Occurrence') self.assertEqual(item.id, '2013-05-07') delta = datetime.timedelta(days=2) self.assertEqual(item.start, self.now + delta) self.assertEqual(item.end, self.now + delta + self.duration)
def recurrence(self): if not self.event.recurrence or IOccurrence.providedBy(self.context): return None ret = [] for recdef in self.event.recurrence.split(): prop, val = recdef.split(':') if prop == 'RRULE': ret.append({ 'property': prop, 'value': icalendar.prop.vRecur.from_ical(val) }) elif prop in ('EXDATE', 'RDATE'): factory = icalendar.prop.vDDDLists # localize ex/rdate # TODO: should better already be localized by event object tzid = self.event.timezone if isinstance(tzid, tuple): tzid = tzid[0] # get list of datetime values from ical string try: dtlist = factory.from_ical(val, timezone=tzid) except ValueError: # TODO: caused by a bug in plone.formwidget.recurrence, # where the recurrencewidget or plone.event fails with # COUNT=1 and a extra RDATE. # TODO: REMOVE this workaround, once this failure is # fixed in recurrence widget. continue ret.append({ 'property': prop, 'value': dtlist }) return ret
def __call__(self): if IOccurrence.providedBy(self.context): # The transient Occurrence objects cannot be edited. disable the # edit border for them. self.request.set('disable_border', True) return self.index() # render me.
def is_occurrence(self): return IOccurrence.providedBy(self.context)
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 getattr(events, '__getitem__', False): events = [events] for event in events: if ICatalogBrain.providedBy(event) or\ IContentListingObject.providedBy(event): event = event.getObject() if not (IEvent.providedBy(event) or IOccurrence.providedBy(event)): # Must be an event. continue 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 if isinstance(tz, tuple): tz_start, tz_end = tz else: tz_start = tz_end = tz tzmap = add_to_zones_map(tzmap, tz_start, acc.start) tzmap = add_to_zones_map(tzmap, tz_end, 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
def images(self): context = aq_inner(self.context) if IOccurrence.providedBy(context): # support for related images on event occurrences context = context.aq_parent rm_behavior = IRelatedMedia(context) imgs = rm_behavior.related_images or [] tcap = rm_behavior.show_titles_as_caption first_img_scales = None further_images = [] gallery = [] if rm_behavior.include_leadimage and ILeadImage.providedBy(context): first_img_scales = context.restrictedTraverse('@@images') first_img_caption = ILeadImage(context).image_caption further_images = imgs elif len(imgs): first_img = imgs[0] first_img_obj = first_img.to_object if first_img_obj: first_img_scales = first_img_obj.restrictedTraverse( '@@images') first_img_caption = tcap and first_img_obj.Title() or u'' further_images = imgs[1:] if first_img_scales: scale = first_img_scales.scale( 'image', scale=rm_behavior.first_image_scale, direction=rm_behavior.first_image_scale_direction and 'down' or 'thumbnail') if scale: large_scale_url = first_img_scales.scale( 'image', scale='large').url gallery.append(dict( url=large_scale_url, tag=scale.tag( title=first_img_caption, alt=first_img_caption, ), caption=tcap and first_img_caption or u'', title=first_img_caption, )) for img in further_images: img_obj = img.to_object if img_obj: scales = img_obj.restrictedTraverse('@@images') scale = scales.scale( 'image', scale=rm_behavior.preview_scale, direction=rm_behavior.preview_scale_direction and 'down' or 'thumbnail') if scale: large_scale_url = scales.scale('image', scale='large').url gallery.append(dict( url=large_scale_url, tag=scale.tag(), caption=tcap and img_obj.Title() or u'', title=img_obj.Title(), )) return gallery
def dict_from_item(item): if hasPloneAppEvent and (IEvent.providedBy(item) or IOccurrence.providedBy(item)): # plone.app.event DX or AT Event is_occurrence = IOccurrence.providedBy(item) acc = IEventAccessor(item) return { "status": "ok", "id": "UID_%s" % (acc.uid), "title": acc.title, "description": acc.description, "start": acc.start.isoformat(), "end": acc.end.isoformat(), "url": acc.url, "editable": editable, "allDay": acc.whole_day, "className": "contextualContentMenuEnabled %s %s %s %s" % ( state and "state-%s" % str(state) or "", editable and "editable" or "", css and css or "", is_occurrence and "occurrence" or ""), "color": color} elif IATEvent.providedBy(item): # Products.ATContentTypes ATEvent allday = (item.end() - item.start()) > 1.0 adapted = interfaces.ISFBaseEventFields(item, None) if adapted: allday = adapted.allDay return { "status": "ok", "id": "UID_%s" % (item.UID()), "title": item.Title(), "description": item.Description(), "start": item.start().ISO8601(), "end": item.end().ISO8601(), "url": item.absolute_url(), "editable": editable, "allDay": allday, "className": "contextualContentMenuEnabled %s %s %s" % ( state and "state-%s" % str(state) or "", editable and "editable" or "", css and css or ""), "color": color} elif ICatalogBrain.providedBy(item): # Event catalog brain if type(item.end) != DateTime: brainend = DateTime(item.end) brainstart = DateTime(item.start) else: brainend = item.end brainstart = item.start allday = (brainend - brainstart) > 1.0 if getattr(item, 'SFAllDay', None) in [False, True]: allday = item.SFAllDay return { "status": "ok", "id": "UID_%s" % (item.UID), "title": item.Title, "description": item.Description, "start": brainstart.ISO8601(), "end": brainend.ISO8601(), "url": item.getURL(), "editable": editable, "allDay": allday, "className": "contextualContentMenuEnabled %s %s %s" % ( state and "state-%s" % str(state) or "", editable and "editable" or "", css and css or ""), "color": color} else: raise ValueError('item type not supported for: %s' % repr(item))
def dict_from_item(item): if hasPloneAppEvent and (IEvent.providedBy(item) or IOccurrence.providedBy(item)): is_occurrence = IOccurrence.providedBy(item) and True or False acc = IEventAccessor(item) return { "status": "ok", "id": "UID_%s" % (acc.uid), "title": acc.title, "description": acc.description, "start": acc.start.isoformat(), "end": acc.end.isoformat(), "url": acc.url, "editable": editable, "allDay": acc.whole_day, "className": "contextualContentMenuEnabled %s %s %s %s" % ( state and "state-%s" % str(state) or "", editable and "editable" or "", css and css or "", is_occurrence and "occurrence" or "", ), "color": color, } elif IATEvent.providedBy(item): allday = (item.end() - item.start()) > 1.0 adapted = interfaces.ISFBaseEventFields(item, None) if adapted: allday = adapted.allDay return [ { "status": "ok", "id": "UID_%s" % (item.UID()), "title": item.Title(), "description": item.Description(), "start": item.start().rfc822(), "end": item.end().rfc822(), "url": item.absolute_url(), "editable": editable, "allDay": allday, "className": "contextualContentMenuEnabled %s %s %s" % (state and "state-%s" % str(state) or "", editable and "editable" or "", css and css or ""), "color": color, } ] elif ICatalogBrain.providedBy(item): if type(item.end) != DateTime: brainend = DateTime(item.end) brainstart = DateTime(item.start) else: brainend = item.end brainstart = item.start allday = (brainend - brainstart) > 1.0 if getattr(item, "SFAllDay", None) in [False, True]: allday = item.SFAllDay return [ { "status": "ok", "id": "UID_%s" % (item.UID), "title": item.Title, "description": item.Description, "start": brainstart.rfc822(), "end": brainend.rfc822(), "url": item.getURL(), "editable": editable, "allDay": allday, "className": "contextualContentMenuEnabled %s %s %s" % (state and "state-%s" % str(state) or "", editable and "editable" or "", css and css or ""), "color": color, } ] else: raise ValueError("item type not supported for: %s" % repr(item))
def to_ical(self): ical = icalendar.Event() event = self.event # TODO: event.text # must be in utc ical.add('dtstamp', utc(datetime.now())) ical.add('created', utc(event.created)) ical.add('last-modified', utc(event.last_modified)) if event.sync_uid: # Re-Use existing icalendar event UID ical.add('uid', event.sync_uid) else: # Else, use plone.uuid ical.add('uid', event.uid) ical.add('url', event.url) ical.add('summary', event.title) if event.description: ical.add('description', event.description) if event.whole_day: ical.add('dtstart', event.start.date()) # RFC5545, 3.6.1 # For cases where a "VEVENT" calendar component # specifies a "DTSTART" property with a DATE value type but no # "DTEND" nor "DURATION" property, the event's duration is taken to # be one day. # # RFC5545 doesn't define clearly, if all-day events should have # a end date on the same date or one day after the start day at # 0:00. Most icalendar libraries use the latter method. # Internally, whole_day events end on the same day one second # before midnight. Using the RFC5545 preferred method for # plone.app.event seems not appropriate, since we would have to fix # the date to end a day before for displaying. # For exporting, we let whole_day events end on the next day at # midnight. # See: # http://stackoverflow.com/questions/1716237/single-day-all-day # -appointments-in-ics-files # http://icalevents.com/1778-all-day-events-adding-a-day-or-not/ # http://www.innerjoin.org/iCalendar/all-day-events.html ical.add('dtend', event.end.date() + timedelta(days=1)) elif event.open_end: # RFC5545, 3.6.1 # For cases where a "VEVENT" calendar component # specifies a "DTSTART" property with a DATE-TIME value type but no # "DTEND" property, the event ends on the same calendar date and # time of day specified by the "DTSTART" property. ical.add('dtstart', event.start) else: ical.add('dtstart', event.start) ical.add('dtend', event.end) if event.recurrence and not IOccurrence.providedBy(self.context): for recdef in event.recurrence.split(): prop, val = recdef.split(':') if prop == 'RRULE': ical.add(prop, icalendar.prop.vRecur.from_ical(val)) elif prop in ('EXDATE', 'RDATE'): factory = icalendar.prop.vDDDLists # localize ex/rdate # TODO: should better already be localized by event object tzid = event.timezone # get list of datetime values from ical string try: dtlist = factory.from_ical(val, timezone=tzid) except ValueError: # TODO: caused by a bug in plone.formwidget.recurrence, # where the recurrencewidget or plone.event fails with # COUNT=1 and a extra RDATE. # TODO: REMOVE this workaround, once this failure is # fixed in recurrence widget. continue ical.add(prop, dtlist) if event.location: ical.add('location', event.location) # TODO: revisit and implement attendee export according to RFC if event.attendees: for attendee in event.attendees: att = icalendar.prop.vCalAddress(attendee) att.params['cn'] = icalendar.prop.vText(attendee) att.params['ROLE'] = icalendar.prop.vText('REQ-PARTICIPANT') ical.add('attendee', att) cn = [] if event.contact_name: cn.append(event.contact_name) if event.contact_phone: cn.append(event.contact_phone) if event.contact_email: cn.append(event.contact_email) if event.event_url: cn.append(event.event_url) if cn: ical.add('contact', u', '.join(cn)) if event.subjects: for subject in event.subjects: ical.add('categories', subject) return ical
def _get_occs(self): date = guess_date_from(self.date) if date: start, end = start_end_from_mode('day', date, self.context) query = {} query['review_state'] = self.data.state search_base_path = self.search_base_path if search_base_path: query['path'] = {'query': search_base_path} list_events = [] events = get_events(self.context, start=start, end=end, sort='start', sort_reverse=False, ret_mode=RET_MODE_OBJECTS, expand=True, **query) today = datetime.datetime.today().date() for occ in events: if IOccurrence.providedBy(occ): occurrence_id = occ.id event = aq_parent(occ) occ_data = ITicketOccurrenceData(event) occs = occ_data.ticket_occurrences(occurrence_id) if occs: occurrence_ticket = occs[0] item_stock = get_item_stock(occurrence_ticket) if item_stock: stock = item_stock.available else: stock = 0 is_today = occ.start.date() == today new_event = { "start": occ.start, "uid": occurrence_ticket.UID(), "stock": stock, "is_today": is_today } list_events.append(new_event) elif IBuyableEvent.providedBy(occ): occ_data = ITicketOccurrenceData(occ) occs = occ_data.tickets if occs: occurrence_ticket = occs[0] item_stock = get_item_stock(occurrence_ticket) if item_stock: stock = item_stock.available else: stock = 0 is_today = occ.start.date() == today new_event = { "start": occ.start, "uid": occurrence_ticket.UID(), "stock": stock, "is_today": is_today } list_events.append(new_event) else: print 'NOT AVAILABLE' return list_events else: return []
def __init__(self, context, request): super(RelatedBaseView, self).__init__(context, request) if IOccurrence.providedBy(self.context): self.context = self.context.aq_parent
def __init__(self, context, request): super(Uploader, self).__init__(context, request) self.intids = getUtility(IIntIds) if IOccurrence.providedBy(context): # support for related images on event occurrences self.context = aq_inner(context).aq_parent
def dict_from_item(item): if hasPloneAppEvent and (IEvent.providedBy(item) or IOccurrence.providedBy(item)): # plone.app.event DX or AT Event is_occurrence = IOccurrence.providedBy(item) acc = IEventAccessor(item) return { "status": "ok", "id": "UID_%s" % (acc.uid), "title": acc.title, "description": acc.description, "start": acc.start.isoformat(), "end": acc.end.isoformat(), "url": acc.url, "editable": editable, "allDay": acc.whole_day, "className": "contextualContentMenuEnabled %s %s %s %s" % ( state and "state-%s" % str(state) or "", editable and "editable" or "", css and css or "", is_occurrence and "occurrence" or ""), "color": color} elif IATEvent.providedBy(item): # Products.ATContentTypes ATEvent allday = (item.end() - item.start()) > 1.0 adapted = interfaces.ISFBaseEventFields(item, None) if adapted: allday = adapted.allDay return { "status": "ok", "id": "UID_%s" % (item.UID()), "title": item.Title(), "description": item.Description(), "start": item.start().ISO8601(), "end": item.end().ISO8601(), "url": item.absolute_url(), "editable": editable, "allDay": allday, "className": "contextualContentMenuEnabled %s %s %s" % ( state and "state-%s" % str(state) or "", editable and "editable" or "", css and css or ""), "color": color} elif ICatalogBrain.providedBy(item): # Event catalog brain if type(item.end) != DateTime: brainend = DateTime(item.end) brainstart = DateTime(item.start) else: brainend = item.end brainstart = item.start allday = (brainend - brainstart) > 1.0 if getattr(item, 'SFAllDay', None) in [False, True]: allday = item.SFAllDay # Set Mexico City Time brainstart = DateTime(' '.join( (brainstart.Date(), brainstart.Time(), 'America/Mexico_City'))) brainend = DateTime(' '.join( (brainend.Date(), brainend.Time(), 'America/Mexico_City'))) return { "status": "ok", "id": "UID_%s" % (item.UID), "title": item.Title, "description": item.Description, "start": brainstart.ISO8601(), "end": brainend.ISO8601(), "url": item.getURL(), "editable": editable, "allDay": allday, "className": "contextualContentMenuEnabled %s %s %s" % ( state and "state-%s" % str(state) or "", editable and "editable" or "", css and css or ""), "color": color} else: raise ValueError('item type not supported for: %s' % repr(item))