From fd85ac746e7fa251361d01fe508baf558fcdeb7b Mon Sep 17 00:00:00 2001 From: Markus Brenneis Date: Sat, 17 Aug 2019 14:05:49 +0200 Subject: [PATCH] Add created and last_modified event attributes --- icalevents/icalparser.py | 16 +++++- test/test_data/created_last_modified.ics | 65 ++++++++++++++++++++++++ test/test_icalevents.py | 17 +++++++ 3 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 test/test_data/created_last_modified.ics diff --git a/icalevents/icalparser.py b/icalevents/icalparser.py index 3b4ed58..cefd76e 100644 --- a/icalevents/icalparser.py +++ b/icalevents/icalparser.py @@ -39,6 +39,8 @@ class Event: self.recurring = False self.location = None self.private = False + self.created = None + self.last_modified = None def time_left(self, time=None): """ @@ -117,6 +119,8 @@ class Event: ne.location = self.location ne.private = self.private ne.uid = uid + ne.created = self.created + ne.last_modified = self.last_modified return ne @@ -177,6 +181,14 @@ def create_event(component, tz=UTC): event_class = component.get('class') event.private = event_class == 'PRIVATE' or event_class == 'CONFIDENTIAL' + if component.get('created'): + event.created = normalize(component.get('created').dt, tz) + + if component.get('last-modified'): + event.last_modified = normalize(component.get('last-modified').dt, tz) + elif event.created: + event.last_modified = event.created + return event @@ -228,7 +240,7 @@ def parse_events(content, start=None, end=None, default_span=timedelta(days=7)): for c in calendar.walk(): if c.name == 'VTIMEZONE': cal_tz = gettz(str(c['TZID'])) - break; + break else: cal_tz = UTC @@ -239,7 +251,7 @@ def parse_events(content, start=None, end=None, default_span=timedelta(days=7)): for component in calendar.walk(): if component.name == "VEVENT": - e = create_event(component) + e = create_event(component, cal_tz) if e.recurring: # Unfold recurring events according to their rrule rule = parse_rrule(component, cal_tz) diff --git a/test/test_data/created_last_modified.ics b/test/test_data/created_last_modified.ics new file mode 100644 index 0000000..3f88a59 --- /dev/null +++ b/test/test_data/created_last_modified.ics @@ -0,0 +1,65 @@ +BEGIN:VCALENDAR +PRODID:-//Google Inc//Google Calendar 70.9054//EN +VERSION:2.0 +CALSCALE:GREGORIAN +METHOD:PUBLISH +BEGIN:VTIMEZONE +TZID:Europe/Berlin +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +TZNAME:CEST +DTSTART:19700329T020000 +RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3 +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +TZNAME:CET +DTSTART:19701025T030000 +RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 +END:STANDARD +END:VTIMEZONE +X-WR-CALNAME:Müll +X-WR-TIMEZONE:Europe/Berlin +X-WR-CALDESC:Müllabholung Treuchtlingen Luitpoldstraße +BEGIN:VEVENT +DTSTART;VALUE=DATE:20170712 +DTEND;VALUE=DATE:20170713 +DTSTAMP:20170711T171222Z +UID:0eedefedba891fcbb49dcfa4279d9d93 +CREATED:20170103T080401 +DESCRIPTION:graue Restmülltonne nicht vergessen! +LAST-MODIFIED:20170711T160050 +LOCATION:Luitpoldstraße\, Treuchtlingen +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:graue Restmülltonne +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20170713 +DTEND;VALUE=DATE:20170714 +DTSTAMP:20170711T171222Z +UID:0eedefedba891fcbb49dcfa4279d9d93 +CREATED:20170104T080401Z +DESCRIPTION:graue Restmülltonne nicht vergessen! +LOCATION:Luitpoldstraße\, Treuchtlingen +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:graue Restmülltonne +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20170714 +DTEND;VALUE=DATE:20170715 +DTSTAMP:20170711T171222Z +UID:0eedefedba891fcbb49dcfa4279d9d93 +DESCRIPTION:graue Restmülltonne nicht vergessen! +LOCATION:Luitpoldstraße\, Treuchtlingen +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:graue Restmülltonne +TRANSP:TRANSPARENT +END:VEVENT +END:VCALENDAR diff --git a/test/test_icalevents.py b/test/test_icalevents.py index 5675a7f..c5d4ee6 100644 --- a/test/test_icalevents.py +++ b/test/test_icalevents.py @@ -222,3 +222,20 @@ class ICalEventsTests(unittest.TestCase): self.assertIsNotNone(search(r"now", str(e2.copy_to(n - relativedelta(hours=1)))), "stringify ongoing event") self.assertIsNotNone(search(r"hours left", str(e2.copy_to(n + relativedelta(hours=3)))), "stringify future event") self.assertIsNotNone(search(r"days left", str(e2.copy_to(n + relativedelta(days=3)))), "stringify future event") + + + def test_event_created_last_modified(self): + ical = "test/test_data/created_last_modified.ics" + start = date(2017, 7, 12) + end = date(2017, 7, 15) + + events = icalevents.events(url=None, file=ical, start=start, end=end) + + self.assertEqual(events[0].created, datetime(2017, 1, 3, 7, 4, 1, tzinfo=UTC)) + self.assertEqual(events[0].last_modified, datetime(2017, 7, 11, 14, 0, 50, tzinfo=UTC)) + + self.assertEqual(events[1].created, datetime(2017, 1, 4, 8, 4, 1, tzinfo=UTC)) + self.assertEqual(events[1].last_modified, datetime(2017, 1, 4, 8, 4, 1, tzinfo=UTC)) + + self.assertEqual(events[2].created, None) + self.assertEqual(events[2].last_modified, None)