I am trying to implement validation using express validator that should only kick in if the field actually has some input. If it is empty it should just be ignored. The first part of the validation if the field is to check to check it meets the regex requirements and the second check is to see if the value exists in the database. Lower case versions of the same username with capital letters are not allowed ie: Shirley and shirley are seen as the same thing.
body('username')
.trim()
.custom((value, { req }) => {
var regex = /^[a-zA-Z0-9]{5,20}$/;
if (value != '' && !value.match(regex)) {
throw new Error('Username does not meet required criteria.');
}
return true;
})
.custom((value, { req }) => {
if (value !== '') {
return User.findOne({ username: new RegExp(`^${value}$`, 'i') })
.then(userDoc => {
if (userDoc) {
return Promise.reject('Username unavailable');
}
return true;
});
}
}),
If I leave the username field empty I still get a validation error telling me 'username unavailable'
Managed to get it working like this
.custom(value => {
if (value !== '') {
return User.findOne({ username: new RegExp(`^${value}$`, 'i') })
.then(userDoc => {
if (userDoc) {
return Promise.reject('Username not available');
} else {
return true;
}
})
} else {
return true;
}
})
Related
router.post("/check", async (req, res) => {
const nom = req.body.nom
const postnom = req.body.postnom
const matricule = req.body.matricule
const numeroBordero = req.body.numero_bordero
const paymentOrder = req.body.payementOrder
const etudiant = Etudiant.findOne({ matricule }, function (err, result) {
if (result == null) {
req.flash("test", "veuillez entrer des infos correctes")
res.redirect("/");
} else if (result !== null) {
if (result.isRegistered !== true) {
Etudiant.updateOne({
_id: result._id
}, {
isRegistered: true
}, function (err) {
if (err) {
console.log(err);
} else {
console.log("correctly updated");
}
})
}
}
})
return res.render("profil", {
etudiant
});
})
Once you call redirect, you cannot call render.
Return after your redirect.
res.redirect("/");
return
What front end framework are you using and what are you trying to accomplish with this endpoint? It seems like the function is checking the value of the request for a record, the running an update if a record was found.
If you want the render on the ui to be conditional on the result of this api call, you need to render separate html accordingly.
I am used to using react or angular, where I simply send a json object to the UI, and let the ui determine which page to navigate to, or which component to conditionally render.
use return res.redirect("/"); instead
You want use async/await but only async is present in your code.
Next, use result === null instead of result == null.
I didn't test your code, but can you run this code ? I think it'll solve your issue.
This code use promises.
router.post("/check", (req, res) => {
const nom = req.body.nom
const postnom = req.body.postnom
const matricule = req.body.matricule
const numeroBordero = req.body.numero_bordero
const paymentOrder = req.body.payementOrder
Etudiant.findOne({ matricule }, function (err, result) {
if (result === null) {
req.flash("test", "veuillez entrer des infos correctes")
res.redirect("/");
} else if (result !== null) {
if (result.isRegistered !== true) {
Etudiant
.updateOne(
{_id: result._id},
{ isRegistered: true}
)
.then(() => {
console.log("correctly updated")
})
.catch((err) => {
console.log(err)
})
}
})
})
IDEA
I have made a second table that I will store special information about a customer. The customer_Id is a foreign key to my customer table. However from my react I have a form and depending on the information in that form I need to send a different query. I have tried with a if sentence and it adds the row to the table with correct information but it doesn't set newReq to what is being returned. When I move it outside the if sentence it works fine and returns the correct info. Is there a fix to this or how can I go about doing this in a better way maybe?
try {
if (req.body.type === "allergy") {
console.log(req.params.id)
const newReq = await db.query('INSERT INTO specialcustomerinfo(customer_id,type,allergicto,dangerscale,priority) values($1,$2,$3,$4,$5) returning *',[req.params.id, req.body.type, req.body.allergicto, req.body.dangerscale, req.body.priority]);
}
else if (req.body.type === "scaredof") {
const newReq = await db.query('INSERT INTO specialcustomerinfo(customer_id,type,freight,priority) values($1,$2,$3,$4) returning *',[req.params.id, req.body.type, req.body.freight, req.body.priority]);
}
else if (req.body.type === "medicine") {
const newReq = await db.query('INSERT INTO specialcustomerinfo(customer_id,type,medicineName,priority) values($1,$2,$3,$4) returning *',[req.params.id, req.body.type, req.body.medicineName, req.body.priority]);
}
else {
console.log("No type match")
}
res.status(201).json({
status: "success",
data: {
bonus: newReq.rows[0],
},
});
} catch (err) { console.log(err) }
})```
const and let are block-scoped in Javascript. That means they can only be accessed inside the block in which they are declared. So, all the different versions of const newReq you declare can only be used inside their block. Instead, declare the variable using let at a higher level in the function so you can use it where you want to.
try {
let newReq;
if (req.body.type === "allergy") {
console.log(req.params.id)
newReq = await db.query('INSERT INTO specialcustomerinfo(customer_id,type,allergicto,dangerscale,priority) values($1,$2,$3,$4,$5) returning *',[req.params.id, req.body.type, req.body.allergicto, req.body.dangerscale, req.body.priority]);
}
else if (req.body.type === "scaredof") {
newReq = await db.query('INSERT INTO specialcustomerinfo(customer_id,type,freight,priority) values($1,$2,$3,$4) returning *',[req.params.id, req.body.type, req.body.freight, req.body.priority]);
}
else if (req.body.type === "medicine") {
newReq = await db.query('INSERT INTO specialcustomerinfo(customer_id,type,medicineName,priority) values($1,$2,$3,$4) returning *',[req.params.id, req.body.type, req.body.medicineName, req.body.priority]);
}
else {
console.log("No type match");
res.sendStatus(401);
return;
}
res.status(201).json({
status: "success",
data: {
bonus: newReq.rows[0],
},
});
} catch (err) {
console.log(err);
res.sendStatus(500);
}
})
FYI, you also need to add a fix for when the code goes into your else clause because that will throw when you try to reference newReg.rows. Probably, you should just send some error status in the else clause and then return which is what I show.
You also need to send an error response in your catch since all paths through your function need to send some sort of response.
I currently have a Mongoose Schema with validation:
assignmentID: {
type: Number,
validate: {
validator: function(v) {
if (!v) {
return false;
}
return Assignment.findById(v)
.then(assignmentDoc => {
if (!assignmentDoc) {
return false;
} else {
return true;
}
})
.catch(error => {
return false;
});
},
message: "Invalid assignment ID."
}
}
The validator works perfectly. However, it is executed when I update a document via .save().
Is it possible to change it so the validation executes only when the document is created and not when the document is updated?
Yes, you can set validateBeforeSave to false:
var schema = new Schema({ name: String });
schema.set('validateBeforeSave', false);
schema.path('name').validate(function (value) {
return v != null;
});
var M = mongoose.model('Person', schema);
var m = new M({ name: null });
m.validate(function(err) {
console.log(err); // Will tell you that null is not allowed.
});
m.save(); // Succeeds despite being invalid
reference: https://mongoosejs.com/docs/guide.html#validateBeforeSave
I am developing a web application using the MEAN stack with Angular 6. I have a form to submit data into MongoDB. Following is the save function and it works.
It saves the extruded value in the DB.
saveExtrudedHeightValue(extrudedHeight: NgForm) {
if (extrudedHeight.value != "" && extrudedHeight.value != null) {
this.extrudedHeightService.saveExtrudedHeight(extrudedHeight.value).subscribe(res => {
console.log(res);
}, (err) => {
console.log(err);
});
}
}
Here is the model
// Schema for extruded height panel
var extrudedHeightSchema = new mongoose.Schema({
userName: {
type: String
},
extrudedHeight: {
type: Number
},
});
module.exports = mongoose.model('extrudedHeightValue', extrudedHeightSchema);
Here is my post route
//post extrudedHeight values
router.post("/save", function(req, res) {
var mod = new extrudedHeight(req.body);
extrudedHeight.findOneAndUpdate({
userName: req.body.email,
extrudedHeight: req.body.extrudedHeight,
},
req.body, {
upsert: true,
new: true
},
function(err, data) {
if (err) {
console.log(err);
res.send(err);
} else {
res.send(mod);
}
}
);
});
Here is the service.
// service for save extruded height
saveExtrudedHeight(extrudedHeight): Observable < any > {
return this.http.post('/extrudedHeight/save', extrudedHeight, httpOptions)
.pipe(
catchError(this.handleError)
);
}
Now I want to save data in DB with the current user's userName. I can retrieve the current user's userName by this.
this.payload.user['email']
My problem is that I do not have an idea how to pass this userName to post route to save in db.
Here is where I get token.
this.authService.onTokenChange().subscribe(
(token: NbAuthJWTToken) => {
if (token.isValid()) {
this.user = token.getPayload().user;
this.payload = token.getPayload();
console.log(this.payload.user['email']);
}
}
)
You can first call this.authService.onTokenChange inside the saveExtrudedHeight method, and then use the flatMap operator to unwrap the internal Observable that would be returned by the http.post.
That would translate to code like this:
import { flatMap } from 'rxjs/operators';
import { throwError } from 'rxjs';
...
saveExtrudedHeight(extrudedHeight): Observable<any> {
const requestPayload = {
extrudedHeight
};
return this.authService.onTokenChange()
.pipe(flatMap(
(token: NbAuthJWTToken) => {
if (token.isValid()) {
this.user = token.getPayload().user;
this.payload = token.getPayload();
const email = this.payload.user['email'];
requestPayload.email = email;
// Make the changes here to send the email as the Request Payload.
return this.http.post('/extrudedHeight/save', requestPayload, httpOptions)
.pipe(
catchError(this.handleError)
);
} else {
throwError('Something went wrong!');
}
}
));
}
PS: I'm not really sure if this would work though as I haven't tested it out and I can't without a minimal working StackBlitz.
I created DELETE API and in the callback function I have written .remove function to delete a product if the id I have given is present. But when I am giving incorrect input, the result is receiving some object which shouldn't be the case. As there is no data with the Id i have given it should be null or undefined.
Can someone help on this?
Route URL-
http://localhost:3000/api/v1/products/:productId/delete
Code -
let deleteProduct = (req, res) => {
if (check.isEmpty(req.params.productId)) {
console.log('productId should be passed')
let apiResponse = response.generate(true, 'productId is missing', 403, null)
res.send(apiResponse)
} else {
productModel.remove({ 'productId': req.params.productId }, (err, result) => {
if (err) {
console.log('Error Occured.')
logger.error(`Error Occured : ${err}`, 'Database', 10)
let apiResponse = response.generate(true, 'Error Occured.', 500, null)
res.send(apiResponse)
} else if (check.isEmpty(result)) {
console.log('Product Not Found.')
let apiResponse = response.generate(true, 'Product Not Found.', 404, null)
res.send(apiResponse)
} else {
console.log('Product Deletion Success')
let apiResponse = response.generate(false, 'Product Deleted Successfully', 200, result)
res.send(apiResponse)
}
})
}
}
let isEmpty = (value) => {
if (value === null || value === undefined || trim(value) === '' || value.length === 0) {
return true;
} else {
return false;
}
}
When I give incorrect productId, Ideally it should give 'Product Not found' but the output is coming as Product Deleted Successfully.
The result will contain an object no matter if it was successful or not, it will never be empty in this case. Please read the documentation here.
check.isEmpty(result) will always be false.