How to change filename using Multer on NodeJS? - node.js

var i=0;
storage = multer.diskStorage({
destination: (req, file, cb) => {
const dir = './uploads/'
console.log(file)
return cb(null,dir)
},
filename: (req, file, cb) => {
i++;
cb(null, Date.now() + '-' + 'Applicant' + '-' + i);
}
})
But Multer always saves it as: img-1676302140202.jpeg or whichever timestamp and extension as long as it is jpg/jpeg, png or webp. But always as 'img', the timestamp but not the counter nor the word 'Applicant'. Can somebody tell me what im doing wrong and/or how can I achieve the desired filename "Date.now() + '-' + 'Applicant' + '-' + I"?
******* EDIT **********
As requested in the comments here is the entire setup:
var express = require('express');
var fs = require('fs');
var moment = require('moment');
var router = express.Router();
const multer = require('multer');
const path = require('path');
const base64ToImage = require('base64-to-image');
const homePath = require("os").homedir()
const env = process.env.NODE_ENV || 'development';
const config = require(__dirname + '/../config/config.json')[env];
const { Sequelize, INTEGER} = require("sequelize");
const { extname } = require('path');
const { request } = require('express');
const { Int } = require('mssql');
const sequelize = new Sequelize(config.database, config.username, config.password, {
host: 'localhost',
dialect: 'mssql'
});
const Op = Sequelize.Op;
const applicant = require("../models").Applicants;
const personalDocument = require("../models").PersonalDocuments;
const city = require("../models").Cities;
const State = require("../models").States;
const civilState = require("../models").CivilState;
const family = require("../models").Families;
const dependent = require("../models").Dependents;
const workExperience = require("../models").WorkExperience;
const language = require("../models").Languages;
const job = require("../models").Jobs;
const study = require("../models").Studies;
const reference = require("../models").References;
applicant.hasMany(personalDocument),
applicant.belongsTo(city),
applicant.belongsTo(state),
applicant.belongsTo(civilState),
applicant.hasMany(family),
applicant.hasMany(dependent),
applicant.hasMany(workExperience),
applicant.hasMany(language),
applicant.belongsTo(job),
applicant.hasMany(study),
applicant.hasMany(reference)
var upload = null;
var storage = null;
async function createDir(){
await fs.mkdir("./uploads", function(err) {
if (err) {
console.log(err)
} else {
console.log("New directory successfully created.")
}
})
}
createDir()
var i=0;
storage = multer.diskStorage({
destination: (req, file, cb) => {
const dir = './uploads/'
console.log(file)
return cb(null,dir)
},
filename: (req, file, cb) => {
i++;
cb(null, Date.now() + '-' + 'Applicant' + '-' + i);
}
})
upload = multer({storage});
//post New Applicant
router.post('/postNewApplicant', upload.single('file'),async function(request, response){
var imageName = request.body.imageName;
var base64Str = request.body.applicantImage;
var pathString = './uploads/';
var optionaObj = {
'filename': imageName,
};
var imageInfo = base64ToImage(base64Str, pathString, optionaObj);
var imagePath = pathString + imageInfo.fileName;
try{
let apply = await applicant.create({
firstName: request.body.firstName,
secondName: request.body.secondName,
lastName: request.body.lastName,
secondLastName: request.body.secondLastName,
nationality: request.body.nationality,
applicantImage: imagePath,
country: request.body.country,
birthDate: request.body.birthDate,
CivilStateId: request.body.CivilStateId,
StateId: request.body.StateId,
CityId: request.body.CityId,
JobId: request.body.JobId,
});
return response.status(200).json({
"idApplicant": apply.id
}) ;
}
catch
(error){
console.log('Error',error.message);
return response.status(500).json({
error,
})
}
}
);
********* EDIT *********
Actually my bad, turns out I had a syntax error in:
var imageName = request.body.imageName;
var base64Str = request.body.applicantImage;
var pathString = './uploads/';
var optionaObj = {
'filename': imageName,
};
var imageInfo = base64ToImage(base64Str, pathString, optionaObj);
var imagePath = pathString + imageInfo.fileName;
In:
var optionaObj = {
'filename': imageName,
};
'filename' should be 'fileName', that's why it keeps naming it as a default 'img - timestamp'. It works perfectly now. Hope it helps someone that's having the same silly mistake as me.

Related

How to perform an HTTP post request using express on Cloud Functions for Firebase using busboy

Hi I am trying to insert data in the database using a POST Request but the data is not being inserted.
On further investigation I found that to upload form-data, busboy needs to be used for image upload in firebase functions but I am not able to find a solution for using busboy with post method.
Hence if someone can please help me resolve this issue.
Below is the code for reference.
app.js
const express = require('express')
//const router = true;
const router = new express.Router()
const userInfo = require('../models/userProfile')
const multer = require('multer');
var fs = require('fs');
var path = require('path');
var JSONStream = require('JSONStream');
const planCheck = require('../models/planDetails');
const login = require('../models/login_creditionals');
const {Storage} = require('#google-cloud/storage');
const {format} = require('util');
const busboy = require('busboy');
const storage = new Storage({
projectId: "biz-1",
keyFilename: "/Users/akm/pixNodes/functions/pixbiz-65a402.json"
});
const bucket = storage.bucket("gs://biz-1");
const upload = multer({
storage: multer.memoryStorage(),
limits: {
fileSize: 10 * 1024 * 1024
}
})
const uploadImageToStorage = (file) => {
return new Promise((resolve, reject) => {
if (!file) {
reject('No image file');
}
let newFileName = `${Date.now() + path.extname(file.originalname)}`;
let fileUpload = bucket.file(newFileName);
const blobStream = fileUpload.createWriteStream({
metadata: {
contentType: file.mimetype
}
});
blobStream.on('error', (error) => {
reject('Something is wrong! Unable to upload at the moment.');
});
blobStream.on('finish', () => {
// The public URL can be used to directly access the file via HTTP.
const url = format(`https://storage.googleapis.com/${bucket.name}/${fileUpload.name}`);
resolve(url);
});
blobStream.end(file.buffer);
});
}
router.post('/userprofile/check' ,upload.single('profile_pic'), async (req,res) => {
var reqFiles;
var reqFilesUrl;
reqFiles = req.file;
if(reqFiles) {
// const imagerUrl = await uploadImageToStorage(reqFiles)
reqFilesUrl = imagerUrl;
console.log(reqFilesUrl);
const notify = new userInfo({
userId: req.body.userId,
mobile_number : req.body.mobileNumber,
profile_pic: reqFilesUrl
})
try {
console.log('success insert data');
await notify.save((err,post) => {
if(err) {
console.log(err);
}
//console.log('data saved', post);
res.status(201).send(post);
});
// });
// res.status(201).send();
console.log('201');
} catch(e) {
//res.status(401);
return res.send(e);
}

Nodejs how to use Multer on function

I have created controller, routes and functions base api. What issue I am getting is how can I use Multer on function.
I have function like this
const { Users } = require('../models/user');
const { Company } = require('../models/company');
const { Jobs } = require('../models/job');
var mongoose = require('mongoose');
const multer = require('multer');
const FILE_TYPE_MAP = {
'image/png': 'png',
'image/jpeg': 'jpeg',
'image/jpg': 'jpg'
};
const storage = multer.diskStorage({
destination: function (req, file, cb) {
const isValid = FILE_TYPE_MAP[file.mimetype];
let uploadError = new Error('invalid image type');
if (isValid) {
uploadError = null;
}
cb(uploadError, 'public/uploads');
},
filename: function (req, file, cb) {
const fileName = file.originalname.split(' ').join('-');
const extension = FILE_TYPE_MAP[file.mimetype];
cb(null, `${fileName}-${Date.now()}.${extension}`);
}
});
const uploadOptions = multer({ storage: storage });
const createJob = function async(req, res) {
const job = new Jobs({
jobTitle: req.body.jobTitle,
jobDescription: req.body.jobDescription,
jobImage: req.body.userType,
jobType: req.body.jobType,
jobNumberOfPeople: req.body.jobNumberOfPeople,
jobHireTime: req.body.jobHireTime,
jobMinPay: req.body.jobMinPay,
jobMaxPay: req.body.jobMaxPay,
jobday: req.body.jobday,
jobRecieveApplication: req.body.jobRecieveApplication,
jobSubmitResume: req.body.jobSubmitResume,
jobApplicationDeadline: req.body.jobApplicationDeadline,
jobCommunationSetting: req.body.jobCommunationSetting,
jobMessageSetting: req.body.jobMessageSetting,
companyID: req.body.companyID,
});
try {
const jobsave = await job.save();
res.status(200).json({ success: true, data: jobsave })
} catch (err) {
if (err.name === 'ValidationError') {
console.error(Object.values(err.errors).map(val => val.message))
return res.status(400).json({ success: false, message: Object.values(err.errors).map(val => val.message)[0] })
}
res.status(400).json({ success: false, message: err })
}
};
module.exports = { createJob };
and routes like this
const express = require('express');
const router = express.Router();
const userController = require('../controllers/user');
const jobController = require('../controllers/jobs');
router.post('/createJob', jobController.createJob);
module.exports = router;
now I need to add uploadOptions.single('jobImage') in function
I am doing like this const createJob =
const createJob = uploadOptions.single('jobImage'), async(req, res) => { };
Its showing this error on comma don't know why
Its working directly on router but I need to do In function
You can use this:
module.exports = {
createJob : [ uploadOptions.single('jobImage'), createJob ]
};

How can I get this to restart if it isn't an english result?

I have an API at https://dev-qaboomapi.azurewebsites.net/randmovie. I have a txt file that lists all movie IDs from https://themoviedb.org and one is selected at random and the information is presented at the API address above. What I can't work out is how to get it to check if the result is an english language movie and then try again if it isn't.
I have an If Else statement that checks the result is an english language movie but I can't work out if it isn't how to start the process again.
var appRouter = function (app) {
app.get("/randMovie", function (req, res) {
const fetchURL = require('fetch').fetchUrl;
const fs = require('fs');
const data = fs.readFileSync('./db/MovieIDs.txt') + '';
const splitData = data.split('\n');
const randomNumber = Math.floor(Math.random() * splitData.length);
const line = splitData.splice(randomNumber, 1);
const lineDATA = line.toString()
const api = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx'
var movieID = lineDATA
var URL = 'https://api.themoviedb.org/3/movie/' + movieID + '?api_key=' + api + "&append_to_response=videos"
fetchURL(URL, function(error, meta, body){
var movieString = body.toString()
var movieJSON = JSON.parse(movieString)
if(movieJSON.original_language == "en") {
res.status(200).send(movieJSON);
} else {
// Not sure what to put here
}
})
});
}
module.exports = appRouter;
I would like it to only return the details of the movie when it is:
if(movieJSON.original_language == "en")
and retry when it isn't.
Here is what you can try, but make sure that function does not run infinity if result is not in English.
var appRouter = function (app) {
app.get("/randMovie", function (req, res) {
retrieveData(req, res);
}
Definition of retrieveData
retrieveData(req, res){
const fetchURL = require('fetch').fetchUrl;
const fs = require('fs');
const data = fs.readFileSync('./db/MovieIDs.txt') + '';
const splitData = data.split('\n');
const randomNumber = Math.floor(Math.random() * splitData.length);
const line = splitData.splice(randomNumber, 1);
const lineDATA = line.toString()
const api = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx'
var movieID = lineDATA
var URL = 'https://api.themoviedb.org/3/movie/' + movieID + '?api_key=' + api + "&append_to_response=videos"
fetchURL(URL, function(error, meta, body){
var movieString = body.toString()
var movieJSON = JSON.parse(movieString)
if(movieJSON.original_language == "en") {
res.status(200).send(movieJSON);
} else {
// Not sure what to put here
retrieveData(req, res);
}
})
}

Cloud functions. The request signature we calculated does not match the signature you provided

I had a task, after registering users in the application (registering through facebook) to keep facebook avatar in firebase storage, as facebook links have a limited period of work. I implemented the function I'll write below, but I get the following error
The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method
When I try to use a link to an image. Please tell me how it can be fixed?
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const gcs = require('#google-cloud/storage')({keyFilename: "service-account-credentials.json"});
const uuid = require('uuid');
const imageDownloader = require('../lib/Images/image-manager.js');
const path = require('path');
const timestamp = require('unix-timestamp');
module.exports = functions.https.onRequest((req, res) => {
const token = req.header('X-Auth-MyApp-Token');
const imageURL = req.body.imagePath;
const bucketName = functions.config().googlecloud.defaultbacketname;
const bucket = gcs.bucket(bucketName);
var userID = '';
const shortID = uuid.v1();
const filename = shortID + '.jpg';
var profileImagePath = '';
return admin.auth().verifyIdToken(token).then(decodedToken => {
userID = decodedToken.uid;
return imageDownloader.downloadImageToLocalDirectory(imageURL, filename)
}).then(localImagePath => {
profileImagePath = path.normalize(path.join('userImages', userID, 'profileImages', filename));
const uploadProm = bucket.upload(localImagePath, {
destination: profileImagePath,
uploadType: "media",
metadata: {
contentType: 'image/jpeg'
}
});
return uploadProm;
}).then(() => {
console.log('success uploaded');
const config = {
action: 'read',
expires: '03-01-2400',
contentType: 'image/jpeg'
};
const userRefPromise = admin.database().ref()
.child('users')
.child(userID)
.once('value');
const profileImageFile = bucket.file(profileImagePath);
return Promise.all([profileImageFile.getSignedUrl(config), userRefPromise])
}).then(results => {
const url = results[0][0];
const userModel = results[1].val();
const userCheckID = userModel['id'];
console.log("get url", url);
// save to database
const userImagesRef = admin.database().ref().child('userImages')
.child(userID)
.child('userProfileImages')
.push();
const timeStamp = timestamp.now();
console.log('timeStamp', timeStamp);
const imageModelID = userImagesRef.key;
const userImagesRefPromise = userImagesRef.update({
'path': url,
'id': imageModelID,
'fileName': filename,
'timeStamp': timeStamp
});
const userRef = admin.database().ref()
.child('users')
.child(userID)
.child('currentProfileImage');
const userRefPromise = userRef.update({
'path': url,
'id': imageModelID,
'fileName': filename,
'timeStamp': timeStamp
});
return Promise.all([userImagesRefPromise, userRefPromise]);
}).then(() => {
const successJSON = {};
successJSON["message"] = "Success operation";
return res.status(200).send(successJSON);
}).catch(error => {
console.log(error);
const errorJSON = {};
errorJSON["error"] = error;
return res.status(error.code).send(errorJSON);
});
});

Nodejs and pdfKit and qr-image

I am working on a small project that works with generating pdf's in node and express, l am using the pdfkit npm module but to generate a pdf. l am also using the qr-image npm module to generate the QR code image but l am struggling to attach the generated the QR code to the pdf. This is the code that l am using to generate the QR code:
var file = "./"+certificationnumber+".png";
var qr_svg = qr.image(file, { type: 'png' });
qr_svg.pipe(require('fs').createWriteStream(file));
And this is how l am trying attache it to the pdf using pdfkit npm module:
doc.image(qr_svg.pipe(require('fs').createWriteStream(file)))
since every pdf has a unique QR code.
Thanks in advance
I exactly have the same problem where get the PDF in 64 bit encoded form and i have to attach qr image to it.
Below is the code snippet.
PDFDocument = require('pdfkit');
const base64 = require('base64-stream');
const doc = new PDFDocument();
doc.image('test.jpeg', {
fit: [250, 300],
align: 'center',
valign: 'center'
});
const finalString = pdf.response;
// contains the base64 string
//logic to append the qr image.
const stream = doc.pipe(base64.encode());
stream.on('data', chunk => finalString += chunk);
stream.on('end', () => {
// the stream is at its end, so push the resulting base64 string to the response
const backToPDF = new Buffer(finalString, 'base64');
read.writeFileSync('./Report.pdf', backToPDF);
});
doc.end();
Here is the solution I have come up with. Using pdf-lib, express and qrcode
const fs = require("fs");
const path = require("path");
const express = require("express");
const http = require("http");
const cors = require("cors");
const multer = require("multer");
const app = express();
const server = http.createServer(app);
const { PDFDocument } = require("pdf-lib");
const QRCode = require("qrcode");
const Joi = require("joi");
const { readFile, writeFile, unlink } = require("fs/promises");
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
const dir = "public";
const subDirectory = "public/uploads";
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
fs.mkdirSync(subDirectory);
}
const generateQRCodeImage = async function (filePath, text, color) {
return new Promise((resolve, reject) => {
QRCode.toFile(
filePath,
text,
{
color,
},
function (err) {
if (err) return reject(err);
resolve();
}
);
});
};
const run = async ({
width,
height,
x,
y,
pathToImage,
pathToPDF,
pathToOutputPDF,
qrCodeText,
qrDarkColor = "#000",
qrLightColor = "#0000",
}) => {
await generateQRCodeImage(pathToImage, qrCodeText, {
dark: qrDarkColor,
light: qrLightColor,
});
const pdfDoc = await PDFDocument.load(await readFile(pathToPDF));
const img = await pdfDoc.embedPng(await readFile(pathToImage));
Array.from({ length: pdfDoc.getPageCount() }).forEach((_, index) => {
let imagePage = pdfDoc.getPage(index);
imagePage.drawImage(img, {
x,
y,
width,
height,
});
});
const pdfBytes = await pdfDoc.save();
await writeFile(pathToOutputPDF, pdfBytes);
};
const pdfFileFilter = function (req, file, callback) {
const ext = path.extname(file.originalname);
if (ext !== ".pdf") {
return callback("This extension is not supported");
}
callback(null, true);
};
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "public/uploads");
},
filename: function (req, file, cb) {
cb(
null,
file.fieldname + "-" + Date.now() + path.extname(file.originalname)
);
},
});
const filesToProcess = multer({ storage: storage, fileFilter: pdfFileFilter });
const schema = Joi.object({
width: Joi.string().regex(/^\d+$/).required(),
height: Joi.string().regex(/^\d+$/).required(),
x: Joi.string().regex(/^\d+$/).required(),
y: Joi.string().regex(/^\d+$/).required(),
qrCodeData: Joi.string().required(),
qrDarkColor: Joi.string(),
qrLightColor: Joi.string(),
});
app.post("/addQrToPdf", filesToProcess.array("file", 1), async (req, res) => {
const pathToImage = "public/uploads/" + Date.now() + "temp-qr.png";
const pathToOutputPDF = "public/uploads/" + Date.now() + "-output.pdf";
if (req.files) {
const [file] = req.files;
if (!file) {
res.send("No file detected on input");
}
const pathToPDF = file.path;
try {
const { width, height, x, y, qrCodeData, qrDarkColor, qrLightColor } =
await schema.validateAsync(req.body);
await run({
width: +width,
height: +height,
x: +x,
y: +y,
qrDarkColor,
qrLightColor,
qrCodeText: qrCodeData,
pathToImage,
pathToOutputPDF,
pathToPDF,
});
const pdfFile = await readFile(pathToOutputPDF);
res.contentType("application/pdf");
res.send(pdfFile);
await unlink(pathToImage);
await unlink(pathToPDF);
await unlink(pathToOutputPDF);
} catch (error) {
try {
await unlink(pathToPDF);
await unlink(pathToImage);
} catch (err) {
console.warn(err);
}
res.send(error);
}
}
});
server.listen(4000, () => console.log("listening on port *:4000"));
I had the same problem.
It looks like it is an async issue.
If you treat the generation of the QR code like a promise and then run the create pdf code, it works.
My code is below (using promise). It should also work using async await
const createPDF = (ticketID) => {
const doc = new pdf
doc.pipe(fs.createWriteStream(`${ticketID}.pdf`))
doc.text('Your Tickets').fontSize(25)
doc.image(`./qrCodes/${ticketID}.png`, {
fit: [250, 300],
align: 'center',
valign: 'center'
});
doc.end()
}
const createQRCode = (ticketID) => {
QR.toFile(`./qrCodes/${ticketID}.png`, String(ticket), {width: 250}).then(qr => {
createPDF(ticketID)
})
}
I use a version without writing to the disk, using the svg path output, extract the path from the qrcode data and render it into the pdf
let s = await toString('hallo2', {
type: 'svg'
})
// extract the 2nd path element
let path = Array.from(s.matchAll(/d="(.*?)"/gm))[1][1]
let doc = new PDFDocument({ size: 'A4' });
doc.scale(8)
.path(data)
.stroke()
doc.pipe(fs.createWriteStream('out2.pdf', {}));
doc.end()

Resources