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