Skip to content

Commit a4248e8

Browse files
committed
add GraphQL mutators to support CUDing, for new admin comments feature of applicant records
1 parent 7867d17 commit a4248e8

File tree

6 files changed

+200
-0
lines changed

6 files changed

+200
-0
lines changed

backend/typescript/graphql/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import userType from "./types/userType";
1818
import dashboardType from "./types/dashboardType";
1919
import dashboardResolvers from "./resolvers/dashboardResolvers";
2020
import reviewType from "./types/reviewType";
21+
import adminCommentResolvers from "./resolvers/adminCommentsResolvers";
22+
import adminCommentsType from "./types/adminCommentsType";
2123

2224
const query = gql`
2325
type Query {
@@ -41,13 +43,15 @@ const executableSchema = makeExecutableSchema({
4143
simpleEntityType,
4244
userType,
4345
dashboardType,
46+
adminCommentsType,
4447
],
4548
resolvers: merge(
4649
authResolvers,
4750
entityResolvers,
4851
simpleEntityResolvers,
4952
userResolvers,
5053
dashboardResolvers,
54+
adminCommentResolvers,
5155
),
5256
});
5357

@@ -90,6 +94,9 @@ const graphQLMiddlewares = {
9094
logout: isAuthorizedByUserId("userId"),
9195
resetPassword: isAuthorizedByEmail("email"),
9296
sendSignInLink: authorizedByAllRoles(),
97+
createAdminComment: authorizedByAdmin(),
98+
updateAdminComment: authorizedByAdmin(),
99+
deleteAdminCommentById: authorizedByAdmin(),
93100
},
94101
};
95102

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import AdminCommentService from "../../services/implementations/adminCommentService";
2+
import IAdminCommentService from "../../services/interfaces/adminCommentService";
3+
import { CreateAdminCommentDTO, AdminCommentDTO } from "../../types";
4+
5+
const adminCommentService: IAdminCommentService = new AdminCommentService();
6+
7+
const adminCommentResolvers = {
8+
Mutation: {
9+
createAdminComment: async (
10+
_parent: undefined,
11+
{ adminComment }: { adminComment: CreateAdminCommentDTO },
12+
): Promise<AdminCommentDTO> => {
13+
const newAdminComment = await adminCommentService.createAdminComment(
14+
adminComment,
15+
);
16+
return newAdminComment;
17+
},
18+
updateAdminComment: async (
19+
_parent: undefined,
20+
{ id, content }: { id: string; content: CreateAdminCommentDTO },
21+
): Promise<AdminCommentDTO> => {
22+
const adminComment = await adminCommentService.updateAdminComment(
23+
id,
24+
content,
25+
);
26+
return adminComment;
27+
},
28+
deleteAdminCommentById: async (
29+
_parent: undefined,
30+
{ id }: { id: string },
31+
): Promise<AdminCommentDTO> => {
32+
const adminComment = await adminCommentService.deleteAdminCommentById(id);
33+
return adminComment;
34+
},
35+
},
36+
};
37+
38+
export default adminCommentResolvers;
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { gql } from "apollo-server-express";
2+
3+
const adminCommentsType = gql`
4+
type AdminCommentDTO {
5+
id: String!
6+
userId: Int!
7+
applicantRecordId: String!
8+
comment: String!
9+
createdAt: String!
10+
updatedAt: String!
11+
}
12+
13+
input CreateAdminCommentDTO {
14+
userId: Int!
15+
applicantRecordId: String!
16+
comment: String!
17+
}
18+
19+
extend type Mutation {
20+
createAdminComment(adminComment: CreateAdminCommentDTO!): AdminCommentDTO!
21+
updateAdminComment(
22+
id: String!
23+
content: CreateAdminCommentDTO!
24+
): AdminCommentDTO!
25+
deleteAdminCommentById(id: String!): AdminCommentDTO!
26+
}
27+
`;
28+
29+
export default adminCommentsType;
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import { AdminCommentDTO, CreateAdminCommentDTO } from "../../types";
2+
import { getErrorMessage } from "../../utilities/errorUtils";
3+
import logger from "../../utilities/logger";
4+
import AdminComment from "../../models/adminComment.model";
5+
import IAdminCommentService from "../interfaces/adminCommentService";
6+
7+
const Logger = logger(__filename);
8+
9+
const grabAdminComment = async (commentId: string): Promise<AdminComment> => {
10+
try {
11+
const adminComment = await AdminComment.findByPk(commentId);
12+
if (!adminComment) {
13+
throw new Error(`adminCommentId ${commentId} not found.`);
14+
}
15+
return adminComment;
16+
} catch (error: unknown) {
17+
Logger.error(
18+
`Failed to get admin comment. Reason = ${getErrorMessage(error)}`,
19+
);
20+
throw error;
21+
}
22+
};
23+
24+
class AdminCommentService implements IAdminCommentService {
25+
/* eslint-disable class-methods-use-this */
26+
27+
async createAdminComment(
28+
content: CreateAdminCommentDTO,
29+
): Promise<AdminCommentDTO> {
30+
try {
31+
const adminComment = await AdminComment.create({
32+
userId: content.userId,
33+
applicantRecordId: content.applicantRecordId,
34+
comment: content.comment,
35+
createdAt: new Date(),
36+
updatedAt: new Date(),
37+
});
38+
return {
39+
id: String(adminComment.id),
40+
userId: adminComment.userId,
41+
applicantRecordId: String(adminComment.applicantRecordId),
42+
comment: adminComment.comment,
43+
createdAt: adminComment.createdAt.toISOString(),
44+
updatedAt: adminComment.updatedAt.toISOString(),
45+
};
46+
} catch (error: unknown) {
47+
Logger.error(
48+
`Failed to create admin comment. Reason = ${getErrorMessage(error)}`,
49+
);
50+
throw error;
51+
}
52+
}
53+
54+
async updateAdminComment(
55+
commentId: string,
56+
content: CreateAdminCommentDTO,
57+
): Promise<AdminCommentDTO> {
58+
const adminComment = await grabAdminComment(commentId);
59+
try {
60+
adminComment.comment = content.comment;
61+
adminComment.updatedAt = new Date();
62+
await adminComment.save();
63+
return {
64+
id: String(adminComment.id),
65+
userId: adminComment.userId,
66+
applicantRecordId: String(adminComment.applicantRecordId),
67+
comment: adminComment.comment,
68+
createdAt: adminComment.createdAt.toISOString(),
69+
updatedAt: adminComment.updatedAt.toISOString(),
70+
};
71+
} catch (error: unknown) {
72+
Logger.error(
73+
`Failed to update admin comment. Reason = ${getErrorMessage(error)}`,
74+
);
75+
throw error;
76+
}
77+
}
78+
79+
async deleteAdminCommentById(id: string): Promise<AdminCommentDTO> {
80+
const adminComment = await grabAdminComment(id);
81+
try {
82+
await adminComment.destroy();
83+
return {
84+
id: String(adminComment.id),
85+
userId: adminComment.userId,
86+
applicantRecordId: String(adminComment.applicantRecordId),
87+
comment: adminComment.comment,
88+
createdAt: adminComment.createdAt.toISOString(),
89+
updatedAt: adminComment.updatedAt.toISOString(),
90+
};
91+
} catch (error: unknown) {
92+
Logger.error(
93+
`Failed to delete admin comment. Reason = ${getErrorMessage(error)}`,
94+
);
95+
throw error;
96+
}
97+
}
98+
}
99+
100+
export default AdminCommentService;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { AdminCommentDTO, CreateAdminCommentDTO } from "../../types";
2+
3+
interface IAdminCommentService {
4+
createAdminComment(content: CreateAdminCommentDTO): Promise<AdminCommentDTO>;
5+
updateAdminComment(
6+
commentId: string,
7+
content: CreateAdminCommentDTO,
8+
): Promise<AdminCommentDTO>;
9+
deleteAdminCommentById(id: string): Promise<AdminCommentDTO>;
10+
}
11+
12+
export default IAdminCommentService;

backend/typescript/types.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,3 +239,17 @@ export type ReviewedApplicantRecordDTO = {
239239
score?: number | null;
240240
reviewerHasConflict: boolean;
241241
};
242+
243+
export type AdminCommentDTO = {
244+
id: string;
245+
userId: number;
246+
applicantRecordId: string;
247+
comment: string;
248+
createdAt: string;
249+
updatedAt: string;
250+
};
251+
252+
export type CreateAdminCommentDTO = Pick<
253+
AdminCommentDTO,
254+
"userId" | "applicantRecordId" | "comment"
255+
>;

0 commit comments

Comments
 (0)