From a378e172881bb333a43c0227d972a04c8ecef642 Mon Sep 17 00:00:00 2001 From: Tijesunimi Date: Mon, 22 Apr 2019 16:33:00 +0100 Subject: [PATCH 1/2] Merged school with user and added extra validation for registration --- config/passport.js | 6 ++-- controllers/auth.js | 70 +++++++++--------------------------- controllers/promise.js | 72 +------------------------------------ controllers/user.js | 80 ------------------------------------------ models/school.js | 17 +++++++-- models/user.js | 48 ------------------------- routes/index.js | 10 ++++-- validation/school.js | 44 ++++++++++++++--------- validation/user.js | 28 --------------- 9 files changed, 72 insertions(+), 303 deletions(-) delete mode 100644 controllers/user.js delete mode 100644 models/user.js delete mode 100644 validation/user.js diff --git a/config/passport.js b/config/passport.js index e1e98d0..0b34941 100644 --- a/config/passport.js +++ b/config/passport.js @@ -1,5 +1,5 @@ const LocalStrategy = require('passport-local'); -const userDb = require("../controllers/promise").UserDb; +const schoolDb = require("../controllers/promise").SchoolDb; module.exports = function (passport) { passport.use(new LocalStrategy({ @@ -7,7 +7,7 @@ module.exports = function (passport) { passwordField: 'password' }, function(username, password, done) { - userDb.findOne({ email: username }) + schoolDb.findOne({ email: username }) .then(user => { if (!user) return done(null, false, { message: 'Incorrect username or password' }); @@ -29,7 +29,7 @@ module.exports = function (passport) { }); passport.deserializeUser(function(id, done) { - userDb.findOne({ _id: id }) + schoolDb.findOne({ _id: id }) .then(user => { done(null, user.toJSON()); }); diff --git a/controllers/auth.js b/controllers/auth.js index 6260912..08e98d6 100644 --- a/controllers/auth.js +++ b/controllers/auth.js @@ -1,72 +1,36 @@ const bcrypt = require('bcrypt'); const schoolDb = require("./promise").SchoolDb; -const userDb = require("./promise").UserDb; const passport = require("passport"); -const validateSchool = require("../validation/school"); -const validateUser = require("../validation/user"); const Auth = { async register(req, res, next) { - var schoolId = null; try { - const { school_name, school_address, school_currency, first_name, last_name, email, password } = req.body; + const { name, email, password } = req.body; - // Validate and create the administrator's school - const newSchool = { - name: school_name, - address: school_address, - currency: school_currency - }; - const { isValid, errors } = validateSchool(newSchool); - if (!isValid) - res.status(400).send({ errors }); + const existingSchool = await schoolDb.findOne({ email: email }); + + if (existingSchool) { + res.status(400).send({ + errors: [ + "A school with this email address already exists" + ] + }); + } else { - var school = await schoolDb.create(newSchool); - schoolId = school._id; - - const newUser = { - first_name: first_name, - last_name: last_name, + var hash = bcrypt.hashSync(password, 10); + + const newSchool = { + name: name, email: email, - school: schoolId, - password: password + password: hash }; - const { isValid, errors } = validateUser(newUser); - if (!isValid) { - schoolDb.findOneAndDelete({ _id: schoolId }); - res.status(400).send({ errors: errors }); - } - else { - const existingUser = await userDb.findOne({ email: email }); - - if (existingUser) { - schoolDb.findOneAndDelete({ _id: schoolId }); - res.status(400).send({ - errors: { - email: "Email address already exists" - } - }); - } - else { - //Hash password - var hash = bcrypt.hashSync(password, 10); - newUser.password = hash; - - const user = await userDb.create(newUser); //Create user and return user - user.school.name = school_name; - user.school.address = school_address; - user.school.currency = school_currency; - user.school.id = schoolId; - res.status(201).send(user.toJSON()); - } - } + const school = await schoolDb.create(newSchool); + res.status(201).send(school.toJSON()); } } catch(error) { console.log(error); - if (schoolId != null) - schoolDb.findOneAndDelete({ _id: schoolId }); res.status(500).json({ errors: error.message }); } }, diff --git a/controllers/promise.js b/controllers/promise.js index 5eeb628..a64b687 100644 --- a/controllers/promise.js +++ b/controllers/promise.js @@ -2,7 +2,6 @@ const Class = require('../models/class'); const Fee = require('../models/fee'); const School = require('../models/school'); const Student = require('../models/student'); -const User = require('../models/user'); /** * @param {string} text * @returns {object} return all @@ -347,78 +346,9 @@ class StudentDb { } } -// user promise -//user promise -class UserDb { - static find(param){ - return new Promise((resolve, reject) => { - User.find(param).populate('school') - .then((res) => { - resolve(res); - }) - .catch((err) => { - reject(err); - }) - }); - } - - static create(param){ - return new Promise((resolve, reject) => { - User.create(param) - .then((res) => { - resolve(res); - }) - .catch((err) => { - reject(err); - }); - }); - } - - static findOne(param){ - return new Promise((resolve, reject) => { - User.findOne(param).populate('school') - .then((res) => { - resolve(res); - }) - .catch((err) => { - reject(err); - }); - }); - } - - /** - * @param {string} param - * @param {string} text - * @return {object} returns updated object - */ - static findOneAndUpdate(param, text){ - return new Promise((resolve, reject) => { - User.findOneAndUpdate(param, text, { new: true }).populate('school') - .then((res) => { - resolve(res); - }) - .catch((err) => { - reject(err); - }); - }); - } - - static findOneAndDelete(param){ - return new Promise((resolve, reject) => { - User.findOneAndDelete(param).populate('school') - .then((res) => { - resolve(res); - }) - .catch((err) => { - reject(err); - }); - }); - } -} module.exports = { ClassDb, FeeDb, SchoolDb, - StudentDb, - UserDb + StudentDb }; diff --git a/controllers/user.js b/controllers/user.js deleted file mode 100644 index 40c13a2..0000000 --- a/controllers/user.js +++ /dev/null @@ -1,80 +0,0 @@ -const _ = require('lodash'); -const userDb = require("./promise").UserDb; - -const User = { - async create(req, res, next){ - const queryText = _.omit(req.body,['school_id']); - try { - const createdUser = await userDb.create(queryText); - return res.status(201).send({ - message: 'User successfully created', - data: createdUser, - }); - } catch(error){ - return res.status(400).send(error); - } - }, - async get_all_users(req, res, next){ - const queryText = { school_id: req.user.school.id }; - try { - const foundUsers = await userDb.find(queryText); - return res.status(200).send({ - message: 'Users retrieved successfully', - data: foundUsers, - }); - } catch (error) { - return res.status(400).send(error); - } - }, - async get_one_user(req, res, next){ - const queryText = { - _id: req.params.id, - school_id: req.user.school.id, - } - try { - const foundUser = await userDb.findOne(queryText); - if (!foundUser) return res.status(404).send({ message: 'User not found' }); - return res.status(200).send({ - message: 'User retrieved successfully', - data: foundUser, - }); - } catch (error) { - return res.status(400).send(error); - } - }, - async update_user(req, res, next){ - const queryText = { - _id: req.params.id, - school_id: req.user.school.id, - } - const updateData = _.omit(req.body, ['school_id']); - try { - const updatedUser = await userDb.findOneAndUpdate(queryText, updateData); - if (!updatedUser) return res.status(404).send({ message: 'User not found' }); - return res.status(200).send({ - message: 'User updated successfully', - data: updatedUser, - }); - } catch (error) { - return res.status(400).send(error); - } - }, - async delete_user(req, res, next){ - const queryText = { - _id: req.params.id, - school_id: req.user.school.id, - } - try { - const deletedUser = await userDb.findOneAndDelete(queryText); - if (!deletedUser) return res.status(404).send({ message: 'User not found' }); - return res.status(200).send({ - message: 'User successfully deleted', - data: deletedUser, - }); - } catch (error) { - return res.status(400).send(error); - } - } -} - -module.exports = User; \ No newline at end of file diff --git a/models/school.js b/models/school.js index 0b88890..908330c 100644 --- a/models/school.js +++ b/models/school.js @@ -1,4 +1,5 @@ const mongoose = require('mongoose'); +const bcrypt = require('bcrypt'); const Schema = mongoose.Schema; @@ -7,12 +8,24 @@ const schoolSchema = new Schema({ type: String, required: true, }, - address: { + email: { type: String, }, - currency: { + password: { type: String, }, }); +schoolSchema.methods.validatePassword = function(password) { + return bcrypt.compareSync(password, this.password); +} + +schoolSchema.methods.toJSON = function() { + return { + name: this.name, + email: this.email, + username: this.username + }; +}; + module.exports = mongoose.model('School', schoolSchema); diff --git a/models/user.js b/models/user.js deleted file mode 100644 index bd1eebf..0000000 --- a/models/user.js +++ /dev/null @@ -1,48 +0,0 @@ -const mongoose = require("mongoose"); -const Schema = mongoose.Schema; -const bcrypt = require("bcrypt"); - -const userSchema = new Schema( - { - first_name: { - type: String, - required: true - }, - last_name: { - type: String, - required: true - }, - school: { - type: mongoose.Schema.Types.ObjectId, - ref: 'School' - }, - email: { - type: String, - required: true - }, - password: { - type: String, - required: true - } - } -); - -userSchema.methods.validatePassword = function(password) { - return bcrypt.compareSync(password, this.password); -} - -userSchema.methods.toJSON = function() { - return { - first_name: this.first_name, - last_name: this.last_name, - email: this.email, - school: { - id: this._id, - name: this.school.name, - address: this.school.address, - currency: this.school.currency, - } - }; -}; - -module.exports = mongoose.model("User", userSchema); \ No newline at end of file diff --git a/routes/index.js b/routes/index.js index b528262..5f8d7a6 100644 --- a/routes/index.js +++ b/routes/index.js @@ -1,15 +1,21 @@ const express = require('express'); +var expressValidator = require('express-validator'); const router = express.Router(); +router.use(expressValidator()); + // import controllers const StudentController = require('../controllers/student'); const ClassController = require('../controllers/class'); const FeeController = require('../controllers/fee'); const TermController = require('../controllers/term'); const AuthController = require('../controllers/auth'); -const studentValidations = require('../validation/student.validation.js') const HomeController = require('../controllers/home'); +//import validations +const studentValidations = require('../validation/student.validation.js'); +const registrationValidations = require('../validation/school'); + // welcome page router.get('/', HomeController.index); @@ -49,7 +55,7 @@ router.get('/about', function(req,res,next){ // API routes // Authentication routes -router.post('/register', AuthController.register); // School administrator registration +router.post('/register', registrationValidations, AuthController.register); // School administrator registration router.post('/login', AuthController.login); // School administrator login diff --git a/validation/school.js b/validation/school.js index 5ea43f5..d486d98 100644 --- a/validation/school.js +++ b/validation/school.js @@ -1,22 +1,34 @@ const validator = require("validator"); +const { sanitizeBody } = require('express-validator/filter'); -function validateSchool(data) { - var errors = {}; +const sanitizeAndValidateSchool = function(req, res, next) { + req.checkBody('name').trim() + .isLength({ min:1 }).withMessage('School name is a required field.'); - if (validator.isEmpty(data.name)) { - errors.school_name = "School name is required"; - } - if (validator.isEmpty(data.address)) { - errors.school_address = "School address is required"; - } - if (validator.isEmpty(data.currency)) { - errors.school_currency = "School currency is required"; - } + req.checkBody('email').trim() + .isLength({ min:1 }).withMessage('School email address is a required field.') + .isEmail().withMessage('School email address must be a valid email.'); + + req.checkBody('password').trim() + .isLength({ min:1 }).withMessage('Password is a required field.') + .matches(/^(?=.*[A-Z])(?=.*[!@#$&*])(?=.*[0-9])(?=.*[a-z]).{8,}$/).withMessage("Password be at least 8 characters, alphanumeric with at least one uppercase letter, and contain at least one special character"); - return { - isValid: Object.keys(errors).length == 0, - errors: errors - }; + req.assert('password', 'Passwords do not match').equals(req.body.confirm_password); + + sanitizeBody('name').escape(); + sanitizeBody('email').escape(); + + var errors = req.validationErrors(); + + if (errors) { + var response = { errors: [] }; + errors.forEach(function(err) { + response.errors.push(err.msg); + }); + res.statusCode = 400; + return res.json(response); + } + return next(); } -module.exports = validateSchool; \ No newline at end of file +module.exports = sanitizeAndValidateSchool; \ No newline at end of file diff --git a/validation/user.js b/validation/user.js deleted file mode 100644 index 4bf5c4d..0000000 --- a/validation/user.js +++ /dev/null @@ -1,28 +0,0 @@ -const validator = require("validator"); - -function validateUser(data) { - var errors = {}; - - if (validator.isEmpty(data.first_name)) { - errors.first_name = "First name is required"; - } - if (validator.isEmpty(data.last_name)) { - errors.last_name = "Last name is required"; - } - if (validator.isEmpty(data.email)) { - errors.email = "Email address is required"; - } - else if (!validator.isEmail(data.email)) { - errors.email = "Email address is not valid"; - } - if (validator.isEmpty(data.password)) { - errors.password = "Password is required"; - } - - return { - isValid: Object.keys(errors).length == 0, - errors: errors - }; -} - -module.exports = validateUser; \ No newline at end of file From 6f84037ea009f9af8313fe46cd51c0c243cff5fc Mon Sep 17 00:00:00 2001 From: Tijesunimi Date: Mon, 22 Apr 2019 16:51:28 +0100 Subject: [PATCH 2/2] Updated refrences to school id --- controllers/class.js | 14 +++++++------- controllers/fee.js | 10 +++++----- controllers/student.js | 12 ++++++------ controllers/term.js | 10 +++++----- models/school.js | 4 ++-- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/controllers/class.js b/controllers/class.js index b914870..561f107 100644 --- a/controllers/class.js +++ b/controllers/class.js @@ -5,7 +5,7 @@ const Class = { async create(req, res) { try { const queryText = _.omit(req.body, ['school_id']); - queryText.school_id = req.user.school.id; + queryText.school_id = req.user.id; const createdClass = await classDb.create(queryText); return res.status(201).send({ message: 'Class successfully created', @@ -17,7 +17,7 @@ const Class = { }, async get_all_classes(req, res) { try { - const queryText = { school_id: req.user.school.id }; + const queryText = { school_id: req.user.id }; const foundClasses = await classDb.find(queryText); return res.status(200).send({ message: 'Classes retrieved successfully', @@ -31,7 +31,7 @@ const Class = { try { const queryText = { parent_id: null, - school_id: req.user.school.id, + school_id: req.user.id, }; const foundClasses = await classDb.find(queryText); return res.status(200).json(foundClasses); @@ -43,7 +43,7 @@ const Class = { try { const queryText = { _id: req.params.id, - school_id: req.user.school.id, + school_id: req.user.id, }; const foundClass = await classDb.findOne(queryText); if (!foundClass) return res.status(404).send({ message: 'Class not found' }); @@ -60,7 +60,7 @@ const Class = { const queryText = { isArm: true, parent_id: req.params.id, - school_id: req.user.school.id, + school_id: req.user.id, }; const foundArms = await classDb.findOne(queryText); return res.status(200).json(foundArms); @@ -72,7 +72,7 @@ const Class = { try { const queryText = { _id: req.params.id, - school_id: req.user.school.id, + school_id: req.user.id, }; const updateData = _.omit(req.body, ['school_id']); const updatedClass = await classDb.findOneAndUpdate(queryText, updateData); @@ -89,7 +89,7 @@ const Class = { try { const queryText = { _id: req.params.id, - school_id: req.user.school.id, + school_id: req.user.id, }; const deletedClass = await classDb.findOneAndDelete(queryText); if (!deletedClass) return res.status(404).send({ message: 'Class not found' }); diff --git a/controllers/fee.js b/controllers/fee.js index f670363..e9d9439 100644 --- a/controllers/fee.js +++ b/controllers/fee.js @@ -4,7 +4,7 @@ const feeDb = require('./promise').FeeDb; const Fee = { async create(req, res) { const queryText = _.omit(req.body, ['school_id']); - queryText.school_id = req.user.school.id; + queryText.school_id = req.user.id; try { const createdFee = await feeDb.create(queryText); return res.status(201).send({ @@ -16,7 +16,7 @@ const Fee = { } }, async get_all_fees(req, res) { - const queryText = { school_id: req.user.school.id }; + const queryText = { school_id: req.user.id }; try { const foundFees = await feeDb.find(queryText); return res.status(200).send({ @@ -30,7 +30,7 @@ const Fee = { async get_one_fee(req, res) { const queryText = { _id: req.params.id, - school_id: req.user.school.id + school_id: req.user.id }; try { const foundFee = await feeDb.findOne(queryText); @@ -46,7 +46,7 @@ const Fee = { async update_fee(req, res) { const queryText = { _id: req.params.id, - school_id: req.user.school.id + school_id: req.user.id }; const updateData = _.omit(req.body, ['school_id']); try { @@ -63,7 +63,7 @@ const Fee = { async delete_fee(req, res) { const queryText = { _id: req.params.id, - school_id: req.user.school.id + school_id: req.user.id }; try { const deletedFee = await feeDb.findOneAndDelete(queryText); diff --git a/controllers/student.js b/controllers/student.js index d2b30ec..9f2c298 100644 --- a/controllers/student.js +++ b/controllers/student.js @@ -6,7 +6,7 @@ const Student = { console.log(req); try { const queryText = _.omit(req.body, ['school_id']); - queryText.school_id = req.user.school.id; + queryText.school_id = req.user.id; console.log(queryText); const createdStudent = await studentDb.create(queryText); return res.status(201).send({ @@ -18,7 +18,7 @@ const Student = { } }, async get_all_students(req, res) { - const queryText = { school_id: req.user.school.id }; + const queryText = { school_id: req.user.id }; try { const foundStudents = await studentDb.find(queryText); return res.status(200).send({ @@ -30,7 +30,7 @@ const Student = { } }, async get_all_students_json(req, res) { - const queryText = { school_id: req.user.school.id }; + const queryText = { school_id: req.user.id }; try { const foundStudents = await studentDb.find(queryText); return res.status(200).json({ @@ -44,7 +44,7 @@ const Student = { async get_one_student(req, res) { const queryText = { _id: req.params.id, - school_id: req.user.school.id, + school_id: req.user.id, }; try { const foundStudent = await studentDb.findOne(queryText); @@ -60,7 +60,7 @@ const Student = { async update_student(req, res) { const queryText = { _id: req.params.id, - school_id: req.user.school.id, + school_id: req.user.id, }; const updateData = _.omit(req.body, ['school_id']); try { @@ -77,7 +77,7 @@ const Student = { async delete_student(req, res) { const queryText = { _id: req.params.id, - school_id: req.user.school.id + school_id: req.user.id }; try { const deletedStudent = await studentDb.findOneAndDelete(queryText); diff --git a/controllers/term.js b/controllers/term.js index e971793..bebb057 100644 --- a/controllers/term.js +++ b/controllers/term.js @@ -5,7 +5,7 @@ const Term = { async create(req, res) { try { const queryText = _.omit(req.body, ['school_id']); - queryText.school_id = req.user.school.id; + queryText.school_id = req.user.id; const createdTerm = await termDb.create(queryText); return res.status(201).send({ message: 'Term created successfully', @@ -16,7 +16,7 @@ const Term = { } }, async get_all_terms(req, res) { - const queryText = { school_id: req.user.school.id }; + const queryText = { school_id: req.user.id }; try { const foundTerms = await termDb.find(queryText); return res.status(200).send({ @@ -30,7 +30,7 @@ const Term = { async get_one_term(req, res) { const queryText = { _id: req.params.id, - school_id: req.user.school.id, + school_id: req.user.id, }; try { const foundTerm = await termDb.findOne(queryText); @@ -46,7 +46,7 @@ const Term = { async update_term(req, res) { const queryText = { _id: req.params.id, - school_id: req.user.school.id, + school_id: req.user.id, }; const updateData = _.omit(req.body,['school_id']); try { @@ -63,7 +63,7 @@ const Term = { async delete_term(req, res) { const queryText = { _id: req.params.id, - school_id: req.user.school.id + school_id: req.user.id }; try { const deletedTerm = await termDb.findOneAndDelete(queryText); diff --git a/models/school.js b/models/school.js index 908330c..27e3514 100644 --- a/models/school.js +++ b/models/school.js @@ -22,9 +22,9 @@ schoolSchema.methods.validatePassword = function(password) { schoolSchema.methods.toJSON = function() { return { + id: this.id, name: this.name, - email: this.email, - username: this.username + email: this.email }; };