GCal Mapping: Callback mechanism using channels

This commit is contained in:
Martin Bauer
2014-04-19 20:36:01 +02:00
committed by Martin Bauer
parent ba0cde09c1
commit fcb04058b5
16 changed files with 185 additions and 45 deletions

View File

@@ -1,3 +1,4 @@
from apiclient.channel import new_webhook_channel, Channel
from django.db import models
from eventplanner.models import Event, EventParticipation
@@ -11,17 +12,56 @@ from django.conf import settings
import logging
import datetime
from django.contrib.auth.models import User
import time
import uuid
logger = logging.getLogger(__name__)
class GCalMapping( models.Model ):
gcal_id = models.CharField( max_length=64 )
event = models.OneToOneField( Event, primary_key=True )
class GCalPushChannel( models.Model ):
"""This table has either zero or one entry. Required to store if a channel already exists,
when it expires, and how to stop (renew) the channel
"""
id = models.CharField( max_length=128, primary_key=True )
address = models.CharField( max_length=256 )
token = models.CharField( max_length=128 )
resource_id = models.CharField( max_length=128 )
expiration = models.IntegerField()
def toGChannel( self ):
return Channel( 'web_hook', self.id, self.token, self.address, self.expiration, resource_id = self.resource_id )
@staticmethod
def fromGChannel( gChannel ):
return GCalPushChannel( id = gChannel.id,
address = gChannel.address,
token = gChannel.token,
expiration = gChannel.expiration,
resource_id= gChannel.resource_id )
@staticmethod
def createNew( callbackUrl, service, ttl = None ):
gChannel = Channel('web_hook', str(uuid.uuid4()), 'blechreizGcal', callbackUrl, params= { 'ttl' : int(ttl) } )
response = service.events().watch( calendarId='primary', body= gChannel.body() ).execute()
gChannel.update( response )
dbChannel = GCalPushChannel.fromGChannel( gChannel )
dbChannel.save()
@staticmethod
def stop( service, gChannel ):
channelService = service.channels()
channelService.stop( body = gChannel.body() ).execute()
GCalPushChannel.fromGChannel( gChannel ).delete()
@@ -40,8 +80,8 @@ def init( gcal_settings ):
http=http, developerKey=gcal_settings['developerKey'] )
service = init( settings.GCAL_COUPLING )
service = init( settings.GCAL_COUPLING )
def createAttendeesObj( event ):
@@ -217,7 +257,6 @@ def syncGCalEvents():
def syncParticipationFromGoogleToLocal():
allEvents = getAllGCalEvents(fromNow=True)
for e in allEvents:
localId = e['extendedProperties']['private']['blechreizID']
localEvent = Event.objects.get( pk=localId )
@@ -236,4 +275,47 @@ def syncParticipationFromGoogleToLocal():
else:
logger.error("Unknown response status when mapping gcal event: " + a['responseStatus'] )
part.save()
part.save()
def checkGCalSubscription():
global service
callbackUrl = settings.GCAL_COUPLING['push_url']
#timeToLive = 14*24*3600 # how long the channel should be active
#renewBeforeExpiry = 2*24*3600 # duration before expiry when channel is renewed
timeToLive = 60*5
renewBeforeExpiry = 60*3
# Test if a channel already exists for this callbackURL
try:
dbChannel = GCalPushChannel.objects.get( address=callbackUrl )
gChannel = dbChannel.toGChannel()
# if expiration time between 0 and two days: stop and create new channel
curTime = int( time.time() * 1000)
if gChannel.expiration > curTime:
# not yet expired
if curTime + renewBeforeExpiry*1000 > gChannel.expiration:
#will expire in less than "renewBeforeExpiry"
print ( "Renewing Google Calendar Subscription: " + callbackUrl )
GCalPushChannel.stop( service, gChannel )
GCalPushChannel.createNew( callbackUrl, service, timeToLive )
else:
print ("Channel active until %d " % ( gChannel.expiration, ) )
else:
print( "Google calendar subscription had expired - getting new subscription" )
syncParticipationFromGoogleToLocal()
GCalPushChannel.createNew( callbackUrl, service, timeToLive )
except GCalPushChannel.DoesNotExist:
# create new channel and save it in database
print ( "No CGalCallback Channel exists yet for: " + callbackUrl )
syncParticipationFromGoogleToLocal()
GCalPushChannel.createNew( callbackUrl, service, timeToLive )
def stopAllGCalSubscriptions():
for dbChannel in GCalPushChannel.objects.all():
print("Stopping %s expiry at %d " % ( dbChannel.id, dbChannel.expiration ) )
GCalPushChannel.stop( service, dbChannel.toGChannel() )