I am tring to upload a file using angular $http method to node backend
I want to upload the form with additional form fields.
This is my code
var data = new FormData();
data.append('title', 'sometitle');
data.append('uploadedFile', $scope.uploadedFile);
FileService.upload(url, data, function(data, status) {
if(status===HTTP_OK) {
$scope.uploadSuccess = true;
$scope.showUploadProgressBar = false;
} else {
// error occured
console.log(data);
}
});
FileService
FileService.upload = function(url, data, callback) {
$http({
method : 'POST',
url : url,
data : data,
headers: {'Content-Type': undefined },
transformRequest: angular.identity
}).success(function(data, status) {
callback(data, callback);
}).error(function(data, status) {
callback(data, status);
});
};
I am using node multiparty module for file upload. I am receiving the file correctly. But the field value for title is undefined.
I don't know why title value is undefined
Node.js backend file upload handler
var form;
if(options.uploads.tempDir) {
form = new multiparty.Form({uploadDir : options.root + '/' + options.uploads.tempDir});
} else {
form = new multiparty.Form();
}
form.on('file', function(name, receivedFile) {
var tmpPath = receivedFile.path,
fileName = receivedFile.originalFilename,
targetDirectory = uploadDirectory + '/' + req.params.id,
targetPath = targetDirectory + '/' + fileName,
file = {
filePath : targetPath,
tempPath : tmpPath,
fileName : fileName,
size : receivedFile.size
};
fileUploadStatus.file = file;
// move file
fse.move(tmpPath, targetPath, function(err) {
if(err) {
console.log('Error moving file [ ' + targetPath + ' ] ' + JSON.stringify(err));
}
});
});
form.on('error', function(err) {
fileUploadStatus.err = err;
req.fileUploadStatus = fileUploadStatus;
next();
});
form.on('close', function() {
req.fileUploadStatus = fileUploadStatus;
next();
});
form.on('field', function(name, value) {
console.log('field called');
console.log(name);
console.log(value);
req.body = req.body || {};
req.body[name] = value;
});
// ignoring parts. Implement any other logic here
form.on('part', function(part) {
var out = new stream.Writable();
out._write = function (chunk, encoding, done) {
done(); // Don't do anything with the data
};
part.pipe(out);
});
// parsing form
form.parse(req);
Related
Trying to upload file from web application to SharePoint directory. Upon successful upload, only the filename is saved to the database. A SharePoint link is hard coded in the frontend to view the file uploaded.
Problem encountered: Sometimes the upload fails with an error message "session was expired.. Please clear the local storage." Clearing cache does not help.
importFiles: retrieves an array of all files from the database.
saveFile: adds the last successfully file name to the end of the array
clearCache: clears the input type [rename field]
var savingFile = function () {
importFiles(() => saveFile(() => clearCache(() => {
$('#modal').modal('hide');
init();
})));
Following is to upload the selected file to the SharePoint directory.
upon successfully upload, () => { savingFile(); }); is called to save the file.
upload_SP() {
if (app.selectedFile.length == 0) {
alert("please select file to upload..");
app.isLoading = false;
return;
}
_.each(app.selectedFile, function (item, index) {
var blob = item.slice(0, item.size, 'image/jpg');
app.finalFile = new File([blob], app.renameFile[index] + '.jpeg', { type: 'image/jpg' });
});
var formData = new FormData();
_.each(app.finalFile, function (file, index) {
formData.append('file-' + index, file);
});
app.sp_action(app.parentId, app.folderId, app.finalFile.name, app.finalFile,
() => { savingFile(); });
}
},
Following method takes the arguments required to upload the file to the SP.
sp_action(parentId, folderId, fileName, data, callback = null) {
$.fileUploadSP(parentId, folderId, fileName, data, function (response) {
app.isSuccessful = response.isSuccessful;
if (response == "success") {
alert("Successfully Uploaded..");
app.messageDismissCountDown = 3;
if (callback) {
callback(response);
}else {
location.reload();
}
}
else {
clearCache(() => { });
app.message = response.message;
app.isLoading = false;
window.scrollTo(0, 0);
}
});
},
Following is AJAX call made to upload the file to the SharePoint.
window.$.getPathSP = function (parentId, forlderId, fileName) {
var origin = "https://graph.microsoft.com/v1.0/drives/" + parentId + "/items/" + forlderId +
":/" + fileName + ":/content"
return origin;
};
window.$.fileUploadSP = function (parentId, forlderId, fileName, data, callback) {
$.ajax({
type: 'PUT',
url: $.getPathSP(parentId, forlderId, fileName),
headers: graphHeader,
data: data,
contentType: false,
processData: false,
async: true,
crossDomain: true,
cache: false,
success: function (response) {
success(response, function () {
if (callback) {
callback("success");
}
});
},
failure: function (response) {
alert("failed")
failure(response, "fail");
},
error: function (response) {
alert("session was expired.. Please clear the local storage.")
error(response, callback);
}
});
};
I'm attempting to retrieve an e-mail attachment image using Node.js imap that can be found here: https://github.com/mscdex/node-imap
After retrieving the image I want to save it to file and then save the name in the MySQL database so I can retrieve it in the front end using EJS.
I've gotten as far as retrieving the e-mail attachment image and attempting to decode it and then save it. Unfortunately when opened from the folder it says: "It appears that we don't support this file format".
Upon further investigation, if I convert it to a base64 string using this online tool: https://www.motobit.com/util/base64-decoder-encoder.asp and then go to a base64 to image converter (https://codebeautify.org/base64-to-image-converter), it shows the image just fine.
I'm skeptical that my code is actually converting the image to base64 as the file size goes up from 250kb to 332kb.
I am unsure of how to proceed to allow the photo to be properly decoded for viewing as the original .jpeg image.
var fs = require('fs'), fileStream;
var {Base64Encode} = require('base64-stream');
const Imap = require('imap'),
inspect = require('util').inspect;
var imap = new Imap({
user: 'gmailaccount#gmail.com',
password: 'gmailaccount',
host: 'imap.gmail.com',
port: 993,
tls: true
});
/* To Uppercase function */
function toUpper(thing) { return thing && thing.toUpperCase ? thing.toUpperCase() : thing;}
/* function to find attachments in imap email */
function findAttachmentParts(struct, attachments) {
attachments = attachments || [];
for (var i = 0, len = struct.length, r; i < len; ++i) {
if (Array.isArray(struct[i])) {
findAttachmentParts(struct[i], attachments);
}
else {
if (struct[i].disposition && ['INLINE', 'ATTACHMENT'].indexOf(struct[i].disposition.type) > -1) {
attachments.push(struct[i]);
}
}
}
return attachments;
}
function buildAttMessageFunction(attachment) {
var filename = attachment.params.name;
var encoding = attachment.encoding;
return function (msg, seqno) {
var prefix = '(#' + seqno + ') ';
msg.on('body', function(stream, info) {
//Create a write stream so that we can stream the attachment to file;
console.log(prefix + 'Streaming this attachment to file', filename, info);
var writeStream = fs.createWriteStream(filename);
writeStream.on('finish', function() {
console.log(prefix + 'Done writing to file %s', filename);
});
//stream.pipe(writeStream); this would write base64 data to the file.
//so we decode during streaming using
if (toUpper(encoding) === 'BASE64') {
//the stream is base64 encoded, so here the stream is decode on the fly and piped to the write stream (file)
stream.pipe(new Base64Encode()).pipe(writeStream);
} else {
//here we have none or some other decoding streamed directly to the file which renders it useless probably
stream.pipe(writeStream);
}
});
msg.once('end', function() {
console.log(prefix + 'Finished attachment %s', filename);
});
};
}
function openInbox(cb){
imap.openBox('INBOX', true, cb);
}
/* Take all unseen emails, output to console and save them to a text file */
imap.once('ready', function(){
openInbox(function(err, box){
if (err) throw err;
imap.search([ 'UNSEEN' ], function(err, results) {
var messages = [];
if (err) throw err;
var f = imap.fetch(results, { id: 1, bodies: ['HEADER.FIELDS (FROM TO SUBJECT DATE)', '1.1'], struct: true });
f.on('message', function(msg, seqno) {
var body = ''
, header = ''
, parsedMsg = {}
var prefix = '(#' + seqno + ') ';
msg.on('body', function(stream, info) {
var buffer = '', count = 0;
if(info.which === 'TEXT' || info.which === '1.1'){
stream.on('data', function(chunk) { body += chunk.toString('utf8') })
stream.once('end', function() { parsedMsg.body = body })
}
else{
stream.on('data', function(chunk) { header += chunk.toString('utf-8') })
stream.once('end', function() { parsedMsg.header = Imap.parseHeader(header) })
}
stream.pipe(fs.createWriteStream('msg-' + seqno + '-body.txt'));
});
msg.once('attributes', function(attrs) {
var attachments = findAttachmentParts(attrs.struct);
console.log(prefix + 'Has attachments: %d', attachments.length);
for(var i = 0, len = attachments.length; i < len; ++i){
var attachment = attachments[i];
/*This is how each attachment looks like {
partID: '2',
type: 'application',
subtype: 'octet-stream',
params: { name: 'file-name.ext' },
id: null,
description: null,
encoding: 'BASE64',
size: 44952,
md5: null,
disposition: { type: 'ATTACHMENT', params: { filename: 'file-name.ext' } },
language: null
}
*/
console.log(prefix + 'Fetching attachment %s', attachment.params.name);
var f = imap.fetch(attrs.uid , {
bodies: [attachment.partID],
struct: true
});
//build function to process attachment message
f.on('message', buildAttMessageFunction(attachment));
}
parsedMsg.attrs = attrs;
console.log(prefix + 'Attributes: %s', inspect(attrs, false, 8));
});
msg.once('end', function() {
console.log(prefix + 'Finished email');
messages.push( parsedMsg );
});
});
f.once('error', function(err) {
console.log('Fetch error: ' + err);
});
f.once('end', function() {
console.log('Done fetching all messages!');
for( i in messages ) {
console.log( i + ': ' + inspect( messages[i], false, 4 ) );
}
imap.end();
});
});
});
});
imap.once('error', function(err){
console.log(err);
});
imap.once('end', function(){
console.log('Connection ended');
});
imap.connect();
The expected output is a .jpeg image saved to the file directory that is able to be viewed. The actual output I am getting is an image file that when double clicked to view says: "It appears that we don't support this file format."
Unfortunately, I couldn't find a way to use node-imap to properly decode and retrieve email attachments. I ended up using imap-simple instead and was able to achieve the desired result.
I used imap-simple's example code block to retrieve attachments.
var imaps = require('imap-simple');
var config = {
imap: {
user: 'your#email.address',
password: 'yourpassword',
host: 'imap.gmail.com',
port: 993,
tls: true,
authTimeout: 3000
}
};
imaps.connect(config).then(function (connection) {
connection.openBox('INBOX').then(function () {
// Fetch emails from the last 24h
var delay = 24 * 3600 * 1000;
var yesterday = new Date();
yesterday.setTime(Date.now() - delay);
yesterday = yesterday.toISOString();
var searchCriteria = ['UNSEEN', ['SINCE', yesterday]];
var fetchOptions = { bodies: ['HEADER.FIELDS (FROM TO SUBJECT DATE)'], struct: true };
// retrieve only the headers of the messages
return connection.search(searchCriteria, fetchOptions);
}).then(function (messages) {
var attachments = [];
messages.forEach(function (message) {
var parts = imaps.getParts(message.attributes.struct);
attachments = attachments.concat(parts.filter(function (part) {
return part.disposition && part.disposition.type.toUpperCase() === 'ATTACHMENT';
}).map(function (part) {
// retrieve the attachments only of the messages with attachments
return connection.getPartData(message, part)
.then(function (partData) {
return {
filename: part.disposition.params.filename,
data: partData
};
});
}));
});
return Promise.all(attachments);
}).then(function (attachments) {
console.log(attachments);
// =>
// [ { filename: 'cats.jpg', data: Buffer() },
// { filename: 'pay-stub.pdf', data: Buffer() } ]
});
});
On both instances of Base64Encode rename it to Base64Decode.
I have a node.js app that has a few files that I am working with, but the main two javascript files are a RestController and AuthController. The RestController is supposed to call the AuthController to pull a new access token from Salesforce, the server that I am attempting to hit.
I currently set up my AuthController.js to work with promises so that I can wait to get my access token. The problem is I have no idea how to get my RestController.js file to wait for the access token from the AuthController.js file.
I am also very very new to Javascript and Promises, so I am not sure if I even set up my functions correctly. Basically, I want my AuthController to handle getting the access token and the RestController to handle the Rest request to our server.
AuthController.js
var fs = require('fs');
var jwt = require('jsonwebtoken');
var request = require('request');
var querystring = require('querystring');
var config = require('../../configs/config.json');
var filename = __dirname + '/../../' + config.key_path;
var access_token;
var readFilePromise = function(file) {
return new Promise(function(ok, notOk) {
fs.readFile(file, function(err,data) {
if (err) {
notOk(err);
} else {
ok(data);
}
});
});
}
var getAccessToken = function(key) {
return new Promise(function(ok,notOk) {
var jwtparams = {
iss : config.client_id,
sub: config.username,
aud: 'https://' + config.host,
exp : Date.now() + 300
};
var token = jwt.sign(jwtparams, key, {algorithm: 'RS256'});
var data = querystring.stringify({
grant_type : 'urn:ietf:params:oauth:grant-type:jwt-bearer',
assertion : token
});
request.post({
headers: {
'Content-Type' : 'application/x-www-form-urlencoded',
'Content-Length' : data.length
},
url: 'https://' + config.host + '/services/oauth2/token',
body: data
}, function(error, response, body) {
if (error) {
return notOk(error);
}
try {
ok(JSON.parse(body).access_token);
} catch (e) {
notOk(e);
}
});
});
}
function main() {
readFilePromise(filename).then(function(data) {
getAccessToken(data.toString()).then(function(data) {
access_token = data.toString();
});
});
}
module.exports = {main};
RestController.js
var https = require('https');
var request = require('request');
var auth = require('./authController.js');
class SystemController {
doProcessPostStatus (req,res) {
if (!req.body.systemId) {
return res.status(400).send([
{
'errorCode' : 'INVALID_REQUEST_BODY',
'message' : 'System Id "systemId" variable is required.'
}
]);
} else if (typeof req.body.success === 'undefined') {
return res.status(400).send([
{
'errorCode' : 'INVALID_REQUEST_BODY',
'message' : 'Success "success" variable is required'
}
]);
} else if (!req.body.message) {
return res.status(400).send([
{
'errorCode' : 'INVALID_REQUEST_BODY',
'message' : 'Message "message" variable is required'
}
]);
}
var access_token = auth.main();
console.log(access_token);
}
}
var systemControllerVar = new SystemController();
module.exports = systemControllerVar;
Any help is greatly appreciated as I am currently stuck, thanks!
I want to get the image path after the execution of the uploadFiles function. This way, I will have the value assigned to self.ProjectImagePath. But it is not working, I think it executes right after the function call. Anyone can help ?
self.submitProject = function(file) {
console.log("Submit Project \n");
uploadFiles.apply(this, arguments);
console.log(self.ProjectImagePath); ///ERROR HERE!!!! (UNDEFINED)
var data = JSON.stringify({
name: self.ProjectName,
room: self.room,
managers: self.Managers,
members: self.ProjectMembers,
image: self.ProjectImagePath
});
//console.log(data);
$http.post('/rooms/' + self.room + '/project', data).success(function(data) {
//$window.location.href = "/";
});
}
function uploadFiles(file) {
file.upload = Upload.upload({
url: 'projectImages/upload',
data: {
file: file
}
});
file.upload.then(function(response) {
$timeout(function() {
file.result = response.data;
self.ProjectImagePath = file.result;
});
}, function(response) {
if (response.status > 0)
self.errorMsg = response.status + ': ' + response.data;
});
}
After execution, the image is uploaded to the server but I cant get its path.
Im using AngularJS
You were having issues with calling code before the promise (asynchronous action) was finished.
This should do what you need:
self.submitProject = function(file) {
console.log("Submit Project");
function handleSuccess(response) {
self.ProjectImagePath = file.result = response.data;
// Should work correctly.
console.log(self.ProjectImage);
var data = JSON.stringify({
name: self.ProjectName,
room: self.room,
managers: self.Managers,
members: self.ProjectMembers,
image: self.ProjectImagePath
});
$http.post('/rooms/' + self.room + '/project', data).success(function(data) {
//$window.location.href = "/";
});
}
function handleError(response) {
if (response.status > 0)
self.errorMsg = response.status + ': ' + response.data;
}
uploadFiles(file, handleSuccess, handleError);
};
function uploadFiles(file, successCallback, errorCallback) {
file.upload = Upload.upload({
url: 'projectImages/upload',
data: {
file: file
}
});
file.upload.then(successCallback, errorCallback);
}
I am new to Angular,I have a scenario, where I need to download multiple files at the same time. My files are stored in GridFS. I am able to download the files, but for example a pdf is blank. The contentType stored in gridFS is "contentType": "binary/octet-stream", Am I missing out on anything?
My Jade code is
tr(ng-repeat='row in displayedCollection')
td {{ row.Name}}
td {{ row.email}}
td
button.btn.btn-info(type='button',ng-click="downloadDocuments(row.documentsSubmitted)" download) Download Documents
My controller code is
$scope.downloadDocuments = function (row) {
angular.forEach(row, function (value, key) {
var fileToDownload = value.id + "," + 'TrainingPartnerAddingTrainingCenter';
$http.get('/downloadDocuments/' + fileToDownload).success(function (result, status, headers, config) {
var _contentType = (headers('Content-Type'));
var _fileName = headers('FileName');
var blob = new Blob([ result ], { type : _contentType });
var url = (window.URL || window.webkitURL).createObjectURL(blob);
var anchor = angular.element('<a/>');
anchor.attr({
href : url,
target : '_blank',
download : _fileName
})[0].click();
});
});
};
my node.js code is as follows
exports.downloadDocument = function (req, res) {
var paramData = req.params.fileToDownload.split(',');
var role = req.session.user.role;
var conn = mongoose.connection;
var gfs = Grid(conn.db, mongoose.mongo);
routesLogger.logInfo(role, "downloadDocument", "START");
gfs.findOne({_id: paramData[0], root: paramData[1]}, function (err, file) {
if (err) {
routesLogger.logError(role, "downloadDocument", err);
return res.status(400).send(err);
}
else if (!file) {
routesLogger.logError(role, "downloadDocument", "No File Found for download");
return res.status(404).send('Error on the database looking for the file.');
}
else {
res.set('Content-Type', file.contentType);
res.set('Content-Disposition', 'attachment; filename="' + file.filename + '"');
var readstream = gfs.createReadStream({
_id: paramData[0],
root: paramData[1]
});
readstream.on("error", function (err) {
routesLogger.logError(role, "downloadDocument", err);
res.end();
});
readstream.pipe(res);
routesLogger.logInfo(role, "downloadDocument", "END");
}
});
};
So the mistake I was doing was not adding the parameter { responseType: 'arraybuffer' }. I found the answer in this link
AngularJS: Display blob (.pdf) in an angular app
$http.get('/downloadDocuments/' + fileToDownload,{ responseType: 'arraybuffer' }).success(function (result, status, headers, config) {
console.log(headers('Content-Type'));
var _contentType = (headers('Content-Type'));
var _fileName = headers('FileName');
var blob = new Blob([result], {type: _contentType });
saveAs(blob, _fileName);