diff --git a/README.md b/README.md
index 039750dc1..8767a3633 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ BlueWave uptime monitoring application
4. [Endpoints](#endpoints)
- POST [/api/v1/auth/register](#post-register)
- POST [/api/v1/auth/login](#post-login)
+ - POST [/api/v1/auth/user/{userId}](#post-auth-user-edit-id)
- GET [/api/v1/monitors](#get-monitors)
- GET [/api/v1/monitor/{id}](#get-monitor-id)
- GET [/api/v1/monitors/user/{userId}](#get-monitors-user-userid)
@@ -251,6 +252,67 @@ curl --request POST \
---
+
+POST/api/v1/auth/user/{userId}
+
+###### Method/Headers
+
+> | Method/Headers | Value |
+> | -------------- | ----- |
+> | Method | POST |
+
+##### Body
+
+> | Name | Type | Notes |
+> | ------------- | -------- | ----------- |
+> | firstname | `string` | |
+> | lastname | `string` | |
+> | profilePicUrl | `string` | |
+> | password | `string` | Min 8 chars |
+
+###### Response Payload
+
+> | Type | Notes |
+> | ------ | ------------------------ |
+> | `User` | Returns the updated user |
+
+##### Sample CURL request
+
+```
+curl --request POST \
+ --url http://localhost:5000/api/v1/auth/user/6654d156634754f789e1f10e \
+ --header 'Authorization: ' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "firstname": "First Name",
+ "lastname: "Last Name"
+}'
+```
+
+###### Sample Response
+
+```json
+{
+ "success": true,
+ "msg": "User updated",
+ "data": {
+ "_id": "6654d156634754f789e1f10e",
+ "firstname": "First Name",
+ "lastname": "Last Name",
+ "email": "me@gmail.com",
+ "isActive": true,
+ "isVerified": false,
+ "createdAt": "2024-05-27T18:30:46.358Z",
+ "updatedAt": "2024-05-27T19:21:51.747Z",
+ "__v": 0
+ }
+}
+```
+
+
+
+---
+
GET /api/v1/monitors
diff --git a/Server/controllers/authController.js b/Server/controllers/authController.js
index a3a43ba0d..cc476ab54 100644
--- a/Server/controllers/authController.js
+++ b/Server/controllers/authController.js
@@ -1,5 +1,10 @@
const express = require("express");
-const { registerValidation, loginValidation } = require("../validation/joi");
+const {
+ registerValidation,
+ loginValidation,
+ editUserParamValidation,
+ editUserBodyValidation,
+} = require("../validation/joi");
const logger = require("../utils/logger");
require("dotenv").config();
var jwt = require("jsonwebtoken");
@@ -107,4 +112,36 @@ const loginController = async (req, res, next) => {
}
};
-module.exports = { registerController, loginController };
+const userEditController = async (req, res, next) => {
+ try {
+ await editUserParamValidation.validateAsync(req.params);
+ await editUserBodyValidation.validateAsync(req.body);
+ } catch (error) {
+ error.status = 422;
+ error.service = SERVICE_NAME;
+ error.message = error.details[0].message;
+ next(error);
+ return;
+ }
+
+ if (req.params.userId !== req.user._id.toString()) {
+ const error = new Error("Unauthorized access");
+ error.status = 401;
+ error.service = SERVICE_NAME;
+ next(error);
+ return;
+ }
+
+ try {
+ const updatedUser = await req.db.updateUser(req, res);
+ res
+ .status(200)
+ .json({ success: true, msg: "User updated", data: updatedUser });
+ } catch (error) {
+ error.service = SERVICE_NAME;
+ next(error);
+ return;
+ }
+};
+
+module.exports = { registerController, loginController, userEditController };
diff --git a/Server/db/MongoDB.js b/Server/db/MongoDB.js
index f7f790e86..a4c9422a3 100644
--- a/Server/db/MongoDB.js
+++ b/Server/db/MongoDB.js
@@ -63,6 +63,31 @@ const getUserByEmail = async (req, res) => {
// Monitors
//****************************************
+/**
+ * Update a user by ID
+ * @async
+ * @param {Express.Request} req
+ * @param {Express.Response} res
+ * @returns {Promise}
+ * @throws {Error}
+ */
+
+const updateUser = async (req, res) => {
+ const candidateUserId = req.params.userId;
+ const candidateUser = req.body;
+
+ try {
+ const updatedUser = await UserModel.findByIdAndUpdate(
+ candidateUserId,
+ candidateUser,
+ { new: true } // Returns updated user instead of pre-update user
+ ).select("-password");
+ return updatedUser;
+ } catch (error) {
+ throw error;
+ }
+};
+
/**
* Get all monitors
* @async
@@ -244,6 +269,7 @@ module.exports = {
connect,
insertUser,
getUserByEmail,
+ updateUser,
getAllMonitors,
getMonitorById,
getMonitorsByUserId,
diff --git a/Server/index.js b/Server/index.js
index 67813051e..1596e0862 100644
--- a/Server/index.js
+++ b/Server/index.js
@@ -65,12 +65,6 @@ app.use("/api/v1/auth", authRouter);
app.use("/api/v1/monitors", verifyJWT, monitorRouter);
app.use("/api/v1/checks", verifyJWT, checkRouter);
-/**
- * Error handler middleware
- * MUST be called after all routes
- */
-app.use(handleErrors);
-
// Testing email service
// app.use('/sendEmail', async (req, res) => {
// const response = sendEmail(['veysel.boybay@bluewavelabs.ca'], 'Testing email service', 'Testing Bluewavelabs
');
@@ -88,4 +82,10 @@ app.use("/api/v1/healthy", (req, res) => {
}
});
+/**
+ * Error handler middleware
+ * Should be called last
+ */
+app.use(handleErrors);
+
connectDbAndRunServer(app, db);
diff --git a/Server/middleware/handleErrors.js b/Server/middleware/handleErrors.js
index 78764c1e1..a20db8571 100644
--- a/Server/middleware/handleErrors.js
+++ b/Server/middleware/handleErrors.js
@@ -3,7 +3,7 @@ const logger = require("../utils/logger");
const handleErrors = (error, req, res, next) => {
const status = error.status || 500;
const message = error.message || "Something went wrong";
- const service = error.errorService || "Unknown service";
+ const service = error.service || "Unknown service";
logger.error(error.message, { service: service });
res.status(status).json({ success: false, msg: message });
diff --git a/Server/middleware/verifyOwnership.js b/Server/middleware/verifyOwnership.js
index 00f7b0787..409303fa4 100644
--- a/Server/middleware/verifyOwnership.js
+++ b/Server/middleware/verifyOwnership.js
@@ -19,6 +19,7 @@ const verifyOwnership = (Model, paramName) => {
// If the userID does not match the document's userID, return a 403 error
if (userId.toString() !== doc.userId.toString()) {
+ console.log("boom");
const error = new Error("Unauthorized access");
error.status = 403;
throw error;
diff --git a/Server/models/user.js b/Server/models/user.js
index d90b484bb..7f3945354 100644
--- a/Server/models/user.js
+++ b/Server/models/user.js
@@ -1,44 +1,41 @@
const mongoose = require("mongoose");
const bcrypt = require("bcrypt");
-const UserSchema = mongoose.Schema({
- firstname: {
- type: String,
- required: true,
+const UserSchema = mongoose.Schema(
+ {
+ firstname: {
+ type: String,
+ required: true,
+ },
+ lastname: {
+ type: String,
+ required: true,
+ },
+ email: {
+ type: String,
+ required: true,
+ unique: true,
+ },
+ password: {
+ type: String,
+ required: true,
+ },
+ profilePicUrl: {
+ type: String,
+ },
+ isActive: {
+ type: Boolean,
+ default: true,
+ },
+ isVerified: {
+ type: Boolean,
+ default: false,
+ },
},
- lastname: {
- type: String,
- required: true,
- },
- email: {
- type: String,
- required: true,
- unique: true,
- },
- password: {
- type: String,
- required: true,
- },
- profilePicUrl: {
- type: String,
- },
- isActive: {
- type: Boolean,
- default: true,
- },
- isVerified: {
- type: Boolean,
- default: false,
- },
- updated_at: {
- type: Date,
- default: Date.now,
- },
- created_at: {
- type: Date,
- default: Date.now,
- },
-});
+ {
+ timestamps: true,
+ }
+);
UserSchema.pre("save", async function (next) {
if (!this.isModified("password")) {
diff --git a/Server/routes/authRoute.js b/Server/routes/authRoute.js
index 48a173b92..637e4bf5e 100644
--- a/Server/routes/authRoute.js
+++ b/Server/routes/authRoute.js
@@ -1,10 +1,14 @@
const router = require("express").Router();
+const { verifyJWT } = require("../middleware/verifyJWT");
+
const {
registerController,
loginController,
+ userEditController,
} = require("../controllers/authController");
router.post("/register", registerController);
router.post("/login", loginController);
+router.post("/user/:userId", verifyJWT, userEditController);
module.exports = router;
diff --git a/Server/validation/joi.js b/Server/validation/joi.js
index ecc19253e..399c243dc 100644
--- a/Server/validation/joi.js
+++ b/Server/validation/joi.js
@@ -1,5 +1,4 @@
const joi = require("joi");
-const user = require("../models/user");
const loginValidation = joi.object({
email: joi.string().email().required(),
@@ -30,10 +29,22 @@ const monitorValidation = joi.object({
interval: joi.number(),
});
+const editUserParamValidation = joi.object({
+ userId: joi.string().required(),
+});
+
+const editUserBodyValidation = joi.object({
+ firstname: joi.string(),
+ lastname: joi.string(),
+ profilePicUrl: joi.string(),
+});
+
module.exports = {
loginValidation,
registerValidation,
getMonitorByIdValidation,
getMonitorsByUserIdValidation,
monitorValidation,
+ editUserParamValidation,
+ editUserBodyValidation,
};