reservations: Sync external Google Calendar events into database
This commit is contained in:
parent
e4280361d1
commit
927e2f4b90
31
reservations/migrations/0002_externalreservation.py
Normal file
31
reservations/migrations/0002_externalreservation.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# Generated by Django 5.0.7 on 2024-08-06 17:17
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("reservations", "0001_initial"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="ExternalReservation",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"reservation_ptr",
|
||||||
|
models.OneToOneField(
|
||||||
|
auto_created=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
parent_link=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
to="reservations.reservation",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("title", models.CharField(max_length=1024)),
|
||||||
|
],
|
||||||
|
bases=("reservations.reservation",),
|
||||||
|
),
|
||||||
|
]
|
@ -132,3 +132,18 @@ class UserReservation(Reservation):
|
|||||||
return super().make_google_calendar_event() | {
|
return super().make_google_calendar_event() | {
|
||||||
"summary": str(self.user),
|
"summary": str(self.user),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ExternalReservation(Reservation):
|
||||||
|
"""Reservations created by something else in Google Calendar"""
|
||||||
|
|
||||||
|
title = models.CharField(max_length=1024)
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return f'External "{self.title}" | {super().__str__()}'
|
||||||
|
|
||||||
|
def make_google_calendar_event(self):
|
||||||
|
"""This should never be called, as these are reservations from Google Calendar and shouldn't be synced back"""
|
||||||
|
raise AttributeError(
|
||||||
|
"External Reservations should not be pushed back to Google Calendar"
|
||||||
|
)
|
||||||
|
@ -10,7 +10,7 @@ from googleapiclient.discovery import build
|
|||||||
from googleapiclient.errors import HttpError
|
from googleapiclient.errors import HttpError
|
||||||
|
|
||||||
from cmsmanage.django_q2_helper import q_task_group
|
from cmsmanage.django_q2_helper import q_task_group
|
||||||
from reservations.models import Reservation, Resource
|
from reservations.models import ExternalReservation, Reservation, Resource
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -110,12 +110,21 @@ def sync_resource_from_google_calendar(
|
|||||||
sendUpdates="none",
|
sendUpdates="none",
|
||||||
).execute()
|
).execute()
|
||||||
else:
|
else:
|
||||||
# TODO: handle external events (either Bookly or manually created)
|
|
||||||
# NOTE: this will also need to check for deleted events
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"Event in Google Calendar not originated by CMSManage: skipping for now | %s",
|
"Event in Google Calendar not originated by CMSManage: adding/updating as external reservation | %s",
|
||||||
event["id"],
|
event["id"],
|
||||||
)
|
)
|
||||||
|
# TODO: this might cause issues if something external
|
||||||
|
# creates events with matching IDs in different calendars
|
||||||
|
reservation, created = ExternalReservation.objects.update_or_create(
|
||||||
|
google_calendar_event_id=event["id"],
|
||||||
|
defaults={
|
||||||
|
"title": event["summary"],
|
||||||
|
"start": parse_google_calendar_datetime(event["start"]),
|
||||||
|
"end": parse_google_calendar_datetime(event["end"]),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
reservation.resources.add(resource)
|
||||||
|
|
||||||
return {event["id"] for event in events}
|
return {event["id"] for event in events}
|
||||||
|
|
||||||
@ -135,32 +144,39 @@ def sync_resource_from_database(
|
|||||||
|
|
||||||
# reservation has an event id, so check if we already handled it earlier
|
# reservation has an event id, so check if we already handled it earlier
|
||||||
elif reservation.google_calendar_event_id not in existing_event_ids:
|
elif reservation.google_calendar_event_id not in existing_event_ids:
|
||||||
# this event was in Google Calendar at some point (possibly for a different
|
if isinstance(reservation, ExternalReservation):
|
||||||
# resource/calendar), but did not appear in list(). Try to update it, then
|
logger.info(
|
||||||
# fall back to insert
|
"External event in database did not exist in future of Google Calendar: deleting locally | %s",
|
||||||
logger.info(
|
reservation.google_calendar_event_id,
|
||||||
"Reservation with event id not in Google Calendar: trying update | %s",
|
|
||||||
reservation.google_calendar_event_id,
|
|
||||||
)
|
|
||||||
try:
|
|
||||||
event = (
|
|
||||||
service.events()
|
|
||||||
.get(
|
|
||||||
calendarId=resource.google_calendar,
|
|
||||||
eventId=reservation.google_calendar_event_id,
|
|
||||||
)
|
|
||||||
.execute()
|
|
||||||
)
|
)
|
||||||
update_calendar_event(service, resource, event, reservation)
|
reservation.delete()
|
||||||
except HttpError as error:
|
else:
|
||||||
if error.status_code == HTTPStatus.NOT_FOUND:
|
# this event was in Google Calendar at some point (possibly for a different
|
||||||
logger.info(
|
# resource/calendar), but did not appear in list(). Try to update it, then
|
||||||
"Event in database not in Google Calendar: inserting | %s",
|
# fall back to insert
|
||||||
reservation.google_calendar_event_id,
|
logger.info(
|
||||||
|
"Reservation with event id not in Google Calendar: trying update | %s",
|
||||||
|
reservation.google_calendar_event_id,
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
event = (
|
||||||
|
service.events()
|
||||||
|
.get(
|
||||||
|
calendarId=resource.google_calendar,
|
||||||
|
eventId=reservation.google_calendar_event_id,
|
||||||
|
)
|
||||||
|
.execute()
|
||||||
)
|
)
|
||||||
insert_calendar_event(service, resource, reservation)
|
update_calendar_event(service, resource, event, reservation)
|
||||||
else:
|
except HttpError as error:
|
||||||
raise
|
if error.status_code == HTTPStatus.NOT_FOUND:
|
||||||
|
logger.info(
|
||||||
|
"Event in database not in Google Calendar: inserting | %s",
|
||||||
|
reservation.google_calendar_event_id,
|
||||||
|
)
|
||||||
|
insert_calendar_event(service, resource, reservation)
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
def sync_resource(service, resource: Resource, now: datetime):
|
def sync_resource(service, resource: Resource, now: datetime):
|
||||||
|
Loading…
Reference in New Issue
Block a user