From 345c5c63eb53c775ee27609a8f7b2114ce923237 Mon Sep 17 00:00:00 2001 From: Dave Date: Sun, 26 Jul 2020 17:38:52 +0100 Subject: [PATCH 01/13] feat: add logging control to system settings --- .../api/applications/getSingleApplicationLog.test.js | 2 +- __test__/middleware/requestLogger.test.js | 10 +++++----- middleware/requestLogger.js | 4 ++-- models/systemSettings.js | 5 +++++ settingAndVariables.txt | 2 +- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/__test__/api/applications/getSingleApplicationLog.test.js b/__test__/api/applications/getSingleApplicationLog.test.js index f09fd51..a34fa73 100644 --- a/__test__/api/applications/getSingleApplicationLog.test.js +++ b/__test__/api/applications/getSingleApplicationLog.test.js @@ -9,7 +9,7 @@ describe("Get single application logs", () => { let app, request; it("should return all logs for a given application", async () => { - process.env.LOGGING_ENABLED = true; + process.env.loggingEnabled = true; //create express app app = express(); diff --git a/__test__/middleware/requestLogger.test.js b/__test__/middleware/requestLogger.test.js index 5bd5f4e..b115aa9 100644 --- a/__test__/middleware/requestLogger.test.js +++ b/__test__/middleware/requestLogger.test.js @@ -43,7 +43,7 @@ describe("Logger middleware", () => { let app, request; it("logging is system-enabled and app-enabled for all requests", async () => { - process.env.LOGGING_ENABLED = true; + process.env.loggingEnabled = true; app = express(); app.use((req, res, next) => { const logging = { @@ -79,7 +79,7 @@ describe("Logger middleware", () => { }); it("logging is system-disabled", async () => { - process.env.LOGGING_ENABLED = false; + process.env.loggingEnabled = false; app = express(); app.use((req, res, next) => { const logging = { @@ -115,7 +115,7 @@ describe("Logger middleware", () => { }); it("logging is not available for application", async () => { - process.env.LOGGING_ENABLED = true; + process.env.loggingEnabled = true; app = express(); app.use((req, res, next) => { const logging = {}; @@ -151,7 +151,7 @@ describe("Logger middleware", () => { }); it("logging is system-enabled and app-enabled for all requests but skipped status 400", async () => { - process.env.LOGGING_ENABLED = true; + process.env.loggingEnabled = true; app = express(); app.use((req, res, next) => { const logging = { @@ -207,7 +207,7 @@ describe("Logger middleware", () => { }); it("logging is system-disabled when env variable is undefined", async () => { - process.env.LOGGING_ENABLED = ""; + process.env.loggingEnabled = ""; app = express(); app.use((req, res, next) => { const logging = { diff --git a/middleware/requestLogger.js b/middleware/requestLogger.js index 117ac90..0889f10 100644 --- a/middleware/requestLogger.js +++ b/middleware/requestLogger.js @@ -36,8 +36,8 @@ exports.requestLogger = (req, res, next) => { res.on("finish", () => { // check if logging is enabled globally - const loggingEnabled = process.env.LOGGING_ENABLED - ? process.env.LOGGING_ENABLED.toLowerCase() === "true" + const loggingEnabled = process.env.loggingEnabled + ? process.env.loggingEnabled.toLowerCase() === "true" : false; try { diff --git a/models/systemSettings.js b/models/systemSettings.js index 6c868fd..20560d2 100644 --- a/models/systemSettings.js +++ b/models/systemSettings.js @@ -29,6 +29,11 @@ const SystemSettingsSchema = new Schema( required: true, default: false, }, + loggingEnabled: { + type: Boolean, + required: true, + default: true, + }, }, { timestamps: true, diff --git a/settingAndVariables.txt b/settingAndVariables.txt index 412a01b..130a4db 100644 --- a/settingAndVariables.txt +++ b/settingAndVariables.txt @@ -20,7 +20,7 @@ SYSTEM SETTINGS [appear as ENV VARS at runtime] - maxRequestsPerMin - global max request rate to prevent DDoS and abuse, even plans cant exceed - defaultMaxRequestsPerDay - for making requests without plan (might be shelved in favor of application default plan) - disableRequestLimits - Disable all limiting, majorly for testing purposes only or open systems - - LOGGING_ENABLED - globally disable logging (make camel-case) + - LOGGING_ENABLED - now loggingEnabled - globally disable logging (make camel-case) - maxItemsPerpage - max items per request page - defaultItemsPerPage - default items per page when not set - logPageSize - The size of records from log From a6eee9cf7c8aea5e49d5b7e49d2990817e091ed4 Mon Sep 17 00:00:00 2001 From: Dave Date: Sun, 26 Jul 2020 17:52:42 +0100 Subject: [PATCH 02/13] fix: update systemSettings test --- __test__/api/msadmins/settings/updateSystemSettings.test.js | 4 ++++ models/systemSettings.js | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/__test__/api/msadmins/settings/updateSystemSettings.test.js b/__test__/api/msadmins/settings/updateSystemSettings.test.js index edefc85..f6b763a 100644 --- a/__test__/api/msadmins/settings/updateSystemSettings.test.js +++ b/__test__/api/msadmins/settings/updateSystemSettings.test.js @@ -21,6 +21,8 @@ describe("PATCH /msAdmins/settings", () => { maxItemsPerPage: 50, defaultMaxRequestsPerDay: 10000, disableRequestLimits: false, + loggingEnabled: true, + logPageSize: 100, }; let res = await request @@ -46,6 +48,8 @@ describe("PATCH /msAdmins/settings", () => { maxItemsPerPage: 20, defaultMaxRequestsPerDay: 10000, disableRequestLimits: false, + loggingEnabled: true, + logPageSize: 100, }; //check for update also in same process because this is a single document collection diff --git a/models/systemSettings.js b/models/systemSettings.js index 20560d2..db3d02d 100644 --- a/models/systemSettings.js +++ b/models/systemSettings.js @@ -34,6 +34,11 @@ const SystemSettingsSchema = new Schema( required: true, default: true, }, + logPageSize: { + type: Number, + required: true, + default: 100, + }, }, { timestamps: true, From f380699b1209ffe43d9df1f373ce51d69097c3ca Mon Sep 17 00:00:00 2001 From: Dave Date: Sun, 26 Jul 2020 22:07:46 +0100 Subject: [PATCH 03/13] feat: create utility to paginate deleted records --- __test__/utils/paginateDeleted.test.js | 52 ++++++++++++++++++ utils/paginateDeleted.js | 73 ++++++++++++++++++++++++++ utils/softDelete.js | 12 +++++ 3 files changed, 137 insertions(+) create mode 100644 __test__/utils/paginateDeleted.test.js create mode 100644 utils/paginateDeleted.js diff --git a/__test__/utils/paginateDeleted.test.js b/__test__/utils/paginateDeleted.test.js new file mode 100644 index 0000000..4491640 --- /dev/null +++ b/__test__/utils/paginateDeleted.test.js @@ -0,0 +1,52 @@ +const { paginateDeleted } = require("../../utils/paginateDeleted"); +const softDelete = require("../../utils/softDelete"); +const MsAdmin = require("../../models/msadmins"); + +describe("Paginete soft-deleted records", () => { + let msAdmin, + idsArray = []; + beforeAll(async () => { + //create dummy records and softDelete them + for (let index = 0; index < 20; index++) { + msAdmin = new MsAdmin({ + fullname: "admin1", + email: `admin${Date.now()}@domain.com`, + password: "some password", + }); + await msAdmin.save(); + + idsArray.push(msAdmin.id); + + //soft delete + if ((index + 2) % 2 === 0) { + await softDelete.deleteById(MsAdmin, msAdmin.id, global.msAdmin.id); + } + } + }); + + afterAll(async () => { + for (let index = 0; index < idsArray.length; index++) { + const msAdminId = idsArray[index]; + await softDelete.restoreById(MsAdmin, msAdminId); + await MsAdmin.findByIdAndDelete(msAdminId); + } + }); + + it("should get all deleted records", async () => { + const deletedAdmins = await paginateDeleted(MsAdmin, "deleted", {}, 5, 1); + expect(deletedAdmins.totalRecords).toEqual(10); + }); + + it("should get all undeleted records", async () => { + const unDeleted = await paginateDeleted(MsAdmin, "unDeleted", {}, 5, 1); + console.log(unDeleted); + expect(unDeleted.totalRecords).toEqual(12); + }); + + it("should get all records", async () => { + const allAdmins = await paginateDeleted(MsAdmin, "all", {}, 5, 1); + expect(allAdmins.totalRecords).toEqual(22); + }); + + //retrieve the deleted records by page +}); diff --git a/utils/paginateDeleted.js b/utils/paginateDeleted.js new file mode 100644 index 0000000..63e0cf8 --- /dev/null +++ b/utils/paginateDeleted.js @@ -0,0 +1,73 @@ +exports.paginateDeleted = async (Model, findFilter, query, limit, page) => { + let currentPage, + totalPages, + hasNext, + hasPrev, + nextPage, + prevPage, + pageRecordCount, + totalRecords, + documents; + + //get total documents in collection + if (findFilter === "unDeleted") { + totalRecords = await Model.countDocuments(query); + } else if (findFilter === "deleted") { + totalRecords = await Model.countDocumentsDeleted(query); + } else if (findFilter === "all") { + totalRecords = await Model.countDocumentsWithDeleted(query); + } else { + //throw an error here + throw new Error("Invalid 'findFilter' specified"); + } + + //divide total by limit(round up) to get number of pages + totalPages = Math.ceil(totalRecords / limit); + + //if requested page is greater than last page return last page with + currentPage = page; + + hasNext = true; + hasPrev = true; + nextPage = page + 1; + prevPage = page - 1; + + if (page >= totalPages) { + currentPage = totalPages; + hasNext = false; + nextPage = null; + } + + if (page <= 1) { + page = 1; + hasPrev = false; + prevPage = null; + } + + const skipCount = limit * (currentPage - 1); + + //skip (limit * page - 1) records and get limit records + let result; + if (findFilter === "unDeleted") { + result = await Model.find(query).skip(skipCount).limit(limit); + } else if (findFilter === "deleted") { + result = await Model.findDeleted(query).skip(skipCount).limit(limit); + } else if (findFilter === "all") { + result = await Model.findWithDeleted(query).skip(skipCount).limit(limit); + } + + pageRecordCount = result.length; + documents = result; + + return { + currentPage, + totalPages, + hasNext, + hasPrev, + nextPage, + prevPage, + pageRecordCount, + totalRecords, + documents, + }; +}; diff --git a/utils/softDelete.js b/utils/softDelete.js index 5b26788..a0e9ecf 100644 --- a/utils/softDelete.js +++ b/utils/softDelete.js @@ -1,3 +1,5 @@ +const { paginateDeleted } = require("./paginateDeleted"); + exports.deleteById = async (Model, targetDocId, deletedById) => { const targetDoc = await Model.findById(targetDocId); if (!targetDoc) { @@ -27,3 +29,13 @@ exports.restoreById = async (Model, targetDocId) => { }); }); }; + +exports.getDeletedRecords = async (Model, findFilter, page = 1, limit = 20) => { + //get disabled records + return paginateDeleted(Model, "deleted", {}, limit, page); +}; + +exports.getAllRecords = async (Model, findFilter, page = 1, limit = 20) => { + //get disabled records + return paginateDeleted(Model, "all", {}, limit, page); +}; From 7c9c9a00c0cc27640535afd9b45784fa4c8ff882 Mon Sep 17 00:00:00 2001 From: Dave Date: Mon, 27 Jul 2020 06:03:00 +0100 Subject: [PATCH 04/13] feat: add softdelete pagination to getAllMsAdmins --- __test__/api/msadmins/getAllMsAdmins.test.js | 43 +++++++++++++++++++ __test__/utils/paginateDeleted.test.js | 31 ++++++++++--- .../msAdminsController/getAllMsAdmins.js | 13 +++++- utils/auth/tokenGenerator.js | 2 +- utils/paginateDeleted.js | 14 +++--- utils/softDelete.js | 6 +-- 6 files changed, 90 insertions(+), 19 deletions(-) diff --git a/__test__/api/msadmins/getAllMsAdmins.test.js b/__test__/api/msadmins/getAllMsAdmins.test.js index cfcbd70..159d69e 100644 --- a/__test__/api/msadmins/getAllMsAdmins.test.js +++ b/__test__/api/msadmins/getAllMsAdmins.test.js @@ -2,6 +2,7 @@ const app = require("../../../server"); const supertest = require("supertest"); const MsAdmin = require("../../../models/msadmins"); const request = supertest(app); +const { deleteById, restoreById } = require("../../../utils/softDelete"); // Cached admin and allMsAdminsResponse. let msAdmin, msAdmin2, msAdmin3, allMsAdminsResponse; @@ -179,4 +180,46 @@ describe("GET /msAdmins", () => { expect(res.body.status).toEqual("error"); expect(res.body.data).toEqual([]); }); + + it("Should get all disabled microservice admins with all pagination params set", async () => { + const url = `/v1/msAdmins`; + const bearerToken = `bearer ${global.superSysToken}`; + + //disable one admin + await deleteById(MsAdmin, msAdmin2.id, global.msSuperAdmin.id); + + const res = await request + .get(url) + .query({ limit: 3, page: 1, sort: "asc", filter: "disabled" }) + .set("Authorization", bearerToken); + + // const expectedValue = allMsAdminsResponse.slice(0, 1); + + expect(res.status).toEqual(200); + expect(res.body.status).toEqual("success"); + expect(res.body.data.records.length).toEqual(1); + + await restoreById(MsAdmin, msAdmin2.Id); + }); + + it("Should get both disabled/enabled microservice admins with all pagination params set", async () => { + const url = `/v1/msAdmins`; + const bearerToken = `bearer ${global.superSysToken}`; + + //disable one admin + await deleteById(MsAdmin, msAdmin2.id, global.msSuperAdmin.id); + + const res = await request + .get(url) + .query({ limit: 3, page: 1, sort: "asc", filter: "all" }) + .set("Authorization", bearerToken); + + // const expectedValue = allMsAdminsResponse.slice(0, 1); + + expect(res.status).toEqual(200); + expect(res.body.status).toEqual("success"); + expect(res.body.data.records.length).toEqual(3); + + await restoreById(MsAdmin, msAdmin2.Id); + }); }); diff --git a/__test__/utils/paginateDeleted.test.js b/__test__/utils/paginateDeleted.test.js index 4491640..a4df5ac 100644 --- a/__test__/utils/paginateDeleted.test.js +++ b/__test__/utils/paginateDeleted.test.js @@ -9,7 +9,7 @@ describe("Paginete soft-deleted records", () => { //create dummy records and softDelete them for (let index = 0; index < 20; index++) { msAdmin = new MsAdmin({ - fullname: "admin1", + fullname: "paginateDeleteTest", email: `admin${Date.now()}@domain.com`, password: "some password", }); @@ -33,19 +33,36 @@ describe("Paginete soft-deleted records", () => { }); it("should get all deleted records", async () => { - const deletedAdmins = await paginateDeleted(MsAdmin, "deleted", {}, 5, 1); + const deletedAdmins = await paginateDeleted( + MsAdmin, + "disabled", + { fullname: "paginateDeleteTest" }, + 5, + 1 + ); expect(deletedAdmins.totalRecords).toEqual(10); }); it("should get all undeleted records", async () => { - const unDeleted = await paginateDeleted(MsAdmin, "unDeleted", {}, 5, 1); - console.log(unDeleted); - expect(unDeleted.totalRecords).toEqual(12); + const unDeleted = await paginateDeleted( + MsAdmin, + "enabled", + { fullname: "paginateDeleteTest" }, + 5, + 1 + ); + expect(unDeleted.totalRecords).toEqual(10); }); it("should get all records", async () => { - const allAdmins = await paginateDeleted(MsAdmin, "all", {}, 5, 1); - expect(allAdmins.totalRecords).toEqual(22); + const allAdmins = await paginateDeleted( + MsAdmin, + "all", + { fullname: "paginateDeleteTest" }, + 5, + 1 + ); + expect(allAdmins.totalRecords).toEqual(20); }); //retrieve the deleted records by page diff --git a/controllers/msAdminsController/getAllMsAdmins.js b/controllers/msAdminsController/getAllMsAdmins.js index 24a3575..104b8a4 100644 --- a/controllers/msAdminsController/getAllMsAdmins.js +++ b/controllers/msAdminsController/getAllMsAdmins.js @@ -1,6 +1,7 @@ const MsAdmin = require("../../models/msadmins"); const CustomError = require("../../utils/customError"); const responseHandler = require("../../utils/responseHandler"); +const { getAllRecords, getDeletedRecords } = require("../../utils/softDelete"); /** * @author David Okanlawon @@ -14,11 +15,20 @@ const responseHandler = require("../../utils/responseHandler"); const getAllMsAdmins = async (req, res, next) => { //get all admins mapping the field names appropriately let admins, allMsAdmins; + const { filter } = req.query; let query = {}; + const { page, limit } = req.paginateOptions; try { - admins = await MsAdmin.paginate(query, req.paginateOptions); + if (filter === "disabled") { + admins = await getDeletedRecords(MsAdmin, page, limit); + } else if (filter === "all") { + admins = await getAllRecords(MsAdmin, page, limit); + } else { + admins = await MsAdmin.paginate(query, req.paginateOptions); + } + allMsAdmins = admins.docs.map((admin) => { return { msAdminId: admin._id, @@ -28,6 +38,7 @@ const getAllMsAdmins = async (req, res, next) => { }; }); } catch (error) { + console.log(error.message); next(new CustomError(400, "An error occured retrieving admin accounts")); return; } diff --git a/utils/auth/tokenGenerator.js b/utils/auth/tokenGenerator.js index 33e24f9..fdaf492 100644 --- a/utils/auth/tokenGenerator.js +++ b/utils/auth/tokenGenerator.js @@ -102,7 +102,7 @@ const getSysToken = async (msAdminId) => { // confirm adminId exists const msAdmin = await MsAdmin.findById(msAdminId); if (!msAdmin) { - console.log(msAdminId, msAdmin); + // console.log(msAdminId, msAdmin); throw new CustomError( 401, "You are not authorized to access this resource" diff --git a/utils/paginateDeleted.js b/utils/paginateDeleted.js index 63e0cf8..45fb800 100644 --- a/utils/paginateDeleted.js +++ b/utils/paginateDeleted.js @@ -7,12 +7,12 @@ exports.paginateDeleted = async (Model, findFilter, query, limit, page) => { prevPage, pageRecordCount, totalRecords, - documents; + docs; //get total documents in collection - if (findFilter === "unDeleted") { + if (findFilter === "enabled") { totalRecords = await Model.countDocuments(query); - } else if (findFilter === "deleted") { + } else if (findFilter === "disabled") { totalRecords = await Model.countDocumentsDeleted(query); } else if (findFilter === "all") { totalRecords = await Model.countDocumentsWithDeleted(query); @@ -48,16 +48,16 @@ exports.paginateDeleted = async (Model, findFilter, query, limit, page) => { //skip (limit * page - 1) records and get limit records let result; - if (findFilter === "unDeleted") { + if (findFilter === "enabled") { result = await Model.find(query).skip(skipCount).limit(limit); - } else if (findFilter === "deleted") { + } else if (findFilter === "disabled") { result = await Model.findDeleted(query).skip(skipCount).limit(limit); } else if (findFilter === "all") { result = await Model.findWithDeleted(query).skip(skipCount).limit(limit); } pageRecordCount = result.length; - documents = result; + docs = result; return { currentPage, @@ -68,6 +68,6 @@ exports.paginateDeleted = async (Model, findFilter, query, limit, page) => { prevPage, pageRecordCount, totalRecords, - documents, + docs, }; }; diff --git a/utils/softDelete.js b/utils/softDelete.js index a0e9ecf..263cf2f 100644 --- a/utils/softDelete.js +++ b/utils/softDelete.js @@ -30,12 +30,12 @@ exports.restoreById = async (Model, targetDocId) => { }); }; -exports.getDeletedRecords = async (Model, findFilter, page = 1, limit = 20) => { +exports.getDeletedRecords = async (Model, page = 1, limit = 20) => { //get disabled records - return paginateDeleted(Model, "deleted", {}, limit, page); + return paginateDeleted(Model, "disabled", {}, limit, page); }; -exports.getAllRecords = async (Model, findFilter, page = 1, limit = 20) => { +exports.getAllRecords = async (Model, page = 1, limit = 20) => { //get disabled records return paginateDeleted(Model, "all", {}, limit, page); }; From 4c1ca8063a045018870d8ecff577d87a888f6ecf Mon Sep 17 00:00:00 2001 From: Dave Date: Tue, 28 Jul 2020 05:58:20 +0100 Subject: [PATCH 05/13] feat: add isBlocked/isDisabled field to queries --- __test__/api/msadmins/getAllMsAdmins.test.js | 3 ++ .../applications/getAllApplications.js | 24 +++++++++++--- .../applications/getSingleApplication.js | 22 +++---------- .../msAdminsController/getAllMsAdmins.js | 1 + .../msAdminsController/getSingleMsAdmin.js | 3 +- .../organizations/getAllOrganizations.js | 33 ++++++++++++++++--- .../organizations/getSingleOrganization.js | 8 +++-- 7 files changed, 64 insertions(+), 30 deletions(-) diff --git a/__test__/api/msadmins/getAllMsAdmins.test.js b/__test__/api/msadmins/getAllMsAdmins.test.js index 159d69e..2ddb95d 100644 --- a/__test__/api/msadmins/getAllMsAdmins.test.js +++ b/__test__/api/msadmins/getAllMsAdmins.test.js @@ -45,18 +45,21 @@ describe("GET /msAdmins", () => { fullname: msAdmin.fullname, email: msAdmin.email, role: msAdmin.role, + isDisabled: false, }, { msAdminId: msAdmin2.id, fullname: msAdmin2.fullname, email: msAdmin2.email, role: msAdmin2.role, + isDisabled: false, }, { msAdminId: msAdmin3.id, fullname: msAdmin3.fullname, email: msAdmin3.email, role: msAdmin3.role, + isDisabled: false, }, ]; }); diff --git a/controllers/msAdminsController/applications/getAllApplications.js b/controllers/msAdminsController/applications/getAllApplications.js index 064a4cf..fc0b647 100644 --- a/controllers/msAdminsController/applications/getAllApplications.js +++ b/controllers/msAdminsController/applications/getAllApplications.js @@ -2,6 +2,10 @@ const Applications = require("../../../models/applications"); const MsAdmin = require("../../../models/msadmins"); const CustomError = require("../../../utils/customError"); const responseHandler = require("../../../utils/responseHandler"); +const { + getAllRecords, + getDeletedRecords, +} = require("../../../utils/softDelete"); /** * @author Ekeyekwu Oscar @@ -20,6 +24,7 @@ const getAllApplications = async (req, res, next) => { let allApplications; let query = {}; + const { page, limit } = req.paginateOptions; try { //check if msAdmin exists @@ -29,11 +34,21 @@ const getAllApplications = async (req, res, next) => { return; } + const { filter } = req.query; + //get all applications - const applications = await Applications.paginate(query, { - ...req.paginateOptions, - populate: "organizationId", - }); + let applications; + + if (filter === "disabled") { + applications = await getDeletedRecords(Applications, page, limit); + } else if (filter === "all") { + applications = await getAllRecords(Applications, page, limit); + } else { + applications = await Applications.paginate(query, { + ...req.paginateOptions, + populate: "organizationId", + }); + } allApplications = applications.docs.map((application) => { return { @@ -41,6 +56,7 @@ const getAllApplications = async (req, res, next) => { applicationName: application.name, organizationId: application.organizationId, organizationName: application.organizationId.name, + isBlocked: application.deleted || false, }; }); diff --git a/controllers/msAdminsController/applications/getSingleApplication.js b/controllers/msAdminsController/applications/getSingleApplication.js index bcf9c3e..8958057 100644 --- a/controllers/msAdminsController/applications/getSingleApplication.js +++ b/controllers/msAdminsController/applications/getSingleApplication.js @@ -29,35 +29,21 @@ const getSingleApplication = async (req, res, next) => { } //get applications - const singleApplication = await Applications.findById( - applicationId - ).populate("organizationId"); + const singleApplication = await Applications.findOneWithDeleted({ + _id: applicationId, + }).populate("organizationId"); if (!singleApplication) { next(new CustomError(404, "Application not Found")); return; } - // let commentsCount, repliesCount; - // const comments = await CommentModel.find({applicationId:applicationId}); - // console.log(comments) - // if (!comments || comments === []) { - // commentsCount = 0; - // repliesCount = 0; - // } else { - // commentsCount = comments.records.length; - // repliesCount = comments.records.reduce((acc, curr) => { - // return acc + curr.numOfReplies; - // }, 0); - // } - // console.log(commentsCount, repliesCount); application = { applicationId: singleApplication._id, applicationName: singleApplication.name, organizationId: singleApplication.organizationId, organizationName: singleApplication.organizationId.name, - // totalNumOfComments: commentsCount, - // totalNumOfReplies: repliesCount, + isBlocked: singleApplication.deleted || false, }; } catch (error) { next(new CustomError(400, "An error occured retrieving Application")); diff --git a/controllers/msAdminsController/getAllMsAdmins.js b/controllers/msAdminsController/getAllMsAdmins.js index 104b8a4..927cc5b 100644 --- a/controllers/msAdminsController/getAllMsAdmins.js +++ b/controllers/msAdminsController/getAllMsAdmins.js @@ -35,6 +35,7 @@ const getAllMsAdmins = async (req, res, next) => { fullname: admin.fullname, email: admin.email, role: admin.role, + isDisabled: admin.deleted || false, }; }); } catch (error) { diff --git a/controllers/msAdminsController/getSingleMsAdmin.js b/controllers/msAdminsController/getSingleMsAdmin.js index bbb3011..b4d7797 100644 --- a/controllers/msAdminsController/getSingleMsAdmin.js +++ b/controllers/msAdminsController/getSingleMsAdmin.js @@ -16,7 +16,7 @@ const getSingleMsAdmin = async (req, res, next) => { //get msAdmin account try { - const msAdmin = await MsAdmin.findById(msAdminId); + const msAdmin = await MsAdmin.findOneWithDeleted({ _id: msAdminId }); if (!msAdmin) { next(new CustomError(404, "MsAdmin account not found")); return; @@ -25,6 +25,7 @@ const getSingleMsAdmin = async (req, res, next) => { fullname: msAdmin.fullname, email: msAdmin.email, role: msAdmin.role, + isDisabled: msAdmin.deleted || false, }; return responseHandler( diff --git a/controllers/msAdminsController/organizations/getAllOrganizations.js b/controllers/msAdminsController/organizations/getAllOrganizations.js index ad615f1..8fbb462 100644 --- a/controllers/msAdminsController/organizations/getAllOrganizations.js +++ b/controllers/msAdminsController/organizations/getAllOrganizations.js @@ -1,6 +1,11 @@ const OrganizationsModel = require("../../../models/organizations"); +const MsAdmin = require("../../../models/msadmins"); const CustomError = require("../../../utils/customError"); const responseHandler = require("../../../utils/responseHandler"); +const { + getAllRecords, + getDeletedRecords, +} = require("../../../utils/softDelete"); /** * @author Ekeyekwu Oscar @@ -15,19 +20,39 @@ const getAllOrganizations = async (req, res, next) => { //get all organizations and map field names appropriately let allOrganizations; + //get msAdminId from token + const { msAdminId } = req.token; + + //check if msAdmin exists + const msAdmin = await MsAdmin.findById(msAdminId); + if (!msAdmin) { + next(new CustomError(404, "MsAdmin account not found")); + return; + } + let query = {}; + const { page, limit } = req.paginateOptions; + const { filter } = req.query; + try { //get all organizations - const organizations = await OrganizationsModel.paginate( - query, - req.paginateOptions - ); + let organizations; + if (filter === "disabled") { + organizations = await getDeletedRecords(OrganizationsModel, page, limit); + } else if (filter === "all") { + organizations = await getAllRecords(OrganizationsModel, page, limit); + } else { + organizations = await OrganizationsModel.paginate(query, { + ...req.paginateOptions, + }); + } allOrganizations = organizations.docs.map((organization) => { return { organizationId: organization._id, organizationName: organization.name, + isBlocked: organization.deleted || false, }; }); diff --git a/controllers/msAdminsController/organizations/getSingleOrganization.js b/controllers/msAdminsController/organizations/getSingleOrganization.js index ef132a7..f9fa072 100644 --- a/controllers/msAdminsController/organizations/getSingleOrganization.js +++ b/controllers/msAdminsController/organizations/getSingleOrganization.js @@ -29,9 +29,9 @@ const getSingleOrganization = async (req, res, next) => { } //get organizations - const singleOrganization = await OrganizationsModel.findById( - organizationId - ); + const singleOrganization = await OrganizationsModel.findOneWithDeleted({ + _id: organizationId, + }); if (!singleOrganization) { next(new CustomError(404, "Organization not Found")); @@ -41,6 +41,8 @@ const getSingleOrganization = async (req, res, next) => { organization = { organizationId: singleOrganization._id, organizationName: singleOrganization.name, + organizationEmail: singleOrganization.email, + isBlocked: singleOrganization.deleted || false, }; } catch (error) { next(new CustomError(400, "An error occured retrieving organization")); From 7d19263ade3527db888e9b740dc3709f6a0feb8d Mon Sep 17 00:00:00 2001 From: Dave Date: Tue, 28 Jul 2020 06:06:45 +0100 Subject: [PATCH 06/13] fix: add await keyword in getSingleApplicationLog --- controllers/applicationsController/getSingleApplicationLog.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/controllers/applicationsController/getSingleApplicationLog.js b/controllers/applicationsController/getSingleApplicationLog.js index 9f9dade..ce36368 100644 --- a/controllers/applicationsController/getSingleApplicationLog.js +++ b/controllers/applicationsController/getSingleApplicationLog.js @@ -11,13 +11,13 @@ const getSingleApplicationLog = async (req, res, next) => { //reuse this controller for msAdmins, they can find any application if (req.token.msAdminId) { - const application = Application.findById(applicationId); + const application = await Application.findById(applicationId); if (!application) { return next(new CustomError(404, "Application not found")); } } else { //check if requested application belongs to organization of admin user - const application = Application.find({ + const application = await Application.find({ _id: applicationId, organizationId, }); From 70bb67d6f0c8f5b4daee9a81f14678e1edec1255 Mon Sep 17 00:00:00 2001 From: Dave Date: Sun, 26 Jul 2020 17:38:52 +0100 Subject: [PATCH 07/13] feat: add logging control to system settings --- .../api/applications/getSingleApplicationLog.test.js | 2 +- __test__/middleware/requestLogger.test.js | 10 +++++----- middleware/requestLogger.js | 4 ++-- models/systemSettings.js | 5 +++++ settingAndVariables.txt | 2 +- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/__test__/api/applications/getSingleApplicationLog.test.js b/__test__/api/applications/getSingleApplicationLog.test.js index f09fd51..a34fa73 100644 --- a/__test__/api/applications/getSingleApplicationLog.test.js +++ b/__test__/api/applications/getSingleApplicationLog.test.js @@ -9,7 +9,7 @@ describe("Get single application logs", () => { let app, request; it("should return all logs for a given application", async () => { - process.env.LOGGING_ENABLED = true; + process.env.loggingEnabled = true; //create express app app = express(); diff --git a/__test__/middleware/requestLogger.test.js b/__test__/middleware/requestLogger.test.js index 5bd5f4e..b115aa9 100644 --- a/__test__/middleware/requestLogger.test.js +++ b/__test__/middleware/requestLogger.test.js @@ -43,7 +43,7 @@ describe("Logger middleware", () => { let app, request; it("logging is system-enabled and app-enabled for all requests", async () => { - process.env.LOGGING_ENABLED = true; + process.env.loggingEnabled = true; app = express(); app.use((req, res, next) => { const logging = { @@ -79,7 +79,7 @@ describe("Logger middleware", () => { }); it("logging is system-disabled", async () => { - process.env.LOGGING_ENABLED = false; + process.env.loggingEnabled = false; app = express(); app.use((req, res, next) => { const logging = { @@ -115,7 +115,7 @@ describe("Logger middleware", () => { }); it("logging is not available for application", async () => { - process.env.LOGGING_ENABLED = true; + process.env.loggingEnabled = true; app = express(); app.use((req, res, next) => { const logging = {}; @@ -151,7 +151,7 @@ describe("Logger middleware", () => { }); it("logging is system-enabled and app-enabled for all requests but skipped status 400", async () => { - process.env.LOGGING_ENABLED = true; + process.env.loggingEnabled = true; app = express(); app.use((req, res, next) => { const logging = { @@ -207,7 +207,7 @@ describe("Logger middleware", () => { }); it("logging is system-disabled when env variable is undefined", async () => { - process.env.LOGGING_ENABLED = ""; + process.env.loggingEnabled = ""; app = express(); app.use((req, res, next) => { const logging = { diff --git a/middleware/requestLogger.js b/middleware/requestLogger.js index 117ac90..0889f10 100644 --- a/middleware/requestLogger.js +++ b/middleware/requestLogger.js @@ -36,8 +36,8 @@ exports.requestLogger = (req, res, next) => { res.on("finish", () => { // check if logging is enabled globally - const loggingEnabled = process.env.LOGGING_ENABLED - ? process.env.LOGGING_ENABLED.toLowerCase() === "true" + const loggingEnabled = process.env.loggingEnabled + ? process.env.loggingEnabled.toLowerCase() === "true" : false; try { diff --git a/models/systemSettings.js b/models/systemSettings.js index 6c868fd..20560d2 100644 --- a/models/systemSettings.js +++ b/models/systemSettings.js @@ -29,6 +29,11 @@ const SystemSettingsSchema = new Schema( required: true, default: false, }, + loggingEnabled: { + type: Boolean, + required: true, + default: true, + }, }, { timestamps: true, diff --git a/settingAndVariables.txt b/settingAndVariables.txt index 412a01b..130a4db 100644 --- a/settingAndVariables.txt +++ b/settingAndVariables.txt @@ -20,7 +20,7 @@ SYSTEM SETTINGS [appear as ENV VARS at runtime] - maxRequestsPerMin - global max request rate to prevent DDoS and abuse, even plans cant exceed - defaultMaxRequestsPerDay - for making requests without plan (might be shelved in favor of application default plan) - disableRequestLimits - Disable all limiting, majorly for testing purposes only or open systems - - LOGGING_ENABLED - globally disable logging (make camel-case) + - LOGGING_ENABLED - now loggingEnabled - globally disable logging (make camel-case) - maxItemsPerpage - max items per request page - defaultItemsPerPage - default items per page when not set - logPageSize - The size of records from log From 7baca97234b583a178460c313d71adc6650d44af Mon Sep 17 00:00:00 2001 From: Dave Date: Sun, 26 Jul 2020 17:52:42 +0100 Subject: [PATCH 08/13] fix: update systemSettings test --- __test__/api/msadmins/settings/updateSystemSettings.test.js | 4 ++++ models/systemSettings.js | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/__test__/api/msadmins/settings/updateSystemSettings.test.js b/__test__/api/msadmins/settings/updateSystemSettings.test.js index edefc85..f6b763a 100644 --- a/__test__/api/msadmins/settings/updateSystemSettings.test.js +++ b/__test__/api/msadmins/settings/updateSystemSettings.test.js @@ -21,6 +21,8 @@ describe("PATCH /msAdmins/settings", () => { maxItemsPerPage: 50, defaultMaxRequestsPerDay: 10000, disableRequestLimits: false, + loggingEnabled: true, + logPageSize: 100, }; let res = await request @@ -46,6 +48,8 @@ describe("PATCH /msAdmins/settings", () => { maxItemsPerPage: 20, defaultMaxRequestsPerDay: 10000, disableRequestLimits: false, + loggingEnabled: true, + logPageSize: 100, }; //check for update also in same process because this is a single document collection diff --git a/models/systemSettings.js b/models/systemSettings.js index 20560d2..db3d02d 100644 --- a/models/systemSettings.js +++ b/models/systemSettings.js @@ -34,6 +34,11 @@ const SystemSettingsSchema = new Schema( required: true, default: true, }, + logPageSize: { + type: Number, + required: true, + default: 100, + }, }, { timestamps: true, From 0a683b5478c0dbe94cf0f5fef7fdd0f7a14dfb4e Mon Sep 17 00:00:00 2001 From: Dave Date: Sun, 26 Jul 2020 22:07:46 +0100 Subject: [PATCH 09/13] feat: create utility to paginate deleted records --- __test__/utils/paginateDeleted.test.js | 52 ++++++++++++++++++ utils/paginateDeleted.js | 73 ++++++++++++++++++++++++++ utils/softDelete.js | 12 +++++ 3 files changed, 137 insertions(+) create mode 100644 __test__/utils/paginateDeleted.test.js create mode 100644 utils/paginateDeleted.js diff --git a/__test__/utils/paginateDeleted.test.js b/__test__/utils/paginateDeleted.test.js new file mode 100644 index 0000000..4491640 --- /dev/null +++ b/__test__/utils/paginateDeleted.test.js @@ -0,0 +1,52 @@ +const { paginateDeleted } = require("../../utils/paginateDeleted"); +const softDelete = require("../../utils/softDelete"); +const MsAdmin = require("../../models/msadmins"); + +describe("Paginete soft-deleted records", () => { + let msAdmin, + idsArray = []; + beforeAll(async () => { + //create dummy records and softDelete them + for (let index = 0; index < 20; index++) { + msAdmin = new MsAdmin({ + fullname: "admin1", + email: `admin${Date.now()}@domain.com`, + password: "some password", + }); + await msAdmin.save(); + + idsArray.push(msAdmin.id); + + //soft delete + if ((index + 2) % 2 === 0) { + await softDelete.deleteById(MsAdmin, msAdmin.id, global.msAdmin.id); + } + } + }); + + afterAll(async () => { + for (let index = 0; index < idsArray.length; index++) { + const msAdminId = idsArray[index]; + await softDelete.restoreById(MsAdmin, msAdminId); + await MsAdmin.findByIdAndDelete(msAdminId); + } + }); + + it("should get all deleted records", async () => { + const deletedAdmins = await paginateDeleted(MsAdmin, "deleted", {}, 5, 1); + expect(deletedAdmins.totalRecords).toEqual(10); + }); + + it("should get all undeleted records", async () => { + const unDeleted = await paginateDeleted(MsAdmin, "unDeleted", {}, 5, 1); + console.log(unDeleted); + expect(unDeleted.totalRecords).toEqual(12); + }); + + it("should get all records", async () => { + const allAdmins = await paginateDeleted(MsAdmin, "all", {}, 5, 1); + expect(allAdmins.totalRecords).toEqual(22); + }); + + //retrieve the deleted records by page +}); diff --git a/utils/paginateDeleted.js b/utils/paginateDeleted.js new file mode 100644 index 0000000..63e0cf8 --- /dev/null +++ b/utils/paginateDeleted.js @@ -0,0 +1,73 @@ +exports.paginateDeleted = async (Model, findFilter, query, limit, page) => { + let currentPage, + totalPages, + hasNext, + hasPrev, + nextPage, + prevPage, + pageRecordCount, + totalRecords, + documents; + + //get total documents in collection + if (findFilter === "unDeleted") { + totalRecords = await Model.countDocuments(query); + } else if (findFilter === "deleted") { + totalRecords = await Model.countDocumentsDeleted(query); + } else if (findFilter === "all") { + totalRecords = await Model.countDocumentsWithDeleted(query); + } else { + //throw an error here + throw new Error("Invalid 'findFilter' specified"); + } + + //divide total by limit(round up) to get number of pages + totalPages = Math.ceil(totalRecords / limit); + + //if requested page is greater than last page return last page with + currentPage = page; + + hasNext = true; + hasPrev = true; + nextPage = page + 1; + prevPage = page - 1; + + if (page >= totalPages) { + currentPage = totalPages; + hasNext = false; + nextPage = null; + } + + if (page <= 1) { + page = 1; + hasPrev = false; + prevPage = null; + } + + const skipCount = limit * (currentPage - 1); + + //skip (limit * page - 1) records and get limit records + let result; + if (findFilter === "unDeleted") { + result = await Model.find(query).skip(skipCount).limit(limit); + } else if (findFilter === "deleted") { + result = await Model.findDeleted(query).skip(skipCount).limit(limit); + } else if (findFilter === "all") { + result = await Model.findWithDeleted(query).skip(skipCount).limit(limit); + } + + pageRecordCount = result.length; + documents = result; + + return { + currentPage, + totalPages, + hasNext, + hasPrev, + nextPage, + prevPage, + pageRecordCount, + totalRecords, + documents, + }; +}; diff --git a/utils/softDelete.js b/utils/softDelete.js index 5b26788..a0e9ecf 100644 --- a/utils/softDelete.js +++ b/utils/softDelete.js @@ -1,3 +1,5 @@ +const { paginateDeleted } = require("./paginateDeleted"); + exports.deleteById = async (Model, targetDocId, deletedById) => { const targetDoc = await Model.findById(targetDocId); if (!targetDoc) { @@ -27,3 +29,13 @@ exports.restoreById = async (Model, targetDocId) => { }); }); }; + +exports.getDeletedRecords = async (Model, findFilter, page = 1, limit = 20) => { + //get disabled records + return paginateDeleted(Model, "deleted", {}, limit, page); +}; + +exports.getAllRecords = async (Model, findFilter, page = 1, limit = 20) => { + //get disabled records + return paginateDeleted(Model, "all", {}, limit, page); +}; From f0daa4effc52e27e8b18a9e08c902e4546dfd6bf Mon Sep 17 00:00:00 2001 From: Dave Date: Mon, 27 Jul 2020 06:03:00 +0100 Subject: [PATCH 10/13] feat: add softdelete pagination to getAllMsAdmins --- __test__/api/msadmins/getAllMsAdmins.test.js | 43 +++++++++++++++++++ __test__/utils/paginateDeleted.test.js | 31 ++++++++++--- .../msAdminsController/getAllMsAdmins.js | 13 +++++- utils/auth/tokenGenerator.js | 2 +- utils/paginateDeleted.js | 14 +++--- utils/softDelete.js | 6 +-- 6 files changed, 90 insertions(+), 19 deletions(-) diff --git a/__test__/api/msadmins/getAllMsAdmins.test.js b/__test__/api/msadmins/getAllMsAdmins.test.js index cfcbd70..159d69e 100644 --- a/__test__/api/msadmins/getAllMsAdmins.test.js +++ b/__test__/api/msadmins/getAllMsAdmins.test.js @@ -2,6 +2,7 @@ const app = require("../../../server"); const supertest = require("supertest"); const MsAdmin = require("../../../models/msadmins"); const request = supertest(app); +const { deleteById, restoreById } = require("../../../utils/softDelete"); // Cached admin and allMsAdminsResponse. let msAdmin, msAdmin2, msAdmin3, allMsAdminsResponse; @@ -179,4 +180,46 @@ describe("GET /msAdmins", () => { expect(res.body.status).toEqual("error"); expect(res.body.data).toEqual([]); }); + + it("Should get all disabled microservice admins with all pagination params set", async () => { + const url = `/v1/msAdmins`; + const bearerToken = `bearer ${global.superSysToken}`; + + //disable one admin + await deleteById(MsAdmin, msAdmin2.id, global.msSuperAdmin.id); + + const res = await request + .get(url) + .query({ limit: 3, page: 1, sort: "asc", filter: "disabled" }) + .set("Authorization", bearerToken); + + // const expectedValue = allMsAdminsResponse.slice(0, 1); + + expect(res.status).toEqual(200); + expect(res.body.status).toEqual("success"); + expect(res.body.data.records.length).toEqual(1); + + await restoreById(MsAdmin, msAdmin2.Id); + }); + + it("Should get both disabled/enabled microservice admins with all pagination params set", async () => { + const url = `/v1/msAdmins`; + const bearerToken = `bearer ${global.superSysToken}`; + + //disable one admin + await deleteById(MsAdmin, msAdmin2.id, global.msSuperAdmin.id); + + const res = await request + .get(url) + .query({ limit: 3, page: 1, sort: "asc", filter: "all" }) + .set("Authorization", bearerToken); + + // const expectedValue = allMsAdminsResponse.slice(0, 1); + + expect(res.status).toEqual(200); + expect(res.body.status).toEqual("success"); + expect(res.body.data.records.length).toEqual(3); + + await restoreById(MsAdmin, msAdmin2.Id); + }); }); diff --git a/__test__/utils/paginateDeleted.test.js b/__test__/utils/paginateDeleted.test.js index 4491640..a4df5ac 100644 --- a/__test__/utils/paginateDeleted.test.js +++ b/__test__/utils/paginateDeleted.test.js @@ -9,7 +9,7 @@ describe("Paginete soft-deleted records", () => { //create dummy records and softDelete them for (let index = 0; index < 20; index++) { msAdmin = new MsAdmin({ - fullname: "admin1", + fullname: "paginateDeleteTest", email: `admin${Date.now()}@domain.com`, password: "some password", }); @@ -33,19 +33,36 @@ describe("Paginete soft-deleted records", () => { }); it("should get all deleted records", async () => { - const deletedAdmins = await paginateDeleted(MsAdmin, "deleted", {}, 5, 1); + const deletedAdmins = await paginateDeleted( + MsAdmin, + "disabled", + { fullname: "paginateDeleteTest" }, + 5, + 1 + ); expect(deletedAdmins.totalRecords).toEqual(10); }); it("should get all undeleted records", async () => { - const unDeleted = await paginateDeleted(MsAdmin, "unDeleted", {}, 5, 1); - console.log(unDeleted); - expect(unDeleted.totalRecords).toEqual(12); + const unDeleted = await paginateDeleted( + MsAdmin, + "enabled", + { fullname: "paginateDeleteTest" }, + 5, + 1 + ); + expect(unDeleted.totalRecords).toEqual(10); }); it("should get all records", async () => { - const allAdmins = await paginateDeleted(MsAdmin, "all", {}, 5, 1); - expect(allAdmins.totalRecords).toEqual(22); + const allAdmins = await paginateDeleted( + MsAdmin, + "all", + { fullname: "paginateDeleteTest" }, + 5, + 1 + ); + expect(allAdmins.totalRecords).toEqual(20); }); //retrieve the deleted records by page diff --git a/controllers/msAdminsController/getAllMsAdmins.js b/controllers/msAdminsController/getAllMsAdmins.js index 24a3575..104b8a4 100644 --- a/controllers/msAdminsController/getAllMsAdmins.js +++ b/controllers/msAdminsController/getAllMsAdmins.js @@ -1,6 +1,7 @@ const MsAdmin = require("../../models/msadmins"); const CustomError = require("../../utils/customError"); const responseHandler = require("../../utils/responseHandler"); +const { getAllRecords, getDeletedRecords } = require("../../utils/softDelete"); /** * @author David Okanlawon @@ -14,11 +15,20 @@ const responseHandler = require("../../utils/responseHandler"); const getAllMsAdmins = async (req, res, next) => { //get all admins mapping the field names appropriately let admins, allMsAdmins; + const { filter } = req.query; let query = {}; + const { page, limit } = req.paginateOptions; try { - admins = await MsAdmin.paginate(query, req.paginateOptions); + if (filter === "disabled") { + admins = await getDeletedRecords(MsAdmin, page, limit); + } else if (filter === "all") { + admins = await getAllRecords(MsAdmin, page, limit); + } else { + admins = await MsAdmin.paginate(query, req.paginateOptions); + } + allMsAdmins = admins.docs.map((admin) => { return { msAdminId: admin._id, @@ -28,6 +38,7 @@ const getAllMsAdmins = async (req, res, next) => { }; }); } catch (error) { + console.log(error.message); next(new CustomError(400, "An error occured retrieving admin accounts")); return; } diff --git a/utils/auth/tokenGenerator.js b/utils/auth/tokenGenerator.js index 33e24f9..fdaf492 100644 --- a/utils/auth/tokenGenerator.js +++ b/utils/auth/tokenGenerator.js @@ -102,7 +102,7 @@ const getSysToken = async (msAdminId) => { // confirm adminId exists const msAdmin = await MsAdmin.findById(msAdminId); if (!msAdmin) { - console.log(msAdminId, msAdmin); + // console.log(msAdminId, msAdmin); throw new CustomError( 401, "You are not authorized to access this resource" diff --git a/utils/paginateDeleted.js b/utils/paginateDeleted.js index 63e0cf8..45fb800 100644 --- a/utils/paginateDeleted.js +++ b/utils/paginateDeleted.js @@ -7,12 +7,12 @@ exports.paginateDeleted = async (Model, findFilter, query, limit, page) => { prevPage, pageRecordCount, totalRecords, - documents; + docs; //get total documents in collection - if (findFilter === "unDeleted") { + if (findFilter === "enabled") { totalRecords = await Model.countDocuments(query); - } else if (findFilter === "deleted") { + } else if (findFilter === "disabled") { totalRecords = await Model.countDocumentsDeleted(query); } else if (findFilter === "all") { totalRecords = await Model.countDocumentsWithDeleted(query); @@ -48,16 +48,16 @@ exports.paginateDeleted = async (Model, findFilter, query, limit, page) => { //skip (limit * page - 1) records and get limit records let result; - if (findFilter === "unDeleted") { + if (findFilter === "enabled") { result = await Model.find(query).skip(skipCount).limit(limit); - } else if (findFilter === "deleted") { + } else if (findFilter === "disabled") { result = await Model.findDeleted(query).skip(skipCount).limit(limit); } else if (findFilter === "all") { result = await Model.findWithDeleted(query).skip(skipCount).limit(limit); } pageRecordCount = result.length; - documents = result; + docs = result; return { currentPage, @@ -68,6 +68,6 @@ exports.paginateDeleted = async (Model, findFilter, query, limit, page) => { prevPage, pageRecordCount, totalRecords, - documents, + docs, }; }; diff --git a/utils/softDelete.js b/utils/softDelete.js index a0e9ecf..263cf2f 100644 --- a/utils/softDelete.js +++ b/utils/softDelete.js @@ -30,12 +30,12 @@ exports.restoreById = async (Model, targetDocId) => { }); }; -exports.getDeletedRecords = async (Model, findFilter, page = 1, limit = 20) => { +exports.getDeletedRecords = async (Model, page = 1, limit = 20) => { //get disabled records - return paginateDeleted(Model, "deleted", {}, limit, page); + return paginateDeleted(Model, "disabled", {}, limit, page); }; -exports.getAllRecords = async (Model, findFilter, page = 1, limit = 20) => { +exports.getAllRecords = async (Model, page = 1, limit = 20) => { //get disabled records return paginateDeleted(Model, "all", {}, limit, page); }; From fafe9ff0a3a7546881b2c0d3e6215905cb3c0849 Mon Sep 17 00:00:00 2001 From: Dave Date: Tue, 28 Jul 2020 05:58:20 +0100 Subject: [PATCH 11/13] feat: add isBlocked/isDisabled field to queries --- __test__/api/msadmins/getAllMsAdmins.test.js | 3 ++ .../applications/getAllApplications.js | 24 ++++++++++--- .../applications/getSingleApplication.js | 22 +++--------- .../msAdminsController/getAllMsAdmins.js | 1 + .../msAdminsController/getSingleMsAdmin.js | 3 +- .../organizations/getAllOrganizations.js | 34 ++++++++++++++++--- .../organizations/getSingleOrganization.js | 7 ++-- 7 files changed, 63 insertions(+), 31 deletions(-) diff --git a/__test__/api/msadmins/getAllMsAdmins.test.js b/__test__/api/msadmins/getAllMsAdmins.test.js index 159d69e..2ddb95d 100644 --- a/__test__/api/msadmins/getAllMsAdmins.test.js +++ b/__test__/api/msadmins/getAllMsAdmins.test.js @@ -45,18 +45,21 @@ describe("GET /msAdmins", () => { fullname: msAdmin.fullname, email: msAdmin.email, role: msAdmin.role, + isDisabled: false, }, { msAdminId: msAdmin2.id, fullname: msAdmin2.fullname, email: msAdmin2.email, role: msAdmin2.role, + isDisabled: false, }, { msAdminId: msAdmin3.id, fullname: msAdmin3.fullname, email: msAdmin3.email, role: msAdmin3.role, + isDisabled: false, }, ]; }); diff --git a/controllers/msAdminsController/applications/getAllApplications.js b/controllers/msAdminsController/applications/getAllApplications.js index 064a4cf..fc0b647 100644 --- a/controllers/msAdminsController/applications/getAllApplications.js +++ b/controllers/msAdminsController/applications/getAllApplications.js @@ -2,6 +2,10 @@ const Applications = require("../../../models/applications"); const MsAdmin = require("../../../models/msadmins"); const CustomError = require("../../../utils/customError"); const responseHandler = require("../../../utils/responseHandler"); +const { + getAllRecords, + getDeletedRecords, +} = require("../../../utils/softDelete"); /** * @author Ekeyekwu Oscar @@ -20,6 +24,7 @@ const getAllApplications = async (req, res, next) => { let allApplications; let query = {}; + const { page, limit } = req.paginateOptions; try { //check if msAdmin exists @@ -29,11 +34,21 @@ const getAllApplications = async (req, res, next) => { return; } + const { filter } = req.query; + //get all applications - const applications = await Applications.paginate(query, { - ...req.paginateOptions, - populate: "organizationId", - }); + let applications; + + if (filter === "disabled") { + applications = await getDeletedRecords(Applications, page, limit); + } else if (filter === "all") { + applications = await getAllRecords(Applications, page, limit); + } else { + applications = await Applications.paginate(query, { + ...req.paginateOptions, + populate: "organizationId", + }); + } allApplications = applications.docs.map((application) => { return { @@ -41,6 +56,7 @@ const getAllApplications = async (req, res, next) => { applicationName: application.name, organizationId: application.organizationId, organizationName: application.organizationId.name, + isBlocked: application.deleted || false, }; }); diff --git a/controllers/msAdminsController/applications/getSingleApplication.js b/controllers/msAdminsController/applications/getSingleApplication.js index bcf9c3e..8958057 100644 --- a/controllers/msAdminsController/applications/getSingleApplication.js +++ b/controllers/msAdminsController/applications/getSingleApplication.js @@ -29,35 +29,21 @@ const getSingleApplication = async (req, res, next) => { } //get applications - const singleApplication = await Applications.findById( - applicationId - ).populate("organizationId"); + const singleApplication = await Applications.findOneWithDeleted({ + _id: applicationId, + }).populate("organizationId"); if (!singleApplication) { next(new CustomError(404, "Application not Found")); return; } - // let commentsCount, repliesCount; - // const comments = await CommentModel.find({applicationId:applicationId}); - // console.log(comments) - // if (!comments || comments === []) { - // commentsCount = 0; - // repliesCount = 0; - // } else { - // commentsCount = comments.records.length; - // repliesCount = comments.records.reduce((acc, curr) => { - // return acc + curr.numOfReplies; - // }, 0); - // } - // console.log(commentsCount, repliesCount); application = { applicationId: singleApplication._id, applicationName: singleApplication.name, organizationId: singleApplication.organizationId, organizationName: singleApplication.organizationId.name, - // totalNumOfComments: commentsCount, - // totalNumOfReplies: repliesCount, + isBlocked: singleApplication.deleted || false, }; } catch (error) { next(new CustomError(400, "An error occured retrieving Application")); diff --git a/controllers/msAdminsController/getAllMsAdmins.js b/controllers/msAdminsController/getAllMsAdmins.js index 104b8a4..927cc5b 100644 --- a/controllers/msAdminsController/getAllMsAdmins.js +++ b/controllers/msAdminsController/getAllMsAdmins.js @@ -35,6 +35,7 @@ const getAllMsAdmins = async (req, res, next) => { fullname: admin.fullname, email: admin.email, role: admin.role, + isDisabled: admin.deleted || false, }; }); } catch (error) { diff --git a/controllers/msAdminsController/getSingleMsAdmin.js b/controllers/msAdminsController/getSingleMsAdmin.js index bbb3011..b4d7797 100644 --- a/controllers/msAdminsController/getSingleMsAdmin.js +++ b/controllers/msAdminsController/getSingleMsAdmin.js @@ -16,7 +16,7 @@ const getSingleMsAdmin = async (req, res, next) => { //get msAdmin account try { - const msAdmin = await MsAdmin.findById(msAdminId); + const msAdmin = await MsAdmin.findOneWithDeleted({ _id: msAdminId }); if (!msAdmin) { next(new CustomError(404, "MsAdmin account not found")); return; @@ -25,6 +25,7 @@ const getSingleMsAdmin = async (req, res, next) => { fullname: msAdmin.fullname, email: msAdmin.email, role: msAdmin.role, + isDisabled: msAdmin.deleted || false, }; return responseHandler( diff --git a/controllers/msAdminsController/organizations/getAllOrganizations.js b/controllers/msAdminsController/organizations/getAllOrganizations.js index a5ae7dc..8fbb462 100644 --- a/controllers/msAdminsController/organizations/getAllOrganizations.js +++ b/controllers/msAdminsController/organizations/getAllOrganizations.js @@ -1,6 +1,11 @@ const OrganizationsModel = require("../../../models/organizations"); +const MsAdmin = require("../../../models/msadmins"); const CustomError = require("../../../utils/customError"); const responseHandler = require("../../../utils/responseHandler"); +const { + getAllRecords, + getDeletedRecords, +} = require("../../../utils/softDelete"); /** * @author Ekeyekwu Oscar @@ -15,20 +20,39 @@ const getAllOrganizations = async (req, res, next) => { //get all organizations and map field names appropriately let allOrganizations; + //get msAdminId from token + const { msAdminId } = req.token; + + //check if msAdmin exists + const msAdmin = await MsAdmin.findById(msAdminId); + if (!msAdmin) { + next(new CustomError(404, "MsAdmin account not found")); + return; + } + let query = {}; + const { page, limit } = req.paginateOptions; + const { filter } = req.query; + try { //get all organizations - const organizations = await OrganizationsModel.paginate( - query, - req.paginateOptions - ); + let organizations; + if (filter === "disabled") { + organizations = await getDeletedRecords(OrganizationsModel, page, limit); + } else if (filter === "all") { + organizations = await getAllRecords(OrganizationsModel, page, limit); + } else { + organizations = await OrganizationsModel.paginate(query, { + ...req.paginateOptions, + }); + } allOrganizations = organizations.docs.map((organization) => { return { organizationId: organization._id, organizationName: organization.name, - organizationEmail: organization.email, + isBlocked: organization.deleted || false, }; }); diff --git a/controllers/msAdminsController/organizations/getSingleOrganization.js b/controllers/msAdminsController/organizations/getSingleOrganization.js index 4ae8d9f..f9fa072 100644 --- a/controllers/msAdminsController/organizations/getSingleOrganization.js +++ b/controllers/msAdminsController/organizations/getSingleOrganization.js @@ -29,9 +29,9 @@ const getSingleOrganization = async (req, res, next) => { } //get organizations - const singleOrganization = await OrganizationsModel.findById( - organizationId - ); + const singleOrganization = await OrganizationsModel.findOneWithDeleted({ + _id: organizationId, + }); if (!singleOrganization) { next(new CustomError(404, "Organization not Found")); @@ -42,6 +42,7 @@ const getSingleOrganization = async (req, res, next) => { organizationId: singleOrganization._id, organizationName: singleOrganization.name, organizationEmail: singleOrganization.email, + isBlocked: singleOrganization.deleted || false, }; } catch (error) { next(new CustomError(400, "An error occured retrieving organization")); From 327e948db1f643b298ed5fb4232359231ca79a8b Mon Sep 17 00:00:00 2001 From: Dave Date: Tue, 28 Jul 2020 06:06:45 +0100 Subject: [PATCH 12/13] fix: add await keyword in getSingleApplicationLog --- controllers/applicationsController/getSingleApplicationLog.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/controllers/applicationsController/getSingleApplicationLog.js b/controllers/applicationsController/getSingleApplicationLog.js index 9f9dade..ce36368 100644 --- a/controllers/applicationsController/getSingleApplicationLog.js +++ b/controllers/applicationsController/getSingleApplicationLog.js @@ -11,13 +11,13 @@ const getSingleApplicationLog = async (req, res, next) => { //reuse this controller for msAdmins, they can find any application if (req.token.msAdminId) { - const application = Application.findById(applicationId); + const application = await Application.findById(applicationId); if (!application) { return next(new CustomError(404, "Application not found")); } } else { //check if requested application belongs to organization of admin user - const application = Application.find({ + const application = await Application.find({ _id: applicationId, organizationId, }); From c3b847d5f8e49e872e9bb7dad28d4e2390a52b15 Mon Sep 17 00:00:00 2001 From: Dave Date: Tue, 28 Jul 2020 07:38:59 +0100 Subject: [PATCH 13/13] feat: update updateSystemSettingsSchema --- .../msadmins/settings/updateSystemSettingsSchema.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/validationRules/msadmins/settings/updateSystemSettingsSchema.js b/utils/validationRules/msadmins/settings/updateSystemSettingsSchema.js index c036d8b..6aa5097 100644 --- a/utils/validationRules/msadmins/settings/updateSystemSettingsSchema.js +++ b/utils/validationRules/msadmins/settings/updateSystemSettingsSchema.js @@ -11,6 +11,8 @@ const updateSystemSettingsSchema = { maxItemsPerPage: Joi.number(), defaultMaxRequestsPerDay: Joi.number(), disableRequestLimits: Joi.boolean(), + loggingEnabled: Joi.boolean(), + logPageSize: Joi.number(), }), };