oncall-engine/engine/apps/google/client.py
Joey Orlando 33364b63c6
Google Calendar Out of Office events - autogenerated shift swap requests (#4104)
# What this PR does

## Which issue(s) this PR closes

Closes https://github.com/grafana/oncall-private/issues/2590

## Checklist

- [x] Unit, integration, and e2e (if applicable) tests updated
- [x] Documentation added (or `pr:no public docs` PR label added if not
required) - will be done in
https://github.com/grafana/oncall-private/issues/2591
- [x] Added the relevant release notes label (see labels prefixed w/
`release:`). These labels dictate how your PR will
show up in the autogenerated release notes. - will be done in
https://github.com/grafana/oncall-private/issues/2591

---------

Co-authored-by: Dominik <dominik.broj@grafana.com>
Co-authored-by: Maxim Mordasov <maxim.mordasov@grafana.com>
2024-04-02 20:10:16 +00:00

84 lines
3.2 KiB
Python

import datetime
import logging
import typing
from django.conf import settings
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from apps.google import constants, utils
from apps.google.types import GoogleCalendarEvent as GoogleCalendarEventType
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
class GoogleCalendarEvent:
def __init__(self, event: GoogleCalendarEventType):
self.raw_event = event
self._start_time = utils.datetime_strptime(event["start"]["dateTime"])
self._end_time = utils.datetime_strptime(event["end"]["dateTime"])
self.start_time_utc = self._start_time.astimezone(datetime.timezone.utc)
self.end_time_utc = self._end_time.astimezone(datetime.timezone.utc)
class GoogleCalendarAPIClient:
MAX_NUMBER_OF_CALENDAR_EVENTS_TO_FETCH = 250
"""
By default the value is 250 events. The page size can never be larger than 2500 events
"""
CALENDAR_ID = "primary"
"""
for right now we only consider the user's primary calendar. If in the future we
want to allow the user to specify a different calendar, we'd need to [retrieve all their calendars](https://developers.google.com/calendar/v3/reference/calendarList/list)
, display this list to them + perist their choice
See `calendarId` under the "Parameters" section [here](https://developers.google.com/calendar/api/v3/reference/events/list)
"""
def __init__(self, access_token: str, refresh_token: str):
"""
https://developers.google.com/calendar/api/quickstart/python
https://google-auth.readthedocs.io/en/stable/reference/google.oauth2.credentials.html
"""
credentials = Credentials(
token=access_token,
refresh_token=refresh_token,
token_uri="https://www.googleapis.com/oauth2/v3/token",
client_id=settings.SOCIAL_AUTH_GOOGLE_OAUTH2_KEY,
client_secret=settings.SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET,
)
self.service = build("calendar", "v3", credentials=credentials)
def fetch_out_of_office_events(self) -> typing.List[GoogleCalendarEvent]:
"""
https://developers.google.com/calendar/api/v3/reference/events/list
"""
logger.info(
f"GoogleCalendarAPIClient - Getting the upcoming {self.MAX_NUMBER_OF_CALENDAR_EVENTS_TO_FETCH} "
"out of office events"
)
now = datetime.datetime.now(datetime.UTC)
time_min = utils.datetime_strftime(now)
time_max = utils.datetime_strftime(
now + datetime.timedelta(days=constants.DAYS_IN_FUTURE_TO_CONSIDER_OUT_OF_OFFICE_EVENTS)
)
events_result = (
self.service.events()
.list(
calendarId=self.CALENDAR_ID,
timeMin=time_min,
timeMax=time_max,
maxResults=self.MAX_NUMBER_OF_CALENDAR_EVENTS_TO_FETCH,
singleEvents=True,
orderBy="startTime",
eventTypes="outOfOffice",
)
.execute()
)
return [GoogleCalendarEvent(event) for event in events_result.get("items", [])]