I'm trying write create user function. I have such code
createUser: function (user) {
return db.User.create({
id: user.id,
username: user.username,
password: sha1(user.password),
first_name: user.first_name,
last_name: user.last_name,
email: user.email,
allow_password: user.allow_password
});
}
but it's correct only when I fill all user's fields. Actually, I strongly need only username and email, but when I put only 2 parameters - I've gotten 500 server error. How I can do other rows implicit?
The answer: you have to convert password before the query
createUser: function (user) {
if(user.password) {
user.password = sha1(user.password);
}
return db.User.create({
id: user.id,
username: user.username,
password: user.password,
first_name: user.first_name,
last_name: user.last_name,
email: user.email,
allow_password: user.allow_password
});
}
Related
I'm trying to perform user validation using if statements but on testing using post man, I keep on getting only the first return statement 'Email is required ' even after adding a valid email address and also an invalid email address. I have attached the user model, user controller logic and a picture of postman's response
user schema model
const mongoose = require('mongoose');
const { Schema } = mongoose
const userSchema = new Schema({
firstName: {
type: String,
required: true,
min: 3,
max: 20
},
lastName: {
type: String,
required: true,
min: 3,
max: 20
},
email: {
type: String,
required: true,
unique: true,
},
phoneNumber: {
type: String,
required: true,
},
password: {
type: String,
required: true,
min: 5
},
confirmPassword: {
type: String,
required: true,
min: 5
}
});
const User = mongoose.model('User', userSchema);
module.exports = User;
user.controller.js
module.exports.users = async(req, res) => {
try {
const email = await user.findOne({ email: req.body.email });
const firstName = await user.find({ firstName: req.body.firstName });
const lastName = await user.find({ lastName: req.body.lastName });
const password = await user.find({ password: req.body.password });
const confirmPassword = await user.find({ confirmPassword: req.body.confirmPassword });
const phoneNumber = await user.find({ phoneNumber: req.body.phoneNumber });
if (!email) return res.send('Email is required')
const filterEmail = /^([a-zA-Z0-9_\.\-])+\#(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
if (!filterEmail.test(email.value)) return
res.send('Please provide a valid email address');
if (email) return res.send('Email already exists');
if (!firstName) return res.send('First Name is required');
if (firstName.length < 3 || firstName.length > 20) return
res.send('First name must be at least 3 characters and less than 20 characters');;
if (!lastName) return res.send('Last Name is required');
if (lastName.length < 3 || lastName.length > 20) return
res.send('Last name must be at least 3 characters and less than 20 characters')
if (!password) return res.send('PassWord is required');
const filterPassword = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9])(?!.*\s).{5,15}$/;
if (!filterPassword.test(password.value)) return
res.send('Password must include at least one lowercase letter, one uppercase letter, one digit, and one special character');
if (!confirmPassword) return res.send(' Please confirm password');
if (password.value !== confirmPassword.value) return res.send('Passwords do not match');
if (!phoneNumber) return res.send('Phone Number is required');
phone(phoneNumber.value);
let User = new user(_.pick(req.body, ['firstName', 'lastName', 'email', 'phoneNumber', 'password']));
bcrypt.genSalt(10, async(err, salt) => {
if (err) throw err;
return user.password = await bcrypt.hash(user.password, salt);
});
await User.save();
} catch (err) {
res.status(500).send('Something went wrong');
console.warn(err);
}
}
Your controller is not good. You need to get the email, lastName and firstName from req.body.
const {email, lastName} = req.body
And then do the validation, which by the way will already happen in mongoose.
const email = await user.findOne({ email: req.body.email });
In this line you are looking in your DB for a user with email = req.body.email. But since there is no such a user it return your if statement
if (!email) return res.send('Email is required')
to get your user you only need to compare with one value if you set it to be unique in your schema, for instead user email.
const user = await user.findOne({ email });
In this case email was already destructed and if there is no user, you can create one.
you can use await user.create() and pass your values and hash the password with pre("save") in your schema.
UserSchema.pre("save", async function () {
if (!this.isModified("password")) return;
const salt = await bcrypt.genSalt(10);
this.password = await bcrypt.hash(this.password, salt);
});
You can also validate user email in the schema
email: {
type: String,
required: [true, "Please provide email"],
match: [
/^(([^<>()[\]\\.,;:\s#"]+(\.[^<>()[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
"Please provide a valid email",
],
unique: true,
},
You can simply install the validator package npm i validator then call it in in the user model const { isEmail } = require('validator'); and finally type this in your schema instead of hardcoding the verification code in the function.
email: { type: String, required: true, validate: [isEmail], unique: true },
Instead of writing custom logic for validation Please add a validation layer after performing security checks
you can use Express validator, to perform all your validations in a smoother way, It will eliminate unnecessary logic and code lines and add structured code to validate all types inputs, nested objects, DB call for existing data handling. It will handle the response and response message on its own without hitting the controller
just hit
npm install --save express-validator
and you are ready to validate requests very easily and effectively
Beside other answers i thought one thing which is missing but yet it is very strong validation method in Node.JS is JOI package, you can define your validation schema and get rid of all other pain full if and else, example is following
const Joi = require('joi');
const schema = Joi.object().keys({
firstName: Joi.string().alphanum().min(3).max(20).required(),
lastName: Joi.string().alphanum().min(3).max(20).required(),
email: Joi.email().required(),
phoneNumber: Joi.string().length(10).pattern(/^[0-9]+$/).required(),
password: Joi.string().min(5).required(),
confirmPassword: Joi.any().valid(Joi.ref('password')).required()
});
const dataToValidate = {
firstName: 'chris',
lastName: 'John',
email: 'test#test.com'
}
const result = Joi.validate(dataToValidate, schema);
// result.error == null means valid
Without node script you can always test your JOI schema and your data object on this webpage
I'm trying to send data on firebase collection but I can't figure out why it can't be sent. Function called createUserWithEmailAndPassword() works normally. In other functions sending data in firebase collection is working fine when I want to send it, but here it doesn't work for some unknown reason. Is this some bug or what?
My function:
SignUp() {
firebase
.auth()
.createUserWithEmailAndPassword(this.email, this.password);
try {
const unique = this.email;
db.collection("user")
.doc(unique)
.set({
name: this.name,
surname: this.surname,
email: this.email,
birth_date: this.birth_date,
city: this.city,
phone_number: this.phone_number,
});
this.success_register=true;
}
catch(error) {
if ((store.currentUser = null)) this.$router.replace({ name: "signup" });
}
}
This code creates a new document every time the user logs in but my task is to update existing same user ID document if it exists else create a new one. How can I do that in V9 Firebase?
Current Code
setDoc(
query(collectionRef),
// db.collection('users').doc(user.uid).set(
{
email: user.email,
lastSeen: serverTimestamp(),
photoURL: user.photoURL
}, {
merge: true
}
);
Old Code that access document UID:
The first parameter in setDoc() should be DocumentReference:
import { doc, setDoc } from "firebase/firestore"
const docRef = doc(db, "users", user.uid);
setDoc(docRef, {
email: user.email,
lastSeen: serverTimestamp(),
photoURL: user.photoURL
}, {
merge: true
}).then(() => console.log("Document updated"));
Alternatively, You can also use updateDoc().
import {
doc,
updateDoc
} from "firebase/firestore"
update(doc(db, "users", user.uid, {
email: user.email,
lastSeen: serverTimestamp(),
photoURL: user.photoURL
}).then(() => console.log("Document updated"));
var databaseRef = firebase.database().ref("Test_Applicants/");
databaseRef.push({
firstname: first_name,
middlename: middle_name,
lastname: last_name,
university: university_full_name,
email: email_address,
phone: phone_number,
date: getDate(),
docs: docURL
}, function(error){
//Callback failed
console.error(error);
});
Is this the right approach? How do I receive a variable or an argument from Firebase through a callback or through any other way to confirm that the data was written successfully? I'd like to upload a file if request is successful or return an error message to the user if the write fails.
This should work
var databaseRef = firebase.database().ref("Test_Applicants/");
databaseRef.push({
firstname: first_name,
middlename: middle_name,
lastname: last_name,
university: university_full_name,
email: email_address,
phone: phone_number,
date: getDate(),
docs: docURL
}, function(error){
if (error) {
console.error(error)
return
}
console.log('Push successful')
//add upload function here
});
You can listen child events in this case using following
databaseRef.on('child_added', function(data) {
console.log(data);
});
More info: https://firebase.google.com/docs/database/web/lists-of-data#listen_for_child_events
databaseRef.push().set({name:"john doe",telephone:"25400000000"}).catch((error)=>console.log(error))
After update my sails (0.10-rc5),
I encountered a problem in beforeCreate function :
beforeCreate : function(values, next){
console.log("Called beforeCreate User ");
console.log(values);
if(!values.password || values.password !== values.confirmation){
return next({
err : ["Password doesn't match password confirmation"]
});
}
bcrypt.genSalt(10, function(err, salt){
console.log("call within bcrypt");
if (err) return next(err);
bcrypt.hash(values.password, salt, function(err, hash){
if(err) return next(err);
values.password = hash;
});
});
Access.findOne()
.where({ level : values.level })
.exec(function(err, level){
console.log("call within findOne");
if(err) return next(err);
values.level = level.id;
});
console.log("after");
console.log(values);
next();
}
However, the output of the above function is as following :
Called beforeCreate User
{ firstName: 'Quad',
lastName: 'Doe',
email: '11#11.com',
password: '123456',
confirmation: '123456',
level: 'admin',
id: '2fa1ba1a-ae1c-4380-9107-3c1f6e8eafb3',
online: false }
after
{ firstName: 'Quad',
lastName: 'Doe',
email: '11#11.com',
password: '123456',
confirmation: '123456',
level: 'admin',
id: '2fa1ba1a-ae1c-4380-9107-3c1f6e8eafb3',
online: false }
call within bcrypt
call within findOne
As you can see, somehow bcrypt.genSalt(.....){} and Access.findOne(...){} were not called prior to after, which is supposed to.
What you are seeing is asynchronous code in action...
Node/Sails does not wait for your callbacks to fire before moving on to the the next task.
You need to "nest" your callbacks so that console.log("AFTER") is called within the last callback.
Take a look at async. It's designed for these types of problems.
Or...
Look into fibers