From ceb8985afbd3c4a6a8b3cec6f7ee972828edd06c Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 17 Aug 2024 09:35:50 -0700 Subject: [PATCH 01/11] Refactored uptimeMonitorsSlice axios requests --- .../UptimeMonitors/uptimeMonitorsSlice.js | 80 +++---------------- Client/src/Utils/axiosConfig.js | 51 ++++++++++++ 2 files changed, 64 insertions(+), 67 deletions(-) diff --git a/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js b/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js index 27d616e1e..1e8b895a1 100644 --- a/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js +++ b/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js @@ -13,32 +13,7 @@ export const createUptimeMonitor = createAsyncThunk( async (data, thunkApi) => { try { const { authToken, monitor } = data; - - const res = await axiosInstance.post(`/monitors`, monitor, { - headers: { - Authorization: `Bearer ${authToken}`, - "Content-Type": "application/json", - }, - }); - return res.data; - } catch (error) { - if (error.response && error.response.data) { - return thunkApi.rejectWithValue(error.response.data); - } - const payload = { - status: false, - msg: error.message ? error.message : "Unknown error", - }; - return thunkApi.rejectWithValue(payload); - } - } -); - -export const getUptimeMonitors = createAsyncThunk( - "monitors/getMonitors", - async (token, thunkApi) => { - try { - const res = await axiosInstance.get("/monitors"); + const res = await axiosInstance.createMonitor(authToken, monitor); return res.data; } catch (error) { if (error.response && error.response.data) { @@ -58,13 +33,13 @@ export const getUptimeMonitorsByUserId = createAsyncThunk( async (token, thunkApi) => { const user = jwtDecode(token); try { - const res = await axiosInstance.get( - `/monitors/user/${user._id}?limit=25&type=http&type=ping&sortOrder=desc&normalize=true`, - { - headers: { - Authorization: `Bearer ${token}`, - }, - } + const res = await axiosInstance.getMonitorsByUserId( + token, + user._id, + 25, + ["http", "ping"], + "desc", + true ); return res.data; } catch (error) { @@ -91,15 +66,10 @@ export const updateUptimeMonitor = createAsyncThunk( interval: monitor.interval, notifications: monitor.notifications, }; - const res = await axiosInstance.put( - `/monitors/${monitor._id}`, - updatedFields, - { - headers: { - Authorization: `Bearer ${authToken}`, - "Content-Type": "application/json", - }, - } + const res = await axiosInstance.updateMonitor( + authToken, + monitor._id, + updatedFields ); return res.data; } catch (error) { @@ -120,12 +90,7 @@ export const deleteUptimeMonitor = createAsyncThunk( async (data, thunkApi) => { try { const { authToken, monitor } = data; - const res = await axiosInstance.delete(`/monitors/${monitor._id}`, { - headers: { - Authorization: `Bearer ${authToken}`, - "Content-Type": "application/json", - }, - }); + const res = await axiosInstance.deleteMonitorById(authToken, monitor._id); return res.data; } catch (error) { if (error.response && error.response.data) { @@ -153,25 +118,6 @@ const uptimeMonitorsSlice = createSlice({ }, extraReducers: (builder) => { builder - // ***************************************************** - // All Monitors - // ***************************************************** - .addCase(getUptimeMonitors.pending, (state) => { - state.isLoading = true; - }) - .addCase(getUptimeMonitors.fulfilled, (state, action) => { - state.isLoading = false; - state.success = action.payload.success; - state.msg = action.payload.msg; - state.monitors = action.payload.data; - }) - .addCase(getUptimeMonitors.rejected, (state, action) => { - state.isLoading = false; - state.success = false; - state.msg = action.payload - ? action.payload.msg - : "Getting uptime monitors failed"; - }) // ***************************************************** // Monitors by userId // ***************************************************** diff --git a/Client/src/Utils/axiosConfig.js b/Client/src/Utils/axiosConfig.js index 8d3040028..ca895709a 100644 --- a/Client/src/Utils/axiosConfig.js +++ b/Client/src/Utils/axiosConfig.js @@ -24,4 +24,55 @@ axiosInstance.interceptors.response.use( } ); +// Create a new monitor +axiosInstance.createMonitor = async (authToken, monitor) => { + return axiosInstance.post(`/monitors`, monitor, { + headers: { + Authorization: `Bearer ${authToken}`, + "Content-Type": "application/json", + }, + }); +}; + +// Get all uptime monitors for a user +axiosInstance.getMonitorsByUserId = async ( + authToken, + userId, + limit, + types, + sortOrder, + normalize +) => { + const typeQuery = types.reduce((acc, type) => acc + `&type=${type}`, ""); + return axiosInstance.get( + `/monitors/user/${userId}?limit=${limit}${typeQuery}&sortOrder=${sortOrder}&normalize=${normalize}`, + { + headers: { + Authorization: `Bearer ${authToken}`, + "Content-Type": "application/json", + }, + } + ); +}; + +// Updates a single monitor +axiosInstance.updateMonitor = async (authToken, monitorId, updatedFields) => { + return axiosInstance.put(`/monitors/${monitorId}`, updatedFields, { + headers: { + Authorization: `Bearer ${authToken}`, + "Content-Type": "application/json", + }, + }); +}; + +// Deletes a single monitor +axiosInstance.deleteMonitorById = async (authToken, monitorId) => { + return axiosInstance.delete(`/monitors/${monitorId}`, { + headers: { + Authorization: `Bearer ${authToken}`, + "Content-Type": "application/json", + }, + }); +}; + export default axiosInstance; From 10fceb6ff1aaa78e4f4446e80abd608169d5aac9 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 17 Aug 2024 09:50:52 -0700 Subject: [PATCH 02/11] refactord pagespeed slice --- .../PageSpeedMonitor/pageSpeedMonitorSlice.js | 81 ++++--------------- Client/src/Utils/axiosConfig.js | 27 ++++--- 2 files changed, 31 insertions(+), 77 deletions(-) diff --git a/Client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js b/Client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js index 6af825a37..9b3e7fa8c 100644 --- a/Client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js +++ b/Client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js @@ -13,32 +13,7 @@ export const createPageSpeed = createAsyncThunk( async (data, thunkApi) => { try { const { authToken, monitor } = data; - - const res = await axiosInstance.post(`/monitors`, monitor, { - headers: { - Authorization: `Bearer ${authToken}`, - "Content-Type": "application/json", - }, - }); - return res.data; - } catch (error) { - if (error.response && error.response.data) { - return thunkApi.rejectWithValue(error.response.data); - } - const payload = { - status: false, - msg: error.message ? error.message : "Unknown error", - }; - return thunkApi.rejectWithValue(payload); - } - } -); - -export const getPageSpeedMonitors = createAsyncThunk( - "pageSpeedMonitors/getPageSpeedMonitors", - async (token, thunkApi) => { - try { - const res = await axiosInstance.get("/monitors"); + const res = await axiosInstance.createMonitor(authToken, monitor); return res.data; } catch (error) { if (error.response && error.response.data) { @@ -58,14 +33,15 @@ export const getPageSpeedByUserId = createAsyncThunk( async (token, thunkApi) => { const user = jwtDecode(token); try { - const res = await axiosInstance.get( - `/monitors/user/${user._id}?limit=25&type=pagespeed&sortOrder=desc`, - { - headers: { - Authorization: `Bearer ${token}`, - }, - } + const res = await axiosInstance.getMonitorsByUserId( + token, + user._id, + 25, + ["pagespeed"], + "desc", + false ); + return res.data; } catch (error) { if (error.response && error.response.data) { @@ -91,15 +67,10 @@ export const updatePageSpeed = createAsyncThunk( interval: monitor.interval, // notifications: monitor.notifications, }; - const res = await axiosInstance.put( - `/monitors/${monitor._id}`, - updatedFields, - { - headers: { - Authorization: `Bearer ${authToken}`, - "Content-Type": "application/json", - }, - } + const res = await axiosInstance.updateMonitor( + authToken, + monitor._id, + updatedFields ); return res.data; } catch (error) { @@ -120,12 +91,7 @@ export const deletePageSpeed = createAsyncThunk( async (data, thunkApi) => { try { const { authToken, monitor } = data; - const res = await axiosInstance.delete(`/monitors/${monitor._id}`, { - headers: { - Authorization: `Bearer ${authToken}`, - "Content-Type": "application/json", - }, - }); + const res = await axiosInstance.deleteMonitorById(authToken, monitor._id); return res.data; } catch (error) { if (error.response && error.response.data) { @@ -153,25 +119,6 @@ const pageSpeedMonitorSlice = createSlice({ }, extraReducers: (builder) => { builder - // ***************************************************** - // All Monitors - // ***************************************************** - .addCase(getPageSpeedMonitors.pending, (state) => { - state.isLoading = true; - }) - .addCase(getPageSpeedMonitors.fulfilled, (state, action) => { - state.isLoading = false; - state.success = action.payload.success; - state.msg = action.payload.msg; - state.monitors = action.payload.data; - }) - .addCase(getPageSpeedMonitors.rejected, (state, action) => { - state.isLoading = false; - state.success = false; - state.msg = action.payload - ? action.payload.msg - : "Getting montiors failed"; - }) // ***************************************************** // Monitors by userId // ***************************************************** diff --git a/Client/src/Utils/axiosConfig.js b/Client/src/Utils/axiosConfig.js index ca895709a..1d15c8ce1 100644 --- a/Client/src/Utils/axiosConfig.js +++ b/Client/src/Utils/axiosConfig.js @@ -43,16 +43,23 @@ axiosInstance.getMonitorsByUserId = async ( sortOrder, normalize ) => { - const typeQuery = types.reduce((acc, type) => acc + `&type=${type}`, ""); - return axiosInstance.get( - `/monitors/user/${userId}?limit=${limit}${typeQuery}&sortOrder=${sortOrder}&normalize=${normalize}`, - { - headers: { - Authorization: `Bearer ${authToken}`, - "Content-Type": "application/json", - }, - } - ); + const params = new URLSearchParams(); + + if (limit) params.append("limit", limit); + if (types) { + types.forEach((type) => { + params.append("type", type); + }); + } + if (sortOrder) params.append("sortOrder", sortOrder); + if (normalize) params.append("normalize", normalize); + + return axiosInstance.get(`/monitors/user/${userId}?${params.toString()}`, { + headers: { + Authorization: `Bearer ${authToken}`, + "Content-Type": "application/json", + }, + }); }; // Updates a single monitor From 41f975cdfa727564d0c2dc7e8892441f3840b492 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 17 Aug 2024 12:55:57 -0700 Subject: [PATCH 03/11] Add comment formatting --- Client/src/Utils/axiosConfig.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Client/src/Utils/axiosConfig.js b/Client/src/Utils/axiosConfig.js index 1d15c8ce1..5cbfc9e06 100644 --- a/Client/src/Utils/axiosConfig.js +++ b/Client/src/Utils/axiosConfig.js @@ -24,7 +24,9 @@ axiosInstance.interceptors.response.use( } ); +// ********************************** // Create a new monitor +// ********************************** axiosInstance.createMonitor = async (authToken, monitor) => { return axiosInstance.post(`/monitors`, monitor, { headers: { @@ -34,7 +36,9 @@ axiosInstance.createMonitor = async (authToken, monitor) => { }); }; +// ********************************** // Get all uptime monitors for a user +// ********************************** axiosInstance.getMonitorsByUserId = async ( authToken, userId, @@ -62,7 +66,9 @@ axiosInstance.getMonitorsByUserId = async ( }); }; +// ********************************** // Updates a single monitor +// ********************************** axiosInstance.updateMonitor = async (authToken, monitorId, updatedFields) => { return axiosInstance.put(`/monitors/${monitorId}`, updatedFields, { headers: { @@ -72,7 +78,9 @@ axiosInstance.updateMonitor = async (authToken, monitorId, updatedFields) => { }); }; +// ********************************** // Deletes a single monitor +// ********************************** axiosInstance.deleteMonitorById = async (authToken, monitorId) => { return axiosInstance.delete(`/monitors/${monitorId}`, { headers: { From 46bd31776081511b791100dd5726f5a63840dc2a Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 17 Aug 2024 13:03:24 -0700 Subject: [PATCH 04/11] Refactor register and login thunks --- Client/src/Features/Auth/authSlice.js | 4 ++-- Client/src/Utils/axiosConfig.js | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Client/src/Features/Auth/authSlice.js b/Client/src/Features/Auth/authSlice.js index 6da315fc4..e51d427ab 100644 --- a/Client/src/Features/Auth/authSlice.js +++ b/Client/src/Features/Auth/authSlice.js @@ -14,7 +14,7 @@ export const register = createAsyncThunk( "auth/register", async (form, thunkApi) => { try { - const res = await axiosInstance.post("/auth/register", form); + const res = await axiosInstance.registerUser(form); return res.data; } catch (error) { if (error.response.data) { @@ -31,7 +31,7 @@ export const register = createAsyncThunk( export const login = createAsyncThunk("auth/login", async (form, thunkApi) => { try { - const res = await axiosInstance.post(`/auth/login`, form); + const res = await axiosInstance.loginUser(form); return res.data; } catch (error) { if (error.response && error.response.data) { diff --git a/Client/src/Utils/axiosConfig.js b/Client/src/Utils/axiosConfig.js index 5cbfc9e06..518af41e1 100644 --- a/Client/src/Utils/axiosConfig.js +++ b/Client/src/Utils/axiosConfig.js @@ -90,4 +90,18 @@ axiosInstance.deleteMonitorById = async (authToken, monitorId) => { }); }; +// ********************************** +// Register a new user +// ********************************** +axiosInstance.registerUser = async (form) => { + return axiosInstance.post(`/auth/register`, form); +}; + +// ********************************** +// Log in an exisiting user +// ********************************** +axiosInstance.loginUser = async (form) => { + return axiosInstance.post(`/auth/login`, form); +}; + export default axiosInstance; From 6d99002fd172875949579ed0dbc727896c8f1cf5 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 17 Aug 2024 20:23:34 -0700 Subject: [PATCH 05/11] Finish refactoring auth slice, fixed several bugs --- Client/src/Features/Auth/authSlice.js | 26 +++---------- Client/src/Utils/axiosConfig.js | 47 +++++++++++++++++++++++ Server/controllers/authController.js | 3 ++ Server/db/mongo/modules/monitorModule.js | 2 +- Server/db/mongo/modules/recoveryModule.js | 1 + Server/index.js | 2 +- 6 files changed, 59 insertions(+), 22 deletions(-) diff --git a/Client/src/Features/Auth/authSlice.js b/Client/src/Features/Auth/authSlice.js index e51d427ab..070cc3eb3 100644 --- a/Client/src/Features/Auth/authSlice.js +++ b/Client/src/Features/Auth/authSlice.js @@ -51,9 +51,6 @@ export const update = createAsyncThunk( const { authToken: token, localData: form } = data; const user = jwtDecode(token); try { - //1.5s delay to show loading spinner - await new Promise((resolve) => setTimeout(resolve, 1500)); - const fd = new FormData(); form.firstName && fd.append("firstName", form.firstName); form.lastName && fd.append("lastName", form.lastName); @@ -69,12 +66,8 @@ export const update = createAsyncThunk( form.deleteProfileImage && fd.append("deleteProfileImage", form.deleteProfileImage); - const res = await axiosInstance.put(`/auth/user/${user._id}`, fd, { - headers: { - Authorization: `Bearer ${token}`, - "Content-Type": "multipart/form-data", - }, - }); + const res = await axiosInstance.updateUser(token, user._id, fd); + return res.data; } catch (error) { if (error.response && error.response.data) { @@ -95,9 +88,7 @@ export const deleteUser = createAsyncThunk( const user = jwtDecode(data); try { - const res = await axiosInstance.delete(`/auth/user/${user._id}`, { - headers: { Authorization: `Bearer ${data}` }, - }); + const res = await axiosInstance.deleteUser(data, user._id); return res.data; } catch (error) { if (error.response && error.response.data) { @@ -116,7 +107,7 @@ export const forgotPassword = createAsyncThunk( "auth/forgotPassword", async (form, thunkApi) => { try { - const res = await axiosInstance.post("/auth/recovery/request", form); + const res = await axiosInstance.forgotPassword(form); return res.data; } catch (error) { if (error.response.data) { @@ -136,13 +127,8 @@ export const setNewPassword = createAsyncThunk( async (data, thunkApi) => { const { token, form } = data; try { - await axiosInstance.post("/auth/recovery/validate", { - recoveryToken: token, - }); - const res = await axiosInstance.post("/auth/recovery/reset", { - ...form, - recoveryToken: token, - }); + await axiosInstance.validateRecoveryToken(token); + const res = await axiosInstance.setNewPassword(token, form); return res.data; } catch (error) { if (error.response.data) { diff --git a/Client/src/Utils/axiosConfig.js b/Client/src/Utils/axiosConfig.js index 518af41e1..093210f90 100644 --- a/Client/src/Utils/axiosConfig.js +++ b/Client/src/Utils/axiosConfig.js @@ -104,4 +104,51 @@ axiosInstance.loginUser = async (form) => { return axiosInstance.post(`/auth/login`, form); }; +// ********************************** +// Update in an exisiting user +// ********************************** +axiosInstance.updateUser = async (authToken, userId, form) => { + return axiosInstance.put(`/auth/user/${userId}`, form, { + headers: { + Authorization: `Bearer ${authToken}`, + "Content-Type": "application/json", + }, + }); +}; + +// ********************************** +// Delete an exisiting user +// ********************************** +axiosInstance.deleteUser = async (authToken, userId) => { + return axiosInstance.delete(`/auth/user/${userId}`, { + headers: { + Authorization: `Bearer ${authToken}`, + "Content-Type": "application/json", + }, + }); +}; + +// ********************************** +// Forgot password request +// ********************************** +axiosInstance.forgotPassword = async (form) => { + return axiosInstance.post(`/auth/recovery/request`, form); +}; + +axiosInstance.validateRecoveryToken = async (recoveryToken) => { + return axiosInstance.post("/auth/recovery/validate", { + recoveryToken, + }); +}; + +// ********************************** +// Set new password request +// ********************************** +axiosInstance.setNewPassword = async (recoveryToken, form) => { + return axiosInstance.post("/auth/recovery/reset", { + ...form, + recoveryToken, + }); +}; + export default axiosInstance; diff --git a/Server/controllers/authController.js b/Server/controllers/authController.js index 93c83c6b8..8efe2ae19 100644 --- a/Server/controllers/authController.js +++ b/Server/controllers/authController.js @@ -450,6 +450,8 @@ const deleteUserController = async (req, res, next) => { } // 1. Find all the monitors associated with the user id + console.log("wtf"); + const monitors = await req.db.getMonitorsByUserId({ params: { userId: _id }, }); @@ -459,6 +461,7 @@ const deleteUserController = async (req, res, next) => { await Promise.all( monitors.map(async (monitor) => { await req.jobQueue.deleteJob(monitor); + await req.db.deleteChecks(monitor._id); await req.db.deleteAlertByMonitorId(monitor._id); await req.db.deletePageSpeedChecksByMonitorId(monitor._id); diff --git a/Server/db/mongo/modules/monitorModule.js b/Server/db/mongo/modules/monitorModule.js index 0fc56c755..4d84700ca 100644 --- a/Server/db/mongo/modules/monitorModule.js +++ b/Server/db/mongo/modules/monitorModule.js @@ -294,7 +294,7 @@ const getMonitorById = async (monitorId) => { */ const getMonitorsByUserId = async (req, res) => { try { - let { limit, type, status, sortOrder, normalize } = req.query; + let { limit, type, status, sortOrder, normalize } = req.query || {}; const monitorQuery = { userId: req.params.userId }; if (type !== undefined) { diff --git a/Server/db/mongo/modules/recoveryModule.js b/Server/db/mongo/modules/recoveryModule.js index c1cc23b94..b643a1664 100644 --- a/Server/db/mongo/modules/recoveryModule.js +++ b/Server/db/mongo/modules/recoveryModule.js @@ -1,3 +1,4 @@ +const UserModel = require("../../../models/user"); const RecoveryToken = require("../../../models/RecoveryToken"); const crypto = require("crypto"); const { errorMessages } = require("../../../utils/messages"); diff --git a/Server/index.js b/Server/index.js index 2cb941ed4..9a5f1797f 100644 --- a/Server/index.js +++ b/Server/index.js @@ -19,7 +19,7 @@ const JobQueue = require("./service/jobQueue"); const NetworkService = require("./service/networkService"); const EmailService = require("./service/emailService"); const PageSpeedService = require("./service/pageSpeedService"); - +const SERVICE_NAME = "Server"; let cleaningUp = false; // Need to wrap server setup in a function to handle async nature of JobQueue From 5beb0684a7aaa668c9215380b8cdf9a610a656f5 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sun, 18 Aug 2024 12:11:24 -0700 Subject: [PATCH 06/11] Renamed axiosConfig to NetworkService --- Client/src/Components/TabPanels/Account/TeamPanel.jsx | 2 +- Client/src/Features/Auth/authSlice.js | 2 +- Client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js | 2 +- Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js | 2 +- Client/src/HOC/withAdminCheck.jsx | 2 +- Client/src/Pages/Auth/Login.jsx | 2 +- Client/src/Pages/Auth/Register/Register.jsx | 2 +- Client/src/Pages/Incidents/IncidentTable/index.jsx | 2 +- Client/src/Pages/Incidents/index.jsx | 2 +- Client/src/Pages/Monitors/Details/PaginationTable/index.jsx | 2 +- Client/src/Pages/Monitors/Details/index.jsx | 2 +- Client/src/Pages/PageSpeed/Details/index.jsx | 2 +- Client/src/Utils/{axiosConfig.js => NetworkService.js} | 0 Client/src/main.jsx | 2 +- 14 files changed, 13 insertions(+), 13 deletions(-) rename Client/src/Utils/{axiosConfig.js => NetworkService.js} (100%) diff --git a/Client/src/Components/TabPanels/Account/TeamPanel.jsx b/Client/src/Components/TabPanels/Account/TeamPanel.jsx index 07bbf6e68..553397f89 100644 --- a/Client/src/Components/TabPanels/Account/TeamPanel.jsx +++ b/Client/src/Components/TabPanels/Account/TeamPanel.jsx @@ -16,7 +16,7 @@ import { useEffect, useState } from "react"; import EditSvg from "../../../assets/icons/edit.svg?react"; import Field from "../../Inputs/Field"; import { credentials } from "../../../Validation/validation"; -import axiosInstance from "../../../Utils/axiosConfig"; +import axiosInstance from "../../../Utils/NetworkService"; import { createToast } from "../../../Utils/toastUtils"; import { useSelector } from "react-redux"; import BasicTable from "../../BasicTable"; diff --git a/Client/src/Features/Auth/authSlice.js b/Client/src/Features/Auth/authSlice.js index 070cc3eb3..9994c2bbb 100644 --- a/Client/src/Features/Auth/authSlice.js +++ b/Client/src/Features/Auth/authSlice.js @@ -1,4 +1,4 @@ -import axiosInstance from "../../Utils/axiosConfig"; +import axiosInstance from "../../Utils/NetworkService"; import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; import { jwtDecode } from "jwt-decode"; diff --git a/Client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js b/Client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js index 9b3e7fa8c..1e75782d0 100644 --- a/Client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js +++ b/Client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js @@ -1,6 +1,6 @@ import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; import { jwtDecode } from "jwt-decode"; -import axiosInstance from "../../Utils/axiosConfig"; +import axiosInstance from "../../Utils/NetworkService"; const initialState = { isLoading: false, monitors: [], diff --git a/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js b/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js index 1e8b895a1..076002259 100644 --- a/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js +++ b/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js @@ -1,6 +1,6 @@ import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; import { jwtDecode } from "jwt-decode"; -import axiosInstance from "../../Utils/axiosConfig"; +import axiosInstance from "../../Utils/NetworkService"; const initialState = { isLoading: false, monitors: [], diff --git a/Client/src/HOC/withAdminCheck.jsx b/Client/src/HOC/withAdminCheck.jsx index 23ee5dc1f..60c0ea088 100644 --- a/Client/src/HOC/withAdminCheck.jsx +++ b/Client/src/HOC/withAdminCheck.jsx @@ -1,6 +1,6 @@ import React, { useEffect } from "react"; import { useNavigate } from "react-router-dom"; -import axiosInstance from "../Utils/axiosConfig"; +import axiosInstance from "../Utils/NetworkService"; const withAdminCheck = (WrappedComponent) => { const WithAdminCheck = (props) => { diff --git a/Client/src/Pages/Auth/Login.jsx b/Client/src/Pages/Auth/Login.jsx index 84f6c518e..d1f251925 100644 --- a/Client/src/Pages/Auth/Login.jsx +++ b/Client/src/Pages/Auth/Login.jsx @@ -7,7 +7,7 @@ import { login } from "../../Features/Auth/authSlice"; import { useDispatch } from "react-redux"; import { createToast } from "../../Utils/toastUtils"; import Button from "../../Components/Button"; -import axiosInstance from "../../Utils/axiosConfig"; +import axiosInstance from "../../Utils/NetworkService"; import Field from "../../Components/Inputs/Field"; import background from "../../assets/Images/background_pattern_decorative.png"; import Logo from "../../assets/icons/bwu-icon.svg?react"; diff --git a/Client/src/Pages/Auth/Register/Register.jsx b/Client/src/Pages/Auth/Register/Register.jsx index 30b439f16..8a4c57f0e 100644 --- a/Client/src/Pages/Auth/Register/Register.jsx +++ b/Client/src/Pages/Auth/Register/Register.jsx @@ -15,7 +15,7 @@ import ArrowBackRoundedIcon from "@mui/icons-material/ArrowBackRounded"; import Check from "../../../Components/Check/Check"; import Button from "../../../Components/Button"; import Field from "../../../Components/Inputs/Field"; -import axiosInstance from "../../../Utils/axiosConfig"; +import axiosInstance from "../../../Utils/NetworkService"; import "../index.css"; /** diff --git a/Client/src/Pages/Incidents/IncidentTable/index.jsx b/Client/src/Pages/Incidents/IncidentTable/index.jsx index 44a30decc..b60bb14f5 100644 --- a/Client/src/Pages/Incidents/IncidentTable/index.jsx +++ b/Client/src/Pages/Incidents/IncidentTable/index.jsx @@ -18,7 +18,7 @@ import ArrowForwardRoundedIcon from "@mui/icons-material/ArrowForwardRounded"; import { useState, useEffect } from "react"; import { useSelector } from "react-redux"; -import axiosInstance from "../../../Utils/axiosConfig"; +import axiosInstance from "../../../Utils/NetworkService"; import { StatusLabel } from "../../../Components/Label"; const IncidentTable = ({ monitors, selectedMonitor, filter }) => { diff --git a/Client/src/Pages/Incidents/index.jsx b/Client/src/Pages/Incidents/index.jsx index f9d53f7c0..730d0c512 100644 --- a/Client/src/Pages/Incidents/index.jsx +++ b/Client/src/Pages/Incidents/index.jsx @@ -2,7 +2,7 @@ import { useState, useEffect } from "react"; import { useSelector } from "react-redux"; import { ButtonGroup, Stack, Skeleton, Typography } from "@mui/material"; import Button from "../../Components/Button"; -import axiosInstance from "../../Utils/axiosConfig"; +import axiosInstance from "../../Utils/NetworkService"; import { useTheme } from "@emotion/react"; import Select from "../../Components/Inputs/Select"; import IncidentTable from "./IncidentTable"; diff --git a/Client/src/Pages/Monitors/Details/PaginationTable/index.jsx b/Client/src/Pages/Monitors/Details/PaginationTable/index.jsx index 28a668977..6127bbe3e 100644 --- a/Client/src/Pages/Monitors/Details/PaginationTable/index.jsx +++ b/Client/src/Pages/Monitors/Details/PaginationTable/index.jsx @@ -13,7 +13,7 @@ import { import { useState, useEffect } from "react"; import { useSelector } from "react-redux"; -import axiosInstance from "../../../../Utils/axiosConfig"; +import axiosInstance from "../../../../Utils/NetworkService"; import { StatusLabel } from "../../../../Components/Label"; import ArrowBackRoundedIcon from "@mui/icons-material/ArrowBackRounded"; import ArrowForwardRoundedIcon from "@mui/icons-material/ArrowForwardRounded"; diff --git a/Client/src/Pages/Monitors/Details/index.jsx b/Client/src/Pages/Monitors/Details/index.jsx index 15cfd2c82..6c23f4a03 100644 --- a/Client/src/Pages/Monitors/Details/index.jsx +++ b/Client/src/Pages/Monitors/Details/index.jsx @@ -3,7 +3,7 @@ import PropTypes from "prop-types"; import { Box, Skeleton, Stack, Typography, useTheme } from "@mui/material"; import { useSelector } from "react-redux"; import { useNavigate, useParams } from "react-router-dom"; -import axiosInstance from "../../../Utils/axiosConfig"; +import axiosInstance from "../../../Utils/NetworkService"; import MonitorDetailsAreaChart from "../../../Components/Charts/MonitorDetailsAreaChart"; import ButtonGroup from "@mui/material/ButtonGroup"; import Button from "../../../Components/Button"; diff --git a/Client/src/Pages/PageSpeed/Details/index.jsx b/Client/src/Pages/PageSpeed/Details/index.jsx index 006f2acf3..c63ad9a86 100644 --- a/Client/src/Pages/PageSpeed/Details/index.jsx +++ b/Client/src/Pages/PageSpeed/Details/index.jsx @@ -9,7 +9,7 @@ import { formatDuration, formatDurationRounded, } from "../../../Utils/timeUtils"; -import axiosInstance from "../../../Utils/axiosConfig"; +import axiosInstance from "../../../Utils/NetworkService"; import Button from "../../../Components/Button"; import WestRoundedIcon from "@mui/icons-material/WestRounded"; import SettingsIcon from "../../../assets/icons/settings-bold.svg?react"; diff --git a/Client/src/Utils/axiosConfig.js b/Client/src/Utils/NetworkService.js similarity index 100% rename from Client/src/Utils/axiosConfig.js rename to Client/src/Utils/NetworkService.js diff --git a/Client/src/main.jsx b/Client/src/main.jsx index f9fa3d640..387d1f931 100644 --- a/Client/src/main.jsx +++ b/Client/src/main.jsx @@ -8,7 +8,7 @@ import { ThemeProvider } from "@mui/material"; import { Provider } from "react-redux"; import { persistor, store } from "./store"; import { PersistGate } from "redux-persist/integration/react"; -import { injectStore } from "./Utils/axiosConfig.js"; +import { injectStore } from "./Utils/NetworkService.js"; injectStore(store); From f78e5ca94cdaf26c2e108f02a760103f7002fa78 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sun, 18 Aug 2024 12:20:28 -0700 Subject: [PATCH 07/11] Add several endpoints --- .../TabPanels/Account/TeamPanel.jsx | 5 +--- Client/src/HOC/withAdminCheck.jsx | 2 +- Client/src/Pages/Auth/Login.jsx | 2 +- Client/src/Pages/Auth/Register/Register.jsx | 4 +-- Client/src/Utils/NetworkService.js | 25 +++++++++++++++++++ 5 files changed, 29 insertions(+), 9 deletions(-) diff --git a/Client/src/Components/TabPanels/Account/TeamPanel.jsx b/Client/src/Components/TabPanels/Account/TeamPanel.jsx index 553397f89..3ff948a26 100644 --- a/Client/src/Components/TabPanels/Account/TeamPanel.jsx +++ b/Client/src/Components/TabPanels/Account/TeamPanel.jsx @@ -52,10 +52,7 @@ const TeamPanel = () => { useEffect(() => { const fetchTeam = async () => { try { - const response = await axiosInstance.get("/auth/users", { - headers: { Authorization: `Bearer ${authToken}` }, - }); - + const response = await axiosInstance.getAllUsers(authToken); setMembers(response.data.data); } catch (error) { createToast({ diff --git a/Client/src/HOC/withAdminCheck.jsx b/Client/src/HOC/withAdminCheck.jsx index 60c0ea088..c6a939679 100644 --- a/Client/src/HOC/withAdminCheck.jsx +++ b/Client/src/HOC/withAdminCheck.jsx @@ -8,7 +8,7 @@ const withAdminCheck = (WrappedComponent) => { useEffect(() => { axiosInstance - .get("/auth/users/admin") + .doesAdminExist() .then((response) => { if (response.data.data === true) { navigate("/login"); diff --git a/Client/src/Pages/Auth/Login.jsx b/Client/src/Pages/Auth/Login.jsx index d1f251925..6a408c970 100644 --- a/Client/src/Pages/Auth/Login.jsx +++ b/Client/src/Pages/Auth/Login.jsx @@ -249,7 +249,7 @@ const Login = () => { useEffect(() => { axiosInstance - .get("/auth/users/admin") + .doesAdminExist() .then((response) => { if (response.data.data === false) { navigate("/register"); diff --git a/Client/src/Pages/Auth/Register/Register.jsx b/Client/src/Pages/Auth/Register/Register.jsx index 8a4c57f0e..1dedaa0f1 100644 --- a/Client/src/Pages/Auth/Register/Register.jsx +++ b/Client/src/Pages/Auth/Register/Register.jsx @@ -397,9 +397,7 @@ const Register = ({ isAdmin }) => { const fetchInvite = async () => { if (token !== undefined) { try { - const res = await axiosInstance.post(`/auth/invite/verify`, { - token, - }); + const res = await axiosInstance.verifyInvitationToken(token); const { role, email } = res.data.data; console.log(role); setForm({ ...form, email, role }); diff --git a/Client/src/Utils/NetworkService.js b/Client/src/Utils/NetworkService.js index 093210f90..58ef2951f 100644 --- a/Client/src/Utils/NetworkService.js +++ b/Client/src/Utils/NetworkService.js @@ -151,4 +151,29 @@ axiosInstance.setNewPassword = async (recoveryToken, form) => { }); }; +// ********************************** +// Check for admin user +// ********************************** +axiosInstance.doesAdminExist = async () => { + return axiosInstance.get("/auth/users/admin"); +}; + +// ********************************** +// Get all users +// ********************************** +axiosInstance.getAllUsers = async (authToken) => { + return axiosInstance.get("/auth/users", { + headers: { Authorization: `Bearer ${authToken}` }, + }); +}; + +// ********************************** +// Verify Invitation Token +// ********************************** +axiosInstance.verifyInvitationToken = async (token) => { + return axiosInstance.post(`/auth/invite/verify`, { + token, + }); +}; + export default axiosInstance; From 92877e20ec06694d35d3aa201541420270e3346b Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sun, 18 Aug 2024 17:18:16 -0700 Subject: [PATCH 08/11] Refactored remaining requests --- .../TabPanels/Account/TeamPanel.jsx | 11 +- .../PageSpeedMonitor/pageSpeedMonitorSlice.js | 1 + .../UptimeMonitors/uptimeMonitorsSlice.js | 1 + .../Pages/Incidents/IncidentTable/index.jsx | 31 +++-- Client/src/Pages/Incidents/index.jsx | 15 +-- .../Details/PaginationTable/index.jsx | 16 +-- Client/src/Pages/Monitors/Details/index.jsx | 26 ++-- Client/src/Pages/PageSpeed/Details/index.jsx | 16 +-- Client/src/Utils/NetworkService.js | 119 ++++++++++++++++-- Server/routes/checkRoute.js | 4 +- 10 files changed, 174 insertions(+), 66 deletions(-) diff --git a/Client/src/Components/TabPanels/Account/TeamPanel.jsx b/Client/src/Components/TabPanels/Account/TeamPanel.jsx index 3ff948a26..ab35a41d1 100644 --- a/Client/src/Components/TabPanels/Account/TeamPanel.jsx +++ b/Client/src/Components/TabPanels/Account/TeamPanel.jsx @@ -176,13 +176,10 @@ const TeamPanel = () => { setErrors((prev) => ({ ...prev, email: error.details[0].message })); } else try { - await axiosInstance.post( - "/auth/invite", - { - email: toInvite.email, - role: toInvite.role, - }, - { headers: { Authorization: `Bearer ${authToken}` } } + await axiosInstance.requestInvitationToken( + authToken, + toInvite.email, + toInvite.role ); closeInviteModal(); diff --git a/Client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js b/Client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js index 1e75782d0..d547e31fa 100644 --- a/Client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js +++ b/Client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js @@ -38,6 +38,7 @@ export const getPageSpeedByUserId = createAsyncThunk( user._id, 25, ["pagespeed"], + null, "desc", false ); diff --git a/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js b/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js index 076002259..d92116a9a 100644 --- a/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js +++ b/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js @@ -38,6 +38,7 @@ export const getUptimeMonitorsByUserId = createAsyncThunk( user._id, 25, ["http", "ping"], + null, "desc", true ); diff --git a/Client/src/Pages/Incidents/IncidentTable/index.jsx b/Client/src/Pages/Incidents/IncidentTable/index.jsx index b60bb14f5..971886551 100644 --- a/Client/src/Pages/Incidents/IncidentTable/index.jsx +++ b/Client/src/Pages/Incidents/IncidentTable/index.jsx @@ -43,17 +43,30 @@ const IncidentTable = ({ monitors, selectedMonitor, filter }) => { return; } try { - let url = `/checks/${selectedMonitor}?sortOrder=desc&filter=${filter}&page=${paginationController.page}&rowsPerPage=${paginationController.rowsPerPage}`; - + let res; if (selectedMonitor === "0") { - url = `/checks/user/${user._id}?sortOrder=desc&filter=${filter}&page=${paginationController.page}&rowsPerPage=${paginationController.rowsPerPage}`; + res = await axiosInstance.getChecksByUser( + authToken, + user._id, + "desc", + null, + null, + filter, + paginationController.page, + paginationController.rowsPerPage + ); + } else { + res = await axiosInstance.getChecksByMonitor( + authToken, + selectedMonitor, + "desc", + null, + null, + filter, + paginationController.page, + paginationController.rowsPerPage + ); } - - const res = await axiosInstance.get(url, { - headers: { - Authorization: `Bearer ${authToken}`, - }, - }); setChecks(res.data.data.checks); setChecksCount(res.data.data.checksCount); } catch (error) { diff --git a/Client/src/Pages/Incidents/index.jsx b/Client/src/Pages/Incidents/index.jsx index 730d0c512..3a50d3194 100644 --- a/Client/src/Pages/Incidents/index.jsx +++ b/Client/src/Pages/Incidents/index.jsx @@ -48,13 +48,14 @@ const Incidents = () => { useEffect(() => { const fetchMonitors = async () => { setLoading(true); - const res = await axiosInstance.get( - `/monitors/user/${authState.user._id}?status=false&limit=1`, - { - headers: { - Authorization: `Bearer ${authState.authToken}`, - }, - } + const res = await axiosInstance.getMonitorsByUserId( + authState.authToken, + authState.user._id, + 1, + null, + null, + null, + null ); // Reduce to a lookup object for 0(1) lookup diff --git a/Client/src/Pages/Monitors/Details/PaginationTable/index.jsx b/Client/src/Pages/Monitors/Details/PaginationTable/index.jsx index 6127bbe3e..2df061e82 100644 --- a/Client/src/Pages/Monitors/Details/PaginationTable/index.jsx +++ b/Client/src/Pages/Monitors/Details/PaginationTable/index.jsx @@ -37,13 +37,15 @@ const PaginationTable = ({ monitorId, dateRange }) => { useEffect(() => { const fetchPage = async () => { try { - const res = await axiosInstance.get( - `/checks/${monitorId}?sortOrder=desc&dateRange=${dateRange}&page=${paginationController.page}&rowsPerPage=${paginationController.rowsPerPage}`, - { - headers: { - Authorization: `Bearer ${authToken}`, - }, - } + const res = await axiosInstance.getChecksByMonitor( + authToken, + monitorId, + "desc", + null, + dateRange, + null, + paginationController.page, + paginationController.rowsPerPage ); setChecks(res.data.data.checks); setChecksCount(res.data.data.checksCount); diff --git a/Client/src/Pages/Monitors/Details/index.jsx b/Client/src/Pages/Monitors/Details/index.jsx index 6c23f4a03..950fe3ee9 100644 --- a/Client/src/Pages/Monitors/Details/index.jsx +++ b/Client/src/Pages/Monitors/Details/index.jsx @@ -121,16 +121,18 @@ const DetailsPage = () => { const fetchMonitor = useCallback(async () => { try { - const res = await axiosInstance.get( - `/monitors/stats/${monitorId}?dateRange=${dateRange}&numToDisplay=50&normalize=true`, - { - headers: { - Authorization: `Bearer ${authToken}`, - }, - } + const res = await axiosInstance.getStatsByMonitorId( + authToken, + monitorId, + null, + null, + dateRange, + 50, + true ); setMonitor(res.data.data); } catch (error) { + console.log(error); console.error("Error fetching monitor of id: " + monitorId); navigate("/not-found"); } @@ -142,13 +144,9 @@ const DetailsPage = () => { useEffect(() => { const fetchCertificate = async () => { - const res = await axiosInstance.get( - `/monitors/certificate/${monitorId}`, - { - headers: { - Authorization: `Bearer ${authToken}`, - }, - } + const res = await axiosInstance.getCertificateExpiry( + authToken, + monitorId ); setCertificateExpiry(res.data.data.certificateDate); }; diff --git a/Client/src/Pages/PageSpeed/Details/index.jsx b/Client/src/Pages/PageSpeed/Details/index.jsx index c63ad9a86..10ae1fc7e 100644 --- a/Client/src/Pages/PageSpeed/Details/index.jsx +++ b/Client/src/Pages/PageSpeed/Details/index.jsx @@ -186,15 +186,15 @@ const PageSpeedDetails = () => { useEffect(() => { const fetchMonitor = async () => { try { - const res = await axiosInstance.get( - `/monitors/stats/${monitorId}?sortOrder=desc&limit=50`, - { - headers: { - Authorization: `Bearer ${authToken}`, - }, - } + const res = await axiosInstance.getStatsByMonitorId( + authToken, + monitorId, + "desc", + 50, + null, + null, + null ); - setMonitor(res.data.data); setAudits(res.data.data.checks[0].audits); } catch (error) { diff --git a/Client/src/Utils/NetworkService.js b/Client/src/Utils/NetworkService.js index 58ef2951f..2c112f22c 100644 --- a/Client/src/Utils/NetworkService.js +++ b/Client/src/Utils/NetworkService.js @@ -44,6 +44,7 @@ axiosInstance.getMonitorsByUserId = async ( userId, limit, types, + status, sortOrder, normalize ) => { @@ -55,6 +56,7 @@ axiosInstance.getMonitorsByUserId = async ( params.append("type", type); }); } + if (status) params.append("status", status); if (sortOrder) params.append("sortOrder", sortOrder); if (normalize) params.append("normalize", normalize); @@ -66,6 +68,35 @@ axiosInstance.getMonitorsByUserId = async ( }); }; +// ********************************** +// Get stats for a monitor +// ********************************** +axiosInstance.getStatsByMonitorId = async ( + authToken, + monitorId, + sortOrder, + limit, + dateRange, + numToDisplay, + normalize +) => { + const params = new URLSearchParams(); + if (sortOrder) params.append("sortOrder", sortOrder); + if (limit) params.append("limit", limit); + if (dateRange) params.append("dateRange", dateRange); + if (numToDisplay) params.append("numToDisplay", numToDisplay); + if (normalize) params.append("normalize", normalize); + + return axiosInstance.get( + `/monitors/stats/${monitorId}?${params.toString()}`, + { + headers: { + Authorization: `Bearer ${authToken}`, + }, + } + ); +}; + // ********************************** // Updates a single monitor // ********************************** @@ -90,6 +121,17 @@ axiosInstance.deleteMonitorById = async (authToken, monitorId) => { }); }; +// ********************************** +// Get certificate +// ********************************** +axiosInstance.getCertificateExpiry = async (authToken, monitorId) => { + return axiosInstance.get(`/monitors/certificate/${monitorId}`, { + headers: { + Authorization: `Bearer ${authToken}`, + }, + }); +}; + // ********************************** // Register a new user // ********************************** @@ -116,18 +158,6 @@ axiosInstance.updateUser = async (authToken, userId, form) => { }); }; -// ********************************** -// Delete an exisiting user -// ********************************** -axiosInstance.deleteUser = async (authToken, userId) => { - return axiosInstance.delete(`/auth/user/${userId}`, { - headers: { - Authorization: `Bearer ${authToken}`, - "Content-Type": "application/json", - }, - }); -}; - // ********************************** // Forgot password request // ********************************** @@ -167,6 +197,19 @@ axiosInstance.getAllUsers = async (authToken) => { }); }; +// ********************************** +// Request Invitation Token +// ********************************** +axiosInstance.requestInvitationToken = async (authToken, email, role) => { + return axiosInstance.post( + `/auth/invite`, + { email, role }, + { + headers: { Authorization: `Bearer ${authToken}` }, + } + ); +}; + // ********************************** // Verify Invitation Token // ********************************** @@ -176,4 +219,56 @@ axiosInstance.verifyInvitationToken = async (token) => { }); }; +// ********************************** +// Get all checks for a given monitor +// ********************************** + +axiosInstance.getChecksByMonitor = async ( + authToken, + monitorId, + sortOrder, + limit, + dateRange, + filter, + page, + rowsPerPage +) => { + const params = new URLSearchParams(); + if (sortOrder) params.append("sortOrder", sortOrder); + if (limit) params.append("limit", limit); + if (dateRange) params.append("dateRange", dateRange); + if (filter) params.append("filter", filter); + if (page) params.append("page", page); + if (rowsPerPage) params.append("rowsPerPage", rowsPerPage); + + return axiosInstance.get(`/checks/${monitorId}?${params.toString()}`, { + headers: { Authorization: `Bearer ${authToken}` }, + }); +}; + +// ********************************** +// Get all checks for a given user +// ********************************** +axiosInstance.getChecksByUser = async ( + authToken, + userId, + sortOrder, + limit, + dateRange, + filter, + page, + rowsPerPage +) => { + const params = new URLSearchParams(); + if (sortOrder) params.append("sortOrder", sortOrder); + if (limit) params.append("limit", limit); + if (dateRange) params.append("dateRange", dateRange); + if (filter) params.append("filter", filter); + if (page) params.append("page", page); + if (rowsPerPage) params.append("rowsPerPage", rowsPerPage); + return axiosInstance.get(`/checks/user/${userId}?${params.toString()}`, { + headers: { Authorization: `Bearer ${authToken}` }, + }); +}; + export default axiosInstance; diff --git a/Server/routes/checkRoute.js b/Server/routes/checkRoute.js index 69aa682af..4bba24e79 100644 --- a/Server/routes/checkRoute.js +++ b/Server/routes/checkRoute.js @@ -15,12 +15,12 @@ router.get( checkController.getChecks ); +router.get("/user/:userId", checkController.getUserChecks); + router.delete( "/:monitorId", verifyOwnership(Monitor, "monitorId"), checkController.deleteChecks ); -router.get("/user/:userId", checkController.getUserChecks); - module.exports = router; From 20e4c7ef078cca2cf6de586e64b4b6cca7048631 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sun, 18 Aug 2024 17:42:49 -0700 Subject: [PATCH 09/11] Refactored axios util into a service --- .../TabPanels/Account/TeamPanel.jsx | 6 +- Client/src/Features/Auth/authSlice.js | 18 +- .../PageSpeedMonitor/pageSpeedMonitorSlice.js | 13 +- .../UptimeMonitors/uptimeMonitorsSlice.js | 13 +- Client/src/HOC/withAdminCheck.jsx | 4 +- Client/src/Pages/Auth/Login.jsx | 4 +- Client/src/Pages/Auth/Register/Register.jsx | 4 +- .../Pages/Incidents/IncidentTable/index.jsx | 6 +- Client/src/Pages/Incidents/index.jsx | 4 +- .../Details/PaginationTable/index.jsx | 4 +- Client/src/Pages/Monitors/Details/index.jsx | 6 +- Client/src/Pages/PageSpeed/Details/index.jsx | 4 +- Client/src/Utils/NetworkService.js | 490 +++++++++--------- Client/src/main.jsx | 6 +- 14 files changed, 293 insertions(+), 289 deletions(-) diff --git a/Client/src/Components/TabPanels/Account/TeamPanel.jsx b/Client/src/Components/TabPanels/Account/TeamPanel.jsx index ab35a41d1..95df3e294 100644 --- a/Client/src/Components/TabPanels/Account/TeamPanel.jsx +++ b/Client/src/Components/TabPanels/Account/TeamPanel.jsx @@ -16,7 +16,7 @@ import { useEffect, useState } from "react"; import EditSvg from "../../../assets/icons/edit.svg?react"; import Field from "../../Inputs/Field"; import { credentials } from "../../../Validation/validation"; -import axiosInstance from "../../../Utils/NetworkService"; +import { networkService } from "../../../main"; import { createToast } from "../../../Utils/toastUtils"; import { useSelector } from "react-redux"; import BasicTable from "../../BasicTable"; @@ -52,7 +52,7 @@ const TeamPanel = () => { useEffect(() => { const fetchTeam = async () => { try { - const response = await axiosInstance.getAllUsers(authToken); + const response = await networkService.getAllUsers(authToken); setMembers(response.data.data); } catch (error) { createToast({ @@ -176,7 +176,7 @@ const TeamPanel = () => { setErrors((prev) => ({ ...prev, email: error.details[0].message })); } else try { - await axiosInstance.requestInvitationToken( + await networkService.requestInvitationToken( authToken, toInvite.email, toInvite.role diff --git a/Client/src/Features/Auth/authSlice.js b/Client/src/Features/Auth/authSlice.js index 9994c2bbb..fa1f0471e 100644 --- a/Client/src/Features/Auth/authSlice.js +++ b/Client/src/Features/Auth/authSlice.js @@ -1,4 +1,4 @@ -import axiosInstance from "../../Utils/NetworkService"; +import { networkService } from "../../main"; import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; import { jwtDecode } from "jwt-decode"; @@ -14,7 +14,7 @@ export const register = createAsyncThunk( "auth/register", async (form, thunkApi) => { try { - const res = await axiosInstance.registerUser(form); + const res = await networkService.registerUser(form); return res.data; } catch (error) { if (error.response.data) { @@ -31,7 +31,7 @@ export const register = createAsyncThunk( export const login = createAsyncThunk("auth/login", async (form, thunkApi) => { try { - const res = await axiosInstance.loginUser(form); + const res = await networkService.loginUser(form); return res.data; } catch (error) { if (error.response && error.response.data) { @@ -57,7 +57,7 @@ export const update = createAsyncThunk( form.password && fd.append("password", form.password); form.newPassword && fd.append("newPassword", form.newPassword); if (form.file && form.file !== "") { - const imageResult = await axiosInstance.get(form.file, { + const imageResult = await networkService.get(form.file, { responseType: "blob", baseURL: "", }); @@ -66,7 +66,7 @@ export const update = createAsyncThunk( form.deleteProfileImage && fd.append("deleteProfileImage", form.deleteProfileImage); - const res = await axiosInstance.updateUser(token, user._id, fd); + const res = await networkService.updateUser(token, user._id, fd); return res.data; } catch (error) { @@ -88,7 +88,7 @@ export const deleteUser = createAsyncThunk( const user = jwtDecode(data); try { - const res = await axiosInstance.deleteUser(data, user._id); + const res = await networkService.deleteUser(data, user._id); return res.data; } catch (error) { if (error.response && error.response.data) { @@ -107,7 +107,7 @@ export const forgotPassword = createAsyncThunk( "auth/forgotPassword", async (form, thunkApi) => { try { - const res = await axiosInstance.forgotPassword(form); + const res = await networkService.forgotPassword(form); return res.data; } catch (error) { if (error.response.data) { @@ -127,8 +127,8 @@ export const setNewPassword = createAsyncThunk( async (data, thunkApi) => { const { token, form } = data; try { - await axiosInstance.validateRecoveryToken(token); - const res = await axiosInstance.setNewPassword(token, form); + await networkService.validateRecoveryToken(token); + const res = await networkService.setNewPassword(token, form); return res.data; } catch (error) { if (error.response.data) { diff --git a/Client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js b/Client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js index d547e31fa..22e2b3324 100644 --- a/Client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js +++ b/Client/src/Features/PageSpeedMonitor/pageSpeedMonitorSlice.js @@ -1,6 +1,6 @@ import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; import { jwtDecode } from "jwt-decode"; -import axiosInstance from "../../Utils/NetworkService"; +import { networkService } from "../../main"; const initialState = { isLoading: false, monitors: [], @@ -13,7 +13,7 @@ export const createPageSpeed = createAsyncThunk( async (data, thunkApi) => { try { const { authToken, monitor } = data; - const res = await axiosInstance.createMonitor(authToken, monitor); + const res = await networkService.createMonitor(authToken, monitor); return res.data; } catch (error) { if (error.response && error.response.data) { @@ -33,7 +33,7 @@ export const getPageSpeedByUserId = createAsyncThunk( async (token, thunkApi) => { const user = jwtDecode(token); try { - const res = await axiosInstance.getMonitorsByUserId( + const res = await networkService.getMonitorsByUserId( token, user._id, 25, @@ -68,7 +68,7 @@ export const updatePageSpeed = createAsyncThunk( interval: monitor.interval, // notifications: monitor.notifications, }; - const res = await axiosInstance.updateMonitor( + const res = await networkService.updateMonitor( authToken, monitor._id, updatedFields @@ -92,7 +92,10 @@ export const deletePageSpeed = createAsyncThunk( async (data, thunkApi) => { try { const { authToken, monitor } = data; - const res = await axiosInstance.deleteMonitorById(authToken, monitor._id); + const res = await networkService.deleteMonitorById( + authToken, + monitor._id + ); return res.data; } catch (error) { if (error.response && error.response.data) { diff --git a/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js b/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js index d92116a9a..9ab7d385b 100644 --- a/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js +++ b/Client/src/Features/UptimeMonitors/uptimeMonitorsSlice.js @@ -1,6 +1,6 @@ import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; import { jwtDecode } from "jwt-decode"; -import axiosInstance from "../../Utils/NetworkService"; +import { networkService } from "../../main"; const initialState = { isLoading: false, monitors: [], @@ -13,7 +13,7 @@ export const createUptimeMonitor = createAsyncThunk( async (data, thunkApi) => { try { const { authToken, monitor } = data; - const res = await axiosInstance.createMonitor(authToken, monitor); + const res = await networkService.createMonitor(authToken, monitor); return res.data; } catch (error) { if (error.response && error.response.data) { @@ -33,7 +33,7 @@ export const getUptimeMonitorsByUserId = createAsyncThunk( async (token, thunkApi) => { const user = jwtDecode(token); try { - const res = await axiosInstance.getMonitorsByUserId( + const res = await networkService.getMonitorsByUserId( token, user._id, 25, @@ -67,7 +67,7 @@ export const updateUptimeMonitor = createAsyncThunk( interval: monitor.interval, notifications: monitor.notifications, }; - const res = await axiosInstance.updateMonitor( + const res = await networkService.updateMonitor( authToken, monitor._id, updatedFields @@ -91,7 +91,10 @@ export const deleteUptimeMonitor = createAsyncThunk( async (data, thunkApi) => { try { const { authToken, monitor } = data; - const res = await axiosInstance.deleteMonitorById(authToken, monitor._id); + const res = await networkService.deleteMonitorById( + authToken, + monitor._id + ); return res.data; } catch (error) { if (error.response && error.response.data) { diff --git a/Client/src/HOC/withAdminCheck.jsx b/Client/src/HOC/withAdminCheck.jsx index c6a939679..55e94d4db 100644 --- a/Client/src/HOC/withAdminCheck.jsx +++ b/Client/src/HOC/withAdminCheck.jsx @@ -1,13 +1,13 @@ import React, { useEffect } from "react"; import { useNavigate } from "react-router-dom"; -import axiosInstance from "../Utils/NetworkService"; +import { networkService } from "../main"; const withAdminCheck = (WrappedComponent) => { const WithAdminCheck = (props) => { const navigate = useNavigate(); useEffect(() => { - axiosInstance + networkService .doesAdminExist() .then((response) => { if (response.data.data === true) { diff --git a/Client/src/Pages/Auth/Login.jsx b/Client/src/Pages/Auth/Login.jsx index 6a408c970..12dc52bef 100644 --- a/Client/src/Pages/Auth/Login.jsx +++ b/Client/src/Pages/Auth/Login.jsx @@ -7,7 +7,7 @@ import { login } from "../../Features/Auth/authSlice"; import { useDispatch } from "react-redux"; import { createToast } from "../../Utils/toastUtils"; import Button from "../../Components/Button"; -import axiosInstance from "../../Utils/NetworkService"; +import { networkService } from "../../main"; import Field from "../../Components/Inputs/Field"; import background from "../../assets/Images/background_pattern_decorative.png"; import Logo from "../../assets/icons/bwu-icon.svg?react"; @@ -248,7 +248,7 @@ const Login = () => { const [step, setStep] = useState(0); useEffect(() => { - axiosInstance + networkService .doesAdminExist() .then((response) => { if (response.data.data === false) { diff --git a/Client/src/Pages/Auth/Register/Register.jsx b/Client/src/Pages/Auth/Register/Register.jsx index 1dedaa0f1..b7dd70dc9 100644 --- a/Client/src/Pages/Auth/Register/Register.jsx +++ b/Client/src/Pages/Auth/Register/Register.jsx @@ -15,7 +15,7 @@ import ArrowBackRoundedIcon from "@mui/icons-material/ArrowBackRounded"; import Check from "../../../Components/Check/Check"; import Button from "../../../Components/Button"; import Field from "../../../Components/Inputs/Field"; -import axiosInstance from "../../../Utils/NetworkService"; +import { networkService } from "../../../main"; import "../index.css"; /** @@ -397,7 +397,7 @@ const Register = ({ isAdmin }) => { const fetchInvite = async () => { if (token !== undefined) { try { - const res = await axiosInstance.verifyInvitationToken(token); + const res = await networkService.verifyInvitationToken(token); const { role, email } = res.data.data; console.log(role); setForm({ ...form, email, role }); diff --git a/Client/src/Pages/Incidents/IncidentTable/index.jsx b/Client/src/Pages/Incidents/IncidentTable/index.jsx index 971886551..e476eac1f 100644 --- a/Client/src/Pages/Incidents/IncidentTable/index.jsx +++ b/Client/src/Pages/Incidents/IncidentTable/index.jsx @@ -18,7 +18,7 @@ import ArrowForwardRoundedIcon from "@mui/icons-material/ArrowForwardRounded"; import { useState, useEffect } from "react"; import { useSelector } from "react-redux"; -import axiosInstance from "../../../Utils/NetworkService"; +import { networkService } from "../../../main"; import { StatusLabel } from "../../../Components/Label"; const IncidentTable = ({ monitors, selectedMonitor, filter }) => { @@ -45,7 +45,7 @@ const IncidentTable = ({ monitors, selectedMonitor, filter }) => { try { let res; if (selectedMonitor === "0") { - res = await axiosInstance.getChecksByUser( + res = await networkService.getChecksByUser( authToken, user._id, "desc", @@ -56,7 +56,7 @@ const IncidentTable = ({ monitors, selectedMonitor, filter }) => { paginationController.rowsPerPage ); } else { - res = await axiosInstance.getChecksByMonitor( + res = await networkService.getChecksByMonitor( authToken, selectedMonitor, "desc", diff --git a/Client/src/Pages/Incidents/index.jsx b/Client/src/Pages/Incidents/index.jsx index 3a50d3194..34768f7f9 100644 --- a/Client/src/Pages/Incidents/index.jsx +++ b/Client/src/Pages/Incidents/index.jsx @@ -2,7 +2,7 @@ import { useState, useEffect } from "react"; import { useSelector } from "react-redux"; import { ButtonGroup, Stack, Skeleton, Typography } from "@mui/material"; import Button from "../../Components/Button"; -import axiosInstance from "../../Utils/NetworkService"; +import { networkService } from "../../main"; import { useTheme } from "@emotion/react"; import Select from "../../Components/Inputs/Select"; import IncidentTable from "./IncidentTable"; @@ -48,7 +48,7 @@ const Incidents = () => { useEffect(() => { const fetchMonitors = async () => { setLoading(true); - const res = await axiosInstance.getMonitorsByUserId( + const res = await networkService.getMonitorsByUserId( authState.authToken, authState.user._id, 1, diff --git a/Client/src/Pages/Monitors/Details/PaginationTable/index.jsx b/Client/src/Pages/Monitors/Details/PaginationTable/index.jsx index 2df061e82..28795dff5 100644 --- a/Client/src/Pages/Monitors/Details/PaginationTable/index.jsx +++ b/Client/src/Pages/Monitors/Details/PaginationTable/index.jsx @@ -13,7 +13,7 @@ import { import { useState, useEffect } from "react"; import { useSelector } from "react-redux"; -import axiosInstance from "../../../../Utils/NetworkService"; +import { networkService } from "../../../../main"; import { StatusLabel } from "../../../../Components/Label"; import ArrowBackRoundedIcon from "@mui/icons-material/ArrowBackRounded"; import ArrowForwardRoundedIcon from "@mui/icons-material/ArrowForwardRounded"; @@ -37,7 +37,7 @@ const PaginationTable = ({ monitorId, dateRange }) => { useEffect(() => { const fetchPage = async () => { try { - const res = await axiosInstance.getChecksByMonitor( + const res = await networkService.getChecksByMonitor( authToken, monitorId, "desc", diff --git a/Client/src/Pages/Monitors/Details/index.jsx b/Client/src/Pages/Monitors/Details/index.jsx index 950fe3ee9..46f181f97 100644 --- a/Client/src/Pages/Monitors/Details/index.jsx +++ b/Client/src/Pages/Monitors/Details/index.jsx @@ -3,7 +3,7 @@ import PropTypes from "prop-types"; import { Box, Skeleton, Stack, Typography, useTheme } from "@mui/material"; import { useSelector } from "react-redux"; import { useNavigate, useParams } from "react-router-dom"; -import axiosInstance from "../../../Utils/NetworkService"; +import { networkService } from "../../../main"; import MonitorDetailsAreaChart from "../../../Components/Charts/MonitorDetailsAreaChart"; import ButtonGroup from "@mui/material/ButtonGroup"; import Button from "../../../Components/Button"; @@ -121,7 +121,7 @@ const DetailsPage = () => { const fetchMonitor = useCallback(async () => { try { - const res = await axiosInstance.getStatsByMonitorId( + const res = await networkService.getStatsByMonitorId( authToken, monitorId, null, @@ -144,7 +144,7 @@ const DetailsPage = () => { useEffect(() => { const fetchCertificate = async () => { - const res = await axiosInstance.getCertificateExpiry( + const res = await networkService.getCertificateExpiry( authToken, monitorId ); diff --git a/Client/src/Pages/PageSpeed/Details/index.jsx b/Client/src/Pages/PageSpeed/Details/index.jsx index 10ae1fc7e..4c2185e13 100644 --- a/Client/src/Pages/PageSpeed/Details/index.jsx +++ b/Client/src/Pages/PageSpeed/Details/index.jsx @@ -9,7 +9,7 @@ import { formatDuration, formatDurationRounded, } from "../../../Utils/timeUtils"; -import axiosInstance from "../../../Utils/NetworkService"; +import { networkService } from "../../../main"; import Button from "../../../Components/Button"; import WestRoundedIcon from "@mui/icons-material/WestRounded"; import SettingsIcon from "../../../assets/icons/settings-bold.svg?react"; @@ -186,7 +186,7 @@ const PageSpeedDetails = () => { useEffect(() => { const fetchMonitor = async () => { try { - const res = await axiosInstance.getStatsByMonitorId( + const res = await networkService.getStatsByMonitorId( authToken, monitorId, "desc", diff --git a/Client/src/Utils/NetworkService.js b/Client/src/Utils/NetworkService.js index 2c112f22c..1c0eb3acb 100644 --- a/Client/src/Utils/NetworkService.js +++ b/Client/src/Utils/NetworkService.js @@ -2,273 +2,273 @@ import axios from "axios"; import { clearAuthState } from "../Features/Auth/authSlice"; const BASE_URL = import.meta.env.VITE_APP_API_BASE_URL; -let store; - -export const injectStore = (s) => { - store = s; -}; - -const axiosInstance = axios.create({ - baseURL: BASE_URL, -}); - -axiosInstance.interceptors.response.use( - (response) => response, - (error) => { - console.error(error); - if (error.response && error.response.status === 401) { - console.log("Invalid token revoked"); - store.dispatch(clearAuthState()); - } - return Promise.reject(error); +class NetworkService { + constructor(store) { + this.store = store; + this.axiosInstance = axios.create({ baseURL: BASE_URL }); + this.axiosInstance.interceptors.response.use( + (response) => response, + (error) => { + console.error(error); + if (error.response && error.response.status === 401) { + console.log("Invalid token revoked"); + networkService; + } + return Promise.reject(error); + } + ); } -); -// ********************************** -// Create a new monitor -// ********************************** -axiosInstance.createMonitor = async (authToken, monitor) => { - return axiosInstance.post(`/monitors`, monitor, { - headers: { - Authorization: `Bearer ${authToken}`, - "Content-Type": "application/json", - }, - }); -}; - -// ********************************** -// Get all uptime monitors for a user -// ********************************** -axiosInstance.getMonitorsByUserId = async ( - authToken, - userId, - limit, - types, - status, - sortOrder, - normalize -) => { - const params = new URLSearchParams(); - - if (limit) params.append("limit", limit); - if (types) { - types.forEach((type) => { - params.append("type", type); + // ********************************** + // Create a new monitor + // ********************************** + async createMonitor(authToken, monitor) { + return this.axiosInstance.post(`/monitors`, monitor, { + headers: { + Authorization: `Bearer ${authToken}`, + "Content-Type": "application/json", + }, }); } - if (status) params.append("status", status); - if (sortOrder) params.append("sortOrder", sortOrder); - if (normalize) params.append("normalize", normalize); - return axiosInstance.get(`/monitors/user/${userId}?${params.toString()}`, { - headers: { - Authorization: `Bearer ${authToken}`, - "Content-Type": "application/json", - }, - }); -}; + // ********************************** + // Get all uptime monitors for a user + // ********************************** + async getMonitorsByUserId( + authToken, + userId, + limit, + types, + status, + sortOrder, + normalize + ) { + const params = new URLSearchParams(); -// ********************************** -// Get stats for a monitor -// ********************************** -axiosInstance.getStatsByMonitorId = async ( - authToken, - monitorId, - sortOrder, - limit, - dateRange, - numToDisplay, - normalize -) => { - const params = new URLSearchParams(); - if (sortOrder) params.append("sortOrder", sortOrder); - if (limit) params.append("limit", limit); - if (dateRange) params.append("dateRange", dateRange); - if (numToDisplay) params.append("numToDisplay", numToDisplay); - if (normalize) params.append("normalize", normalize); + if (limit) params.append("limit", limit); + if (types) { + types.forEach((type) => { + params.append("type", type); + }); + } + if (status) params.append("status", status); + if (sortOrder) params.append("sortOrder", sortOrder); + if (normalize) params.append("normalize", normalize); - return axiosInstance.get( - `/monitors/stats/${monitorId}?${params.toString()}`, - { + return this.axiosInstance.get( + `/monitors/user/${userId}?${params.toString()}`, + { + headers: { + Authorization: `Bearer ${authToken}`, + "Content-Type": "application/json", + }, + } + ); + } + + // ********************************** + // Get stats for a monitor + // ********************************** + async getStatsByMonitorId( + authToken, + monitorId, + sortOrder, + limit, + dateRange, + numToDisplay, + normalize + ) { + const params = new URLSearchParams(); + if (sortOrder) params.append("sortOrder", sortOrder); + if (limit) params.append("limit", limit); + if (dateRange) params.append("dateRange", dateRange); + if (numToDisplay) params.append("numToDisplay", numToDisplay); + if (normalize) params.append("normalize", normalize); + + return this.axiosInstance.get( + `/monitors/stats/${monitorId}?${params.toString()}`, + { + headers: { + Authorization: `Bearer ${authToken}`, + }, + } + ); + } + + // ********************************** + // Updates a single monitor + // ********************************** + async updateMonitor(authToken, monitorId, updatedFields) { + return this.axiosInstance.put(`/monitors/${monitorId}`, updatedFields, { + headers: { + Authorization: `Bearer ${authToken}`, + "Content-Type": "application/json", + }, + }); + } + // ********************************** + // Deletes a single monitor + // ********************************** + async deleteMonitorById(authToken, monitorId) { + return this.axiosInstance.delete(`/monitors/${monitorId}`, { + headers: { + Authorization: `Bearer ${authToken}`, + "Content-Type": "application/json", + }, + }); + } + // ********************************** + // Get certificate + // ********************************** + async getCertificateExpiry(authToken, monitorId) { + return this.axiosInstance.get(`/monitors/certificate/${monitorId}`, { headers: { Authorization: `Bearer ${authToken}`, }, - } - ); -}; + }); + } -// ********************************** -// Updates a single monitor -// ********************************** -axiosInstance.updateMonitor = async (authToken, monitorId, updatedFields) => { - return axiosInstance.put(`/monitors/${monitorId}`, updatedFields, { - headers: { - Authorization: `Bearer ${authToken}`, - "Content-Type": "application/json", - }, - }); -}; + // ********************************** + // Register a new user + // ********************************** + async registerUser(form) { + return this.axiosInstance.post(`/auth/register`, form); + } -// ********************************** -// Deletes a single monitor -// ********************************** -axiosInstance.deleteMonitorById = async (authToken, monitorId) => { - return axiosInstance.delete(`/monitors/${monitorId}`, { - headers: { - Authorization: `Bearer ${authToken}`, - "Content-Type": "application/json", - }, - }); -}; + // ********************************** + // Log in an exisiting user + // ********************************** + async loginUser(form) { + return this.axiosInstance.post(`/auth/login`, form); + } -// ********************************** -// Get certificate -// ********************************** -axiosInstance.getCertificateExpiry = async (authToken, monitorId) => { - return axiosInstance.get(`/monitors/certificate/${monitorId}`, { - headers: { - Authorization: `Bearer ${authToken}`, - }, - }); -}; + // ********************************** + // Update in an exisiting user + // ********************************** + async updateUser(authToken, userId, form) { + return this.axiosInstance.put(`/auth/user/${userId}`, form, { + headers: { + Authorization: `Bearer ${authToken}`, + "Content-Type": "application/json", + }, + }); + } -// ********************************** -// Register a new user -// ********************************** -axiosInstance.registerUser = async (form) => { - return axiosInstance.post(`/auth/register`, form); -}; + // ********************************** + // Forgot password request + // ********************************** + async forgotPassword(form) { + return this.axiosInstance.post(`/auth/recovery/request`, form); + } -// ********************************** -// Log in an exisiting user -// ********************************** -axiosInstance.loginUser = async (form) => { - return axiosInstance.post(`/auth/login`, form); -}; + async validateRecoveryToken(recoveryToken) { + return this.axiosInstance.post("/auth/recovery/validate", { + recoveryToken, + }); + } -// ********************************** -// Update in an exisiting user -// ********************************** -axiosInstance.updateUser = async (authToken, userId, form) => { - return axiosInstance.put(`/auth/user/${userId}`, form, { - headers: { - Authorization: `Bearer ${authToken}`, - "Content-Type": "application/json", - }, - }); -}; + // ********************************** + // Set new password request + // ********************************** + async setNewPassword(recoveryToken, form) { + return this.axiosInstance.post("/auth/recovery/reset", { + ...form, + recoveryToken, + }); + } -// ********************************** -// Forgot password request -// ********************************** -axiosInstance.forgotPassword = async (form) => { - return axiosInstance.post(`/auth/recovery/request`, form); -}; + // ********************************** + // Check for admin user + // ********************************** + async doesAdminExist() { + return this.axiosInstance.get("/auth/users/admin"); + } -axiosInstance.validateRecoveryToken = async (recoveryToken) => { - return axiosInstance.post("/auth/recovery/validate", { - recoveryToken, - }); -}; - -// ********************************** -// Set new password request -// ********************************** -axiosInstance.setNewPassword = async (recoveryToken, form) => { - return axiosInstance.post("/auth/recovery/reset", { - ...form, - recoveryToken, - }); -}; - -// ********************************** -// Check for admin user -// ********************************** -axiosInstance.doesAdminExist = async () => { - return axiosInstance.get("/auth/users/admin"); -}; - -// ********************************** -// Get all users -// ********************************** -axiosInstance.getAllUsers = async (authToken) => { - return axiosInstance.get("/auth/users", { - headers: { Authorization: `Bearer ${authToken}` }, - }); -}; - -// ********************************** -// Request Invitation Token -// ********************************** -axiosInstance.requestInvitationToken = async (authToken, email, role) => { - return axiosInstance.post( - `/auth/invite`, - { email, role }, - { + // ********************************** + // Get all users + // ********************************** + async getAllUsers(authToken) { + return this.axiosInstance.get("/auth/users", { headers: { Authorization: `Bearer ${authToken}` }, - } - ); -}; + }); + } -// ********************************** -// Verify Invitation Token -// ********************************** -axiosInstance.verifyInvitationToken = async (token) => { - return axiosInstance.post(`/auth/invite/verify`, { - token, - }); -}; + // ********************************** + // Request Invitation Token + // ********************************** + async requestInvitationToken(authToken, email, role) { + return this.axiosInstance.post( + `/auth/invite`, + { email, role }, + { + headers: { Authorization: `Bearer ${authToken}` }, + } + ); + } -// ********************************** -// Get all checks for a given monitor -// ********************************** + // ********************************** + // Verify Invitation Token + // ********************************** + async verifyInvitationToken(token) { + return this.axiosInstance.post(`/auth/invite/verify`, { + token, + }); + } -axiosInstance.getChecksByMonitor = async ( - authToken, - monitorId, - sortOrder, - limit, - dateRange, - filter, - page, - rowsPerPage -) => { - const params = new URLSearchParams(); - if (sortOrder) params.append("sortOrder", sortOrder); - if (limit) params.append("limit", limit); - if (dateRange) params.append("dateRange", dateRange); - if (filter) params.append("filter", filter); - if (page) params.append("page", page); - if (rowsPerPage) params.append("rowsPerPage", rowsPerPage); + // ********************************** + // Get all checks for a given monitor + // ********************************** - return axiosInstance.get(`/checks/${monitorId}?${params.toString()}`, { - headers: { Authorization: `Bearer ${authToken}` }, - }); -}; + async getChecksByMonitor( + authToken, + monitorId, + sortOrder, + limit, + dateRange, + filter, + page, + rowsPerPage + ) { + const params = new URLSearchParams(); + if (sortOrder) params.append("sortOrder", sortOrder); + if (limit) params.append("limit", limit); + if (dateRange) params.append("dateRange", dateRange); + if (filter) params.append("filter", filter); + if (page) params.append("page", page); + if (rowsPerPage) params.append("rowsPerPage", rowsPerPage); -// ********************************** -// Get all checks for a given user -// ********************************** -axiosInstance.getChecksByUser = async ( - authToken, - userId, - sortOrder, - limit, - dateRange, - filter, - page, - rowsPerPage -) => { - const params = new URLSearchParams(); - if (sortOrder) params.append("sortOrder", sortOrder); - if (limit) params.append("limit", limit); - if (dateRange) params.append("dateRange", dateRange); - if (filter) params.append("filter", filter); - if (page) params.append("page", page); - if (rowsPerPage) params.append("rowsPerPage", rowsPerPage); - return axiosInstance.get(`/checks/user/${userId}?${params.toString()}`, { - headers: { Authorization: `Bearer ${authToken}` }, - }); -}; + return this.axiosInstance.get(`/checks/${monitorId}?${params.toString()}`, { + headers: { Authorization: `Bearer ${authToken}` }, + }); + } -export default axiosInstance; + // ********************************** + // Get all checks for a given user + // ********************************** + async getChecksByUser( + authToken, + userId, + sortOrder, + limit, + dateRange, + filter, + page, + rowsPerPage + ) { + const params = new URLSearchParams(); + if (sortOrder) params.append("sortOrder", sortOrder); + if (limit) params.append("limit", limit); + if (dateRange) params.append("dateRange", dateRange); + if (filter) params.append("filter", filter); + if (page) params.append("page", page); + if (rowsPerPage) params.append("rowsPerPage", rowsPerPage); + return this.axiosInstance.get( + `/checks/user/${userId}?${params.toString()}`, + { + headers: { Authorization: `Bearer ${authToken}` }, + } + ); + } +} + +export default NetworkService; diff --git a/Client/src/main.jsx b/Client/src/main.jsx index 387d1f931..00cec7d14 100644 --- a/Client/src/main.jsx +++ b/Client/src/main.jsx @@ -8,10 +8,8 @@ import { ThemeProvider } from "@mui/material"; import { Provider } from "react-redux"; import { persistor, store } from "./store"; import { PersistGate } from "redux-persist/integration/react"; -import { injectStore } from "./Utils/NetworkService.js"; - -injectStore(store); - +import NetworkService from "./Utils/NetworkService.js"; +export const networkService = new NetworkService(store); ReactDOM.createRoot(document.getElementById("root")).render( From 69597b3df0a4b52b8bc5cec21dff1976b91f0e08 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sun, 18 Aug 2024 17:56:18 -0700 Subject: [PATCH 10/11] Add jsdocs --- Client/src/Utils/NetworkService.js | 262 +++++++++++++++++++++++------ 1 file changed, 211 insertions(+), 51 deletions(-) diff --git a/Client/src/Utils/NetworkService.js b/Client/src/Utils/NetworkService.js index 1c0eb3acb..21f1c1845 100644 --- a/Client/src/Utils/NetworkService.js +++ b/Client/src/Utils/NetworkService.js @@ -19,9 +19,17 @@ class NetworkService { ); } - // ********************************** - // Create a new monitor - // ********************************** + /** + * + * ************************************ + * Create a new monitor + * ************************************ + * + * @async + * @param {string} authToken - The authorization token to be used in the request header. + * @param {Object} monitor - The monitor object to be sent in the request body. + * @returns {Promise} The response from the axios POST request. + */ async createMonitor(authToken, monitor) { return this.axiosInstance.post(`/monitors`, monitor, { headers: { @@ -31,9 +39,21 @@ class NetworkService { }); } - // ********************************** - // Get all uptime monitors for a user - // ********************************** + /** + * ************************************ + * Get all uptime monitors for a user + * ************************************ + * + * @async + * @param {string} authToken - The authorization token to be used in the request header. + * @param {string} userId - The ID of the user whose monitors are to be retrieved. + * @param {number} [limit] - The maximum number of monitors to retrieve. + * @param {Array} [types] - The types of monitors to retrieve. + * @param {string} [status] - The status of the monitors to retrieve. + * @param {string} [sortOrder] - The order in which to sort the retrieved monitors. + * @param {boolean} [normalize] - Whether to normalize the retrieved monitors. + * @returns {Promise} The response from the axios GET request. + */ async getMonitorsByUserId( authToken, userId, @@ -66,9 +86,21 @@ class NetworkService { ); } - // ********************************** - // Get stats for a monitor - // ********************************** + /** + * ************************************ + * Get stats for a monitor + * ************************************ + * + * @async + * @param {string} authToken - The authorization token to be used in the request header. + * @param {string} monitorId - The ID of the monitor whose statistics are to be retrieved. + * @param {string} [sortOrder] - The order in which to sort the retrieved statistics. + * @param {number} [limit] - The maximum number of statistics to retrieve. + * @param {string} [dateRange] - The date range for which to retrieve statistics. + * @param {number} [numToDisplay] - The number of statistics to display. + * @param {boolean} [normalize] - Whether to normalize the retrieved statistics. + * @returns {Promise} The response from the axios GET request. + */ async getStatsByMonitorId( authToken, monitorId, @@ -95,9 +127,17 @@ class NetworkService { ); } - // ********************************** - // Updates a single monitor - // ********************************** + /** + * ************************************ + * Updates a single monitor + * ************************************ + * + * @async + * @param {string} authToken - The authorization token to be used in the request header. + * @param {string} monitorId - The ID of the monitor to be updated. + * @param {Object} updatedFields - The fields to be updated for the monitor. + * @returns {Promise} The response from the axios PUT request. + */ async updateMonitor(authToken, monitorId, updatedFields) { return this.axiosInstance.put(`/monitors/${monitorId}`, updatedFields, { headers: { @@ -106,9 +146,17 @@ class NetworkService { }, }); } - // ********************************** - // Deletes a single monitor - // ********************************** + + /** + * ************************************ + * Deletes a single monitor by its ID + * ************************************ + * + * @async + * @param {string} authToken - The authorization token to be used in the request header. + * @param {string} monitorId - The ID of the monitor to be deleted. + * @returns {Promise} The response from the axios DELETE request. + */ async deleteMonitorById(authToken, monitorId) { return this.axiosInstance.delete(`/monitors/${monitorId}`, { headers: { @@ -117,9 +165,18 @@ class NetworkService { }, }); } - // ********************************** - // Get certificate - // ********************************** + + /** + * ************************************ + * Gets the certificate expiry for a monitor + * ************************************ + * + * @async + * @param {string} authToken - The authorization token to be used in the request header. + * @param {string} monitorId - The ID of the monitor whose certificate expiry is to be retrieved. + * @returns {Promise} The response from the axios GET request. + * + */ async getCertificateExpiry(authToken, monitorId) { return this.axiosInstance.get(`/monitors/certificate/${monitorId}`, { headers: { @@ -128,23 +185,45 @@ class NetworkService { }); } - // ********************************** - // Register a new user - // ********************************** + /** + * ************************************ + * Registers a new user + * ************************************ + * + * @async + * @param {Object} form - The form data for the new user to be registered. + * @returns {Promise} The response from the axios POST request. + */ async registerUser(form) { return this.axiosInstance.post(`/auth/register`, form); } - // ********************************** - // Log in an exisiting user - // ********************************** + /** + * ************************************ + * Logs in a user + * ************************************ + * + * @async + * @param {Object} form - The form data for the user to be logged in. + * @returns {Promise} The response from the axios POST request. + * + */ async loginUser(form) { return this.axiosInstance.post(`/auth/login`, form); } - // ********************************** - // Update in an exisiting user - // ********************************** + /** + * ************************************ + * Updates a user + * ************************************ + * + * @async + * @param {string} authToken - The authorization token to be used in the request header. + * @param {string} userId - The ID of the user to be updated. + * @param {Object} form - The form data for the user to be updated. + * @returns {Promise} The response from the axios PUT request. + * + */ async updateUser(authToken, userId, form) { return this.axiosInstance.put(`/auth/user/${userId}`, form, { headers: { @@ -154,22 +233,46 @@ class NetworkService { }); } - // ********************************** - // Forgot password request - // ********************************** + /** + * ************************************ + * Forgot password request + * ************************************ + * + * @async + * @param {Object} form - The form data for the password recovery request. + * @returns {Promise} The response from the axios POST request. + * + */ async forgotPassword(form) { return this.axiosInstance.post(`/auth/recovery/request`, form); } + /** + * ************************************ + * Validates a recovery token + * ************************************ + * + * @async + * @param {string} recoveryToken - The recovery token to be validated. + * @returns {Promise} The response from the axios POST request. + * + */ async validateRecoveryToken(recoveryToken) { return this.axiosInstance.post("/auth/recovery/validate", { recoveryToken, }); } - // ********************************** - // Set new password request - // ********************************** + /** + * ************************************ + * Requests password recovery + * ************************************ + * + * @async + * @param {Object} form - The form data for the password recovery request. + * @returns {Promise} The response from the axios POST request. + * + */ async setNewPassword(recoveryToken, form) { return this.axiosInstance.post("/auth/recovery/reset", { ...form, @@ -177,25 +280,47 @@ class NetworkService { }); } - // ********************************** - // Check for admin user - // ********************************** + /** + * ************************************ + * Checks if an admin user exists + * ************************************ + * + * @async + * @returns {Promise} The response from the axios GET request. + * + */ async doesAdminExist() { return this.axiosInstance.get("/auth/users/admin"); } - // ********************************** - // Get all users - // ********************************** + /** + * ************************************ + * Get all users + * ************************************ + * + * @async + * @param {string} authToken - The authorization token to be used in the request header. + * @returns {Promise} The response from the axios GET request. + * + */ async getAllUsers(authToken) { return this.axiosInstance.get("/auth/users", { headers: { Authorization: `Bearer ${authToken}` }, }); } - // ********************************** - // Request Invitation Token - // ********************************** + /** + * ************************************ + * Requests an invitation token + * ************************************ + * + * @async + * @param {string} authToken - The authorization token to be used in the request header. + * @param {string} email - The email of the user to be invited. + * @param {string} role - The role of the user to be invited. + * @returns {Promise} The response from the axios POST request. + * + */ async requestInvitationToken(authToken, email, role) { return this.axiosInstance.post( `/auth/invite`, @@ -206,18 +331,39 @@ class NetworkService { ); } - // ********************************** - // Verify Invitation Token - // ********************************** + /** + * ************************************ + * Verifies an invitation token + * ************************************ + * + * @async + * @param {string} token - The invitation token to be verified. + * @returns {Promise} The response from the axios POST request. + * + */ async verifyInvitationToken(token) { return this.axiosInstance.post(`/auth/invite/verify`, { token, }); } - // ********************************** - // Get all checks for a given monitor - // ********************************** + /** + * ************************************ + * Get all checks for a given monitor + * ************************************ + * + * @async + * @param {string} authToken - The authorization token to be used in the request header. + * @param {string} monitorId - The ID of the monitor. + * @param {string} sortOrder - The order in which to sort the checks. + * @param {number} limit - The maximum number of checks to retrieve. + * @param {string} dateRange - The range of dates for which to retrieve checks. + * @param {string} filter - The filter to apply to the checks. + * @param {number} page - The page number to retrieve in a paginated list. + * @param {number} rowsPerPage - The number of rows per page in a paginated list. + * @returns {Promise} The response from the axios GET request. + * + */ async getChecksByMonitor( authToken, @@ -242,9 +388,23 @@ class NetworkService { }); } - // ********************************** - // Get all checks for a given user - // ********************************** + /** + * ************************************ + * Get all checks for a given user + * ************************************ + * + * @async + * @param {string} authToken - The authorization token to be used in the request header. + * @param {string} userId - The ID of the user. + * @param {string} sortOrder - The order in which to sort the checks. + * @param {number} limit - The maximum number of checks to retrieve. + * @param {string} dateRange - The range of dates for which to retrieve checks. + * @param {string} filter - The filter to apply to the checks. + * @param {number} page - The page number to retrieve in a paginated list. + * @param {number} rowsPerPage - The number of rows per page in a paginated list. + * @returns {Promise} The response from the axios GET request. + * + */ async getChecksByUser( authToken, userId, From 85a82bb8c78c74a50651c1621cd7075765e7406d Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sun, 18 Aug 2024 22:07:36 -0700 Subject: [PATCH 11/11] removed log statement --- Server/controllers/authController.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Server/controllers/authController.js b/Server/controllers/authController.js index 8efe2ae19..4b5f51121 100644 --- a/Server/controllers/authController.js +++ b/Server/controllers/authController.js @@ -450,7 +450,6 @@ const deleteUserController = async (req, res, next) => { } // 1. Find all the monitors associated with the user id - console.log("wtf"); const monitors = await req.db.getMonitorsByUserId({ params: { userId: _id },