annotate gpp/gcalendar/calendar.py @ 339:b871892264f2

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