nodejs - Getting 401 error trying to download docs revisions with Google Drive API export links - node.js

I need to download all the revisions of a google doc with the Drive API using nodejs but I don't understand how to authorize the request for the export links. Once I get the export link for each revision I call:
var options = {
url: 'https://docs.google.com/feeds/download/documents/export/Export?id=1DRl6rbcVuuLVyb_WlhBLiYiCByWcS2bKGlLIsn7E8_8&revision=1&exportFormat=txt', //example link
method: 'GET',
headers: {
Authorization: `Bearer ${jwToken}`,
},
}
request(options).pipe(fs.createWriteStream(mydownloadfilename));
where the "jwToken" is the token I use to get the revisions list so I guess it should be still valid. However, with this I get the 401-Unauthorized page. What am I doing wrong?
Thanks

According to the Drive API v3 documentation:
Revisions for Google Docs, Sheets, and Slides can't be downloaded.
So essentially, if the actual revision you want to retrieve is the file itself, then the method above is the correct one.
As for the authorization part, you will need to perform the Node.js Quickstart from here and follow the steps explained there.
Since you want to export the file, you will just need to modify the code and add this part:
function downloadDoc() {
var fileId = 'ID_OF_THE_DOC';
var dest = fs.createWriteStream('DESTINATION_OF_THE_OUTPUT_STREAM');
drive.files.export({
fileId: fileId,
mimeType: 'application/vnd.google-apps.document'
})
.on('end', function () {
console.log('Done');
})
.on('error', function (err) {
console.log('Error during download', err);
})
.pipe(dest);
}
Reference
Drive API v3 - Manage Revisions;
Drive API v3 - Files:export;
Drive API v3 - Quickstart;
Drive API v3 - Download a document.

I am facing this same problem. The solution is to use
OAUTH2 authorization for a user that has Edit or Owner permissions for a file
Get an access token that expires quickly
call the V2 URI (V3 does not work) for the file/rev to get "export links" 3) Call the correct export link for your format type
then you will get a randomized temporary redirect link from Google that you can then call to get the binary stream.
This is a great starting point for C# .NET -- windows oauth console app, if you want working code to do steps 1 and 2. I posted a working v2 code function here that you can put into the console app example.

Related

Download file from HTTP Drive API v3 with real file name

I have a custom REST Service in which a user from our platform downloads packages and binaries, but the problem is that the GDrive API downloads the file with the FileID as the file name:
async Download(fileID, res, type='stream') {
var Google = await CloudStorage.Initialize();
https.get(Google.API.STORAGE.Files.Download(fileID), {
headers: {
"Authorization": "Bearer " + Google.AccessToken.token,
"Content-Type": "text/plain"
},
responseType: type
}, (resApi) => {
res.writeHead(resApi.statusCode);
resApi.pipe(res);
}).end();
}
Example: https://MyUrl.com/beta/plugins/download/ABCDE12345
Where ABCDE12345 is the FileID of the file required by Google Drive API in order to GET the file.
The pipe of the response from the API indeed makes the downloaded file be named ABCDE12345.
Is there a way to make the download similar as doing it directly from the Google Drive Link?
When you download the file from the "Download" button through the Google Drive link it does download the file with the real name... How could I achieve this with my endpoint?
So,I had to use my girlfriend as the "rubber duck" and explain her my code when it came to my head while explaining: Use a fake endpoint for the named files.
My solution was to trick the endpoint by assigning a filename in a path parameter:
router.get('/dl/:id/:filename', async (req, res) => {
CloudStorage.Download(req.params.id, req.params.filename, res);
});
Now, having the :filename as a parameter allows me to verify it against the GDrive API since it's available for the given ID
In the end, it is now used as: https://MyUrl.com/beta/plugins/dl/ABCDE12345/Real File Name.ext
I can verify if Real File Name.ext is the real file name, if it is, then download it and the endpoint will allow me to create a file with this name :)

Microsoft login: Curl, Postman, and Dotnet work but Node (axios) request returns 404

I'm trying to access a graph api (specifically bookings) that only allows the Delegated (work or school account) permission. We need to be able to allow anonymous users to schedule bookings, so we created a fake microsoft user for our server to interact with their api.
I'm able to successfully authorize my user with Postman, Curl, and Dotnet, but I can't get Axios to work for the life of me, even after generating the code from Postman itself. I'm using the same exact URL in each method.
Note: my environment variables don't have typos and I'm running the code in Azure Functions. I know this is a hacky solution, but it seems to be the only way to do it using Microsoft Bookings.
Here's my code:
let data = new FormData();
data.append('grant_type', 'password');
data.append('username', process.env.MICROSOFT_USERNAME);
data.append('password', process.env.MICROSOFT_PASSWORD);
data.append('client_id', process.env.MICROSOFT_CLIENT_ID);
data.append('client_secret', process.env.MICROSOFT_CLIENT_SECRET);
data.append('resource', 'https://graph.microsoft.com/');
data.append('scope', 'https://graph.microsoft.com/.default');
const config = {
method: 'post',
url: `https://login.microsoftonline.com/${process.env.MICROSOFT_TENANT}/oauth2/token`,
headers:
data.getHeaders(),
data: data
};
axios(config).then(resp => {
console.log(resp);
}).catch(e => {
console.log(e);
});

How to create a Google Drive folder using node.js with googleapis official module

I'm trying this way:
var oauth2Client = new OAuth2(GDRIVE_CLIENT_ID, GDRIVE_CLIENT_SECRET, GDRIVE_REDIRECT_URI);
oauth2Client.setCredentials({
access_token: some_valid_access_token
});
drive.files.insert({
auth: oauth2Client,
resource: {
mimeType: 'application/vnd.google-apps.folder',
title: 'my new folder'
}
},function(err,response){
if(err){
console.log('error at gdrive creat folder: ' + util.inspect(err));
}else{
console.log('create response: ' + util.inspect(response));
}
});
And getting an error:
You cannot upload content to files of type application/vnd.google-apps.folder
What's the correct way of doing this?
The error message means that you (or the library on your behalf) is trying to upload content. This makes sense for regular files, but not for folders which have no content.
So either:-
You're not using the library correctly and there is a content-less insert you should be using
It's a bug in the library
I would suggest raise an issue on the GitHub project https://github.com/google/google-api-nodejs-client and update this question with whatever response you get.
If it's holding you up, just replace the library call with a really simple POST to the Drive endpoint with your "resource" as the POST body. You might find it's so easy that you throw the library away and do it all yourself.

Google Spreadsheet Creation - Node.js

I am trying to create new google spreadsheet using the google spreadsheet api using node.js
I have managed to get the Google OAuth 2.0 working, where I am getting the access tokens for the clients.
Now on searching the Google API docs there are example using the gData client library but nothing giving me pointers to node.js
Here are my findings for creating a new google spreadhseet
Upload a spreadsheet manually OR
Use a resumable upload link
There is not much information on the resumable upload link.
I can see the HTTP Post Request and Response but I do not understand how to construct the post request in node.js
EDIT--
I am reading Google Apps Platform
Here is how to do it with the create method of the Google Sheets API (currently v4).
This code examples does not use any 3rd party libraries, it uses googleapis: Google API's official Node.js client
const google = require('googleapis');
const sheets = google.sheets('v4');
// authenticate, and store that authentication, in this example
// it is stored in a variable called `auth`. I am using JWT
// authentication, but you can use the any form of authentication
const auth = new google.auth.JWT(
key.client_email,
null,
key.private_key,
['https://www.googleapis.com/auth/spreadsheets'], // make sure that your auth scope includes `spreadsheets`, `drive` or `drive.file`
null
);
sheets.spreadsheets.create({
auth: auth,
resource: {
properties: {
title: 'Title of your new spreadsheet'
}
}
}, (err, response) => {
if (err) {
console.log(`The API returned an error: ${err}`);
return;
}
console.log('Created a new spreadsheet:')
console.log(response);
});
If all you want to know is how to construct post request, then check this example
http://nodejs.org/api/http.html#http_http_request_options_callback
Checkout
https://github.com/EastCloud/node-spreadsheets/
EastCloud has written a friendly-ish wrapper around the Google Docs/Drive API
If you are new and want to get and add data to Google spreadsheets, please refer below link to get step-by-step guide.
https://www.twilio.com/blog/2017/03/google-spreadsheets-and-javascriptnode-js.html
I was tested same in recent nodejs project

Upload a photo to facebook album

I have a nodejs (+express + mongodb,gridstore) backend, and want to upload a photo to a facebook album.
I came across 2 methods. the first ( https://developers.facebook.com/blog/post/526/ ) needs to get the full url resource of my picture, which I don't have as it is data that I pull from gridstore,
and the second ( https://developers.facebook.com/docs/reference/api/album/ ) is very poorly documented, via the Graph API, where I can't figure out what my request should look like. (the form-data, what fields should it have, how to convert my data blob\stream from gridstore to it)
Here is what I currently have, and doesn't work:
facebook.uploadPhoto = function (token, albumId, photo, callback) {
var fb = fermata.json('https://graph.facebook.com/' + albumId);
fb.photos({access_token:token}).post({'Content-Type':"multipart/form-data"}, {source:{data:photo}}, callback);
};
Any help would be much appreciated
There is a good chance the file is not properly serialized. Fermata will take a node File buffer via data. Have you tried passing that instead?
fs.readFile("/path/to/photo.jpg", function (err, data) {
fermata.json("https://graph.facebook.com/graph/api").post({"Content-Type":"multipart/form-data"}, {fileField: {data:data, name:"", type:""} }, callback);
});
Adding your access token etc..
I solved this problem by using a simple POST to the facebook graph API using the poster module.
var options = {
uploadUrl: 'https://graph.facebook.com/'+user+'/photos?access_token='+accessToken,
method: 'POST',
fileId: 'source',
fields: {'message':''} // Additional fields according to graph API
};
var fileName = ''; // Local or remote url where to find the image
poster.post(fileName, options, function(err, data) {
if (err) {
//Something went wrong
} else {
// Everything ok
}
});
Honestly, I've got limited experience working with the Facebook graph API and mostly using PHP and Java.
Here is some streams that you might find helpful:
Upload Photo To Album with Facebook's Graph API
Facebook Graph API - upload photo using JavaScript
Basically, I recommend you punt a little in your implementation and code it in the following way:
Create a REST web service function call in Node.js to output a single image from gridstore using an internal UID.
Code your uploadToFacebook function to use an image URL that calls the REST web service function.
Basically, this would allow you to validate the image output by pointing your browser to the REST web service and avoid any blob\stream conversions inside your uploadToFacebook function. I'm assuming you store the image in gridstore vs. mongodb.
hope that helps...

Resources