Downloading a file from Mongoose in Angular - angularjs

I've managed to upload a file and store it in my MongoDB, but now I want to be able to downlaod this file from the same mongoDB. In server-side I'm using the GridFS module in Mongoose to upload and download using the gfs-read/write-stream.
Downlaod code in Mongoose looks like :
app.post('/Download', function (req, res) {
grid.mongo = mongoose.mongo;
var gfs = grid(conn.db);
var readstream = gfs.createReadStream({
filename: 'Program.cs'
});
readstream.pipe(res);
})
In my angular i have this so far:
$scope.Download = function () {
$http.post(url + "/Download")
.success(function (res) {
console.log(res);
})
}
the console.log response is shown here
I want to save this content into a .cs file in my local file system, also want to be able to prompt the user for the download-path, How do I do this?

Try below code
app.post('/Download', function (req, res) {
var filenameId = "";// mention _id value of 'Program.cs'
var filename = 'Program.cs';
var _id = new ObjectID(filenameId );
var gfs = new Grid(conn.db, "yourfile_collection_name");// default value is fs
gfs.get(_id, function(err, data) {
if (err)
throw err;
res.setHeader('Content-Disposition','attachment; filename="' + filename + '"');
res.send(data);
});
};

Related

I cant download a zip file in AngularJS (from Laravel response)

I am trying to download a zip file from a Laravel API using Angular JS. I do not believe the issue is from Laravel.
Basically when the response comes and the download trigger is made it does not know its a .zip file, however the file itself is good. But then when I manually add the .zip extension in Angular JS in the file name the browser advises its a corrupt file.
If I do not add the extension, it downloads fine, and then if i rename the file with no extension in Windows and change it to test.zip it works perfectly as a zip file. This is how I know the data is good.
I have tried arraybuffer responseType and blob. With blob I am getting the download trigger, with arraybuffer nothing is happening (including no console errors).
Here is my JS controller code:
vm.downloadSelectedFiles = function() {
vm.selectedFiles = [];
angular.forEach(vm.fileDownloadList, function(value,index) {
if(value==1) {
vm.selectedFiles.push(index);
}
});
Data.downloadSelectedFiles(vm.selectedFiles,vm.stationIDToLookUp)
.then(function (data) {
var url = $window.URL || $window.webkitURL;
vm.fileUrl = url.createObjectURL(data.data);
var a = document.createElement("a");
a.href = vm.fileUrl;
a.download = 'test.zip';
//a.download = 'test';
a.click();
}).catch(function (err) {
});
}
Here is my JS service code
downloadSelectedFiles: function downloadSelectedFiles(selectedFiles,stationID) {
var apiBase = apiUrl + 'download-selected-files';
var config = {
//responseType: 'arraybuffer'
responseType: 'blob'
};
var data = {
selectedFiles: selectedFiles,
stationID: stationID
}
return $http.post(apiBase, data, config);
}
And just in case there is something relevant about the response from the API. Here is my Laravel code
public function downloadSelectedFiles(PublishDataRequest $requestData) {
return response()->file(storage_path() . '/app/files/test.zip');
}
Try setting the MIME type to application/zip:
Data.downloadSelectedFiles(vm.selectedFiles,vm.stationIDToLookUp)
.then(function (response) {
var blob = response.data;
var zipBlob = new Blob([blob], { type: "application/zip" });
var url = $window.URL || $window.webkitURL;
vm.fileUrl = url.createObjectURL(zipBlob);
var a = document.createElement("a");
a.href = vm.fileUrl;
a.download = 'test.zip';
//a.download = 'test';
a.click();
}).catch(function (response) {
console.log("ERROR", response);
throw response;
});

passing extra info to multer Upload API

I am using the multer way for upload in node.js, explained in detail here https://ciphertrick.com/2015/12/07/file-upload-with-angularjs-and-nodejs/
I am trying to pass another information with requested data which is called invoiceId:
Upload.upload({
url: 'http://localhost:4000/api/ubiq/listInvoiceAttachedFiles/attach', //webAPI exposed to upload the file
data: {file: file, invoiceId:invoiceId} //pass file as data, should be user ng-model
}).then(function (resp) { //upload function returns a promise
if (resp.data.error_code === 0) { //validate success
$window.alert('Success ' + resp.config.data.file.name + ' uploaded');
console.log(resp.config.data.file); ....etc
But I am getting req.body empty on the server side:
/** API path that will upload the files */
server.post('/api/ubiq/listInvoiceAttachedFiles/attach', function(req, res) {
console.log(req.body);
security.verifyPermission("/api/ubiq/listInvoiceAttachedFiles/attach", req.session.currentUser, true /*isInSession*/).then(function (successInfo) {
if (!successInfo.isAllowed) {
console.log('not allowed');
return res.json(apiHelp.notAllowed());
}
What am I doing wrong?
Multer re-attaches the body object within the callback of the upload function.
Your data should be available after this line.
https://github.com/rahil471/file-upload-with-angularjs-and-nodejs/blob/master/server/app.js#L35
The following snippet is my working code and I have tested and used multiple time in my application.
Multer have two storage engines:
DiskStorage
MemoryStorage
I have used DiskStorage, which gives more control over disk storage on file.
var express = require("express");
var app = express()
var router = express.Router();
var multer = require("multer");
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, dirPath);
},
filename: function (req, file, cb) {
var datetimestamp = Date.now() + Math.floor(Math.random() * (1 - 99999999999 + 1)) + 9999999999999;
cb(null, datetimestamp + '.' + file.originalname.split('.')[file.originalname.split('.').length - 1].toLowerCase());
}
});
var infoUpload = multer({storage: storage});
router
.route(API_PATH)
.post(infoUpload.array("file"), function (req, res) {
console.log(req.body);
});
Following are few links which give you a brief explanation.
http://derpturkey.com/node-multipart-form-data-explained/
http://alexkatz.me/posts/image-upload-with-node-and-multer/
Hope it may help to resolve an issue.

File download using SuperAgent

I'm trying to download files from server using SuperAgent. Please find the code below.
downloadDocument(fileIdMongo) {
var request = require('superagent');
var apiBaseUrl = "api/downloadDoc";
var self = this;
var req = request.get(apiBaseUrl);
req.query({ id: fileIdMongo })
req.end(function(err, res) {
if (err) {
console.log("error ocurred");
} else {
var blob = new Blob([res.text], {
type: 'text/csv/jpeg/jpg/png/pdf/docx/doc;charset=utf8;'
});
var element = document.createElement('a');
document.body.appendChild(element);
element.download = "Capture.PNG";
element.href = window.URL.createObjectURL(blob);
element.style.display = '';
element.click();
}
});
}
I'm trying to get a .png file from the server. I tested server with PostMan rest client. I'm able to get the .png file. But the file is not visible when using SuperAgent.
Use the below line of code in the else part.
window.location= 'api/CommercialInvoice?item=' + item.id,'';
element.click();

nodejs write simple image blob - Upload.dataUrltoBlob

Simple question. How do I save a image blob in Nodejs from angular.
AngularSide:
$scope.upload = function (dataUrl, picFile) {
Upload.upload({
url: 'http://test.dev:3000/register/user/uploads',
data: {
file: Upload.dataUrltoBlob(dataUrl, picFile.name)
},
}).then(function (response) {
$timeout(function () {
$scope.result = response.data;
});
}, function (response) {
if (response.status > 0) $scope.errorMsg = response.status
+ ': ' + response.data;
}, function (evt) {
$scope.progress = parseInt(100.0 * evt.loaded / evt.total);
});
}
nodejs side: Do I need middleware here? if so which one should I use?
router.post('/user/uploads', multipartMiddleware, function(req, resp) {
var newPath = "/Users/testUser/test_hold_files/" + req.files.file.originalFilename;
fs.writeFile(newPath, req.files.file, function(err) {
if (err) {
console.log("Data Error ");
return console.error(err);
}
});
res.status(200).jsonp({status: "status: success "});
});
right now this just writes out the file with correct name but its empty.
You used to be able to access the uploaded file through req.files.imageName and then you would fs.readFile from tmp and write it permanently, which is no longer the case in express 4.0
In Express 4, req.files is no longer available on the req object by default. To access uploaded files on the req.files object, use multipart-handling middleware like busboy, multer, formidable, multiparty, connect-multiparty, or pez.
Soooooooo, you can feel free to use which ever one of those middlewares names above and then follow their API for dealing with uploaded files like images. Hope this helps, enjoy.
Ok,
After a long time of messing with this stuff. I found an answer. It does load the file in my folder.
I feel this is only partial since it does not resize the actual file smaller. It is what is selected with https://github.com/danialfarid/ng-file-upload. I used the
Upload.upload({
url: 'http://test.dev:3000/register/user/uploads',
data: {
file: Upload.dataUrltoBlob(dataUrl, picFile.name)
},
This did zoom into the file on selected image. It did not make the actual file size smaller. I am still looking into this issue.
var formidable = require('formidable'),
util = require('util'),
fs_extra = require('fs-extra');
This is my post to accept images.
router.post('/user/uploads', function (req, res){
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
res.writeHead(200, {'content-type': 'text/plain'});
res.write('received upload:\n\n');
res.end(util.inspect({fields: fields, files: files}));
});
form.on('end', function(fields, files) {
/* Temporary location of our uploaded file */
var temp_path = this.openedFiles[0].path;
/* The file name of the uploaded file */
var file_name = this.openedFiles[0].name;
/* Location where we want to copy the uploaded file */
var new_location = "/Users/testUser/test_hold_files/";
fs_extra.copy(temp_path, new_location + file_name, function(err) {
if (err) {
console.error(err);
} else {
console.log("success!")
}
});
});
});
I have also noticed that I can view the file in chrome but not load it into gimp. Gimp gives me a file error.
Small steps I guess.
Maybe Datsik can give us some insight on what is going on here.
https://stackoverflow.com/users/2128168/datsik
Phil

How to retrieve all images from gridFs in a single http Request

I am new in mean.js(angular.js+node.js) and using GridFs to store images. In order to retrieve the images now i am sending a http request for each image. I am worried about the fact that whether it will affect the speed of the site. So i want to retrieve all images together From gridFs. Is that possible? can anybody help me? below provided is my client side code.
$http.get('/uploads?filename=' + imagename).success(function(response) {
$scope.img.push({imageph: response, image: item.image, url: item.url});
}).error(function (err) {
console.log('Error uploading file: ' + err);
});
my server side code is:
var qo = url.parse(req.url, true).query;
var filename = qo.filename;
if (filename !== 'undefined')
{
var rstream = gfs.createReadStream(filename);
var bufs = [];
rstream.on('data', function (chunk) {
bufs.push(chunk);
}).on('error', function () {
res.send();
})
.on('end', function () { // done
var fbuf = Buffer.concat(bufs);
var imageFile = (fbuf.toString('base64'));
var ret = 'data:image/jpeg;base64,' + imageFile;
res.send(ret);
});
}

Resources