Create a Google Document with a built-in object using Node - node.js

I've seen the post below on how to create a Google doc instance using Node.
Create a Google Document with Google Drive API and Node.js
But I also want to pass through an object so when the google doc gets created, it has that object stored in its environment. Is there a way to do so by passing the object through one of the parameters below?
DRIVE.files.create({
resource: {
name: fileName,
mimeType: fileType
},
media: {
mimeType: fileType,
body: fileContent
}
}
Any help would be much appreciated

You want to create new Google Document by including Google Apps Script as the container-bound script.
As a sample situation, you want to include the script of var obj = { “foo”:”bar”}.
You want to achieve this using googleapis with Node.js.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
In this answer, in order to achieve this, I used the methods of projects.create and projects.updateContent in Google Apps Script API.
Flow:
The flow of this answer is as follows.
Create new Google Document.
Create new GAS project as the container-bound script to the created Google Document.
Put the script to the created GAS project.
Preparation:
Before you run the script, please prepare as follows.
Please enable Google Apps Script API at API console.
From your question, I thought that you have already enabled Drive API at API console.
Please set the scopes of https://www.googleapis.com/auth/drive and https://www.googleapis.com/auth/script.projects.
Please remove the credential file including the access token and refresh token. Because this way is used for reflecting the new scopes to the access token. When you run the script after the credential file was removed, the authorization process is run. So please retrieve the code and retrieve the access token and refresh token using the code.
Please prepare a sample text file as the filename of sample.txt. Because media is used in your script.
Sample script:
const drive = google.drive({ version: "v3", auth });
const script = google.script({ version: "v1", auth });
drive.files.create(
{
requestBody: {
name: "sampleDocument",
mimeType: "application/vnd.google-apps.document"
},
media: {
mimeType: "text/plain",
body: fs.createReadStream("./sample.txt")
}
},
(err, res) => {
if (err) {
console.error(err);
return;
}
script.projects.create(
{
requestBody: {
title: "sampleGASProject",
parentId: res.data.id
}
},
(err, res) => {
if (err) {
console.log(err);
return;
}
script.projects.updateContent(
{
scriptId: res.data.scriptId,
auth,
resource: {
files: [
{
name: "Code",
type: "SERVER_JS",
source: 'var obj = {"foo":"bar"}\n'
},
{
name: "appsscript",
type: "JSON",
source:
'{"timeZone":"America/New_York","exceptionLogging":"STACKDRIVER"}'
}
]
}
},
(err, res) => {
if (err) {
console.log(err);
return;
}
console.log("Done.");
}
);
}
);
}
);
When you run this sample script, new Google Document is created as the filename of sampleDocument and new GAS project is created as the project name of sampleGASProject.
After the script was finished, you can see new Google Document at the root folder. When you open the Google Document and open the script editor, you can see the script of var obj = {"foo":"bar"}.
Note:
If you are using the service account, unfortunately, GAS project cannot be managed with the service account. Please be careful this. So please use OAuth2.
References:
Method: projects.create
Method: projects.updateContent
In my environment, I could confirm that the sample script works. But if that didn't work in your environment, I apologize. At that time, please check whether API is enabled and/or other environment. If I misunderstood your question and this was not the direction you want, I apologize.

Related

What is causing this 400 return code from the Google API when working with Calendars

I am having some trouble with the Google APIs and trying to interact with Google Calendar. I'm getting a missing resource 400 error when attempting to insert a new calendar ID.
Below is a snippet of the error JSON (I can't include everything due to some sensitive elements), I don't know what missing resource it's complaining about.
code: 400,
errors: [
{
domain: 'global',
reason: 'required',
message: 'Missing resource.'
}
]
The code that's causing the problem is here (some pieces are omitted):
const { google } = require('googleapis');
const { googlePrivateKey, googleClientEmail, googleProjectNumber } = require('../../config.json');
const SCOPES = ['https://www.googleapis.com/auth/calendar'];
//OMITTED SECTION
const jwtClient = new google.auth.JWT(
googleClientEmail,
'./keyfile.json',
googlePrivateKey,
SCOPES,
);
const calendar = new google.calendar({
version: 'v3',
project: googleProjectNumber,
auth: jwtClient,
});
calendar.calendarList.insert({
id: name,
// 'description': description,
});
Referenced variables are drawn from other surrounding code or from an existing config.json file (not included due to sensitivity of information contained within). The information in config.json is known working (I was able to make a request to retrieve the list of calendars with a 200 response using another piece of code not shown here).
I've looked at as much documentation I can find, but I can't seem to discover any information on what I'm missing/doing wrong.
In your script, how about the following modification?
From:
calendar.calendarList.insert({
id: name,
// 'description': description,
});
To:
const name = "###"; // Please set your calendar ID.
calendar.calendarList.insert(
{
resource: { id: name },
},
(err, res) => {
if (err) {
console.log(err.errors);
return;
}
console.log(res.data);
}
);
Please set your expected calendar ID to name. If this value is not correct, an error like "'Not Found" occurs. Please be careful about this.
Reference:
CalendarList: insert

Can't modify permissions for a file I just created via OAuth in Google Drive API

I have a web app that allows users to sign in via oAuth, which grants them the https://www.googleapis.com/auth/drive.file scope, and then they can create and edit text files via files.create and files.update. This all works fine in Node.js using the googleapis NPM module.
However, I also allow other users to view and edit those files via my app if they are accessed via the appropriate link. To do this, as soon as the file is created, I also immediately create a permission for that file as in the code below.
This works fine 95% of the time, but occasionally, I have a user get an error which shows up as a 403 error from Google, with the message "the user does not have sufficient permissions for this file." The file is created just fine, as he can verify by manually opening the folder in Google Drive, but the app errors out at the "drive.permissions.create" step, and afterward, that same file cannot be opened or edited by him via the app with the same error.
What in the world is going on? Why does my user not have permissions for his own file he just created half a second ago via OAuth, and why does it work for most everyone else? Regenerating the access/refresh tokens does not help him either. I'm so confused.
const drive = google.drive({ version: 'v3', auth: Oauth }); //Oauth credentials generated at login
const media = {
mimeType : 'text/plain',
body : newfile.text
};
const fileMetadata = {
'name' : `${newfile.title}.txt`,
'description' : `${newfile.description}`,
'parents' : [folderId],
'properties' : {
'title' : newfile.title,
}
};
const obj = await drive.files.create({
resource : fileMetadata,
media : media
})
.catch((err)=>{
console.error(err);
return res.status(500).send('Error while creating new file');
});
if(!obj) return;
await drive.permissions.create({
resource : { type : 'anyone',
role : 'writer' },
fileId : obj.data.id,
fields : 'id',
})
.catch((err)=>{
console.error(err);
return res.status(500).send('Error updating permissions');
});

Why can't Clarifai validate model output request with API key generated in the Clarifai Portal or with the Personal Access token?

Update
I'm able to get my original code, and the suggestions as well working when running it in isolation. However, what I need to do is call it from within a Firebase onRequest or onCall function. When this code gets wrapped by these, the malformed headers and request for authorization are still an issue. We use many other APIs this way so it's puzzling why the Clarifiai API is having these issues. Any suggestions on using it with Firebase?
Original
New to Clarifai and having some authentication issues while attempting to retrieve model outputs from the Food Model.
I've tried two different keys:
API key generated from an app I created in the Portal
API key - the Personal Access Token I generated for myself
In both cases I encounter an Empty or malformed authorization header response.
{
"status":{
"code":11102,
"description":"Invalid request",
"details":"Empty or malformed authorization header. Please provide an API key or session token.",
"req_id":"xyzreasdfasdfasdfasdfasf"
},
"outputs":[
]
}
I've following the following articles to piece together this code. This is running in a Node 10 environment.
Initialization
Food Model
Prediction
const { ClarifaiStub } = require('clarifai-nodejs-grpc');
const grpc = require('#grpc/grpc-js');
const stub = ClarifaiStub.json();
const metadata = new grpc.Metadata();
metadata.set("authorization", "Key xyzKey");
return new Promise((resolve, reject) => {
stub.PostModelOutputs(
{
model_id: 'bd367be194cf45149e75f01d59f77ba7',
inputs: [{ data: { image: { url: 'https://samples.clarifai.com/metro-north.jpg' } } }],
},
metadata,
(err, response) => {
if (err) {
return reject(`ERROR: ${err}`);
}
resolve(JSON.stringify(response));
}
);
});
}
Update: There was an issue in versions prior to 7.0.2 where, if you had another library using #grpc/grpc-js with a different version, the grpc.Metadata object wasn't necessarily constructed from the library version that clarifai-grpc-nodejs was using.
To fix the issue, update the clarifai-grpc-nodejs library, and require the grpc object like this:
const {ClarifaiStub, grpc} = require("clarifai-nodejs-grpc");
Previously, the grpc object was imported directly from #grpc/grpc-js, which was the source of the problem.
There are two ways of authenticating to the Clarifai API:
with an API key, which is application-specific, meaning that an API key is attached to an application and can only do operations inside that application,
with a Personal Access Token (PAT), which is user-specific, which means you can assess / manipulate / do operations on all the applications the user owns / has access to (and also create/update/delete applications themselves).
When using a PAT, you have to specify, in your request data, which application you are targeting. With an API key this is not needed.
I've tested your example (using Node 12, though it should work in 10 as well) with a valid API key and it works fina (after putting it into an async function). Here's a full runnable example (replace YOUR_API_KEY with your valid API key).
function predict() {
const { ClarifaiStub } = require('clarifai-nodejs-grpc');
const grpc = require('#grpc/grpc-js');
const stub = ClarifaiStub.json();
const metadata = new grpc.Metadata();
metadata.set("authorization", "Key YOUR_API_KEY");
return new Promise((resolve, reject) => {
stub.PostModelOutputs(
{
model_id: 'bd367be194cf45149e75f01d59f77ba7',
inputs: [{ data: { image: { url: 'https://samples.clarifai.com/metro-north.jpg' } } }],
},
metadata,
(err, response) => {
if (err) {
return reject(`ERROR: ${err}`);
}
resolve(JSON.stringify(response));
}
);
});
}
async function main() {
const response = await predict();
console.log(response);
}
main();
If you want to use a PAT in the above example, two things must change. Firstly, replace the API key with a PAT:
...
metadata.set("authorization", "Key YOUR_PAT");
...
To the method request object, add the application ID.
...
stub.PostModelOutputs(
{
user_app_id: {
user_id: "me", // The literal "me" resolves to your user ID.
app_id: "YOUR_APPLICATION_ID"
},
model_id: 'bd367be194cf45149e75f01d59f77ba7',
inputs: [{ data: { image: { url: 'https://samples.clarifai.com/metro-north.jpg' } } }],
},
...
Make sure that you have respected the format to pass the key in your code as such:
const metadata = new grpc.Metadata();
metadata.set("authorization", "Key {YOUR_CLARIFAI_API_KEY}");
Make sure that "Key" is present.
Let me know.
EDIT: So looks like Firebase doesn't support custom headers. This is likely impacting the 'Authorization' header. At least this is my best guess. See the comments in the following ticket.
Firebase hosting custom headers not working
The following code works for me:
{
const { ClarifaiStub } = require('clarifai-nodejs-grpc');
const grpc = require('#grpc/grpc-js');
const stub = ClarifaiStub.json();
const metadata = new grpc.Metadata();
metadata.set("authorization", "Key {APP API KEY}");
return new Promise((resolve, reject) => {
stub.PostModelOutputs(
{
model_id: 'bd367be194cf45149e75f01d59f77ba7',
inputs: [{ data: { image: { url: 'https://samples.clarifai.com/metro-north.jpg' } } }],
},
metadata,
(err, response) => {
if (err) {
return reject(`ERROR: ${err}`);
}
console.log(JSON.stringify(response));
resolve(JSON.stringify(response));
}
);
});
}
There was a missing { although I'm not sure if that is what is reflected in the actual code you are running. I'm using in this case an APP API Key (when you create an App, there will be an API Key on the Application Details page.
It sounds like you might be using a Personal Access Token instead, which can be used like this:
{
const { ClarifaiStub } = require('clarifai-nodejs-grpc');
const grpc = require('#grpc/grpc-js');
const stub = ClarifaiStub.json();
const metadata = new grpc.Metadata();
metadata.set("authorization", "Key {Personal Access Token}"); // Sounds like you've made the personal access token correctly - go into settings, then authentication, then create one. Make sure it has proper permissions (I believe all by default).
return new Promise((resolve, reject) => {
stub.PostModelOutputs(
{
user_app_id: {
user_id: "{USER ID}", // I used my actual ID, I did not put 'me'. You can find this under your profile.
app_id: "{APP NAME}" // This is the app ID found in the upper left corner of the app after it is created - not the API Key. This is generally what you named the app when you created it.
},
model_id: 'bd367be194cf45149e75f01d59f77ba7',
inputs: [{ data: { image: { url: 'https://samples.clarifai.com/metro-north.jpg' } } }],
},
metadata,
(err, response) => {
if (err) {
return reject(`ERROR: ${err}`);
}
console.log(JSON.stringify(response));
resolve(JSON.stringify(response));
}
);
});
}
Make sure to fill out the: {Personal Access Token}, {USER ID} and {APP NAME}. I used my actual user id (found in the profile), and the app name is not the API Key for the app, but the name in the upper left corner when you're on the Application details page. This call worked for me.

Node: Google Drive API for listing all files using query

May I know how can I list all the files using query in the Google Drive using the GoogleAPIS library
https://github.com/google/google-api-nodejs-client/
I have no idea, how to use this library!
I dont know where should I place my query, I have tried the code below, but I am not getting any response..
Test 1:
drive.files.list("mimeType='image/jpg'", function(data){
//I am getting all the data, the query is not working..
));
Test 2:
drive.files.list({
media: {
mimeType: 'application/vnd.google-apps.folder'
}
}, function(err, data){
//I am getting all the data, the query is not working..
});
Test 3:
drive.files.list({
resource: {
mimeType: 'application/vnd.google-apps.folder'
}
}, function(err, data){
//This returns error not working at all!
});
You can check the drive.files.list function given here https://github.com/google/google-api-nodejs-client/blob/master/apis/drive/v2.js#L733 and use something like the following for it.
var drive = google.drive({ version: 'v2', auth: oauth2Client });
drive.files.list({
q='mimeType='image/jpg''
}, callback);
More details on the input parameters for the list function are on https://developers.google.com/drive/v2/reference/files/list

Basic file download example

I have been struggling my brain reading the nodejs documentation for google-apis.
I gathered a pretty long list of examples, but any of them helps me to do what I want to do. I just want to download a file from my drive using node js.
I have set up the OAUTH and I get an access token using this code (source: http://masashi-k.blogspot.com.es/2013/07/accessing-to-my-google-drive-from-nodejs.html )
var googleDrive = require('google-drive');
var GoogleTokenProvider = require("refresh-token").GoogleTokenProvider,
async = require('async'),
request = require('request'),
_accessToken;
var tokenProvider = new GoogleTokenProvider({
'refresh_token': REFRESH_TOKEN,
'client_id' : CLIENT_ID,
'client_secret': CLIENT_SECRET
});
tokenProvider.getToken(function(err, access_token) {
console.log("Access Token=", access_token);
_accessToken = access_token;
});
But I don't know how to continue from here. I tried with things like this with no luck:
function listFiles(token, callback) {
googleDrive(token).files().get(callback)
}
function callback(err, response, body) {
if (err) return console.log('err', err)
console.log('response', response)
console.log('body', JSON.parse(body))
}
listFiles(_accessToken,callback);
I feel like I'm very close, but I need some help here.
Thanks in advance.
There are two ways of doing that, depending on what you want to download. There is a big difference between downloading native Google Doc files and normal files:
Docs have to be downloaded using files.export API method, providing proper mime type to convert doc into
Normal files can be downloaded using files.get method, providing correct flag if you want to download file data instead of metadata
I'd suggest using GoogleApis NodeJS library (https://github.com/google/google-api-nodejs-client)
Initializing Drive API:
var Google = require('googleapis');
var OAuth2 = Google.auth.OAuth2;
var oauth2Client = new OAuth2('clientId','clientSecret','redirectUrl');
oauth2Client.setCredentials({
access_token: 'accessTokenHere'
refresh_token: 'refreshTokenHere'
});
var drive = Google.drive({
version: 'v3',
auth: this.oauth2Client
});
Importing file:
drive.files.get({
fileId: fileId,
alt: 'media' // THIS IS IMPORTANT PART! WITHOUT THIS YOU WOULD GET ONLY METADATA
}, function(err, result) {
console.log(result); // Binary file content here
});
Exporting native Google docs (you have to provide mime type for conversion):
drive.files.export({
fileId: fileId,
mimeType: 'application/pdf' // Provide mimetype of your liking from list of supported ones
}, function(err, result) {
console.log(result); // Binary file content here
});
Maybe it will help someone after so much time ;)
Take a look at the officially supported NodeJS client library for Google APIs at https://github.com/google/google-api-nodejs-client
The code required to get a file from Drive will be similar to that code at the bottom of the README used for inserting a file into Google Drive. You can also test your parameters to the API by using the API Explorer: https://developers.google.com/apis-explorer/#p/drive/v2/drive.files.get
Here's an example call to get a file from Google Drive:
client
.drive.files.get({ fileId: 'xxxx' })
.execute(function(err, file) {
// do something with file here
});

Resources