def marshall(self, instance, **kw): events = kw.get('events', None) if events is None: event_types = getattr(instance, 'event_types', ('ATEvent', 'Event')) events = instance.contentValues( filter={'portal_type':event_types}) events.sort() vevents = [marshall_event_to_vevent(event) for event in events] if not vevents: # There were no events. iCalendar spec (RFC 2445) requires # VCALENDAR to have at least one subcomponent. Let's create # a fake event. # NB Mozilla Calendar produces a 0-length file when publishing # empty calendars. Sadly it does not then accept them # (http://bugzilla.mozilla.org/show_bug.cgi?id=229266). dtstamp = datetime.utcnow().strftime("%Y%m%dT%H%M%SZ") event = VEvent() vevents.append(event) event.add('uid', "placeholder-%s" % dtstamp) event.add('summary', 'Empty calendar') dtstart = vDatetime.from_ical(dtstamp[:-1]) event.add('dtstart', dtstart) dtstamp = vDatetime.from_ical(dtstamp) event.add('dtstamp', dtstamp) vcal = wrap_into_vcalendar(*vevents, **{'title': instance.context.Title()}) return ('text/calendar', len(vcal), vcal)
def marshall(self, instance, **kw): events = kw.get('events', None) if events is None: event_types = getattr(instance, 'event_types', ('ATEvent', 'Event')) events = instance.contentValues( filter={'portal_type': event_types}) events.sort() vevents = [marshall_event_to_vevent(event) for event in events] if not vevents: # There were no events. iCalendar spec (RFC 2445) requires # VCALENDAR to have at least one subcomponent. Let's create # a fake event. # NB Mozilla Calendar produces a 0-length file when publishing # empty calendars. Sadly it does not then accept them # (http://bugzilla.mozilla.org/show_bug.cgi?id=229266). dtstamp = datetime.utcnow().strftime("%Y%m%dT%H%M%SZ") event = VEvent() vevents.append(event) event.add('uid', "placeholder-%s" % dtstamp) event.add('summary', 'Empty calendar') dtstart = vDatetime.from_ical(dtstamp[:-1]) event.add('dtstart', dtstart) dtstamp = vDatetime.from_ical(dtstamp) event.add('dtstamp', dtstamp) vcal = wrap_into_vcalendar(*vevents, **{'title': instance.context.Title()}) return ('text/calendar', len(vcal), vcal)
def marshall_event_to_vevent(instance): wf = getToolByName(instance, 'portal_workflow') dtstamp = utc_strftime(datetime.utcnow(), "%Y%m%dT%H%M%SZ") uid_hash = abs(hash(instance)) state = wf.getInfoFor(instance, 'review_state') status = re_status_mapping.get(state, 'TENTATIVE') event = VEvent() event.add('uid', generateUID(instance)) event.add('summary', instance.Title(), encode=False) event.add('description', instance.Description(), encode=False) if hasattr(aq_base(instance), 'getLocation'): location = instance.getLocation() if location: event.add('location', location, encode=False) if hasattr(aq_base(instance), 'Subject'): subject = instance.Subject() if subject: for category in subject: event.add('categories', category, encode=False) if hasattr(aq_base(instance), 'event_url'): url = instance.event_url if callable(url): # Ugh, it's callable in ATContentTypes. url = url() if url: event.add('url', url) event['url'].params['value'] = 'URI' if hasattr(aq_base(instance), 'getAttendees'): for att in instance.getAttendees(): name, email = parseaddr(att) if not name: name = att email = '' if email: email = 'mailto:%s' % email else: email = 'invalid:nomail' address = vCalAddress(email) address.params['cn'] = name event.add('attendee', address, encode=False) if (hasattr(aq_base(instance), 'duration') and instance.duration == date.resolution): # All day event. dtstart = vDate.from_ical(utc_strftime(instance.start_date, '%Y%m%d')) event.add('dtstart', dtstart) dtend = vDate.from_ical(utc_strftime(instance.end_date, '%Y%m%d')) event.add('dtend', dtend) else: # Normal event dtstart = vDatetime.from_ical( utc_strftime(instance.start_date, '%Y%m%dT%H%M%SZ')) event.add('dtstart', dtstart) dtend = vDatetime.from_ical( utc_strftime(instance.end_date, '%Y%m%dT%H%M%SZ')) event.add('dtend', dtend) dtstamp = vDatetime.from_ical(dtstamp) event.add('dtstamp', dtstamp) #event.add('status', status) return event
def import_feed(self, feed): from molly.apps.feeds.models import Item, vCard calendar = Calendar.from_string(urllib2.urlopen(feed.rss_url).read()) items = set() for component in calendar.walk(): if component.name == 'VEVENT': item, created = Item.objects.get_or_create(feed=feed, guid=str(component.get('UID'))) # Do not create the event if one the property is not correct, # first tries to parse DT as datetime then as date, if it still # fails, then ignore try: try: item.dt_start = vDatetime.from_ical(str( component.get('DTSTART'))) except ValueError, ve: item.dt_start = vDate.from_ical(str( component.get('DTSTART'))) if component.get('DTEND'): try: item.dt_end = vDatetime.from_ical(str( component.get('DTEND'))) except ValueError, ve: item.dt_end = vDate.from_ical(str( component.get('DTEND'))) item.title = vText.from_ical(str( component.get('SUMMARY')).strip()) if component.get('URL'): item.link = str(component.get('URL')) if component.get('DESCRIPTION'): item.description = sanitise_html(vText.from_ical(str( component.get('DESCRIPTION')))) if str(component.get('LOCATION')) != '': location, created = vCard.objects.get_or_create( name=vText.from_ical(str( component.get('LOCATION')).strip())) # in the future, we could imagine to (try to) geocode # the location to get a point field... location.save() item.venue = location try: item.last_modified = vDatetime.from_ical(str( component.get('LAST-MODIFIED'))) except Exception, e: item.last_modified = datetime.now() item.save() items.add(item)
def _upload_events(self, events): """ Upload all given events to caldav calendar and remove all other events in time period. :raise caldav.error.ReportError: Raised if list of existing events in time period could not be loaded. :raise caldav.error.DeleteError: Raised if removing of already existing event failed. :raise caldav.error.PutError: Raised if upload of an event failed. """ # Filter events which where already uploaded log.info('Fetch all existing events') events = list(events) old_event_ids = self.upload_calendar.retrieve_event(self.start_time, self.end_time) n = 0 for (new, old_id) in itertools.product(events, old_event_ids): if new['uid'] == old_id: events.remove(new) old_event_ids.remove(old_id) n += 1 if n > 0: log.info('{n} event(s) where already uploaded'.format(n=n)) # Remove only deprecated events n = len(old_event_ids) if n > 0: log.info('Delete {n} deprecated event(s) in given time period'.format(n=n)) else: log.info('No deprecated event(s) found in calendar') for i, uid in enumerate(old_event_ids): log.info('Delete event {index}/{num}'.format(index=i+1, num=n)) self.upload_calendar.delete_event(uid) # Upload all events n = len(events) if n > 0: log.info('Upload all new events') else: log.info('No new events found') for i, ev in enumerate(events): log.info('Upload event {index}/{num}'.format(index=i+1, num=n)) uid = ev['uid'] title = ev['summary'] start = vDatetime.from_ical(ev['dtstart'].to_ical(), 'Europe/Berlin') end = vDatetime.from_ical(ev['dtend'].to_ical(), 'Europe/Berlin') location = ev['location'] self.upload_calendar.add_event(uid, title, start, end, location) log.info('Uploaded all changes')
def test_prop_vDatetime(self): from ..prop import vDatetime dt = datetime(2001, 1, 1, 12, 30, 0) self.assertEqual(vDatetime(dt).to_ical(), b'20010101T123000') self.assertEqual(vDatetime.from_ical('20000101T120000'), datetime(2000, 1, 1, 12, 0)) dutc = pytz.utc.localize(datetime(2001, 1, 1, 12, 30, 0)) self.assertEqual(vDatetime(dutc).to_ical(), b'20010101T123000Z') dutc = pytz.utc.localize(datetime(1899, 1, 1, 12, 30, 0)) self.assertEqual(vDatetime(dutc).to_ical(), b'18990101T123000Z') self.assertEqual(vDatetime.from_ical('20010101T000000'), datetime(2001, 1, 1, 0, 0)) self.assertRaises(ValueError, vDatetime.from_ical, '20010101T000000A') utc = vDatetime.from_ical('20010101T000000Z') self.assertEqual(vDatetime(utc).to_ical(), b'20010101T000000Z') # 1 minute before transition to DST dat = vDatetime.from_ical('20120311T015959', 'America/Denver') self.assertEqual(dat.strftime('%Y%m%d%H%M%S %z'), '20120311015959 -0700') # After transition to DST dat = vDatetime.from_ical('20120311T030000', 'America/Denver') self.assertEqual(dat.strftime('%Y%m%d%H%M%S %z'), '20120311030000 -0600') dat = vDatetime.from_ical('20101010T000000', 'Europe/Vienna') self.assertEqual(vDatetime(dat).to_ical(), b'20101010T000000')
def match_indexes(self, indexes, tzify): vs = {} for name, value in indexes.items(): if name and name[2:] in self.all_props: if value and value[0]: if not isinstance(value[0], vDDDTypes): vs[name[2:]] = vDDDTypes(vDatetime.from_ical(value[0])) else: vs[name[2:]] = value[0] try: component_handler = self.component_handlers[self.comp] except KeyError: logging.warning('unknown component %r in time-range filter', self.comp) return False return component_handler(self.start, self.end, vs, tzify)
def _parse_ical_datetime(self, dt, tz_name): """Return a timezone-aware datetime from the iCalendar datetime format. Since this will always be from a Google Calendar event feed, and each calendar has a timezone associated with it, the datetime string will always be in the TZID=Timezone_Name:YYYYMMDDTHHMMSS format. If the datetime is invalid, this will return None. If no timezone is defined for the datetime string, the timezone whose name is specified in the tz_name string is used. Arguments: dt -- a string of the iCalendar datetime Returns: a timezone-aware datetime instance or None """ dt_parts = dt.split(':') _datetime = None # Apply timezone information to the time, either from its own specification or # from the passed timezone name if len(dt_parts) == 2: tzinfo = dt_parts[0].split('=')[1] timezone = pytz.timezone(tzinfo) _datetime = dt_parts[1] else: _datetime = dt_parts[0] if tz_name: timezone = pytz.timezone(tz_name) # Return the datetime with timezone information try: parsed_datetime = vDatetime.from_ical(_datetime) except ValueError: return None else: return timezone.localize(parsed_datetime)
def match_indexes(self, prop, tzify): return any( self.match(vDDDTypes(vDatetime.from_ical(p)), tzify) for p in prop[None])
def test_windows_timezone(self): """test that an example""" self.assertEqual( vDatetime.from_ical('20170507T181920', 'Eastern Standard Time'), pytz.timezone('America/New_York').localize(datetime(2017, 5, 7, 18, 19, 20)) )
def __conv_vDDD_to_datetime(vddd, tz=pytz.utc): return vDatetime.from_ical(vddd.to_ical()).astimezone(tz)
def marshall_event_to_vevent(instance): wf = getToolByName(instance, 'portal_workflow') dtstamp = utc_strftime(datetime.utcnow(), "%Y%m%dT%H%M%SZ") uid_hash = abs(hash(instance)) state = wf.getInfoFor(instance, 'review_state') status = re_status_mapping.get(state, 'TENTATIVE') event = VEvent() event.add('uid', generateUID(instance)) event.add('summary', instance.Title(), encode=False) event.add('description', instance.Description(), encode=False) if hasattr(aq_base(instance), 'getLocation'): location = instance.getLocation() if location: event.add('location', location, encode=False) if hasattr(aq_base(instance), 'Subject'): subject = instance.Subject() if subject: for category in subject: event.add('categories', category, encode=False) if hasattr(aq_base(instance), 'event_url'): url = instance.event_url if callable(url): # Ugh, it's callable in ATContentTypes. url = url() if url: event.add('url', url) event['url'].params['value'] = 'URI' if hasattr(aq_base(instance), 'getAttendees'): for att in instance.getAttendees(): name, email = parseaddr(att) if not name: name = att email = '' if email: email = 'mailto:%s' % email else: email = 'invalid:nomail' address = vCalAddress(email) address.params['cn'] = name event.add('attendee', address, encode=False) if (hasattr(aq_base(instance), 'duration') and instance.duration == date.resolution): # All day event. dtstart = vDate.from_ical( utc_strftime(instance.start_date, '%Y%m%d')) event.add('dtstart', dtstart) dtend = vDate.from_ical( utc_strftime(instance.end_date, '%Y%m%d')) event.add('dtend', dtend) else: # Normal event dtstart = vDatetime.from_ical( utc_strftime(instance.start_date, '%Y%m%dT%H%M%SZ')) event.add('dtstart', dtstart) dtend = vDatetime.from_ical( utc_strftime(instance.end_date, '%Y%m%dT%H%M%SZ')) event.add('dtend', dtend) dtstamp = vDatetime.from_ical(dtstamp) event.add('dtstamp', dtstamp) #event.add('status', status) return event
def test_date_vcal2google(self): self.assertEqual( date_vcal2google( vDatetime(vDatetime.from_ical('20140828T120150')), 120), '2014-08-28T12:01:50+02:00')