diff --git a/server/src/index.ts b/server/src/index.ts index 354b90f85..a0ccbb98e 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -18,6 +18,7 @@ import Mailgun from "mailgun.js"; import { messagesCollection } from "./utilities/firebaseInit"; import { calculateDistanceInMeters } from "./actions/calculateDistance"; import { scheduleCron } from "./actions/deleter"; +import mainRouter from "./routes/mainRouteHandler"; const { createServer } = require("http"); const { Server } = require("socket.io"); @@ -156,187 +157,9 @@ app.get("/", (req, res) => { res.send("Echologator API"); }); -app.get("/users", async (req, res) => { - let query = ""; - try { - if (req.query.lat && req.query.lon && req.query.radius) { - // Looks up all users close to a geographic location extended by a radius (in meters). - query = "?lat&lon&radius"; - const lat = Number(req.query.lat); - const lon = Number(req.query.lon); - const radius = Number(req.query.radius); +app.use(mainRouter); - const userIds = await findNearbyUsers(lat, lon, radius); - res.json(userIds); - } else if (req.query.userId) { - query = "?userId"; - const userId = req.query.userId; - if (typeof userId != "string") throw Error(" [userId] is not a string."); - - const user = await getConnectedUser(userId); - if (user) { - res.json(user); - } else { - // getConnectedUserDisplayName() will return false is an error is thrown, and print it to console. - throw Error("getConnectedUser() failed."); - } - } - } catch (error) { - console.error( - `[EXP] Error returning request :\n`, - error.message - ); - res.json(`Operation failed.`); - } -}); - -app.post("/users", async (req, res) => { - try { - const status = await createUser({ - uid: req.body.uid, - socketId: req.body.socketId, - displayName: req.body.displayName, - userIcon: { - foregroundImage: req.body.userIcon.foregroundImage, - backgroundImage: req.body.userIcon.backgroundImage, - }, - location: { - lat: Number(req.body.location.lat), - lon: Number(req.body.location.lon), - geohash: req.body.location.geohash, - }, - }); - if (status === false) throw new Error("Error creating user: "); - res.json("Operation was handled successfully."); - console.log("[EXP] Request returned successfully."); - } catch (error) { - console.error( - "[EXP] Error returning request :\n", - error.message - ); - res.json(`Operation failed.`); - } -}); - -app.put("/users", async (req, res) => { - let query = ""; - try { - if (req.query.userId && req.query.toggleConnection) { - // Note: toggleConnection should be assigned 'true', but it at least needs to contain any value. We don't perform a check on this parameter for this reason. - query = "?userId&toggleConnection"; - const userId = req.query.userId; - if (typeof userId != "string") throw Error(" [userId] is not a string."); - - const success = await toggleUserConnectionStatus(userId); - if (!success) throw Error(" toggleUserConnectionStatus() failed."); - } else if (req.query.userId && req.query.lat && req.query.lon) { - query = "?userId&lat&lon"; - const userId = req.query.userId; - const lat = Number(req.query.lat); - const lon = Number(req.query.lon); - if (typeof userId != "string") throw Error(" [userId] is not a string."); - if (typeof lat != "number") throw Error(" [lat] is not a number."); - if (typeof lon != "number") throw Error(" [lon] is not a number."); - - const success = await updateUserLocation(userId, lat, lon); - if (!success) throw Error(" toggleUserConnectionStatus() failed."); - } else if (req.query.userId && req.query.displayName) { - query = "?userId&displayName"; - const userId = req.query.userId; - if (typeof userId != "string") throw Error(" [userId] is not a string."); - const displayName = req.query.displayName; - if (typeof displayName != "string") - throw Error(" [displayName] is not a string."); - - const success = await updateUserDisplayName(userId, displayName); - if (!success) throw Error("updateDisplayName() failed."); - } - console.log(`[EXP] Request returned successfully.`); - res.json(`Operation was handled successfully.`); - } catch (error) { - console.error( - `[EXP] Error returning request :\n`, - error.message - ); - res.json(`Operation failed.`); - } -}); - -app.delete("/users", async (req, res) => { - let query = ""; - try { - query = "?userId"; - const userId = req.query.userId; - if (typeof userId != "string") throw Error(" [userId] is not a string."); - - const success = await deleteConnectedUserByUID(userId); - if (!success) throw Error(" deleteUserById() failed."); - - console.log(`[EXP] Request returned successfully.`); - res.json(`Operation was handled successfully.`); - } catch (error) { - console.error( - `[EXP] Error returning request :\n`, - error.message - ); - res.json(`Operation failed.`); - } -}); - -app.post("/verify", async (req, res) => { - let query = ""; - try { - if (req.query.email) { - query = "?email"; - const email = req.query.email; - const mailgun = new Mailgun(FormData); - const mg = mailgun.client({ - username: "api", - key: process.env.MAILGUN_API_KEY || "key-yourkeyhere", - }); - const data = { - from: "Mailgun Sandbox ", - to: email, - subject: "Verify your email for echologator", - template: "app email verification", - }; - const verifyEmailResponse = await mg.messages.create( - "sandboxf8629624c26849cf8546cd0bc01ee862.mailgun.org", - data - ); - console.log(`[EXP] Request returned successfully.`); - res.json(verifyEmailResponse); - } - } catch (error) { - console.error( - `[EXP] Error returning request :\n`, - error - ); - res.json(`Operation failed.`); - } -}); - -// Error handling -app.get("*", (req, res) => { - res.json("404: Path could not be found! COULD NOT {GET}"); - res.status(404); -}); - -app.post("*", (req, res) => { - res.json("404: Path could not be found! COULD NOT {POST}"); - res.status(404); -}); - -app.put("*", (req, res) => { - res.json("404: Path could not be found! COULD NOT {PUT}"); - res.status(404); -}); - -app.delete("*", (req, res) => { - res.json("404: Path could not be found! COULD NOT {DELETE}"); - res.status(404); -}); app.listen(express_port, () => { return console.log( @@ -344,6 +167,8 @@ app.listen(express_port, () => { ); }); + + //Remove the comments if you want to use the deleter !!!!!! //scheduleCron(); // Begin searching and collecting Garbage (old messages) diff --git a/server/src/routes/auth/authRouteHandler.ts b/server/src/routes/auth/authRouteHandler.ts new file mode 100644 index 000000000..533e6225e --- /dev/null +++ b/server/src/routes/auth/authRouteHandler.ts @@ -0,0 +1,10 @@ +import { Router } from "express"; +import authEmailRoute from "./email"; + +const authRouter = Router(); + + +authRouter.use(authEmailRoute); + + +export default authRouter; \ No newline at end of file diff --git a/server/src/routes/auth/email.ts b/server/src/routes/auth/email.ts new file mode 100644 index 000000000..f1dadcde1 --- /dev/null +++ b/server/src/routes/auth/email.ts @@ -0,0 +1,39 @@ +import { Router } from "express"; +import Mailgun from "mailgun.js"; + +const authEmailRoute = Router(); + +authEmailRoute.post("/verify", async (req, res) => { + let query = ""; + try { + if (req.query.email) { + query = "?email"; + const email = req.query.email; + const mailgun = new Mailgun(FormData); + const mg = mailgun.client({ + username: "api", + key: process.env.MAILGUN_API_KEY || "key-yourkeyhere", + }); + const data = { + from: "Mailgun Sandbox ", + to: email, + subject: "Verify your email for echologator", + template: "app email verification", + }; + const verifyEmailResponse = await mg.messages.create( + "sandboxf8629624c26849cf8546cd0bc01ee862.mailgun.org", + data + ); + console.log(`[EXP] Request returned successfully.`); + res.json(verifyEmailResponse); + } + } catch (error) { + console.error( + `[EXP] Error returning request :\n`, + error + ); + res.json(`Operation failed.`); + } +}); + +export default authEmailRoute; \ No newline at end of file diff --git a/server/src/routes/error/error.ts b/server/src/routes/error/error.ts new file mode 100644 index 000000000..2f717bcd6 --- /dev/null +++ b/server/src/routes/error/error.ts @@ -0,0 +1,27 @@ +import { Router } from "express"; + +const errorRouter = Router(); + + +// Error handling +errorRouter.get("*", (req, res) => { + res.json("404: Path could not be found! COULD NOT {GET}"); + res.status(404); +}); + +errorRouter.post("*", (req, res) => { + res.json("404: Path could not be found! COULD NOT {POST}"); + res.status(404); +}); + +errorRouter.put("*", (req, res) => { + res.json("404: Path could not be found! COULD NOT {PUT}"); + res.status(404); +}); + +errorRouter.delete("*", (req, res) => { +res.json("404: Path could not be found! COULD NOT {DELETE}"); + res.status(404); +}); + +export default errorRouter; \ No newline at end of file diff --git a/server/src/routes/mainRouteHandler.ts b/server/src/routes/mainRouteHandler.ts new file mode 100644 index 000000000..35aacc16e --- /dev/null +++ b/server/src/routes/mainRouteHandler.ts @@ -0,0 +1,12 @@ +import { Router } from "express"; +import authRouter from "./auth/authRouteHandler"; +import userRouter from "./user/userRouteHandler"; +import errorRouter from "./error/error"; + +const mainRouter = Router(); + +mainRouter.use(authRouter); +mainRouter.use(userRouter); +mainRouter.use(errorRouter); + +export default mainRouter; \ No newline at end of file diff --git a/server/src/routes/user/create.ts b/server/src/routes/user/create.ts new file mode 100644 index 000000000..56a2e05a1 --- /dev/null +++ b/server/src/routes/user/create.ts @@ -0,0 +1,34 @@ +import { Router } from "express"; +import { createUser } from "../../actions/createConnectedUser"; + +const createUserRoute = Router(); + +createUserRoute.post("/users", async (req, res) => { + try { + const status = await createUser({ + uid: req.body.uid, + socketId: req.body.socketId, + displayName: req.body.displayName, + userIcon: { + foregroundImage: req.body.userIcon.foregroundImage, + backgroundImage: req.body.userIcon.backgroundImage, + }, + location: { + lat: Number(req.body.location.lat), + lon: Number(req.body.location.lon), + geohash: req.body.location.geohash, + }, + }); + if (status === false) throw new Error("Error creating user: "); + res.json("Operation was handled successfully."); + console.log("[EXP] Request returned successfully."); + } catch (error) { + console.error( + "[EXP] Error returning request :\n", + error.message + ); + res.json(`Operation failed.`); + } +}); + +export default createUserRoute; \ No newline at end of file diff --git a/server/src/routes/user/delete.ts b/server/src/routes/user/delete.ts new file mode 100644 index 000000000..b87d49edd --- /dev/null +++ b/server/src/routes/user/delete.ts @@ -0,0 +1,27 @@ +import { Router } from "express"; +import { deleteConnectedUserByUID } from "../../actions/deleteConnectedUser"; + +const deleteUserRoute = Router(); + +deleteUserRoute.post("/users", async (req, res) => { + let query = ""; + try { + query = "?userId"; + const userId = req.query.userId; + if (typeof userId != "string") throw Error(" [userId] is not a string."); + + const success = await deleteConnectedUserByUID(userId); + if (!success) throw Error(" deleteUserById() failed."); + + console.log(`[EXP] Request returned successfully.`); + res.json(`Operation was handled successfully.`); + } catch (error) { + console.error( + `[EXP] Error returning request :\n`, + error.message + ); + res.json(`Operation failed.`); + } +}); + +export default deleteUserRoute; diff --git a/server/src/routes/user/nearby.ts b/server/src/routes/user/nearby.ts new file mode 100644 index 000000000..43c9763f0 --- /dev/null +++ b/server/src/routes/user/nearby.ts @@ -0,0 +1,41 @@ +import { Router } from "express"; +import { findNearbyUsers, getConnectedUser } from "../../actions/getConnectedUsers"; + +const nearbyUserRoute = Router(); + +nearbyUserRoute.get("/users", async (req, res) => { + let query = ""; + try { + if (req.query.lat && req.query.lon && req.query.radius) { + // Looks up all users close to a geographic location extended by a radius (in meters). + query = "?lat&lon&radius"; + + const lat = Number(req.query.lat); + const lon = Number(req.query.lon); + const radius = Number(req.query.radius); + + const userIds = await findNearbyUsers(lat, lon, radius); + res.json(userIds); + } else if (req.query.userId) { + query = "?userId"; + const userId = req.query.userId; + if (typeof userId != "string") throw Error(" [userId] is not a string."); + + const user = await getConnectedUser(userId); + if (user) { + res.json(user); + } else { + // getConnectedUserDisplayName() will return false is an error is thrown, and print it to console. + throw Error("getConnectedUser() failed."); + } + } + } catch (error) { + console.error( + `[EXP] Error returning request :\n`, + error.message + ); + res.json(`Operation failed.`); + } +}); + +export default nearbyUserRoute; diff --git a/server/src/routes/user/update.ts b/server/src/routes/user/update.ts new file mode 100644 index 000000000..6d068a465 --- /dev/null +++ b/server/src/routes/user/update.ts @@ -0,0 +1,50 @@ +import { Router } from "express"; +import { toggleUserConnectionStatus, updateUserDisplayName, updateUserLocation } from "../../actions/updateConnectedUser"; + +const updateUserRoute = Router(); + +updateUserRoute.put("/users", async (req, res) => { + let query = ""; + try { + if (req.query.userId && req.query.toggleConnection) { + // Note: toggleConnection should be assigned 'true', but it at least needs to contain any value. We don't perform a check on this parameter for this reason. + query = "?userId&toggleConnection"; + const userId = req.query.userId; + if (typeof userId != "string") throw Error(" [userId] is not a string."); + + const success = await toggleUserConnectionStatus(userId); + if (!success) throw Error(" toggleUserConnectionStatus() failed."); + } else if (req.query.userId && req.query.lat && req.query.lon) { + query = "?userId&lat&lon"; + const userId = req.query.userId; + const lat = Number(req.query.lat); + const lon = Number(req.query.lon); + if (typeof userId != "string") throw Error(" [userId] is not a string."); + if (typeof lat != "number") throw Error(" [lat] is not a number."); + if (typeof lon != "number") throw Error(" [lon] is not a number."); + + const success = await updateUserLocation(userId, lat, lon); + if (!success) throw Error(" toggleUserConnectionStatus() failed."); + } else if (req.query.userId && req.query.displayName) { + query = "?userId&displayName"; + const userId = req.query.userId; + if (typeof userId != "string") throw Error(" [userId] is not a string."); + const displayName = req.query.displayName; + if (typeof displayName != "string") + throw Error(" [displayName] is not a string."); + + const success = await updateUserDisplayName(userId, displayName); + if (!success) throw Error("updateDisplayName() failed."); + } + console.log(`[EXP] Request returned successfully.`); + res.json(`Operation was handled successfully.`); + } catch (error) { + console.error( + `[EXP] Error returning request :\n`, + error.message + ); + res.json(`Operation failed.`); + } + }); + +export default updateUserRoute; \ No newline at end of file diff --git a/server/src/routes/user/userRouteHandler.ts b/server/src/routes/user/userRouteHandler.ts new file mode 100644 index 000000000..dea0b91e0 --- /dev/null +++ b/server/src/routes/user/userRouteHandler.ts @@ -0,0 +1,16 @@ +import { Router } from "express"; +import createUserRoute from "./create"; +import deleteUserRoute from "./delete"; +import updateUserRoute from "./update"; +import nearbyUserRoute from "./nearby"; + +const userRouter = Router(); + + +userRouter.use(createUserRoute); +userRouter.use(deleteUserRoute); +userRouter.use(nearbyUserRoute); +userRouter.use(updateUserRoute); + + +export default userRouter;