Google calendar sync
This commit is contained in:
parent
a85e2472f1
commit
ba0cde09c1
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
|
|
@ -2,12 +2,14 @@ from django.db import models
|
|||
from django.utils.translation import ugettext as _
|
||||
from django.contrib.auth.models import User, Permission
|
||||
|
||||
|
||||
from django.db.models import Q
|
||||
|
||||
from datetime import datetime
|
||||
from location_field.models import PlainLocationField
|
||||
|
||||
from django.db.models import Q
|
||||
from django.dispatch import Signal
|
||||
|
||||
|
||||
|
||||
|
||||
class NoNextEventException( Exception ):
|
||||
def __str__(self):
|
||||
|
@ -114,6 +116,9 @@ class Event ( models.Model ):
|
|||
return nextEvent
|
||||
|
||||
|
||||
before_read = Signal()
|
||||
|
||||
|
||||
class EventParticipation( models.Model ):
|
||||
OPTIONS = ( ('?' , _('?' )),
|
||||
('Yes', _('Yes')),
|
||||
|
@ -125,6 +130,7 @@ class EventParticipation( models.Model ):
|
|||
status = models.CharField ( max_length=3, choices = OPTIONS, default='?', verbose_name=_("status") )
|
||||
comment = models.CharField ( max_length=64, blank=True, verbose_name=_("comment") )
|
||||
|
||||
|
||||
def get_username(self):
|
||||
return self.user.username
|
||||
|
||||
|
@ -141,6 +147,10 @@ class EventParticipation( models.Model ):
|
|||
else:
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def raiseBeforeReadSignal():
|
||||
before_read.send( sender=EventParticipation )
|
||||
|
||||
@staticmethod
|
||||
def isMember( user ):
|
||||
return user.has_perm('eventplanner.member')
|
||||
|
|
|
@ -6,7 +6,6 @@ from django.forms import TextInput
|
|||
|
||||
from models import Event, EventParticipation
|
||||
|
||||
|
||||
from serializers import ParticipationSerializer
|
||||
|
||||
import datetime
|
||||
|
@ -62,6 +61,7 @@ def eventplanning( request ):
|
|||
"""
|
||||
View for a specific user, to edit his events
|
||||
"""
|
||||
EventParticipation.raiseBeforeReadSignal()
|
||||
# non-members see the grid - but cannot edit anything
|
||||
if not EventParticipation.isMember( request.user ):
|
||||
return events_grid(request)
|
||||
|
@ -78,6 +78,8 @@ def eventplanning( request ):
|
|||
|
||||
|
||||
def events_grid( request ):
|
||||
EventParticipation.raiseBeforeReadSignal()
|
||||
|
||||
usernames = [ u.username for u in EventParticipation.members() ]
|
||||
|
||||
all_future_events = list ( Event.objects.filter( date__gte = datetime.date.today() ).order_by( 'date') )
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
__author__ = 'martin'
|
||||
import signals
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
from oauth2client.client import OAuth2WebServerFlow
|
||||
from oauth2client.file import Storage
|
||||
|
||||
|
||||
flow = OAuth2WebServerFlow(client_id='34462582242-4kpdvvbi27ajt4u22uitqurpve9o8ipj.apps.googleusercontent.com',
|
||||
client_secret='y4t9XBrJdCODPTO5UvtONWWn',
|
||||
scope='https://www.googleapis.com/auth/calendar',
|
||||
redirect_uri='http://localhost')
|
||||
|
||||
createLink = False
|
||||
if createLink:
|
||||
auth_uri = flow.step1_get_authorize_url()
|
||||
print "AuthURI:"
|
||||
print auth_uri
|
||||
print "Visit this link - grab the key from the url and paste it into the else block"
|
||||
exit(0)
|
||||
else:
|
||||
code = "4/Iais8aK8_KxbMQjq3Rtw3PFXu6Nr.8itpukY_6ZgZOl05ti8ZT3ax27a3hAI"
|
||||
credentials = flow.step2_exchange( code )
|
||||
storage = Storage('calendarCredentials.dat')
|
||||
storage.put( credentials )
|
|
@ -0,0 +1,76 @@
|
|||
from oauth2client.client import OAuth2WebServerFlow
|
||||
from apiclient.discovery import build
|
||||
from oauth2client.file import Storage
|
||||
import httplib2
|
||||
|
||||
|
||||
flow = OAuth2WebServerFlow(client_id='34462582242-4kpdvvbi27ajt4u22uitqurpve9o8ipj.apps.googleusercontent.com',
|
||||
client_secret='y4t9XBrJdCODPTO5UvtONWWn',
|
||||
scope='https://www.googleapis.com/auth/calendar',
|
||||
redirect_uri='http://localhost')
|
||||
|
||||
|
||||
#auth_uri = flow.step1_get_authorize_url()
|
||||
#print "AuthURI:"
|
||||
#print auth_uri
|
||||
#exit(0)
|
||||
|
||||
#code="4/z524dROAcIc24igDftg99LqjyJPG.4jR5ZcA_RPYaOl05ti8ZT3a5aIW3hAI"
|
||||
#credentials = flow.step2_exchange( code )
|
||||
|
||||
storage = Storage('calendarCredentials.dat')
|
||||
credentials = storage.get()
|
||||
if credentials is None or credentials.invalid == True:
|
||||
print "Invalid credentials"
|
||||
exit( 0)
|
||||
|
||||
|
||||
http = httplib2.Http()
|
||||
http = credentials.authorize( http )
|
||||
service = build( serviceName='calendar', version='v3', http=http, developerKey='blechreiz-homepage' )
|
||||
calendarId = 'blechreizensemble@gmail.com'
|
||||
|
||||
|
||||
def getEvents(pageToken=None):
|
||||
events = service.events().list(
|
||||
calendarId='primary',
|
||||
singleEvents=True,
|
||||
maxResults=1000,
|
||||
orderBy='startTime',
|
||||
timeMin='2012-11-01T00:00:00-08:00',
|
||||
timeMax='2018-11-30T00:00:00-08:00',
|
||||
pageToken=pageToken,
|
||||
).execute()
|
||||
return events
|
||||
|
||||
|
||||
def createEvent():
|
||||
print ( "Creating Event ")
|
||||
event = {
|
||||
'summary': 'Blechreiz Probe',
|
||||
'description': 'Eine Beschreibung.. bitte alle instrumente mitbringen',
|
||||
'location': 'Rohr',
|
||||
'start': {
|
||||
'dateTime': '2014-03-23T19:00:00',
|
||||
'timeZone': 'Europe/Berlin'
|
||||
},
|
||||
'end': {
|
||||
'dateTime': '2014-03-23T23:05:00',
|
||||
'timeZone': 'Europe/Berlin'
|
||||
},
|
||||
'attendees': [
|
||||
{
|
||||
'id': 'martinbauer86@gmail.com',
|
||||
'email': 'martinbauer86@gmail.com',
|
||||
'displayName': "MartinB",
|
||||
},
|
||||
],
|
||||
}
|
||||
created_event = service.events().insert(calendarId='primary', body=event).execute()
|
||||
|
||||
|
||||
print created_event['id']
|
||||
|
||||
|
||||
#createEvent()
|
||||
print getEvents()
|
|
@ -106,13 +106,20 @@ def buildGCalEvent( event, timezone="Europe/Berlin" ):
|
|||
|
||||
# -------------------------------------------------------------------------------
|
||||
|
||||
def getAllGCalEvents(pageToken=None):
|
||||
def getAllGCalEvents( fromNow=False, pageToken=None ):
|
||||
|
||||
if fromNow:
|
||||
now = datetime.datetime.now()
|
||||
minTime = now.strftime("%Y-%m-%dT%H:%M:%S-00:00")
|
||||
else:
|
||||
minTime = '2000-01-01T00:00:00-00:00'
|
||||
|
||||
events = service.events().list(
|
||||
calendarId='primary',
|
||||
singleEvents=True,
|
||||
maxResults=1000,
|
||||
orderBy='startTime',
|
||||
timeMin='2000-01-01T00:00:00-00:00',
|
||||
timeMin=minTime,
|
||||
timeMax='2100-01-01T00:00:00-00:00',
|
||||
pageToken=pageToken,
|
||||
privateExtendedProperty='blechreizEvent=true',
|
||||
|
@ -208,3 +215,25 @@ def syncGCalEvents():
|
|||
return len (eventsToCreate_djangoID), len(eventsToDelete_googleID )
|
||||
|
||||
|
||||
def syncParticipationFromGoogleToLocal():
|
||||
allEvents = getAllGCalEvents(fromNow=True)
|
||||
|
||||
for e in allEvents:
|
||||
localId = e['extendedProperties']['private']['blechreizID']
|
||||
localEvent = Event.objects.get( pk=localId )
|
||||
for a in e['attendees']:
|
||||
user = User.objects.get( email= a['email'] )
|
||||
part = EventParticipation.get_or_create( user, localEvent )
|
||||
if 'comment' in a:
|
||||
part.comment = a['comment']
|
||||
|
||||
if a['responseStatus'] == 'needsAction' or a['responseStatus']=='tentative':
|
||||
part.status = '?'
|
||||
elif a['responseStatus'] == 'accepted':
|
||||
part.status = 'Yes'
|
||||
elif a['responseStatus'] == 'declined':
|
||||
part.status = 'No'
|
||||
else:
|
||||
logger.error("Unknown response status when mapping gcal event: " + a['responseStatus'] )
|
||||
|
||||
part.save()
|
|
@ -1,27 +1,67 @@
|
|||
from django.db.models.signals import post_save,pre_delete
|
||||
from django.dispatch import receiver
|
||||
from eventplanner.models import Event, EventParticipation
|
||||
from eventplanner.models import Event, EventParticipation, before_read
|
||||
|
||||
from eventplanner_gcal.models import createGCalEvent, updateGCalEvent
|
||||
from eventplanner_gcal.models import deleteGCalEvent, syncParticipationFromGoogleToLocal
|
||||
|
||||
|
||||
class SignalLock:
|
||||
def __init__(self):
|
||||
self.locked=False
|
||||
|
||||
def __enter__(self):
|
||||
if self.locked:
|
||||
return False
|
||||
|
||||
self.locked=True
|
||||
return True
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
self.locked=False
|
||||
|
||||
def isLocked(self):
|
||||
return self.locked
|
||||
|
||||
signalLock = SignalLock()
|
||||
|
||||
from eventplanner_gcal.models import createGCalEvent, updateGCalEvent, deleteGCalEvent
|
||||
|
||||
@receiver( post_save,sender= Event)
|
||||
def event_post_save_handler(event, **kwargs):
|
||||
created = kwargs['created']
|
||||
if created:
|
||||
createGCalEvent( event ).execute()
|
||||
else:
|
||||
updateGCalEvent( event ).execute()
|
||||
def event_post_save_handler( **kwargs):
|
||||
if not signalLock.isLocked():
|
||||
with signalLock:
|
||||
event = kwargs['instance']
|
||||
created = kwargs['created']
|
||||
if created:
|
||||
print("Creating Gcal event")
|
||||
createGCalEvent( event ).execute()
|
||||
else:
|
||||
print( "Updating Gcal event")
|
||||
updateGCalEvent( event ).execute()
|
||||
|
||||
|
||||
|
||||
@receiver( pre_delete,sender= Event)
|
||||
def event_pre_delete_handler(event, **kwargs):
|
||||
deleteGCalEvent( event ).execute()
|
||||
|
||||
def event_pre_delete_handler( **kwargs):
|
||||
if not signalLock.isLocked():
|
||||
with signalLock:
|
||||
event = kwargs['instance']
|
||||
print ("Deleting GCAL event")
|
||||
deleteGCalEvent( event ).execute()
|
||||
|
||||
|
||||
@receiver( post_save, sender=EventParticipation )
|
||||
def participation_post_save_handler(participation, **kwargs):
|
||||
updateGCalEvent( participation.event ).execute()
|
||||
|
||||
def participation_post_save_handler( **kwargs):
|
||||
if not signalLock.isLocked():
|
||||
with signalLock:
|
||||
participation = kwargs['instance']
|
||||
print("Participation post save -> update gcal")
|
||||
updateGCalEvent( participation.event ).execute()
|
||||
|
||||
|
||||
@receiver( before_read, sender=EventParticipation )
|
||||
def participation_before_read_handler( **kwargs):
|
||||
if not signalLock.isLocked():
|
||||
with signalLock:
|
||||
print("SyncParticipation from google")
|
||||
syncParticipationFromGoogleToLocal()
|
Loading…
Reference in New Issue