diff --git a/eventplanner_gcal/management/__init__.py b/eventplanner_gcal/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/eventplanner_gcal/management/commands/events_gcal_sync.py b/eventplanner_gcal/management/commands/events_gcal_sync.py deleted file mode 100644 index a810ad0..0000000 --- a/eventplanner_gcal/management/commands/events_gcal_sync.py +++ /dev/null @@ -1,10 +0,0 @@ -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() diff --git a/eventplanner_gcal/management/commands/gcal_delete_all.py b/eventplanner_gcal/management/commands/gcal_delete_all.py new file mode 100644 index 0000000..a01ec21 --- /dev/null +++ b/eventplanner_gcal/management/commands/gcal_delete_all.py @@ -0,0 +1,9 @@ +from django.core.management.base import NoArgsCommand +from eventplanner_gcal.models import deleteAllGCalEvents + +class Command(NoArgsCommand): + help = 'Delete all events in the google calendar created by this app' + def handle_noargs(self, **options): + print ("Deleting all GCal Events.") + nrOfDeletedEvents = deleteAllGCalEvents() + print ("Deleted %d events. To Restore them from local database run gcal_sync" % (nrOfDeletedEvents, ) ) diff --git a/eventplanner_gcal/management/commands/gcal_sync.py b/eventplanner_gcal/management/commands/gcal_sync.py new file mode 100644 index 0000000..36601b1 --- /dev/null +++ b/eventplanner_gcal/management/commands/gcal_sync.py @@ -0,0 +1,10 @@ +from django.core.management.base import NoArgsCommand + +from eventplanner_gcal.models import syncGCalEvents + +class Command(NoArgsCommand): + help = 'Synchronize Google Calendar with locally stored Events' + def handle_noargs(self, **options): + print ( "Running Sync") + created, deleted = syncGCalEvents() + print ( "Created %d and deleted %d events" % (created,deleted) ) diff --git a/eventplanner_gcal/models.py b/eventplanner_gcal/models.py index 423e42c..64683a2 100644 --- a/eventplanner_gcal/models.py +++ b/eventplanner_gcal/models.py @@ -65,7 +65,7 @@ def createAttendeesObj( event ): return result -def createEvent( event, timezone="Europe/Berlin" ): +def buildGCalEvent( event, timezone="Europe/Berlin" ): if service is None: logger.error("createEvent: Google API connection not configured") return @@ -89,7 +89,7 @@ def createEvent( event, timezone="Europe/Berlin" ): else: endTime = datetime.time( 22, 30 ) - googleEvent = { + return { 'summary': unicode(settings.GCAL_COUPLING['eventPrefix'] + event.title), 'description': unicode(event.desc), 'location': unicode(event.location), @@ -103,10 +103,10 @@ def createEvent( event, timezone="Europe/Berlin" ): }, 'attendees': createAttendeesObj( event ), } - return service.events().insert(calendarId='primary', body=googleEvent) +# ------------------------------------------------------------------------------- -def getAllEvents(pageToken=None): +def getAllGCalEvents(pageToken=None): events = service.events().list( calendarId='primary', singleEvents=True, @@ -120,15 +120,43 @@ def getAllEvents(pageToken=None): return events['items'] -def onGcalEventCreated( request_id, response, exception ): - if exception is not None: - print ( "response " + str( response ) ) - raise exception +def createGCalEvent( event, timezone="Europe/Berlin" ): + googleEvent = buildGCalEvent(event,timezone) + return service.events().insert(calendarId='primary', body=googleEvent) + +def updateGCalEvent( event, timezone="Europe/Berlin"): + googleEvent = buildGCalEvent(event,timezone) + mapping = GCalMapping.objects.get( event=event ) + gcalId = mapping.gcal_id + return service.events().patch(calendarId='primary', eventId= gcalId, body=googleEvent) + +def deleteGCalEvent( event ): + mapping = GCalMapping.objects.get( event=event ) + gcalId = mapping.gcal_id + return service.events().delete(calendarId='primary', eventId=gcalId) + + + +# ------------------------------------------------------------------------------- + +def deleteAllGCalEvents(): + if service is None: + logger.error("deleteAllGCalEvents: Google API connection not configured") + return + + gcalIds = [ ev['id'] for ev in getAllGCalEvents() ] + l = len(gcalIds) + if l == 0: + return l + + batch = BatchHttpRequest() + for id in gcalIds: + batch.add( service.events().delete(calendarId='primary', eventId=id) ) + batch.execute() + + return l + - googleId = response['id'] - djangoId = response['extendedProperties']['private']['blechreizID'] - mapping = GCalMapping( gcal_id = googleId, event = Event.objects.get( pk=djangoId ) ) - mapping.save() def syncGCalEvents(): @@ -136,7 +164,7 @@ def syncGCalEvents(): logger.error("syncGCalEvents: Google API connection not configured") return - allEvents = getAllEvents() + allEvents = getAllGCalEvents() eventsAtGoogle_djangoID = set() eventsAtGoogle_googleID = set() @@ -151,11 +179,23 @@ def syncGCalEvents(): eventsToDelete_googleID = eventsAtGoogle_googleID - localEvents_googleID + def onGcalEventCreated( request_id, response, exception ): + """Callback function for created events""" + 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() + + batch = BatchHttpRequest() batchIsEmpty = True for eventDjangoID in eventsToCreate_djangoID: - batch.add( createEvent( Event.objects.get( pk=eventDjangoID ) ), callback=onGcalEventCreated ) + batch.add( createGCalEvent( Event.objects.get( pk=eventDjangoID ) ), callback=onGcalEventCreated ) batchIsEmpty=False for eventGoogleID in eventsToDelete_googleID: @@ -165,7 +205,6 @@ def syncGCalEvents(): if not batchIsEmpty: batch.execute() - - + return len (eventsToCreate_djangoID), len(eventsToDelete_googleID ) diff --git a/eventplanner_gcal/signals.py b/eventplanner_gcal/signals.py new file mode 100644 index 0000000..bc73d63 --- /dev/null +++ b/eventplanner_gcal/signals.py @@ -0,0 +1,27 @@ +from django.db.models.signals import post_save,pre_delete +from django.dispatch import receiver +from eventplanner.models import Event, EventParticipation + +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() + + +@receiver( pre_delete,sender= Event) +def event_pre_delete_handler(event, **kwargs): + deleteGCalEvent( event ).execute() + + + +@receiver( post_save, sender=EventParticipation ) +def participation_post_save_handler(participation, **kwargs): + updateGCalEvent( participation.event ).execute() + + +