changeset 451:345825e6dcae

Working on #220. Can't test locally, so committing in increments.
author Brian Neal <bgneal@gmail.com>
date Thu, 30 Jun 2011 01:57:17 +0000
parents acc129bfd0d3
children c77359d0d951
files gpp/gcalendar/admin.py gpp/gcalendar/admin_views.py gpp/gcalendar/oauth.py gpp/gcalendar/settings.py gpp/settings.py
diffstat 5 files changed, 186 insertions(+), 60 deletions(-) [+]
line wrap: on
line diff
--- a/gpp/gcalendar/admin.py	Sun Jun 26 00:15:36 2011 +0000
+++ b/gpp/gcalendar/admin.py	Thu Jun 30 01:57:17 2011 +0000
@@ -1,15 +1,31 @@
 """
 This file contains the automatic admin site definitions for the gcalendar application.
+
 """
+from django.conf import settings
+from django.conf.urls.defaults import *
 from django.contrib import admin
+from django.contrib import messages
+from django.core.urlresolvers import reverse
 from django.http import HttpResponse
-from django.conf.urls.defaults import *
+from django.http import HttpResponseRedirect
+from django.shortcuts import render_to_response
+from django.template import RequestContext
+
+import gdata.client
 
 from gcalendar.models import Event
-from gcalendar.admin_views import google_sync
+from gcalendar.forms import PasswordForm
+from gcalendar.calendar import Calendar
+from gcalendar.calendar import CalendarError
+from gcalendar import oauth
+
 import bio.badges
 
 
+SCOPES = ['https://www.google.com/calendar/feeds/']
+
+
 class EventAdmin(admin.ModelAdmin):
     list_display = ('what', 'user', 'start_date', 'where', 'date_submitted',
             'status', 'is_approved', 'google_html')
@@ -30,9 +46,15 @@
     def get_urls(self):
         urls = super(EventAdmin, self).get_urls()
         my_urls = patterns('',
-            url(r'^google_sync/$', 
-                self.admin_site.admin_view(google_sync), 
-                name="gcalendar-google_sync")
+            url(r'^google_sync/$',
+                self.admin_site.admin_view(self.google_sync),
+                name="gcalendar-google_sync"),
+            url(r'^fetch_auth/$',
+                self.admin_site.admin_view(self.fetch_auth),
+                name="gcalendar-fetch_auth"),
+             url(r'^get_access_token/$',
+                self.admin_site.admin_view(self.get_access_token),
+                name="gcalendar-get_access_token"),
         )
         return my_urls + urls
 
@@ -57,6 +79,72 @@
 
     approve_events.short_description = "Approve selected events"
 
+    def google_sync(self, request):
+        """View to synchronize approved event changes with Google calendar."""
+        events = Event.pending_events.all()
+        messages = []
+        err_msg = ''
+        if request.method == 'POST':
+            form = PasswordForm(request.POST)
+            if form.is_valid():
+                try:
+                    cal = Calendar(settings.GCAL_EMAIL,
+                            form.cleaned_data['password'],
+                            settings.GCAL_CALENDAR_ID)
+                    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', {
+            'current_app': self.admin_site.name,
+            'messages': messages,
+            'err_msg': err_msg,
+            'events': events,
+            'form': form,
+            },
+            context_instance=RequestContext(request))
+
+    def fetch_auth(self, request):
+        """
+        This view fetches a request token and then redirects the user to
+        authorize it.
+
+        """
+        callback_url = reverse('admin:gcalendar-get_access_token')
+        try:
+            auth_url = oauth.fetch_auth(request, SCOPES, callback_url)
+        except gdata.client.Error, e:
+            messages.error(request, str(e))
+            return HttpResponseRedirect(reverse('admin:gcalendar-google_sync'))
+        else:
+            return HttpResponseRedirect(auth_url)
+
+    def get_access_token(self, request):
+        """
+        This view is called by Google after the user has authorized us access to
+        their data. We call into the oauth module to upgrade the oauth token to 
+        an access token. We then save the access token in the database and
+        redirect back to our admin Google sync view.
+
+        """
+        try:
+            access_token = oauth.get_access_token(request)
+        except gdata.client.Error, e:
+            messages.error(request, str(e))
+        else:
+            # TODO: save access token
+            pass
+
+        return HttpResponseRedirect(reverse('admin:gcalendar-google_sync'))
+
 
 admin.site.register(Event, EventAdmin)
-
--- a/gpp/gcalendar/admin_views.py	Sun Jun 26 00:15:36 2011 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-"""
-Admin views for the gcalendar application.
-"""
-from django.shortcuts import render_to_response
-from django.template import RequestContext
-
-from gcalendar.models import Event
-from gcalendar.forms import PasswordForm
-from gcalendar.calendar import Calendar
-from gcalendar.calendar import CalendarError
-import gcalendar.settings
-
-
-def google_sync(request):
-    """View to synchronize approved event changes with Google calendar."""
-    events = Event.pending_events.all()
-    messages = []
-    err_msg = ''
-    if request.method == 'POST':
-        form = PasswordForm(request.POST)
-        if form.is_valid():
-            try:
-                cal = Calendar(gcalendar.settings.EMAIL,
-                        form.cleaned_data['password'],
-                        gcalendar.settings.CALENDAR_ID)
-                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', {
-        'messages': messages,
-        'err_msg': err_msg,
-        'events': events,
-        'form': form,
-        },
-        context_instance=RequestContext(request))
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gpp/gcalendar/oauth.py	Thu Jun 30 01:57:17 2011 +0000
@@ -0,0 +1,82 @@
+"""
+This module handles the OAuth integration with Google.
+
+"""
+from __future__ import with_statement
+import logging
+
+import gdata.gauth
+from gdata.calendar_resource.client import CalendarResourceClient
+
+from django.conf import settings
+
+
+logger = logging.getLogger(__name__)
+USER_AGENT = 'surfguitar101-gcalendar-v1'
+REQ_TOKEN_SESSION_KEY = 'gcalendar oauth request token'
+
+
+def fetch_auth(request, scopes, callback_url):
+    """
+    This function fetches a request token from Google and stores it in the
+    session. It then returns the authorization URL as a string.
+
+    request - the HttpRequest object for the user requesting the token. The
+    token is stored in the session object attached to this request.
+
+    scopes - a list of scope strings that the request token is for. See
+    http://code.google.com/apis/gdata/faq.html#AuthScopes
+
+    callback_url - a string that is the URL that Google should redirect the user
+    to after the user has authorized our application access to their data.
+
+    This function only supports RSA-SHA1 authentication. Settings in the Django
+    settings module determine the consumer key and path to the RSA private key.
+    """
+    logger.info("fetch_auth started...")
+    client = CalendarResourceClient(None, source=USER_AGENT)
+
+    with open(settings.GOOGLE_OAUTH_PRIVATE_KEY_PATH, 'r') as f:
+        rsa_key = f.read()
+    logger.info("read RSA key; now getting request token")
+
+    request_token = client.GetOAuthToken(
+            scopes,
+            callback_url,
+            settings.GOOGLE_OAUTH_CONSUMER_KEY,
+            rsa_private_key=rsa_key)
+
+    logger.info("received token")
+    request.session[REQ_TOKEN_SESSION_KEY] = request_token
+
+    auth_url = request_token.generate_authorization_url(google_apps_domain=None)
+    logger.info("generated auth url '%s'", str(auth_url))
+
+    return str(auth_url)
+
+
+def get_access_token(request):
+    """
+    This function should be called after Google has sent the user back to us
+    after the user authorized us. We retrieve the oauth token from the request
+    URL and then upgrade it to an access token. We then return the access token.
+
+    """
+    logger.info("get_access_token started; retrieving saved request_token...")
+
+    saved_token = request.session.get(REQ_TOKEN_SESSION_KEY)
+    if saved_token is None:
+        logger.error("saved request token not found in session!")
+        return None
+
+    logger.info("extracting token...")
+    request_token = gdata.gauth.AuthorizeRequestToken(saved_token,
+                        request.build_absolute_uri())
+
+    logger.info("upgrading to access token...")
+
+    client = CalendarResourceClient(None, source=USER_AGENT)
+    access_token = client.GetAccessToken(request_token)
+
+    logger.info("upgraded to access token...")
+    return access_token
--- a/gpp/gcalendar/settings.py	Sun Jun 26 00:15:36 2011 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-"""
-This file contains the user tweakable settings for the gcalendar application.
-"""
-
-EMAIL = 'bgneal@gmail.com'
-CALENDAR_ID = 'i81lu3fkh57sgqqenogefd9v78@group.calendar.google.com'
-
-# vim: ts=4 sw=4
--- a/gpp/settings.py	Sun Jun 26 00:15:36 2011 +0000
+++ b/gpp/settings.py	Thu Jun 30 01:57:17 2011 +0000
@@ -261,6 +261,16 @@
 OEMBED_MAXWIDTH = 480
 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
+
 #######################################################################
 # Configure Logging
 #######################################################################