From eb4e4b2444c770ed3dac730d471a5271dbc4049c Mon Sep 17 00:00:00 2001 From: Harrison Deng Date: Thu, 7 Apr 2022 17:56:04 -0500 Subject: [PATCH] Added suspension mechanism. --- .../client/src/utils/httpClients.js | 2 +- .../server/controllers/userController.js | 112 ++++++++++++------ sports-matcher/server/middleware/authority.js | 24 ++++ sports-matcher/server/middleware/database.js | 8 +- sports-matcher/server/schemas/userModel.js | 1 + 5 files changed, 107 insertions(+), 40 deletions(-) diff --git a/sports-matcher/client/src/utils/httpClients.js b/sports-matcher/client/src/utils/httpClients.js index 36a9ea2..4e2ddcc 100644 --- a/sports-matcher/client/src/utils/httpClients.js +++ b/sports-matcher/client/src/utils/httpClients.js @@ -5,6 +5,6 @@ export const apiClient = axios.create({ timeout: 5000, withCredentials: process.env.NODE_ENV === "development", validateStatus: function (status) { - return status === 401 || status == 200; + return status === 401 || status === 200 || status === 400 || status === 201; } }); \ No newline at end of file diff --git a/sports-matcher/server/controllers/userController.js b/sports-matcher/server/controllers/userController.js index 7267b64..3d589ca 100644 --- a/sports-matcher/server/controllers/userController.js +++ b/sports-matcher/server/controllers/userController.js @@ -1,5 +1,6 @@ import express from "express"; -import { requireAuthenticated } from "../middleware/authority.js"; +import validator from "validator"; +import { requireAdmin, requireAuthenticated } from "../middleware/authority.js"; import { needDatabase } from "../middleware/database.js"; import userModel from "../schemas/userModel.js"; import User from "../schemas/userModel.js"; @@ -67,50 +68,85 @@ UserController.get("/:id?", needDatabase, requireAuthenticated, async (req, res) res.status(200).send(user); }); + UserController.patch("/:id?", needDatabase, requireAuthenticated, async (req, res) => { - let user = null; - if (req.params.id) { - if (req.user.accessLevel > 2) { - user = await userModel.findById(req.params.id); + try { + let user = null; + if (req.params.id) { + if (req.user.accessLevel > 2) { + user = await userModel.findById(req.params.id); + } else { + res.status(401).send("Unauthorized."); + return; + } } else { - res.status(401).send("Unauthorized."); + user = req.user; + } + if (req.body._id) { + res.status(400).send("Cannot change user ID."); return; } - } else { - user = req.user; - } - if (req.body._id) { - res.status(400).send("Cannot change user ID."); - return; - } - if (req.body.createdMatches) { - res.status(400).send("Cannot directly change the list of created matches."); - return; - } + if (req.body.createdMatches) { + res.status(400).send("Cannot directly change the list of created matches."); + return; + } - if (req.body.password) { - res.status(400).send("Cannot directly change user password."); - return; - } + if (req.body.password) { + res.status(400).send("Cannot directly change user password."); + return; + } - if (req.body.participatingMatches) { - res.status(400).send("Cannot directly change the list of participating matches."); - return; - } + if (req.body.participatingMatches) { + res.status(400).send("Cannot directly change the list of participating matches."); + return; + } - if (req.body.joinDate) { - res.status(400).send("Cannot change the join date."); - return; - } + if (req.body.joinDate) { + res.status(400).send("Cannot change the join date."); + return; + } - if (req.body.accessLevel && req.user.accessLevel < 3) { - res.status(401).send("Unauthorized to change the access level of this user."); - return; - } + if (req.body.accessLevel && req.user.accessLevel < 3) { + res.status(401).send("Unauthorized to change the access level of this user."); + return; + } - await user.updateOne(req.body); - res.status(200).send("Updated."); + if (req.body.suspend && req.user.accessLevel < 3) { + res.status(401).send("Unauthorized to change the accounts disabled date. "); + return; + } + + await user.updateOne(req.body); + res.status(200).send("Updated."); + } catch (error) { + console.error(error); + res.status(500).send("Internal server error"); + } +}); + +UserController.get("/all/active", requireAdmin, async (req, res) => { + try { + if (req.user.accessLevel < 3) { + res.status(401).send("You do not have the required privileges."); + return; + } + let res = await userModel.find().where("suspend").lt(Date.now); + res.status(200).send({ all: res }); + } catch (error) { + console.error(error); + res.status(500).send("Internal server error"); + } +}); + +UserController.get("/all/suspended", requireAuthenticated, async (req, res) => { + try { + let res = await userModel.find().where("suspend").gte(Date.now); + res.status(200).send({ suspended: res }); + } catch (error) { + console.error(error); + res.status(500).send("Internal server error"); + } }); /* TODO: Implement middleware for removing users. @@ -136,13 +172,15 @@ UserController.delete("/:id?", needDatabase, requireAuthenticated, async (req, r UserController.post("/", needDatabase, async (req, res) => { try { - let createdUser = new User({ + const data = { email: req.body.email, firstName: req.body.firstName, lastName: req.body.lastName, phone: req.body.phone, password: req.body.password, - }); + }; + + let createdUser = new User(data); await createdUser.save(); res.sendStatus(201); return; diff --git a/sports-matcher/server/middleware/authority.js b/sports-matcher/server/middleware/authority.js index 9c09f66..f7ff1b5 100644 --- a/sports-matcher/server/middleware/authority.js +++ b/sports-matcher/server/middleware/authority.js @@ -2,6 +2,7 @@ import MongoStore from "connect-mongo"; import session from "express-session"; import { mongooseDbName, mongoURI } from "../database/mongoose.js"; import userModel from "../schemas/userModel.js"; +import { checkDatabaseConnection } from "./database.js"; const sessionConf = { secret: process.env.SESSION_SECRET || "super duper secret string.", cookie: { @@ -18,6 +19,10 @@ if (process.env.NODE_ENV === "production") { export const userSession = session(sessionConf); export async function requireAuthenticated(req, res, next) { + if (!checkDatabaseConnection()) { + req.status(500).send("Internal server error."); + return; + } if (req.session.userId) { req.user = await userModel.findById(req.session.userId); next(); @@ -26,3 +31,22 @@ export async function requireAuthenticated(req, res, next) { return; } } + + +export async function requireAdmin(req, res, next) { + if (!checkDatabaseConnection()) { + req.status(500).send("Internal server error."); + return; + } + if (req.session.userId) { + req.user = await userModel.findById(req.session.userId); + if (req.user.accessLevel < 3) { + res.status(401).send("Not authorized"); + return; + } + next(); + } else { + res.status(401).send("Not authorized."); + return; + } +} \ No newline at end of file diff --git a/sports-matcher/server/middleware/database.js b/sports-matcher/server/middleware/database.js index 149344a..f9ffa87 100644 --- a/sports-matcher/server/middleware/database.js +++ b/sports-matcher/server/middleware/database.js @@ -1,9 +1,13 @@ import mongoose from "mongoose"; -export function needDatabase(res, req, next) { - if (mongoose.connection.readyState != 1) { +export function needDatabase(req, res, next) { + if (checkDatabaseConnection()) { res.status(500).send("Internal server error: Database connection faulty."); } else { next(); } +} + +export function checkDatabaseConnection() { + return mongoose.connection.readyState == 1; } \ No newline at end of file diff --git a/sports-matcher/server/schemas/userModel.js b/sports-matcher/server/schemas/userModel.js index 28a2be5..1a98925 100644 --- a/sports-matcher/server/schemas/userModel.js +++ b/sports-matcher/server/schemas/userModel.js @@ -36,6 +36,7 @@ const userSchema = new mongoose.Schema({ participatingMatchesPublicity: { type: Boolean, required: true, default: false }, friends: { type: Types.ObjectId, ref: modelNameRegister.User }, accessLevel: { type: Number, required: true, default: 0 }, + suspend: { type: Date, required: true, default: Date.now } // suspend the user until the when the user was created. }); userSchema.statics.credentialsExist = async function (email, password) {