I am using MongoDB, mongoose, ejs and NodeJS for my site. I have a update password function which is not working properly. I have checked again and again by login different things in console and there is no problem in getting data in req. So I guess my problem is in the controller. This is my controller:
module.exports.update_password = function (req, res) {
console.log(req.user);
Company.findOne({ username: req.user.username }, function (err, user) {
if (user.password == req.body.current_password) {
if (req.body.new_password == req.body.confirm_password) {
Company.findOneAndUpdate({ username: req.user.username }, { password: req.body.new_password }, { upsert: true }, function (err, doc) {
if (err) return res.send(500, { error: err });
req.flash('notify', 'Password changed!')
return res.redirect('/profile');
});
}
else req.flash('notify', 'New password does not match with confirm password');
}
else req.flash('notify', '!')
});
return res.redirect('/profile');
}
everytime updating my password I get this error:
node:events:355
throw er; // Unhandled 'error' event
^
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at new NodeError (node:internal/errors:329:5)
at ServerResponse.setHeader (node:_http_outgoing:573:11)
at ServerResponse.header (/home/krush/github/Project_Lightspeed/node_modules/express/lib/response.js:771:10)
at ServerResponse.location (/home/krush/github/Project_Lightspeed/node_modules/express/lib/response.js:888:15)
at ServerResponse.redirect (/home/krush/github/Project_Lightspeed/node_modules/express/lib/response.js:926:18)
at /home/krush/github/Project_Lightspeed/controllers/authentication_controller.js:45:32
at /home/krush/github/Project_Lightspeed/node_modules/mongoose/lib/model.js:4857:16
at /home/krush/github/Project_Lightspeed/node_modules/mongoose/lib/model.js:4857:16
at /home/krush/github/Project_Lightspeed/node_modules/mongoose/lib/helpers/promiseOrCallback.js:24:16
at /home/krush/github/Project_Lightspeed/node_modules/mongoose/lib/model.js:4880:21
at /home/krush/github/Project_Lightspeed/node_modules/mongoose/lib/query.js:4397:11
at /home/krush/github/Project_Lightspeed/node_modules/kareem/index.js:136:16
at processTicksAndRejections (node:internal/process/task_queues:76:11)
Emitted 'error' event on Function instance at:
at /home/krush/github/Project_Lightspeed/node_modules/mongoose/lib/model.js:4859:13
at /home/krush/github/Project_Lightspeed/node_modules/mongoose/lib/helpers/promiseOrCallback.js:24:16
[... lines matching original stack trace ...]
at processTicksAndRejections (node:internal/process/task_queues:76:11) {
code: 'ERR_HTTP_HEADERS_SENT'
}
[nodemon] app crashed - waiting for file changes before starting...
It seems that the problem is that the return res.redirect('/profile'); command is executed before your callback functions. Which is normal since this is how the event loop works.
Try to remove the return res.redirect('/profile'); line to see if the error goes away. Callbacks at node.js execute at a later stage of the event loop.
Generally I would recommend to refactor your code to use promises instead of callbacks since that causes the "callback hell" anti-pattern.
If you refactor your code to use promises, then you will be able to use .then or async await, which will help you write cleaner code and help you spot any error easily.
Related
i want to create custom token in cloud function but before that I want to check and compare timestamp from realtime database and with current time.if the timestamp is below 10 min then I want to create custom token and send back to client.please help me to achieve this.i am new to this cloud function firebase.
here is my code
export const authaccount = functions.https.onCall(async (data) => {
try {
const snap= await admin.database().ref("/register/"+data).get();
const time=snap.val().timestamp;
const now=new Date().getDate();
const reg=new Date(time).getDate();
const today=Math.abs(now-reg);
const daydiff=Math.floor(today/1000/60/60/24);
const nowminutes=new Date().getUTCMinutes();
const regminutes=new Date(time).getUTCMinutes();
const timediff=Math.abs(nowminutes-regminutes);
if (timediff<10 && daydiff==0) {
try {
admin.auth().createCustomToken(data).then((customtoken)=>{
console.log("auth created"+" "+timediff+" "+daydiff+" "+customtoken);
return customtoken;
});
} catch (err1) {
throw new functions.https.HttpsError("unknown", err1.message, err1);
}
} else {
console.log("else "+" "+now+" "+reg+" "+time+" "+daydiff);
}
} catch (err2) {
throw new functions.https.HttpsError("unknown", err2.message, err2);
}
});
2:53:20.626 AM
authaccount
Error: Process exited with code 16 at process.<anonymous> (/layers/google.nodejs.functions-framework/functions-framework/node_modules/#google-cloud/functions-framework/build/src/invoker.js:275:22) at process.emit (events.js:314:20) at process.EventEmitter.emit (domain.js:483:12) at process.exit (internal/process/per_thread.js:168:15) at Object.sendCrashResponse (/layers/google.nodejs.functions-framework/functions-framework/node_modules/#google-cloud/functions-framework/build/src/logger.js:37:9) at process.<anonymous> (/layers/google.nodejs.functions-framework/functions-framework/node_modules/#google-cloud/functions-framework/build/src/invoker.js:271:22) at process.emit (events.js:314:20) at process.EventEmitter.emit (domain.js:483:12) at processPromiseRejections (internal/process/promises.js:209:33) at processTicksAndRejections (internal/process/task_queues.js:98:32)
2:53:19.559 AM
authaccount
Error: The caller does not have permission; Please refer to https://firebase.google.com/docs/auth/admin/create-custom-tokens for more details on how to use and troubleshoot this feature. at FirebaseAuthError.FirebaseError [as constructor] (/workspace/node_modules/firebase-admin/lib/utils/error.js:44:28) at FirebaseAuthError.PrefixedFirebaseError [as constructor] (/workspace/node_modules/firebase-admin/lib/utils/error.js:90:28) at new FirebaseAuthError (/workspace/node_modules/firebase-admin/lib/utils/error.js:149:16) at Function.FirebaseAuthError.fromServerError (/workspace/node_modules/firebase-admin/lib/utils/error.js:188:16) at /workspace/node_modules/firebase-admin/lib/auth/token-generator.js:114:53 at processTicksAndRejections (internal/process/task_queues.js:97:5) at async Promise.all (index 1)
2:53:19.558 AM
authaccount
Unhandled rejection
2:53:19.469 AM
authaccount
Function execution took 1386 ms, finished with status code: 200
please help to solve this problem. i don't know where I am making the mistake.
You will need to make sure your Firebase Admin sdk is initiated and running before the function proceeds
if (firebase.apps.length === 0) {
firebase.initializeApp();
}
Resource: https://firebase.google.com/docs/admin/setup#initialize-without-parameters
I doubt you have modified the IAM permissions on your service account but as the comment suggested: https://firebase.google.com/docs/auth/admin/create-custom-tokens#service_account_does_not_have_required_permissions
Once that is confirmed to be working - you will need to ensure that the onCall data is a string and not null, some simple health checks can help you debug your process
console.log(typeof data);
console.warn("Data", data);
from there I would also debug your date times and the realtime database result, these are async and will require the promise to be resolved before you can use it.
Update:
All cloud functions should return a response to the client
onCall uses promises on the client and supports a 'return Object'
example:
return {
token: myCustomToken,
possible: otherValue
};
for comparison, onRequest uses fetch like responses and supports codes
response.status(500)
response.send({name:value})
return;
Source:
https://firebase.google.com/docs/functions/callable#sending_back_the_result
Source:
https://firebase.google.com/docs/functions/http-events#using_express_request_and_response_objects
Update:
all paths and promises need to resolve correctly, this includes awaiting promises to resolve and returning their result or storing the result for any secondary processing - I suggest cleaning up the code, remove the try/catch and use .then().catch()
Example:
if (timediff<10 && daydiff==0) {
return await admin.auth().createCustomToken(data)
.then((customtoken)=>{
console.log("auth created"+" "+timediff+" "+daydiff+" "+customtoken);
return customtoken;
})
.catch (err) {
return new functions.https.HttpsError("unknown", err.message, err);
}
}
else {
console.log("else "+" "+now+" "+reg+" "+time+" "+daydiff);
return "else "+" "+now+" "+reg+" "+time+" "+daydiff;
}
Greetings!
I have a Node-Express endpoint that calls addAdminController.js (Attached Below) to create a new admin.
Everything works well from functionality point of view. However, When you check if user already exists using mongoose FindOne method, it leaves a warning on the console. This however, does not stop the function from running and I'm successfully returning "Email Already in Use" as json object in Postman.
I want to know why i'm seeing this error and what am I doing wrong with Promise Handling. Your help is much appreciated.
addAdminController.js
const adminsModel = require("../../../../models/admins");
const bcrypt = require("bcryptjs");
exports.addAdminController = async (req, res, next) => {
const { name, email, password, role, image, status } = req.body;
//check if user already exists
try {
adminsModel
.findOne({ email }, (err, admin) => {
if (admin) {
res.status(400).json("Email Already in use");
return;
}
})
.exec();
} catch (error) {
return res.status(500).json("Something Went Wrong");
}
//Encrypt Password using Bcrypt
const saltRounds = 12;
const hashPass = bcrypt.hashSync(password, saltRounds);
//Create New Model with Hashed Password
const newAdmin = new adminsModel({
name: name,
email: email,
password: hashPass,
role: role,
image: image,
status: status,
});
// Save new admin user.
try {
await newAdmin.save();
res.json(newAdmin);
return;
} catch (error) {
res.status(400).json("There was an error creating admin user");
}
};
Console Warning
node:18700) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:533:11)
at ServerResponse.header (F:07_Developrs\Github\APIv2\node_modules\express\lib\response.js:771:10)
at ServerResponse.send (F:07_Developrs\Github\APIv2\node_modules\express\lib\response.js:170:12)
at ServerResponse.json (F:\07_Developrs\Github\APIv2\node_modules\express\lib\response.js:267:15)
at exports.addAdminController (F:\07_Developrs\Github\APIv2\routes\api\admins\addAdmin\addAdmin.controller.js:37:19)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:18700) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:18700) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
First of all, you shouldn't be using callback version of findOne function because code below findOne function call will execute before the callback of findOne executes.
As code below the findOne function call depends on whether user already exists or not, await the result of adminsModel.findOne(...) and check findOne function returned a user or not.
Secondly, wrap findOne function call with try-catch block to handle rejected promise.
try {
const user = await adminsModel.findOne({ email });
if (user) {
return res.status(400).json("Email Already in use");
}
// code to run if user doesn't exists
} catch (error) {
return res.status(500).json("Something Went Wrong");
}
I am working on an fantasy soccer app for my friends and I, but I am getting this age old error and it doesn't seem like any of the other questions answered on here really fit my situation. In the first block of code below, the console.log is returning the correct data, so I am very certain that the res.json(populatedClub) should be working just fine. I cannot find anywhere else in my code that is triggering another res.send() or res.json() in this chain of events.
Is anybody else able to see what I am not?
My route:
fantasyClubRouter.get('/:userId',
(req, res) => {
FantasyClub
.findOne({manager: req.params.userId})
.populate({
path: 'manager',
model: 'User'
})
.exec((error, populatedClub) => {
if (error) {
return () => {throw new Error(error)};
}
console.log('populatedClub:', populatedClub);
res.json(populatedClub);
})
.catch(error => {
throw new Error(error);
});
}
);
The error stack:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:471:11)
at ServerResponse.header (/home/ubuntu/workspace/node_modules/express/lib/response.js:767:10)
at ServerResponse.send (/home/ubuntu/workspace/node_modules/express/lib/response.js:170:12)
at ServerResponse.json (/home/ubuntu/workspace/node_modules/express/lib/response.js:267:15)
at FantasyClub.findOne.populate.exec (/home/ubuntu/workspace/server/fantasyClub-routes.js:18:11)
at /home/ubuntu/workspace/node_modules/mongoose/lib/model.js:4187:16
at (anonymous function).call (/home/ubuntu/workspace/node_modules/mongoose/lib/query.js:3128:7)
at process.nextTick (/home/ubuntu/workspace/node_modules/mongoose/lib/query.js:2019:28)
at process._tickCallback (internal/process/next_tick.js:61:11)
Emitted 'error' event at:
at /home/ubuntu/workspace/node_modules/mongoose/lib/model.js:4189:13
at (anonymous function).call (/home/ubuntu/workspace/node_modules/mongoose/lib/query.js:3128:7)
at process.nextTick (/home/ubuntu/workspace/node_modules/mongoose/lib/query.js:2019:28)
at process._tickCallback (internal/process/next_tick.js:61:11)
I figured out what I had done wrong, and it was so simple that I'm almost embarrassed to admit it, but here it goes.
I updated from an older version of Mongoose and forgot to update my code accordingly. Always make sure your code matches what the docs say for the version of the library you are using.
This is the working code:
fantasyClubRouter.get('/:userId',
(req, res) => {
FantasyClub
.findOne({manager: req.params.userId})
.populate({
path: 'manager',
model: 'User'
})
.then(populatedClub => {
res.json(populatedClub);
})
.catch(error => {
throw new Error(error);
});
}
);
I'm currently writing a function that will create a notification for every User that is in the committee of a specified Society (It's a social network site btw) and whenever I run this:
User.statics.newSocietyNotification = function(req, socID, typeID, url, next){
var tmpUsers = []
Society.findById(socID, function(err, doc){
console.log(doc)
doc.committee.forEach(function(comMember, i){
tmpUsers.push(comMember._uid)
})
this.find({'_id' : { $in : tmpUsers } }, function(err, docs){
if(err){
console.log(err)
}
if(docs.length == 0 || docs == null){
next(false)
}
next(docs)
console.log(docs)
})
})
}
It crashes the server with this message:
TypeError: this.find is not a function
at /home/ubuntu/workspace/models/user.js:368:10
at Query.<anonymous> (/home/ubuntu/workspace/node_modules/mongoose/lib/model.js:3324:16)
at /home/ubuntu/workspace/node_modules/mongoose/node_modules/kareem/index.js:259:21
at /home/ubuntu/workspace/node_modules/mongoose/node_modules/kareem/index.js:127:16
at nextTickCallbackWith0Args (node.js:420:9)
at process._tickCallback (node.js:349:13)
If anyone knows what I'm doing wrong I would greatly appreciate the help :)
EDIT:
Using User.find instead of 'this'
TypeError: User.find is not a function
at /home/ubuntu/workspace/models/user.js:368:10
at Query.<anonymous> (/home/ubuntu/workspace/node_modules/mongoose/lib/model.js:3324:16)
at /home/ubuntu/workspace/node_modules/mongoose/node_modules/kareem/index.js:259:21
at /home/ubuntu/workspace/node_modules/mongoose/node_modules/kareem/index.js:127:16
at nextTickCallbackWith0Args (node.js:420:9)
at process._tickCallback (node.js:349:13)
Your this on line 368 is referring to context of the callback function of the findById method. That callback function (which is an object, under the hood) doesn't have a method called find.
Instead, use Society.find(... or User.find(... to look up something else in the database.
I am using Redis and consulting it from nodejs, using the module Redis.
When i exec a client.multi() and the redis server is down the callback doesn't send the error and the nodejs app terminates.
This is the error
/Users/a/db/node_modules/redis/index.js:151
throw callback_err;
^
TypeError: Cannot read property 'length' of undefined
at Command.callback (/Users/a/db/node_modules/redis/index.js:1098:35)
at RedisClient.flush_and_error (/Users/a/db/node_modules/redis/index.js:148:29)
at RedisClient.on_error (/Users/a/db/node_modules/redis/index.js:184:10)
at Socket.<anonymous> (/Users/a/db/node_modules/redis/index.js:95:14)
at Socket.EventEmitter.emit (events.js:95:17)
at net.js:441:14
at process._tickCallback (node.js:415:13)
this is my code:
Constructor class
var redis = require('redis');
var client;
function Redis(){
client = redis.createClient();
client.on("error", function (err) {
console.log("Error " + err);
});
}
Redis.prototype.multi = function(commands,callback){
var err = null;
client.multi(commands).exec(function (error, res) {
if(error){
process.nextTick(function(){
callback(error,null)
})
}else{
process.nextTick(function(){
callback(null,res)
})
}
});
}
FYI, I ran across this in an old lib that depended on old version of node_redis.
This issue was a bug and was fixed in v0.9.1 - November 23, 2013: https://github.com/mranney/node_redis/pull/457
I think that people are still reaching here... (not sure if this answers this specific question directly, but I assume people reaching here since the multi.exec() returns true / the event loop is not waiting for it's response.
After the fixes that went in (in node-redis), it is possible to wrap the result of exec with Promise, and then you will be sure that the result will include the replies from the multi.
So, you can add some redis commands to the multi:
await multi.exists(key);
await multi.sadd(key2,member);
And then in the result do something like:
return new Promise((resolve, reject) => {
multi.exec((err, replies) => {
if (err) {
reject(err);
}
return resolve(replies);
});
});
Otherwise, if you will just do: const reply = await multi.exec();
it will just return you true, and not the replies
** Important to mention - this refers to 'async-redis' and 'node-redis'