As part of Project Strobe, Google is planning to move many of the Google Drive API scopes to "restricted" which means that you need an independent security verification.
In the same article, they suggest using the Google Picker and drive.file scope to obtain per file access. I've successfully implemented the Google Picker API to access files and retreive the meta data of the file. But how do I actually import the content of the file with this flow (for example, the data in an actual Google sheet)?
GOOGLE PICKER WRAPPER
import React from "react";
import PropTypes from "prop-types";
import loadScript from "load-script";
const GOOGLE_SDK_URL = "https://apis.google.com/js/api.js";
let scriptLoadingStarted = false;
class GoogleFilePicker extends React.Component {
static propTypes = {
children: PropTypes.node,
clientId: PropTypes.string.isRequired,
developerKey: PropTypes.string,
scope: PropTypes.array,
viewId: PropTypes.string,
authImmediate: PropTypes.bool,
origin: PropTypes.string,
onChange: PropTypes.func,
onAuthenticate: PropTypes.func,
onAuthFailed: PropTypes.func,
createPicker: PropTypes.func,
multiselect: PropTypes.bool,
navHidden: PropTypes.bool,
disabled: PropTypes.bool,
authToken: PropTypes.string,
};
static defaultProps = {
onChange: () => {},
onAuthenticate: () => {},
onAuthFailed: () => {},
scope: ["https://www.googleapis.com/auth/drive.file"],
viewId: "DOCS",
authImmediate: false,
multiselect: false,
navHidden: false,
disabled: false,
authToken: "",
};
constructor(props) {
super(props);
this.onApiLoad = this.onApiLoad.bind(this);
this.onChoose = this.onChoose.bind(this);
}
componentDidMount() {
if (this.isGoogleReady()) {
// google api is already exists
// init immediately
this.onApiLoad();
} else if (!scriptLoadingStarted) {
// load google api and the init
scriptLoadingStarted = true;
loadScript(GOOGLE_SDK_URL, this.onApiLoad);
} else {
// is loading
}
}
isGoogleReady() {
return !!window.gapi;
}
isGoogleAuthReady() {
return !!window.gapi.auth;
}
isGooglePickerReady() {
return !!window.google.picker;
}
onApiLoad() {
window.gapi.load("auth");
window.gapi.load("picker");
}
doAuth(callback) {
window.gapi.auth.authorize(
{
client_id: this.props.clientId,
scope: this.props.scope,
immediate: this.props.authImmediate,
},
callback
);
}
onChoose() {
if (
!this.isGoogleReady() ||
!this.isGoogleAuthReady() ||
!this.isGooglePickerReady() ||
this.props.disabled
) {
return null;
}
// const token = window.gapi.auth.getToken();
// const oauthToken = token && token.access_token;
const oauthToken = this.props.authToken;
if (oauthToken) {
this.createPicker(oauthToken);
} else {
this.doAuth((response) => {
if (response.access_token) {
this.createPicker(response.access_token);
} else {
this.props.onAuthFailed(response);
}
});
}
}
createPicker(oauthToken) {
// this.props.onAuthenticate(oauthToken);
if (this.props.createPicker) {
return this.props.createPicker(window.google, oauthToken);
}
const googleViewId = window.google.picker.ViewId[this.props.viewId];
const view = new window.google.picker.View(googleViewId);
if (this.props.mimeTypes) {
view.setMimeTypes(this.props.mimeTypes.join(","));
}
if (this.props.query) {
view.setQuery(this.props.query);
}
if (!view) {
throw new Error("Can't find view by viewId");
}
const picker = new window.google.picker.PickerBuilder()
.addView(view)
.setOAuthToken(oauthToken)
.setDeveloperKey(this.props.developerKey)
.setCallback(this.props.onChange);
if (this.props.origin) {
picker.setOrigin(this.props.origin);
}
if (this.props.navHidden) {
picker.enableFeature(window.google.picker.Feature.NAV_HIDDEN);
}
if (this.props.multiselect) {
picker.enableFeature(window.google.picker.Feature.MULTISELECT_ENABLED);
}
picker.build().setVisible(true);
}
render() {
console.log(window.gapi);
return (
<div onClick={this.onChoose}>
{this.props.children ? (
this.props.children
) : (
<button>Open google chooser</button>
)}
</div>
);
}
}
export default GoogleFilePicker;
CALLING THE WRAPPER
I'm calling the component above in the code below. Once the document is retrieved I call the copyFile function. This function works as expected when the document has been created by the app, but not when the file has been created by the user outside of the app. I know that this intended by Google for the drive.google.file scope but the documentation implies that using the Google Picker should solve this.
<GoogleFilePicker
clientId="CLIENT ID"
developerKey="DEVELOPER KEY"
scope={["https://www.googleapis.com/auth/drive.file"]}
onChange={(data) => {
if (data.docs) {
copyFile(data.docs[0].id, `Template: ${data.docs[0].name}`, "");
}
}}
onAuthenticate={(token) => console.log("oauth token:", token)}
onAuthFailed={(data) => console.log("on auth failed:", data)}
multiselect={true}
navHidden={true}
authImmediate={false}
// mimeTypes={["image/png", "image/jpeg", "image/jpg"]}
viewId={"DOCS"}
authToken={auth.state.user.googleToken}
>