GCal Mapping: Callback mechanism using channels
This commit is contained in:
committed by
Martin Bauer
parent
ba0cde09c1
commit
fcb04058b5
@@ -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() )
|
||||
Reference in New Issue
Block a user