Skip to content

Commit ae9a9e3

Browse files
committed
add features for add attendance and fetch it for student admin assistant
1 parent 21d7068 commit ae9a9e3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+991
-36
lines changed

prisma/schema.prisma

+26-20
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ model Practicum {
6565
assistantGroups AssistantGroup[]
6666
LabExamScore LabExamScore[]
6767
ControlCard ControlCard[]
68+
Attendance Attendance[]
6869
6970
@@map("practicums")
7071
}
@@ -112,7 +113,7 @@ model Meeting {
112113

113114
model Attendance {
114115
id String @id @default(uuid())
115-
classroom Classroom @relation(fields: [classroomId], references: [id], onDelete: Cascade, onUpdate: Cascade)
116+
classroom Classroom? @relation(fields: [classroomId], references: [id], onDelete: Cascade, onUpdate: Cascade)
116117
meeting Meeting @relation(fields: [meetingId], references: [id], onDelete: Cascade, onUpdate: Cascade)
117118
student Profile @relation(fields: [profileId], references: [id], onDelete: Cascade, onUpdate: Cascade)
118119
attendanceStatus ATTENDANCE_STATUS @default(ABSENT)
@@ -121,42 +122,47 @@ model Attendance {
121122
note String? @db.Text
122123
createdAt DateTime @default(now())
123124
updatedAt DateTime @default(now()) @updatedAt
124-
classroomId String
125+
classroomId String?
125126
meetingId String
126127
profileId String
128+
practicum Practicum @relation(fields: [practicumId], references: [id], onDelete: Cascade, onUpdate: Cascade)
129+
practicumId String
127130
128131
@@map("attendances")
129132
}
130133

131134
model AssistantGroup {
132-
id String @id @default(uuid())
133-
number Int @db.UnsignedSmallInt
134-
assistant Profile @relation(name: "assistant_group_assistant", fields: [assistantId], references: [id], onDelete: Cascade, onUpdate: Cascade)
135-
students Profile[] @relation(name: "assistant_group_student")
136-
practicum Practicum @relation(fields: [practicumId], references: [id], onDelete: Cascade, onUpdate: Cascade)
137-
githubRepoLink String? @db.VarChar(255)
138-
createdAt DateTime @default(now())
139-
updatedAt DateTime @default(now()) @updatedAt
135+
id String @id @default(uuid())
136+
number Int @db.UnsignedSmallInt
137+
assistant Profile @relation(name: "assistant_group_assistant", fields: [assistantId], references: [id], onDelete: Cascade, onUpdate: Cascade)
138+
students Profile[] @relation(name: "assistant_group_student")
139+
practicum Practicum @relation(fields: [practicumId], references: [id], onDelete: Cascade, onUpdate: Cascade)
140+
githubRepoLink String? @db.VarChar(255)
141+
createdAt DateTime @default(now())
142+
updatedAt DateTime @default(now()) @updatedAt
140143
assistantId String
141144
practicumId String
145+
ControlCard ControlCard[]
142146
143147
@@map("assistant_groups")
144148
}
145149

146150
model ControlCard {
147-
id String @id @default(uuid())
148-
student Profile @relation(fields: [profileId], references: [id], onDelete: Cascade, onUpdate: Cascade)
149-
meeting Meeting @relation(fields: [meetingId], references: [id], onDelete: Cascade, onUpdate: Cascade)
150-
firstAssistance Assistance? @relation(name: "control_card_first_assistance", fields: [firstAssistanceId], references: [id])
151-
secondAssistance Assistance? @relation(name: "control_card_second_assistance", fields: [secondAssistanceId], references: [id])
152-
createdAt DateTime @default(now())
153-
updatedAt DateTime @default(now()) @updatedAt
151+
id String @id @default(uuid())
152+
student Profile @relation(fields: [profileId], references: [id], onDelete: Cascade, onUpdate: Cascade)
153+
meeting Meeting @relation(fields: [meetingId], references: [id], onDelete: Cascade, onUpdate: Cascade)
154+
firstAssistance Assistance? @relation(name: "control_card_first_assistance", fields: [firstAssistanceId], references: [id])
155+
secondAssistance Assistance? @relation(name: "control_card_second_assistance", fields: [secondAssistanceId], references: [id])
156+
createdAt DateTime @default(now())
157+
updatedAt DateTime @default(now()) @updatedAt
154158
profileId String
155159
meetingId String
156-
firstAssistanceId String? @unique
157-
secondAssistanceId String? @unique
158-
practicum Practicum? @relation(fields: [practicumId], references: [id], onDelete: Cascade, onUpdate: Cascade)
160+
firstAssistanceId String? @unique
161+
secondAssistanceId String? @unique
162+
practicum Practicum? @relation(fields: [practicumId], references: [id], onDelete: Cascade, onUpdate: Cascade)
159163
practicumId String?
164+
group AssistantGroup? @relation(fields: [assistantGroupId], references: [id], onDelete: Cascade, onUpdate: Cascade)
165+
assistantGroupId String?
160166
161167
@@map("control_cards")
162168
}

readme.md

+7
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,10 @@ untuk menambahkan data student pada database
2525
1. (practicums.getPracticumStudentCards) /api/practicums/{practicumId}/students/{studentProfileId}/cards -> get student control cards based on the practicum (authorized for assistant and admin)
2626
2. (practicums.getStudentPracticumControlCards) /api/cards/{controlCardId} -> get control card detail (authorized for assistant and student)
2727
3. (cards.getControlCardDetail) /api/practicums/{practicumId}/cards -> get student own control cards (authorized for student)
28+
29+
## DEV LOG <20 July 2024>
30+
31+
1. (practicums.getStudentPracticumAttendancesByAdminAndAssistant) /api/practicums/{practicumId}/students/{studentProfileId}/attendances -> get student attendances based on the practicum (authorized for assistant and admin)
32+
2. (meetings.addAttendanceForStudentInAMeeting) /api/meetings/{meetingId}/attendances -> post attendances based on the meeting
33+
3. (practicums.getPracticumAttendancesForStudent) /api/practicums/{practicumId}/attendances -> get student own attendances (authorized for student)
34+
4. (attendances.deleteAttendanceById) /api/attendances/{attendanceId} -> delete attendance by id (authorized for assistant and admin)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { NextFunction, Request, Response } from "express";
2+
3+
export abstract class AttendanceHandler {
4+
constructor() {
5+
this.deleteAttendance = this.deleteAttendance.bind(this);
6+
}
7+
8+
abstract deleteAttendance(
9+
req: Request,
10+
res: Response,
11+
next: NextFunction
12+
): Promise<any>;
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { Request, Response, NextFunction } from "express";
2+
import {
3+
RESPONSE_MESSAGE,
4+
createResponse,
5+
getTokenPayload,
6+
} from "../../../utils";
7+
import { SchemaValidator } from "../../../utils/validator/SchemaValidator";
8+
import { ParamsDictionary } from "express-serve-static-core";
9+
import { ParsedQs } from "qs";
10+
import { AttendanceService } from "../../../services/attendance/AttendanceService";
11+
import { AttendanceHandler } from "./AttendanceHandler";
12+
13+
export class AttendanceHandlerImpl extends AttendanceHandler {
14+
private attendanceService: AttendanceService;
15+
private schemaValidator: SchemaValidator;
16+
17+
constructor(
18+
service: {
19+
attendanceService: AttendanceService;
20+
},
21+
schemaValidator: SchemaValidator
22+
) {
23+
super();
24+
this.attendanceService = service.attendanceService;
25+
this.schemaValidator = schemaValidator;
26+
}
27+
28+
async deleteAttendance(
29+
req: Request,
30+
res: Response,
31+
next: NextFunction
32+
): Promise<any> {
33+
const { id } = req.params;
34+
35+
try {
36+
await this.attendanceService.deleteAttendanceById(id);
37+
38+
return res
39+
.status(200)
40+
.json(
41+
createResponse(
42+
RESPONSE_MESSAGE.SUCCESS,
43+
"delete attendance succesfully"
44+
)
45+
);
46+
} catch (error) {
47+
return next(error);
48+
}
49+
}
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { Router } from "express";
2+
import { AuthorizationBearer } from "../../../middleware/auth/AuthorizationBearer";
3+
import { BaseRouter } from "../../base/Router";
4+
import { USER_ROLE } from "@prisma/client";
5+
import { AttendanceHandler } from "../handler/AttendanceHandler";
6+
7+
export class AttendanceRouter extends BaseRouter {
8+
private authorizationMiddlware: AuthorizationBearer;
9+
private handler: AttendanceHandler;
10+
11+
constructor(
12+
handler: AttendanceHandler,
13+
authorizationMiddleware: AuthorizationBearer
14+
) {
15+
super("/attendances");
16+
this.handler = handler;
17+
this.authorizationMiddlware = authorizationMiddleware;
18+
}
19+
20+
register(): Router {
21+
// * delete attendance by id
22+
this.router
23+
.route(this.path + "/:id")
24+
.delete(
25+
this.authorizationMiddlware.authorize([
26+
USER_ROLE.ADMIN,
27+
USER_ROLE.ASSISTANT,
28+
]),
29+
this.handler.deleteAttendance
30+
);
31+
32+
return this.router;
33+
}
34+
}

src/api/classroom/handler/ClassroomHandlerImpl.ts

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export class ClassroomHandlerImpl extends ClassRoomHandler {
2626
constructor(
2727
service: {
2828
classroomPracticumStudentsService: ClassroomPracticumStudentsService;
29+
2930
classroomService: ClassroomService;
3031
meetingService: MeetingService;
3132
},

src/api/meeting/handler/MeetingHandler.ts

+7
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,15 @@ export abstract class MeetingHandler {
55
this.deleteMeeting = this.deleteMeeting.bind(this);
66
this.getMeeting = this.getMeeting.bind(this);
77
this.putMeeting = this.putMeeting.bind(this);
8+
this.postMeetingAttendance = this.postMeetingAttendance.bind(this);
89
}
910

11+
abstract postMeetingAttendance(
12+
req: Request,
13+
res: Response,
14+
next: NextFunction
15+
): Promise<any>;
16+
1017
abstract putMeeting(
1118
req: Request,
1219
res: Response,

src/api/meeting/handler/MeetingHandlerImpl.ts

+33
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,55 @@ import { MeetingHandler } from "./MeetingHandler";
1212
import { MeetingDTO } from "../../../utils/dto/meeting/IMeetingDTO";
1313
import { IPutClassroomMeetingPayload } from "../../../utils/interfaces/request/IPutClassroomMeetingPayload";
1414
import { PracticumMeetingPutPayloadSchema } from "../../../utils/validator/meeting/Joi/PracticumMeetingPutPayloadSchema";
15+
import { IPostMeetingAttendancePayload } from "../../../utils/interfaces/request/IPostMeetingAttendancePayload";
16+
import { MeetingAttendancePostPayloadSchema } from "../../../utils/validator/attendance/Joi/MeetingAttendancePostPayloadSchema";
17+
import { AttendanceService } from "../../../services/attendance/AttendanceService";
1518

1619
export class MeetingHandlerImpl extends MeetingHandler {
1720
private meetingService: MeetingService;
21+
private attendanceService: AttendanceService;
1822
private schemaValidator: SchemaValidator;
1923

2024
constructor(
2125
service: {
2226
meetingService: MeetingService;
27+
attendanceService: AttendanceService;
2328
},
2429
schemaValidator: SchemaValidator
2530
) {
2631
super();
2732
this.meetingService = service.meetingService;
33+
this.attendanceService = service.attendanceService;
2834
this.schemaValidator = schemaValidator;
2935
}
3036

37+
async postMeetingAttendance(
38+
req: Request,
39+
res: Response,
40+
next: NextFunction
41+
): Promise<any> {
42+
const { id } = req.params;
43+
const payload: IPostMeetingAttendancePayload = req.body;
44+
const { profileId } = getTokenPayload(res);
45+
46+
try {
47+
this.schemaValidator.validate({
48+
schema: MeetingAttendancePostPayloadSchema,
49+
payload,
50+
});
51+
52+
await this.attendanceService.addAttendance(id, payload, profileId);
53+
54+
return res
55+
.status(200)
56+
.json(
57+
createResponse(RESPONSE_MESSAGE.SUCCESS, "successfully edit meeting")
58+
);
59+
} catch (error) {
60+
return next(error);
61+
}
62+
}
63+
3164
async putMeeting(
3265
req: Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>,
3366
res: Response<any, Record<string, any>>,

src/api/meeting/router/MeetingRouterImpl.ts

+8
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ export class MeetingRouter extends BaseRouter {
4242
this.handler.putMeeting
4343
);
4444

45+
// * create attendance of a meeting
46+
this.router
47+
.route(this.path + "/:id/attendances")
48+
.post(
49+
this.authorizationMiddlware.authorize([USER_ROLE.ASSISTANT]),
50+
this.handler.postMeetingAttendance
51+
);
52+
4553
return this.router;
4654
}
4755
}

src/api/practicum/handler/PracticumHandler.ts

+15
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,23 @@ export abstract class PracticumHandler {
1818
this.getPracticumControlCards = this.getPracticumControlCards.bind(this);
1919
this.getStudentPracticumControlCards =
2020
this.getStudentPracticumControlCards.bind(this);
21+
this.getPracticumAttendances = this.getPracticumAttendances.bind(this);
22+
this.getStudentPracticumAttendances =
23+
this.getStudentPracticumAttendances.bind(this);
2124
}
2225

26+
abstract getStudentPracticumAttendances(
27+
req: Request,
28+
res: Response,
29+
next: NextFunction
30+
): Promise<any>;
31+
32+
abstract getPracticumAttendances(
33+
req: Request,
34+
res: Response,
35+
next: NextFunction
36+
): Promise<any>;
37+
2338
abstract getStudentPracticumControlCards(
2439
req: Request,
2540
res: Response,

0 commit comments

Comments
 (0)