diff --git a/Servers/controllers/user.ctrl.ts b/Servers/controllers/user.ctrl.ts index 7016231f..0d079253 100644 --- a/Servers/controllers/user.ctrl.ts +++ b/Servers/controllers/user.ctrl.ts @@ -4,8 +4,16 @@ import { createNewUserQuery, deleteUserByIdQuery, getAllUsersQuery, + getAssessmentsForProject, + getControlCategoriesForProject, + getControlForControlCategory, + getQuestionsForSubTopic, + getSubControlForControl, + getSubTopicsForTopic, + getTopicsForAssessment, getUserByEmailQuery, getUserByIdQuery, + getUserProjects, resetPasswordQuery, updateUserByIdQuery, } from "../utils/user.utils"; @@ -331,6 +339,86 @@ async function checkUserExists( } } +async function calculateProgress( + req: Request, + res: Response +): Promise { + try { + const id = parseInt(req.params.id) + const userProjects = await getUserProjects(id) + + let assessmentsMetadata = [] + let allTotalAssessments = 0 + let allDoneAssessments = 0 + + let controlsMetadata = [] + let allTotalSubControls = 0 + let allDoneSubControls = 0 + + for (const userProject of userProjects) { + let totalSubControls = 0 + let doneSubControls = 0 + const controlcategories = await getControlCategoriesForProject(userProject.id) + for (const controlcategory of controlcategories) { + const controls = await getControlForControlCategory(controlcategory.id) + for (const control of controls) { + const subControls = await getSubControlForControl(control.id) + for (const subControl of subControls) { + totalSubControls++; + if (subControl.status === "Done") { + doneSubControls++; + } + } + } + } + allTotalSubControls += totalSubControls + allDoneSubControls += doneSubControls + controlsMetadata.push({ projectId: userProject.id, totalSubControls, doneSubControls }) + + let totalAssessments = 0 + let doneAssessments = 0 + const assessments = await getAssessmentsForProject(userProject.id) + for (const assessment of assessments) { + const topics = await getTopicsForAssessment(assessment.id) + for (const topic of topics) { + const subTopics = await getSubTopicsForTopic(topic.id) + for (const subTopic of subTopics) { + const questions = await getQuestionsForSubTopic(subTopic.id) + for (const question of questions) { + totalAssessments++; + if (question.answer) { + doneAssessments++ + } + } + } + } + } + allTotalAssessments += totalAssessments + allDoneAssessments += doneAssessments + assessmentsMetadata.push({ projectId: userProject.id, totalAssessments, doneAssessments }) + } + + const response = { + controls: { + projects: controlsMetadata, + totalSubControls: allTotalSubControls, + doneSubControls: allDoneSubControls, + percentageComplete: Number(((allDoneSubControls / allTotalSubControls) * 100).toFixed(2)) + }, + assessments: { + projects: assessmentsMetadata, + totalAssessments: allTotalAssessments, + doneAssessments: allDoneAssessments, + percentageComplete: Number(((allDoneAssessments / allTotalAssessments) * 100).toFixed(2)) + } + } + return res.status(200).json(response) + } catch (error) { + console.log(error); + return res.status(500).json({ message: "Internal server error" }); + } +} + export { getAllUsers, getUserByEmail, @@ -341,4 +429,5 @@ export { updateUserById, deleteUserById, checkUserExists, + calculateProgress }; diff --git a/Servers/routes/user.route.ts b/Servers/routes/user.route.ts index 5d28c39e..f947374d 100644 --- a/Servers/routes/user.route.ts +++ b/Servers/routes/user.route.ts @@ -19,6 +19,7 @@ import { loginUser, resetPassword, updateUserById, + calculateProgress } from "../controllers/user.ctrl"; import authenticateJWT from "../middleware/auth.middleware"; @@ -148,4 +149,6 @@ router.delete("/:id", authenticateJWT, deleteUserById); */ router.get("/check/exists", checkUserExists); +router.get("/:id/calculate-progress", calculateProgress) + export default router; diff --git a/Servers/swagger.yaml b/Servers/swagger.yaml index 0bc4eb42..c02de18a 100644 --- a/Servers/swagger.yaml +++ b/Servers/swagger.yaml @@ -3855,6 +3855,90 @@ paths: example: internal server error error: type: object + /users/{id}/calculate-progress: + get: + tags: [users] + security: + - JWTAuth: [] + parameters: + - in: path + name: id + schema: + type: integer + required: true + description: id of the user + responses: + "200": + description: user + content: + application/json: + type: object + properties: + controls: + type: object + properties: + projects: + type: array + items: + type: object + properties: + projectId: + type: integer + example: 1 + totalSubControls: + type: integer + example: 12 + doneSubControls: + type: integer + example: 1 + totalSubControls: + type: integer + example: 12 + doneSubControls: + type: integer + example: 1 + percentageComplete: + type: number + format: float + example: 8.33 + assessments: + type: object + properties: + projects: + type: array + items: + type: object + properties: + projectId: + type: integer + example: 1 + totalAssessments: + type: integer + example: 34 + doneAssessments: + type: integer + example: 0 + totalAssessments: + type: integer + example: 34 + doneAssessments: + type: integer + example: 0 + percentageComplete: + type: number + format: float + example: 0 + "500": + description: internal server error + content: + application/json: + type: object + properties: + message: + type: string + example: internal server error + error: + type: object /roles: get: diff --git a/Servers/utils/user.utils.ts b/Servers/utils/user.utils.ts index ab2b9696..0ace3e9d 100644 --- a/Servers/utils/user.utils.ts +++ b/Servers/utils/user.utils.ts @@ -229,3 +229,67 @@ export const checkUserExistsQuery = async (): Promise => { throw error; } }; + +export const getUserProjects = async (id: number) => { + const result = await pool.query( + "SELECT id FROM projects WHERE id = $1", + [id] + ) + return result.rows +} + +export const getControlCategoriesForProject = async (id: number) => { + const result = await pool.query( + "SELECT id FROM controlcategories WHERE project_id = $1", + [id] + ) + return result.rows +} + +export const getControlForControlCategory = async (id: number) => { + const result = await pool.query( + "SELECT id FROM controls WHERE control_group = $1", + [id] + ) + return result.rows +} + +export const getSubControlForControl = async (id: number) => { + const result = await pool.query( + "SELECT * FROM subcontrols WHERE control_id = $1", + [id] + ) + return result.rows +} + +export const getAssessmentsForProject = async (id: number) => { + const result = await pool.query( + "SELECT id FROM assessments WHERE project_id = $1", + [id] + ) + return result.rows +} + +export const getTopicsForAssessment = async (id: number) => { + const result = await pool.query( + "SELECT id FROM topics WHERE assessment_id = $1", + [id] + ) + return result.rows +} + +export const getSubTopicsForTopic = async (id: number) => { + const result = await pool.query( + "SELECT id FROM subtopics WHERE topic_id = $1", + [id] + ) + return result.rows +} + +export const getQuestionsForSubTopic = async (id: number) => { + const result = await pool.query( + "SELECT * FROM questions WHERE subtopic_id = $1", + [id] + ) + return result.rows +}