Skip to content

Commit

Permalink
Iris: Allow team repository access for Iris (#9975)
Browse files Browse the repository at this point in the history
  • Loading branch information
bassner authored Dec 10, 2024
1 parent bb05226 commit b44dafa
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_IRIS;

import java.util.List;
import java.util.Objects;
import java.util.Optional;

Expand All @@ -27,6 +28,7 @@
import de.tum.cit.aet.artemis.iris.service.settings.IrisSettingsService;
import de.tum.cit.aet.artemis.iris.service.websocket.IrisChatWebsocketService;
import de.tum.cit.aet.artemis.programming.domain.ProgrammingExercise;
import de.tum.cit.aet.artemis.programming.domain.ProgrammingExerciseStudentParticipation;
import de.tum.cit.aet.artemis.programming.domain.ProgrammingSubmission;
import de.tum.cit.aet.artemis.programming.repository.ProgrammingExerciseRepository;
import de.tum.cit.aet.artemis.programming.repository.ProgrammingExerciseStudentParticipationRepository;
Expand Down Expand Up @@ -144,7 +146,14 @@ public void requestAndHandleResponse(IrisExerciseChatSession session) {
}

private Optional<ProgrammingSubmission> getLatestSubmissionIfExists(ProgrammingExercise exercise, User user) {
var participations = programmingExerciseStudentParticipationRepository.findAllWithSubmissionsByExerciseIdAndStudentLogin(exercise.getId(), user.getLogin());
List<ProgrammingExerciseStudentParticipation> participations;
if (exercise.isTeamMode()) {
participations = programmingExerciseStudentParticipationRepository.findAllWithSubmissionByExerciseIdAndStudentLoginInTeam(exercise.getId(), user.getLogin());
}
else {
participations = programmingExerciseStudentParticipationRepository.findAllWithSubmissionsByExerciseIdAndStudentLogin(exercise.getId(), user.getLogin());
}

if (participations.isEmpty()) {
return Optional.empty();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,18 @@ Page<String> findRepositoryUrisByRecentDueDateOrRecentExamEndDate(@Param("earlie
""")
List<ProgrammingExerciseStudentParticipation> findAllWithSubmissionsByExerciseIdAndStudentLogin(@Param("exerciseId") long exerciseId, @Param("username") String username);

@Query("""
SELECT participation
FROM ProgrammingExerciseStudentParticipation participation
LEFT JOIN FETCH participation.team team
LEFT JOIN FETCH team.students student
LEFT JOIN FETCH participation.submissions
WHERE participation.exercise.id = :exerciseId
AND student.login = :username
ORDER BY participation.testRun ASC
""")
List<ProgrammingExerciseStudentParticipation> findAllWithSubmissionByExerciseIdAndStudentLoginInTeam(@Param("exerciseId") long exerciseId, @Param("username") String username);

@EntityGraph(type = LOAD, attributePaths = "team.students")
Optional<ProgrammingExerciseStudentParticipation> findWithTeamStudentsById(long participationId);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package de.tum.cit.aet.artemis.core.connector;

import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_IRIS;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withRawStatus;
Expand Down Expand Up @@ -100,6 +101,38 @@ public void mockProgrammingExerciseChatResponse(Consumer<PyrisExerciseChatPipeli
// @formatter:on
}

public void mockProgrammingExerciseChatResponseExpectingSubmissionId(Consumer<PyrisExerciseChatPipelineExecutionDTO> responseConsumer, long submissionId) {
// @formatter:off
mockServer
.expect(ExpectedCount.once(), requestTo(pipelinesApiURL + "/tutor-chat/default/run"))
.andExpect(method(HttpMethod.POST))
.andExpect(request -> {
var mockRequest = (MockClientHttpRequest) request;
var jsonNode = mapper.readTree(mockRequest.getBodyAsString());

assertThat(jsonNode.has("submission"))
.withFailMessage("Request body must contain a 'submission' field")
.isTrue();
assertThat(jsonNode.get("submission").isObject())
.withFailMessage("The 'submission' field must be an object")
.isTrue();
assertThat(jsonNode.get("submission").has("id"))
.withFailMessage("The 'submission' object must contain an 'id' field")
.isTrue();
assertThat(jsonNode.get("submission").get("id").asLong())
.withFailMessage("Submission ID in request (%d) does not match expected ID (%d)",
jsonNode.get("submission").get("id").asLong(), submissionId)
.isEqualTo(submissionId);
})
.andRespond(request -> {
var mockRequest = (MockClientHttpRequest) request;
var dto = mapper.readValue(mockRequest.getBodyAsString(), PyrisExerciseChatPipelineExecutionDTO.class);
responseConsumer.accept(dto);
return MockRestResponseCreators.withRawStatus(HttpStatus.ACCEPTED.value()).createResponse(request);
});
// @formatter:on
}

public void mockTextExerciseChatResponse(Consumer<PyrisTextExerciseChatPipelineExecutionDTO> responseConsumer) {
// @formatter:off
mockServer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,15 +159,28 @@ public Set<GradingCriterion> addGradingInstructionsToExercise(Exercise exercise)
}

/**
* Accesses the first found exercise of a course with the passed type. The course stores exercises in a set, therefore any
* Accesses the first found non-team exercise of a course with the passed type. The course stores exercises in a set, therefore any
* exercise with the corresponding type could be accessed.
*
* @param course The course which should be searched for the exercise.
* @param clazz The class (type) of the exercise to look for.
* @return The first exercise which was found in the course and is of the expected type.
*/
public <T extends Exercise> T getFirstExerciseWithType(Course course, Class<T> clazz) {
var exercise = course.getExercises().stream().filter(ex -> ex.getClass().equals(clazz)).findFirst().orElseThrow();
var exercise = course.getExercises().stream().filter(ex -> !ex.isTeamMode() && ex.getClass().equals(clazz)).findFirst().orElseThrow();
return (T) exercise;
}

/**
* Accesses the first found team exercise of a course with the passed type. The course stores exercises in a set, therefore any
* exercise with the corresponding type could be accessed.
*
* @param course The course which should be searched for the exercise.
* @param clazz The class (type) of the exercise to look for.
* @return The first exercise which was found in the course and is of the expected type.
*/
public <T extends Exercise> T getFirstTeamExerciseWithType(Course course, Class<T> clazz) {
var exercise = course.getExercises().stream().filter(ex -> ex.isTeamMode() && ex.getClass().equals(clazz)).findFirst().orElseThrow();
return (T) exercise;
}

Expand Down
Loading

0 comments on commit b44dafa

Please sign in to comment.