use of de.tum.in.www1.artemis.domain.exam.Exam in project ArTEMiS by ls1intum.
the class ModelingExerciseResource method updateModelingExercise.
/**
* PUT modeling-exercises : Updates an existing modelingExercise.
*
* @param modelingExercise the modelingExercise to update
* @param notificationText the text shown to students
* @return the ResponseEntity with status 200 (OK) and with body the updated modelingExercise, or with status 400 (Bad Request) if the modelingExercise is not valid, or with
* status 500 (Internal Server Error) if the modelingExercise couldn't be updated
* @throws URISyntaxException if the Location URI syntax is incorrect
*/
@PutMapping("modeling-exercises")
@PreAuthorize("hasRole('EDITOR')")
public ResponseEntity<ModelingExercise> updateModelingExercise(@RequestBody ModelingExercise modelingExercise, @RequestParam(value = "notificationText", required = false) String notificationText) throws URISyntaxException {
log.debug("REST request to update ModelingExercise : {}", modelingExercise);
if (modelingExercise.getId() == null) {
return createModelingExercise(modelingExercise);
}
// validates general settings: points, dates
modelingExercise.validateGeneralSettings();
// Valid exercises have set either a course or an exerciseGroup
modelingExercise.checkCourseAndExerciseGroupExclusivity(ENTITY_NAME);
// Check that the user is authorized to update the exercise
var user = userRepository.getUserWithGroupsAndAuthorities();
// Important: use the original exercise for permission check
final ModelingExercise modelingExerciseBeforeUpdate = modelingExerciseRepository.findByIdElseThrow(modelingExercise.getId());
authCheckService.checkHasAtLeastRoleForExerciseElseThrow(Role.EDITOR, modelingExerciseBeforeUpdate, user);
// Forbid changing the course the exercise belongs to.
if (!Objects.equals(modelingExerciseBeforeUpdate.getCourseViaExerciseGroupOrCourseMember().getId(), modelingExercise.getCourseViaExerciseGroupOrCourseMember().getId())) {
throw new ConflictException("Exercise course id does not match the stored course id", ENTITY_NAME, "cannotChangeCourseId");
}
// Forbid conversion between normal course exercise and exam exercise
exerciseService.checkForConversionBetweenExamAndCourseExercise(modelingExercise, modelingExerciseBeforeUpdate, ENTITY_NAME);
ModelingExercise updatedModelingExercise = modelingExerciseRepository.save(modelingExercise);
exerciseService.logUpdate(modelingExercise, modelingExercise.getCourseViaExerciseGroupOrCourseMember(), user);
exerciseService.updatePointsInRelatedParticipantScores(modelingExerciseBeforeUpdate, updatedModelingExercise);
participationRepository.removeIndividualDueDatesIfBeforeDueDate(updatedModelingExercise, modelingExerciseBeforeUpdate.getDueDate());
modelingExerciseService.scheduleOperations(updatedModelingExercise.getId());
exerciseService.checkExampleSubmissions(updatedModelingExercise);
groupNotificationService.checkAndCreateAppropriateNotificationsWhenUpdatingExercise(modelingExerciseBeforeUpdate, updatedModelingExercise, notificationText, instanceMessageSendService);
return ResponseEntity.ok().headers(HeaderUtil.createEntityUpdateAlert(applicationName, true, ENTITY_NAME, modelingExercise.getId().toString())).body(updatedModelingExercise);
}
use of de.tum.in.www1.artemis.domain.exam.Exam in project ArTEMiS by ls1intum.
the class ParticipantScoreResource method getScoresOfExam.
/**
* GET /exams/:examId/exam-scores gets the exam scores of the exam
* <p>
* This method represents a server based way to calculate a students achieved points / score in an exam.
* <p>
* Currently both this server based calculation method and the traditional client side calculation method is used
* side-by-side in exam-scores.component.ts.
* <p>
* The goal is to switch completely to this much faster server based calculation if the {@link de.tum.in.www1.artemis.service.listeners.ResultListener}
* has been battle tested enough.
*
* @param examId the id of the exam for which to calculate the exam scores
* @return list of scores for every registered user in the xam
*/
@GetMapping("/exams/{examId}/exam-scores")
@PreAuthorize("hasRole('INSTRUCTOR')")
public ResponseEntity<List<ScoreDTO>> getScoresOfExam(@PathVariable Long examId) {
long start = System.currentTimeMillis();
log.debug("REST request to get exam scores for exam : {}", examId);
Exam exam = examRepository.findByIdWithRegisteredUsersExerciseGroupsAndExercisesElseThrow(examId);
authorizationCheckService.checkHasAtLeastRoleInCourseElseThrow(Role.INSTRUCTOR, exam.getCourse(), null);
List<ScoreDTO> scoreDTOS = participantScoreService.calculateExamScores(exam);
log.info("getScoresOfExam took {}ms", System.currentTimeMillis() - start);
return ResponseEntity.ok().body(scoreDTOS);
}
use of de.tum.in.www1.artemis.domain.exam.Exam in project ArTEMiS by ls1intum.
the class ResultResource method createResultForExternalSubmission.
/**
* POST exercises/:exerciseId/external-submission-results : Creates a new result for the provided exercise and student (a participation and an empty submission will also be created if they do not exist yet)
*
* @param exerciseId The exercise ID for which a result should get created
* @param studentLogin The student login (username) for which a result should get created
* @param result The result to be created
* @return The newly created result
* @throws URISyntaxException if the Location URI syntax is incorrect
*/
@PostMapping("exercises/{exerciseId}/external-submission-results")
@PreAuthorize("hasRole('INSTRUCTOR')")
public ResponseEntity<Result> createResultForExternalSubmission(@PathVariable Long exerciseId, @RequestParam String studentLogin, @RequestBody Result result) throws URISyntaxException {
log.debug("REST request to create Result for External Submission for Exercise : {}", exerciseId);
if (result.getParticipation() != null && result.getParticipation().getExercise() != null && !result.getParticipation().getExercise().getId().equals(exerciseId)) {
throw new BadRequestAlertException("exerciseId in RequestBody doesnt match exerciseId in path!", "Exercise", "400");
}
Exercise exercise = exerciseRepository.findByIdElseThrow(exerciseId);
authCheckService.checkHasAtLeastRoleForExerciseElseThrow(Role.INSTRUCTOR, exercise, null);
if (!exercise.isExamExercise()) {
if (exercise.getDueDate() == null || ZonedDateTime.now().isBefore(exercise.getDueDate())) {
return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(applicationName, true, "result", "externalSubmissionBeforeDueDate", "External submissions are not supported before the exercise due date.")).build();
}
} else {
Exam exam = exercise.getExerciseGroup().getExam();
ZonedDateTime latestIndividualExamEndDate = examDateService.getLatestIndividualExamEndDate(exam);
if (latestIndividualExamEndDate == null || ZonedDateTime.now().isBefore(latestIndividualExamEndDate)) {
return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(applicationName, true, "result", "externalSubmissionBeforeDueDate", "External submissions are not supported before the end of the exam.")).build();
}
}
if (exercise instanceof QuizExercise) {
return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(applicationName, true, "result", "externalSubmissionForQuizExercise", "External submissions are not supported for Quiz exercises.")).build();
}
Optional<User> student = userRepository.findOneWithGroupsAndAuthoritiesByLogin(studentLogin);
authCheckService.checkHasAtLeastRoleForExerciseElseThrow(Role.INSTRUCTOR, exercise, null);
if (student.isEmpty() || !authCheckService.isAtLeastStudentInCourse(exercise.getCourseViaExerciseGroupOrCourseMember(), student.get())) {
return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(applicationName, true, "result", "studentNotFound", "The student could not be found in this course.")).build();
}
// Check if a result exists already for this exercise and student. If so, do nothing and just inform the instructor.
Optional<StudentParticipation> optionalParticipation = participationService.findOneByExerciseAndStudentLoginAnyStateWithEagerResults(exercise, studentLogin);
if (optionalParticipation.isPresent() && optionalParticipation.get().getResults() != null && !optionalParticipation.get().getResults().isEmpty()) {
return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(applicationName, true, "result", "resultAlreadyExists", "A result already exists for this student in this exercise.")).build();
}
// Create a participation and a submitted empty submission if they do not exist yet
StudentParticipation participation = participationService.createParticipationWithEmptySubmissionIfNotExisting(exercise, student.get(), SubmissionType.EXTERNAL);
Submission submission = participationRepository.findByIdWithLegalSubmissionsElseThrow(participation.getId()).findLatestSubmission().get();
result.setParticipation(participation);
result.setSubmission(submission);
// Create a new manual result which can be rated or unrated depending on what was specified in the create form
Result savedResult = resultService.createNewManualResult(result, exercise instanceof ProgrammingExercise, result.isRated());
return ResponseEntity.created(new URI("/api/results/" + savedResult.getId())).headers(HeaderUtil.createEntityCreationAlert(applicationName, true, ENTITY_NAME, savedResult.getId().toString())).body(savedResult);
}
use of de.tum.in.www1.artemis.domain.exam.Exam in project ArTEMiS by ls1intum.
the class ComplaintResource method createComplaintForExamExercise.
/**
* POST complaints/exam/examId: create a new complaint for an exam exercise
*
* @param complaint the complaint to create
* @param principal that wants to complain
* @param examId the examId of the exam which contains the exercise
* @return the ResponseEntity with status 201 (Created) and with body the new complaints
* @throws URISyntaxException if the Location URI syntax is incorrect
*/
// TODO: should be exams/{examId}/(participations/{participationId}/)complaints
@PostMapping("complaints/exam/{examId}")
@PreAuthorize("hasRole('USER')")
public ResponseEntity<Complaint> createComplaintForExamExercise(@PathVariable Long examId, @RequestBody Complaint complaint, Principal principal) throws URISyntaxException {
log.debug("REST request to save Complaint for exam exercise: {}", complaint);
if (complaint.getId() != null) {
throw new BadRequestAlertException("A new complaint cannot already have an id", COMPLAINT_ENTITY_NAME, "idexists");
}
if (complaint.getResult() == null || complaint.getResult().getId() == null) {
throw new BadRequestAlertException("A complaint can be only associated to a result", COMPLAINT_ENTITY_NAME, "noresultid");
}
if (complaintRepository.findByResultId(complaint.getResult().getId()).isPresent()) {
throw new BadRequestAlertException("A complaint for this result already exists", COMPLAINT_ENTITY_NAME, "complaintexists");
}
Result result = resultRepository.findByIdElseThrow(complaint.getResult().getId());
// For non-exam exercises, the POST complaints should be used
if (!result.getParticipation().getExercise().isExamExercise()) {
throw new BadRequestAlertException("A complaint for an course exercise cannot be filed using this component", COMPLAINT_ENTITY_NAME, "complaintAboutCourseExerciseWrongComponent");
}
authCheckService.isOwnerOfParticipationElseThrow((StudentParticipation) result.getParticipation());
// To build correct creation alert on the front-end we must check which type is the complaint to apply correct i18n key.
String entityName = complaint.getComplaintType() == ComplaintType.MORE_FEEDBACK ? MORE_FEEDBACK_ENTITY_NAME : COMPLAINT_ENTITY_NAME;
Complaint savedComplaint = complaintService.createComplaint(complaint, OptionalLong.of(examId), principal);
// Remove assessor information from client request
savedComplaint.getResult().setAssessor(null);
return ResponseEntity.created(new URI("/api/complaints/" + savedComplaint.getId())).headers(HeaderUtil.createEntityCreationAlert(applicationName, true, entityName, savedComplaint.getId().toString())).body(savedComplaint);
}
use of de.tum.in.www1.artemis.domain.exam.Exam in project ArTEMiS by ls1intum.
the class ComplaintResource method createComplaint.
/**
* POST complaints: create a new complaint
*
* @param complaint the complaint to create
* @param principal that wants to complain
* @return the ResponseEntity with status 201 (Created) and with body the new complaints
* @throws URISyntaxException if the Location URI syntax is incorrect
*/
// TODO: should be participations/{participationId}/results/{resultId}/complaints
@PostMapping("complaints")
@PreAuthorize("hasRole('USER')")
public ResponseEntity<Complaint> createComplaint(@RequestBody Complaint complaint, Principal principal) throws URISyntaxException {
log.debug("REST request to save Complaint: {}", complaint);
if (complaint.getId() != null) {
throw new BadRequestAlertException("A new complaint cannot already have an id", COMPLAINT_ENTITY_NAME, "idexists");
}
if (complaint.getResult() == null || complaint.getResult().getId() == null) {
throw new BadRequestAlertException("A complaint can be only associated to a result", COMPLAINT_ENTITY_NAME, "noresultid");
}
if (complaintRepository.findByResultId(complaint.getResult().getId()).isPresent()) {
throw new BadRequestAlertException("A complaint for this result already exists", COMPLAINT_ENTITY_NAME, "complaintexists");
}
Result result = resultRepository.findByIdElseThrow(complaint.getResult().getId());
// For exam exercises, the POST complaints/exam/examId should be used
if (result.getParticipation().getExercise().isExamExercise()) {
throw new BadRequestAlertException("A complaint for an exam exercise cannot be filed using this component", COMPLAINT_ENTITY_NAME, "complaintAboutExamExerciseWrongComponent");
}
authCheckService.checkHasAtLeastRoleForExerciseElseThrow(Role.STUDENT, result.getParticipation().getExercise(), null);
// To build correct creation alert on the front-end we must check which type is the complaint to apply correct i18n key.
String entityName = complaint.getComplaintType() == ComplaintType.MORE_FEEDBACK ? MORE_FEEDBACK_ENTITY_NAME : COMPLAINT_ENTITY_NAME;
Complaint savedComplaint = complaintService.createComplaint(complaint, OptionalLong.empty(), principal);
// Remove assessor information from client request
savedComplaint.getResult().setAssessor(null);
return ResponseEntity.created(new URI("/api/complaints/" + savedComplaint.getId())).headers(HeaderUtil.createEntityCreationAlert(applicationName, true, entityName, savedComplaint.getId().toString())).body(savedComplaint);
}
Aggregations