Mercurial > public > sg101
comparison gpp/gcalendar/calendar.py @ 1:dbd703f7d63a
Initial import of sg101 stuff from private repository.
author | gremmie |
---|---|
date | Mon, 06 Apr 2009 02:43:12 +0000 |
parents | |
children | cce1fc3f8752 |
comparison
equal
deleted
inserted
replaced
0:900ba3c7b765 | 1:dbd703f7d63a |
---|---|
1 """ | |
2 This file contains the calendar class wich abstracts the Google gdata API for working with | |
3 Google Calendars. | |
4 """ | |
5 import datetime | |
6 import pytz | |
7 | |
8 from django.utils.tzinfo import FixedOffset | |
9 from gdata.calendar.service import CalendarService | |
10 from gdata.calendar import CalendarEventFeed | |
11 from gdata.calendar import CalendarEventEntry | |
12 from gdata.calendar import Who | |
13 from gdata.calendar import Where | |
14 from gdata.calendar import When | |
15 from gdata.service import BadAuthentication | |
16 import atom | |
17 | |
18 from gcalendar.models import Event | |
19 | |
20 | |
21 class CalendarError(Exception): | |
22 def __init__(self, errs): | |
23 self.errs = errs | |
24 | |
25 def __str__(self): | |
26 return repr(self.errs) | |
27 | |
28 | |
29 class Calendar(object): | |
30 DATE_FMT = '%Y-%m-%d' | |
31 DATE_TIME_FMT = DATE_FMT + 'T%H:%M:%S' | |
32 DATE_TIME_TZ_FMT = DATE_TIME_FMT + '.000Z' | |
33 | |
34 def __init__(self, email, password, calendar_id='default'): | |
35 self.client = CalendarService() | |
36 self.client.email = email | |
37 self.client.password = password | |
38 self.client.source = 'Google-Calendar_Python_GCalendar' | |
39 self.insert_feed = '/calendar/feeds/%s/private/full' % calendar_id | |
40 self.batch_feed = '%s/batch' % self.insert_feed | |
41 try: | |
42 self.client.ProgrammaticLogin() | |
43 except BadAuthentication: | |
44 raise CalendarError(['Incorrect password']) | |
45 except Exception, e: | |
46 raise CalendarError([e]) | |
47 | |
48 def sync_events(self, qs): | |
49 request_feed = CalendarEventFeed() | |
50 for model in qs: | |
51 if model.status == Event.NEW_APRV: | |
52 event = CalendarEventEntry() | |
53 request_feed.AddInsert(entry=self._populate_event(model, event)) | |
54 elif model.status == Event.EDIT_APRV: | |
55 event = self._retrieve_event(model) | |
56 request_feed.AddUpdate(entry=self._populate_event(model, event)) | |
57 elif model.status == Event.DEL_APRV: | |
58 event = self._retrieve_event(model) | |
59 request_feed.AddDelete(entry=event) | |
60 else: | |
61 assert False, 'unexpected status in sync_events' | |
62 | |
63 response_feed = self.client.ExecuteBatch(request_feed, self.batch_feed) | |
64 err_msgs = [] | |
65 for entry in response_feed.entry: | |
66 i = int(entry.batch_id.text) | |
67 code = int(entry.batch_status.code) | |
68 | |
69 error = False | |
70 if qs[i].status == Event.NEW_APRV or qs[i].status == Event.EDIT_APRV: | |
71 if (code == 201 and qs[i].status == Event.NEW_APRV) or \ | |
72 (code == 200 and qs[i].status == Event.EDIT_APRV): | |
73 qs[i].google_id = entry.id.text | |
74 qs[i].status = Event.ON_CAL | |
75 qs[i].save() | |
76 else: | |
77 error = True | |
78 elif qs[i].status == Event.DEL_APRV: | |
79 if code == 200: | |
80 qs[i].delete() | |
81 else: | |
82 error = True | |
83 | |
84 if error: | |
85 err_msgs.append('%s - (%d) %s' % \ | |
86 (qs[i].title, code, entry.batch_status.reason)) | |
87 | |
88 if len(err_msgs) > 0: | |
89 raise CalendarError(err_msgs) | |
90 | |
91 def _retrieve_event(self, model): | |
92 try: | |
93 event = self.client.GetCalendarEventEntry(model.google_id) | |
94 except Exception: | |
95 raise CalendarError(['Could not retrieve event from Google: %s' % model.what]) | |
96 return event | |
97 | |
98 def _populate_event(self, model, event): | |
99 """Populates a gdata event from an Event model object.""" | |
100 event.title = atom.Title(text=model.what) | |
101 event.content = atom.Content(text=model.html) | |
102 event.where = [Where(value_string=model.where)] | |
103 event.who = [Who(name=model.user.username, email=model.user.email)] | |
104 | |
105 if model.all_day: | |
106 start_time = self._make_time(model.start_date) | |
107 if model.start_date == model.end_date: | |
108 end_time = None | |
109 else: | |
110 end_time = self._make_time(model.end_date) | |
111 else: | |
112 start_time = self._make_time(model.start_date, model.start_time, model.time_zone) | |
113 end_time = self._make_time(model.end_date, model.end_time, model.time_zone) | |
114 | |
115 event.when = [When(start_time=start_time, end_time=end_time)] | |
116 return event | |
117 | |
118 def _make_time(self, date, time=None, tz_name=None): | |
119 """ | |
120 Returns the gdata formatted date/time string given a date, optional time, | |
121 and optional time zone name (e.g. 'US/Pacific'). If the time zone name is None, | |
122 no time zone info will be added to the string. | |
123 """ | |
124 | |
125 if time is not None: | |
126 d = datetime.datetime.combine(date, time) | |
127 else: | |
128 d = datetime.datetime(date.year, date.month, date.day) | |
129 | |
130 if time is None: | |
131 s = d.strftime(self.DATE_FMT) | |
132 elif tz_name is None: | |
133 s = d.strftime(self.DATE_TIME_FMT) | |
134 else: | |
135 try: | |
136 tz = pytz.timezone(tz_name) | |
137 except pytz.UnknownTimeZoneError: | |
138 raise CalendarError(['Invalid time zone: %s' (tz_name,)]) | |
139 local = tz.localize(d) | |
140 zulu = local.astimezone(FixedOffset(0)) | |
141 s = zulu.strftime(self.DATE_TIME_TZ_FMT) | |
142 | |
143 return s | |
144 | |
145 # vim: ts=4 sw=4 |