const User = require("../models/user.js"); const asyncHandler = require("express-async-handler"); const { body, validationResult } = require("express-validator"); const { default: mongoose } = require("mongoose"); const bcrypt = require("bcryptjs"); const passport = require("passport"); exports.new_get = (req, res, next) => { res.render("newuser", { errors: false }); }; exports.new_post = [ // Validate and sanitize fields body("username", "Please enter a username!") .trim() .escape() .isLength({ min: 1 }) .custom(async (value) => { const found = await User.findOne({ username: value }).lean().exec(); if (found) throw new Error("User already exists!"); else return value; }), body("password", "Please enter a password!") .trim() .escape() .isLength({ min: 1 }), body("confirm", "Please confirm password!") .trim() .escape() .isLength({ min: 1 }) .custom((value, { req }) => { if (value !== req.body.password) throw new Error("Passwords don't match!"); else return value; }), // Process request after validation and sanitization. asyncHandler(async (req, res, next) => { // Extract the validation errors from a request. const errors = validationResult(req); // if there are validation errors if (!errors.isEmpty()) { // Render the creation form again with sanitized values/error messages. res.render("newuser", { errors: errors.array(), }); return; } // else data is valid // create new user with hashed password const user = new User({ username: req.body.username, password: await bcrypt.hash(req.body.password, 10), _id: new mongoose.Types.ObjectId(), }); await user.save(); // saved. Redirect to login page res.redirect(`/user/login`); }), ]; exports.login_get = (req, res, next) => { res.render("login", { error: false }); }; exports.login_post = (req, res, next) => { passport.authenticate("local", (err, user, options) => { if (!user) { return res.render("login", { error: options.message }); } req.login(user, (error) => { if (error) { console.log(error); } return res.redirect("/"); }); })(req, res, next); }; exports.logout = (req, res, next) => { req.logout(() => { res.redirect("/"); }); }; exports.get = asyncHandler(async (req, res, next) => { const user = await User.findById(req.params.userID).exec(); res.render("user", { user: user, currentUser: req.user, }); }); exports.put_get = asyncHandler(async (req, res, next) => { const user = await User.findById(req.params.userID).lean().exec(); res.render("edituser", { user: user, }); }); exports.put = [ // Validate and sanitize fields // username cannot be changed for security/impersonation reasons body("oldpassword", "Please enter current password to authorize changes!") .trim() .escape() .isLength({ min: 1 }), body("password", "Please enter new password!").optional().trim().escape(), body("confirm", "Please confirm new password!") .optional() .trim() .escape() .custom((value, { req }) => { if (value !== req.body.password) throw new Error("Passwords don't match!"); else return value; }), // tbd: allow profile pic changes with multer // Process request after validation and sanitization. asyncHandler(async (req, res, next) => { // Extract the validation errors from a request. const errors = validationResult(req); // if there are validation errors if (!errors.isEmpty()) { // Render the creation form again with sanitized values/error messages. res.render("edituser", { errors: errors.array(), }); return; } // else data is valid // find existing user in DB const dbUser = User.findById(req.params.userID).lean().exec(); // make new user const user = new User({ username: dbUser.username, password: await bcrypt.hash(req.body.password, 10), _id: dbUser._id, }); // update user in DB to new user await User.findByIdAndUpdate(dbUser._id, user, {}); // saved. logout and redirect to log in again req.logout((err) => { if (err) { return next(err); } res.redirect("/user/login"); }); }), ]; exports.delete = asyncHandler(async (req, res, next) => { await User.findByIdAndDelete(req.params.userID); req.logout((err) => { if (err) { return next(err); } res.redirect("/user/login"); }); });