From 3a668c9e116961f5c526a8ebc30f173cf8522bca Mon Sep 17 00:00:00 2001 From: andrewlalis Date: Fri, 17 Jan 2025 21:32:40 -0500 Subject: [PATCH] Added ability to move students to another class. --- api/source/api_modules/classroom_compliance.d | 55 +++++++++++++--- app/src/api/classroom_compliance.ts | 8 +++ .../classroom_compliance/EditStudentView.vue | 63 ++++++++++++++++++- 3 files changed, 117 insertions(+), 9 deletions(-) diff --git a/api/source/api_modules/classroom_compliance.d b/api/source/api_modules/classroom_compliance.d index df85f43..38f0184 100644 --- a/api/source/api_modules/classroom_compliance.d +++ b/api/source/api_modules/classroom_compliance.d @@ -64,6 +64,7 @@ void registerApiEndpoints(PathHandler handler) { handler.addMapping(Method.GET, STUDENT_PATH, &getStudent); handler.addMapping(Method.PUT, STUDENT_PATH, &updateStudent); handler.addMapping(Method.DELETE, STUDENT_PATH, &deleteStudent); + handler.addMapping(Method.PUT, STUDENT_PATH ~ "/class", &moveStudentToOtherClass); handler.addMapping(Method.GET, STUDENT_PATH ~ "/entries", &getStudentEntries); handler.addMapping(Method.GET, STUDENT_PATH ~ "/overview", &getStudentOverview); @@ -394,15 +395,24 @@ void getEntries(ref HttpRequestContext ctx) { // Find the student object this entry belongs to, then add it to their list. ulong studentId = row.peek!ulong(5); bool studentFound = false; - foreach (idx, student; students) { - if (student.id == studentId) { - studentObjects[idx].object["entries"].object[dateStr] = entry; + foreach (idx, studentObj; studentObjects) { + if (studentObj.object["id"].uinteger == studentId) { + studentObj.object["entries"].object[dateStr] = entry; studentFound = true; break; } } if (!studentFound) { - throw new Exception("Failed to find student."); + // The student isn't in our list of original students from the class, so it's a student who's moved to another. + JSONValue obj = JSONValue.emptyObject; + obj.object["id"] = JSONValue(studentId); + obj.object["deskNumber"] = JSONValue(row.peek!ushort(7)); + obj.object["name"] = JSONValue(row.peek!string(6)); + obj.object["removed"] = JSONValue(row.peek!bool(8)); + obj.object["entries"] = JSONValue.emptyObject; + obj.object["entries"].object[dateStr] = entry; + obj.object["score"] = JSONValue(null); + studentObjects ~= obj; } } @@ -411,9 +421,9 @@ void getEntries(ref HttpRequestContext ctx) { foreach (studentId, score; scores) { JSONValue scoreValue = score.isNull ? JSONValue(null) : JSONValue(score.value); bool studentFound = false; - foreach (idx, student; students) { - if (studentId == student.id) { - studentObjects[idx].object["score"] = scoreValue; + foreach (studentObj; studentObjects) { + if (studentObj.object["id"].uinteger == studentId) { + studentObj.object["score"] = scoreValue; studentFound = true; break; } @@ -737,6 +747,37 @@ private Optional!double calculateScore( return Optional!double.of(score); } +void moveStudentToOtherClass(ref HttpRequestContext ctx) { + auto db = getDb(); + User user = getUserOrThrow(ctx, db); + auto student = getStudentOrThrow(ctx, db, user); + struct Payload { + ulong classId; + } + Payload payload = readJsonPayload!(Payload)(ctx); + if (payload.classId == student.classId) { + return; // Quit if the student is already in the desired class. + } + // Check that the desired class exists, and belongs to the user. + bool newClassIdValid = canFind( + db, + "SELECT id FROM classroom_compliance_class WHERE user_id = ? and id = ?", + user.id, payload.classId + ); + if (!newClassIdValid) { + ctx.response.status = HttpStatus.BAD_REQUEST; + ctx.response.writeBodyString("Invalid class was selected."); + return; + } + // All good, so update the student's class to the desired one, and reset their desk. + db.execute( + "UPDATE classroom_compliance_student SET class_id = ?, desk_number = 0 WHERE id = ?", + payload.classId, + student.id + ); + // We just return 200 OK, no response body. +} + void getStudentEntries(ref HttpRequestContext ctx) { auto db = getDb(); User user = getUserOrThrow(ctx, db); diff --git a/app/src/api/classroom_compliance.ts b/app/src/api/classroom_compliance.ts index c151d18..da210d5 100644 --- a/app/src/api/classroom_compliance.ts +++ b/app/src/api/classroom_compliance.ts @@ -140,6 +140,14 @@ export class ClassroomComplianceAPIClient extends APIClient { return super.put(`/classes/${classId}/students/${studentId}`, data) } + moveStudentToOtherClass( + classId: number, + studentId: number, + newClassId: number, + ): APIResponse { + return super.put(`/classes/${classId}/students/${studentId}/class`, { classId: newClassId }) + } + deleteStudent(classId: number, studentId: number): APIResponse { return super.delete(`/classes/${classId}/students/${studentId}`) } diff --git a/app/src/apps/classroom_compliance/EditStudentView.vue b/app/src/apps/classroom_compliance/EditStudentView.vue index be46d8e..230ff82 100644 --- a/app/src/apps/classroom_compliance/EditStudentView.vue +++ b/app/src/apps/classroom_compliance/EditStudentView.vue @@ -1,12 +1,15 @@