def __init__(self, per): start, end_or_duration = per if not (isinstance(start, datetime) or isinstance(start, date)): raise ValueError('Start value MUST be a datetime or date instance') if not (isinstance(end_or_duration, datetime) or isinstance(end_or_duration, date) or isinstance(end_or_duration, timedelta)): raise ValueError('end_or_duration MUST be a datetime, ' 'date or timedelta instance') by_duration = 0 if isinstance(end_or_duration, timedelta): by_duration = 1 duration = end_or_duration end = start + duration else: end = end_or_duration duration = end - start if start > end: raise ValueError("Start time is greater than end time") self.params = Parameters() # set the timezone identifier # does not support different timezones for start and end tzid = tzid_from_dt(start) if tzid: self.params['TZID'] = tzid self.start = start self.end = end self.by_duration = by_duration self.duration = duration
def parse_dates(self, item, component): """Extracts date information from ICS into the Event item :param item: The Event item :param component: An ICS VEVENT component """ # add dates # check if component .dt return date instead of datetime, if so, convert to datetime dtstart = component.get('dtstart').dt dates_start = dtstart if isinstance(dtstart, datetime.datetime) \ else datetime.datetime.combine(dtstart, datetime.datetime.min.time()) if not dates_start.tzinfo: dates_start = local_to_utc(config.DEFAULT_TIMEZONE, dates_start) try: dtend = component.get('dtend').dt if isinstance(dtend, datetime.datetime): dates_end = dtend else: # Date only is non inclusive dates_end = \ (datetime.datetime.combine(dtend, datetime.datetime.max.time()) - datetime.timedelta(days=1)).replace(microsecond=0) if not dates_end.tzinfo: dates_end = local_to_utc(config.DEFAULT_TIMEZONE, dates_end) except AttributeError: dates_end = None item['dates'] = {'start': dates_start, 'end': dates_end, 'tz': ''} # set timezone info if date is a datetime if isinstance(component.get('dtstart').dt, datetime.datetime): item['dates']['tz'] = tzid_from_dt(component.get('dtstart').dt)
def to_ical(self): dt = self.dt tzid = tzid_from_dt(dt) s = "%04d%02d%02dT%02d%02d%02d" % (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second) if tzid == 'UTC': s += "Z" elif tzid: self.params.update({'TZID': tzid}) return s.encode('utf-8')
def to_ical(self): dt = self.dt tzid = tzid_from_dt(dt) s = "%04d%02d%02dT%02d%02d%02d" % ( dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second ) if tzid == 'UTC': s += "Z" elif tzid: self.params.update({'TZID': tzid}) return s.encode('utf-8')
def __init__(self, dt): if not isinstance(dt, (datetime, date, timedelta, time)): raise ValueError('You must use datetime, date, timedelta or time') if isinstance(dt, datetime): self.params = Parameters(dict(value='DATE-TIME')) elif isinstance(dt, date): self.params = Parameters(dict(value='DATE')) elif isinstance(dt, time): self.params = Parameters(dict(value='TIME')) if (isinstance(dt, datetime) or isinstance(dt, time))\ and getattr(dt, 'tzinfo', False): tzinfo = dt.tzinfo if tzinfo is not pytz.utc and not isinstance(tzinfo, tzutc): # set the timezone as a parameter to the property tzid = tzid_from_dt(dt) if tzid: self.params.update({'TZID': tzid}) self.dt = dt
def __init__(self, dt): if not isinstance(dt, (datetime, date, timedelta, time, tuple)): raise ValueError('You must use datetime, date, timedelta, ' 'time or tuple (for periods)') if isinstance(dt, datetime): self.params = Parameters({'value': 'DATE-TIME'}) elif isinstance(dt, date): self.params = Parameters({'value': 'DATE'}) elif isinstance(dt, time): self.params = Parameters({'value': 'TIME'}) elif isinstance(dt, tuple): self.params = Parameters({'value': 'PERIOD'}) if (isinstance(dt, datetime) or isinstance(dt, time))\ and getattr(dt, 'tzinfo', False): tzinfo = dt.tzinfo if tzinfo is not pytz.utc and\ (tzutc is None or not isinstance(tzinfo, tzutc)): # set the timezone as a parameter to the property tzid = tzid_from_dt(dt) if tzid: self.params.update({'TZID': tzid}) self.dt = dt
def parse(self, cal, provider=None): try: items = [] for component in cal.walk(): if component.name == "VEVENT": item = { ITEM_TYPE: CONTENT_TYPE.TEXT, GUID_FIELD: generate_guid(type=GUID_NEWSML), FORMAT: FORMATS.PRESERVED } item['name'] = component.get('summary') item['definition_short'] = component.get('summary') item['definition_long'] = component.get('description') item['original_source'] = component.get('uid') # add dates # check if component .dt return date instead of datetime, if so, convert to datetime dtstart = component.get('dtstart').dt dates_start = dtstart if isinstance(dtstart, datetime.datetime) \ else datetime.datetime.combine(dtstart, datetime.datetime.min.time()) if not dates_start.tzinfo: dates_start = utc.localize(dates_start) try: dtend = component.get('dtend').dt dates_end = dtend if isinstance(dtend, datetime.datetime) \ else datetime.datetime.combine(dtend, datetime.datetime.min.time()) if not dates_end.tzinfo: dates_end = utc.localize(dates_end) except AttributeError as e: dates_end = None item['dates'] = { 'start': dates_start, 'end': dates_end, 'tz': '', 'recurring_rule': {} } # parse ics RRULE to fit eventsML recurring_rule r_rule = component.get('rrule') if isinstance(r_rule, vRecur): r_rule_dict = vRecur.from_ical(r_rule) if 'FREQ' in r_rule_dict.keys(): item['dates']['recurring_rule'][ 'frequency'] = ''.join(r_rule_dict.get('FREQ')) if 'INTERVAL' in r_rule_dict.keys(): item['dates']['recurring_rule'][ 'interval'] = r_rule_dict.get('INTERVAL')[0] if 'UNTIL' in r_rule_dict.keys(): item['dates']['recurring_rule'][ 'until'] = r_rule_dict.get('UNTIL')[0] if 'COUNT' in r_rule_dict.keys(): item['dates']['recurring_rule'][ 'count'] = r_rule_dict.get('COUNT') if 'BYMONTH' in r_rule_dict.keys(): item['dates']['recurring_rule'][ 'bymonth'] = ' '.join( r_rule_dict.get('BYMONTH')) if 'BYDAY' in r_rule_dict.keys(): item['dates']['recurring_rule'][ 'byday'] = ' '.join(r_rule_dict.get('BYDAY')) if 'BYHOUR' in r_rule_dict.keys(): item['dates']['recurring_rule'][ 'byhour'] = ' '.join(r_rule_dict.get('BYHOUR')) if 'BYMIN' in r_rule_dict.keys(): item['dates']['recurring_rule'][ 'bymin'] = ' '.join(r_rule_dict.get('BYMIN')) # set timezone info if date is a datetime if isinstance( component.get('dtstart').dt, datetime.datetime): item['dates']['tz'] = tzid_from_dt( component.get('dtstart').dt) # add participants item['participant'] = [] if component.get('attendee'): for attendee in component.get('attendee'): if isinstance(attendee, vCalAddress): item['participant'].append({ 'name': vCalAddress.from_ical(attendee), 'qcode': '' }) # add organizers item['organizer'] = [{ 'name': component.get('organizer', ''), 'qcode': '' }] # add location item['location'] = [{ 'name': component.get('location', ''), 'qcode': '', 'geo': '' }] if component.get('geo'): item['location'][0]['geo'] = vGeo.from_ical( component.get('geo').to_ical()) # IMPORTANT: firstcreated must be less than 2 days past # we must preserve the original event created and updated in some other fields if component.get('created'): item['event_created'] = component.get('created').dt if component.get('last-modified'): item['event_lastmodified'] = component.get( 'last-modified').dt item['firstcreated'] = utcnow() item['versioncreated'] = utcnow() items.append(item) original_source_ids = [ _['original_source'] for _ in items if _.get('original_source', None) ] existing_items = list( get_resource_service('events').get_from_mongo( req=None, lookup={'original_source': { '$in': original_source_ids }})) def original_source_exists(item): """Return true if the item exists in `existing_items`""" for c in existing_items: if c['original_source'] == item['original_source']: if c['dates']['start'] == item['dates']['start']: return True return False def is_future(item): """Return true if the item is reccuring or in the future""" if not item['dates'].get('recurring_rule'): if item['dates']['start'] < utcnow() - datetime.timedelta( days=1): return False return True items = [_ for _ in items if is_future(_)] items = [_ for _ in items if not original_source_exists(_)] return items except Exception as ex: raise ParserError.parseMessageError(ex, provider)