How to upload a file using filesystem I/O in Mean app? - angularjs

I am using fs for uploading a file in my web app but the console shows that the file has been saved to the desired location which I have entered but the file doesn't show up there.
The code is here:-
var fs = require('fs-extra');
var path = require('path');
module.exports.updatePhoto = function(req,res) {
var file = req.files.file;
var userId = req.body.userId;
console.log("User "+ userId +" is submitting ", file);
var uploadDate = new Date();
var tempPath = file.path;
var targetPath = path.join(__dirname, "../../uploads/" + userId + uploadDate +file.name);
var savePath = "/uploads/" + userId + uploadDate + file.name;
fs.rename(tempPath, targetPath,function(err){
if(err) {
console.log(err);
}
else {
User.findById(userId, function(err, userData){
var user = userData;
user.image = savePath;
user.save(function(err){
if(err) {
console.log("failed")
res.json({status: 500})
}
else {
console.log("saved");
res.json({status: 200})
}
})
})
}
})
};

Are you using connect-multiparty to get the file from Express? https://github.com/expressjs/connect-multiparty
I ended up loading the files to AWS. So the best I can offer is the code to do that. It is basically free for my usage and I use docker to rebuild my site so this make it more flexible.
My File.Js:
'use strict';
module.exports = function (app) {
/**
* Module dependencies.
*/
var auth = require('../config/auth'),
api = {},
multiparty = require('connect-multiparty'),
multipartyMiddleware = multiparty(),
path = require('path'),
uuid = require('node-uuid'),
fs = require('fs'),
S3FS = require('s3fs');
var s3fsImpl = new S3FS('FOLDER_NAME_ENTER_HERE', {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
});
/**
* Saves the logo file to the server
*/
api.uploadImage = function(req, res) {
// We are able to access req.files.file thanks to the multiparty middleware
var folder = req.params.folder;
var file = req.files.file;
var filename = uuid.v4() + path.extname(file.name);
var stream = fs.createReadStream(file.path);
s3fsImpl.writeFile(folder + '/' + filename, stream).then(function () {
fs.unlink(file.path, function (err) {
if (err) {
console.error(err);
}
});
return res.status(200).json({'fileName': filename, 'url': 'https://s3-us-west-2.amazonaws.com/AWS_FOLDER_ENTER_HERE' + folder + '/' + filename});
});
};
/**
* Routes
*/
app.route('/api/files/:folder/uploadImage')
.post(auth.jwtCheck, multipartyMiddleware, api.uploadImage);
};

Related

My code in server express for seo stuff react-app hasn't work as expected, what im doing wrong?

I made an express server for my react application, for seo optimization. I need to dynamically substitute meta tags in order to make the preview of the post look attractive when I post it on social networks. Inside the router, I make a get request via axios to the backend to get data from a specific post, and then from the received response I pull out the data from the required fields and put it in meta tags. In order to replace old data that is not fresh, I made temporary variables with data for meta tags and after a new request, temporary data is replaced with new ones and so on in a circle. My code is not working as I expect, what could be the problem? Is there a way to store temporary variables right inside the index file or do I need to make a temporary storage?
right down my index.js file:
const axios = require('axios');
const path = require('path');
const express = require('express');
const fs = require('fs');
const baseUrl = 'https://itnews.pro/pre/api';
const app = express();
const PORT = process.env.MIDDLEWARE_EXPRESS_PORT || 8084;
const indexPath = path.resolve(__dirname, '..', 'build', 'index.html');
let tempMainTitle = 'IT-NEWS';
let tempMetaTitle = '__META_OG_TITLE__';
let tempMetaUrl = '__META_OG_URL__';
let tempMetaCover = '__META_OG_IMAGE__';
let tempMetaDescription = '__META_OG_DESCRIPTION__';
let mainTitle = '';
let metaTitle = '';
let metaUrl = '';
let metaCover = '';
let metaDescription = '';
app.get('/*', (req, res, next) => {
let urlForRequest = `${baseUrl + "/publication/objects" + req.url.replace('/news/', "/").replace("/events/", "/") + "?format=json"}`;
if (req.url.includes('news') || req.url.includes('events') || req.url.includes('arcticles')) {
axios.get(urlForRequest)
.then((a_res) => {
//settings data for meta tags
mainTitle = a_res?.data?.title;
metaTitle = a_res?.data?.title;
metaUrl = baseUrl + a_res?.data?.id_full;
metaCover = baseUrl + a_res?.data?.cover;
metaDescription = a_res?.data?.short_content.replace('<p>', '').replace('</p>', '');
//cahce variable for replacing in the future with new data
tempMetaTitle = a_res?.data?.title;
tempMetaUrl = baseUrl + a_res?.data?.id_full;
tempMetaCover = baseUrl + a_res?.data?.cover;
tempMetaDescription = a_res?.data?.short_content.replace('<p>', '').replace('</p>', '');
tempMainTitle = a_res?.data?.title
return res.data;
})
.catch((err) => {
console.log("cant fetch data from expres: ", err);
})
.finally((console.log("Ooops")))
}
fs.readFile(indexPath, 'utf8', (err, htmlData) => {
if (err) {
console.error('Error during file reading', err);
return res.status(404).end()
}
htmlData = htmlData.replace(`<title>${tempMainTitle}</title>`, `<title>${mainTitle}</title>`)
.replace(tempMetaTitle, metaTitle)
.replace('__META_OG_TYPE__', 'article')
.replace(tempMetaDescription, metaDescription)
.replace(tempMetaCover, metaCover)
.replace(tempMetaUrl, metaUrl);
return res.send(htmlData);
});
});
//path to static that will be rendered
app.use(express.static(path.resolve(__dirname, '..', 'build')));
app.listen(PORT, (error) => {
if (error) {
return console.log('Error during app startup', error);
}
console.log("listening on " + PORT + "...");
});
I tried to make the request and reading from the file asynchronous and it didn't help.

how to export data into CSV and PDF files using angularjs

I want to, when i click on button (separate for both CSV and PDF), it automatically download in CSV and PDF file with correct Formatting.
this CSV code i want to add PDF inside code
$scope.downloadData = function() {
var datasets = $scope.datasets.reverse();
var file_name = $scope.m_id+ '.csv';
var dataUrl = 'data:text/csv;charset=utf-8,';
var json = [];
if(datasets !== null) {
for(idx = 0; idx < datasets.length; idx++) {
var dataset = datasets[idx].data;
var time = datasets[idx].timestamp;
time = $filter('date')(time, "dd/MMMM/yyyy-hh:mm a");
dataset.time = time;
json.push(dataset);
}
var fields = Object.keys(json[0]);
var csv = json.map(
function(row) {
return fields.map(
function(fieldName) {
return '"' + (row[fieldName] || '') + '"';
}
);
}
);
csv.unshift(fields);
var csv_str = csv.join('%0A');
var downloadURL = dataUrl + csv_str;
var saveAs = function(uri, filename) {
var link = document.createElement('a');
if (typeof link.download === 'string') {
document.body.appendChild(link); // Firefox requires the link to be in the body
link.download = filename;
link.href = uri;
link.target = "_blank";
link.click();
document.body.removeChild(link); // remove the link when done
} else {
location.replace(uri);
}
};
saveAs(downloadURL, file_name);
} else {
$scope.err_msg = 'Failed to get data. Try reloading the page.';
}
};
I try some of script i found on internet, but it is not working, some have formatting issue and save have downloading.
In Advance Thanks.
You should use this awesome library for pdf/csv or whatever else formats.. File Saver
Here's is code example, service created using FileSaver
function download(api, file, contentType) {
var d = $q.defer();
$http({
method: 'GET',
url: api,
responseType: 'arraybuffer',
headers: {
'Content-type': contentType
}
}).success(function(response) {
var data = new Blob([response], {
type: contentType+ ';charset=utf-8'
});
FileSaver.saveAs(data, file);
d.resolve(response);
}).error(function(response) {
d.reject(response);
});
return d.promise;
}
file input is name of file, you can use same service and pass the types and file names direct from controller.
Let;s you service name is homeService
for pdf call
homeservice.download('/api/download/whaever', 'export.pdf', 'application/pdf')

Zipping multiple files in Nodejs having size ~ 300kb each and streaming to client

My code is working fine when I zip 3 files around 300kb each and send it to client. Used following links for help:
Dynamically create and stream zip to client
how to convert multiple files to compressed zip file using node js
But as soon as I try to zip 4th file I get "download - Failed Network error" in chrome.
Following is my code:
var express = require('express');
var app = express();
var fileSystem = require('fs');
var Archiver = require('archiver');
var util = require('util');
var AdmZip = require('adm-zip');
var config = require('./config');
var log_file = fileSystem.createWriteStream(__dirname + '/debug.log', {flags : 'a'});
logError = function(d) { //
log_file.write('[' + new Date().toUTCString() + '] ' + util.format(d) + '\n');
};
app.get('/zip', function(req, res, next) {
try {
res = setHeaderOfRes(res);
sendZip(req, res);
}catch (err) {
logError(err.message);
next(err); // This will call the error middleware for 500 error
}
});
var setHeaderOfRes = function (res){
res.setHeader("Access-Control-Allow-Origin", "*"); //Remove this when this is on production
res.setHeader("Content-Type", "application/zip");
res.setHeader("Content-disposition", "attachment;");
return res;
};
var sendZip = function (req, res) {
var filesNotFound = [];
zip.pipe(res);
if (req.query.leapIds) {
var leapIdsArray = req.query.leapIds.split(',');
var i, lengthi;
for (i = 0, lengthi = leapIdsArray.length; i < lengthi; i++) {
try {
var t = config.web.sharedFilePath + leapIdsArray[i] + '.vsdx';
if (fileSystem.statSync(t).isFile()) {
zip.append(new fileSystem.createReadStream(t), {
name: leapIdsArray[i] + '.vsdx'
});
};
} catch (err) {
filesNotFound.push(leapIdsArray[i] + '.vsdx');
}
}
var k, lengthk;
var str = '';
for (k = 0, lengthk = filesNotFound.length; k < lengthk; k++) {
str += filesNotFound[k] +',';
}
if(filesNotFound.length > 0){
zip.append('These file/files does not exist on server - ' + str , { name: 'logFile.log' });
}
zip.finalize();
}
};
I tried zip.file instead of zip.append that didn't work.
I want to zip minimum 10 files of 300kb each and send it to the client. Can anyone please let me know the approach.
Thanks
/********************* Update ****************************************
I was only looking at server.js created in node. Actually the data is sent correctly to client. Angularjs client code seems to be not working for large files.
$http.get(env.nodeJsServerUrl + "zip?leapIds=" + nodeDetails, { responseType: "arraybuffer" }
).then(function (response) {
nodesDetails = response.data;
var base64String = _arrayBufferToBase64(nodesDetails);
function _arrayBufferToBase64(buffer) {
var binary = '';
var bytes = new Uint8Array(buffer);
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return window.btoa(binary);
}
var anchor = angular.element('<a/>');
anchor.attr({
href: 'data:application/zip;base64,' + base64String,
target: '_blank',
download: $scope.main.routeParams.sectorId + "-ProcessFiles.zip"
})[0].click();
});
This part href: 'data:application/zip;base64,' + base64String, seems to be failing for large data received from server. For small files it is working. Large files it is failing.
Found out.
The problem was not in nodejs zipping logic. That worked perfect.
Issue was in the way I was handling the received response data.
If the data that is received is too large then following code fails
anchor.attr({
href: 'data:application/zip;base64,' + base64String,
target: '_blank',
download: $scope.main.routeParams.sectorId + "-ProcessFiles.zip"
})[0].click();
so the work around is to use blob:
function b64toBlob(b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
var byteCharacters = atob(b64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
var blob = new Blob(byteArrays, { type: contentType });
return blob;
}
var contentType = 'application/zip'
var blob = b64toBlob(base64String, contentType);
saveAs(blob, "hello world.zip");
This link helped me out: How to save binary data of zip file in Javascript?
already answered here: https://stackoverflow.com/a/62639710/8612027
Sending a zip file as binary data with expressjs and node-zip:
app.get("/multipleinzip", (req, res) => {
var zip = new require('node-zip')();
var csv1 = "a,b,c,d,e,f,g,h\n1,2,3,4,5,6,7,8\n1,2,3,4,5,6,7,8\n1,2,3,4,5,6,7,8\n1,2,3,4,5,6,7,8";
zip.file('test1.file', csv1);
var csv2 = "z,w,x,d,e,f,g,h\n1,2,3,4,5,6,7,8\n1,2,3,4,5,6,7,8\n1,2,3,4,5,6,7,8\n1,2,3,4,5,6,7,8";
zip.file('test2.file', csv2);
var csv3 = "q,w,e,d,e,f,g,h\n1,2,3,4,5,6,7,8\n1,2,3,4,5,6,7,8\n1,2,3,4,5,6,7,8\n1,2,3,4,5,6,7,8";
zip.file('test3.file', csv3);
var csv4 = "t,y,u,d,e,f,g,h\n1,2,3,4,5,6,7,8\n1,2,3,4,5,6,7,8\n1,2,3,4,5,6,7,8\n1,2,3,4,5,6,7,8";
zip.file('test4.file', csv4);
var data = zip.generate({base64:false,compression:'DEFLATE'});
console.log(data); // ugly data
res.type("zip")
res.send(new Buffer(data, 'binary'));
})
Creating a download link for the zip file. Fetch data and convert the response to an arraybuffer with ->
//get the response from fetch as arrayBuffer...
var data = response.arrayBuffer();
const blob = new Blob([data]);
const fileName = `${filename}.${extension}`;
if (navigator.msSaveBlob) {
// IE 10+
navigator.msSaveBlob(blob, fileName);
} else {
const link = document.createElement('a');
// Browsers that support HTML5 download attribute
if (link.download !== undefined) {
const url = URL.createObjectURL(blob);
link.setAttribute('href', url);
link.setAttribute('download', fileName);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}

Saving Location of Scraped Image to DB - Node/MEAN

After scraping an image I'm able to download to a folder using request. I would like to pass along the location of this image to my Mongoose collection.
In the callback I think there should be a way to save the location so I can pass this along when saving my model object.
exports.createLook = function(req, res) {
var url = req.body.image;
var randomizer = '123456';
var download = function(url, filename, callback) {
request(url)
.pipe(fs.createWriteStream(filename))
.on('close', callback);
};
download(url, '../client/assets/images/' + randomizer + '.jpg', function() {
console.log('done');
// do something?
});
// now get model details to save
var newLook = new Look();
newLook.title = req.body.title;
newLook.image = // image location
newLook.save(function(err, look) {
if(err) return res.send(500);
} else {
res.send(item);
}
}
Assuming that 'randomizer' will be generated I would do:
exports.createLook = function(req, res) {
var url = req.body.image;
var randomizer = getSomthingRandom();
var download = function(url, filename, callback) {
request(url)
.pipe(fs.createWriteStream(filename))
.on('close', callback(filename);
};
download(url, '../client/assets/images/' + randomizer + '.jpg', function(filename) {
console.log('done');
// now get model details to save
var newLook = new Look();
newLook.title = req.body.title;
newLook.image = filename;
....
});

How do you upload an image file to mongoose database using mean js

I am new to the mean stack. I want to know how to upload an image file to the database(mongoose) through angularjs. If possible, please provide me with some code. I have searched the internet but I haven't found any suitable code.
You have plenty ways and tools to achieve what you want. I put one of them here:
For this one I use angular-file-upload as client side. So you need this one in your controller:
$scope.onFileSelect = function(image) {
if (angular.isArray(image)) {
image = image[0];
}
// This is how I handle file types in client side
if (image.type !== 'image/png' && image.type !== 'image/jpeg') {
alert('Only PNG and JPEG are accepted.');
return;
}
$scope.uploadInProgress = true;
$scope.uploadProgress = 0;
$scope.upload = $upload.upload({
url: '/upload/image',
method: 'POST',
file: image
}).progress(function(event) {
$scope.uploadProgress = Math.floor(event.loaded / event.total);
$scope.$apply();
}).success(function(data, status, headers, config) {
$scope.uploadInProgress = false;
// If you need uploaded file immediately
$scope.uploadedImage = JSON.parse(data);
}).error(function(err) {
$scope.uploadInProgress = false;
console.log('Error uploading file: ' + err.message || err);
});
};
And following code in your view (I also added file type handler for modern browsers):
Upload image <input type="file" data-ng-file-select="onFileSelect($files)" accept="image/png, image/jpeg">
<span data-ng-if="uploadInProgress">Upload progress: {{ uploadProgress }}</span>
<img data-ng-src="uploadedImage" data-ng-if="uploadedImage">
For server side, I used node-multiparty.
And this is what you need in your server side route:
app.route('/upload/image')
.post(upload.postImage);
And in server side controller:
var uuid = require('node-uuid'),
multiparty = require('multiparty'),
fs = require('fs');
exports.postImage = function(req, res) {
var form = new multiparty.Form();
form.parse(req, function(err, fields, files) {
var file = files.file[0];
var contentType = file.headers['content-type'];
var tmpPath = file.path;
var extIndex = tmpPath.lastIndexOf('.');
var extension = (extIndex < 0) ? '' : tmpPath.substr(extIndex);
// uuid is for generating unique filenames.
var fileName = uuid.v4() + extension;
var destPath = 'path/to/where/you/want/to/store/your/files/' + fileName;
// Server side file type checker.
if (contentType !== 'image/png' && contentType !== 'image/jpeg') {
fs.unlink(tmpPath);
return res.status(400).send('Unsupported file type.');
}
fs.rename(tmpPath, destPath, function(err) {
if (err) {
return res.status(400).send('Image is not saved:');
}
return res.json(destPath);
});
});
};
As you can see, I store uploaded files in file system, so I just used node-uuid to give them unique name. If you want to store your files directly in database, you don't need uuid, and in that case, just use Buffer data type.
Also please take care of things like adding angularFileUpload to your angular module dependencies.
I got ENOENT and EXDEV errors. After solving these, below code worked for me.
var uuid = require('node-uuid'),
multiparty = require('multiparty'),
fs = require('fs');
var form = new multiparty.Form();
form.parse(req, function(err, fields, files) {
var file = files.file[0];
var contentType = file.headers['content-type'];
var tmpPath = file.path;
var extIndex = tmpPath.lastIndexOf('.');
var extension = (extIndex < 0) ? '' : tmpPath.substr(extIndex);
// uuid is for generating unique filenames.
var fileName = uuid.v4() + extension;
var destPath = appRoot +'/../public/images/profile_images/' + fileName;
// Server side file type checker.
if (contentType !== 'image/png' && contentType !== 'image/jpeg') {
fs.unlink(tmpPath);
return res.status(400).send('Unsupported file type.');
}
var is = fs.createReadStream(tmpPath);
var os = fs.createWriteStream(destPath);
if(is.pipe(os)) {
fs.unlink(tmpPath, function (err) { //To unlink the file from temp path after copy
if (err) {
console.log(err);
}
});
return res.json(destPath);
}else
return res.json('File not uploaded');
});
for variable 'appRoot' do below in express.js
path = require('path');
global.appRoot = path.resolve(__dirname);

Resources