use of de.tum.in.www1.artemis.domain.hestia.ExerciseHint in project ArTEMiS by ls1intum.
the class ExerciseHintResource method deleteExerciseHint.
/**
* {@code DELETE exercises/:exerciseId/exercise-hints/:exerciseHintId} : delete the exerciseHint with given id.
*
* @param exerciseHintId the id of the exerciseHint to delete
* @param exerciseId the exercise id of which to delete the exercise hint
* @return the {@link ResponseEntity} with status {@code 204 (NO_CONTENT)},
* or with status {@code 400 (Bad Request)} if the exerciseHint is a codeHint,
* or with status {@code 409 (Conflict)} if the exerciseId is not valid.
*/
@DeleteMapping("exercises/{exerciseId}/exercise-hints/{exerciseHintId}")
@PreAuthorize("hasRole('EDITOR')")
public ResponseEntity<Void> deleteExerciseHint(@PathVariable Long exerciseId, @PathVariable Long exerciseHintId) {
log.debug("REST request to delete ExerciseHint : {}", exerciseHintId);
ProgrammingExercise exercise = programmingExerciseRepository.findByIdElseThrow(exerciseId);
authCheckService.checkHasAtLeastRoleForExerciseElseThrow(Role.EDITOR, exercise, null);
var exerciseHint = exerciseHintRepository.findByIdElseThrow(exerciseHintId);
if (exerciseHint instanceof CodeHint) {
throw new BadRequestAlertException("A code hint cannot be deleted manually.", CODE_HINT_ENTITY_NAME, "manualCodeHintOperation");
}
if (!exerciseHint.getExercise().getId().equals(exerciseId)) {
throw new ConflictException("An exercise hint can only be deleted if the exerciseIds match.", EXERCISE_HINT_ENTITY_NAME, "exerciseIdsMismatch");
}
exerciseHintRepository.deleteById(exerciseHintId);
return ResponseEntity.noContent().headers(HeaderUtil.createEntityDeletionAlert(applicationName, true, EXERCISE_HINT_ENTITY_NAME, exerciseHintId.toString())).build();
}
use of de.tum.in.www1.artemis.domain.hestia.ExerciseHint in project ArTEMiS by ls1intum.
the class ExerciseHintIntegrationTest method getHintForAnExerciseAsTutorForbidden.
@Test
@WithMockUser(username = "tutor1", roles = "TA")
public void getHintForAnExerciseAsTutorForbidden() throws Exception {
ExerciseHint exerciseHint = exerciseHintRepository.findAll().get(0);
request.get("/api/exercises/" + exerciseHint.getExercise().getId() + "/exercise-hints/" + exerciseHint.getId(), HttpStatus.FORBIDDEN, ExerciseHint.class);
}
use of de.tum.in.www1.artemis.domain.hestia.ExerciseHint in project ArTEMiS by ls1intum.
the class DatabaseUtilService method addHintsToExercise.
public void addHintsToExercise(Exercise exercise) {
ExerciseHint exerciseHint1 = new ExerciseHint().content("content 1").exercise(exercise).title("title 1");
ExerciseHint exerciseHint2 = new ExerciseHint().content("content 2").exercise(exercise).title("title 2");
ExerciseHint exerciseHint3 = new ExerciseHint().content("content 3").exercise(exercise).title("title 3");
Set<ExerciseHint> hints = new HashSet<>();
hints.add(exerciseHint1);
hints.add(exerciseHint2);
hints.add(exerciseHint3);
exercise.setExerciseHints(hints);
exerciseHintRepository.saveAll(hints);
}
use of de.tum.in.www1.artemis.domain.hestia.ExerciseHint in project ArTEMiS by ls1intum.
the class CodeHintResource method generateCodeHintsForExercise.
/**
* {@code POST programming-exercises/:exerciseId/code-hints} : Create a new exerciseHint for an exercise.
*
* @param exerciseId the exerciseId of the exercise of which to create the exerciseHint
* @param deleteOldCodeHints Whether old code hints should be deleted
* @return the {@link ResponseEntity} with status {@code 200 (Ok)} and with body the new code hints,
*/
@PostMapping("programming-exercises/{exerciseId}/code-hints")
@PreAuthorize("hasRole('EDITOR')")
public ResponseEntity<List<CodeHint>> generateCodeHintsForExercise(@PathVariable Long exerciseId, @RequestParam(value = "deleteOldCodeHints", defaultValue = "true") boolean deleteOldCodeHints) {
log.debug("REST request to generate CodeHints for ProgrammingExercise: {}", exerciseId);
ProgrammingExercise exercise = programmingExerciseRepository.findByIdElseThrow(exerciseId);
authCheckService.checkHasAtLeastRoleForExerciseElseThrow(Role.EDITOR, exercise, null);
// Hints for exam exercises are not supported at the moment
if (exercise.isExamExercise()) {
throw new AccessForbiddenException("Code hints for exams are currently not supported");
}
var codeHints = codeHintService.generateCodeHintsForExercise(exercise, deleteOldCodeHints);
return ResponseEntity.ok(codeHints);
}
use of de.tum.in.www1.artemis.domain.hestia.ExerciseHint in project ArTEMiS by ls1intum.
the class ExerciseHintService method getAvailableExerciseHints.
/**
* Returns all exercise hints that the user can currently activate for a given programming exercise.
* Exercise hints will be shown for the first task that meets the following conditions:
* (1) the subsequent number of the latest submissions the previous task is successful is greater or equal to the hint's threshold
* (2) the subsequent number of the latest submissions the current task is unsuccessful is greater or equal to the hint's threshold
* If no task matches these conditions, no exercise hints will be returned
* Note: A task is successful, if the feedback within the submission is positive for all associated test cases within this task
*
* @param exercise The programming exercise
* @param user The user
* @return All available exercise hints
*/
public Set<ExerciseHint> getAvailableExerciseHints(ProgrammingExercise exercise, User user) {
var submissions = getSubmissionsForStudent(exercise, user);
if (submissions.isEmpty()) {
return new HashSet<>();
}
var latestResult = submissions.get(0).getLatestResult();
// latest submissions has no result or latest result has no feedback (most commonly due to a build error)
if (latestResult == null || latestResult.getFeedbacks().isEmpty()) {
return new HashSet<>();
}
var exerciseHints = exerciseHintRepository.findByExerciseId(exercise.getId());
var tasks = programmingExerciseTaskService.getSortedTasks(exercise);
var subsequentNumberOfUnsuccessfulSubmissionsByTask = tasks.stream().collect(Collectors.toMap(task -> task, task -> subsequentNumberOfSubmissionsForTaskWithStatus(submissions, task, false)));
var subsequentNumberOfSuccessfulSubmissionsByTask = tasks.stream().collect(Collectors.toMap(task -> task, task -> subsequentNumberOfSubmissionsForTaskWithStatus(submissions, task, true)));
for (int i = 0; i < tasks.size(); i++) {
var task = tasks.get(i);
int subsequentNumberOfUnsuccessfulSubmissionsForCurrentTask = subsequentNumberOfUnsuccessfulSubmissionsByTask.get(task);
// current task is successful
if (subsequentNumberOfUnsuccessfulSubmissionsForCurrentTask == 0) {
continue;
}
var hintsInTask = exerciseHints.stream().filter(hint -> Objects.nonNull(hint.getProgrammingExerciseTask()) && Objects.equals(hint.getProgrammingExerciseTask().getId(), task.getId())).collect(Collectors.toSet());
// no hints exist for the current task
if (hintsInTask.isEmpty()) {
continue;
}
Optional<Integer> subsequentNumberSuccessfulSubmissionsForPreviousTask;
if (i == 0) {
subsequentNumberSuccessfulSubmissionsForPreviousTask = Optional.empty();
} else {
subsequentNumberSuccessfulSubmissionsForPreviousTask = Optional.of(subsequentNumberOfSuccessfulSubmissionsByTask.get(tasks.get(i - 1)));
}
// skip current task if the previous task was not successful
if (0 == subsequentNumberSuccessfulSubmissionsForPreviousTask.orElse(-1)) {
continue;
}
// add the available hints for the current task
var availableHintsForCurrentTask = getAvailableExerciseHintsForTask(subsequentNumberSuccessfulSubmissionsForPreviousTask, subsequentNumberOfUnsuccessfulSubmissionsForCurrentTask, hintsInTask);
if (!availableHintsForCurrentTask.isEmpty()) {
return availableHintsForCurrentTask;
}
}
return new HashSet<>();
}
Aggregations