How to convert string "req.body" to data (function)? - javascript

I make a function checkCompanyPermit with paramater companyIdSource and array allowed.
Example:
companyIdSouce: "req.body.companyId", "req.params.companyId"...
allowed: "user", "admin"...
With parameter companyIdSource as string, I want to convert it to data. It's worked if I use eval(companyIdSource) but it's bad. How can I do another?
I try use Function("return " + companyIdSource)() but it return an error: req is not defined.
const checkCompanyPermit = (companyIdSource, ...allowed) => {
return async (req, res, next) => {
try {
const companyId = eval(companyIdSource) //Bad code, change another code
const company = await Company.findById(companyId)
//... some code
} catch (error) {
next(error)
}
}
}
checkCompanyPermit("req.body.companyId", "manager")

Since you already have access to the req object in your middleware, there is no need to pass the full string representation for req.body.companyId, just the property you need to check will suffice. Use the bracket notation to access the value from req.body object i.e.
const checkCompanyPermit = (companyIdSource, allowed) => {
return async (req, res, next) => {
try {
const companyId = req.body[companyIdSource]
const company = await Company.findById(companyId)
//... some code
} catch (error) {
next(error)
}
}
}
checkCompanyPermit("companyId", "manager")

It's Working For You.
const ObjectId = require('mongodb').ObjectId;
const checkCompanyPermit = (companyIdSource, ...allowed) => {
return async (req, res, next) => {
try {
const companyId = ObjectId('companyIdSource') //Replace here new code
const company = await Company.findById(companyId)
//... some code
} catch (error) {
next(error)
}
}
}
checkCompanyPermit("req.body.companyId", "manager")

Related

Why mongoose is not awaiting for await new MODEL.save()

I have 2 servers and one of these is work fine, but second (modified variant of first) is not
`This is not works:
router.post("/", async (req, res, next) => {
const newBriefAppeal = await new BriefAppeal(req.body);
let appealId;
let target;
let goals;
let brand;
let ***;
try {
const savedBriefAppeal = await newBriefAppeal.save(function (err, appeal) {
appealId = appeal.id;
target = appeal.step01target;
goals = appeal.step02goals;
brand = appeal.step03brand;
*** = appeal.***
});
res.status(200).json(savedBriefAppeal);
} catch (err) {
res.status(500).json(err);
}
});
`
and i got error
node:events:491
throw er; // Unhandled 'error' event
^
TypeError: Cannot read properties of undefined (reading 'id')
`but this variant in my similar project works fine:
router.post("/", async (req, res, next) => {
const newAppeal = await new Appeal(req.body);
let appealId;
let name;
let email;
let phone;
let subject;
let message;
let attachments = [];
try {
const savedAppeal = await newAppeal.save(function (err, appeal) {
appealId = appeal.id;
name = appeal.name;
email = appeal.email;
phone = appeal.phone;
subject = appeal.subject;
message = appeal.text;
attachments = appeal.appealAttach.map((attachment) => ({
filename: attachment,
path: "./uploads/media/mailAttachments/" + attachment,
}));
});
res.status(200).json(savedAppeal);
} catch (err) {
res.status(500).json(err);
}
});
Where's i'm wrong and why my appeal is undefined ?
Because you're passing in a callback. As it says in the documentation, save only returns a promise when you don't pass in a callback:
Returns:
...Returns undefined if used with callback or a Promise otherwise.
Either use the old-style callback signature or use the promise feature.

adding propety to object won't work inside async function

i am trying to add fileUrl property to the order object inside async function but it won't work
i expect the order object to have a fileUrl property after adding it but it won't work
router.get('/my-orders/:id', isAuth, async (req, res) => {
const id = req.params.id;
try {
const orders = await Order.find({ userId: id });
if (orders.length > 0) {
for (const order of orders) {
const getObjectParams = {
Bucket: bucketName,
Key: order.fileName,
}
const command = new GetObjectCommand(getObjectParams);
const url = await getSignedUrl(s3, command, { expiresIn: 3600 });
// adding fileUrl property to order
order.fileUrl = url;
// it logs only order without fileUrl property
console.log(order);
}
res.send('OK');
}
} catch (error) {
console.error(error);
}
})
In MongoDB, iterating a cursor (which is what Order.find() gives you) will give you MongoDB documents, not plain Javascript objects. If you want plain Javascript objects that you can then manipulate like a plain Javascript object, then use .toObject() on the document.
router.get('/my-orders/:id', isAuth, async (req, res) => {
const id = req.params.id;
try {
const orders = await Order.find({ userId: id });
if (orders.length > 0) {
for (const order of orders) {
const getObjectParams = {
Bucket: bucketName,
Key: order.fileName,
}
const command = new GetObjectCommand(getObjectParams);
const url = await getSignedUrl(s3, command, { expiresIn: 3600 });
// convert from monogdb document to plain Javascript object
const modifiedOrder = order.toObject();
// adding fileUrl property to order
modifiedOrder.fileUrl = url;
console.log(modifiedOrder);
}
res.send('OK');
} else {
res.send('No Orders Found');
}
} catch (error) {
console.error(error);
// always send some response, even for errors
res.sendStatus(500);
}
});
Note, I also cleaned things up so that this request handler is always sending a response, even when no orders are found or when there's an error.
For further discussion of other options, including .lean() and .set(), see this answer.

Sending through variables in `res.render` that are conditionally empty

I'm trying to send through multiple variables into a res.render but I'm unsure of how to do it without an undefined error. Either one or the other will have an object to pass through but never both at the same time. Here's my current code that will give an undefined error.
app.get('/', async (req, res) => {
if (req.query.search) {
const search = req.query.search
const regex = new RegExp(search, 'i')
const searchedblogposts = await BlogPost.find({title: {$regex: regex}})
console.log(searchedblogposts)
} else {
const blogposts = await BlogPost.find({})
}
res.render('index', {
blogposts,
searchedblogposts
})
})
Well, this is because one of blogPosts or searchBlogPosts remains undefined at any point of time and you're passing both in res.render . What you can do is this:
app.get('/', async (req, res) => {
let blogPosts;
if (req.query.search) {
const search = req.query.search
const regex = new RegExp(search, 'i')
blogPosts = await BlogPost.find({title: {$regex: regex}})
} else {
blogposts = await BlogPost.find({})
}
res.render('index', {
blogposts,
})
})
OR this:
app.get('/', async (req, res) => {
const blogPosts = req.query.search? await BlogPost.find({title: {$regex: new RegExp(req.query.search, 'i')}})
: await BlogPost.find({})
res.render('index', {
blogposts,
})
})

create middlware with input argument in nodejs

i want to create a misslware in nodejs for access Level , i create this middlware :
class AccessUser extends middlware {
async AccessUser(access,req, res, next) {
const getTokenFrom = (req) => {
const authorization = req.headers["authorization"];
if (authorization && authorization.toLowerCase().startsWith("bearer ")) {
return authorization.substring(7);
}
return null;
};
const token = getTokenFrom(req);
if (token) {
jwt.verify(token, "shhhhh", (err, decoded) => {
if (err) return new ForbiddenResponse().Send(res);
let permission = decoded.info.permission;
let item = permission.find((x) => x.permissionId == access);
if (!item) {
return new ForbiddenResponse().Send(res);
} else {
next();
}
});
}
}
}
i add the argument name access to input of AccessUser in this middlware :
async AccessUser(access,req, res, next)
and i want to need compare the access with x.permissionId . but it show me this error :
(node:2168) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'authorization' of undefined
this error for this line :
const authorization = req.headers["authorization"];
and i use this middlware by this :
router.post(
"/Create",
access.AccessUser("Role:Add")
);
now whats the problem ? how can i use the middllware with input argument ?????
AccessUser is not a express middleware, the method signature has to be (req,res,next).
You can get around this if you define AccessUser as a factory function (there's no need to define it async as you're not awaiting any async call):
class AccessUser {
accessUser(access) {
return function (req, res, next) {
const getTokenFrom = (req) => {
const authorization = req.headers["authorization"];
if (authorization && authorization.toLowerCase().startsWith("bearer ")) {
return authorization.substring(7);
}
return null;
};
const token = getTokenFrom(req);
if (token) {
jwt.verify(token, "shhhhh", (err, decoded) => {
if (err) return new ForbiddenResponse().Send(res);
let permission = decoded.info.permission;
let item = permission.find((x) => x.permissionId == access);
if (!item) {
return new ForbiddenResponse().Send(res);
} else {
next();
}
});
}// TODO: handle case if no token exists?
}
}
}
module.exports = AccessUser;
Then use it like this:
const AccessUserMiddleware = require('./path-to-access-middleware');
const AccessUser = new AccessUserMiddleware();
app.get('/', AccessUser.accessUser("Role:Add"));

Read Props of Promise of Stream in nodejs

basically what I want to achieve is check in a middleware whether an uploaded file has the correct image type (png for example). This is what I have come up with till now:
export const fileCheckMiddleware = (req, res, next) => {
const acceptedImageTypes = ["image/gif", "image/jpeg", "image/png"];
const oldWrite = res.write;
const oldEnd = res.end;
const chunks = [];
res.write = (...restArgs) => {
chunks.push(new Buffer(restArgs[0]));
oldWrite.apply(res, restArgs);
};
res.end = async (...restArgs) => {
if (restArgs[0]) {
chunks.push(new Buffer(restArgs[0]));
}
const body = Buffer.concat(chunks).toString("utf8");
try {
let parsedBody = {};
try {
parsedBody = JSON.parse(body);
} catch (err) {
parsedBody = { data: { unparsedBody: body } };
}
const { variables } = req.body;
console.log("\x1b[1m%s\x1b[0m", "LOG variables", variables.file);
if (variables.file) {
console.log("\x1b[1m%s\x1b[0m", "LOG type", typeof variables.file);
}
} catch (err) {}
oldEnd.apply(res, restArgs);
};
next();
};
The logged type of variables.file is an object. And the result of the console.log is this:
LOG variables Promise {
{ filename: 'trump.jpeg',
mimetype: 'image/jpeg',
encoding: '7bit',
createReadStream: [Function: createReadStream] } }
So how can I access the mimetype here? I tried to map over the keys, variables.file["Promise"],...
Promise is not a key of variables.file, it's the type of variables.file. That means your code starts executing as soon as the HTTP request starts, and the file is received asynchronously, so you have to do something like:
variables.file.then(file => {
// Do whatever you want with the file
next();
});
Or declare the surrounding function as async and do this:
const file = await variables.file;
// Do whatever you want with the file
next();

Categories

Resources