Unable to add array to specific part of mongodb - javascript

In my database i have the following setup for testdata:
test1 [
[0] { test: Array, comments: Array },
[1] { test: Array, comments: Array }
]
I've since before added the test Array using
var testet1 = { test: newTest1.split(" "), comments: Array };
user.test1.push(testet1);
But I'm for some reason unable to add an array to comments using:
user.test1[0].comments.push(newTest1);
Below is how i define the userSchema, it contains more but i think they are irrelevant in this scenario.
var UserSchema = new Schema({
test1: { type: Array, required: false },
test2: { type: Array, required: false },
test3: { type: Array, required: false }
});
Below is a part of the code that saves the data to the database. The "newTest1" is an array of comments. I've been trying to add a comment to the object but have been unable to.
No error is displayed, the array I'm trying to get into the object is just not added. It's really hard to find the why it's not working when no error is shown.
html:
<form name="edit.test1" ng-submit="ctrl.updateTest1(newComment1, newComment2, ctrl.artikel)">
<div class="form-group">
<label>Kommentarer:</label>
<input class="form-control" type="text" name="test1" placeholder="Comment on first value" ng-model="newComment1" autocomplete="off">
<br>
<input class="form-control" type="text" name="test1" placeholder="Comment on second value" ng-model="newComment2" autocomplete="off">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
Controller:
app.updateTest1 = function(newComment1, newComment2, index) {
app.errorMsg = false; // Clear any error message
app.disabled = true; // Lock form while processing
// Check if username submitted is valid
var userObject = {}; // Create the user object to pass to function
userObject._id = app.currentUser; // Pass current user _id in order to edit
userObject.test1 = [$scope.newComment1, $scope.newComment2, index]; // Set the new username provided
// Runs function to update the user's username
User.editUser(userObject).then(function(data) {
// Behöver jag lägga till något här??
});
};
Userfactory:
userFactory.editUser = function(id) {
return $http.put('/api/edit', id);
};
Creating a new user when a user registers:
router.post('/users', function(req, res) {
var user = new User(); // Create new User object
user.username = req.body.username; // Save username from request to User object
user.password = req.body.password; // Save password from request to User object
user.email = req.body.email; // Save email from request to User object
user.name = req.body.name; // Save name from request to User object
user.temporarytoken = jwt.sign({ username: user.username, email: user.email }, secret, { expiresIn: '24h' }); // Create a token for activating account through e-mail
// Check if request is valid and not empty or null
if (req.body.username === null || req.body.username === '' || req.body.password === null || req.body.password === '' || req.body.email === null || req.body.email === '' || req.body.name === null || req.body.name === '') {
res.json({ success: false, message: 'Ensure username, email, and password were provided' });
} else {
// Save new user to database
user.save(function(err) {
if (err) {
// Check if any validation errors exists (from user model)
if (err.errors !== null) {
if (err.errors.name) {
res.json({ success: false, message: err.errors.name.message }); // Display error in validation (name)
} else if (err.errors.email) {
res.json({ success: false, message: err.errors.email.message }); // Display error in validation (email)
} else if (err.errors.username) {
res.json({ success: false, message: err.errors.username.message }); // Display error in validation (username)
} else if (err.errors.password) {
res.json({ success: false, message: err.errors.password.message }); // Display error in validation (password)
} else {
res.json({ success: false, message: err }); // Display any other errors with validation
}
} else if (err) {
// Check if duplication error exists
if (err.code == 11000) {
if (err.errmsg[61] == "u") {
res.json({ success: false, message: 'That username is already taken' }); // Display error if username already taken
} else if (err.errmsg[61] == "e") {
res.json({ success: false, message: 'That e-mail is already taken' }); // Display error if e-mail already taken
}
} else {
res.json({ success: false, message: err }); // Display any other error
}
}
} else {
// Create e-mail object to send to user
var email = {
from: 'MEAN Stack Staff, cruiserweights#zoho.com',
to: [user.email, 'gugui3z24#gmail.com'],
subject: 'Your Activation Link',
text: 'Hello ' + user.name + ', thank you for registering at localhost.com. Please click on the following link to complete your activation: http://www.herokutestapp3z24.com/activate/' + user.temporarytoken,
html: 'Hello<strong> ' + user.name + '</strong>,<br><br>Thank you for registering at localhost.com. Please click on the link below to complete your activation:<br><br>http://www.herokutestapp3z24.com/activate/'
};
// Function to send e-mail to the user
client.sendMail(email, function(err, info) {
if (err) {
console.log(err); // If error with sending e-mail, log to console/terminal
} else {
console.log(info); // Log success message to console if sent
console.log(user.email); // Display e-mail that it was sent to
}
});
res.json({ success: true, message: 'Account registered! Please check your e-mail for activation link.' }); // Send success message back to controller/request
}
});
}
});
api.js:
router.put('/edit', function(req, res) {
var editUser = req.body._id; // Assign _id from user to be editted to a variable
if (req.body.name) var newName = req.body.name; // Check if a change to name was requested
if (req.body.username) var newUsername = req.body.username; // Check if a change to username was requested
if (req.body.email) var newEmail = req.body.email; // Check if a change to e-mail was requested
if (req.body.permission) var newPermission = req.body.permission; // Check if a change to permission was requested
if (req.body.test1) {
var newTest1 = req.body.test1;
}
if (req.body.test2) {
var newTest2 = req.body.test2;
}
if (req.body.test3) {
var newTest3 = req.body.test3;
}
if (req.body.test4) {
var newTest4 = req.body.test4;
}
if (req.body.test5) {
var newTest5 = req.body.test5;
}
// Look for logged in user in database to check if have appropriate access
User.findOne({ username: req.decoded.username }, function(err, mainUser) {
if (err) {
// Create an e-mail object that contains the error. Set to automatically send it to myself for troubleshooting.
var email = {
from: 'MEAN Stack Staff, cruiserweights#zoho.com',
to: 'gugui3z24#gmail.com',
subject: 'Error Logged',
text: 'The following error has been reported in the MEAN Stack Application: ' + err,
html: 'The following error has been reported in the MEAN Stack Application:<br><br>' + err
};
// Function to send e-mail to myself
client.sendMail(email, function(err, info) {
if (err) {
console.log(err); // If error with sending e-mail, log to console/terminal
} else {
console.log(info); // Log success message to console if sent
console.log(user.email); // Display e-mail that it was sent to
}
});
res.json({ success: false, message: 'Something went wrong. This error has been logged and will be addressed by our staff. We apologize for this inconvenience!' });
} else {
// Check if logged in user is found in database
if (!mainUser) {
res.json({ success: false, message: "no user found" }); // Return error
} else {
// Check if a change to name was requested
-----> HERE if (newTest1) {
// Check if person making changes has appropriate access
if (mainUser.permission === 'admin') {
// Look for user in database
User.findOne({ _id: editUser }, function(err, user) {
if (err) {
res.json({ success: false, message: 'Something went wrong. This error has been logged and will be addressed by our staff. We apologize for this inconvenience!' });
} else {
// Check if user is in database
if (!user) {
res.json({ success: false, message: 'No user found' }); // Return error
} else {
if (Array.isArray(newTest1)) {
------> this does not work user.test1[0].comments.push(newTest1);
//user.test1.splice(index, 0, newTest1)
} else {
---> this works var testet1 = { test: newTest1.split(" "), comments: Array };
user.test1.push(testet1); // Assign new name to user in database
}
// Save changes
user.save(function(err) {
if (err) {
console.log(err); // Log any errors to the console
} else {
res.json({ success: true, message: 'Name has been updated!' }); // Return success message
}
});
}
}
});
Why is this? How can i add an array to comments in my db?

Related

bcrypt compareSync returns false even they have same string

I am trying to make login functionality
While I was creating the login function like this
login: (req,res) => {
const body = req.body;
getUserByEmail(body.email,(err,results)=>{
if(err){
console.log(err);
}
if(!results){
return res.json({
sucess: 0,
data: "Invalid email or password 1"
});
}
console.log(body.pw);
console.log(results.pw);
const result = compareSync(body.pw,results.pw);
console.log(result)
if(result){
results.pw = undefined;
const jsontoken = sign({result: results},"1234413",{
expiresIn: "1h"
});
return res.json({
sucess: 1,
message: "login sucessfully",
token: jsontoken
});
}else{
return res.json({
sucess: 0,
data: "Invalid email or password2"
});
}
});
}
Terminal Answer
I console log the body.pw and results.pw but seems like it give me same strings but
I was not sure why it gives me false result even if I have same string for body.pw and results.pw
compareSync compares a password with a hash. You first need to hash the password before comparing it with the plain-text password.
First run
bcrypt.hash(myPlaintextPassword, saltRounds).then(function(hash) {
// Store hash in your password DB.
});
Then you can compare
bcrypt.compare(myPlaintextPassword, hash).then(function(result) {
// result == true
});

How to fix "Error: Can't set headers after they are sent" in Express

I have recently been developing a MERN application and I have recently came into the trouble that express is saying that I am setting headers after they are sent.
I am using mongo db and trying to update a user profile.
I have tried to comment out my res.send points to find the issue but I have failed to do so.
Here is my post method for updating the user profile:
app.post("/api/account/update", (req, res) => {
const { body } = req;
// Validating and Checking Email
if (body.email) {
var email = body.email;
email = email.toLowerCase();
email = email.trim();
body.email = email;
User.find(
{
email: body.email
},
(err, previousUsers) => {
if (previousUsers.length > 0) {
return res.send({
success: false,
message:
"Error: There is already another account with that email address"
});
} else {
}
}
);
}
// Validating Names Function
function checkName(name) {
var alphaExp = /^[a-zA-Z]+$/;
if (!name.match(alphaExp)) {
return res.send({
success: false,
message: "Error: Names cannot contain special characters or numbers"
});
}
}
checkName(body.firstName);
checkName(body.lastName);
// Making sure that all fields cannot be empty
if (!body.email && !body.firstName && !body.lastName) {
return res.send({
success: false,
message: "Error: You cannot submit nothing"
});
}
// Getting User ID from the current session
UserSession.findById(body.tokenID, function(err, userData) {
// Finding User ID using the current users session token
if (userData.isDeleted) {
return res.send({
success: false,
message:
"Error: Session token is no longer valid, please login to recieve a new one"
});
}
// Deleting the token ID from the body object as user table entry doesnt store tokens
delete body.tokenID;
// Finding the user profile and updating fields that are present
User.findByIdAndUpdate(userData.userId, body, function(err, userInfo) {
if (!err) {
return res.send({
success: true,
message: "Success: User was updated successfully"
});
}
});
});
});
This is the call that I am doing to the backend of the site:
onUpdateProfile: function(fieldsObj) {
return new Promise(function(resolve, reject) {
// Get Session Token
const obj = getFromStorage("the_main_app");
// Defining what fields are getting updated
fieldsObj.tokenID = obj.token;
// Post request to backend
fetch("/api/account/update", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(fieldsObj)
})
.then(res => {
console.log("Verify Token - Res");
return res.json();
})
.then(json => {
console.log("Verify Token JSON", json);
if (json.success) {
window.location.href = `/manage-account?success=${json.success}`;
} else {
window.location.href = `/manage-account?success=${json.success}`;
}
});
});
}
Here is my error message that I am getting:
Error: Can't set headers after they are sent.
at validateHeader (_http_outgoing.js:491:11)
at ServerResponse.setHeader (_http_outgoing.js:498:3)
at ServerResponse.header (C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\node_modules\express\lib\response.js:767:10)
at ServerResponse.send (C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\node_modules\express\lib\response.js:170:12)
at ServerResponse.json (C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\node_modules\express\lib\response.js:267:15)
at ServerResponse.send (C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\node_modules\express\lib\response.js:158:21)
at C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\routes\api\account.js:270:22
at C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\node_modules\mongoose\lib\model.js:4641:16
at process.nextTick (C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\node_modules\mongoose\lib\query.js:2624:28)
at _combinedTickCallback (internal/process/next_tick.js:131:7)
at process._tickCallback (internal/process/next_tick.js:180:9)
[nodemon] app crashed - waiting for file changes before starting...
Can anyone help me with this?
EDIT
I have changed my code, this seems to now work however I feel like its a little messy when put together. Any refactoring tips?
Code:
app.post("/api/account/update", (req, res) => {
// Preform checks on data that is passed through
const { body } = req;
var messages = {
ExistedUser:
"Error: There is already another account with that email address",
NameFormat: "Error: Names cannot contain special characters or numbers",
BlankInputs: "Error: You cannot submit nothing",
accountLoggedOut:
"Error: Session token is no longer valid, please login to recieve a new one",
successfullyUpdated: "Success: User was updated successfully"
};
var usersFound;
if (body.email) {
var email = body.email;
email = email.toLowerCase();
email = email.trim();
body.email = email;
User.find(
{
email: body.email
},
(err, UserCount) => {
usersFound = UserCount;
}
);
}
function capitalize(text) {
return text.replace(/\b\w/g, function(m) {
return m.toUpperCase();
});
}
if (body.firstName) {
body.firstName = capitalize(body.firstName);
}
if (body.lastName) {
body.lastName = capitalize(body.lastName);
}
//Making sure that all fields cannot be empty
if (!body.email && !body.firstName && !body.lastName) {
return res.send({
success: false,
message: messages.BlankInputs
});
}
// Getting User ID from the current session
UserSession.findById(body.tokenID, function(err, userData) {
// Finding User ID using the current users session token
if (userData.isDeleted) {
return res.end({
success: false,
message: messages.accountLoggedOut
});
}
if (userData) {
// Deleting the token ID from the body object as user table entry doesnt store tokens
delete body.tokenID;
// Finding the user profile and updating fields that are present
User.findByIdAndUpdate(userData.userId, body, function(err, userInfo) {
if (userInfo) {
if (!usersFound.length > 0) {
return res.send({
success: true,
message: messages.successfullyUpdated
});
} else {
return res.send({
success: false,
message: messages.ExistedUser
});
}
}
});
}
});
});
You're calling res.send() twice. res.send() ends the process. You ought to refactor such that you call res.write() and only call res.send() when you're done.
This StackOverflow link describes the difference in more detail. What is the difference between res.send and res.write in express?
I believe this is happening, as you're trying to send a response after the first / initial response has already been sent to the browser. For example:
checkName(body.firstName);
checkName(body.lastName);
Running this function twice is going to try and yield 2 different "response" messages.
The product of a single route, should ultimately be a single response.
Thanks for all your help on this issue.
Here is my final code that allowed it to work.
I have also tried to "refactor" it too. Let me know if you'd do something else.
app.post("/api/account/update", (req, res) => {
const { body } = req;
console.log(body, "Logged body");
// Defining objects to be used at the end of request
var updateUserInfo = {
userInfo: {},
sessionToken: body.tokenID
};
var hasErrors = {
errors: {}
};
// Checking that there is at least one value to update
if (!body.email && !body.firstName && !body.lastName) {
var blankError = {
success: false,
message: "Error: You cannot change your details to nothing"
};
hasErrors.errors = { ...hasErrors.errors, ...blankError };
} else {
console.log("Normal Body", body);
clean(body);
console.log("Cleaned Body", body);
updateUserInfo.userInfo = body;
delete updateUserInfo.userInfo.tokenID;
}
// Function to check if object is empty
function isEmpty(obj) {
if (Object.keys(obj).length === 0) {
return true;
} else {
return false;
}
}
// Function to remove objects from body if blank
function clean(obj) {
for (var propName in obj) {
if (obj[propName] === "" || obj[propName] === null) {
delete obj[propName];
}
}
}
// Checking and Formatting Names Given
function capitalize(text) {
return text.replace(/\b\w/g, function(m) {
return m.toUpperCase();
});
}
if (body.firstName) {
body.firstName = capitalize(body.firstName);
}
if (body.lastName) {
body.lastName = capitalize(body.lastName);
}
// Checking and formatting email
if (body.email) {
body.email = body.email.toLowerCase();
body.email = body.email.trim();
// Checking for email in database
User.find({ email: body.email }, (err, EmailsFound) => {
if (EmailsFound.length > 0) {
var EmailsFoundErr = {
success: false,
message: "There is already an account with that email address"
};
hasErrors.errors = { ...hasErrors.errors, ...EmailsFoundErr };
}
});
}
// Getting User Session Token
UserSession.findById(updateUserInfo.sessionToken, function(err, userData) {
// Finding User ID using the current users session token
if (userData.isDeleted) {
var userDeletedError = {
success: false,
message:
"Your account is currently logged out, you must login to change account details"
};
hasErrors.errors = { ...hasErrors.errors, ...userDeletedError };
} else {
// Finding the user profile and updating fields that are present
User.findByIdAndUpdate(
userData.userId,
updateUserInfo.userInfo,
function(err, userInfo) {
// userInfo varable contains user db entry
if (err) {
var updateUserError = {
success: false,
message: "Error: Server Error"
};
hasErrors.errors = {
...hasErrors.errors,
...updateUserError
};
}
if (isEmpty(hasErrors.errors)) {
res.send({
success: true,
message: "Success: You have updated your profile!"
});
} else {
res.send({
success: false,
message: hasErrors.errors
});
}
}
);
}
});
});

Code is being executed even after return statement is there?

I am using mongoose unique validator to make name and email in my user model unique. And when i try to save a duplicate user in database it is giving me error which is ok , but even after returning the response, the code below the return statement is being executed and i am getting an error that says
" Error: Can't set headers after they are sent."
Here is my code.
User.js:
var mongoose = require("mongoose")
var uniqueValidator = require("mongoose-unique-validator");
var crypto = require("crypto");
var userSchema = new mongoose.Schema(
{
name: {
type: String,
required: [true, 'cant be blank'],
unique: true,
match: [/^[a-zA-Z0-9]+$/, "is invalid"],
index: true
},
email: {
type: String,
unique: true,
required: [true, 'cant be blank'],
index: true
},
salt: String,
password_hash: String
}, { timestamps: true });
userSchema.plugin(uniqueValidator, { message: "already taken" });
userSchema.methods.setPassword = function (password) {
this.salt = crypto.randomBytes(15).toString('hex');
//console.log(this.salt);
this.hash = crypto.pbkdf2Sync(password, this.salt, 10000, 512, 'sha512').toString('hex');
//console.log(this.hash);
}
userSchema.methods.checkPassword = function (password) {
var hash = crypto.pbkdf2Sync(password, this.salt, 10000, 512, 'sha512').toString('hex');
return this.hash == hash;
}
var User = module.exports = mongoose.model("User", userSchema);
router.js
//route for Signup
router.get("/signup", function (req, res) {
res.render('signup.html');
});
router.post('/signup', function (req, res) {
var name = req.body.name;
var email = req.body.email;
var password = req.body.password;
var verify = req.body.verify;
if (!name || !email || !password || !verify || password != verify) {
var passwordError;
if (password != verify)
passwordError = 'Password are not matching';
res.render('signup.html', { 'Error': 'Invalid Details', 'name': name, 'email': email, 'passwordError': passwordError });
return;
}
var newUser = User(
{
name: name,
email: email
});
newUser.setPassword(password);
newUser.save(function (err) {
if (err) {
//console.log("Database Error:%s" , err);
console.log(err);
// Even after using return statement the code below this
// statement is being executed . I dont know why?
return res.status(500).send({ success: false, message: 'User already exists' });
}
});
console.log("here");
req.session.user = newUser;
console.log(newUser);
res.redirect('/newpost');
});
Note : I have not added the full code for router.js file.
I know a workaround for this problem will be to add the remaining code in an else statement.But i am not getting why this error is coming at first.
The error i get in console is:
{ _id: 5a645473ae051e159a62f080,
name: 'dipen',
email: 'dipenbhatt12#gmail.com',
salt: '2f3e989389918507aaea0915b59852' }
{ [ValidationError: User validation failed: name: already taken]
errors:
{ name:
{ [ValidatorError: already taken]
message: 'already taken',
name: 'ValidatorError',
properties: [Object],
kind: 'unique',
path: 'name',
value: 'dipen',
reason: undefined,
'$isValidatorError': true } },
_message: 'User validation failed',
name: 'ValidationError' }
events.js:141
throw er; // Unhandled 'error' event
^
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:335:11)
at ServerResponse.header (/home/asmodeus/Programs/HelloWorld/node_modules/express/lib/response.js:767:10)
at ServerResponse.send (/home/asmodeus/Programs/HelloWorld/node_modules/express/lib/response.js:170:12)
at ServerResponse.json (/home/asmodeus/Programs/HelloWorld/node_modules/express/lib/response.js:267:15)
at ServerResponse.send (/home/asmodeus/Programs/HelloWorld/node_modules/express/lib/response.js:158:21)
at /home/asmodeus/Programs/HelloWorld/router.js:141:27
at /home/asmodeus/Programs/HelloWorld/node_modules/mongoose/lib/model.js:3907:16
at /home/asmodeus/Programs/HelloWorld/node_modules/mongoose/lib/model.js:334:16
at /home/asmodeus/Programs/HelloWorld/node_modules/kareem/index.js:246:48
at next (/home/asmodeus/Programs/HelloWorld/node_modules/kareem/index.js:167:27)
at Kareem.execPre.Kareem.execPost.callback [as execPost] (/home/asmodeus/Programs/HelloWorld/node_modules/kareem/index.js:217:3)
at _handleWrapError (/home/asmodeus/Programs/HelloWorld/node_modules/kareem/index.js:245:21)
at /home/asmodeus/Programs/HelloWorld/node_modules/kareem/index.js:271:14
at _next (/home/asmodeus/Programs/HelloWorld/node_modules/kareem/index.js:94:14)
at Immediate._onImmediate (/home/asmodeus/Programs/HelloWorld/node_modules/kareem/index.js:420:34)
at processImmediate [as _immediateCallback] (timers.js:383:17)
Just use the fact that save returns a Promise:
//Make the route async
router.post('/signup' , async function(req,res){
//validate user input
const { name, email, password, verify } = req.body;
if(!name || !email || !password || !verify)
return res.json({ error:"Wrong data"});
}
//create a new user
const user = User({ name, email });
// asynchronously save it to db, catch all errors
try {
await user.save();
//return valid response
return res.json({success: true});
} catch(e){
return res.json({error:"dupe"});
}
});
Your code does not work because you simply cant return from a callback. That returns to the internal function that called the callback.

Multilayered array in database, can't push array into second layer

In my database i have the following setup for testdata:
test1 [
[0] { test: Array, comments: Array },
[1] { test: Array, comments: Array }
]
Below is how i define the userSchema, it contains more but i think they are irrelevant in this scenario.
var UserSchema = new Schema({
test1: { type: Array, required: false },
test2: { type: Array, required: false },
test3: { type: Array, required: false }
});
Below is a part of the code that saves the data to the database. The "newTest1" is an array of comments. I've been trying to add a comment to the object but have been unable to. The idea is that i first add the data which creates the object (see api.js below) and then add the comments.
No error is displayed, the array I'm trying to get into the object is just not added. In the api.js (code snippet further down) I'm able to push into the first layer of the array but not the object within. This must mean that i can't see into the array from the database but i don't know why this is. I think if i somehow could get the array from the database, add the comments then user.save it would work but i don't know how to do that or if that is the best solution. Could someone help me out?
html:
<form name="edit.test1" ng-submit="ctrl.updateTest1(newComment1, newComment2, ctrl.artikel)">
<div class="form-group">
<label>Kommentarer:</label>
<input class="form-control" type="text" name="test1" placeholder="Comment on first value" ng-model="newComment1" autocomplete="off">
<br>
<input class="form-control" type="text" name="test1" placeholder="Comment on second value" ng-model="newComment2" autocomplete="off">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
Controller:
app.updateTest1 = function(newComment1, newComment2, index) {
app.errorMsg = false; // Clear any error message
app.disabled = true; // Lock form while processing
// Check if username submitted is valid
var userObject = {}; // Create the user object to pass to function
userObject._id = app.currentUser; // Pass current user _id in order to edit
userObject.test1 = [$scope.newComment1, $scope.newComment2, index]; // Set the new username provided
// Runs function to update the user's username
User.editUser(userObject).then(function(data) {
// Behöver jag lägga till något här??
});
};
Userfactory:
userFactory.editUser = function(id) {
return $http.put('/api/edit', id);
};
Creating a new user when a user registers:
router.post('/users', function(req, res) {
var user = new User(); // Create new User object
user.username = req.body.username; // Save username from request to User object
user.password = req.body.password; // Save password from request to User object
user.email = req.body.email; // Save email from request to User object
user.name = req.body.name; // Save name from request to User object
user.temporarytoken = jwt.sign({ username: user.username, email: user.email }, secret, { expiresIn: '24h' }); // Create a token for activating account through e-mail
// Check if request is valid and not empty or null
if (req.body.username === null || req.body.username === '' || req.body.password === null || req.body.password === '' || req.body.email === null || req.body.email === '' || req.body.name === null || req.body.name === '') {
res.json({ success: false, message: 'Ensure username, email, and password were provided' });
} else {
// Save new user to database
user.save(function(err) {
if (err) {
// Check if any validation errors exists (from user model)
if (err.errors !== null) {
if (err.errors.name) {
res.json({ success: false, message: err.errors.name.message }); // Display error in validation (name)
} else if (err.errors.email) {
res.json({ success: false, message: err.errors.email.message }); // Display error in validation (email)
} else if (err.errors.username) {
res.json({ success: false, message: err.errors.username.message }); // Display error in validation (username)
} else if (err.errors.password) {
res.json({ success: false, message: err.errors.password.message }); // Display error in validation (password)
} else {
res.json({ success: false, message: err }); // Display any other errors with validation
}
} else if (err) {
// Check if duplication error exists
if (err.code == 11000) {
if (err.errmsg[61] == "u") {
res.json({ success: false, message: 'That username is already taken' }); // Display error if username already taken
} else if (err.errmsg[61] == "e") {
res.json({ success: false, message: 'That e-mail is already taken' }); // Display error if e-mail already taken
}
} else {
res.json({ success: false, message: err }); // Display any other error
}
}
} else {
// Create e-mail object to send to user
var email = {
from: 'MEAN Stack Staff, cruiserweights#zoho.com',
to: [user.email, 'gugui3z24#gmail.com'],
subject: 'Your Activation Link',
text: 'Hello ' + user.name + ', thank you for registering at localhost.com. Please click on the following link to complete your activation: http://www.herokutestapp3z24.com/activate/' + user.temporarytoken,
html: 'Hello<strong> ' + user.name + '</strong>,<br><br>Thank you for registering at localhost.com. Please click on the link below to complete your activation:<br><br>http://www.herokutestapp3z24.com/activate/'
};
// Function to send e-mail to the user
client.sendMail(email, function(err, info) {
if (err) {
console.log(err); // If error with sending e-mail, log to console/terminal
} else {
console.log(info); // Log success message to console if sent
console.log(user.email); // Display e-mail that it was sent to
}
});
res.json({ success: true, message: 'Account registered! Please check your e-mail for activation link.' }); // Send success message back to controller/request
}
});
}
});
api.js:
router.put('/edit', function(req, res) {
var editUser = req.body._id; // Assign _id from user to be editted to a variable
if (req.body.name) var newName = req.body.name; // Check if a change to name was requested
if (req.body.username) var newUsername = req.body.username; // Check if a change to username was requested
if (req.body.email) var newEmail = req.body.email; // Check if a change to e-mail was requested
if (req.body.permission) var newPermission = req.body.permission; // Check if a change to permission was requested
if (req.body.test1) {
var newTest1 = req.body.test1;
}
if (req.body.test2) {
var newTest2 = req.body.test2;
}
if (req.body.test3) {
var newTest3 = req.body.test3;
}
if (req.body.test4) {
var newTest4 = req.body.test4;
}
if (req.body.test5) {
var newTest5 = req.body.test5;
}
// Look for logged in user in database to check if have appropriate access
User.findOne({ username: req.decoded.username }, function(err, mainUser) {
if (err) {
// Create an e-mail object that contains the error. Set to automatically send it to myself for troubleshooting.
var email = {
from: 'MEAN Stack Staff, cruiserweights#zoho.com',
to: 'gugui3z24#gmail.com',
subject: 'Error Logged',
text: 'The following error has been reported in the MEAN Stack Application: ' + err,
html: 'The following error has been reported in the MEAN Stack Application:<br><br>' + err
};
// Function to send e-mail to myself
client.sendMail(email, function(err, info) {
if (err) {
console.log(err); // If error with sending e-mail, log to console/terminal
} else {
console.log(info); // Log success message to console if sent
console.log(user.email); // Display e-mail that it was sent to
}
});
res.json({ success: false, message: 'Something went wrong. This error has been logged and will be addressed by our staff. We apologize for this inconvenience!' });
} else {
// Check if logged in user is found in database
if (!mainUser) {
res.json({ success: false, message: "no user found" }); // Return error
} else {
// Check if a change to name was requested
-----> HERE if (newTest1) {
// Check if person making changes has appropriate access
if (mainUser.permission === 'admin') {
// Look for user in database
User.findOne({ _id: editUser }, function(err, user) {
if (err) {
res.json({ success: false, message: 'Something went wrong. This error has been logged and will be addressed by our staff. We apologize for this inconvenience!' });
} else {
// Check if user is in database
if (!user) {
res.json({ success: false, message: 'No user found' }); // Return error
} else {
if (Array.isArray(newTest1)) {
------> this does not work user.test1[0].comments.push(newTest1);
//user.test1.splice(index, 0, newTest1)
} else {
---> this works var testet1 = { test: newTest1.split(" "), comments: Array };
user.test1.push(testet1); // Assign new name to user in database
}
// Save changes
user.save(function(err) {
if (err) {
console.log(err); // Log any errors to the console
} else {
res.json({ success: true, message: 'Name has been updated!' }); // Return success message
}
});
}
}
});
First you need to make some tweaks at your Schema to make test1 array include objects with properties answers and comments and make them array too. And then insert it to your main Schema like this:
var nestedSchema = new Schema ({
answers: {type: Array, required: false},
comments: {type: Array, required: false}
})
var UserSchema = new Schema({
test1: { type: [nestedSchema], required: false },
test2: { type: Array, required: false },
test3: { type: Array, required: false }
});
Then user.test1[0].comments.push(newTest1) should work correctly. Don't forget to pass the index of the needed answer when pushing new comment. Like this user.test1[index].comments.push(newTest1)
Javascript arrays are always numbered indexes, and does not support named indexes. Unless I missed something it looks like you are trying to create an associative array by giving it a named index which will not work.

Strange async behavior in Node with Mongoose and promises

So I'm using Node.js + Mongoose + Lie as a promise library. The code is as follows:
var User = require('../models/user'),
Promise = require('lie'),
jwt = require('jsonwebtoken'),
config = require('../../config');
module.exports = function(express) {
var router = express.Router();
router.post('/', function(req, res) {
if (!req.body.username) return res.json({ success: false, reason: 'Username not supplied.' });
if (!req.body.password) return res.json({ success: false, reason: 'Password not supplied.' });
var findUser = new Promise(function(resolve, reject) {
User.findOne({ username: req.body.username }, function(err, user) {
if (err) reject (err);
if (!user) reject({ success: false, reason: 'User not found or password is incorrect.' });
if (!user.validPassword(req.body.password)) reject({ success: false, reason: 'User not found or password is incorrect.' });
resolve(user);
});
});
var sendToken = function(user) {
var token = jwt.sign({ username: user.username }, config.secret, { expiresIn: 2 * 60 * 60 });
res.json({ success: true, token: token });
};
findUser.then(function(value) {
sendToken(value);
}).catch(function(reason) {
res.send(reason);
});
return router;
};
So basically it's an auth route, which sends a signed jwt if everything is good. The strange behavior is that if I send a wrong username, the server throws an error saying
TypeError: Cannot read property 'validPassword' of null
So, it says that the user === null when it reaches the password validity check, HOWEVER, before this validity check, there is a check that a user is found, mainly
if (!user) reject({ success: false, reason: 'User not found or password is incorrect.' });
And here the server already knows that user === null, hence it should reject this promise with success: false, and this piece of code should be thrown into catch part, but it doesn't happen.
Any ideas, please?
I should add that if I change that if (!user.validPassword... part to else if instead of if, it works like it should. However I cannot understand why any code is still executed after the promise gets rejected.
EDIT
While learning node, I mainly used the MEAN Machine book, which is a great help, and there they use this syntax:
if (!user) {
//
} else if (user) {
//
}
But I guess it should work my way as well.
You are not stopping execution of your function on reject, so if findOne results in empty result validPassword is still get called.
Probably you need to add return:
User.findOne({ username: req.body.username }, function(err, user) {
if (err)
return reject (err);
if (!user)
return reject({ success: false, reason: 'User not found or password is incorrect.' });
if (!user.validPassword(req.body.password))
return reject({ success: false, reason: 'User not found or password is incorrect.' });
resolve(user);
});
Or use else if:
User.findOne({ username: req.body.username }, function(err, user) {
if (err) {
reject (err);
} else if (!user) {
reject({ success: false, reason: 'User not found or password is incorrect.' });
} else if (!user.validPassword(req.body.password))
reject({ success: false, reason: 'User not found or password is incorrect.' });
} else {
resolve(user);
}
});

Categories

Resources