Exemple #1
0
def ical_init():
	cal = Calendar()
	cal.add('prodid', '-//CSPay calendar//EN/')
	cal.add('version', '2.0')
	TZ = Timezone()
	TZ.add('tzid','Europe/Bucharest')
	
	TZS = StandardT()
	TZS.add('TZOFFSETFROM',timedelta(hours=3))
	TZS.add('TZOFFSETTO',timedelta(hours=2))
	TZS.add('TZNAME','EET')
	TZS.add('DTSTART',datetime(1997,10,26))
	TZS.add('rrule',vRecur.from_ical('FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU'))
	TZ.add_component(TZS)

	TZS = DaylightT()
	TZS.add('TZOFFSETFROM',timedelta(hours=2))
	TZS.add('TZOFFSETTO',timedelta(hours=3))
	TZS.add('TZNAME','EEST')
	TZS.add('DTSTART',datetime(1997,03,30))
	TZS.add('rrule',vRecur.from_ical('FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU'))
	TZ.add_component(TZS)
	
	cal.add_component(TZ)
	
	return cal
 def testMultipleRRules(self):
     props = Event()
     addProps(
         props,
         summary="Event",
         uid="1234",
         dtstart=dt.datetime(2016, 4, 5, 9),
         dtend=dt.datetime(2016, 4, 5, 13),
         dtstamp=dt.datetime(2016, 4, 5, 13),
         rrule=vRecur.from_ical("FREQ=WEEKLY;WKST=SU;BYDAY=MO,TU,WE,TH,FR"))
     props.add('rrule',
               vRecur.from_ical("FREQ=MONTHLY;WKST=SU;BYDAY=-1SA,-1SU"))
     with self.assertRaises(CalendarTypeError) as expected:
         self.factory.makeFromProps(props, None)
     self.assertEqual(str(expected.exception), "Multiple RRULEs")
 def testLunchTimes(self):
     tz = pytz.timezone("Pacific/Auckland")
     vev = SimpleVEvent()
     addProps(
         vev,
         summary="All lunch times",
         uid="999",
         dtstart=timezone.make_aware(dt.datetime(1996, 3, 1, 12), tz),
         dtend=timezone.make_aware(dt.datetime(1996, 3, 1, 13), tz),
         rrule=vRecur.from_ical("FREQ=WEEKLY;WKST=SU;BYDAY=MO,TU,WE,TH,FR"))
     span = TimeZoneSpan(vev)
     vev = SimpleVEvent()
     addProps(vev,
              summary="Saturday Brunch",
              uid="2000",
              dtstart=timezone.make_aware(dt.datetime(2019, 6, 4, 10), tz),
              dtend=timezone.make_aware(dt.datetime(2019, 6, 4, 11, 30),
                                        tz))
     span.add(vev)
     vtz = span.createVTimeZone(tz)
     self.assertEqual(vtz['TZID'], "Pacific/Auckland")
     export = vtz.to_ical()
     nzdt = b"\r\n".join([
         b"BEGIN:DAYLIGHT",
         b"DTSTART;VALUE=DATE-TIME:19951001T030000",
         b"RDATE:19961006T030000,19971005T030000,19981004T030000,19991003T030000,2000",
         b" 1001T030000,20011007T030000,20021006T030000,20031005T030000,20041003T03000",
         b" 0,20051002T030000,20061001T030000,20070930T030000,20080928T030000,20090927",
         b" T030000,20100926T030000,20110925T030000,20120930T030000,20130929T030000,20",
         b" 140928T030000,20150927T030000,20160925T030000,20170924T030000,20180930T030",
         b" 000,20190929T030000,20200927T030000,20210926T030000,20220925T030000,202309",
         b" 24T030000,20240929T030000,20250928T030000,20260927T030000,20270926T030000,",
         b" 20280924T030000,20290930T030000,20300929T030000,20310928T030000,20320926T0",
         b" 30000,20330925T030000,20340924T030000,20350930T030000,20360928T030000,2037",
         b" 0927T030000",
         b"TZNAME:NZDT",
         b"TZOFFSETFROM:+1200",
         b"TZOFFSETTO:+1300",
         b"END:DAYLIGHT",
     ])
     self.assertIn(nzdt, export)
     nzst = b"\r\n".join([
         b"BEGIN:STANDARD",
         b"DTSTART;VALUE=DATE-TIME:19960317T020000",
         b"RDATE:19970316T020000,19980315T020000,19990321T020000,20000319T020000,2001",
         b" 0318T020000,20020317T020000,20030316T020000,20040321T020000,20050320T02000",
         b" 0,20060319T020000,20070318T020000,20080406T020000,20090405T020000,20100404",
         b" T020000,20110403T020000,20120401T020000,20130407T020000,20140406T020000,20",
         b" 150405T020000,20160403T020000,20170402T020000,20180401T020000,20190407T020",
         b" 000,20200405T020000,20210404T020000,20220403T020000,20230402T020000,202404",
         b" 07T020000,20250406T020000,20260405T020000,20270404T020000,20280402T020000,",
         b" 20290401T020000,20300407T020000,20310406T020000,20320404T020000,20330403T0",
         b" 20000,20340402T020000,20350401T020000,20360406T020000,20370405T020000",
         b"TZNAME:NZST",
         b"TZOFFSETFROM:+1300",
         b"TZOFFSETTO:+1200",
         b"END:STANDARD",
     ])
     self.assertIn(nzst, export)
    def parse_recurring_rules(self, item, component):
        """Extracts ICS RRULE into the Event item

        :param item: The Event item
        :param component: An ICS VEVENT component
        """

        # parse ics RRULE to fit eventsML recurring_rule
        r_rule = component.get('rrule')
        if not isinstance(r_rule, vRecur):
            return

        r_rule_dict = vRecur.from_ical(r_rule)
        recurring_rule: Dict[str, Union[str, int, datetime.date,
                                        datetime.datetime]] = {}

        if r_rule.get('FREQ'):
            recurring_rule['frequency'] = ''.join(r_rule_dict['FREQ'])
        if len(r_rule.get('INTERVAL') or []):
            recurring_rule['interval'] = r_rule_dict['INTERVAL'][0]
        if len(r_rule.get('UNTIL') or []):
            recurring_rule['until'] = r_rule_dict['UNTIL'][0]
        if r_rule.get('COUNT'):
            recurring_rule['count'] = r_rule_dict['COUNT']
        if r_rule.get('BYMONTH'):
            recurring_rule['bymonth'] = ' '.join(r_rule_dict['BYMONTH'])
        if r_rule.get('BYDAY'):
            recurring_rule['byday'] = ' '.join(r_rule_dict['BYDAY'])
        if r_rule.get('BYHOUR'):
            recurring_rule['byhour'] = ' '.join(r_rule_dict['BYHOUR'])
        if r_rule.get('BYMIN'):
            recurring_rule['bymin'] = ' '.join(r_rule_dict['BYMIN'])

        if recurring_rule.get('count'):
            recurring_rule['endRepeatMode'] = 'count'
        elif recurring_rule.get('until'):
            recurring_rule['endRepeatMode'] = 'until'

            # If the `until` attribute is just a date
            # then copy the time/tzinfo from `dates.end` attribute
            if isinstance(recurring_rule['until'], datetime.date):
                end_date = item['dates']['end']
                recurring_rule['until'] = datetime.datetime.combine(
                    recurring_rule['until'], end_date.time(), end_date.tzinfo)
        else:
            # If the calendar does not provide an end date
            # then set `count` to MAX_RECURRENT_EVENTS settings
            recurring_rule['count'] = get_max_recurrent_events()
            recurring_rule['endRepeatMode'] = 'count'

        item['dates']['recurring_rule'] = recurring_rule
Exemple #5
0
 def fromPage(cls, page):
     vevent = super().fromPage(page)
     minDt = pytz.utc.localize(dt.datetime.min)
     # FIXME support Anniversary date type events?
     dtstart = page._getMyFirstDatetimeFrom() or minDt
     dtend = page._getMyFirstDatetimeTo() or minDt
     vevent.set('UID', page.uid)
     vevent.set('DTSTART', vDatetime(dtstart))
     vevent.set('DTEND', vDatetime(dtend))
     vevent.set('DESCRIPTION', page.details)
     vevent.set('LOCATION', page.location)
     vevent.vchildren, exDates = cls.__getExceptions(page)
     if exDates:
         vevent.set('EXDATE', exDates)
     vevent.set('RRULE', vRecur.from_ical(page.repeat._getRrule()))
     return vevent
Exemple #6
0
 def fromPage(cls, page):
     vevent = super().fromPage(page)
     minDt = pytz.utc.localize(dt.datetime.min)
     dtstart = page._getMyFirstDatetimeFrom() or minDt
     dtend = page._getMyFirstDatetimeTo() or minDt
     vevent.set('UID', page.uid)
     vevent.set('DTSTART', vDatetime(dtstart))
     vevent.set('DTEND', vDatetime(dtend))
     vevent._setDesc(page.details)
     vevent.set('LOCATION', page.location)
     vevent.vchildren, exDates = cls.__getExceptions(page)
     if exDates:
         vevent.set('EXDATE', exDates)
     until = page.repeat.until
     if until:
         until = getAwareDatetime(until, dt.time.max, dtend.tzinfo)
         until = until.astimezone(pytz.utc)
     vevent.set('RRULE', vRecur.from_ical(page.repeat._getRrule(until)))
     return vevent
 def testOverlapping(self):
     tz = pytz.timezone("Pacific/Auckland")
     vev = SimpleVEvent()
     addProps(vev,
              summary="Storytelling",
              uid="1000",
              dtstart=timezone.make_aware(dt.datetime(2016, 4, 5, 10), tz),
              dtend=timezone.make_aware(dt.datetime(2016, 4, 5, 11), tz),
              rrule=vRecur.from_ical(
                  "FREQ=WEEKLY;WKST=SU;BYDAY=TU;UNTIL=20160519"))
     span = TimeZoneSpan(vev)
     vev = SimpleVEvent()
     addProps(vev,
              summary="Parade",
              uid="1002",
              dtstart=timezone.make_aware(dt.datetime(2016, 4, 5, 9), tz),
              dtend=timezone.make_aware(dt.datetime(2016, 4, 5, 13), tz))
     span.add(vev)
     vtz = span.createVTimeZone(tz)
     self.assertEqual(vtz['TZID'], "Pacific/Auckland")
     export = vtz.to_ical()
     nzdt = b"\r\n".join([
         b"BEGIN:DAYLIGHT",
         b"DTSTART;VALUE=DATE-TIME:20160925T030000",
         b"TZNAME:NZDT",
         b"TZOFFSETFROM:+1200",
         b"TZOFFSETTO:+1300",
         b"END:DAYLIGHT",
     ])
     self.assertIn(nzdt, export)
     nzst = b"\r\n".join([
         b"BEGIN:STANDARD",
         b"DTSTART;VALUE=DATE-TIME:20160403T020000",
         b"TZNAME:NZST",
         b"TZOFFSETFROM:+1300",
         b"TZOFFSETTO:+1200",
         b"END:STANDARD",
     ])
     self.assertIn(nzst, export)
Exemple #8
0
 def add_end(self, d):
         end = vDatetime(datetime(d.year, d. month, d.day,
                                  12, 0, 0, tzinfo = UTC))
         self.rpt += end.ical()
         self.ev.add('rrule',vRecur.from_ical(self.rpt))
    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)