Skip to content

Commit 138f52d

Browse files
committed
added types and update query
1 parent 2b6ce00 commit 138f52d

File tree

7 files changed

+137
-0
lines changed

7 files changed

+137
-0
lines changed

.claude/settings.local.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Bash(git log:*)",
5+
"Bash(npx tsc --noEmit)",
6+
"Bash(./node_modules/.bin/tsc:*)",
7+
"Bash(npm run lint)",
8+
"Bash(npm run fix:*)"
9+
],
10+
"deny": [],
11+
"ask": []
12+
}
13+
}

backend/typescript/graphql/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ const graphQLMiddlewares = {
8787
bulkCreateReviewedApplicantRecord: authorizedByAllRoles(),
8888
deleteReviewedApplicantRecord: authorizedByAllRoles(),
8989
bulkDeleteReviewedApplicantRecord: authorizedByAllRoles(),
90+
updateReviewedApplicantRecord: authorizedByAllRoles(),
9091
createUser: authorizedByAdmin(),
9192
updateUser: authorizedByAdmin(),
9293
deleteUserById: authorizedByAdmin(),

backend/typescript/graphql/resolvers/reviewedApplicantRecordResolver.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
ReviewedApplicantRecordDTO,
44
CreateReviewedApplicantRecordDTO,
55
DeleteReviewedApplicantRecordDTO,
6+
UpdateReviewedApplicantRecordDTO,
67
} from "../../types";
78
import { getErrorMessage } from "../../utilities/errorUtils";
89

@@ -61,6 +62,19 @@ const reviewedApplicantRecordResolvers = {
6162
throw new Error(getErrorMessage(error));
6263
}
6364
},
65+
66+
updateReviewedApplicantRecord: async (
67+
_parent: undefined,
68+
args: { input: UpdateReviewedApplicantRecordDTO },
69+
): Promise<ReviewedApplicantRecordDTO> => {
70+
try {
71+
return await reviewedApplicantRecordService.updateReviewedApplicantRecord(
72+
args.input,
73+
);
74+
} catch (error) {
75+
throw new Error(getErrorMessage(error));
76+
}
77+
},
6478
},
6579
};
6680

backend/typescript/graphql/types/reviewedApplicantRecordTypes.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@ const reviewedApplicantRecordTypes = gql`
4444
reviewerId: Int!
4545
}
4646
47+
input UpdateReviewedApplicantRecordInput {
48+
applicantRecordId: ID!
49+
reviewerId: Int!
50+
review: ReviewInput
51+
status: String
52+
}
53+
4754
extend type Mutation {
4855
createReviewedApplicantRecord(
4956
input: CreateReviewedApplicantRecordInput!
@@ -60,6 +67,10 @@ const reviewedApplicantRecordTypes = gql`
6067
bulkDeleteReviewedApplicantRecord(
6168
inputs: [DeleteReviewedApplicantRecord!]!
6269
): [ReviewedApplicantRecord!]!
70+
71+
updateReviewedApplicantRecord(
72+
input: UpdateReviewedApplicantRecordInput!
73+
): ReviewedApplicantRecord!
6374
}
6475
`;
6576

backend/typescript/services/implementations/reviewedApplicantRecordService.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { sequelize } from "../../models";
22
import ReviewedApplicantRecord from "../../models/reviewedApplicantRecord.model";
3+
import ApplicantRecord from "../../models/applicantRecord.model";
34
import {
45
ReviewedApplicantRecordDTO,
56
CreateReviewedApplicantRecordDTO,
67
DeleteReviewedApplicantRecordDTO,
8+
UpdateReviewedApplicantRecordDTO,
79
} from "../../types";
810

911
import IReviewApplicantRecordService from "../interfaces/IReviewedApplicantRecordService";
@@ -80,6 +82,85 @@ class ReviewedApplicantRecordService implements IReviewApplicantRecordService {
8082

8183
return deletedRecords.map((r) => r.toJSON() as ReviewedApplicantRecordDTO);
8284
}
85+
86+
/* eslint-disable class-methods-use-this */
87+
async updateReviewedApplicantRecord({
88+
applicantRecordId,
89+
reviewerId,
90+
review,
91+
status,
92+
}: UpdateReviewedApplicantRecordDTO): Promise<ReviewedApplicantRecordDTO> {
93+
const updatedRecord = await sequelize.transaction(async (t) => {
94+
const reviewedRecord = await ReviewedApplicantRecord.findOne({
95+
where: { applicantRecordId, reviewerId },
96+
transaction: t,
97+
});
98+
99+
if (!reviewedRecord) {
100+
throw new Error(
101+
`ReviewedApplicantRecord not found for applicantRecordId: ${applicantRecordId} and reviewerId: ${reviewerId}`,
102+
);
103+
}
104+
105+
const oldReviewedScore = reviewedRecord.score || 0;
106+
107+
if (review !== undefined) {
108+
reviewedRecord.review = {
109+
...reviewedRecord.review,
110+
...review,
111+
};
112+
113+
const { passionFSG, teamPlayer, desireToLearn, skill } =
114+
reviewedRecord.review;
115+
116+
if (
117+
passionFSG === undefined ||
118+
teamPlayer === undefined ||
119+
desireToLearn === undefined ||
120+
skill === undefined
121+
) {
122+
throw new Error(
123+
"Invalid review update: All four score fields (passionFSG, teamPlayer, desireToLearn, skill) must be present after the update",
124+
);
125+
}
126+
127+
reviewedRecord.score = passionFSG + teamPlayer + desireToLearn + skill;
128+
129+
if (review.skillCategory !== undefined) {
130+
reviewedRecord.skillCategory = review.skillCategory;
131+
}
132+
}
133+
134+
if (status !== undefined) {
135+
reviewedRecord.status = status;
136+
}
137+
138+
await reviewedRecord.save({ transaction: t });
139+
140+
const newReviewedScore = reviewedRecord.score || 0;
141+
142+
const applicantRecord = await ApplicantRecord.findOne({
143+
where: { id: applicantRecordId },
144+
transaction: t,
145+
});
146+
147+
if (!applicantRecord) {
148+
throw new Error(
149+
`ApplicantRecord not found for applicantRecordId: ${applicantRecordId}`,
150+
);
151+
}
152+
153+
const oldCombinedScore = applicantRecord.combined_score || 0;
154+
applicantRecord.combined_score =
155+
oldCombinedScore - oldReviewedScore + newReviewedScore;
156+
157+
await applicantRecord.save({ transaction: t });
158+
159+
return reviewedRecord;
160+
});
161+
162+
return updatedRecord.toJSON() as ReviewedApplicantRecordDTO;
163+
}
83164
}
84165

85166
export default ReviewedApplicantRecordService;

backend/typescript/services/interfaces/IReviewedApplicantRecordService.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
ReviewedApplicantRecordDTO,
33
CreateReviewedApplicantRecordDTO,
44
DeleteReviewedApplicantRecordDTO,
5+
UpdateReviewedApplicantRecordDTO,
56
} from "../../types";
67

78
interface IReviewApplicantRecordService {
@@ -37,6 +38,15 @@ interface IReviewApplicantRecordService {
3738
bulkDeleteReviewedApplicantRecord(
3839
deleteReviewedApplicantRecords: DeleteReviewedApplicantRecordDTO[],
3940
): Promise<ReviewedApplicantRecordDTO[]>;
41+
42+
/**
43+
* Updates the review content and/or status of a ReviewedApplicantRecord
44+
* Also updates the combined score in the ApplicantRecord table
45+
* @Param updateReviewedApplicantRecordDTO data to update reviewed applicant record
46+
*/
47+
updateReviewedApplicantRecord(
48+
updateReviewedApplicantRecordDTO: UpdateReviewedApplicantRecordDTO,
49+
): Promise<ReviewedApplicantRecordDTO>;
4050
}
4151

4252
export default IReviewApplicantRecordService;

backend/typescript/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,13 @@ export type DeleteReviewedApplicantRecordDTO = {
220220
reviewerId: number;
221221
};
222222

223+
export type UpdateReviewedApplicantRecordDTO = {
224+
applicantRecordId: string;
225+
reviewerId: number;
226+
review?: Review;
227+
status?: ReviewStatus;
228+
};
229+
223230
export type AdminCommentDTO = {
224231
id: string;
225232
userId: number;

0 commit comments

Comments
 (0)