Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Athena: Allow feedback suggestion module selection on exercise level #7809

Merged
merged 51 commits into from
Mar 9, 2024
Merged
Show file tree
Hide file tree
Changes from 46 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
814c2e6
Allow module selection per exercise, make necessary adaptions, add mi…
maximiliansoelch Dec 13, 2023
a18661c
Add more tests to increase coverage
maximiliansoelch Dec 18, 2023
b4501bd
Fix client-test build
maximiliansoelch Dec 18, 2023
e3fa983
Add more client-test for athena-service.ts
maximiliansoelch Dec 18, 2023
ba9e6e4
Fix client-test build
maximiliansoelch Dec 18, 2023
6f7f9ac
Rename REST endpoint for available athena modules
maximiliansoelch Dec 19, 2023
08d8f59
Add AthenaExerciseIntegrationTest
maximiliansoelch Dec 19, 2023
dc01774
Fix failing server-tests
maximiliansoelch Dec 19, 2023
38fdcab
Add JavaDocs comments & improve German label translation
maximiliansoelch Dec 19, 2023
229aed5
Merge branch 'develop' into feature/athena/allow-module-selection-for…
maximiliansoelch Dec 19, 2023
a4ac997
Adapt feedback suggestions options component to new Angular control s…
maximiliansoelch Dec 19, 2023
7d2faf4
Fix Athena module access check for exam exercises
maximiliansoelch Dec 19, 2023
adcdb99
Merge branch 'develop' into feature/athena/allow-module-selection-for…
maximiliansoelch Dec 22, 2023
c6211e7
Remove duplicate plagiarism control from merge
maximiliansoelch Dec 22, 2023
aa034d8
Add comments to mock methods
maximiliansoelch Dec 22, 2023
4a69b0f
Add check if athena is enabled for the exercise to feedback suggestio…
maximiliansoelch Dec 28, 2023
7f0bb5e
Add check to disallow module change after due date has passed
maximiliansoelch Dec 29, 2023
fd27d6c
Merge branch 'develop' into feature/athena/allow-module-selection-for…
maximiliansoelch Dec 29, 2023
1ef48c8
Fix failing test
maximiliansoelch Dec 29, 2023
5a097aa
Fix client test compilation
maximiliansoelch Dec 29, 2023
9f4669a
Fix client test
maximiliansoelch Dec 29, 2023
d356565
Remove all todos
maximiliansoelch Dec 29, 2023
4891ee8
Merge branch 'develop' into feature/athena/allow-module-selection-for…
maximiliansoelch Dec 29, 2023
4da186f
Add client test for course update component
maximiliansoelch Dec 29, 2023
34805af
Merge branch 'develop' into feature/athena/allow-module-selection-for…
maximiliansoelch Jan 2, 2024
8dc67fe
Integrate review suggestions
maximiliansoelch Jan 22, 2024
ea561ea
Add empty tag to silence intellij warning
maximiliansoelch Jan 22, 2024
9351bcf
Merge branch 'develop' into feature/athena/allow-module-selection-for…
maximiliansoelch Jan 22, 2024
b9ee338
Fix merge issues
maximiliansoelch Jan 22, 2024
8a44478
Fix logger usage in AthenaModuleService
maximiliansoelch Jan 22, 2024
bc8d076
Merge branch 'develop' into feature/athena/allow-module-selection-for…
maximiliansoelch Jan 22, 2024
0da87ec
Show Athena status on prog exercise details page
maximiliansoelch Jan 24, 2024
624b7cf
Merge branch 'develop' into feature/athena/allow-module-selection-for…
maximiliansoelch Jan 29, 2024
741afa3
Merge branch 'develop' into feature/athena/allow-module-selection-for…
maximiliansoelch Jan 29, 2024
42f94a9
Merge branch 'develop' into feature/athena/allow-module-selection-for…
maximiliansoelch Feb 13, 2024
2d99755
Merge branch 'develop' into feature/athena/allow-module-selection-for…
maximiliansoelch Feb 13, 2024
57ba9db
Implement review suggestions
maximiliansoelch Feb 13, 2024
4e9d641
Fix failing test compilation introduced in merge conflict resolution
maximiliansoelch Feb 13, 2024
a1fe637
Fix client issue if profileInfo is not loaded yet
maximiliansoelch Feb 13, 2024
a26deeb
Merge branch 'develop' into feature/athena/allow-module-selection-for…
maximiliansoelch Feb 17, 2024
238d54c
revert prettier changes
maximiliansoelch Feb 17, 2024
0cff0c0
Merge branch 'develop' into feature/athena/allow-module-selection-for…
maximiliansoelch Feb 19, 2024
1e1c3a7
Merge branch 'develop' into feature/athena/allow-module-selection-for…
maximiliansoelch Feb 19, 2024
66e172a
Merge branch 'develop' into feature/athena/allow-module-selection-for…
maximiliansoelch Feb 21, 2024
f269d7f
Merge branch 'develop' into feature/athena/allow-module-selection-for…
maximiliansoelch Feb 21, 2024
f03b7f7
Fix wrong variable name in getAthenaTextModulesForCourse
maximiliansoelch Feb 23, 2024
d515c63
Merge branch 'develop' into feature/athena/allow-module-selection-for…
maximiliansoelch Mar 2, 2024
9b847bd
Remove old client test case getSemesters() introduced while resolving…
maximiliansoelch Mar 2, 2024
f49d065
Merge branch 'develop' into feature/athena/allow-module-selection-for…
maximiliansoelch Mar 2, 2024
a9e4295
Merge branch 'develop' into feature/athena/allow-module-selection-for…
maximiliansoelch Mar 2, 2024
c3dfdd3
Merge branch 'develop' into feature/athena/allow-module-selection-for…
maximiliansoelch Mar 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/main/java/de/tum/in/www1/artemis/domain/Course.java
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,9 @@ public class Course extends DomainObject {
@JsonView(QuizView.Before.class)
private Integer accuracyOfScores = 1; // default value

@Column(name = "restricted_athena_modules_access", nullable = false)
private boolean restrictedAthenaModulesAccess = false; // default is false

/**
* Note: Currently just used in the scope of the tutorial groups feature
*/
Expand Down Expand Up @@ -791,6 +794,14 @@ public void setAccuracyOfScores(Integer accuracyOfScores) {
this.accuracyOfScores = accuracyOfScores;
}

public boolean getRestrictedAthenaModulesAccess() {
return restrictedAthenaModulesAccess;
}

public void setRestrictedAthenaModulesAccess(boolean restrictedAthenaModulesAccess) {
this.restrictedAthenaModulesAccess = restrictedAthenaModulesAccess;
}

public Set<TutorialGroup> getTutorialGroups() {
return tutorialGroups;
}
Expand Down
16 changes: 10 additions & 6 deletions src/main/java/de/tum/in/www1/artemis/domain/Exercise.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ public abstract class Exercise extends BaseExercise implements LearningObject {
@Column(name = "second_correction_enabled")
private Boolean secondCorrectionEnabled = false;

@Column(name = "feedback_suggestions_enabled") // enables Athena
private Boolean feedbackSuggestionsEnabled = false;
@Column(name = "feedback_suggestion_module") // Athena module name (Athena enabled) or null
private String feedbackSuggestionModule;
maximiliansoelch marked this conversation as resolved.
Show resolved Hide resolved

@ManyToOne
@JsonView(QuizView.Before.class)
Expand Down Expand Up @@ -782,12 +782,16 @@ public void setSecondCorrectionEnabled(boolean secondCorrectionEnabled) {
this.secondCorrectionEnabled = secondCorrectionEnabled;
}

public boolean getFeedbackSuggestionsEnabled() {
return Boolean.TRUE.equals(feedbackSuggestionsEnabled);
public String getFeedbackSuggestionModule() {
return feedbackSuggestionModule;
}

public void setFeedbackSuggestionsEnabled(boolean feedbackSuggestionsEnabled) {
this.feedbackSuggestionsEnabled = feedbackSuggestionsEnabled;
public void setFeedbackSuggestionModule(String feedbackSuggestionModule) {
this.feedbackSuggestionModule = feedbackSuggestionModule;
}

public boolean areFeedbackSuggestionsEnabled() {
return feedbackSuggestionModule != null;
}

public Set<GradingCriterion> getGradingCriteria() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@
import javax.validation.constraints.NotNull;

import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.jpa.repository.*;
maximiliansoelch marked this conversation as resolved.
Show resolved Hide resolved
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
maximiliansoelch marked this conversation as resolved.
Show resolved Hide resolved

import de.tum.in.www1.artemis.domain.Exercise;
import de.tum.in.www1.artemis.domain.metrics.ExerciseTypeMetricsEntry;
Expand Down Expand Up @@ -573,23 +572,39 @@ default boolean toggleSecondCorrection(Exercise exercise) {
Set<Exercise> getAllExercisesUserParticipatedInWithEagerParticipationsSubmissionsResultsFeedbacksTestCasesByUserId(@Param("userId") long userId);

/**
* Finds all exercises filtered by feedback suggestions and due date.
* Finds all exercises filtered by feedback suggestion modules not null and due date.
*
* @param feedbackSuggestionsEnabled - filter by feedback suggestions enabled
* @param dueDate - filter by due date
* @param dueDate - filter by due date
* @return Set of Exercises
*/
Set<Exercise> findByFeedbackSuggestionsEnabledAndDueDateIsAfter(boolean feedbackSuggestionsEnabled, ZonedDateTime dueDate);
Set<Exercise> findByFeedbackSuggestionModuleNotNullAndDueDateIsAfter(ZonedDateTime dueDate);

/**
* Find all exercises feedback suggestions (Athena) and with *Due Date* in the future.
*
* @return Set of Exercises
*/
default Set<Exercise> findAllFeedbackSuggestionsEnabledExercisesWithFutureDueDate() {
return findByFeedbackSuggestionsEnabledAndDueDateIsAfter(true, ZonedDateTime.now());
return findByFeedbackSuggestionModuleNotNullAndDueDateIsAfter(ZonedDateTime.now());
}

/**
* Revokes the access by setting all exercises that currently utilize a restricted module to null.
*
* @param courseId The course for which the access should be revoked
* @param restrictedFeedbackSuggestionModule Collection of restricted modules
*/
@Transactional // ok because of modifying query
@Modifying
@Query("""
UPDATE Exercise e
SET e.feedbackSuggestionModule = NULL
WHERE e.course.id = :courseId
AND e.feedbackSuggestionModule IN :restrictedFeedbackSuggestionModule
""")
void revokeAccessToRestrictedFeedbackSuggestionModulesByCourseId(@Param("courseId") Long courseId,
@Param("restrictedFeedbackSuggestionModule") Collection<String> restrictedFeedbackSuggestionModule);

/**
* For an explanation, see {@link de.tum.in.www1.artemis.web.rest.ExamResource#getAllExercisesWithPotentialPlagiarismForExam(long,long)}
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ public Optional<Submission> getNextAssessableSubmission(Exercise exercise, boole
*/
public <S extends Submission> Optional<S> getAthenaSubmissionToAssess(Exercise exercise, boolean skipAssessmentQueue, boolean examMode, int correctionRound,
Function<Long, Optional<S>> findSubmissionById) {
if (exercise.getFeedbackSuggestionsEnabled() && athenaSubmissionSelectionService.isPresent() && !skipAssessmentQueue && correctionRound == 0) {
if (exercise.areFeedbackSuggestionsEnabled() && athenaSubmissionSelectionService.isPresent() && !skipAssessmentQueue && correctionRound == 0) {
var assessableSubmissions = getAssessableSubmissions(exercise, examMode, correctionRound);
var athenaSubmissionId = athenaSubmissionSelectionService.get().getProposedSubmissionId(exercise, assessableSubmissions.stream().map(Submission::getId).toList());
if (athenaSubmissionId.isPresent()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public TextExercise importTextExercise(final TextExercise templateExercise, Text
TextExercise newExercise = copyTextExerciseBasis(importedExercise, gradingInstructionCopyTracker);
if (newExercise.isExamExercise()) {
// Disable feedback suggestions on exam exercises (currently not supported)
newExercise.setFeedbackSuggestionsEnabled(false);
newExercise.setFeedbackSuggestionModule(null);
}

TextExercise newTextExercise = textExerciseRepository.save(newExercise);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,17 @@ public class AthenaFeedbackSendingService {

private final AthenaConnector<RequestDTO, ResponseDTO> connector;

private final AthenaModuleUrlHelper athenaModuleUrlHelper;
private final AthenaModuleService athenaModuleService;

private final AthenaDTOConverter athenaDTOConverter;

/**
* Creates a new service to send feedback to the Athena service
*/
public AthenaFeedbackSendingService(@Qualifier("athenaRestTemplate") RestTemplate athenaRestTemplate, AthenaModuleUrlHelper athenaModuleUrlHelper,
public AthenaFeedbackSendingService(@Qualifier("athenaRestTemplate") RestTemplate athenaRestTemplate, AthenaModuleService athenaModuleService,
AthenaDTOConverter athenaDTOConverter) {
connector = new AthenaConnector<>(athenaRestTemplate, ResponseDTO.class);
this.athenaModuleUrlHelper = athenaModuleUrlHelper;
this.athenaModuleService = athenaModuleService;
this.athenaDTOConverter = athenaDTOConverter;
}

Expand Down Expand Up @@ -72,7 +72,7 @@ public void sendFeedback(Exercise exercise, Submission submission, List<Feedback
*/
@Async
public void sendFeedback(Exercise exercise, Submission submission, List<Feedback> feedbacks, int maxRetries) {
if (!exercise.getFeedbackSuggestionsEnabled()) {
if (!exercise.areFeedbackSuggestionsEnabled()) {
throw new IllegalArgumentException("The exercise does not have feedback suggestions enabled.");
}

Expand All @@ -89,7 +89,7 @@ public void sendFeedback(Exercise exercise, Submission submission, List<Feedback
// Only send manual feedback from tutors to Athena
final RequestDTO request = new RequestDTO(athenaDTOConverter.ofExercise(exercise), athenaDTOConverter.ofSubmission(exercise.getId(), submission),
feedbacks.stream().filter(Feedback::isManualFeedback).map((feedback) -> athenaDTOConverter.ofFeedback(exercise, submission.getId(), feedback)).toList());
ResponseDTO response = connector.invokeWithRetry(athenaModuleUrlHelper.getAthenaModuleUrl(exercise.getExerciseType()) + "/feedbacks", request, maxRetries);
ResponseDTO response = connector.invokeWithRetry(athenaModuleService.getAthenaModuleUrl(exercise) + "/feedbacks", request, maxRetries);
log.info("Athena responded to feedback: {}", response.data);
}
catch (NetworkingException networkingException) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,19 @@ public class AthenaFeedbackSuggestionsService {

private final AthenaConnector<RequestDTO, ResponseDTOProgramming> programmingAthenaConnector;

private final AthenaModuleUrlHelper athenaModuleUrlHelper;
private final AthenaModuleService athenaModuleService;

private final AthenaDTOConverter athenaDTOConverter;

/**
* Creates a new AthenaFeedbackSuggestionsService to receive feedback suggestions from the Athena service.
*/
public AthenaFeedbackSuggestionsService(@Qualifier("athenaRestTemplate") RestTemplate athenaRestTemplate, AthenaModuleUrlHelper athenaModuleUrlHelper,
public AthenaFeedbackSuggestionsService(@Qualifier("athenaRestTemplate") RestTemplate athenaRestTemplate, AthenaModuleService athenaModuleService,
AthenaDTOConverter athenaDTOConverter) {
textAthenaConnector = new AthenaConnector<>(athenaRestTemplate, ResponseDTOText.class);
programmingAthenaConnector = new AthenaConnector<>(athenaRestTemplate, ResponseDTOProgramming.class);
this.athenaDTOConverter = athenaDTOConverter;
this.athenaModuleUrlHelper = athenaModuleUrlHelper;
this.athenaModuleService = athenaModuleService;
}

private record RequestDTO(ExerciseDTO exercise, SubmissionDTO submission) {
Expand Down Expand Up @@ -70,7 +70,7 @@ public List<TextFeedbackDTO> getTextFeedbackSuggestions(TextExercise exercise, T
}

final RequestDTO request = new RequestDTO(athenaDTOConverter.ofExercise(exercise), athenaDTOConverter.ofSubmission(exercise.getId(), submission));
ResponseDTOText response = textAthenaConnector.invokeWithRetry(athenaModuleUrlHelper.getAthenaModuleUrl(exercise.getExerciseType()) + "/feedback_suggestions", request, 0);
ResponseDTOText response = textAthenaConnector.invokeWithRetry(athenaModuleService.getAthenaModuleUrl(exercise) + "/feedback_suggestions", request, 0);
log.info("Athena responded to feedback suggestions request: {}", response.data);
return response.data.stream().toList();
}
Expand All @@ -86,8 +86,7 @@ public List<ProgrammingFeedbackDTO> getProgrammingFeedbackSuggestions(Programmin
log.debug("Start Athena Feedback Suggestions Service for Exercise '{}' (#{}).", exercise.getTitle(), exercise.getId());

final RequestDTO request = new RequestDTO(athenaDTOConverter.ofExercise(exercise), athenaDTOConverter.ofSubmission(exercise.getId(), submission));
ResponseDTOProgramming response = programmingAthenaConnector.invokeWithRetry(athenaModuleUrlHelper.getAthenaModuleUrl(exercise.getExerciseType()) + "/feedback_suggestions",
request, 0);
ResponseDTOProgramming response = programmingAthenaConnector.invokeWithRetry(athenaModuleService.getAthenaModuleUrl(exercise) + "/feedback_suggestions", request, 0);
log.info("Athena responded to feedback suggestions request: {}", response.data);
return response.data.stream().toList();
}
Expand Down
Loading
Loading