If I make a document in Google drive and type some text, I can later go to file => Publish to the Web and get a link to a public webpage-style of the google doc, along with an embed link.
This is how its done manually. How can I do this automatically with a Node.JS server script (for example, using a Service Account) using the Goolgle Drive API? I couldn't find anything about this particular thing in their docs, is this possible? DO I need to make a google script instead? Is it even possible with that?
You want to publish the Google Document to web using googleapis with Node.js.
You want to retrieve the published URL.
You want to achieve this using the service account.
You have already had the service account and been able to use Drive API.
From your question and replying comments, I could understand like this. If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Usage:
In order to use the following sample script, please do the following flow.
Prepare a Google Document.
In this case, as a test case, please create new Google Document to your Google Drive.
Share the created Google Document with the email of the service account as the writer.
Retrieve the file ID of the Google Document.
Set the variables to the following sample script.
Run the script.
In this case, "Revisions: update" of Drive API is used.
By this, the Google Document is published to the web and you can see the published URL at the console.
Sample script:
const { google } = require("googleapis");
// Please set the email and private key of service account.
const auth = new google.auth.JWT(
"### email of service account ###",
null,
"### private key of service account ###" ,
["https://www.googleapis.com/auth/drive"]
);
const fileId = "###"; // Please set the file ID.
const drive = google.drive({ version: "v3", auth });
const body = {
resource: {
published: true,
publishedOutsideDomain: true,
publishAuto: true
},
fileId: fileId,
revisionId: 1
};
drive.revisions.update(body, err => {
if (err) {
console.error(err);
return;
}
console.log(`https://docs.google.com/document/d/${fileId}/pub`);
});
Please set the private key like "-----BEGIN PRIVATE KEY-----\n###\n-----END PRIVATE KEY-----\n".
Note:
The published URL is https://docs.google.com/document/d/${fileId}/pub. In this case, the file ID is used. Because unfortunately, in the current stage, the URL like https://docs.google.com/document/d/e/2PACX-###/pubhtml cannot be retrieved by Google API.
Reference:
Revisions: update
Related
I want to interact with the Google's Drive API from a Cloud Function for Firebase. For authentication / authorization, I am currently relying on getClient, which I believe uses the Service Account exposed in the Cloud Function environment:
import { google } from 'googleapis';
// Within the Cloud Function body:
const auth = await google.auth.getClient({
scopes: [
'https://www.googleapis.com/auth/drive.file',
],
});
const driveAPI = google.drive({ version: 'v3', auth });
// read files, create file etc. using `driveAPI`...
The above approach works, as long as target directories / files list the email address of the service account as an editor.
However, I'd like to interact with the Drive API on behalf of another user (which I control), so that this user becomes (for example) the owner of files being created. How can I achieve this?
To set the user you want to deligate as in your code just add a subject to the client, with user being the email of the user on your workspace domain.
const client = await auth.getClient();
client.subject = user;
I was able to achieve calling the Drive API on behalf of another user thanks to the suggestions made by #DalmTo.
The first step is to configure domain-wide delegation of authority in Google Workspace for the default AppEngine Service Account.
Next, the code in my question can be extended to receive a subject with the email of the user to impersonate via the clientOptions:
import { google } from 'googleapis';
// Within the Cloud Function body:
const auth = await google.auth.getClient({
scopes: [
'https://www.googleapis.com/auth/drive.file',
],
clientOptions: {
subject: 'email#to.impersonate',
},
keyFile: './serviceAccountKey.json',
});
const driveAPI = google.drive({ version: 'v3', auth });
// read files, create file etc. using `driveAPI`...
Now, the truly odd thing is that this only works when also passing the service account key via the keyFile option in addition. I.e., relying on the key being automatically populated (as it is in Cloud Functions for Firebase) does NOT work when also trying to impersonate a request. There are ongoing discussions of this bug on GitHub, specifically see this comment.
To make domain-wide delegation work without having to provide the keyFile option (which will likely require you to manage the sensitive key file in some way), another option is to sign a JWT and use it to obtain an Oauth token. The approach is outlined by Google, and I found this SO answer providing a code-example very helpful.
For a Google project app that i code with node js, I need to have the client access to upload a file into his drive. As I test my code, no file appears in my drive. It's probably because I run the thing with my service account. So what i did is that : as i have a client ID (with my email etc.) and key that I created with google, i uploaded the json that contains those informations :
{
"web":
{
"project_id":"",
"private_key_id": "",
"private_key": "-----BEGIN PRIVATE KEY-----\n\n-----END PRIVATE KEY-----\n",
"client_email": "",
"client_id":"",
"auth_uri":"https://accounts.google.com/o/oauth2/auth",
"token_uri":"https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs",
"client_secret":"",
"redirect_uris":["https://developers.google.com/oauthplayground"]
}
}
Obviously blank spaces aren't blank in my code.
I also handled, in the google console, the client API access and added the client with the Drive API application.
As I run the thing in the terminal, I get this error in the terminal :
"Error: No key or keyFile set."
Thanks ! In my js, I have access to the api and to my keys.json file containing the informations necessary.
If you want to upload a file to your / a user's drive with the service account - you need to give to the service account a) the scopes to access yours / the user's drive (implies domain-wide delegation) and b) either a reading permission to the file or enable impersonation so it acts on your / your user's behalf.
If you want to test a method (e.g. upload a file) without a service account, I recommend you to do it with the Try this API.
If you want to test your code with your own credentials instead of the service account - the authentication process will be different, as well as the content of the required credentials.json file. You need to stick to the procedure and authorization process as outlined in the quickstart - you can download the correct credentials file directly by clicking the "Enable the Drive API" button in the quickstart documentation. The correct credentials.json file for running the code as you (opposed to service account) will be the following:
{
"installed":{
"client_id":"XXX.apps.googleusercontent.com",
"project_id":"XXX",
"auth_uri":"https://accounts.google.com/o/oauth2/auth",
"token_uri":"https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs",
"client_secret":"XXX",
"redirect_uris":["urn:ietf:wg:oauth:2.0:oob","http://localhost"]
}
}
The private key (and key Id) is only necessary for service accounts.
I followed this quickstart tutorial for the Google Calendar API using javascript in my web application. As I need the possibility to show Calendar data on the webpage without user login, I need to implement API calls using a Service Account. Unfortunately I cant't find any good tutorials or explanations for doing so in javascript and since I am fairly new to the subject of API programming I kind of need some guidance.
Ty in advance.
Using Service account on client side is not secure. You may want to switch to a server side implementation for that. Assuming you are familiar with javascript I suggest to follow NodeJS implementation from here.
To create Service Account select service account after step 1->a.
Refer this image for option.
To use Service Account replace the authorize() logic with this
var email = credentials.client_email;
var key = credentials.private_key;
const jwt = new google.auth.JWT(
email, null, key, SCOPES
);
jwt.authorize((err, data) => {
if (err) {
console.error(err);
throw err;
}
console.log('You have been successfully authenticated: ', data);
callback(jwt);
});
As you are using Service Account you also need to create a calendar in your Gmail account to use. Then go to settings and select Add People to share it with client_email from your json, then use your Calendar Id (from Calendar settings) in API Call replacing primary
I am following the Google Docs API for javascript example to the letter, and got the basic example working. I have an api key, a secret token and I have set which ip addresses can access the data (http://localhost).
The demo works, it shows an auth button and after authenticating I can download google's example data using:
// google data example
var sheetId = "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms"
// load and show data
gapi.client.sheets.spreadsheets.values.get({
spreadsheetId: sheetId,
range: 'Class Data!A2:E',
}).then(function(response) {
console.log("loaded data " + response);
});
The problem is that if I replace the sheet id with the id of my own google docs sheet, I get Failed to load resource: the server responded with a status of 404.
I have even made my own sheet public. You can view it straight in any browser without even logging in. But even then I can't load the data using the API! (I don't want my sheet to be public though).
What step am I missing to connect to my own data?
To actually make the Sheets Quickstart work for your own spreadsheet, make sure you've done these things:
Start a local webserver like python -m SimpleHTTPServer 8080 so you actually have a connection to the internet.
Provide the correct SpreadSheet ID
Provide the correct sheet name, as well as sheetname in A1Notation.
Provide the correct sheet range in A1 Notation.
(I also removed the API KEY variables)
And here's the screenshot that I got it working:
I am using the Google Analytics Javascript library to let users view a GeoMap of the particular page they are on. However, everytime they attempt to do so, thye have to go through an authentication process only to have my data displayed on my page. How can I find an alternative to this. I only want to embed my Analytics data through a visualized graph on my page so that all anonymous viewers can see it. This is the code where the process takes place.
google.setOnLoadCallback(init);
/**
* This is called once the Google Data JavaScript library has been loaded.
* It creates a new AnalyticsService object, adds a click handler to the
* authentication button and updates the button text depending on the status.
*/
function init()
{
myService = new google.gdata.analytics.AnalyticsService('charts_sample');
/*
this is essentially the line I want to replace. It anonymously
tries to access my viewer's account.I want to set this scope such as it
address the URI of my Analytics account
*/
scope = 'https://www.google.com/analytics/feeds';
/*
if the above scope is altered to my URI then the below unnecessary login
steps will not be required at all. This is the reason why my viewers are
taken to their analytics page which is fundamentally non-existent.
*/
$("authButton").onclick = function() {
// Test if the user is not authenticated.
if (!google.accounts.user.checkLogin(scope))
{
// Authenticate the user.
google.accounts.user.login(scope);
} else
{
// Log the user out.
google.accounts.user.logout();
getStatus();
}
}
getStatus();
}
// gets the account data and then gets the outputs of the requested query
function getStatus()
{
getAccountFeed();
getDataFeed();
}
function getAccountFeed()
{
//Here agsain, I want to modify it access my account's URI
var myFeedUri ='https://www.google.com/analytics/feeds/accounts/default?max-results=50';
myService.getAccountFeed(myFeedUri, handleAccountFeed, handleError);
}
function getDataFeed()
{
var myMapPopularityFeedUri = 'https://www.google.com/analytics/feeds/data?ids=ga%3A53482361&dimensions=ga%3ApagePath%2Cga%3Acity%2Cga%3Acountry%2Cga%3Aregion%2Cga%3Alongitude%2Cga%3Alatitude&metrics=ga%3Avisitors&start-date=2011-12-01&end-date=2011-12-25&max-results=50';
myService.getDataFeed(myMapPopularityFeedUri, handleDataFeed, handleError);
}
Help will be appreciated a lot. Please don't be too critical. Its my first question here. Instead let me know and I will make for my amendments.
Here is a screenshot of what the embed looks like upon my own click, i.e, after GA has
fetched my own data through my account. The geoMap is at the bottom of the page.
It seems the best way is creating of the separate shared (public) feed (report) in Analytics.
Just feed security requires authorization login to view or receive data if the feed (report) was created under personal credentials ... independently to what version OAuth or OAuth2 is used, just if you use request to view data on the site you should use at least API key (for public reports) OR OAuth credentials for personal reports.
look this guide:
Loading an API and Making a Request
or choose any other example from this page:
Google Analytics: Core Reporting API Client Libraries & Sample Code (v3)
Use this nice tool also:
OAuth 2.0 Playground
Generate API key for maps:
Google Maps API Family
Google Maps JS API tutorial:
Google Maps JavaScript API V3
Have you looked at using oAuth2 for the Authorization?