From c6f5c9b14daead5cfffa13173168840ed2918cc0 Mon Sep 17 00:00:00 2001 From: Joey Orlando Date: Thu, 4 Apr 2024 12:03:40 -0400 Subject: [PATCH] Google Calendar integration improvements (#4147) # What this PR does - UI enhancements - Fix bug when going through the Google OAuth2 disconnection flow. We should send the `refresh_token` in the `revoke` HTTP request, rather than the `access_token` (`access_token` expires frequently and can result in Google sending back HTTP 400.. `refresh_token` is long lived and can also be sent in the revoke flow) ## Checklist - [ ] Unit, integration, and e2e (if applicable) tests updated - [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. --------- Co-authored-by: Maxim Mordasov --- engine/apps/social_auth/pipeline/google.py | 12 +++++- .../tabs/GoogleCalendar/GoogleCalendar.tsx | 40 +++++++++---------- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/engine/apps/social_auth/pipeline/google.py b/engine/apps/social_auth/pipeline/google.py index 065a69db..0d5fc609 100644 --- a/engine/apps/social_auth/pipeline/google.py +++ b/engine/apps/social_auth/pipeline/google.py @@ -22,6 +22,16 @@ def persist_access_and_refresh_tokens(backend: typing.Type[BaseAuth], response: def disconnect_user_google_oauth2_settings(backend: typing.Type[BaseAuth], user: User, *args, **kwargs): + """ + Don't use `google_oauth2_user.access_token` when revoking token, use `refresh_token` instead. If we use + the access token, we may get an HTTP 400 from Google because the token may be invalid or revoked. + + https://stackoverflow.com/a/18578660/3902555 + """ + logger.info(f"Disconnecting user {user.pk} from Google OAuth2") + # 2nd argument, uid, is not needed for GoogleOauth2 backend - backend.revoke_token(user.google_oauth2_user.access_token, "") + backend.revoke_token(user.google_oauth2_user.refresh_token, "") user.finish_google_oauth2_disconnection_flow() + + logger.info(f"Successfully disconnected user {user.pk} from Google OAuth2") diff --git a/grafana-plugin/src/containers/UserSettings/parts/tabs/GoogleCalendar/GoogleCalendar.tsx b/grafana-plugin/src/containers/UserSettings/parts/tabs/GoogleCalendar/GoogleCalendar.tsx index 1dc44487..efa91cc0 100644 --- a/grafana-plugin/src/containers/UserSettings/parts/tabs/GoogleCalendar/GoogleCalendar.tsx +++ b/grafana-plugin/src/containers/UserSettings/parts/tabs/GoogleCalendar/GoogleCalendar.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useState } from 'react'; import { css } from '@emotion/css'; -import { Button, HorizontalGroup, InlineSwitch, VerticalGroup, useStyles2 } from '@grafana/ui'; +import { Button, HorizontalGroup, Switch, VerticalGroup, useStyles2 } from '@grafana/ui'; import { observer } from 'mobx-react'; import { Block } from 'components/GBlock/Block'; @@ -21,11 +21,16 @@ const GoogleCalendar: React.FC<{ id: ApiSchemas['User']['pk'] }> = observer(({ i const styles = useStyles2(getStyles); - const user = userStore.items[id]; - const [googleCalendarSettings, setGoogleCalendarSettings] = useState(user?.google_calendar_settings); - const [showSchedulesDropdown, setShowSchedulesDropdown] = useState( - user.google_calendar_settings?.oncall_schedules_to_consider_for_shift_swaps?.length > 0 - ); + const [googleCalendarSettings, setGoogleCalendarSettings] = + useState(); + const [showSchedulesDropdown, setShowSchedulesDropdown] = useState(); + + useEffect(() => { + userStore.fetchItemById({ userPk: id }).then((user) => { + setGoogleCalendarSettings(user.google_calendar_settings); + setShowSchedulesDropdown(user.google_calendar_settings.oncall_schedules_to_consider_for_shift_swaps?.length > 0); + }); + }, []); const handleShowSchedulesDropdownChange = (event: React.ChangeEvent) => { const value = event.target.checked; @@ -36,12 +41,6 @@ const GoogleCalendar: React.FC<{ id: ApiSchemas['User']['pk'] }> = observer(({ i } }; - useEffect(() => { - if (user) { - setGoogleCalendarSettings(user.google_calendar_settings); - } - }, [user]); - const handleSchedulesChange = (value) => { setGoogleCalendarSettings((v) => ({ ...v, oncall_schedules_to_consider_for_shift_swaps: value })); @@ -50,10 +49,12 @@ const GoogleCalendar: React.FC<{ id: ApiSchemas['User']['pk'] }> = observer(({ i }); }; + const user = userStore.items[id]; + return ( - + {user.has_google_oauth2_connected ? ( @@ -71,7 +72,7 @@ const GoogleCalendar: React.FC<{ id: ApiSchemas['User']['pk'] }> = observer(({ i ) : ( - +
@@ -93,13 +94,10 @@ const GoogleCalendar: React.FC<{ id: ApiSchemas['User']['pk'] }> = observer(({ i {user.has_google_oauth2_connected && ( - + + + Specify the schedules to sync with Google calendar + {showSchedulesDropdown && (