From e64829d964004f7285a3d56c1f6f5213d209fbdf Mon Sep 17 00:00:00 2001 From: Matti Lupari Date: Tue, 4 Jun 2024 18:35:24 +0300 Subject: [PATCH] CSCEXAM-1333 Fix handling of query params / reservation removal --- app/controllers/ReservationController.java | 152 ++++++++---------- .../reservation-details.component.ts | 3 +- 2 files changed, 71 insertions(+), 84 deletions(-) diff --git a/app/controllers/ReservationController.java b/app/controllers/ReservationController.java index 6b37c15be..2edfb1c94 100644 --- a/app/controllers/ReservationController.java +++ b/app/controllers/ReservationController.java @@ -45,6 +45,7 @@ import models.base.GeneratedIdentityModel; import org.joda.time.DateTime; import org.joda.time.format.ISODateTimeFormat; +import play.data.DynamicForm; import play.libs.Json; import play.mvc.Http; import play.mvc.Result; @@ -82,15 +83,14 @@ public Result getExams(Http.Request request, Optional filter) { el = el.ilike("name", String.format("%%%s%%", filter.get())); } if (user.hasRole(Role.Name.TEACHER)) { - el = - el - .gt("periodEnd", new Date()) - .disjunction() - .eq("creator", user) - .eq("examOwners", user) - .eq("examInspections.user", user) - .eq("shared", true) - .endJunction(); + el = el + .gt("periodEnd", new Date()) + .disjunction() + .eq("creator", user) + .eq("examOwners", user) + .eq("examInspections.user", user) + .eq("shared", true) + .endJunction(); } return ok(el.findList(), props); } @@ -140,28 +140,23 @@ public Result getTeachers(Optional filter) { @Restrict({ @Group("ADMIN") }) public CompletionStage removeReservation(long id, Http.Request request) throws NotFoundException { - var msg = request.body().asJson().get("msg").asText(""); var enrolment = DB.find(ExamEnrolment.class).where().eq("reservation.id", id).findOne(); - if (enrolment == null) { throw new NotFoundException(String.format("No reservation with id %d for current user.", id)); } - var participation = DB.find(ExamParticipation.class).where().eq("exam", enrolment.getExam()).findOne(); - if (participation != null) { return wrapAsPromise( forbidden(String.format("i18n_unable_to_remove_reservation (id=%d).", participation.getId())) ); } - var reservation = enrolment.getReservation(); + var msg = formFactory.form().bindFromRequest(request).get("msg"); // Let's not send emails about historical reservations if (reservation.getEndAt().isAfter(DateTime.now())) { var student = enrolment.getUser(); emailComposer.composeReservationCancellationNotification(student, reservation, msg, false, enrolment); } - if (reservation.getExternalReservation() != null) { return externalReservationHandler.removeReservation(reservation, enrolment.getUser(), msg); } else { @@ -263,8 +258,7 @@ public Result getExaminationEvents( Optional end, Http.Request request ) { - var query = DB - .find(ExamEnrolment.class) + var query = DB.find(ExamEnrolment.class) .fetch("user", "id, firstName, lastName, email, userIdentifier") .fetch("exam", "id, name, state, trialCount, implementation") .fetch("exam.course", "code") @@ -277,13 +271,12 @@ public Result getExaminationEvents( .isNotNull("exam"); var user = request.attrs().get(Attrs.AUTHENTICATED_USER); if (user.hasRole(Role.Name.TEACHER)) { - query = - query - .disjunction() - .eq("exam.parent.examOwners", user) - .eq("exam.examOwners", user) - .endJunction() - .ne("exam.state", Exam.State.DELETED); + query = query + .disjunction() + .eq("exam.parent.examOwners", user) + .eq("exam.examOwners", user) + .endJunction() + .ne("exam.state", Exam.State.DELETED); } if (start.isPresent()) { @@ -292,12 +285,11 @@ public Result getExaminationEvents( } if (state.isPresent()) { - query = - switch (state.get()) { - case "NO_SHOW" -> query.eq("noShow", true); - case "EXTERNAL_UNFINISHED", "EXTERNAL_FINISHED" -> query.isNull("id"); // Deliberately force an empty result set - default -> query.eq("exam.state", Exam.State.valueOf(state.get())).eq("noShow", false); - }; + query = switch (state.get()) { + case "NO_SHOW" -> query.eq("noShow", true); + case "EXTERNAL_UNFINISHED", "EXTERNAL_FINISHED" -> query.isNull("id"); // Deliberately force an empty result set + default -> query.eq("exam.state", Exam.State.valueOf(state.get())).eq("noShow", false); + }; } if (studentId.isPresent()) { @@ -308,23 +300,21 @@ public Result getExaminationEvents( } } if (examId.isPresent()) { - query = - query - .ne("exam.state", Exam.State.DELETED) // Local student reservation - .disjunction() - .eq("exam.parent.id", examId.get()) - .eq("exam.id", examId.get()) - .endJunction(); + query = query + .ne("exam.state", Exam.State.DELETED) // Local student reservation + .disjunction() + .eq("exam.parent.id", examId.get()) + .eq("exam.id", examId.get()) + .endJunction(); } if (ownerId.isPresent() && user.hasRole(Role.Name.ADMIN)) { var userId = ownerId.get(); - query = - query - .disjunction() - .eq("exam.examOwners.id", userId) - .eq("exam.parent.examOwners.id", userId) - .endJunction(); + query = query + .disjunction() + .eq("exam.examOwners.id", userId) + .eq("exam.parent.examOwners.id", userId) + .endJunction(); } var enrolments = query .orderBy("examinationEventConfiguration.examinationEvent.start") @@ -368,8 +358,7 @@ public Result getReservations( Optional externalRef, Http.Request request ) { - var query = DB - .find(Reservation.class) + var query = DB.find(Reservation.class) .fetch("enrolment", "noShow, retrialPermitted") .fetch("user", "id, firstName, lastName, email, userIdentifier") .fetch("enrolment.exam", "id, name, state, trialCount, implementation") @@ -387,15 +376,14 @@ public Result getReservations( var user = request.attrs().get(Attrs.AUTHENTICATED_USER); if (user.hasRole(Role.Name.TEACHER)) { - query = - query - .isNull("enrolment.externalExam") // Hide reservations of external students (just to be sure) - .isNull("enrolment.collaborativeExam") // Hide collaborative exams from teachers. - .ne("enrolment.exam.state", Exam.State.DELETED) // Hide deleted exams from teachers - .disjunction() - .eq("enrolment.exam.parent.examOwners", user) - .eq("enrolment.exam.examOwners", user) - .endJunction(); + query = query + .isNull("enrolment.externalExam") // Hide reservations of external students (just to be sure) + .isNull("enrolment.collaborativeExam") // Hide collaborative exams from teachers. + .ne("enrolment.exam.state", Exam.State.DELETED) // Hide deleted exams from teachers + .disjunction() + .eq("enrolment.exam.parent.examOwners", user) + .eq("enrolment.exam.examOwners", user) + .endJunction(); } if (start.isPresent()) { @@ -411,19 +399,18 @@ public Result getReservations( } if (state.isPresent()) { - query = - switch (state.get()) { - case "NO_SHOW" -> query.eq("enrolment.noShow", true); - case "EXTERNAL_UNFINISHED" -> query - .isNotNull("externalUserRef") - .isNull("enrolment.externalExam.finished"); - case "EXTERNAL_FINISHED" -> query - .isNotNull("externalUserRef") - .isNotNull("enrolment.externalExam.finished"); - default -> query - .eq("enrolment.exam.state", Exam.State.valueOf(state.get())) - .eq("enrolment.noShow", false); - }; + query = switch (state.get()) { + case "NO_SHOW" -> query.eq("enrolment.noShow", true); + case "EXTERNAL_UNFINISHED" -> query + .isNotNull("externalUserRef") + .isNull("enrolment.externalExam.finished"); + case "EXTERNAL_FINISHED" -> query + .isNotNull("externalUserRef") + .isNotNull("enrolment.externalExam.finished"); + default -> query + .eq("enrolment.exam.state", Exam.State.valueOf(state.get())) + .eq("enrolment.noShow", false); + }; } if (studentId.isPresent()) { @@ -444,33 +431,32 @@ public Result getReservations( query = query.eq("machine.id", machineId.get()); } if (examId.isPresent()) { - query = - query - .disjunction() - .eq("enrolment.exam.parent.id", examId.get()) - .eq("enrolment.exam.id", examId.get()) - .endJunction(); + query = query + .disjunction() + .eq("enrolment.exam.parent.id", examId.get()) + .eq("enrolment.exam.id", examId.get()) + .endJunction(); } else if (externalRef.isPresent()) { query = query.eq("enrolment.collaborativeExam.externalRef", externalRef.get()); } if (ownerId.isPresent() && user.hasRole(Role.Name.ADMIN)) { var userId = ownerId.get(); - query = - query - .disjunction() - .eq("enrolment.exam.examOwners.id", userId) - .eq("enrolment.exam.parent.examOwners.id", userId) - .endJunction(); + query = query + .disjunction() + .eq("enrolment.exam.examOwners.id", userId) + .eq("enrolment.exam.parent.examOwners.id", userId) + .endJunction(); } var reservations = query.orderBy("startAt").findSet(); var result = ok(reservations); var anonIds = reservations .stream() - .filter(r -> - r.getEnrolment() != null && - r.getEnrolment().getExam() != null && - r.getEnrolment().getExam().isAnonymous() + .filter( + r -> + r.getEnrolment() != null && + r.getEnrolment().getExam() != null && + r.getEnrolment().getExam().isAnonymous() ) .map(GeneratedIdentityModel::getId) .collect(Collectors.toSet()); diff --git a/ui/src/app/reservation/reservation-details.component.ts b/ui/src/app/reservation/reservation-details.component.ts index 6b3a9baae..db463c23a 100644 --- a/ui/src/app/reservation/reservation-details.component.ts +++ b/ui/src/app/reservation/reservation-details.component.ts @@ -20,6 +20,7 @@ import { Component, Input, OnChanges } from '@angular/core'; import { RouterLink } from '@angular/router'; import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { ToastrService } from 'ngx-toastr'; +import { noop } from 'rxjs'; import { ExamEnrolment } from 'src/app/enrolment/enrolment.model'; import { ApplyDstPipe } from 'src/app/shared/date/apply-dst.pipe'; import { CourseCodeComponent } from 'src/app/shared/miscellaneous/course-code.component'; @@ -85,7 +86,7 @@ export class ReservationDetailsComponent implements OnChanges { this.fixedReservations.splice(this.fixedReservations.indexOf(reservation), 1); this.toast.info(this.translate.instant('i18n_reservation_removed')); }) - .catch((err) => this.toast.error(err)); + .catch(noop); } permitRetrial(enrolment: ExamEnrolment) {