diff --git a/Client/src/Components/TabPanels/Account/TeamPanel.jsx b/Client/src/Components/TabPanels/Account/TeamPanel.jsx index 8745a3037..a2ebebd97 100644 --- a/Client/src/Components/TabPanels/Account/TeamPanel.jsx +++ b/Client/src/Components/TabPanels/Account/TeamPanel.jsx @@ -185,7 +185,7 @@ const TeamPanel = () => { "/auth/invite", { email: toInvite.email, - role: [toInvite.role], + role: toInvite.role, }, { headers: { Authorization: `Bearer ${authToken}` } } ); diff --git a/Client/src/Pages/Auth/Register/Register.jsx b/Client/src/Pages/Auth/Register/Register.jsx index a5db76373..3b6b43306 100644 --- a/Client/src/Pages/Auth/Register/Register.jsx +++ b/Client/src/Pages/Auth/Register/Register.jsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useState, useEffect } from "react"; import { useNavigate } from "react-router-dom"; import { useTheme } from "@emotion/react"; import { Stack, Typography } from "@mui/material"; @@ -15,13 +15,13 @@ import { createToast } from "../../../Utils/toastUtils"; import Field from "../../../Components/Inputs/Field"; import { register } from "../../../Features/Auth/authSlice"; import { useParams } from "react-router-dom"; +import axiosInstance from "../../../Utils/axiosConfig"; const Register = ({ isAdmin }) => { const dispatch = useDispatch(); const navigate = useNavigate(); const { token } = useParams(); const theme = useTheme(); - // TODO If possible, change the IDs of these fields to match the backend const idMap = { "register-firstname-input": "firstName", @@ -41,10 +41,27 @@ const Register = ({ isAdmin }) => { }); const [errors, setErrors] = useState({}); + useEffect(() => { + const fetchInvite = async () => { + if (token !== undefined) { + try { + const res = await axiosInstance.post(`/auth/invite/verify`, { + token, + }); + const { role, email } = res.data.data; + console.log(role); + setForm({ ...form, email, role }); + } catch (error) { + console.log(error); + } + } + }; + fetchInvite(); + }, [token]); + const handleSubmit = async (e) => { e.preventDefault(); - - const registerForm = { ...form, role: isAdmin ? ["admin"] : [] }; + const registerForm = { ...form, role: isAdmin ? ["admin"] : form.role }; const { error } = credentials.validate(registerForm, { abortEarly: false, context: { password: form.password }, diff --git a/Client/src/Validation/validation.js b/Client/src/Validation/validation.js index 00d5a1d49..a60259234 100644 --- a/Client/src/Validation/validation.js +++ b/Client/src/Validation/validation.js @@ -68,7 +68,7 @@ const credentials = joi.object({ } return value; }), - role: joi.array().required(), + role: joi.array(), }); const monitorValidation = joi.object({ diff --git a/Server/controllers/authController.js b/Server/controllers/authController.js index 28126c0a2..88a7c7f71 100644 --- a/Server/controllers/authController.js +++ b/Server/controllers/authController.js @@ -10,6 +10,7 @@ const { deleteUserParamValidation, inviteRoleValidation, inviteBodyValidation, + inviteVerifciationBodyValidation, } = require("../validation/joi"); const logger = require("../utils/logger"); require("dotenv").config(); @@ -58,20 +59,21 @@ const registerController = async (req, res, next) => { return; } - // Check if an admin user exists, if so, error - try { - const admin = await req.db.checkAdmin(req, res); - console.log(admin); - if (admin === true) { - throw new Error(errorMessages.AUTH_ADMIN_EXISTS); - } - } catch (error) { - console.log("WEEEEEEE", error.message); - error.service = SERVICE_NAME; - error.status = 403; - next(error); - return; - } + // TODO Can there be more than one admin? + // // Check if an admin user exists, if so, error + // try { + // const admin = await req.db.checkAdmin(req, res); + // console.log(admin); + // if (admin === true) { + // throw new Error(errorMessages.AUTH_ADMIN_EXISTS); + // } + // } catch (error) { + // console.log("WEEEEEEE", error.message); + // error.service = SERVICE_NAME; + // error.status = 403; + // next(error); + // return; + // } // Create a new user try { @@ -237,6 +239,21 @@ const inviteController = async (req, res, next) => { } }; +const inviteVerifyController = async (req, res, next) => { + try { + await inviteVerifciationBodyValidation.validateAsync(req.body); + const invite = await req.db.getInviteToken(req, res); + + res + .status(200) + .json({ status: "success", msg: "Invite verified", data: invite }); + } catch (error) { + error.service = SERVICE_NAME; + next(error); + return; + } +}; + /** * Checks to see if an admin account exists * @async @@ -445,6 +462,7 @@ module.exports = { loginController, userEditController, inviteController, + inviteVerifyController, checkAdminController, recoveryRequestController, validateRecoveryTokenController, diff --git a/Server/db/MongoDB.js b/Server/db/MongoDB.js index 104e49f38..02447022e 100644 --- a/Server/db/MongoDB.js +++ b/Server/db/MongoDB.js @@ -46,6 +46,7 @@ const insertUser = async (req, res) => { const avatar = await GenerateAvatarImage(req.file); userData.avatarImage = avatar; } + console.log(userData); const newUser = new UserModel(userData); await newUser.save(); return await UserModel.findOne({ _id: newUser._id }) @@ -174,6 +175,7 @@ const requestInviteToken = async (req, res) => { await InviteToken.deleteMany({ email: req.body.email }); let inviteToken = new InviteToken({ email: req.body.email, + role: req.body.role, token: crypto.randomBytes(32).toString("hex"), }); await inviteToken.save(); @@ -183,6 +185,20 @@ const requestInviteToken = async (req, res) => { } }; +const getInviteToken = async (req, res) => { + try { + const invite = await InviteToken.findOneAndDelete({ + token: req.body.token, + }); + if (invite === null) { + throw new Error(errorMessages.AUTH_INVITE_NOT_FOUND); + } + return invite; + } catch (error) { + throw error; + } +}; + /** * Request a recovery token * @async @@ -693,6 +709,7 @@ module.exports = { deleteUser, getAllUsers, requestInviteToken, + getInviteToken, requestRecoveryToken, validateRecoveryToken, resetPassword, diff --git a/Server/models/InviteToken.js b/Server/models/InviteToken.js index 6abc3d30b..10515dadb 100644 --- a/Server/models/InviteToken.js +++ b/Server/models/InviteToken.js @@ -7,6 +7,10 @@ const InviteTokenSchema = mongoose.Schema( required: true, unique: true, }, + role: { + type: Array, + required: true, + }, token: { type: String, required: true, diff --git a/Server/routes/authRoute.js b/Server/routes/authRoute.js index 02a1a67dd..137434b7a 100644 --- a/Server/routes/authRoute.js +++ b/Server/routes/authRoute.js @@ -17,6 +17,7 @@ const { getAllUsersController, deleteUserController, inviteController, + inviteVerifyController, } = require("../controllers/authController"); //Auth routes @@ -38,6 +39,7 @@ router.delete( ); router.post("/invite", verifyJWT, inviteController); +router.post("/invite/verify", inviteVerifyController); //Recovery routes router.post("/recovery/request", recoveryRequestController); diff --git a/Server/utils/messages.js b/Server/utils/messages.js index 9ef5c6938..19d9929ab 100644 --- a/Server/utils/messages.js +++ b/Server/utils/messages.js @@ -6,6 +6,7 @@ const errorMessages = { // Auth Controller UNAUTHORIZED: "Unauthorized access", AUTH_ADMIN_EXISTS: "Admin already exists", + AUTH_INVITE_NOT_FOUND: "Invite not found", //Error handling middleware UNKNOWN_SERVICE: "Unknown service", diff --git a/Server/validation/joi.js b/Server/validation/joi.js index ec773632c..6384f13ba 100644 --- a/Server/validation/joi.js +++ b/Server/validation/joi.js @@ -68,7 +68,7 @@ const editUserBodyValidation = joi.object({ /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*()])[A-Za-z0-9!@#$%^&*()]+$/ ), deleteProfileImage: joi.boolean(), - role: joi.string(), + role: joi.array(), }); const recoveryValidation = joi.object({ @@ -107,9 +107,11 @@ const inviteBodyValidation = joi.object({ "string.empty": "Email is required", "string.email": "Must be a valid email address", }), - role: joi.string().required().messages({ - "string.empty": "Role is required", - }), + role: joi.array().required(), +}); + +const inviteVerifciationBodyValidation = joi.object({ + token: joi.string().required(), }); //**************************************** @@ -239,6 +241,7 @@ module.exports = { newPasswordValidation, inviteRoleValidation, inviteBodyValidation, + inviteVerifciationBodyValidation, getMonitorByIdValidation, getMonitorsByUserIdValidation, monitorValidation,