From 41f8a13adee87e4b7f38233168a8df03b303ce00 Mon Sep 17 00:00:00 2001 From: OomsOoms Date: Fri, 24 May 2024 16:51:53 +0100 Subject: [PATCH] Changed the user model and username validation --- server/src/api/controllers/user.controller.js | 4 +- server/src/api/helpers/sendEmail.js | 40 +++++++------- server/src/api/models/user.model.js | 52 ++++++++++++++++--- server/src/api/services/user.service.js | 25 +++++++-- server/src/api/validations/user.validation.js | 7 ++- 5 files changed, 94 insertions(+), 34 deletions(-) diff --git a/server/src/api/controllers/user.controller.js b/server/src/api/controllers/user.controller.js index b66ee49..d68ba41 100644 --- a/server/src/api/controllers/user.controller.js +++ b/server/src/api/controllers/user.controller.js @@ -10,8 +10,8 @@ const { userService } = require('../services'); async function registerUser(req, res) { // get the username, email, and password from the request body const { username, email, password } = req.body; - await userService.registerUser(username, email, password); - res.status(201).json({ message: 'User created successfully' }); + const user = await userService.registerUser(username, email, password); + res.status(201).json(user); } /** diff --git a/server/src/api/helpers/sendEmail.js b/server/src/api/helpers/sendEmail.js index c558a48..5b03cea 100644 --- a/server/src/api/helpers/sendEmail.js +++ b/server/src/api/helpers/sendEmail.js @@ -1,29 +1,29 @@ -const nodemailer = require('nodemailer'); +//const nodemailer = require('nodemailer'); +// im getting spammed so much so im just loggin the email module.exports = function (to, subject, text) { - const transporter = nodemailer.createTransport({ - service: 'Gmail', - host: 'smtp.gmail.com', - port: 465, - secure: true, - auth: { - user: process.env.EMAIL_USER, - pass: process.env.EMAIL_PASS, - }, - }); - console.log(process.env.EMAIL_USER, process.env.EMAIL_PASS); + //const transporter = nodemailer.createTransport({ + // service: 'Gmail', + // host: 'smtp.gmail.com', + // port: 465, + // secure: true, + // auth: { + // user: process.env.EMAIL_USER, + // pass: process.env.EMAIL_PASS, + // }, + //}); const mailOptions = { //from: "", // If not set, it will be sent from the default email of the gmail account to: to, subject: subject, text: text, }; - - transporter.sendMail(mailOptions, (error, info) => { - if (error) { - console.error('Error sending email: ', error); - } else { - console.log('Email sent: ', info.response); - } - }); + //transporter.sendMail(mailOptions, (error, info) => { + // if (error) { + // console.error('Error sending email: ', error); + // } else { + // console.log('Email sent: ', info.response); + // } + //}); + console.log(mailOptions); }; diff --git a/server/src/api/models/user.model.js b/server/src/api/models/user.model.js index 398cafe..b781410 100644 --- a/server/src/api/models/user.model.js +++ b/server/src/api/models/user.model.js @@ -17,22 +17,62 @@ const UserSchema = new mongoose.Schema( type: String, required: true, }, - passwordChangedAt: { - type: Number, - default: () => Math.floor(Date.now() / 1000), + profile: { + displayName: { + type: String, + default: this.username, + }, + bio: { + type: String, + default: 'No bio provided', + }, + profilePicture: { + type: String, + default: + 'https://i.pinimg.com/736x/c3/57/fa/c357face2de95f03e31c27cecec2ef63.jpg', + }, }, - active: { - type: Boolean, - default: false, + settings: { + language: { + type: String, + default: 'en', + }, + }, + createdAt: { + type: Date, + default: Date.now(), + index: { + expireAfterSeconds: 60, + partialFilterExpression: { active: false }, + }, + }, + updatedAt: { + type: Date, + default: () => Date.now(), }, roles: { type: [String], default: ['user'], }, + active: { + type: Boolean, + default: false, + }, + lastLogin: { + type: Date, + default: null, + }, }, { collection: 'Users' } ); +UserSchema.pre('save', function (next) { + // 'this' refers to the User document. + if (!this.profile.displayName) { + this.profile.displayName = this.username; + } + next(); +}); UserSchema.pre('save', async function (next) { if (!this.isModified('password')) return next(); this.password = await hashPassword(this.password); diff --git a/server/src/api/services/user.service.js b/server/src/api/services/user.service.js index 29e7f00..4d75621 100644 --- a/server/src/api/services/user.service.js +++ b/server/src/api/services/user.service.js @@ -2,17 +2,33 @@ const { User } = require('../models'); const { generateJwt, comparePasswords, sendEmail } = require('../helpers'); const { Error } = require('../helpers'); -// if a user hasnt verified their email within a certain time frame, they should be deleted -// jwt token method im using might not be the best for this so i might need to change it async function registerUser(username, email, password) { try { + // Few details are needed to create a user, this is to reduce friction in the registration process const user = new User({ username, email, password }); await user.save(); const token = generateJwt({ id: user._id }, { expiresIn: '10m' }); const verificationLink = `${process.env.DOMAIN}/api/users/verify?token=${token}`; sendEmail(email, 'Verify your email', verificationLink); - - return true; + return { + success: true, + message: + 'User created, email verification link sent and will expire in 10 minutes', + user: { + _id: user._id, + username: user.username, + email: user.email, + active: user.active, + profile: { + bio: user.profile.bio, + profilePicture: user.profile.profilePicture, + displayName: user.profile.displayName, + }, + settings: { + language: user.settings.language, + }, + }, + }; } catch (error) { if (error.code === 11000) { if (error.keyValue.username) { @@ -21,7 +37,6 @@ async function registerUser(username, email, password) { throw Error.mongoConflictError('Email already exists'); } } - // Throw an error if its not a duplicate key error throw error; } } diff --git a/server/src/api/validations/user.validation.js b/server/src/api/validations/user.validation.js index 9649eb6..3f7e587 100644 --- a/server/src/api/validations/user.validation.js +++ b/server/src/api/validations/user.validation.js @@ -10,6 +10,11 @@ const registerUser = [ .bail() .isLength({ min: 3 }) .withMessage('Username must be at least 3 characters long') + .bail() + .matches(/^[a-z0-9_-]+$/) + .withMessage( + 'Username can only contain lowercase letters, numbers, underscores, and hyphens' + ) .bail(), body('email') .notEmpty() @@ -26,7 +31,7 @@ const registerUser = [ .withMessage('Password is required') .bail() .isLength({ min: 8 }) - .withMessage('Password must be at least 8 characters long') + .withMessage('Password must be at least 8 characters long') .bail() .trim() .escape()