From 7dd862e134519b3c3a9cd7114a4ed2b3edb17daa Mon Sep 17 00:00:00 2001 From: Harrison Deng Date: Mon, 4 Apr 2022 22:50:26 -0500 Subject: [PATCH] Added U and D endpoints. --- .../server/controllers/matchController.js | 89 +++++++++++- .../server/controllers/userController.js | 137 +++++++++--------- sports-matcher/server/middleware/authority.js | 6 +- sports-matcher/server/schemas/matchModel.js | 13 ++ 4 files changed, 176 insertions(+), 69 deletions(-) diff --git a/sports-matcher/server/controllers/matchController.js b/sports-matcher/server/controllers/matchController.js index bfb9080..8619e20 100644 --- a/sports-matcher/server/controllers/matchController.js +++ b/sports-matcher/server/controllers/matchController.js @@ -46,7 +46,6 @@ MatchController.get("/recent/:limit?", needDatabase, async (req, res) => { } }); -// TODO: delete, update match. MatchController.post("/", needDatabase, authenticationGuard, async (req, res) => { try { const userId = req.session.userId; @@ -73,6 +72,47 @@ MatchController.post("/", needDatabase, authenticationGuard, async (req, res) => } }); +MatchController.patch("/:id", needDatabase, authenticationGuard, async (req, res) => { + const match = await matchModel.findById(req.params.id); + if (!match) { + res.status(400).send("Invalid match ID provided."); + return; + } + + if (req.user._id !== match.creator && req.user.accessLevel < 3) { + res.status(401).send("Not authorized."); + return; + } + + if (req.body._id) { + res.status(400).send("Cannot change ID of match."); + return; + } + + if (req.body.creator) { + res.status(400).send("Cannot change creator of match."); + return; + } + + await match.updateOne(req.body); + + res.status(200).send(match); +}); + +MatchController.delete("/:id", needDatabase, authenticationGuard, async (req, res) => { + const match = await matchModel.findById(req.params.id); + if (!match) { + res.status(400).send("Invalid match ID provided."); + return; + } + + if (req.user._id !== match.creator && req.user.accessLevel < 3) { + res.status(401).send("Not authorized."); + return; + } + await match.deleteOne(); +}); + MatchController.get("/:matchId", needDatabase, async (req, res) => { if (!req.params.matchId) { res.status(404).send("Id must be provided to retrieve match"); @@ -91,4 +131,51 @@ MatchController.get("/:matchId", needDatabase, async (req, res) => { } }); +MatchController.get("/join/:id", needDatabase, authenticationGuard, async (req, res) => { + const match = await matchModel.findById(req.params.id); + const user = req.user; + if (!match) { + res.status(400).send("Invalid match ID provided."); + return; + } + + if (user.participatingMatches.includes(match._id)) { + res.status(400).send("Already participating in match."); + return; + } + + match.participants.push(user._id); + user.participatingMatches.push(match._id); + + await match.save(); + await user.save(); + + res.status(200).send("Joined."); +}); + +MatchController.get("/leave/:id", needDatabase, authenticationGuard, async (req, res) => { + const match = await matchModel.findById(req.params.id); + const user = req.user; + + if (!match) { + res.status(400).send("Invalid match ID provided."); + return; + } + + if (!user.participatingMatches.includes(match._id)) { + res.status(400).send("Not part of match."); + return; + } + + const userIndex = match.participants.indexOf(user._id); + match.participants.splice(userIndex, 1); + await match.save(); + + const matchIndex = user.participatingMatches.indexOf(match._id); + user.participatingMatches.splice(matchIndex, 1); + await user.save(); + + res.status(200).send("Left match."); +}); + export default MatchController; \ No newline at end of file diff --git a/sports-matcher/server/controllers/userController.js b/sports-matcher/server/controllers/userController.js index 821e50b..4ca3888 100644 --- a/sports-matcher/server/controllers/userController.js +++ b/sports-matcher/server/controllers/userController.js @@ -1,6 +1,7 @@ import express from "express"; import { authenticationGuard } from "../middleware/authority.js"; import { needDatabase } from "../middleware/database.js"; +import userModel from "../schemas/userModel.js"; import User from "../schemas/userModel.js"; const UserController = express.Router(); @@ -49,84 +50,88 @@ UserController.get("/logout", authenticationGuard, (req, res) => { }); }); -UserController.get("/email/:userId?", needDatabase, authenticationGuard, async (req, res) => { - if (!req.params.userId) req.params.userId = req.session.userId; - const curUser = await User.findById(req.session.userId); - const selUser = req.session.userId === req.params.userId ? curUser : await User.findById(req.params.userId); - if (selUser.email.public || curUser._id === selUser._id || curUser.accessLevel > 2) { - res.status(200).send({ email: selUser.email }); +UserController.get("/:id?", needDatabase, authenticationGuard, async (req, res) => { + 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("Could not authenticate request."); + user = req.user; } + user.password = undefined; + res.status(200).send(user); }); -UserController.get("/firstName/:userId?", needDatabase, authenticationGuard, async (req, res) => { - if (!req.params.userId) req.params.userId = req.session.userId; - const curUser = await User.findById(req.session.userId); - const selUser = req.session.userId === req.params.userId ? curUser : await User.findById(req.params.userId); - if (selUser.firstName.public || curUser._id === selUser._id || curUser.accessLevel > 2) { - res.status(200).send({ firstName: selUser.firstName }); +UserController.patch("/:id?", needDatabase, authenticationGuard, async (req, res) => { + 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("Could not authenticate request."); + 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.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.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; + } + + await user.updateOne(req.body); + res.status(200).send("Updated."); }); -UserController.get("/lastName/:userId?", needDatabase, authenticationGuard, async (req, res) => { - if (!req.params.userId) req.params.userId = req.session.userId; - const curUser = await User.findById(req.session.userId); - const selUser = req.session.userId === req.params.userId ? curUser : await User.findById(req.params.userId); - if (selUser.lastName.public || curUser._id === selUser._id || curUser.accessLevel > 2) { - res.status(200).send({ email: selUser.lastName }); +/* TODO: Implement middleware for removing users. + +UserController.delete("/:id?", needDatabase, authenticationGuard, async (req, res) => { + 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("Could not authenticate request."); + user = req.user; } + + await user.deleteOne(); + res.status(200).send("Deleted user."); }); -UserController.get("/phone/:userId?", needDatabase, authenticationGuard, async (req, res) => { - if (!req.params.userId) req.params.userId = req.session.userId; - const curUser = await User.findById(req.session.userId); - const selUser = req.session.userId === req.params.userId ? curUser : await User.findById(req.params.userId); - if (selUser.phone.public || curUser._id === selUser._id || curUser.accessLevel > 2) { - res.status(200).send({ phone: selUser.phone }); - } else { - res.status(401).send("Could not authenticate request."); - } -}); - -UserController.get("/participatingMatches/:userId?", needDatabase, authenticationGuard, async (req, res) => { - if (!req.params.userId) req.params.userId = req.session.userId; - const curUser = await User.findById(req.session.userId); - const selUser = req.session.userId === req.params.userId ? curUser : await User.findById(req.params.userId); - if (selUser.participatingMatches.public || curUser._id === selUser._id || curUser.accessLevel > 2) { - res.status(200).send({ participatingMatches: selUser.participatingMatches }); - } else { - res.status(401).send("Could not authenticate request."); - } -}); - -UserController.get("/joinDate/:userId?", needDatabase, authenticationGuard, async (req, res) => { - if (!req.params.userId) req.params.userId = req.session.userId; - const curUser = await User.findById(req.session.userId); - const selUser = req.session.userId === req.params.userId ? curUser : await User.findById(req.params.userId); - if (curUser._id === selUser._id || curUser.accessLevel > 2) { - res.status(200).send({ joinDate: selUser.joinDate }); - } else { - res.status(401).send("Could not authenticate request."); - } -}); - -UserController.get("/createdMatches/:userId?", needDatabase, authenticationGuard, async (req, res) => { - if (!req.params.userId) req.params.userId = req.session.userId; - const curUser = await User.findById(req.session.userId); - const selUser = req.session.userId === req.params.userId ? curUser : await User.findById(req.params.userId); - if (curUser._id === selUser._id || curUser.accessLevel > 2) { - res.status(200).send({ createdMatches: selUser.createdMatches }); - } else { - res.status(401).send("Could not authenticate request."); - } -}); - -// TODO: Finish update requests using put. +*/ UserController.post("/", needDatabase, async (req, res) => { try { diff --git a/sports-matcher/server/middleware/authority.js b/sports-matcher/server/middleware/authority.js index 8c1c082..bcab71e 100644 --- a/sports-matcher/server/middleware/authority.js +++ b/sports-matcher/server/middleware/authority.js @@ -1,6 +1,7 @@ import MongoStore from "connect-mongo"; import session from "express-session"; import { mongooseDbName, mongoURI } from "../database/mongoose.js"; +import userModel from "../schemas/userModel.js"; const sessionConf = { secret: process.env.SESSION_SECRET || "super duper secret string.", cookie: { @@ -16,11 +17,12 @@ if (process.env.NODE_ENV === "production") { } export const userSession = session(sessionConf); -export function authenticationGuard(req, res, next) { +export async function authenticationGuard(req, res, next) { if (req.session.userId) { + req.user = await userModel.findById(req.session.userId); next(); } else { - res.sendStatus(401); + res.status(401).send("Not authorized."); return; } } diff --git a/sports-matcher/server/schemas/matchModel.js b/sports-matcher/server/schemas/matchModel.js index e86b35b..85c55ee 100644 --- a/sports-matcher/server/schemas/matchModel.js +++ b/sports-matcher/server/schemas/matchModel.js @@ -24,4 +24,17 @@ const matchSchema = new mongoose.Schema({ createDate: { type: Date, required: true, default: Date.now } }); +matchSchema.pre("remove", function (next) { + const match = this; + match.populate("creator").populate("participants"); + + match.participants.forEach(participant => { + const index = participant.participatingMatches.indexOf(match._id); + participant.participatingMatches.splice(index, 1); + }); + + match.creator.createdMatches.splice(match.creator.createdMatches.indexOf(match._id), 1); + next(); +}); + export default mongoose.model(ModelNameRegister.Match, matchSchema); \ No newline at end of file