From 3c2df3a1a29a71fa7bf4b850f0e52e441399d2e8 Mon Sep 17 00:00:00 2001 From: Tereshchenko Aleksandr Date: Fri, 27 Sep 2024 11:24:40 +0300 Subject: [PATCH] Log event to event_log when there are changes to graders list --- src/server/db/models/Grader.ts | 4 + src/server/db/models/Thesis.ts | 4 + src/server/routes/thesis.integration-test.js | 294 ++++++++++++++++++- src/server/routes/thesis.ts | 2 + src/server/routes/thesisHelpers.ts | 48 +++ 5 files changed, 346 insertions(+), 6 deletions(-) diff --git a/src/server/db/models/Grader.ts b/src/server/db/models/Grader.ts index c947e11..8960a4f 100644 --- a/src/server/db/models/Grader.ts +++ b/src/server/db/models/Grader.ts @@ -4,9 +4,11 @@ import { InferCreationAttributes, DataTypes, UUIDV4, + NonAttribute, } from 'sequelize' import { sequelize } from '../connection' +import User from './User' class Grader extends Model< InferAttributes, @@ -19,6 +21,8 @@ class Grader extends Model< declare userId: string declare isPrimaryGrader: boolean + + declare user: NonAttribute } Grader.init( diff --git a/src/server/db/models/Thesis.ts b/src/server/db/models/Thesis.ts index a996408..e781dca 100644 --- a/src/server/db/models/Thesis.ts +++ b/src/server/db/models/Thesis.ts @@ -4,10 +4,12 @@ import { InferCreationAttributes, DataTypes, UUIDV4, + NonAttribute, } from 'sequelize' import type { ThesisStatus } from '@backend/types' import { sequelize } from '../connection' +import Grader from './Grader' class Thesis extends Model< InferAttributes, @@ -26,6 +28,8 @@ class Thesis extends Model< declare startDate: string declare targetDate: string | undefined + + declare graders: NonAttribute } Thesis.init( diff --git a/src/server/routes/thesis.integration-test.js b/src/server/routes/thesis.integration-test.js index f4fc16c..196ab49 100644 --- a/src/server/routes/thesis.integration-test.js +++ b/src/server/routes/thesis.integration-test.js @@ -1408,7 +1408,7 @@ describe('thesis router', () => { ) .field('json', JSON.stringify(newThesis)) expect(response.status).toEqual(201) - + const eventLog = await EventLog.findOne({ where: { type: 'THESIS_CREATED', thesisId: response.body.id }, }) @@ -2777,7 +2777,7 @@ describe('thesis router', () => { }) thesis1.status = 'CANCELLED' - thesis1.save() + await thesis1.save() const updatedThesis = { programId: 'Testing program', @@ -2906,9 +2906,9 @@ describe('thesis router', () => { }) describe('when the thesis already has IN_PROGRESS status', () => { - beforeEach(() => { + beforeEach(async () => { thesis1.status = 'IN_PROGRESS' - thesis1.save() + await thesis1.save() }) it('should return 200, update the thesis and not log status change event', async () => { @@ -2969,9 +2969,9 @@ describe('thesis router', () => { }) describe('when the thesis has status other than PLANING or IN_PROGRESS', () => { - beforeEach(() => { + beforeEach(async () => { thesis1.status = 'CANCELLED' - thesis1.save() + await thesis1.save() }) it('should return 200, update the thesis and log status change event', async () => { @@ -3032,6 +3032,288 @@ describe('thesis router', () => { }) }) }) + + describe('logic for adding THESIS_GRADERS_CHANGED event to the event_log table', () => { + describe('when a new grader is added to the thesis', () => { + beforeEach(async () => { + await Grader.destroy({ where: { thesisId: thesis1.id } }) + await Grader.create({ + userId: user4.id, + thesisId: thesis1.id, + isPrimaryGrader: true, + isExternal: false, + }) + }) + + it('adds THESIS_GRADERS_CHANGED event to the event_log table', async () => { + const updatedThesis = { + programId: 'Updated program', + studyTrackId: 'new-test-study-track-id', + topic: 'Updated topic', + status: 'PLANNING', + startDate: '1970-01-01T00:00:00.000Z', + targetDate: '2070-01-01T00:00:00.000Z', + supervisions: [ + { + user: user1, + percentage: 100, + isExternal: false, + isPrimarySupervisor: true, + }, + ], + graders: [ + { + user: user4, + isPrimaryGrader: true, + isExternal: false, + }, + { + user: user5, + isPrimaryGrader: false, + isExternal: false, + }, + ], + authors: [user2], + } + const response = await request + .put(`/api/theses/${thesis1.id}`) + .set({ uid: user1.id, hygroupcn: 'hy-employees' }) + .attach( + 'waysOfWorking', + path.resolve( + dirname(fileURLToPath(import.meta.url)), + './index.ts' + ) + ) + .attach( + 'researchPlan', + path.resolve( + dirname(fileURLToPath(import.meta.url)), + './index.ts' + ) + ) + .field('json', JSON.stringify(updatedThesis)) + expect(response.status).toEqual(200) + + const eventLog = await EventLog.findOne({ + where: { type: 'THESIS_GRADERS_CHANGED', thesisId: thesis1.id }, + }) + expect(eventLog).not.toBeNull() + }) + }) + + describe('when a grader is removed from the thesis', () => { + beforeEach(async () => { + await Grader.destroy({ where: { thesisId: thesis1.id } }) + await Grader.bulkCreate([ + { + userId: user4.id, + thesisId: thesis1.id, + isPrimaryGrader: true, + isExternal: false, + }, + { + userId: user5.id, + thesisId: thesis1.id, + isPrimaryGrader: false, + isExternal: false, + }, + ]) + }) + + it('adds THESIS_GRADERS_CHANGED event to the event_log table', async () => { + const updatedThesis = { + programId: 'Updated program', + studyTrackId: 'new-test-study-track-id', + topic: 'Updated topic', + status: 'PLANNING', + startDate: '1970-01-01T00:00:00.000Z', + targetDate: '2070-01-01T00:00:00.000Z', + supervisions: [ + { + user: user1, + percentage: 100, + isExternal: false, + isPrimarySupervisor: true, + }, + ], + graders: [ + { + user: user4, + isPrimaryGrader: true, + isExternal: false, + }, + ], + authors: [user2], + } + const response = await request + .put(`/api/theses/${thesis1.id}`) + .set({ uid: user1.id, hygroupcn: 'hy-employees' }) + .attach( + 'waysOfWorking', + path.resolve( + dirname(fileURLToPath(import.meta.url)), + './index.ts' + ) + ) + .attach( + 'researchPlan', + path.resolve( + dirname(fileURLToPath(import.meta.url)), + './index.ts' + ) + ) + .field('json', JSON.stringify(updatedThesis)) + expect(response.status).toEqual(200) + + const eventLog = await EventLog.findOne({ + where: { type: 'THESIS_GRADERS_CHANGED', thesisId: thesis1.id }, + }) + expect(eventLog).not.toBeNull() + }) + }) + + describe('when a primary grader changes when', () => { + beforeEach(async () => { + await Grader.destroy({ where: { thesisId: thesis1.id } }) + await Grader.bulkCreate([ + { + userId: user4.id, + thesisId: thesis1.id, + isPrimaryGrader: true, + isExternal: false, + }, + { + userId: user5.id, + thesisId: thesis1.id, + isPrimaryGrader: false, + isExternal: false, + }, + ]) + }) + + it('adds THESIS_GRADERS_CHANGED event to the event_log table', async () => { + const updatedThesis = { + programId: 'Updated program', + studyTrackId: 'new-test-study-track-id', + topic: 'Updated topic', + status: 'PLANNING', + startDate: '1970-01-01T00:00:00.000Z', + targetDate: '2070-01-01T00:00:00.000Z', + supervisions: [ + { + user: user1, + percentage: 100, + isExternal: false, + isPrimarySupervisor: true, + }, + ], + graders: [ + { + user: user4, + isPrimaryGrader: false, + isExternal: false, + }, + { + user: user5, + isPrimaryGrader: true, + isExternal: false, + }, + ], + authors: [user2], + } + const response = await request + .put(`/api/theses/${thesis1.id}`) + .set({ uid: user1.id, hygroupcn: 'hy-employees' }) + .attach( + 'waysOfWorking', + path.resolve( + dirname(fileURLToPath(import.meta.url)), + './index.ts' + ) + ) + .attach( + 'researchPlan', + path.resolve( + dirname(fileURLToPath(import.meta.url)), + './index.ts' + ) + ) + .field('json', JSON.stringify(updatedThesis)) + expect(response.status).toEqual(200) + + const eventLog = await EventLog.findOne({ + where: { type: 'THESIS_GRADERS_CHANGED', thesisId: thesis1.id }, + }) + expect(eventLog).not.toBeNull() + }) + }) + + describe('when graders are unchanged', () => { + beforeEach(async () => { + await Grader.destroy({ where: { thesisId: thesis1.id } }) + await Grader.bulkCreate([ + { + userId: user4.id, + thesisId: thesis1.id, + isPrimaryGrader: true, + isExternal: false, + }, + ]) + }) + + it('does not add THESIS_GRADERS_CHANGED event to the event_log table', async () => { + const updatedThesis = { + programId: 'Updated program', + studyTrackId: 'new-test-study-track-id', + topic: 'Updated topic', + status: 'PLANNING', + startDate: '1970-01-01T00:00:00.000Z', + targetDate: '2070-01-01T00:00:00.000Z', + supervisions: [ + { + user: user1, + percentage: 100, + isExternal: false, + isPrimarySupervisor: true, + }, + ], + graders: [ + { + user: user4, + isPrimaryGrader: true, + isExternal: false, + }, + ], + authors: [user2], + } + const response = await request + .put(`/api/theses/${thesis1.id}`) + .set({ uid: user1.id, hygroupcn: 'hy-employees' }) + .attach( + 'waysOfWorking', + path.resolve( + dirname(fileURLToPath(import.meta.url)), + './index.ts' + ) + ) + .attach( + 'researchPlan', + path.resolve( + dirname(fileURLToPath(import.meta.url)), + './index.ts' + ) + ) + .field('json', JSON.stringify(updatedThesis)) + expect(response.status).toEqual(200) + + const eventLog = await EventLog.findOne({ + where: { type: 'THESIS_GRADERS_CHANGED' }, + }) + expect(eventLog).toBeNull() + }) + }) + }) }) }) }) diff --git a/src/server/routes/thesis.ts b/src/server/routes/thesis.ts index 4db1f7b..6cb45ba 100644 --- a/src/server/routes/thesis.ts +++ b/src/server/routes/thesis.ts @@ -26,6 +26,7 @@ import { authorizeStatusChange } from '../middleware/authorizeStatusChange' import { getAndCreateExtUsers, getFindThesesOptions, + handleGradersChangeEventLog, handleStatusChangeEventLog, } from './thesisHelpers' import { @@ -260,6 +261,7 @@ thesisRouter.put( await handleAttachmentByLabel(req, id, 'waysOfWorking', t) await handleStatusChangeEventLog(originalThesis, thesisData, req.user, t) + await handleGradersChangeEventLog(originalThesis, thesisData, req.user, t) }) const updatedThesis = await fetchThesisById(id, req.user) diff --git a/src/server/routes/thesisHelpers.ts b/src/server/routes/thesisHelpers.ts index 8e2f063..01589f7 100644 --- a/src/server/routes/thesisHelpers.ts +++ b/src/server/routes/thesisHelpers.ts @@ -184,3 +184,51 @@ export const handleStatusChangeEventLog = async ( ) } } + +export const handleGradersChangeEventLog = async ( + originalThesis: Thesis, + updatedThesis: ThesisData, + actionUser: UserType, + transaction: Transaction +) => { + const originalGraders = originalThesis.graders + const updatedGraders = updatedThesis.graders + + const removedGraders = originalGraders.filter( + (originalGrader) => + !updatedGraders.some( + (updatedGrader) => + updatedGrader.user?.email === originalGrader.user.email + ) + ) + + const addedGraders = updatedGraders.filter( + (updatedGrader) => + !originalGraders.some( + (originalGrader) => + originalGrader.user.email === updatedGrader.user?.email + ) + ) + + const changedGraders = originalGraders.filter((originalGrader) => { + const updatedGrader = updatedGraders.find( + (grader) => grader.user?.email === originalGrader.user.email + ) + return updatedGrader?.isPrimaryGrader !== originalGrader.isPrimaryGrader + }) + + if (removedGraders.length || addedGraders.length || changedGraders.length) { + await EventLog.create( + { + userId: actionUser.id, + thesisId: originalThesis.id, + type: 'THESIS_GRADERS_CHANGED', + data: { + originalGraders: originalThesis.graders, + updatedGraders: updatedThesis.graders, + }, + }, + { transaction } + ) + } +}