From c6b15074fb0f12b83f1a481cf5098580f738dfbf Mon Sep 17 00:00:00 2001 From: Harrison Deng Date: Fri, 1 Apr 2022 05:36:10 -0500 Subject: [PATCH] Created some create and read endpoints. --- server/controllers/MatchController.js | 71 +++++++++++ server/controllers/SportController.js | 48 ++++++++ server/controllers/UserController.js | 168 ++++++++++++++++++++++++++ server/server.js | 28 ++++- 4 files changed, 314 insertions(+), 1 deletion(-) create mode 100644 server/controllers/MatchController.js create mode 100644 server/controllers/SportController.js create mode 100644 server/controllers/UserController.js diff --git a/server/controllers/MatchController.js b/server/controllers/MatchController.js new file mode 100644 index 0000000..69057d6 --- /dev/null +++ b/server/controllers/MatchController.js @@ -0,0 +1,71 @@ +import express from "express"; +import { authenticationGuard } from "../middleware/Authority.js"; +import { needDatabase } from "../middleware/Database.js"; +import Match from "../schemas/Match.js"; +import Sport from "../schemas/Sport.js"; +import User from "../schemas/User.js"; +const MatchController = express.Router(); + +MatchController.get("/search/:sport", needDatabase, async (req, res) => { + try { + let sport = Sport.findByName(req.params.sport); + let query = Match.find({ sport: sport._id }); + query.where("dateTime").gte(Date.now); // We don't want to return any results of matches that have already occurred. + if (req.query.within) query.where("location").within({ center: req.query.location.split(","), radius: req.query.within }); + if (req.query.minDifficulty) query.where("difficulty").gte(req.query.minDifficulty); + if (req.query.maxDifficulty) query.where("difficulty").lte(req.query.maxDifficulty); + if (req.query.beforeDate) query.where("dateTime").lte(req.query.beforeDate); + + let queryResults = await query; + res.send({ queryResults }); + } catch (error) { + console.error(error); + res.status(500).send("Internal server error."); + } +}); + +// TODO: delete, update match. +MatchController.post("/", needDatabase, authenticationGuard, async (req, res) => { + try { + const userId = req.session.userId; + const match = new Match({ + title: req.body.title, + dateTime: req.body.dateTime, + public: req.body.public, + location: req.body.location, + creator: userId, + difficulty: req.body.difficulty, + sport: await Sport.findByName(req.body.sport) + }); + await match.save(); + const user = await User.findById(userId); + user.createdMatches.push(match._id); + user.participatingMatches.value.push(match._id); + await user.save(); + res.status(201).send(match); + } catch (error) { + console.error(error); + res.status(500).send("Internal server error."); + // TODO: Develop the error handling. + } +}); + +MatchController.get("/:matchId", needDatabase, async (req, res) => { + if (!req.params.matchId) { + res.status(404).send("Id must be provided to retrieve match"); + return; + } + try { + const match = await Match.findById(req.params.matchId); + if (match) { + res.status(200).send(match); + } else { + res.status(404).send("Could not find match with ID: " + req.params.matchId); + } + } catch (error) { + res.status(500).send("Internal server error."); + // TODO: Develop the error handling. + } +}); + +export default MatchController; \ No newline at end of file diff --git a/server/controllers/SportController.js b/server/controllers/SportController.js new file mode 100644 index 0000000..cf8a65a --- /dev/null +++ b/server/controllers/SportController.js @@ -0,0 +1,48 @@ +import express from "express"; +import { authenticationGuard } from "../middleware/Authority.js"; +import { needDatabase } from "../middleware/Database.js"; +import Sport from "../schemas/Sport.js"; +import User from "../schemas/User.js"; + +const SportController = express.Router(); + +SportController.post("/", needDatabase, authenticationGuard, async (req, res) => { + const user = await User.findById(req.session.userId); + try { + if (user.accessLevel <= 2) { + res.status(403).send("Insufficient privileges."); + return; + } + const sport = new Sport({ + name: req.body.name, + maxPlayers: req.body.maxPlayers, + minPlayers: req.body.minPlayers, + description: req.body.description + }); + await sport.save(); + res.status(201).send("Successfully created new sport."); + } catch (error) { + res.status(500).send("Internal server error."); + // TODO: Add proper error checking here. + } +}); + +SportController.get("/:sportId", needDatabase, async (req, res) => { + try { + res.status(200).send(await Sport.findById(req.params.sportId)); + } catch (error) { + res.status(500).send("Internal server error."); + // TODO: Add proper error checking here. + } +}); + +SportController.get("/", needDatabase, async (req, res) => { + try { + res.status(200).send(await Sport.find()); + } catch (error) { + res.status(500).send("Internal server error."); + // TODO: Add proper error checking here. + } +}); + +export default SportController; \ No newline at end of file diff --git a/server/controllers/UserController.js b/server/controllers/UserController.js new file mode 100644 index 0000000..de2dfb1 --- /dev/null +++ b/server/controllers/UserController.js @@ -0,0 +1,168 @@ +import express from "express"; +import { authenticationGuard } from "../middleware/Authority.js"; +import { needDatabase } from "../middleware/Database.js"; +import User from "../schemas/User.js"; +const UserController = express.Router(); + +UserController.post("/login", needDatabase, async (req, res) => { + try { + const email = req.body.email; + const pwd = req.body.password; + const user = await User.credentialsExist(email, pwd); + if (!user) { + res.sendStatus(401); + return; + } else { + req.session.userId = user._id; + req.session.email = user.email.value; + res.status(200).send("Authenticated."); + } + } catch (error) { + if (error.name === "TypeError") { + res.status(400).send("Missing required user info."); + } else if (error.message === "Credentials do not exist.") { + res.status(401).send("Credentials do not exist."); + } else { + console.error(error); + if (process.env.NODE_ENV === "development") { + res.status(500).send(error.toString()); + } else { + res.status(500).send("Internal server error. This issue has been noted."); + } + } + } +}); + +UserController.get("/logout", authenticationGuard, (req, res) => { + req.session.destroy((err) => { + if (err) { + console.error(err); + if (process.env.NODE_ENV === "development") { + res.status(500).send(err.toString()); + } else { + res.status(500).send("Internal server error. This issue has been noted."); + } + res.status(500).send(""); + } else { + res.sendStatus(200); + } + }); +}); + +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.value }); + } else { + res.status(401).send("Could not authenticate request."); + } +}); + +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.value }); + } else { + res.status(401).send("Could not authenticate request."); + } +}); + +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.value }); + } else { + res.status(401).send("Could not authenticate request."); + } +}); + +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.value }); + } 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).populate("participatingMatches.value"); + 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.value }); + } 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).populate("createdMatches"); + 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 { + let createdUser = new User({ + email: req.body.email, + firstName: req.body.firstName, + lastName: req.body.lastName, + phone: req.body.phone, + password: req.body.password, + }); + await createdUser.save(); + res.sendStatus(201); + } catch (err) { + if (err.name === "TypeError" || err.name === "ValidationError") { + if (process.env.NODE_ENV === "development") { + console.error(err); + res.status(400).send(err.toString()); + } else { + res.status(400).send("Missing required user info."); + } + } else if (err.name === "MongoServerError" && err.message.startsWith("E11000")) { + if (process.env.NODE_ENV === "development") { + console.error(err); + res.status(409).send(err.toString()); + } else { + res.status(409).send("User already exists."); + } + } else { + console.error(err); + if (process.env.NODE_ENV === "development") { + res.status(500).send(err.toString()); + } else { + res.status(500).send("Internal server error. This issue has been noted."); + } + } + } +}); + +export default UserController; diff --git a/server/server.js b/server/server.js index 6103e39..7115ac3 100644 --- a/server/server.js +++ b/server/server.js @@ -1,5 +1,31 @@ import express from "express"; +import bodyParser from "body-parser"; +import { mongoose } from "./database/mongoose.js"; +import UserController from "./controllers/UserController.js"; +import MatchController from "./controllers/MatchController.js"; +import SportController from "./controllers/SportController.js"; +import { userSession } from "./middleware/Authority.js"; const server = express(); +const port = process.env.PORT || 3000; -server.use(express.static("public")); // For all client files. \ No newline at end of file +server.use(express.static("public")); // For all client files. + +if (process.env.NODE_ENV === "development") { + mongoose.set("bufferCommands", false); // We want to know if there are connection issues immediately for development. Disables globally. +} + +// Docs: https://www.npmjs.com/package/body-parser +server.use(bodyParser.json()); +server.use(bodyParser.urlencoded({ extended: true })); + +server.use(userSession); + +server.use("/user", UserController); +server.use("/match", MatchController); +server.use("/sport", SportController); + + +server.listen(port, () => { + console.log(`Server listening on port ${port}.`); +}); \ No newline at end of file