Various fixes
This commit is contained in:
7
eventplanner_gcal/admin.py
Normal file
7
eventplanner_gcal/admin.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from .models import GCalMapping, GCalPushChannel, UserGCalCoupling
|
||||
|
||||
admin.site.register(UserGCalCoupling)
|
||||
admin.site.register(GCalMapping)
|
||||
admin.site.register(GCalPushChannel)
|
||||
@@ -79,11 +79,20 @@ def create_gcal_service_object():
|
||||
return None
|
||||
|
||||
|
||||
def _invalidate_service_on_error(exc):
|
||||
"""Reset the cached service object so the next call retries credential loading."""
|
||||
global _service_object
|
||||
logger.warning(f"Invalidating cached GCal service due to error: {exc}")
|
||||
_service_object = None
|
||||
|
||||
|
||||
def get_service_object():
|
||||
"""Get or create the Google Calendar service object."""
|
||||
global _service_object
|
||||
if _service_object is None:
|
||||
_service_object = create_gcal_service_object()
|
||||
if _service_object is None:
|
||||
logger.error("Failed to create Google Calendar service object")
|
||||
return _service_object
|
||||
|
||||
|
||||
@@ -93,6 +102,12 @@ def reset_service_object():
|
||||
_service_object = None
|
||||
|
||||
|
||||
def get_service_object_fresh():
|
||||
"""Force-create a new service object, bypassing and replacing the cache."""
|
||||
reset_service_object()
|
||||
return get_service_object()
|
||||
|
||||
|
||||
# --------------------- Building GCal event representation ------------------------------------
|
||||
|
||||
|
||||
@@ -303,6 +318,7 @@ def delete_all_gcal_events(service=None):
|
||||
batch.execute()
|
||||
except Exception as e:
|
||||
logger.error(f"Error deleting GCal events: {e}")
|
||||
_invalidate_service_on_error(e)
|
||||
|
||||
GCalMapping.objects.all().delete()
|
||||
|
||||
@@ -389,6 +405,7 @@ def sync_from_local_to_google(service=None):
|
||||
batch.execute()
|
||||
except Exception as e:
|
||||
logger.error(f"Error executing batch request: {e}")
|
||||
_invalidate_service_on_error(e)
|
||||
|
||||
return len(events_to_create_django_id), len(events_to_delete_google_id)
|
||||
|
||||
@@ -485,33 +502,39 @@ def check_gcal_subscription(
|
||||
|
||||
callback_url = settings.GCAL_COUPLING["push_url"]
|
||||
|
||||
try:
|
||||
db_channel = GCalPushChannel.objects.get(address=callback_url)
|
||||
channels = GCalPushChannel.objects.filter(address=callback_url)
|
||||
|
||||
cur_time = int(time.time() * 1000)
|
||||
if channels.count() > 1:
|
||||
logger.warning(
|
||||
f"Multiple GCal channels found for {callback_url}. Stopping all and creating fresh one."
|
||||
)
|
||||
for ch in channels:
|
||||
ch.stop(service)
|
||||
channels = GCalPushChannel.objects.none()
|
||||
|
||||
if db_channel.expiration > cur_time:
|
||||
# not yet expired
|
||||
if cur_time + renew_before_expiry * 1000 > db_channel.expiration:
|
||||
# will expire in less than "renew_before_expiry"
|
||||
logger.info(f"Renewing Google Calendar Subscription: {callback_url}")
|
||||
db_channel.stop(service)
|
||||
GCalPushChannel.create_new(callback_url, service, time_to_live)
|
||||
else:
|
||||
logger.info(f"Channel active until {db_channel.expiration}")
|
||||
else:
|
||||
logger.info(
|
||||
"Google calendar subscription had expired - getting new subscription"
|
||||
)
|
||||
# to get back in sync again we have to decide which data to take
|
||||
# so we use the local data as reference
|
||||
sync_from_local_to_google(service)
|
||||
GCalPushChannel.create_new(callback_url, service, time_to_live)
|
||||
db_channel = channels.first()
|
||||
|
||||
except GCalPushChannel.DoesNotExist:
|
||||
if db_channel is None:
|
||||
logger.info(f"No GCalCallback Channel exists yet for: {callback_url}")
|
||||
# to get back in sync again we have to decide which data to take
|
||||
# so we use the local data as reference
|
||||
sync_from_local_to_google(service)
|
||||
GCalPushChannel.create_new(callback_url, service, time_to_live)
|
||||
return
|
||||
|
||||
cur_time = int(time.time() * 1000)
|
||||
|
||||
if db_channel.expiration > cur_time:
|
||||
# not yet expired
|
||||
if cur_time + renew_before_expiry * 1000 > db_channel.expiration:
|
||||
# will expire in less than "renew_before_expiry"
|
||||
logger.info(f"Renewing Google Calendar Subscription: {callback_url}")
|
||||
db_channel.stop(service)
|
||||
GCalPushChannel.create_new(callback_url, service, time_to_live)
|
||||
else:
|
||||
logger.info(f"Channel active until {db_channel.expiration}")
|
||||
else:
|
||||
logger.info(
|
||||
"Google calendar subscription had expired - getting new subscription"
|
||||
)
|
||||
sync_from_local_to_google(service)
|
||||
GCalPushChannel.create_new(callback_url, service, time_to_live)
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
from django.core.management.base import NoArgsCommand
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
from eventplanner_gcal.google_sync import checkGCalSubscription
|
||||
from eventplanner_gcal.google_sync import check_gcal_subscription
|
||||
|
||||
class Command(NoArgsCommand):
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Checks if the GCal notification channel is still active'
|
||||
def handle_noargs(self, **options):
|
||||
print ( "Checking Subscription")
|
||||
checkGCalSubscription()
|
||||
|
||||
def handle(self, *args, **options):
|
||||
self.stdout.write('Checking Subscription')
|
||||
check_gcal_subscription()
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
from django.core.management.base import NoArgsCommand
|
||||
from eventplanner_gcal.google_sync import deleteAllGCalEvents
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
class Command(NoArgsCommand):
|
||||
from eventplanner_gcal.google_sync import delete_all_gcal_events
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
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, ) )
|
||||
|
||||
def handle(self, *args, **options):
|
||||
self.stdout.write('Deleting all GCal Events.')
|
||||
nr_deleted = delete_all_gcal_events()
|
||||
self.stdout.write(f'Deleted {nr_deleted} events. To restore them run gcal_sync')
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
from django.core.management.base import NoArgsCommand
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
from eventplanner_gcal.google_sync import stopAllGCalSubscriptions
|
||||
from eventplanner_gcal.google_sync import stop_all_gcal_subscriptions
|
||||
|
||||
class Command(NoArgsCommand):
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Stops all GCal subscriptions'
|
||||
def handle_noargs(self, **options):
|
||||
stopAllGCalSubscriptions()
|
||||
|
||||
def handle(self, *args, **options):
|
||||
stop_all_gcal_subscriptions()
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
from django.core.management.base import NoArgsCommand
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
from eventplanner_gcal.google_sync import syncFromLocalToGoogle
|
||||
from eventplanner_gcal.google_sync import sync_from_local_to_google
|
||||
|
||||
class Command(NoArgsCommand):
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Synchronize Google Calendar with locally stored Events'
|
||||
def handle_noargs(self, **options):
|
||||
print ( "Running Sync")
|
||||
created, deleted = syncFromLocalToGoogle()
|
||||
print ( "Created %d and deleted %d events" % (created,deleted) )
|
||||
|
||||
def handle(self, *args, **options):
|
||||
self.stdout.write('Running Sync')
|
||||
created, deleted = sync_from_local_to_google()
|
||||
self.stdout.write(f'Created {created} and deleted {deleted} events')
|
||||
|
||||
@@ -4,6 +4,7 @@ Views for Google Calendar integration management.
|
||||
|
||||
import logging
|
||||
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import redirect, render
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
@@ -18,12 +19,14 @@ from .models import UserGCalCoupling
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@login_required
|
||||
def run_sync(request):
|
||||
"""Manually trigger a sync from local to Google Calendar."""
|
||||
sync_from_local_to_google()
|
||||
return redirect("/")
|
||||
|
||||
|
||||
@login_required
|
||||
def manage(request):
|
||||
"""
|
||||
View for managing Google Calendar integration settings.
|
||||
|
||||
Reference in New Issue
Block a user