Dropbox API - Force Direct download - javascript

I using the dropbox API to upload files into dropbox and then generate a shareable links and sending those to the users.
But the issue is I want to force download the file instead of preview via dropbox share link.
I know I can force download setting ?dl=1 at the end of the link but the shareable link generated by dropbox comes back with ?dl=0
Code:
request.put('https://api-content.dropbox.com/1/files_put/auto/reports/' + req.body.Name +'.pdf', {
headers: {
Authorization: 'TOKEN',
'Content-Type': 'application/pdf'
},
body: content
}, function optionalCallback(err, httpResponse, bodymsg) {
if (err) {
console.log(err);
}
else {
console.log("File uploaded to dropbox successfully!");
fs.unlink(temp_dir + 'report.pdf', function(err) {
if (err)
throw err;
else {
console.log("file deleted from server!");
}
});
request.post('https://api.dropboxapi.com/1/shares/auto/reports/' + req.body.Name + '.pdf'+ '?short_url=false?dl=1', {
headers: {
Authorization: 'TOKEN'
}
}, function optionalCallback(err, httpResponse, bodymsg) {
if (err) {
console.log(err);
}
else {
console.log('Shared link 2 ' + JSON.parse(httpResponse.body).url);
res.json(JSON.parse(httpResponse.body).url);
}
});
}
});
I am using the V1 of dropbox API which will be deprecated soon but for now I need to use it.

Using the dl=1 URL parameter is the correct way to force downloads on these links. You can find more information on this here:
https://www.dropbox.com/help/desktop-web/force-download
To do this properly, you should use an actual URL parser to parse the URL. Then, if it already has a dl parameter, set it to 1. If it doesn't, then add dl parameter set to 1.

You can take advantage of streams and just redirect download stream into client. Here is an example using my minimalistic dropbox-v2-api wrapper and hapijs route configuration:
{
path: '/getFile',
method: 'GET',
handler: (request, response) => {
dropbox({
resource: 'files/download',
parameters: {
path: '/dropbox/image.jpg'
}
}, (err, result) => {
//download completed
}).pipe(response); //piping file stream
}
}

Related

Download a PDF file in Node and redirect into front end React

Can you help me to download a file in Node.js and redirect page into the front end? I am using MERN stack (Mongo, Express, React, Node).
After authenticating with the Google Auth, I want to download a file in Node, then I want to redirect the page.
router.get(
'/auth/google/callback',
passportGoogle.authenticate('google', {
failureRedirect: '/',
}),
(req, res) => {
try {
var file = 'resume.pdf';
res.download(file, (err => {
if (err) {
console.log(err)
} else {
window.location.href = '/';
}
}));
}
);
I tried this code, but after downloading it's not redirecting page to front end.
(req, res) => {
try {
var file = 'resume.pdf';
res.download(file, (error => {
if (!error) {
window.location.replace("http://stackoverflow.com");
} else {
console.log(error)
}
}));
}
catch {
console.log(error)
}
Since the headers are already sent with the download response, you'll have to go different route than this.
You'll need to change the response yourself.
var data = //filedata
res.set({
Content-Type: 'text/plain',
Location: '/'
});
res.end(data);
Utilize the Location header accordingly for your redirect.
On the client, you'll want to use:
window.location.replace("/headerLocation");
You want to use this on the client after the success of your callback to your download pdf method.
The reason your getting window undefined is because you're attempting to execute this on your nodejs server. The window object exists on the client.

google drive api - list files shared with me in app with read and write permissions only to files created by app (permissions auth/drive.file)

I'm doing tests to share files with Google apis I already have how to share the files with someone ams as far as I understand is shared with user permission as reading or writing that is what I need through an app, on the side of the person to whom the file was shared I can not see it as far as I have noticed the api does not consult the files for read permissions in drive in the app just set the permission as "https://www.googleapis.com/auth/drive.file" Because I just want my app to have access to the files that she created.
owner (list in api) --> shared --> user (not list in api)
/////////CODE SHARED FILE OWNER
var request1 = gapi.client.request({
'path': '/drive/v3/files/' + fileId + '/permissions',
'method': 'POST',
'headers': {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + sTokenDrive
},
'body':{
'role': 'writer',
'type': 'user',
'emailAddress' : 'user#gmail.com'
}
});
request1.execute(function(resp) {
console.log(resp);
});
////////CODE LIST FILE USER
<script src="https://apis.google.com/js/api.js"></script>
<script>
/**
* Sample JavaScript code for drive.files.list
* See instructions for running APIs Explorer code samples locally:
* https://developers.google.com/explorer-help/guides/code_samples#javascript
*/
function authenticate() {
return gapi.auth2.getAuthInstance()
.signIn({scope: "https://www.googleapis.com/auth/drive.file"})
.then(function() { console.log("Sign-in successful"); },
function(err) { console.error("Error signing in", err); });
}
function loadClient() {
return gapi.client.load("https://content.googleapis.com/discovery/v1/apis/drive/v3/rest")
.then(function() { console.log("GAPI client loaded for API"); },
function(err) { console.error("Error loading GAPI client for API", err); });
}
// Make sure the client is loaded and sign-in is complete before calling this method.
function execute() {
return gapi.client.drive.files.list({
"corpus": "user",
"q": "sharedWithMe = true"
})
.then(function(response) {
// Handle the results here (response.result has the parsed body).
console.log("Response", response);
},
function(err) { console.error("Execute error", err); });
}
gapi.load("client:auth2", function() {
gapi.auth2.init({client_id: 'CLIENT_ID'});
});
</script>
<button onclick="authenticate().then(loadClient)">authorize and load</button>
<button onclick="execute()">execute</button>

How to upload and update youtube channel banner using node js googleapis client

I am writing an application that uploads and updates the youtube channel banner. i am using node.js and google api client.
In the official api documentation there's no examples on node.js how to send the image content, also there's no information about the callback's signature
Here is my code:
var google = require('googleapis');
var OAuth2 = google.auth.OAuth2;
var oauth2Client = new OAuth2();
var youtube = google.youtube({ version: 'v3' });
//Setting the credentials
oauth2Client.setCredentials({
access_token: 'STORED_IN_DATABASE',
refresh_token: 'STORED_IN_DATABASE',
});
//Send the request
youtube.channelBanners.insert({
auth: oauth2Client,
//image_content
}, callback);
After calling the insert method, i have to call channels.update method, which also doesn't have the examples on node.js
From Channel banners insert, you have to call :
channelBanners.insert, and get the url field from the response
channels.update with the previous retrieved URL
You will also need the channel id for channels.update request. Note also that from Channel update :
If you are submitting an update request, and your request does not specify a value for a property that already has a value, the property's existing value will be deleted.
So you may want to call channels.list to get the channel object with brandingSettings part to be updated
The API call with google-api-nodejs-client:
channelBanners.insert
youtube.channelBanners.insert({
media: {
mimeType: "image/jpeg",
body: fs.createReadStream('banner.jpeg')
}
}, function(err, uploadResponse, response) {
});
The available mimeType are image/jpeg, image/png, application/octet-stream
channels.list
youtube.channels.list({
part: "brandingSettings",
mine: true
}, function(err, channelListRsp, response) {
});
channels.update
channelListRsp.items[0].brandingSettings.image.bannerExternalUrl = uploadResponse.url;
youtube.channels.update({
part: "brandingSettings",
resource: channelListRsp.items[0]
}, function(err, channelUpdateResp, response) {
});
Full example which update the banner for the first channel found in the channel list of current user :
youtube = google.youtube({
version: 'v3',
auth: oauth2Client
});
youtube.channelBanners.insert({
media: {
mimeType: "image/jpeg",
body: fs.createReadStream('banner.jpeg')
}
}, function(err, uploadResponse, response) {
if (err)
console.error("channelBanners.insert error : ", err);
if (response)
console.log('channelBanners.insert : ' + response.statusCode);
if (uploadResponse && uploadResponse.url) {
console.log("setting channel brandingSettings : " + uploadResponse.url);
youtube.channels.list({
part: "brandingSettings",
mine: true
}, function(err, channelListRsp, response) {
if (err)
console.error('channels.list error : ', err);
if (response)
console.log('channels.list : ' + response.statusCode);
if (channelListRsp && channelListRsp.items && channelListRsp.items.length > 0) {
console.log("updating banner for channel id : " + channelListRsp.items[0].id);
// set the url
channelListRsp.items[0].brandingSettings.image.bannerExternalUrl = uploadResponse.url;
//update channel brandingSettings
youtube.channels.update({
part: "brandingSettings",
resource: channelListRsp.items[0]
}, function(err, channelUpdateResp, response) {
if (err)
console.error('channels.update error : ', err);
if (response)
console.log('channels.update : ' + response.statusCode);
if (channelUpdateResp)
console.log(channelUpdateResp);
});
}
});
}
});

Passing a file via POST to NodeJS and then pass to another API without saving on Disk

I need to receive a file from the user in a React UI (using axios), send this file to a NodeJS method via POST using Express and then, I need to send this same file via POST directly to another API (.NET WebAPI) without saving on disk. I'm trying to pass the data file directly (req.files.file.data), but the .NET API doesn't recognise the file in the request.
Is there any possibility to create a temporary file within a "var" and send it as I do when I read a file from disk?
This example works fine with local files:
var formData = {
form: "{ abn: '666666666' }",
files: JSON.stringify([
{
name: "file1",
type: "1",
number: "6666"
},
{
name: "file2",
type: "3",
number: "3333"
},
]),
// Pass multiple values /w an Array
attachments: [
fs.createReadStream(__dirname + '/../file1.txt'),
fs.createReadStream(__dirname + '/../file2.txt')
],
};
var reqs = request.post({url:'https://tms-dev-api.micway.com.au/api/company/file', formData: formData, json: true}, function optionalCallback(err, response, body) {
if (err) {
return res.send(err);
}
return res.send({
status: response.statusCode,
body: body
});
});
I am creating a local file and then sending it through; however, I don't believe that it is the best way to do it. Like This:
router.post('/file', function(req, res) {
var fstream;
req.pipe(req.busboy);
req.busboy.on('file', function (fieldname, file, filename) {
fstream = fs.createWriteStream(__dirname + '/' + filename);
file.pipe(fstream);
var formData = {
attachments: [
fs.createReadStream(__dirname + '/' + filename)
],
};
var reqs = request.post({url:'https://tms-dev-api.micway.com.au/api/company/file', formData: formData, json: true}, function optionalCallback(err, response, body) {
if (err) {
return res.send(err);
}
console.log({
status: response.statusCode,
body: body
})
return res.send({
status: response.statusCode,
body: body
});
});
});
});
Thanks!
The solution that I find effective, is by saving it during execution, reading and manipulating the data in other to send it to the other API, and immediately delete it from Disk as soon as I get the response.
Create a PassThrough() stream instead of writing the file to the disk:
const { PassThrough } = require('stream')
...
fstream = new PassThrough()
file.pipe(fstream);

NodeJS: Uploading a remote file to S3 with request and knox

I'm trying to devise a way to upload a file from a url to s3 using request and knox. Currently, my code looks like this:
request(item.productImage, function(err, res, body) {
if (!err && res.statusCode == 200) {
fs.writeFile('/tmp/' + filename, body, 'base64', function(err, data){
if (err) {
return console.log(err);
}
client.putFile('/tmp/' + filename, '/item/' + item._id + '/' + filename, function(err, res) {
if (err) {
return console.log(err);
}
});
});
}
});
This doesn't work as it downloads about 652 bytes of a 4kb file before it stops. Strangely, if I don't provide a callback to fs.writeFile() it downloads the entire 4kb locally.
What's the best way of accomplishing this?
There are a number of questions about this here on Stackoverflow, but I can't seem to find one that answers your question. The solution below should work, however, I'm having trouble getting knox to work at all on my machine right now. I hope you will be more lucky!
UPDATE: I seem to have had some problems with s3 here, the code below works -- I did change one thing, you need to specify encoding as null to request, so you get a Buffer back. Otherwise, binary data won't work so well.
request(item.productImage, {encoding: null}, function(err, res, body) {
if(!err && res.statusCode == 200) {
var req = client.put('/item/' + item._id + '/' + filename, {
'Content-Type': res.headers['content-type'],
'Content-Length': res.headers['content-length']
});
req.on('response', function(res) {
console.log('response from s3, status:', res.statusCode, 'url:', req.url);
});
req.on('error', function(err) {
console.error('Error uploading to s3:', err);
});
req.end(body);
}
});
Note: With this solution, you avoid having to buffer the files to disk - that's why I chose to use the lower level put method of the knox client.

Categories

Resources