diff options
author | Mike Crute <mcrute@gmail.com> | 2010-08-05 09:13:35 -0400 |
---|---|---|
committer | Mike Crute <mcrute@gmail.com> | 2010-08-05 09:13:35 -0400 |
commit | 70f622d3275635cafba88044300048771dc655b1 (patch) | |
tree | 1e96fe4bf0279427e030a93516dfd2c2ff3ccb24 | |
parent | 477f86f1c8db8376c2305c6a18f4e37cecf55947 (diff) | |
download | calendar_proxy-70f622d3275635cafba88044300048771dc655b1.tar.bz2 calendar_proxy-70f622d3275635cafba88044300048771dc655b1.tar.xz calendar_proxy-70f622d3275635cafba88044300048771dc655b1.zip |
Added support for organizers, all-day events. alarms and event statuses
-rw-r--r-- | exchange/commands.py | 116 |
1 files changed, 108 insertions, 8 deletions
diff --git a/exchange/commands.py b/exchange/commands.py index b1169e2..9c72a3e 100644 --- a/exchange/commands.py +++ b/exchange/commands.py | |||
@@ -12,18 +12,70 @@ development code but it does the trick. Watch out, it doesn't consider | |||
12 | many corner cases. | 12 | many corner cases. |
13 | """ | 13 | """ |
14 | 14 | ||
15 | import re | ||
16 | |||
15 | import dateutil.parser as date_parser | 17 | import dateutil.parser as date_parser |
16 | import xml.etree.cElementTree as ElementTree | 18 | import xml.etree.cElementTree as ElementTree |
17 | 19 | ||
18 | from string import Template | 20 | from string import Template |
19 | from httplib import HTTPSConnection | 21 | from httplib import HTTPSConnection |
20 | from datetime import datetime, timedelta | 22 | from datetime import datetime, timedelta, date, tzinfo |
21 | from exchange import ExchangeException, EST | 23 | from exchange import ExchangeException, EST |
22 | from icalendar import Calendar, Event as _Event | 24 | from icalendar import Calendar, Event as _Event, Alarm |
25 | from icalendar import vCalAddress, vText | ||
26 | |||
27 | |||
28 | class InvalidEventError(Exception): | ||
29 | pass | ||
30 | |||
31 | |||
32 | class Organizer(object): | ||
33 | |||
34 | def __init__(self, cn, email): | ||
35 | self.cn = cn | ||
36 | self.email = email | ||
37 | |||
38 | def __repr__(self): | ||
39 | return u"vCalAddress(%s)" % str.__repr__(self) | ||
40 | |||
41 | def ical(self): | ||
42 | return "CN=%s:%s" % (self.cn, self.email) | ||
43 | |||
44 | def __str__(self): | ||
45 | return self.ical() | ||
46 | |||
47 | |||
48 | class EST(tzinfo): | ||
49 | |||
50 | def tzname(self, dt): | ||
51 | return "EST" | ||
52 | |||
53 | def utcoffset(self, dt): | ||
54 | return timedelta(0) | ||
55 | |||
56 | dst = utcoffset | ||
57 | |||
58 | |||
59 | class EmailParser(object): | ||
60 | |||
61 | EXCHANGE_FORMAT = re.compile("([^<]*)<([^>]*)>") | ||
62 | |||
63 | def parse(self, email): | ||
64 | if not email: | ||
65 | return | ||
66 | |||
67 | match = self.EXCHANGE_FORMAT.match(email) | ||
68 | if match: | ||
69 | return match.groups() | ||
23 | 70 | ||
24 | 71 | ||
25 | class Event(_Event): | 72 | class Event(_Event): |
26 | 73 | ||
74 | def __init__(self): | ||
75 | super(Event, self).__init__() | ||
76 | self.start_date = None | ||
77 | self.end_date = None | ||
78 | |||
27 | def _get_element_text(self, element, key): | 79 | def _get_element_text(self, element, key): |
28 | value = element.find(key) | 80 | value = element.find(key) |
29 | 81 | ||
@@ -36,11 +88,53 @@ class Event(_Event): | |||
36 | add_as = key if not add_as else add_as | 88 | add_as = key if not add_as else add_as |
37 | self.add(add_as, value) | 89 | self.add(add_as, value) |
38 | 90 | ||
91 | def add_organizer(self, element): | ||
92 | value = self._get_element_text(element, 'organizer') | ||
93 | |||
94 | parsed = EmailParser().parse(value) | ||
95 | if not parsed: | ||
96 | return | ||
97 | |||
98 | name = parsed[0].strip().strip('"') | ||
99 | |||
100 | organizer = vCalAddress('MAILTO:%s' % parsed[1]) | ||
101 | organizer.params['cn'] = vText(name) | ||
102 | organizer.params['ROLE'] = vText('CHAIR') | ||
103 | |||
104 | self.add('organizer', organizer, encode=0) | ||
105 | |||
39 | def add_date(self, element, key, add_as=None): | 106 | def add_date(self, element, key, add_as=None): |
40 | value = date_parser.parse(self._get_element_text(element, key)) | 107 | value = date_parser.parse(self._get_element_text(element, key)) |
41 | 108 | ||
42 | add_as = key if not add_as else add_as | 109 | if key == 'start_date': |
43 | self.add(add_as, value) | 110 | self.start_date = value |
111 | elif key == 'end_date': | ||
112 | self.end_date = value | ||
113 | else: | ||
114 | add_as = key if not add_as else add_as | ||
115 | self.add(add_as, value) | ||
116 | |||
117 | def finalize(self): | ||
118 | if not self.start_date and self.end_date: | ||
119 | raise InvalidEventError() | ||
120 | |||
121 | delta = self.end_date - self.start_date | ||
122 | if delta.days > 1: | ||
123 | start_date = date(self.start_date.year, self.start_date.month, self.start_date.day) | ||
124 | end_date = date(self.end_date.year, self.end_date.month, self.end_date.day) | ||
125 | else: | ||
126 | start_date = self.start_date | ||
127 | end_date = self.end_date | ||
128 | |||
129 | if self.start_date > datetime.now(tz=EST()): | ||
130 | alarm = Alarm() | ||
131 | alarm.add("action", "DISPLAY") | ||
132 | alarm.add("description", "REMINDER") | ||
133 | alarm.add("trigger", timedelta(minutes=-15)) | ||
134 | self.add_component(alarm) | ||
135 | |||
136 | self.add('dtstart', start_date) | ||
137 | self.add('dtend', end_date) | ||
44 | 138 | ||
45 | 139 | ||
46 | class ExchangeRequest(object): | 140 | class ExchangeRequest(object): |
@@ -152,10 +246,16 @@ class FetchCalendar(ExchangeCommand): | |||
152 | event = Event() | 246 | event = Event() |
153 | event.add_text(item, 'subject', add_as='summary') | 247 | event.add_text(item, 'subject', add_as='summary') |
154 | event.add_text(item, 'location') | 248 | event.add_text(item, 'location') |
249 | event.add_text(item, 'status') | ||
155 | event.add_text(item, 'description') | 250 | event.add_text(item, 'description') |
156 | event.add_date(item, 'start_date', add_as='dtstart') | 251 | event.add_date(item, 'start_date') |
157 | event.add_date(item, 'end_date', add_as='dtend') | 252 | event.add_date(item, 'end_date') |
158 | 253 | event.add_organizer(item) | |
159 | calendar.add_component(event) | 254 | |
255 | try: | ||
256 | event.finalize() | ||
257 | calendar.add_component(event) | ||
258 | except InvalidEventError: | ||
259 | print "Rejected event" | ||
160 | 260 | ||
161 | return calendar | 261 | return calendar |