Started with google calendar coupling

This commit is contained in:
Martin Bauer 2014-03-08 22:36:25 +01:00
parent 5a3d739a9b
commit ee37a5ddcb
8 changed files with 205 additions and 0 deletions

View File

@ -158,6 +158,7 @@ INSTALLED_APPS = (
'website', # Blechreiz Website in general 'website', # Blechreiz Website in general
'musicians', # User Management 'musicians', # User Management
'eventplanner', # Event Management 'eventplanner', # Event Management
'eventplanner_gcal', # Event Management Sync with Google Calendar
'simpleforum', # Messages ( Forum ) 'simpleforum', # Messages ( Forum )
'location_field', # custom location field used in Event Management 'location_field', # custom location field used in Event Management
'scoremanager', # manager of scores, repertoire etc. 'scoremanager', # manager of scores, repertoire etc.
@ -176,6 +177,15 @@ REST_FRAMEWORK = {
} }
GCAL_COUPLING = {
'eventPrefix' : 'Blechreiz: ',
'developerKey' : 'blechreiz-homepage',
'clientId' : '34462582242-4kpdvvbi27ajt4u22uitqurpve9o8ipj.apps.googleusercontent.com',
'client_secret' : 'y4t9XBrJdCODPTO5UvtONWWn',
'credentials_file' : PROJECT_PATH + '/calendarCredentials.dat',
}
CRISPY_TEMPLATE_PACK = 'bootstrap' CRISPY_TEMPLATE_PACK = 'bootstrap'
# A sample logging configuration. The only tangible logging # A sample logging configuration. The only tangible logging

View File

@ -10,6 +10,8 @@ import musicians.urls
import website.urls import website.urls
import scoremanager.urls import scoremanager.urls
from eventplanner_gcal.views import *
import settings import settings
from django.conf.urls.static import static from django.conf.urls.static import static
@ -24,4 +26,5 @@ urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls) ), url(r'^admin/', include(admin.site.urls) ),
url(r'^location_field/', include('location_field.urls')), url(r'^location_field/', include('location_field.urls')),
#url(r'^gallery/', include(imagestore.urls, namespace='imagestore') ), #url(r'^gallery/', include(imagestore.urls, namespace='imagestore') ),
url(r'^eventSync/', runSync )
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View File

@ -0,0 +1 @@
__author__ = 'martin'

View File

@ -0,0 +1 @@
{"_module": "oauth2client.client", "token_expiry": "2014-03-08T14:33:53Z", "access_token": "ya29.1.AADtN_UH8eRhIXsdwF4W1D5oC8xYlMhG-0qeT210pyb6pxk7LTLmd-EnUNVS2UjJZQ", "token_uri": "https://accounts.google.com/o/oauth2/token", "invalid": false, "token_response": {"access_token": "ya29.1.AADtN_UH8eRhIXsdwF4W1D5oC8xYlMhG-0qeT210pyb6pxk7LTLmd-EnUNVS2UjJZQ", "token_type": "Bearer", "expires_in": 3600}, "client_id": "34462582242-4kpdvvbi27ajt4u22uitqurpve9o8ipj.apps.googleusercontent.com", "id_token": null, "client_secret": "y4t9XBrJdCODPTO5UvtONWWn", "revoke_uri": "https://accounts.google.com/o/oauth2/revoke", "_class": "OAuth2Credentials", "refresh_token": "1/7-6-m_lLAKX8IeD7OuGtkcIiprty_nZUSxhMunSC5b0", "user_agent": null}

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,10 @@
from django.core.management.base import BaseCommand
from eventplanner_gcal.models import syncGCalEvents
class Command(BaseCommand):
help = 'Synchronize Google Calendar with locally stored Events'
def handle(self, **options):
print ( "Running Sync")
syncGCalEvents()

171
eventplanner_gcal/models.py Normal file
View File

@ -0,0 +1,171 @@
from django.db import models
from eventplanner.models import Event, EventParticipation
from apiclient.discovery import build
from apiclient.http import BatchHttpRequest
from oauth2client.file import Storage
import httplib2
from django.conf import settings
import logging
import datetime
from django.contrib.auth.models import User
logger = logging.getLogger(__name__)
class GCalMapping( models.Model ):
gcal_id = models.CharField( max_length=64 )
event = models.OneToOneField( Event, primary_key=True )
def init( gcal_settings ):
"""Creates a API service object required by the following synchronization functions"""
storage = Storage( gcal_settings['credentials_file'] )
credentials = storage.get()
if credentials is None or credentials.invalid == True:
logger.error("Unable to initialize Google Calendar coupling. Check your settings!")
return None
http = httplib2.Http()
http = credentials.authorize( http )
return build( serviceName='calendar', version='v3',
http=http, developerKey=gcal_settings['developerKey'] )
service = init( settings.GCAL_COUPLING )
def createAttendeesObj( event ):
result = []
for u in User.objects.all():
if u.email.endswith( "@gmail.com") or u.email.endswith("@googlemail.com"):
participation = EventParticipation.get_or_create( u, event )
status = "tentative"
if participation.status == 'Yes': status = "accepted"
if participation.status == 'No' : status = "declined"
o = {
'id': u.email,
'email': u.email,
'displayName': u.username,
'comment': participation.comment,
'responseStatus': status,
}
result.append( o )
return result
def createEvent( event, timezone="Europe/Berlin" ):
if service is None:
logger.error("createEvent: Google API connection not configured")
return
def createDateTimeObj( date, time ):
if time is None:
return { 'date': unicode(date), 'timeZone': timezone }
else:
return { 'dateTime': unicode(date) + 'T' + unicode(time) , 'timeZone': timezone }
startDate = event.date
endDate = event.end_date
if endDate is None: endDate = startDate
startTime = event.meeting_time
if startTime is None: startTime = event.time
if startTime is None:
endTime = None
else:
endTime = datetime.time( 22, 30 )
googleEvent = {
'summary': unicode(settings.GCAL_COUPLING['eventPrefix'] + event.title),
'description': unicode(event.desc),
'location': unicode(event.location),
'start': createDateTimeObj( startDate, startTime ),
'end' : createDateTimeObj( endDate, endTime ),
'extendedProperties': {
'private': {
'blechreizEvent': 'true',
'blechreizID': event.id,
}
},
'attendees': createAttendeesObj( event ),
}
return service.events().insert(calendarId='primary', body=googleEvent)
def getAllEvents(pageToken=None):
events = service.events().list(
calendarId='primary',
singleEvents=True,
maxResults=1000,
orderBy='startTime',
timeMin='2000-01-01T00:00:00-00:00',
timeMax='2100-01-01T00:00:00-00:00',
pageToken=pageToken,
privateExtendedProperty='blechreizEvent=true',
).execute()
return events['items']
def onGcalEventCreated( request_id, response, exception ):
if exception is not None:
print ( "response " + str( response ) )
raise exception
googleId = response['id']
djangoId = response['extendedProperties']['private']['blechreizID']
mapping = GCalMapping( gcal_id = googleId, event = Event.objects.get( pk=djangoId ) )
mapping.save()
def syncGCalEvents():
if service is None:
logger.error("syncGCalEvents: Google API connection not configured")
return
allEvents = getAllEvents()
eventsAtGoogle_djangoID = set()
eventsAtGoogle_googleID = set()
for gcalEv in allEvents:
eventsAtGoogle_djangoID.add( int(gcalEv['extendedProperties']['private']['blechreizID'] ) )
eventsAtGoogle_googleID.add( gcalEv['id'] )
localEvents_djangoID = set( Event. objects.all().values_list('pk' , flat=True) )
localEvents_googleID = set( GCalMapping.objects.all().values_list('gcal_id', flat=True) )
eventsToCreate_djangoID = localEvents_djangoID - eventsAtGoogle_djangoID
eventsToDelete_googleID = eventsAtGoogle_googleID - localEvents_googleID
batch = BatchHttpRequest()
batchIsEmpty = True
for eventDjangoID in eventsToCreate_djangoID:
batch.add( createEvent( Event.objects.get( pk=eventDjangoID ) ), callback=onGcalEventCreated )
batchIsEmpty=False
for eventGoogleID in eventsToDelete_googleID:
batch.add( service.events().delete(calendarId='primary', eventId=eventGoogleID) )
batchIsEmpty=False
if not batchIsEmpty:
batch.execute()

View File

@ -0,0 +1,8 @@
from django.shortcuts import redirect
from eventplanner_gcal.models import syncGCalEvents
def runSync( request ):
syncGCalEvents()
return redirect("/")