diff --git a/Client/src/Features/Monitors/monitorsSlice.js b/Client/src/Features/Monitors/monitorsSlice.js
index 8086f1eb4..2d6f8e2ba 100644
--- a/Client/src/Features/Monitors/monitorsSlice.js
+++ b/Client/src/Features/Monitors/monitorsSlice.js
@@ -51,7 +51,7 @@ export const getMonitorsByUserId = createAsyncThunk(
const user = jwtDecode(token);
try {
const res = await axiosInstance.get(
- `/monitors/user/${user._id}?limit=25`,
+ `/monitors/user/${user._id}?limit=25&type=http&type=ping&sortOrder=desc`,
{
headers: {
Authorization: `Bearer ${token}`,
diff --git a/Client/src/Pages/Incidents/index.jsx b/Client/src/Pages/Incidents/index.jsx
index b2765d628..8f588fe73 100644
--- a/Client/src/Pages/Incidents/index.jsx
+++ b/Client/src/Pages/Incidents/index.jsx
@@ -33,7 +33,7 @@ const Incidents = () => {
useEffect(() => {
const fetchIncidents = async () => {
const res = await axiosInstance.get(
- `/monitors/incidents/user/${authState.user._id}`,
+ `/monitors/user/${authState.user._id}?status=false`,
{
headers: {
Authorization: `Bearer ${authState.authToken}`,
diff --git a/Client/src/Pages/Monitors/Details/index.jsx b/Client/src/Pages/Monitors/Details/index.jsx
index 2cce554e8..18ff56e6a 100644
--- a/Client/src/Pages/Monitors/Details/index.jsx
+++ b/Client/src/Pages/Monitors/Details/index.jsx
@@ -82,11 +82,14 @@ const DetailsPage = () => {
useEffect(() => {
const fetchMonitor = async () => {
- const res = await axiosInstance.get(`/monitors/${monitorId}`, {
- headers: {
- Authorization: `Bearer ${authToken}`,
- },
- });
+ const res = await axiosInstance.get(
+ `/monitors/${monitorId}?sortOrder=asc`,
+ {
+ headers: {
+ Authorization: `Bearer ${authToken}`,
+ },
+ }
+ );
setMonitor(res.data.data);
const data = {
cols: [
diff --git a/Client/src/Pages/Monitors/index.jsx b/Client/src/Pages/Monitors/index.jsx
index 5e193fe62..42498d2f9 100644
--- a/Client/src/Pages/Monitors/index.jsx
+++ b/Client/src/Pages/Monitors/index.jsx
@@ -100,6 +100,9 @@ const Monitors = () => {
: "var(--env-var-color-19)",
};
+ // Reverse checks so latest check is on the right
+ const reversedChecks = monitor.checks.slice().reverse();
+
return {
id: monitor._id,
handleClick: () => navigate(`/monitors/${monitor._id}`),
@@ -117,7 +120,7 @@ const Monitors = () => {
/>
),
},
- { id: idx + 2, data: },
+ { id: idx + 2, data: },
{ id: idx + 3, data: monitor.type },
{ id: idx + 4, data: "TODO" },
],
diff --git a/README.md b/README.md
index e40dc81e6..c1d645004 100644
--- a/README.md
+++ b/README.md
@@ -6,16 +6,12 @@


-
An open source server monitoring application
-
-

-
BlueWave Uptime is an open source server monitoring application used to track the operational status and performance of servers and websites. It regularly checks whether a server/website is accessible and performs optimally, providing real-time alerts and reports on the monitored services' availability, downtime, and response time.
## Contributing
@@ -776,7 +772,7 @@ curl --request GET \
-GET /api/v1/monitor/{id}
+GET /api/v1/monitor/{id}?status
###### Method/Headers
@@ -785,6 +781,14 @@ curl --request GET \
> | Method | GET |
> | content-type | application/json |
+###### Query Params
+
+> | Name | Type | Required | Notes |
+> | --------- | --------- | -------- | ------------------------------------------------ |
+> | status | `boolean` | Optional | Check status |
+> | limit | `number` | Optional | Number of checks to return |
+> | sortOrder | `string` | Optional | `desc`:Newest -> Oldest, `asc`: Oldest -> Newest |
+
###### Response Payload
> | Type | Notes |
@@ -795,7 +799,7 @@ curl --request GET \
```
curl --request GET \
- --url http://localhost:5000/api/v1/monitors/664d070786e62625ac612ca1 \
+ --url http://localhost:5000/api/v1/monitors/664d070786e62625ac612ca1?status=true?limit=0 \
--header '' \
```
@@ -857,6 +861,15 @@ curl --request GET \
> | Method | GET |
> | content-type | application/json |
+###### Query Params
+
+> | Name | Type | Required | Notes |
+> | --------- | --------- | -------- | ------------------------------------------------- |
+> | status | `boolean` | Optional | Check status |
+> | type | `string` | Optional | Multiple allowed: `http` \| `ping` \| `pagespeed` |
+> | limit | `number` | Optional | Monitor status |
+> | sortOrder | `string` | Optional | `desc`:Newest -> Oldest, `asc`: Oldest -> Newest |
+
###### Response Payload
> | Type | Notes |
diff --git a/Server/controllers/monitorController.js b/Server/controllers/monitorController.js
index 1e3f3db4e..5e3899005 100644
--- a/Server/controllers/monitorController.js
+++ b/Server/controllers/monitorController.js
@@ -1,8 +1,10 @@
const {
- getMonitorByIdValidation,
+ getMonitorByIdParamValidation,
+ getMonitorByIdQueryValidation,
getMonitorsByUserIdValidation,
monitorValidation,
editMonitorBodyValidation,
+ getMonitorsByUserIdQueryValidation,
} = require("../validation/joi");
const SERVICE_NAME = "monitorController";
@@ -41,7 +43,8 @@ const getAllMonitors = async (req, res, next) => {
*/
const getMonitorById = async (req, res, next) => {
try {
- await getMonitorByIdValidation.validateAsync(req.params);
+ await getMonitorByIdParamValidation.validateAsync(req.params);
+ await getMonitorByIdQueryValidation.validateAsync(req.query);
} catch (error) {
error.status = 422;
error.message = error.details[0].message;
@@ -77,14 +80,9 @@ const getMonitorById = async (req, res, next) => {
* @throws {Error}
*/
const getMonitorsByUserId = async (req, res, next) => {
- const { error } = getMonitorsByUserIdValidation.validate(req.params);
- if (error) {
- return res
- .status(422)
- .json({ success: false, msg: error.details[0].message });
- }
-
try {
+ await getMonitorsByUserIdValidation.validateAsync(req.params);
+ await getMonitorsByUserIdQueryValidation.validateAsync(req.query);
const userId = req.params.userId;
const monitors = await req.db.getMonitorsByUserId(req, res);
@@ -99,60 +97,6 @@ const getMonitorsByUserId = async (req, res, next) => {
}
};
-/**
- * Returns monitor with matching ID and incidents
- * @async
- * @param {Express.Request} req
- * @param {Express.Response} res
- * @returns {Promise}
- * @throws {Error}
- */
-const getMonitorByIdForIncidents = async (req, res, next) => {
- try {
- await getMonitorByIdValidation.validateAsync(req.params);
-
- let monitorWithIncidents = await req.db.getMonitorByIdForIncidents(
- req,
- res
- );
-
- return res.json({
- success: true,
- msg: successMessages.MONTIOR_GET_BY_ID,
- data: monitorWithIncidents,
- });
- } catch (error) {
- error.service = SERVICE_NAME;
- next(error);
- }
-};
-
-/**
- * Returns all monitors with incidents that belong to User with UserID
- * @async
- * @param {Express.Request} req
- * @param {Express.Response} res
- * @returns {Promise}
- * @throws {Error}
- */
-const getMonitorsByUserIdForIncidents = async (req, res, next) => {
- try {
- await getMonitorsByUserIdValidation.validateAsync(req.params);
- let monitorsWithIncidents = await req.db.getMonitorsByUserIdForIncidents(
- req,
- res
- );
- return res.json({
- success: true,
- msg: successMessages.MONITOR_GET_BY_USER_ID(req.params.userId),
- data: monitorsWithIncidents,
- });
- } catch (error) {
- error.service = SERVICE_NAME;
- next(error);
- }
-};
-
/**
* Creates a new monitor
* @async
@@ -282,8 +226,6 @@ module.exports = {
getAllMonitors,
getMonitorById,
getMonitorsByUserId,
- getMonitorByIdForIncidents,
- getMonitorsByUserIdForIncidents,
createMonitor,
deleteMonitor,
deleteAllMonitors,
diff --git a/Server/db/mongo/modules/monitorModule.js b/Server/db/mongo/modules/monitorModule.js
index 694bcf745..a06ad9c05 100644
--- a/Server/db/mongo/modules/monitorModule.js
+++ b/Server/db/mongo/modules/monitorModule.js
@@ -1,6 +1,6 @@
const Monitor = require("../../../models/Monitor");
const Check = require("../../../models/Check");
-
+const PageSpeedCheck = require("../../../models/PageSpeedCheck");
const { errorMessages } = require("../../../utils/messages");
/**
@@ -30,10 +30,40 @@ const getAllMonitors = async (req, res) => {
*/
const getMonitorById = async (req, res) => {
try {
- const monitor = await Monitor.findById(req.params.monitorId);
- const checks = await Check.find({ monitorId: monitor._id }).sort({
- createdAt: 1,
- });
+
+ const { monitorId } = req.params;
+ let { status, limit, sortOrder } = req.query;
+
+ // This effectively removes limit, returning all checks
+ if (limit === undefined) limit = 0;
+
+ // Default sort order is newest -> oldest
+ if (sortOrder === "asc") {
+ sortOrder = 1;
+ } else if (sortOrder === "desc") {
+ sortOrder = -1;
+ } else sortOrder = -1;
+
+ const monitor = await Monitor.findById(monitorId);
+
+ const checksQuery = { monitorId: monitor._id };
+
+ if (status !== undefined) {
+ checksQuery.status = status;
+ }
+
+ // Determine model type
+ let model =
+ monitor.type === "http" || monitor.type === "ping"
+ ? Check
+ : PageSpeedCheck;
+
+ const checks = await model
+ .find(checksQuery)
+ .sort({
+ createdAt: sortOrder,
+ })
+ .limit(limit);
const monitorWithChecks = { ...monitor.toObject(), checks };
return monitorWithChecks;
} catch (error) {
@@ -51,79 +81,45 @@ const getMonitorById = async (req, res) => {
*/
const getMonitorsByUserId = async (req, res) => {
try {
- const limit = req.query ? req.query.limit : undefined;
- const monitors = await Monitor.find({ userId: req.params.userId });
- console.log("monitors", monitors);
+ let { limit, type, status, sortOrder } = req.query;
+ const monitorQuery = { userId: req.params.userId };
+
+ if (type !== undefined) {
+ const types = Array.isArray(type) ? type : [type];
+ monitorQuery.type = { $in: types };
+ }
+
+ // Default sort order is newest -> oldest
+ if (sortOrder === "asc") {
+ sortOrder = 1;
+ } else if (sortOrder === "desc") {
+ sortOrder = -1;
+ } else sortOrder = -1;
+
+ // This effectively removes limit, returning all checks
+ if (limit === undefined) limit = 0;
+
+ const monitors = await Monitor.find(monitorQuery);
// Map each monitor to include its associated checks
const monitorsWithChecks = await Promise.all(
monitors.map(async (monitor) => {
- if (limit) {
- // Checks are order newest -> oldest
- const checks = await Check.find({ monitorId: monitor._id })
- .sort({
- createdAt: -1,
- })
- .limit(limit);
- return { ...monitor.toObject(), checks };
- } else {
- const checks = await Check.find({ monitorId: monitor._id }).sort({
- createdAt: -1,
- });
- return { ...monitor.toObject(), checks };
+ const checksQuery = { monitorId: monitor._id };
+ if (status !== undefined) {
+ checksQuery.status = status;
}
- })
- );
- return monitorsWithChecks;
- } catch (error) {
- throw error;
- }
-};
+ let model =
+ monitor.type === "http" || monitor.type === "ping"
+ ? Check
+ : PageSpeedCheck;
-/**
- * Get monitors by UserID
- * @async
- * @param {Express.Request} req
- * @param {Express.Response} res
- * @returns {Promise}
- * @throws {Error}
- */
-const getMonitorByIdForIncidents = async (req, res, next) => {
- try {
- const monitor = await Monitor.findById(req.params.monitorId);
- const checks = await Check.find({
- monitorId: monitor._id,
- status: false,
- }).sort({
- createdAt: 1,
- });
- const monitorWithChecks = { ...monitor.toObject(), checks };
- return monitorWithChecks;
- } catch (error) {
- throw error;
- }
-};
-
-/**
- * Get monitors by UserID
- * @async
- * @param {Express.Request} req
- * @param {Express.Response} res
- * @returns {Promise>}
- * @throws {Error}
- */
-const getMonitorsByUserIdForIncidents = async (req, res) => {
- try {
- const monitors = await Monitor.find({ userId: req.params.userId });
- // Map each monitor to include its associated checks
- const monitorsWithChecks = await Promise.all(
- monitors.map(async (monitor) => {
- const checks = await Check.find({
- monitorId: monitor._id,
- status: false,
- }).sort({
- createdAt: 1,
- });
+ // Checks are order newest -> oldest
+ const checks = await model
+ .find(checksQuery)
+ .sort({
+ createdAt: sortOrder,
+ })
+ .limit(limit);
return { ...monitor.toObject(), checks };
})
);
@@ -228,8 +224,6 @@ module.exports = {
getAllMonitors,
getMonitorById,
getMonitorsByUserId,
- getMonitorByIdForIncidents,
- getMonitorsByUserIdForIncidents,
createMonitor,
deleteMonitor,
deleteAllMonitors,
diff --git a/Server/db/mongo/modules/pageSpeedCheckModule.js b/Server/db/mongo/modules/pageSpeedCheckModule.js
index 77f076311..65376a324 100644
--- a/Server/db/mongo/modules/pageSpeedCheckModule.js
+++ b/Server/db/mongo/modules/pageSpeedCheckModule.js
@@ -14,7 +14,7 @@ const PageSpeedCheck = require("../../../models/PageSpeedCheck");
*/
const createPageSpeedCheck = async (pageSpeedCheckData) => {
try {
- const pageSpeedCheck = await new pageSpeedCheck({
+ const pageSpeedCheck = await new PageSpeedCheck({
...pageSpeedCheckData,
}).save();
return pageSpeedCheck;
diff --git a/Server/routes/monitorRoute.js b/Server/routes/monitorRoute.js
index 9ba703244..ae7a5852e 100644
--- a/Server/routes/monitorRoute.js
+++ b/Server/routes/monitorRoute.js
@@ -7,15 +7,6 @@ router.get("/", monitorController.getAllMonitors);
router.get("/:monitorId", monitorController.getMonitorById);
router.get("/user/:userId", monitorController.getMonitorsByUserId);
-router.get(
- "/incidents/:monitorId",
- monitorController.getMonitorByIdForIncidents
-);
-router.get(
- "/incidents/user/:userId",
- monitorController.getMonitorsByUserIdForIncidents
-);
-
router.post("/", monitorController.createMonitor);
router.post(
"/delete/:monitorId",
diff --git a/Server/service/networkService.js b/Server/service/networkService.js
index 0ed093e8c..0ee65c424 100644
--- a/Server/service/networkService.js
+++ b/Server/service/networkService.js
@@ -189,6 +189,7 @@ class NetworkService {
const insertedCheck = await writeToDB(data);
return insertedCheck.status;
} catch (error) {
+ console.log(error);
logger.error(`Error wrtiting check for ${data.monitorId}`, {
service: this.SERVICE_NAME,
monitorId: data.monitorId,
diff --git a/Server/validation/joi.js b/Server/validation/joi.js
index ffb9a3f6e..704ac7cb4 100644
--- a/Server/validation/joi.js
+++ b/Server/validation/joi.js
@@ -118,14 +118,32 @@ const inviteVerifciationBodyValidation = joi.object({
// Monitors
//****************************************
-const getMonitorByIdValidation = joi.object({
+const getMonitorByIdParamValidation = joi.object({
monitorId: joi.string().required(),
});
+const getMonitorByIdQueryValidation = joi.object({
+ status: joi.boolean(),
+ sortOrder: joi.string().valid("asc", "desc"),
+ limit: joi.number(),
+});
+
const getMonitorsByUserIdValidation = joi.object({
userId: joi.string().required(),
});
+const getMonitorsByUserIdQueryValidation = joi.object({
+ status: joi.boolean(),
+ sortOrder: joi.string().valid("asc", "desc"),
+ limit: joi.number(),
+ type: joi
+ .alternatives()
+ .try(
+ joi.string().valid("http", "ping", "pagespeed"),
+ joi.array().items(joi.string().valid("http", "ping", "pagespeed"))
+ ),
+});
+
const monitorValidation = joi.object({
_id: joi.string(),
userId: joi.string().required(),
@@ -244,9 +262,10 @@ module.exports = {
inviteRoleValidation,
inviteBodyValidation,
inviteVerifciationBodyValidation,
- getMonitorByIdValidation,
+ getMonitorByIdParamValidation,
+ getMonitorByIdQueryValidation,
getMonitorsByUserIdValidation,
- monitorValidation,
+ getMonitorsByUserIdQueryValidation,
editMonitorBodyValidation,
editUserParamValidation,
editUserBodyValidation,