Started with google calendar coupling
This commit is contained in:
parent
5a3d739a9b
commit
ee37a5ddcb
|
@ -158,6 +158,7 @@ INSTALLED_APPS = (
|
|||
'website', # Blechreiz Website in general
|
||||
'musicians', # User Management
|
||||
'eventplanner', # Event Management
|
||||
'eventplanner_gcal', # Event Management Sync with Google Calendar
|
||||
'simpleforum', # Messages ( Forum )
|
||||
'location_field', # custom location field used in Event Management
|
||||
'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'
|
||||
|
||||
# A sample logging configuration. The only tangible logging
|
||||
|
|
|
@ -10,6 +10,8 @@ import musicians.urls
|
|||
import website.urls
|
||||
import scoremanager.urls
|
||||
|
||||
from eventplanner_gcal.views import *
|
||||
|
||||
import settings
|
||||
from django.conf.urls.static import static
|
||||
|
||||
|
@ -24,4 +26,5 @@ urlpatterns = patterns('',
|
|||
url(r'^admin/', include(admin.site.urls) ),
|
||||
url(r'^location_field/', include('location_field.urls')),
|
||||
#url(r'^gallery/', include(imagestore.urls, namespace='imagestore') ),
|
||||
url(r'^eventSync/', runSync )
|
||||
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
__author__ = 'martin'
|
|
@ -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}
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -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()
|
|
@ -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()
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
from django.shortcuts import redirect
|
||||
|
||||
from eventplanner_gcal.models import syncGCalEvents
|
||||
|
||||
def runSync( request ):
|
||||
syncGCalEvents()
|
||||
return redirect("/")
|
||||
|
Loading…
Reference in New Issue