From 25f89637496e93227a152254d1007a455e5e26b1 Mon Sep 17 00:00:00 2001 From: Joey Orlando Date: Mon, 15 Apr 2024 08:56:28 -0400 Subject: [PATCH] Google Calendar Integration + automatic Shift Swap Request generation (#4220) # What this PR does ## Which issue(s) this PR closes Closes https://github.com/grafana/oncall-private/issues/2591 ## Checklist - [ ] Unit, integration, and e2e (if applicable) tests updated (N/A) - [x] Documentation added (or `pr:no public docs` PR label added if not required) - [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. --- .../on-call-schedules/shift-swaps/index.md | 18 ++++++++++++++++++ engine/apps/api/views/features.py | 2 +- engine/settings/base.py | 9 +++++---- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/docs/sources/manage/on-call-schedules/shift-swaps/index.md b/docs/sources/manage/on-call-schedules/shift-swaps/index.md index a867dbc8..9b8d26d4 100644 --- a/docs/sources/manage/on-call-schedules/shift-swaps/index.md +++ b/docs/sources/manage/on-call-schedules/shift-swaps/index.md @@ -98,6 +98,24 @@ You can also check (and take) a swap request details in the web UI. Once a swap is taken, the affected rotations and the final schedule will reflect the changes. +## Google Calendar Integration + +Grafana OnCall allows you to connect your Google user to your OnCall user, giving us read-only access to your +Google Calendar's Out of Office events. We periodically check your Out of Office events to see if these overlap +with any of your on-call shifts. If so, we'll go ahead and automatically generate a shift swap request for you! + +To link your Google user, simply head over to "View my profile" on the OnCall "Users" page. From there, follow the steps +under the Google Calendar tab. Once linked, you can further configure things, such as which OnCall schedules you would +like us to consider for automatic shift swap generation (by default we will consider all of the schedules that you +are involved in). + +### Configuring for open source + +1. Follow the instructions [here](https://developers.google.com/identity/protocols/oauth2) to setup your Google OAuth2 +application. +2. Create a Client ID for your OAuth2 app and set the `SOCIAL_AUTH_GOOGLE_OAUTH2_KEY` and `SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET` +environment variables accordingly. + {{% docs/reference %}} [mobile push notification]: "/docs/oncall/ -> /docs/oncall//manage/mobile-app/push-notifications#shift-swap-notifications" [mobile push notification]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/oncall/manage/mobile-app/push-notifications#shift-swap-notifications" diff --git a/engine/apps/api/views/features.py b/engine/apps/api/views/features.py index cad151b8..acd98de8 100644 --- a/engine/apps/api/views/features.py +++ b/engine/apps/api/views/features.py @@ -65,7 +65,7 @@ class FeaturesAPIView(APIView): if is_labels_feature_enabled(self.request.auth.organization): enabled_features.append(Feature.LABELS) - if settings.FEATURE_GOOGLE_OAUTH2_ENABLED: + if settings.GOOGLE_OAUTH2_ENABLED: enabled_features.append(Feature.GOOGLE_OAUTH2) return enabled_features diff --git a/engine/settings/base.py b/engine/settings/base.py index 4fe03513..aebee7a2 100644 --- a/engine/settings/base.py +++ b/engine/settings/base.py @@ -71,7 +71,6 @@ GRAFANA_CLOUD_NOTIFICATIONS_ENABLED = getenv_boolean("GRAFANA_CLOUD_NOTIFICATION FEATURE_LABELS_ENABLED_FOR_ALL = getenv_boolean("FEATURE_LABELS_ENABLED_FOR_ALL", default=False) # Enable labels feature for organizations from the list. Use OnCall organization ID, for this flag FEATURE_LABELS_ENABLED_PER_ORG = getenv_list("FEATURE_LABELS_ENABLED_PER_ORG", default=list()) -FEATURE_GOOGLE_OAUTH2_ENABLED = getenv_boolean("FEATURE_GOOGLE_OAUTH2_ENABLED", default=False) TWILIO_API_KEY_SID = os.environ.get("TWILIO_API_KEY_SID") TWILIO_API_KEY_SECRET = os.environ.get("TWILIO_API_KEY_SECRET") @@ -650,15 +649,17 @@ AUTHENTICATION_BACKENDS = [ "apps.social_auth.backends.GoogleOAuth2", ] -if FEATURE_GOOGLE_OAUTH2_ENABLED: +SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = os.environ.get("SOCIAL_AUTH_GOOGLE_OAUTH2_KEY") +SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = os.environ.get("SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET") +GOOGLE_OAUTH2_ENABLED = SOCIAL_AUTH_GOOGLE_OAUTH2_KEY is not None and SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET is not None + +if GOOGLE_OAUTH2_ENABLED: CELERY_BEAT_SCHEDULE["sync_google_calendar_out_of_office_events_for_all_users"] = { "task": "apps.google.tasks.sync_out_of_office_calendar_events_for_all_users", "schedule": crontab(minute="*/30"), # every 30 minutes "args": (), } -SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = os.environ.get("SOCIAL_AUTH_GOOGLE_OAUTH2_KEY") -SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = os.environ.get("SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET") # NOTE: for right now we probably only need the calendar.events.readonly scope # however, if we want to write events back to the user's calendar # we'll probably need to change this to the calendar.events scope