fix: Updates gapi to use new google identity service.
fix: Updates gapi to use new google identity service.
This commit is contained in:
parent
29b6ce7721
commit
bbb339d86f
|
@ -52,6 +52,7 @@ export function loadGoogleAPI() {
|
|||
return Promise.resolve();
|
||||
})
|
||||
.then(() => dispatch(setGoogleAPIState(GOOGLE_API_STATES.LOADED)))
|
||||
.then(() => googleApi.signInIfNotSignedIn())
|
||||
.then(() => googleApi.isSignedIn())
|
||||
.then(isSignedIn => {
|
||||
if (isSignedIn) {
|
||||
|
@ -150,8 +151,7 @@ export function setGoogleAPIState(
|
|||
* selectedBoundStreamID: *} | never>)}
|
||||
*/
|
||||
export function showAccountSelection() {
|
||||
return () =>
|
||||
googleApi.showAccountSelection();
|
||||
return () => googleApi.showAccountSelection(true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -161,7 +161,7 @@ export function showAccountSelection() {
|
|||
*/
|
||||
export function signIn() {
|
||||
return (dispatch: Dispatch<any>) => googleApi.get()
|
||||
.then(() => googleApi.signInIfNotSignedIn())
|
||||
.then(() => googleApi.signInIfNotSignedIn(true))
|
||||
.then(() => dispatch({
|
||||
type: SET_GOOGLE_API_STATE,
|
||||
googleAPIState: GOOGLE_API_STATES.SIGNED_IN
|
||||
|
@ -205,10 +205,10 @@ export function updateProfile() {
|
|||
.then(profile => {
|
||||
dispatch({
|
||||
type: SET_GOOGLE_API_PROFILE,
|
||||
profileEmail: profile.getEmail()
|
||||
profileEmail: profile.email
|
||||
});
|
||||
|
||||
return profile.getEmail();
|
||||
return profile.email;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -20,10 +20,9 @@ export const API_URL_LIVE_BROADCASTS = 'https://content.googleapis.com/youtube/v
|
|||
/**
|
||||
* Array of API discovery doc URLs for APIs used by the googleApi.
|
||||
*
|
||||
* @type {string[]}
|
||||
* @type {string}
|
||||
*/
|
||||
export const DISCOVERY_DOCS
|
||||
= [ 'https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest' ];
|
||||
export const DISCOVERY_DOCS = 'https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest';
|
||||
|
||||
/**
|
||||
* An enumeration of the different states the Google API can be in.
|
||||
|
@ -61,6 +60,13 @@ export const GOOGLE_API_STATES = {
|
|||
*/
|
||||
export const GOOGLE_SCOPE_CALENDAR = 'https://www.googleapis.com/auth/calendar';
|
||||
|
||||
/**
|
||||
* Google API auth scope to access user email.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
export const GOOGLE_SCOPE_USERINFO = 'https://www.googleapis.com/auth/userinfo.email';
|
||||
|
||||
/**
|
||||
* Google API auth scope to access YouTube streams.
|
||||
*
|
||||
|
|
|
@ -3,10 +3,13 @@ import {
|
|||
API_URL_LIVE_BROADCASTS,
|
||||
DISCOVERY_DOCS,
|
||||
GOOGLE_SCOPE_CALENDAR,
|
||||
GOOGLE_SCOPE_USERINFO,
|
||||
GOOGLE_SCOPE_YOUTUBE
|
||||
} from './constants';
|
||||
import logger from './logger';
|
||||
|
||||
const GOOGLE_API_CLIENT_LIBRARY_URL = 'https://apis.google.com/js/api.js';
|
||||
const GOOGLE_GIS_LIBRARY_URL = 'https://accounts.google.com/gsi/client';
|
||||
|
||||
/**
|
||||
* A promise for dynamically loading the Google API Client Library.
|
||||
|
@ -50,9 +53,9 @@ const googleApi = {
|
|||
}
|
||||
|
||||
return this._getGoogleApiClient()
|
||||
.auth2.getAuthInstance()
|
||||
.currentUser.get()
|
||||
.getBasicProfile();
|
||||
.client.oauth2
|
||||
.userinfo.get().getPromise()
|
||||
.then(r => r.result);
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -68,23 +71,40 @@ const googleApi = {
|
|||
initializeClient(clientId, enableYoutube, enableCalendar) {
|
||||
return this.get()
|
||||
.then(api => new Promise((resolve, reject) => {
|
||||
const scope
|
||||
= `${enableYoutube ? GOOGLE_SCOPE_YOUTUBE : ''} ${enableCalendar ? GOOGLE_SCOPE_CALENDAR : ''}`
|
||||
.trim();
|
||||
|
||||
// setTimeout is used as a workaround for api.client.init not
|
||||
// resolving consistently when the Google API Client Library is
|
||||
// loaded asynchronously. See:
|
||||
// github.com/google/google-api-javascript-client/issues/399
|
||||
setTimeout(() => {
|
||||
api.client.init({
|
||||
clientId,
|
||||
discoveryDocs: DISCOVERY_DOCS,
|
||||
scope
|
||||
api.client.init({})
|
||||
.then(() => {
|
||||
if (enableCalendar) {
|
||||
api.client.load(DISCOVERY_DOCS);
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
api.client.load('https://www.googleapis.com/discovery/v1/apis/oauth2/v1/rest');
|
||||
})
|
||||
.then(resolve)
|
||||
.catch(reject);
|
||||
}, 500);
|
||||
}))
|
||||
.then(() => new Promise((resolve, reject) => {
|
||||
try {
|
||||
const scope
|
||||
= `${enableYoutube ? GOOGLE_SCOPE_YOUTUBE : ''} ${enableCalendar ? GOOGLE_SCOPE_CALENDAR : ''}`
|
||||
.trim();
|
||||
|
||||
this.tokenClient = this._getGoogleGISApiClient().accounts.oauth2.initTokenClient({
|
||||
// eslint-disable-next-line camelcase
|
||||
client_id: clientId,
|
||||
scope: `${scope} ${GOOGLE_SCOPE_USERINFO}`,
|
||||
callback: '' // defined at request time in await/promise scope.
|
||||
});
|
||||
resolve();
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
|
@ -95,13 +115,38 @@ const googleApi = {
|
|||
* @returns {Promise}
|
||||
*/
|
||||
isSignedIn() {
|
||||
return this.get()
|
||||
.then(api => Boolean(api
|
||||
&& api.auth2
|
||||
&& api.auth2.getAuthInstance
|
||||
&& api.auth2.getAuthInstance()
|
||||
&& api.auth2.getAuthInstance().isSignedIn
|
||||
&& api.auth2.getAuthInstance().isSignedIn.get()));
|
||||
return new Promise((resolve, _) => {
|
||||
const te = parseInt(this.tokenExpires, 10);
|
||||
const isExpired = isNaN(this.tokenExpires) ? true : new Date().getTime() > te;
|
||||
|
||||
resolve(Boolean(!isExpired));
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Generates a script tag.
|
||||
*
|
||||
* @param {string} src - The source for the script tag.
|
||||
* @returns {Promise<unknown>}
|
||||
* @private
|
||||
*/
|
||||
_loadScriptTag(src) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const scriptTag = document.createElement('script');
|
||||
|
||||
scriptTag.async = true;
|
||||
scriptTag.addEventListener('error', () => {
|
||||
scriptTag.remove();
|
||||
|
||||
reject();
|
||||
});
|
||||
scriptTag.addEventListener('load', resolve);
|
||||
scriptTag.type = 'text/javascript';
|
||||
|
||||
scriptTag.src = src;
|
||||
|
||||
document.head.appendChild(scriptTag);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -114,29 +159,19 @@ const googleApi = {
|
|||
return googleClientLoadPromise;
|
||||
}
|
||||
|
||||
googleClientLoadPromise = new Promise((resolve, reject) => {
|
||||
const scriptTag = document.createElement('script');
|
||||
|
||||
scriptTag.async = true;
|
||||
scriptTag.addEventListener('error', () => {
|
||||
scriptTag.remove();
|
||||
|
||||
googleClientLoadPromise = this._loadScriptTag(GOOGLE_API_CLIENT_LIBRARY_URL)
|
||||
.catch(() => {
|
||||
googleClientLoadPromise = null;
|
||||
|
||||
reject();
|
||||
});
|
||||
scriptTag.addEventListener('load', resolve);
|
||||
scriptTag.type = 'text/javascript';
|
||||
|
||||
scriptTag.src = GOOGLE_API_CLIENT_LIBRARY_URL;
|
||||
|
||||
document.head.appendChild(scriptTag);
|
||||
})
|
||||
})
|
||||
.then(() => new Promise((resolve, reject) =>
|
||||
this._getGoogleApiClient().load('client:auth2', {
|
||||
this._getGoogleApiClient().load('client', {
|
||||
callback: resolve,
|
||||
onerror: reject
|
||||
})))
|
||||
.then(this._loadScriptTag(GOOGLE_GIS_LIBRARY_URL))
|
||||
.catch(() => {
|
||||
googleClientLoadPromise = null;
|
||||
})
|
||||
.then(() => this._getGoogleApiClient());
|
||||
|
||||
return googleClientLoadPromise;
|
||||
|
@ -171,25 +206,50 @@ const googleApi = {
|
|||
* Prompts the participant to sign in to the Google API Client Library, even
|
||||
* if already signed in.
|
||||
*
|
||||
* @param {boolean} consent - Whether to show account selection dialog.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
showAccountSelection() {
|
||||
showAccountSelection(consent: boolean) {
|
||||
return this.get()
|
||||
.then(api => api.auth2.getAuthInstance().signIn());
|
||||
.then(api => new Promise((resolve, reject) => {
|
||||
try {
|
||||
// Settle this promise in the response callback for requestAccessToken()
|
||||
this.tokenClient.callback = resp => {
|
||||
if (resp.error !== undefined) {
|
||||
reject(resp);
|
||||
}
|
||||
|
||||
// Get the number of seconds the token is valid for, subtract 5 minutes
|
||||
// to account for differences in clock settings and convert to ms.
|
||||
const expiresIn = (parseInt(api.client.getToken().expires_in, 10) - 300) * 1000;
|
||||
const now = new Date();
|
||||
const expireDate = new Date(now.getTime() + expiresIn);
|
||||
|
||||
this.tokenExpires = expireDate.getTime().toString();
|
||||
|
||||
resolve(resp);
|
||||
};
|
||||
|
||||
this.tokenClient.requestAccessToken({ prompt: consent ? 'consent' : '' });
|
||||
} catch (err) {
|
||||
logger.error('Error requesting token', err);
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
* Prompts the participant to sign in to the Google API Client Library, if
|
||||
* not already signed in.
|
||||
*
|
||||
* @param {boolean} consent - Whether to show account selection dialog.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
signInIfNotSignedIn() {
|
||||
signInIfNotSignedIn(consent: boolean) {
|
||||
return this.get()
|
||||
.then(() => this.isSignedIn())
|
||||
.then(isSignedIn => {
|
||||
if (!isSignedIn) {
|
||||
return this.showAccountSelection();
|
||||
return this.showAccountSelection(consent);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@ -201,11 +261,10 @@ const googleApi = {
|
|||
*/
|
||||
signOut() {
|
||||
return this.get()
|
||||
.then(api =>
|
||||
api.auth2
|
||||
&& api.auth2.getAuthInstance
|
||||
&& api.auth2.getAuthInstance()
|
||||
&& api.auth2.getAuthInstance().signOut());
|
||||
.then(() => {
|
||||
this.tokenClient = undefined;
|
||||
this.tokenExpires = undefined;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -387,6 +446,17 @@ const googleApi = {
|
|||
*/
|
||||
_getGoogleApiClient() {
|
||||
return window.gapi;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Returns the global Google Identity Services Library object.
|
||||
*
|
||||
* @private
|
||||
* @returns {Object|undefined}
|
||||
*/
|
||||
_getGoogleGISApiClient() {
|
||||
return window.google;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
import { getLogger } from '../base/logging/functions';
|
||||
|
||||
export default getLogger('features/base/redux');
|
Loading…
Reference in New Issue