Mercurial > public > sg101
changeset 458:9a4bffdf37c3
Finishing up #220. Updated to GData v2.0 and using the new OAuth access token.
author | Brian Neal <bgneal@gmail.com> |
---|---|
date | Sat, 02 Jul 2011 03:52:43 +0000 (2011-07-02) |
parents | 7b7332037396 |
children | 9d3bd7304050 |
files | gpp/gcalendar/admin.py gpp/gcalendar/calendar.py gpp/gcalendar/forms.py gpp/gcalendar/models.py gpp/gcalendar/oauth.py gpp/settings.py gpp/templates/gcalendar/event.html gpp/templates/gcalendar/google_sync.html |
diffstat | 8 files changed, 115 insertions(+), 72 deletions(-) [+] |
line wrap: on
line diff
--- a/gpp/gcalendar/admin.py Fri Jul 01 00:49:11 2011 +0000 +++ b/gpp/gcalendar/admin.py Sat Jul 02 03:52:43 2011 +0000 @@ -12,15 +12,13 @@ from django.core.urlresolvers import reverse from django.http import HttpResponse from django.http import HttpResponseRedirect -from django.shortcuts import render_to_response +from django.shortcuts import render from django.template import RequestContext import gdata.client from gcalendar.models import Event, AccessToken -from gcalendar.forms import PasswordForm -from gcalendar.calendar import Calendar -from gcalendar.calendar import CalendarError +from gcalendar.calendar import Calendar, CalendarError from gcalendar import oauth import bio.badges @@ -83,38 +81,39 @@ approve_events.short_description = "Approve selected events" def google_sync(self, request): - """View to synchronize approved event changes with Google calendar.""" + """ + View to synchronize approved event changes with Google calendar. + + """ + # Get pending events events = Event.pending_events.all() + + # Attempt to get saved access token to the Google calendar + access_token = AccessToken.objects.get_token().access_token() + messages = [] err_msg = '' if request.method == 'POST': - form = PasswordForm(request.POST) - if form.is_valid(): + if access_token: try: - cal = Calendar(settings.GCAL_EMAIL, - form.cleaned_data['password'], - settings.GCAL_CALENDAR_ID) + cal = Calendar(source=oauth.USER_AGENT, + calendar_id=settings.GCAL_CALENDAR_ID, + access_token=access_token) cal.sync_events(events) except CalendarError, e: err_msg = e.msg events = Event.pending_events.all() - form = PasswordForm() else: messages.append('All events processed successfully.') events = Event.objects.none() - form = PasswordForm() - else: - form = PasswordForm() - - return render_to_response('gcalendar/google_sync.html', { + return render(request, 'gcalendar/google_sync.html', { 'current_app': self.admin_site.name, + 'access_token': access_token, 'messages': messages, 'err_msg': err_msg, 'events': events, - 'form': form, - }, - context_instance=RequestContext(request)) + }) def fetch_auth(self, request): """ @@ -146,13 +145,8 @@ except gdata.client.Error, e: messages.error(request, str(e)) else: - try: - token = AccessToken.objects.get(id=1) - except AccessToken.DoesNotExist: - token = AccessToken() - - token.token = gdata.gauth.TokenToBlob(access_token) - token.auth_date = datetime.datetime.now() + token = AccessToken.objects.get_token() + token.update(access_token) token.save() return HttpResponseRedirect(reverse('admin:gcalendar-google_sync'))
--- a/gpp/gcalendar/calendar.py Fri Jul 01 00:49:11 2011 +0000 +++ b/gpp/gcalendar/calendar.py Sat Jul 02 03:52:43 2011 +0000 @@ -1,19 +1,16 @@ """ This file contains the calendar class wich abstracts the Google gdata API for working with Google Calendars. + """ import datetime import pytz from django.utils.tzinfo import FixedOffset -from gdata.calendar.service import CalendarService -from gdata.calendar import CalendarEventFeed -from gdata.calendar import CalendarEventEntry -from gdata.calendar import Who -from gdata.calendar import Where -from gdata.calendar import When -from gdata.service import BadAuthentication -import atom +from gdata.calendar.client import CalendarClient +from gdata.calendar.data import (CalendarEventEntry, CalendarEventFeed, + CalendarWhere, When, EventWho) +import atom.data from gcalendar.models import Event @@ -31,19 +28,12 @@ DATE_TIME_FMT = DATE_FMT + 'T%H:%M:%S' DATE_TIME_TZ_FMT = DATE_TIME_FMT + '.000Z' - def __init__(self, email, password, calendar_id='default'): - self.client = CalendarService() - self.client.email = email - self.client.password = password - self.client.source = 'Google-Calendar_Python_GCalendar' - self.insert_feed = '/calendar/feeds/%s/private/full' % calendar_id + def __init__(self, source=None, calendar_id='default', access_token=None): + self.client = CalendarClient(source=source, auth_token=access_token) + + self.insert_feed = ('https://www.google.com/calendar/feeds/' + '%s/private/full' % calendar_id) self.batch_feed = '%s/batch' % self.insert_feed - try: - self.client.ProgrammaticLogin() - except BadAuthentication: - raise CalendarError('Incorrect password') - except Exception, e: - raise CalendarError(str(e)) def sync_events(self, qs): request_feed = CalendarEventFeed() @@ -71,17 +61,23 @@ code = int(entry.batch_status.code) error = False - if qs[i].status == Event.NEW_APRV or qs[i].status == Event.EDIT_APRV: - if (code == 201 and qs[i].status == Event.NEW_APRV) or ( - code == 200 and qs[i].status == Event.EDIT_APRV): - qs[i].google_id = entry.id.text + if qs[i].status == Event.NEW_APRV: + if code == 201: + qs[i].status = Event.ON_CAL + qs[i].google_id = entry.GetEditLink().href qs[i].google_url = entry.GetHtmlLink().href + qs[i].save() + qs[i].notify_on_calendar() + else: + error = True + + elif qs[i].status == Event.EDIT_APRV: + if code == 200: qs[i].status = Event.ON_CAL qs[i].save() - if code == 201: - qs[i].notify_on_calendar() else: error = True + elif qs[i].status == Event.DEL_APRV: if code == 200: qs[i].delete() @@ -97,7 +93,7 @@ def _retrieve_event(self, model): try: - event = self.client.GetCalendarEventEntry(model.google_id) + event = self.client.GetEventEntry(model.google_id) except Exception, e: raise CalendarError('Could not retrieve event from Google: %s, %s' \ % (model.what, e)) @@ -105,10 +101,10 @@ def _populate_event(self, model, event): """Populates a gdata event from an Event model object.""" - event.title = atom.Title(text=model.what) - event.content = atom.Content(text=model.html) - event.where = [Where(value_string=model.where)] - event.who = [Who(name=model.user.username, email=model.user.email)] + event.title = atom.data.Title(text=model.what) + event.content = atom.data.Content(text=model.html) + event.where = [CalendarWhere(value=model.where)] + event.who = [EventWho(email=model.user.email)] if model.all_day: start_time = self._make_time(model.start_date) @@ -120,9 +116,9 @@ start_time = self._make_time(model.start_date, model.start_time, model.time_zone) end_time = self._make_time(model.end_date, model.end_time, model.time_zone) - event.when = [When(start_time=start_time, end_time=end_time)] + event.when = [When(start=start_time, end=end_time)] return event - + def _make_time(self, date, time=None, tz_name=None): """ Returns the gdata formatted date/time string given a date, optional time,
--- a/gpp/gcalendar/forms.py Fri Jul 01 00:49:11 2011 +0000 +++ b/gpp/gcalendar/forms.py Sat Jul 02 03:52:43 2011 +0000 @@ -155,7 +155,3 @@ raise forms.ValidationError("Invalid timezone.") return tz - -class PasswordForm(forms.Form): - password = forms.CharField(widget=forms.PasswordInput()) -
--- a/gpp/gcalendar/models.py Fri Jul 01 00:49:11 2011 +0000 +++ b/gpp/gcalendar/models.py Sat Jul 02 03:52:43 2011 +0000 @@ -2,12 +2,15 @@ Models for the gcalendar application. """ +import datetime + from django.db import models from django.db.models import Q from django.contrib.auth.models import User from core.markup import site_markup import forums.tools +from gcalendar.oauth import serialize_token, deserialize_token GIG_FORUM_SLUG = "gigs" @@ -107,6 +110,22 @@ self.save() +class AccessTokenManager(models.Manager): + """ + A manager for the AccessToken table. Only one access token is saved in the + database. This manager provides a convenience method to either return that + access token or a brand new one. + + """ + def get_token(self): + try: + token = self.get(pk=1) + except AccessToken.DoesNotExist: + token = AccessToken() + + return token + + class AccessToken(models.Model): """ This model represents serialized OAuth access tokens for reading and @@ -116,6 +135,26 @@ auth_date = models.DateTimeField() token = models.TextField() + objects = AccessTokenManager() + def __unicode__(self): return u'Access token created on ' + unicode(self.auth_date) + def update(self, access_token, auth_date=None): + """ + This function updates the AccessToken object with the input parameters: + access_token - an access token from Google's OAuth dance + auth_date - a datetime or None. If None, now() is used. + + """ + self.auth_date = auth_date if auth_date else datetime.datetime.now() + self.token = serialize_token(access_token) + + def access_token(self): + """ + This function returns a Google OAuth access token by deserializing the + token field from the database. + If the token attribute is empty, None is returned. + + """ + return deserialize_token(self.token) if self.token else None
--- a/gpp/gcalendar/oauth.py Fri Jul 01 00:49:11 2011 +0000 +++ b/gpp/gcalendar/oauth.py Sat Jul 02 03:52:43 2011 +0000 @@ -80,3 +80,20 @@ logger.info("upgraded to access token...") return access_token + + +def serialize_token(token): + """ + This function turns a token into a string and returns it. + + """ + return gdata.gauth.TokenToBlob(token) + + +def deserialize_token(s): + """ + This function turns a string into a token returns it. The string must have + previously been created with serialize_token(). + + """ + return gdata.gauth.TokenFromBlob(s)
--- a/gpp/settings.py Fri Jul 01 00:49:11 2011 +0000 +++ b/gpp/settings.py Sat Jul 02 03:52:43 2011 +0000 @@ -262,12 +262,9 @@ OEMBED_MAXHEIGHT = 295 # GCalendar settings - -GCAL_EMAIL = 'bgneal@gmail.com' GCAL_CALENDAR_ID = 'i81lu3fkh57sgqqenogefd9v78@group.calendar.google.com' # Google OAuth settings - GOOGLE_OAUTH_CONSUMER_KEY = local_settings.GOOGLE_OAUTH_CONSUMER_KEY GOOGLE_OAUTH_PRIVATE_KEY_PATH = local_settings.GOOGLE_OAUTH_PRIVATE_KEY_PATH
--- a/gpp/templates/gcalendar/event.html Fri Jul 01 00:49:11 2011 +0000 +++ b/gpp/templates/gcalendar/event.html Sat Jul 02 03:52:43 2011 +0000 @@ -12,8 +12,6 @@ <ul> <li>If applicable, please fill out the <strong>Where</strong> field as completely as you can. Google will generate a Google map from this information.</li> - <li>Currently, images and smilies won't show up correctly on the Google calendar. If you would - like to include an image, add a link to it instead.</li> <li>Once submitted, your event will be reviewed by the site staff for approval. Normally it will appear on the calendar within 24 hours.</li> </ul>
--- a/gpp/templates/gcalendar/google_sync.html Fri Jul 01 00:49:11 2011 +0000 +++ b/gpp/templates/gcalendar/google_sync.html Sat Jul 02 03:52:43 2011 +0000 @@ -1,4 +1,6 @@ {% extends 'admin/base_site.html' %} +{% load url from future %} +{% load core_tags %} {% block title %}Sync Events w/Google Calendar{% endblock %} {% block breadcrumbs %} <div class="breadcrumbs"> @@ -14,9 +16,11 @@ <li>{{ err_msg }}</li> </ul> {% endif %} + +<p>Access token status: {% bool_icon access_token %} — <a href="{% url 'admin:gcalendar-fetch_auth' %}">Request new access token</a></p> + {% if events %} -<p>To synchronize the following approved events with the Google calendar, please enter the password for the -account and click submit.</p> +<p>The following pending events have been approved and are ready to be synchronized with the Google calendar.</p> <ol> {% for event in events %} {% if not event.on_calendar %} @@ -25,10 +29,12 @@ {% endif %} {% endfor %} </ol> + +{% if access_token %} <form action="." method="POST">{% csrf_token %} - {{ form.as_p }} - <p><input type="submit" name="submit" value="Submit" /></p> + <p><input type="submit" name="synchronize" value="Synchronize Events" /></p> </form> +{% endif %} {% else %} <p>No events to synchronize at this time.</p> {% endif %}