From 9032dcd0d65088a0a5cefd7c40526008a00a8b48 Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Tue, 17 Dec 2024 14:24:48 +0100 Subject: [PATCH 01/22] add AbstractTextApi --- .../de/tum/cit/aet/artemis/text/api/AbstractTextApi.java | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/main/java/de/tum/cit/aet/artemis/text/api/AbstractTextApi.java diff --git a/src/main/java/de/tum/cit/aet/artemis/text/api/AbstractTextApi.java b/src/main/java/de/tum/cit/aet/artemis/text/api/AbstractTextApi.java new file mode 100644 index 000000000000..7ad178ab5b08 --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/text/api/AbstractTextApi.java @@ -0,0 +1,6 @@ +package de.tum.cit.aet.artemis.text.api; + +import de.tum.cit.aet.artemis.core.api.AbstractApi; + +public abstract class AbstractTextApi implements AbstractApi { +} From 333043136241b3658509bf9c450903889a1c0388 Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Tue, 17 Dec 2024 14:25:36 +0100 Subject: [PATCH 02/22] add TextExerciseImportApi and use in LearningObjectImportService --- .../service/LearningObjectImportService.java | 30 +++++++------- .../text/api/TextExerciseImportApi.java | 39 +++++++++++++++++++ 2 files changed, 54 insertions(+), 15 deletions(-) create mode 100644 src/main/java/de/tum/cit/aet/artemis/text/api/TextExerciseImportApi.java diff --git a/src/main/java/de/tum/cit/aet/artemis/atlas/service/LearningObjectImportService.java b/src/main/java/de/tum/cit/aet/artemis/atlas/service/LearningObjectImportService.java index c992524f8158..6d005ff41ee1 100644 --- a/src/main/java/de/tum/cit/aet/artemis/atlas/service/LearningObjectImportService.java +++ b/src/main/java/de/tum/cit/aet/artemis/atlas/service/LearningObjectImportService.java @@ -1,6 +1,7 @@ package de.tum.cit.aet.artemis.atlas.service; import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_ATLAS; +import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_CORE; import java.io.IOException; import java.time.ZonedDateTime; @@ -37,6 +38,7 @@ import de.tum.cit.aet.artemis.atlas.repository.CompetencyLectureUnitLinkRepository; import de.tum.cit.aet.artemis.atlas.repository.CourseCompetencyRepository; import de.tum.cit.aet.artemis.core.domain.Course; +import de.tum.cit.aet.artemis.core.exception.ApiNotPresentException; import de.tum.cit.aet.artemis.core.exception.NoUniqueQueryException; import de.tum.cit.aet.artemis.exercise.domain.Exercise; import de.tum.cit.aet.artemis.exercise.repository.ExerciseRepository; @@ -60,9 +62,8 @@ import de.tum.cit.aet.artemis.quiz.domain.QuizExercise; import de.tum.cit.aet.artemis.quiz.repository.QuizExerciseRepository; import de.tum.cit.aet.artemis.quiz.service.QuizExerciseImportService; +import de.tum.cit.aet.artemis.text.api.TextExerciseImportApi; import de.tum.cit.aet.artemis.text.domain.TextExercise; -import de.tum.cit.aet.artemis.text.repository.TextExerciseRepository; -import de.tum.cit.aet.artemis.text.service.TextExerciseImportService; /** * Service for importing learning objects related to competencies. @@ -87,9 +88,7 @@ public class LearningObjectImportService { private final ModelingExerciseImportService modelingExerciseImportService; - private final TextExerciseRepository textExerciseRepository; - - private final TextExerciseImportService textExerciseImportService; + private final Optional textExerciseImportApi; private final QuizExerciseRepository quizExerciseRepository; @@ -116,12 +115,11 @@ public class LearningObjectImportService { public LearningObjectImportService(ExerciseRepository exerciseRepository, ProgrammingExerciseRepository programmingExerciseRepository, ProgrammingExerciseImportService programmingExerciseImportService, FileUploadExerciseRepository fileUploadExerciseRepository, FileUploadExerciseImportService fileUploadExerciseImportService, ModelingExerciseRepository modelingExerciseRepository, - ModelingExerciseImportService modelingExerciseImportService, TextExerciseRepository textExerciseRepository, TextExerciseImportService textExerciseImportService, - QuizExerciseRepository quizExerciseRepository, QuizExerciseImportService quizExerciseImportService, LectureRepository lectureRepository, - LectureImportService lectureImportService, LectureUnitRepository lectureUnitRepository, LectureUnitImportService lectureUnitImportService, - CourseCompetencyRepository courseCompetencyRepository, ProgrammingExerciseTaskRepository programmingExerciseTaskRepository, - GradingCriterionRepository gradingCriterionRepository, CompetencyExerciseLinkRepository competencyExerciseLinkRepository, - CompetencyLectureUnitLinkRepository competencyLectureUnitLinkRepository) { + ModelingExerciseImportService modelingExerciseImportService, Optional textExerciseImportApi, QuizExerciseRepository quizExerciseRepository, + QuizExerciseImportService quizExerciseImportService, LectureRepository lectureRepository, LectureImportService lectureImportService, + LectureUnitRepository lectureUnitRepository, LectureUnitImportService lectureUnitImportService, CourseCompetencyRepository courseCompetencyRepository, + ProgrammingExerciseTaskRepository programmingExerciseTaskRepository, GradingCriterionRepository gradingCriterionRepository, + CompetencyExerciseLinkRepository competencyExerciseLinkRepository, CompetencyLectureUnitLinkRepository competencyLectureUnitLinkRepository) { this.exerciseRepository = exerciseRepository; this.programmingExerciseRepository = programmingExerciseRepository; this.programmingExerciseImportService = programmingExerciseImportService; @@ -129,8 +127,7 @@ public LearningObjectImportService(ExerciseRepository exerciseRepository, Progra this.fileUploadExerciseImportService = fileUploadExerciseImportService; this.modelingExerciseRepository = modelingExerciseRepository; this.modelingExerciseImportService = modelingExerciseImportService; - this.textExerciseRepository = textExerciseRepository; - this.textExerciseImportService = textExerciseImportService; + this.textExerciseImportApi = textExerciseImportApi; this.quizExerciseRepository = quizExerciseRepository; this.quizExerciseImportService = quizExerciseImportService; this.lectureRepository = lectureRepository; @@ -208,8 +205,11 @@ private Exercise importOrLoadExercise(Exercise sourceExercise, Course course) th case ModelingExercise modelingExercise -> importOrLoadExercise(modelingExercise, course, modelingExerciseRepository::findUniqueWithCompetenciesByTitleAndCourseId, modelingExerciseRepository::findByIdWithExampleSubmissionsAndResultsAndPlagiarismDetectionConfigElseThrow, modelingExerciseImportService::importModelingExercise); - case TextExercise textExercise -> importOrLoadExercise(textExercise, course, textExerciseRepository::findUniqueWithCompetenciesByTitleAndCourseId, - textExerciseRepository::findByIdWithExampleSubmissionsAndResultsAndGradingCriteriaElseThrow, textExerciseImportService::importTextExercise); + case TextExercise textExercise -> { + var api = textExerciseImportApi.orElseThrow(() -> new ApiNotPresentException(TextExerciseImportApi.class, PROFILE_CORE)); + yield importOrLoadExercise(textExercise, course, api::findUniqueWithCompetenciesByTitleAndCourseId, + api::findByIdWithExampleSubmissionsAndResultsAndGradingCriteriaElseThrow, api::importTextExercise); + } case QuizExercise quizExercise -> importOrLoadExercise(quizExercise, course, quizExerciseRepository::findUniqueWithCompetenciesByTitleAndCourseId, quizExerciseRepository::findByIdWithQuestionsAndStatisticsAndCompetenciesAndBatchesAndGradingCriteriaElseThrow, (exercise, templateExercise) -> { try { diff --git a/src/main/java/de/tum/cit/aet/artemis/text/api/TextExerciseImportApi.java b/src/main/java/de/tum/cit/aet/artemis/text/api/TextExerciseImportApi.java new file mode 100644 index 000000000000..03ab59b8e950 --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/text/api/TextExerciseImportApi.java @@ -0,0 +1,39 @@ +package de.tum.cit.aet.artemis.text.api; + +import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_CORE; + +import java.util.Optional; + +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Controller; + +import de.tum.cit.aet.artemis.core.exception.NoUniqueQueryException; +import de.tum.cit.aet.artemis.text.domain.TextExercise; +import de.tum.cit.aet.artemis.text.repository.TextExerciseRepository; +import de.tum.cit.aet.artemis.text.service.TextExerciseImportService; + +@Controller +@Profile(PROFILE_CORE) +public class TextExerciseImportApi extends AbstractTextApi { + + private final TextExerciseRepository textExerciseRepository; + + private final TextExerciseImportService textExerciseImportService; + + public TextExerciseImportApi(TextExerciseRepository textExerciseRepository, TextExerciseImportService textExerciseImportService) { + this.textExerciseRepository = textExerciseRepository; + this.textExerciseImportService = textExerciseImportService; + } + + public Optional findUniqueWithCompetenciesByTitleAndCourseId(String title, long courseId) throws NoUniqueQueryException { + return textExerciseRepository.findUniqueWithCompetenciesByTitleAndCourseId(title, courseId); + } + + public TextExercise findByIdWithExampleSubmissionsAndResultsAndGradingCriteriaElseThrow(long exerciseId) { + return textExerciseRepository.findByIdWithExampleSubmissionsAndResultsAndGradingCriteriaElseThrow(exerciseId); + } + + public TextExercise importTextExercise(final TextExercise templateExercise, TextExercise importedExercise) { + return textExerciseImportService.importTextExercise(templateExercise, importedExercise); + } +} From a60687010fc5314398a60751bc5e339775c07aa7 Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Tue, 17 Dec 2024 15:03:21 +0100 Subject: [PATCH 03/22] use TextExerciseImportApi in ExamImportService --- .../exam/service/ExamImportService.java | 25 ++++++++----------- .../text/api/TextExerciseImportApi.java | 5 ++++ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/java/de/tum/cit/aet/artemis/exam/service/ExamImportService.java b/src/main/java/de/tum/cit/aet/artemis/exam/service/ExamImportService.java index 58fcf03cc97a..9c93791dc385 100644 --- a/src/main/java/de/tum/cit/aet/artemis/exam/service/ExamImportService.java +++ b/src/main/java/de/tum/cit/aet/artemis/exam/service/ExamImportService.java @@ -39,17 +39,14 @@ import de.tum.cit.aet.artemis.quiz.domain.QuizExercise; import de.tum.cit.aet.artemis.quiz.repository.QuizExerciseRepository; import de.tum.cit.aet.artemis.quiz.service.QuizExerciseImportService; +import de.tum.cit.aet.artemis.text.api.TextExerciseImportApi; import de.tum.cit.aet.artemis.text.domain.TextExercise; -import de.tum.cit.aet.artemis.text.repository.TextExerciseRepository; -import de.tum.cit.aet.artemis.text.service.TextExerciseImportService; @Profile(PROFILE_CORE) @Service public class ExamImportService { - private final TextExerciseImportService textExerciseImportService; - - private final TextExerciseRepository textExerciseRepository; + private final Optional textExerciseImportApi; private final ModelingExerciseImportService modelingExerciseImportService; @@ -81,15 +78,14 @@ public class ExamImportService { private final ChannelService channelService; - public ExamImportService(TextExerciseImportService textExerciseImportService, TextExerciseRepository textExerciseRepository, - ModelingExerciseImportService modelingExerciseImportService, ModelingExerciseRepository modelingExerciseRepository, ExamRepository examRepository, - ExerciseGroupRepository exerciseGroupRepository, QuizExerciseRepository quizExerciseRepository, QuizExerciseImportService importQuizExercise, - CourseRepository courseRepository, ProgrammingExerciseService programmingExerciseService1, ProgrammingExerciseRepository programmingExerciseRepository, + public ExamImportService(Optional textExerciseImportApi, ModelingExerciseImportService modelingExerciseImportService, + ModelingExerciseRepository modelingExerciseRepository, ExamRepository examRepository, ExerciseGroupRepository exerciseGroupRepository, + QuizExerciseRepository quizExerciseRepository, QuizExerciseImportService importQuizExercise, CourseRepository courseRepository, + ProgrammingExerciseService programmingExerciseService1, ProgrammingExerciseRepository programmingExerciseRepository, ProgrammingExerciseImportService programmingExerciseImportService, FileUploadExerciseRepository fileUploadExerciseRepository, FileUploadExerciseImportService fileUploadExerciseImportService, GradingCriterionRepository gradingCriterionRepository, ProgrammingExerciseTaskRepository programmingExerciseTaskRepository, ChannelService channelService) { - this.textExerciseImportService = textExerciseImportService; - this.textExerciseRepository = textExerciseRepository; + this.textExerciseImportApi = textExerciseImportApi; this.modelingExerciseImportService = modelingExerciseImportService; this.modelingExerciseRepository = modelingExerciseRepository; this.examRepository = examRepository; @@ -288,7 +284,7 @@ private void addExercisesToExerciseGroup(ExerciseGroup exerciseGroupToCopy, Exer for (Exercise exerciseToCopy : exerciseGroupToCopy.getExercises()) { // We need to set the new Exercise Group to the old exercise, so the new exercise group is correctly set for the new exercise exerciseToCopy.setExerciseGroup(exerciseGroupCopied); - Optional exerciseCopied = switch (exerciseToCopy.getExerciseType()) { + Optional exerciseCopied = switch (exerciseToCopy.getExerciseType()) { case MODELING -> { final Optional optionalOriginalModellingExercise = modelingExerciseRepository .findByIdWithExampleSubmissionsAndResultsAndPlagiarismDetectionConfigAndGradingCriteria(exerciseToCopy.getId()); @@ -300,11 +296,10 @@ private void addExercisesToExerciseGroup(ExerciseGroup exerciseGroupToCopy, Exer } case TEXT -> { - final Optional optionalOriginalTextExercise = textExerciseRepository.findWithExampleSubmissionsAndResultsById(exerciseToCopy.getId()); - if (optionalOriginalTextExercise.isEmpty()) { + if (textExerciseImportApi.isEmpty()) { yield Optional.empty(); } - yield Optional.of(textExerciseImportService.importTextExercise(optionalOriginalTextExercise.get(), (TextExercise) exerciseToCopy)); + yield textExerciseImportApi.get().importTextExercise(exerciseToCopy.getId(), (TextExercise) exerciseToCopy); } case PROGRAMMING -> { diff --git a/src/main/java/de/tum/cit/aet/artemis/text/api/TextExerciseImportApi.java b/src/main/java/de/tum/cit/aet/artemis/text/api/TextExerciseImportApi.java index 03ab59b8e950..930cf98fb185 100644 --- a/src/main/java/de/tum/cit/aet/artemis/text/api/TextExerciseImportApi.java +++ b/src/main/java/de/tum/cit/aet/artemis/text/api/TextExerciseImportApi.java @@ -36,4 +36,9 @@ public TextExercise findByIdWithExampleSubmissionsAndResultsAndGradingCriteriaEl public TextExercise importTextExercise(final TextExercise templateExercise, TextExercise importedExercise) { return textExerciseImportService.importTextExercise(templateExercise, importedExercise); } + + public Optional importTextExercise(final long templateExerciseId, final TextExercise exerciseToCopy) { + final Optional optionalOriginalTextExercise = textExerciseRepository.findWithExampleSubmissionsAndResultsById(templateExerciseId); + return optionalOriginalTextExercise.map(textExercise -> textExerciseImportService.importTextExercise(textExercise, exerciseToCopy)); + } } From 308827535d45e28ca84ea96ba6eed69512596558 Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Tue, 17 Dec 2024 15:11:02 +0100 Subject: [PATCH 04/22] add TextExerciseSubmissionApi and use in ExampleSubmissionService --- .../service/ExampleSubmissionService.java | 18 +++++--- .../text/api/TextExerciseSubmissionApi.java | 43 +++++++++++++++++++ 2 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 src/main/java/de/tum/cit/aet/artemis/text/api/TextExerciseSubmissionApi.java diff --git a/src/main/java/de/tum/cit/aet/artemis/assessment/service/ExampleSubmissionService.java b/src/main/java/de/tum/cit/aet/artemis/assessment/service/ExampleSubmissionService.java index 73e961df3855..154271e43b24 100644 --- a/src/main/java/de/tum/cit/aet/artemis/assessment/service/ExampleSubmissionService.java +++ b/src/main/java/de/tum/cit/aet/artemis/assessment/service/ExampleSubmissionService.java @@ -15,6 +15,7 @@ import de.tum.cit.aet.artemis.assessment.repository.ExampleSubmissionRepository; import de.tum.cit.aet.artemis.assessment.repository.GradingCriterionRepository; import de.tum.cit.aet.artemis.assessment.repository.TutorParticipationRepository; +import de.tum.cit.aet.artemis.core.exception.ApiNotPresentException; import de.tum.cit.aet.artemis.core.exception.BadRequestAlertException; import de.tum.cit.aet.artemis.exercise.domain.Exercise; import de.tum.cit.aet.artemis.exercise.domain.Submission; @@ -23,6 +24,7 @@ import de.tum.cit.aet.artemis.modeling.domain.ModelingExercise; import de.tum.cit.aet.artemis.modeling.domain.ModelingSubmission; import de.tum.cit.aet.artemis.modeling.service.ModelingExerciseImportService; +import de.tum.cit.aet.artemis.text.api.TextExerciseSubmissionApi; import de.tum.cit.aet.artemis.text.domain.TextExercise; import de.tum.cit.aet.artemis.text.domain.TextSubmission; import de.tum.cit.aet.artemis.text.repository.TextSubmissionRepository; @@ -44,6 +46,8 @@ public class ExampleSubmissionService { private final ModelingExerciseImportService modelingExerciseImportService; + private final Optional textExerciseSubmissionApi; + private final TextSubmissionRepository textSubmissionRepository; private final GradingCriterionRepository gradingCriterionRepository; @@ -51,13 +55,15 @@ public class ExampleSubmissionService { private final TutorParticipationRepository tutorParticipationRepository; public ExampleSubmissionService(ExampleSubmissionRepository exampleSubmissionRepository, SubmissionRepository submissionRepository, ExerciseRepository exerciseRepository, - TextExerciseImportService textExerciseImportService, ModelingExerciseImportService modelingExerciseImportService, TextSubmissionRepository textSubmissionRepository, - GradingCriterionRepository gradingCriterionRepository, TutorParticipationRepository tutorParticipationRepository) { + TextExerciseImportService textExerciseImportService, ModelingExerciseImportService modelingExerciseImportService, + Optional textExerciseSubmissionApi, TextSubmissionRepository textSubmissionRepository, GradingCriterionRepository gradingCriterionRepository, + TutorParticipationRepository tutorParticipationRepository) { this.exampleSubmissionRepository = exampleSubmissionRepository; this.submissionRepository = submissionRepository; this.exerciseRepository = exerciseRepository; this.modelingExerciseImportService = modelingExerciseImportService; this.textExerciseImportService = textExerciseImportService; + this.textExerciseSubmissionApi = textExerciseSubmissionApi; this.textSubmissionRepository = textSubmissionRepository; this.gradingCriterionRepository = gradingCriterionRepository; this.tutorParticipationRepository = tutorParticipationRepository; @@ -136,11 +142,9 @@ public ExampleSubmission importStudentSubmissionAsExampleSubmission(Long submiss newExampleSubmission.setSubmission(modelingExerciseImportService.copySubmission(modelingSubmission, gradingInstructionCopyTracker)); } if (exercise instanceof TextExercise) { - TextSubmission textSubmission = textSubmissionRepository.findByIdWithEagerResultsAndFeedbackAndTextBlocksElseThrow(submissionId); - checkGivenExerciseIdSameForSubmissionParticipation(exercise.getId(), textSubmission.getParticipation().getExercise().getId()); - // example submission does not need participation - textSubmission.setParticipation(null); - newExampleSubmission.setSubmission(textExerciseImportService.copySubmission(textSubmission, gradingInstructionCopyTracker)); + var api = textExerciseSubmissionApi.orElseThrow(() -> new ApiNotPresentException(TextExerciseSubmissionApi.class, PROFILE_CORE)); + TextSubmission textSubmission = api.importStudentSubmission(submissionId, exercise.getId(), gradingInstructionCopyTracker); + newExampleSubmission.setSubmission(textSubmission); } return exampleSubmissionRepository.save(newExampleSubmission); } diff --git a/src/main/java/de/tum/cit/aet/artemis/text/api/TextExerciseSubmissionApi.java b/src/main/java/de/tum/cit/aet/artemis/text/api/TextExerciseSubmissionApi.java new file mode 100644 index 000000000000..a3caddaccc50 --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/text/api/TextExerciseSubmissionApi.java @@ -0,0 +1,43 @@ +package de.tum.cit.aet.artemis.text.api; + +import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_CORE; + +import java.util.Map; +import java.util.Objects; + +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Controller; + +import de.tum.cit.aet.artemis.assessment.domain.GradingInstruction; +import de.tum.cit.aet.artemis.text.domain.TextSubmission; +import de.tum.cit.aet.artemis.text.repository.TextSubmissionRepository; +import de.tum.cit.aet.artemis.text.service.TextExerciseImportService; + +@Controller +@Profile(PROFILE_CORE) +public class TextExerciseSubmissionApi extends AbstractTextApi { + + private final TextSubmissionRepository textSubmissionRepository; + + private final TextExerciseImportService textExerciseImportService; + + public TextExerciseSubmissionApi(TextSubmissionRepository textSubmissionRepository, TextExerciseImportService textExerciseImportService) { + this.textSubmissionRepository = textSubmissionRepository; + this.textExerciseImportService = textExerciseImportService; + } + + public TextSubmission importStudentSubmission(long submissionId, long exerciseId, Map gradingInstructionCopyTracker) { + TextSubmission textSubmission = textSubmissionRepository.findByIdWithEagerResultsAndFeedbackAndTextBlocksElseThrow(submissionId); + checkGivenExerciseIdSameForSubmissionParticipation(exerciseId, textSubmission.getParticipation().getExercise().getId()); + + // example submission does not need participation + textSubmission.setParticipation(null); + return textExerciseImportService.copySubmission(textSubmission, gradingInstructionCopyTracker); + } + + private void checkGivenExerciseIdSameForSubmissionParticipation(long originalExerciseId, long exerciseIdInSubmission) { + if (!Objects.equals(originalExerciseId, exerciseIdInSubmission)) { + throw new IllegalArgumentException("ExerciseId does not match with the exerciseId in submission participation"); + } + } +} From 5fd08eee88d7e427b7db7c76759e88c8ad55cc74 Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Tue, 17 Dec 2024 15:19:32 +0100 Subject: [PATCH 05/22] use TextExerciseSubmissionApi in StudentExamService --- .../exam/service/StudentExamService.java | 18 +++++++++--------- .../text/api/TextExerciseSubmissionApi.java | 4 ++++ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/main/java/de/tum/cit/aet/artemis/exam/service/StudentExamService.java b/src/main/java/de/tum/cit/aet/artemis/exam/service/StudentExamService.java index 41757da8eddd..16139e2829b8 100644 --- a/src/main/java/de/tum/cit/aet/artemis/exam/service/StudentExamService.java +++ b/src/main/java/de/tum/cit/aet/artemis/exam/service/StudentExamService.java @@ -35,6 +35,7 @@ import de.tum.cit.aet.artemis.communication.service.WebsocketMessagingService; import de.tum.cit.aet.artemis.core.domain.User; import de.tum.cit.aet.artemis.core.exception.AccessForbiddenException; +import de.tum.cit.aet.artemis.core.exception.ApiNotPresentException; import de.tum.cit.aet.artemis.core.exception.EntityNotFoundException; import de.tum.cit.aet.artemis.core.repository.UserRepository; import de.tum.cit.aet.artemis.core.security.SecurityUtils; @@ -72,9 +73,9 @@ import de.tum.cit.aet.artemis.quiz.repository.QuizSubmissionRepository; import de.tum.cit.aet.artemis.quiz.repository.SubmittedAnswerRepository; import de.tum.cit.aet.artemis.quiz.service.QuizPoolService; +import de.tum.cit.aet.artemis.text.api.TextExerciseSubmissionApi; import de.tum.cit.aet.artemis.text.domain.TextExercise; import de.tum.cit.aet.artemis.text.domain.TextSubmission; -import de.tum.cit.aet.artemis.text.repository.TextSubmissionRepository; /** * Service Implementation for managing StudentExam. @@ -109,7 +110,7 @@ public class StudentExamService { private final SubmittedAnswerRepository submittedAnswerRepository; - private final TextSubmissionRepository textSubmissionRepository; + private final Optional textExerciseSubmissionApi; private final ModelingSubmissionRepository modelingSubmissionRepository; @@ -126,18 +127,16 @@ public class StudentExamService { private final ExamQuizQuestionsGenerator examQuizQuestionsGenerator; public StudentExamService(StudentExamRepository studentExamRepository, UserRepository userRepository, ParticipationService participationService, - QuizSubmissionRepository quizSubmissionRepository, SubmittedAnswerRepository submittedAnswerRepository, TextSubmissionRepository textSubmissionRepository, - ModelingSubmissionRepository modelingSubmissionRepository, SubmissionVersionService submissionVersionService, - ProgrammingExerciseParticipationService programmingExerciseParticipationService, SubmissionService submissionService, + QuizSubmissionRepository quizSubmissionRepository, SubmittedAnswerRepository submittedAnswerRepository, ModelingSubmissionRepository modelingSubmissionRepository, + SubmissionVersionService submissionVersionService, ProgrammingExerciseParticipationService programmingExerciseParticipationService, SubmissionService submissionService, StudentParticipationRepository studentParticipationRepository, ExamQuizService examQuizService, ProgrammingExerciseRepository programmingExerciseRepository, - ProgrammingTriggerService programmingTriggerService, ExamRepository examRepository, CacheManager cacheManager, WebsocketMessagingService websocketMessagingService, - @Qualifier("taskScheduler") TaskScheduler scheduler, QuizPoolService quizPoolService) { + ProgrammingTriggerService programmingTriggerService, Optional textExerciseSubmissionApi, ExamRepository examRepository, + CacheManager cacheManager, WebsocketMessagingService websocketMessagingService, @Qualifier("taskScheduler") TaskScheduler scheduler, QuizPoolService quizPoolService) { this.participationService = participationService; this.studentExamRepository = studentExamRepository; this.userRepository = userRepository; this.quizSubmissionRepository = quizSubmissionRepository; this.submittedAnswerRepository = submittedAnswerRepository; - this.textSubmissionRepository = textSubmissionRepository; this.modelingSubmissionRepository = modelingSubmissionRepository; this.submissionVersionService = submissionVersionService; this.programmingExerciseParticipationService = programmingExerciseParticipationService; @@ -146,6 +145,7 @@ public StudentExamService(StudentExamRepository studentExamRepository, UserRepos this.submissionService = submissionService; this.programmingExerciseRepository = programmingExerciseRepository; this.programmingTriggerService = programmingTriggerService; + this.textExerciseSubmissionApi = textExerciseSubmissionApi; this.examRepository = examRepository; this.cacheManager = cacheManager; this.websocketMessagingService = websocketMessagingService; @@ -314,7 +314,7 @@ else if (submittedAnswer instanceof ShortAnswerSubmittedAnswer) { TextSubmission existingSubmissionInDatabase = (TextSubmission) existingParticipationInDatabase.findLatestSubmission().orElse(null); TextSubmission textSubmissionFromClient = (TextSubmission) submissionFromClient; if (!isContentEqualTo(existingSubmissionInDatabase, textSubmissionFromClient)) { - textSubmissionRepository.save(textSubmissionFromClient); + textExerciseSubmissionApi.orElseThrow(() -> new ApiNotPresentException(TextExerciseSubmissionApi.class, PROFILE_CORE)); saveSubmissionVersion(currentUser, submissionFromClient); } } diff --git a/src/main/java/de/tum/cit/aet/artemis/text/api/TextExerciseSubmissionApi.java b/src/main/java/de/tum/cit/aet/artemis/text/api/TextExerciseSubmissionApi.java index a3caddaccc50..8206ff61f7a6 100644 --- a/src/main/java/de/tum/cit/aet/artemis/text/api/TextExerciseSubmissionApi.java +++ b/src/main/java/de/tum/cit/aet/artemis/text/api/TextExerciseSubmissionApi.java @@ -35,6 +35,10 @@ public TextSubmission importStudentSubmission(long submissionId, long exerciseId return textExerciseImportService.copySubmission(textSubmission, gradingInstructionCopyTracker); } + public TextSubmission saveTextSubmission(TextSubmission textSubmission) { + return textSubmissionRepository.save(textSubmission); + } + private void checkGivenExerciseIdSameForSubmissionParticipation(long originalExerciseId, long exerciseIdInSubmission) { if (!Objects.equals(originalExerciseId, exerciseIdInSubmission)) { throw new IllegalArgumentException("ExerciseId does not match with the exerciseId in submission participation"); From 50da32e909befacf78dc7942362d624c0b9c83f8 Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Tue, 17 Dec 2024 15:22:24 +0100 Subject: [PATCH 06/22] add TextSubmissionExportApi and use in TextPlagiarismDetectionService --- .../TextPlagiarismDetectionService.java | 12 ++++++-- .../text/api/TextSubmissionExportApi.java | 28 +++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionExportApi.java diff --git a/src/main/java/de/tum/cit/aet/artemis/plagiarism/service/TextPlagiarismDetectionService.java b/src/main/java/de/tum/cit/aet/artemis/plagiarism/service/TextPlagiarismDetectionService.java index 6a5bbe7e945c..2523ee8784d3 100644 --- a/src/main/java/de/tum/cit/aet/artemis/plagiarism/service/TextPlagiarismDetectionService.java +++ b/src/main/java/de/tum/cit/aet/artemis/plagiarism/service/TextPlagiarismDetectionService.java @@ -24,6 +24,7 @@ import de.jplag.exceptions.ExitException; import de.jplag.options.JPlagOptions; import de.jplag.text.NaturalLanguage; +import de.tum.cit.aet.artemis.core.exception.ApiNotPresentException; import de.tum.cit.aet.artemis.core.exception.BadRequestAlertException; import de.tum.cit.aet.artemis.core.util.TimeLogUtil; import de.tum.cit.aet.artemis.exercise.domain.participation.Participation; @@ -31,6 +32,7 @@ import de.tum.cit.aet.artemis.plagiarism.domain.PlagiarismCheckState; import de.tum.cit.aet.artemis.plagiarism.domain.text.TextPlagiarismResult; import de.tum.cit.aet.artemis.plagiarism.service.cache.PlagiarismCacheService; +import de.tum.cit.aet.artemis.text.api.TextSubmissionExportApi; import de.tum.cit.aet.artemis.text.domain.TextExercise; import de.tum.cit.aet.artemis.text.domain.TextSubmission; import de.tum.cit.aet.artemis.text.service.TextSubmissionExportService; @@ -41,6 +43,8 @@ public class TextPlagiarismDetectionService { private static final Logger log = LoggerFactory.getLogger(TextPlagiarismDetectionService.class); + private final Optional textSubmissionExportApi; + private final TextSubmissionExportService textSubmissionExportService; private final PlagiarismWebsocketService plagiarismWebsocketService; @@ -49,8 +53,9 @@ public class TextPlagiarismDetectionService { private final PlagiarismService plagiarismService; - public TextPlagiarismDetectionService(TextSubmissionExportService textSubmissionExportService, PlagiarismWebsocketService plagiarismWebsocketService, - PlagiarismCacheService plagiarismCacheService, PlagiarismService plagiarismService) { + public TextPlagiarismDetectionService(Optional textSubmissionExportApi, TextSubmissionExportService textSubmissionExportService, + PlagiarismWebsocketService plagiarismWebsocketService, PlagiarismCacheService plagiarismCacheService, PlagiarismService plagiarismService) { + this.textSubmissionExportApi = textSubmissionExportApi; this.textSubmissionExportService = textSubmissionExportService; this.plagiarismWebsocketService = plagiarismWebsocketService; this.plagiarismCacheService = plagiarismCacheService; @@ -129,7 +134,8 @@ public TextPlagiarismResult checkPlagiarism(TextExercise textExercise, float sim } try { - textSubmissionExportService.saveSubmissionToFile(submission, participantIdentifier, submissionsFolderName); + textSubmissionExportApi.orElseThrow(() -> new ApiNotPresentException(TextSubmissionExportApi.class, PROFILE_CORE)).saveSubmissionToFile(submission, + participantIdentifier, submissionsFolderName); } catch (IOException e) { log.error(e.getMessage()); diff --git a/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionExportApi.java b/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionExportApi.java new file mode 100644 index 000000000000..7eebdb69f0cd --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionExportApi.java @@ -0,0 +1,28 @@ +package de.tum.cit.aet.artemis.text.api; + +import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_CORE; + +import java.io.IOException; + +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Controller; + +import de.tum.cit.aet.artemis.text.domain.TextSubmission; +import de.tum.cit.aet.artemis.text.service.TextSubmissionExportService; + +@Controller +@Profile(PROFILE_CORE) +public class TextSubmissionExportApi extends AbstractTextApi { + + private final TextSubmissionExportService textSubmissionExportService; + + public TextSubmissionExportApi(TextSubmissionExportService textSubmissionExportService) { + this.textSubmissionExportService = textSubmissionExportService; + } + + public void saveSubmissionToFile(TextSubmission submission, String studentLogin, String submissionsFolderName) throws IOException { + textSubmissionExportService.saveSubmissionToFile(submission, studentLogin, submissionsFolderName); + + } + +} From 0bb86193a05cfc6a7d8726f20501734927c2079a Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Tue, 17 Dec 2024 15:23:37 +0100 Subject: [PATCH 07/22] rename TextExerciseSubmissionApi to TextSubmissionApi --- .../aet/artemis/exam/service/StudentExamService.java | 12 ++++++------ ...ciseSubmissionApi.java => TextSubmissionApi.java} | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) rename src/main/java/de/tum/cit/aet/artemis/text/api/{TextExerciseSubmissionApi.java => TextSubmissionApi.java} (90%) diff --git a/src/main/java/de/tum/cit/aet/artemis/exam/service/StudentExamService.java b/src/main/java/de/tum/cit/aet/artemis/exam/service/StudentExamService.java index 16139e2829b8..5dfd90e72c04 100644 --- a/src/main/java/de/tum/cit/aet/artemis/exam/service/StudentExamService.java +++ b/src/main/java/de/tum/cit/aet/artemis/exam/service/StudentExamService.java @@ -73,7 +73,7 @@ import de.tum.cit.aet.artemis.quiz.repository.QuizSubmissionRepository; import de.tum.cit.aet.artemis.quiz.repository.SubmittedAnswerRepository; import de.tum.cit.aet.artemis.quiz.service.QuizPoolService; -import de.tum.cit.aet.artemis.text.api.TextExerciseSubmissionApi; +import de.tum.cit.aet.artemis.text.api.TextSubmissionApi; import de.tum.cit.aet.artemis.text.domain.TextExercise; import de.tum.cit.aet.artemis.text.domain.TextSubmission; @@ -110,7 +110,7 @@ public class StudentExamService { private final SubmittedAnswerRepository submittedAnswerRepository; - private final Optional textExerciseSubmissionApi; + private final Optional textSubmissionApi; private final ModelingSubmissionRepository modelingSubmissionRepository; @@ -130,8 +130,8 @@ public StudentExamService(StudentExamRepository studentExamRepository, UserRepos QuizSubmissionRepository quizSubmissionRepository, SubmittedAnswerRepository submittedAnswerRepository, ModelingSubmissionRepository modelingSubmissionRepository, SubmissionVersionService submissionVersionService, ProgrammingExerciseParticipationService programmingExerciseParticipationService, SubmissionService submissionService, StudentParticipationRepository studentParticipationRepository, ExamQuizService examQuizService, ProgrammingExerciseRepository programmingExerciseRepository, - ProgrammingTriggerService programmingTriggerService, Optional textExerciseSubmissionApi, ExamRepository examRepository, - CacheManager cacheManager, WebsocketMessagingService websocketMessagingService, @Qualifier("taskScheduler") TaskScheduler scheduler, QuizPoolService quizPoolService) { + ProgrammingTriggerService programmingTriggerService, Optional textSubmissionApi, ExamRepository examRepository, CacheManager cacheManager, + WebsocketMessagingService websocketMessagingService, @Qualifier("taskScheduler") TaskScheduler scheduler, QuizPoolService quizPoolService) { this.participationService = participationService; this.studentExamRepository = studentExamRepository; this.userRepository = userRepository; @@ -145,7 +145,7 @@ public StudentExamService(StudentExamRepository studentExamRepository, UserRepos this.submissionService = submissionService; this.programmingExerciseRepository = programmingExerciseRepository; this.programmingTriggerService = programmingTriggerService; - this.textExerciseSubmissionApi = textExerciseSubmissionApi; + this.textSubmissionApi = textSubmissionApi; this.examRepository = examRepository; this.cacheManager = cacheManager; this.websocketMessagingService = websocketMessagingService; @@ -314,7 +314,7 @@ else if (submittedAnswer instanceof ShortAnswerSubmittedAnswer) { TextSubmission existingSubmissionInDatabase = (TextSubmission) existingParticipationInDatabase.findLatestSubmission().orElse(null); TextSubmission textSubmissionFromClient = (TextSubmission) submissionFromClient; if (!isContentEqualTo(existingSubmissionInDatabase, textSubmissionFromClient)) { - textExerciseSubmissionApi.orElseThrow(() -> new ApiNotPresentException(TextExerciseSubmissionApi.class, PROFILE_CORE)); + textSubmissionApi.orElseThrow(() -> new ApiNotPresentException(TextSubmissionApi.class, PROFILE_CORE)); saveSubmissionVersion(currentUser, submissionFromClient); } } diff --git a/src/main/java/de/tum/cit/aet/artemis/text/api/TextExerciseSubmissionApi.java b/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionApi.java similarity index 90% rename from src/main/java/de/tum/cit/aet/artemis/text/api/TextExerciseSubmissionApi.java rename to src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionApi.java index 8206ff61f7a6..41610dbd16a1 100644 --- a/src/main/java/de/tum/cit/aet/artemis/text/api/TextExerciseSubmissionApi.java +++ b/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionApi.java @@ -15,13 +15,13 @@ @Controller @Profile(PROFILE_CORE) -public class TextExerciseSubmissionApi extends AbstractTextApi { +public class TextSubmissionApi extends AbstractTextApi { private final TextSubmissionRepository textSubmissionRepository; private final TextExerciseImportService textExerciseImportService; - public TextExerciseSubmissionApi(TextSubmissionRepository textSubmissionRepository, TextExerciseImportService textExerciseImportService) { + public TextSubmissionApi(TextSubmissionRepository textSubmissionRepository, TextExerciseImportService textExerciseImportService) { this.textSubmissionRepository = textSubmissionRepository; this.textExerciseImportService = textExerciseImportService; } From 7964cda44b7fed715e46fb002f41ccd5367eebff Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Tue, 17 Dec 2024 15:27:55 +0100 Subject: [PATCH 08/22] use TextSubmissionExportApi in CourseExamExportService --- .../service/export/CourseExamExportService.java | 15 ++++++++------- .../text/api/TextSubmissionExportApi.java | 16 ++++++++++++++-- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/main/java/de/tum/cit/aet/artemis/core/service/export/CourseExamExportService.java b/src/main/java/de/tum/cit/aet/artemis/core/service/export/CourseExamExportService.java index ad14a6097a26..9e9e1ff56c2c 100644 --- a/src/main/java/de/tum/cit/aet/artemis/core/service/export/CourseExamExportService.java +++ b/src/main/java/de/tum/cit/aet/artemis/core/service/export/CourseExamExportService.java @@ -48,8 +48,8 @@ import de.tum.cit.aet.artemis.programming.service.ProgrammingExerciseExportService; import de.tum.cit.aet.artemis.quiz.domain.QuizExercise; import de.tum.cit.aet.artemis.quiz.service.QuizExerciseWithSubmissionsExportService; +import de.tum.cit.aet.artemis.text.api.TextSubmissionExportApi; import de.tum.cit.aet.artemis.text.domain.TextExercise; -import de.tum.cit.aet.artemis.text.service.TextExerciseWithSubmissionsExportService; /** * Service Implementation for exporting courses and exams. @@ -67,7 +67,7 @@ public class CourseExamExportService { private final ZipFileService zipFileService; - private final TextExerciseWithSubmissionsExportService textExerciseWithSubmissionsExportService; + private final Optional textSubmissionExportApi; private final FileUploadExerciseWithSubmissionsExportService fileUploadExerciseWithSubmissionsExportService; @@ -81,15 +81,16 @@ public class CourseExamExportService { private final WebsocketMessagingService websocketMessagingService; - public CourseExamExportService(ProgrammingExerciseExportService programmingExerciseExportService, ZipFileService zipFileService, FileService fileService, - TextExerciseWithSubmissionsExportService textExerciseWithSubmissionsExportService, + public CourseExamExportService(ProgrammingExerciseExportService programmingExerciseExportService, ZipFileService zipFileService, + Optional textSubmissionExportApi, FileService fileService, + FileUploadExerciseWithSubmissionsExportService fileUploadExerciseWithSubmissionsExportService, ModelingExerciseWithSubmissionsExportService modelingExerciseWithSubmissionsExportService, QuizExerciseWithSubmissionsExportService quizExerciseWithSubmissionsExportService, WebsocketMessagingService websocketMessagingService, ExamRepository examRepository) { this.programmingExerciseExportService = programmingExerciseExportService; this.zipFileService = zipFileService; + this.textSubmissionExportApi = textSubmissionExportApi; this.fileService = fileService; - this.textExerciseWithSubmissionsExportService = textExerciseWithSubmissionsExportService; this.fileUploadExerciseWithSubmissionsExportService = fileUploadExerciseWithSubmissionsExportService; this.modelingExerciseWithSubmissionsExportService = modelingExerciseWithSubmissionsExportService; this.quizExerciseWithSubmissionsExportService = quizExerciseWithSubmissionsExportService; @@ -423,8 +424,8 @@ private List exportExercises(String notificationTopic, Set exerc .ifPresent(exportedExercises::add); case FileUploadExercise fileUploadExercise -> exportedExercises.add(fileUploadExerciseWithSubmissionsExportService .exportFileUploadExerciseWithSubmissions(fileUploadExercise, submissionsExportOptions, exerciseExportDir, exportErrors, reportData)); - case TextExercise textExercise -> exportedExercises.add(textExerciseWithSubmissionsExportService.exportTextExerciseWithSubmissions(textExercise, - submissionsExportOptions, exerciseExportDir, exportErrors, reportData)); + case TextExercise textExercise -> textSubmissionExportApi.ifPresent(api -> exportedExercises + .add(api.exportTextExerciseWithSubmissions(textExercise, submissionsExportOptions, exerciseExportDir, exportErrors, reportData))); case ModelingExercise modelingExercise -> exportedExercises.add(modelingExerciseWithSubmissionsExportService .exportModelingExerciseWithSubmissions(modelingExercise, submissionsExportOptions, exerciseExportDir, exportErrors, reportData)); case QuizExercise quizExercise -> diff --git a/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionExportApi.java b/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionExportApi.java index 7eebdb69f0cd..48ae66398e68 100644 --- a/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionExportApi.java +++ b/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionExportApi.java @@ -3,11 +3,17 @@ import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_CORE; import java.io.IOException; +import java.nio.file.Path; +import java.util.List; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Controller; +import de.tum.cit.aet.artemis.core.service.ArchivalReportEntry; +import de.tum.cit.aet.artemis.exercise.dto.SubmissionExportOptionsDTO; +import de.tum.cit.aet.artemis.text.domain.TextExercise; import de.tum.cit.aet.artemis.text.domain.TextSubmission; +import de.tum.cit.aet.artemis.text.service.TextExerciseWithSubmissionsExportService; import de.tum.cit.aet.artemis.text.service.TextSubmissionExportService; @Controller @@ -16,13 +22,19 @@ public class TextSubmissionExportApi extends AbstractTextApi { private final TextSubmissionExportService textSubmissionExportService; - public TextSubmissionExportApi(TextSubmissionExportService textSubmissionExportService) { + private final TextExerciseWithSubmissionsExportService textExerciseWithSubmissionsExportService; + + public TextSubmissionExportApi(TextSubmissionExportService textSubmissionExportService, TextExerciseWithSubmissionsExportService textExerciseWithSubmissionsExportService) { this.textSubmissionExportService = textSubmissionExportService; + this.textExerciseWithSubmissionsExportService = textExerciseWithSubmissionsExportService; } public void saveSubmissionToFile(TextSubmission submission, String studentLogin, String submissionsFolderName) throws IOException { textSubmissionExportService.saveSubmissionToFile(submission, studentLogin, submissionsFolderName); - } + public Path exportTextExerciseWithSubmissions(TextExercise exercise, SubmissionExportOptionsDTO optionsDTO, Path exportDir, List exportErrors, + List reportEntries) { + return textExerciseWithSubmissionsExportService.exportTextExerciseWithSubmissions(exercise, optionsDTO, exportDir, exportErrors, reportEntries); + } } From 8264208370a50610ad15fe14ddefe16dc0d63caa Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Tue, 17 Dec 2024 15:31:11 +0100 Subject: [PATCH 09/22] use TextSubmissionApi in ParticipationTeamWebsocketService --- .../web/ParticipationTeamWebsocketService.java | 13 +++++++------ .../aet/artemis/text/api/TextSubmissionApi.java | 14 +++++++++++++- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/tum/cit/aet/artemis/exercise/web/ParticipationTeamWebsocketService.java b/src/main/java/de/tum/cit/aet/artemis/exercise/web/ParticipationTeamWebsocketService.java index ad7d9b0fa16a..1d1adaf260ef 100644 --- a/src/main/java/de/tum/cit/aet/artemis/exercise/web/ParticipationTeamWebsocketService.java +++ b/src/main/java/de/tum/cit/aet/artemis/exercise/web/ParticipationTeamWebsocketService.java @@ -34,6 +34,7 @@ import de.tum.cit.aet.artemis.communication.service.WebsocketMessagingService; import de.tum.cit.aet.artemis.core.domain.User; +import de.tum.cit.aet.artemis.core.exception.ApiNotPresentException; import de.tum.cit.aet.artemis.core.repository.UserRepository; import de.tum.cit.aet.artemis.core.security.SecurityUtils; import de.tum.cit.aet.artemis.exercise.domain.Exercise; @@ -48,9 +49,9 @@ import de.tum.cit.aet.artemis.modeling.domain.ModelingSubmission; import de.tum.cit.aet.artemis.modeling.service.ModelingSubmissionService; import de.tum.cit.aet.artemis.programming.dto.OnlineTeamStudentDTO; +import de.tum.cit.aet.artemis.text.api.TextSubmissionApi; import de.tum.cit.aet.artemis.text.domain.TextExercise; import de.tum.cit.aet.artemis.text.domain.TextSubmission; -import de.tum.cit.aet.artemis.text.service.TextSubmissionService; @Controller @Profile(PROFILE_CORE) @@ -68,7 +69,7 @@ public class ParticipationTeamWebsocketService { private final ExerciseRepository exerciseRepository; - private final TextSubmissionService textSubmissionService; + private final Optional textSubmissionApi; private final ModelingSubmissionService modelingSubmissionService; @@ -81,14 +82,14 @@ public class ParticipationTeamWebsocketService { private Map lastActionTracker; public ParticipationTeamWebsocketService(WebsocketMessagingService websocketMessagingService, SimpUserRegistry simpUserRegistry, UserRepository userRepository, - StudentParticipationRepository studentParticipationRepository, ExerciseRepository exerciseRepository, TextSubmissionService textSubmissionService, + StudentParticipationRepository studentParticipationRepository, ExerciseRepository exerciseRepository, Optional textSubmissionApi, ModelingSubmissionService modelingSubmissionService, @Qualifier("hazelcastInstance") HazelcastInstance hazelcastInstance) { this.websocketMessagingService = websocketMessagingService; this.simpUserRegistry = simpUserRegistry; this.userRepository = userRepository; this.studentParticipationRepository = studentParticipationRepository; this.exerciseRepository = exerciseRepository; - this.textSubmissionService = textSubmissionService; + this.textSubmissionApi = textSubmissionApi; this.modelingSubmissionService = modelingSubmissionService; this.hazelcastInstance = hazelcastInstance; } @@ -215,8 +216,8 @@ private void updateSubmission(@DestinationVariable Long participationId, @Payloa modelingSubmissionService.hideDetails(submission, user); } else if (submission instanceof TextSubmission textSubmission && exercise instanceof TextExercise textExercise) { - submission = textSubmissionService.handleTextSubmission(textSubmission, textExercise, user); - textSubmissionService.hideDetails(submission, user); + submission = textSubmissionApi.orElseThrow(() -> new ApiNotPresentException(TextSubmissionApi.class, PROFILE_CORE)).handleTextSubmission(textSubmission, textExercise, + user); } else { throw new IllegalArgumentException("Submission type '" + submission.getType() + "' not allowed."); diff --git a/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionApi.java b/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionApi.java index 41610dbd16a1..1ed033f9bfed 100644 --- a/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionApi.java +++ b/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionApi.java @@ -9,9 +9,12 @@ import org.springframework.stereotype.Controller; import de.tum.cit.aet.artemis.assessment.domain.GradingInstruction; +import de.tum.cit.aet.artemis.core.domain.User; +import de.tum.cit.aet.artemis.text.domain.TextExercise; import de.tum.cit.aet.artemis.text.domain.TextSubmission; import de.tum.cit.aet.artemis.text.repository.TextSubmissionRepository; import de.tum.cit.aet.artemis.text.service.TextExerciseImportService; +import de.tum.cit.aet.artemis.text.service.TextSubmissionService; @Controller @Profile(PROFILE_CORE) @@ -21,9 +24,12 @@ public class TextSubmissionApi extends AbstractTextApi { private final TextExerciseImportService textExerciseImportService; - public TextSubmissionApi(TextSubmissionRepository textSubmissionRepository, TextExerciseImportService textExerciseImportService) { + private final TextSubmissionService textSubmissionService; + + public TextSubmissionApi(TextSubmissionRepository textSubmissionRepository, TextExerciseImportService textExerciseImportService, TextSubmissionService textSubmissionService) { this.textSubmissionRepository = textSubmissionRepository; this.textExerciseImportService = textExerciseImportService; + this.textSubmissionService = textSubmissionService; } public TextSubmission importStudentSubmission(long submissionId, long exerciseId, Map gradingInstructionCopyTracker) { @@ -39,6 +45,12 @@ public TextSubmission saveTextSubmission(TextSubmission textSubmission) { return textSubmissionRepository.save(textSubmission); } + public TextSubmission handleTextSubmission(TextSubmission textSubmission, TextExercise exercise, User user) { + var submission = textSubmissionService.handleTextSubmission(textSubmission, exercise, user); + textSubmissionService.hideDetails(submission, user); + return submission; + } + private void checkGivenExerciseIdSameForSubmissionParticipation(long originalExerciseId, long exerciseIdInSubmission) { if (!Objects.equals(originalExerciseId, exerciseIdInSubmission)) { throw new IllegalArgumentException("ExerciseId does not match with the exerciseId in submission participation"); From b231a7304fd22388862d72b139ab4168eeea7392 Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Tue, 17 Dec 2024 15:32:00 +0100 Subject: [PATCH 10/22] change ExampleSubmissionService --- .../service/ExampleSubmissionService.java | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/main/java/de/tum/cit/aet/artemis/assessment/service/ExampleSubmissionService.java b/src/main/java/de/tum/cit/aet/artemis/assessment/service/ExampleSubmissionService.java index 154271e43b24..1df5ca27c81e 100644 --- a/src/main/java/de/tum/cit/aet/artemis/assessment/service/ExampleSubmissionService.java +++ b/src/main/java/de/tum/cit/aet/artemis/assessment/service/ExampleSubmissionService.java @@ -24,11 +24,9 @@ import de.tum.cit.aet.artemis.modeling.domain.ModelingExercise; import de.tum.cit.aet.artemis.modeling.domain.ModelingSubmission; import de.tum.cit.aet.artemis.modeling.service.ModelingExerciseImportService; -import de.tum.cit.aet.artemis.text.api.TextExerciseSubmissionApi; +import de.tum.cit.aet.artemis.text.api.TextSubmissionApi; import de.tum.cit.aet.artemis.text.domain.TextExercise; import de.tum.cit.aet.artemis.text.domain.TextSubmission; -import de.tum.cit.aet.artemis.text.repository.TextSubmissionRepository; -import de.tum.cit.aet.artemis.text.service.TextExerciseImportService; @Profile(PROFILE_CORE) @Service @@ -42,29 +40,22 @@ public class ExampleSubmissionService { private final ExerciseRepository exerciseRepository; - private final TextExerciseImportService textExerciseImportService; - private final ModelingExerciseImportService modelingExerciseImportService; - private final Optional textExerciseSubmissionApi; - - private final TextSubmissionRepository textSubmissionRepository; + private final Optional textSubmissionApi; private final GradingCriterionRepository gradingCriterionRepository; private final TutorParticipationRepository tutorParticipationRepository; public ExampleSubmissionService(ExampleSubmissionRepository exampleSubmissionRepository, SubmissionRepository submissionRepository, ExerciseRepository exerciseRepository, - TextExerciseImportService textExerciseImportService, ModelingExerciseImportService modelingExerciseImportService, - Optional textExerciseSubmissionApi, TextSubmissionRepository textSubmissionRepository, GradingCriterionRepository gradingCriterionRepository, + ModelingExerciseImportService modelingExerciseImportService, Optional textSubmissionApi, GradingCriterionRepository gradingCriterionRepository, TutorParticipationRepository tutorParticipationRepository) { this.exampleSubmissionRepository = exampleSubmissionRepository; this.submissionRepository = submissionRepository; this.exerciseRepository = exerciseRepository; this.modelingExerciseImportService = modelingExerciseImportService; - this.textExerciseImportService = textExerciseImportService; - this.textExerciseSubmissionApi = textExerciseSubmissionApi; - this.textSubmissionRepository = textSubmissionRepository; + this.textSubmissionApi = textSubmissionApi; this.gradingCriterionRepository = gradingCriterionRepository; this.tutorParticipationRepository = tutorParticipationRepository; } @@ -142,7 +133,7 @@ public ExampleSubmission importStudentSubmissionAsExampleSubmission(Long submiss newExampleSubmission.setSubmission(modelingExerciseImportService.copySubmission(modelingSubmission, gradingInstructionCopyTracker)); } if (exercise instanceof TextExercise) { - var api = textExerciseSubmissionApi.orElseThrow(() -> new ApiNotPresentException(TextExerciseSubmissionApi.class, PROFILE_CORE)); + var api = textSubmissionApi.orElseThrow(() -> new ApiNotPresentException(TextSubmissionApi.class, PROFILE_CORE)); TextSubmission textSubmission = api.importStudentSubmission(submissionId, exercise.getId(), gradingInstructionCopyTracker); newExampleSubmission.setSubmission(textSubmission); } From 2c872908f981a7cb648f0ef302468d029d659854 Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Tue, 17 Dec 2024 15:37:35 +0100 Subject: [PATCH 11/22] replace with api in AthenaDTOConverterService --- .../service/AthenaDTOConverterService.java | 24 +++++++------- .../tum/cit/aet/artemis/text/api/TextApi.java | 33 +++++++++++++++++++ 2 files changed, 45 insertions(+), 12 deletions(-) create mode 100644 src/main/java/de/tum/cit/aet/artemis/text/api/TextApi.java diff --git a/src/main/java/de/tum/cit/aet/artemis/athena/service/AthenaDTOConverterService.java b/src/main/java/de/tum/cit/aet/artemis/athena/service/AthenaDTOConverterService.java index dcd463f65ed1..22585484e8c2 100644 --- a/src/main/java/de/tum/cit/aet/artemis/athena/service/AthenaDTOConverterService.java +++ b/src/main/java/de/tum/cit/aet/artemis/athena/service/AthenaDTOConverterService.java @@ -1,6 +1,9 @@ package de.tum.cit.aet.artemis.athena.service; import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_ATHENA; +import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_CORE; + +import java.util.Optional; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Profile; @@ -8,7 +11,6 @@ import de.tum.cit.aet.artemis.assessment.domain.Feedback; import de.tum.cit.aet.artemis.assessment.repository.GradingCriterionRepository; -import de.tum.cit.aet.artemis.assessment.repository.TextBlockRepository; import de.tum.cit.aet.artemis.athena.dto.ExerciseBaseDTO; import de.tum.cit.aet.artemis.athena.dto.FeedbackBaseDTO; import de.tum.cit.aet.artemis.athena.dto.ModelingExerciseDTO; @@ -21,15 +23,16 @@ import de.tum.cit.aet.artemis.athena.dto.TextExerciseDTO; import de.tum.cit.aet.artemis.athena.dto.TextFeedbackDTO; import de.tum.cit.aet.artemis.athena.dto.TextSubmissionDTO; +import de.tum.cit.aet.artemis.core.exception.ApiNotPresentException; import de.tum.cit.aet.artemis.exercise.domain.Exercise; import de.tum.cit.aet.artemis.exercise.domain.Submission; import de.tum.cit.aet.artemis.modeling.domain.ModelingExercise; import de.tum.cit.aet.artemis.modeling.domain.ModelingSubmission; import de.tum.cit.aet.artemis.programming.domain.ProgrammingSubmission; import de.tum.cit.aet.artemis.programming.repository.ProgrammingExerciseRepository; +import de.tum.cit.aet.artemis.text.api.TextApi; import de.tum.cit.aet.artemis.text.domain.TextBlock; import de.tum.cit.aet.artemis.text.domain.TextSubmission; -import de.tum.cit.aet.artemis.text.repository.TextExerciseRepository; /** * Service to convert exercises, submissions and feedback to DTOs for Athena. @@ -41,18 +44,15 @@ public class AthenaDTOConverterService { @Value("${server.url}") private String artemisServerUrl; - private final TextBlockRepository textBlockRepository; - - private final TextExerciseRepository textExerciseRepository; + private final Optional textApi; private final ProgrammingExerciseRepository programmingExerciseRepository; private final GradingCriterionRepository gradingCriterionRepository; - public AthenaDTOConverterService(TextBlockRepository textBlockRepository, TextExerciseRepository textExerciseRepository, - ProgrammingExerciseRepository programmingExerciseRepository, GradingCriterionRepository gradingCriterionRepository) { - this.textBlockRepository = textBlockRepository; - this.textExerciseRepository = textExerciseRepository; + public AthenaDTOConverterService(Optional textApi, ProgrammingExerciseRepository programmingExerciseRepository, + GradingCriterionRepository gradingCriterionRepository) { + this.textApi = textApi; this.programmingExerciseRepository = programmingExerciseRepository; this.gradingCriterionRepository = gradingCriterionRepository; } @@ -67,7 +67,7 @@ public ExerciseBaseDTO ofExercise(Exercise exercise) { switch (exercise.getExerciseType()) { case TEXT -> { // Fetch text exercise with grade criteria - var textExercise = textExerciseRepository.findWithGradingCriteriaByIdElseThrow(exercise.getId()); + var textExercise = textApi.orElseThrow(() -> new ApiNotPresentException(TextApi.class, PROFILE_CORE)).findWithGradingCriteriaByIdElseThrow(exercise.getId()); return TextExerciseDTO.of(textExercise); } case PROGRAMMING -> { @@ -117,8 +117,8 @@ public FeedbackBaseDTO ofFeedback(Exercise exercise, long submissionId, Feedback switch (exercise.getExerciseType()) { case TEXT -> { TextBlock feedbackTextBlock = null; - if (feedback.getReference() != null) { - feedbackTextBlock = textBlockRepository.findById(feedback.getReference()).orElse(null); + if (feedback.getReference() != null && textApi.isPresent()) { + feedbackTextBlock = textApi.get().findById(feedback.getReference()); } return TextFeedbackDTO.of(exercise.getId(), submissionId, feedback, feedbackTextBlock); } diff --git a/src/main/java/de/tum/cit/aet/artemis/text/api/TextApi.java b/src/main/java/de/tum/cit/aet/artemis/text/api/TextApi.java new file mode 100644 index 000000000000..16e559931da6 --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/text/api/TextApi.java @@ -0,0 +1,33 @@ +package de.tum.cit.aet.artemis.text.api; + +import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_CORE; + +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Controller; + +import de.tum.cit.aet.artemis.assessment.repository.TextBlockRepository; +import de.tum.cit.aet.artemis.text.domain.TextBlock; +import de.tum.cit.aet.artemis.text.domain.TextExercise; +import de.tum.cit.aet.artemis.text.repository.TextExerciseRepository; + +@Controller +@Profile(PROFILE_CORE) +public class TextApi extends AbstractTextApi { + + private final TextExerciseRepository textExerciseRepository; + + private final TextBlockRepository textBlockRepository; + + public TextApi(TextExerciseRepository textExerciseRepository, TextBlockRepository textBlockRepository) { + this.textExerciseRepository = textExerciseRepository; + this.textBlockRepository = textBlockRepository; + } + + public TextExercise findWithGradingCriteriaByIdElseThrow(long exerciseId) { + return textExerciseRepository.findWithGradingCriteriaByIdElseThrow(exerciseId); + } + + public TextBlock findById(String reference) { + return textBlockRepository.findById(reference).orElse(null); + } +} From c57172c85426badc082984258bce2f2ea1eaa440 Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Tue, 17 Dec 2024 15:39:32 +0100 Subject: [PATCH 12/22] fix related test --- .../connectors/AthenaFeedbackSendingServiceTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/java/de/tum/cit/aet/artemis/athena/service/connectors/AthenaFeedbackSendingServiceTest.java b/src/test/java/de/tum/cit/aet/artemis/athena/service/connectors/AthenaFeedbackSendingServiceTest.java index eae7d0041044..2a85649e5fa9 100644 --- a/src/test/java/de/tum/cit/aet/artemis/athena/service/connectors/AthenaFeedbackSendingServiceTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/athena/service/connectors/AthenaFeedbackSendingServiceTest.java @@ -21,7 +21,6 @@ import de.tum.cit.aet.artemis.assessment.domain.GradingInstruction; import de.tum.cit.aet.artemis.assessment.domain.Result; import de.tum.cit.aet.artemis.assessment.repository.GradingCriterionRepository; -import de.tum.cit.aet.artemis.assessment.repository.TextBlockRepository; import de.tum.cit.aet.artemis.assessment.util.GradingCriterionUtil; import de.tum.cit.aet.artemis.athena.AbstractAthenaTest; import de.tum.cit.aet.artemis.athena.service.AthenaDTOConverterService; @@ -34,6 +33,7 @@ import de.tum.cit.aet.artemis.programming.domain.ProgrammingSubmission; import de.tum.cit.aet.artemis.programming.test_repository.ProgrammingExerciseTestRepository; import de.tum.cit.aet.artemis.programming.util.ProgrammingExerciseUtilService; +import de.tum.cit.aet.artemis.text.api.TextApi; import de.tum.cit.aet.artemis.text.domain.TextBlock; import de.tum.cit.aet.artemis.text.domain.TextExercise; import de.tum.cit.aet.artemis.text.domain.TextSubmission; @@ -46,10 +46,10 @@ class AthenaFeedbackSendingServiceTest extends AbstractAthenaTest { private AthenaModuleService athenaModuleService; @Mock - private TextBlockRepository textBlockRepository; + private TextExerciseRepository textExerciseRepository; @Mock - private TextExerciseRepository textExerciseRepository; + private TextApi textApi; @Mock private ProgrammingExerciseTestRepository programmingExerciseRepository; @@ -82,19 +82,19 @@ class AthenaFeedbackSendingServiceTest extends AbstractAthenaTest { @BeforeEach void setUp() { athenaFeedbackSendingService = new AthenaFeedbackSendingService(athenaRequestMockProvider.getRestTemplate(), athenaModuleService, - new AthenaDTOConverterService(textBlockRepository, textExerciseRepository, programmingExerciseRepository, gradingCriterionRepository)); + new AthenaDTOConverterService(Optional.of(textApi), programmingExerciseRepository, gradingCriterionRepository)); athenaRequestMockProvider.enableMockingOfRequests(); textExercise = textExerciseUtilService.createSampleTextExercise(null); textExercise.setFeedbackSuggestionModule(ATHENA_MODULE_TEXT_TEST); - when(textExerciseRepository.findWithGradingCriteriaByIdElseThrow(textExercise.getId())).thenReturn(textExercise); + when(textApi.findWithGradingCriteriaByIdElseThrow(textExercise.getId())).thenReturn(textExercise); textSubmission = new TextSubmission(2L).text("Test - This is what the feedback references - Submission"); textBlock = new TextBlock().startIndex(7).endIndex(46).text("This is what the feedback references").submission(textSubmission); textBlock.computeId(); - when(textBlockRepository.findById(textBlock.getId())).thenReturn(Optional.of(textBlock)); + when(textApi.findById(textBlock.getId())).thenReturn(Optional.of(textBlock)); textFeedback = new Feedback().type(FeedbackType.MANUAL).credits(5.0).reference(textBlock.getId()); textFeedback.setText("Title"); From fa062f231bfb687a83136d2d2d591d298ccd0d6a Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Tue, 17 Dec 2024 15:40:13 +0100 Subject: [PATCH 13/22] make TextApi#findById return an optional --- .../artemis/athena/service/AthenaDTOConverterService.java | 2 +- src/main/java/de/tum/cit/aet/artemis/text/api/TextApi.java | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/tum/cit/aet/artemis/athena/service/AthenaDTOConverterService.java b/src/main/java/de/tum/cit/aet/artemis/athena/service/AthenaDTOConverterService.java index 22585484e8c2..8b4c2a477895 100644 --- a/src/main/java/de/tum/cit/aet/artemis/athena/service/AthenaDTOConverterService.java +++ b/src/main/java/de/tum/cit/aet/artemis/athena/service/AthenaDTOConverterService.java @@ -118,7 +118,7 @@ public FeedbackBaseDTO ofFeedback(Exercise exercise, long submissionId, Feedback case TEXT -> { TextBlock feedbackTextBlock = null; if (feedback.getReference() != null && textApi.isPresent()) { - feedbackTextBlock = textApi.get().findById(feedback.getReference()); + feedbackTextBlock = textApi.get().findById(feedback.getReference()).orElse(null); } return TextFeedbackDTO.of(exercise.getId(), submissionId, feedback, feedbackTextBlock); } diff --git a/src/main/java/de/tum/cit/aet/artemis/text/api/TextApi.java b/src/main/java/de/tum/cit/aet/artemis/text/api/TextApi.java index 16e559931da6..44d3bd9a8753 100644 --- a/src/main/java/de/tum/cit/aet/artemis/text/api/TextApi.java +++ b/src/main/java/de/tum/cit/aet/artemis/text/api/TextApi.java @@ -2,6 +2,8 @@ import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_CORE; +import java.util.Optional; + import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Controller; @@ -27,7 +29,7 @@ public TextExercise findWithGradingCriteriaByIdElseThrow(long exerciseId) { return textExerciseRepository.findWithGradingCriteriaByIdElseThrow(exerciseId); } - public TextBlock findById(String reference) { - return textBlockRepository.findById(reference).orElse(null); + public Optional findById(String reference) { + return textBlockRepository.findById(reference); } } From a52fde48efe47f84a25c4f8c90878039e077b74e Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Tue, 17 Dec 2024 15:42:47 +0100 Subject: [PATCH 14/22] move import functionality to TextSubmissionImportApi --- .../service/ExampleSubmissionService.java | 11 ++--- .../artemis/text/api/TextSubmissionApi.java | 25 +---------- .../text/api/TextSubmissionImportApi.java | 43 +++++++++++++++++++ 3 files changed, 50 insertions(+), 29 deletions(-) create mode 100644 src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionImportApi.java diff --git a/src/main/java/de/tum/cit/aet/artemis/assessment/service/ExampleSubmissionService.java b/src/main/java/de/tum/cit/aet/artemis/assessment/service/ExampleSubmissionService.java index 1df5ca27c81e..e08ef6cd865a 100644 --- a/src/main/java/de/tum/cit/aet/artemis/assessment/service/ExampleSubmissionService.java +++ b/src/main/java/de/tum/cit/aet/artemis/assessment/service/ExampleSubmissionService.java @@ -25,6 +25,7 @@ import de.tum.cit.aet.artemis.modeling.domain.ModelingSubmission; import de.tum.cit.aet.artemis.modeling.service.ModelingExerciseImportService; import de.tum.cit.aet.artemis.text.api.TextSubmissionApi; +import de.tum.cit.aet.artemis.text.api.TextSubmissionImportApi; import de.tum.cit.aet.artemis.text.domain.TextExercise; import de.tum.cit.aet.artemis.text.domain.TextSubmission; @@ -42,20 +43,20 @@ public class ExampleSubmissionService { private final ModelingExerciseImportService modelingExerciseImportService; - private final Optional textSubmissionApi; + private final Optional textSubmissionImportApi; private final GradingCriterionRepository gradingCriterionRepository; private final TutorParticipationRepository tutorParticipationRepository; public ExampleSubmissionService(ExampleSubmissionRepository exampleSubmissionRepository, SubmissionRepository submissionRepository, ExerciseRepository exerciseRepository, - ModelingExerciseImportService modelingExerciseImportService, Optional textSubmissionApi, GradingCriterionRepository gradingCriterionRepository, - TutorParticipationRepository tutorParticipationRepository) { + ModelingExerciseImportService modelingExerciseImportService, Optional textSubmissionImportApi, + GradingCriterionRepository gradingCriterionRepository, TutorParticipationRepository tutorParticipationRepository) { this.exampleSubmissionRepository = exampleSubmissionRepository; this.submissionRepository = submissionRepository; this.exerciseRepository = exerciseRepository; this.modelingExerciseImportService = modelingExerciseImportService; - this.textSubmissionApi = textSubmissionApi; + this.textSubmissionImportApi = textSubmissionImportApi; this.gradingCriterionRepository = gradingCriterionRepository; this.tutorParticipationRepository = tutorParticipationRepository; } @@ -133,7 +134,7 @@ public ExampleSubmission importStudentSubmissionAsExampleSubmission(Long submiss newExampleSubmission.setSubmission(modelingExerciseImportService.copySubmission(modelingSubmission, gradingInstructionCopyTracker)); } if (exercise instanceof TextExercise) { - var api = textSubmissionApi.orElseThrow(() -> new ApiNotPresentException(TextSubmissionApi.class, PROFILE_CORE)); + var api = textSubmissionImportApi.orElseThrow(() -> new ApiNotPresentException(TextSubmissionApi.class, PROFILE_CORE)); TextSubmission textSubmission = api.importStudentSubmission(submissionId, exercise.getId(), gradingInstructionCopyTracker); newExampleSubmission.setSubmission(textSubmission); } diff --git a/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionApi.java b/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionApi.java index 1ed033f9bfed..3879d412fc18 100644 --- a/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionApi.java +++ b/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionApi.java @@ -2,18 +2,13 @@ import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_CORE; -import java.util.Map; -import java.util.Objects; - import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Controller; -import de.tum.cit.aet.artemis.assessment.domain.GradingInstruction; import de.tum.cit.aet.artemis.core.domain.User; import de.tum.cit.aet.artemis.text.domain.TextExercise; import de.tum.cit.aet.artemis.text.domain.TextSubmission; import de.tum.cit.aet.artemis.text.repository.TextSubmissionRepository; -import de.tum.cit.aet.artemis.text.service.TextExerciseImportService; import de.tum.cit.aet.artemis.text.service.TextSubmissionService; @Controller @@ -22,25 +17,13 @@ public class TextSubmissionApi extends AbstractTextApi { private final TextSubmissionRepository textSubmissionRepository; - private final TextExerciseImportService textExerciseImportService; - private final TextSubmissionService textSubmissionService; - public TextSubmissionApi(TextSubmissionRepository textSubmissionRepository, TextExerciseImportService textExerciseImportService, TextSubmissionService textSubmissionService) { + public TextSubmissionApi(TextSubmissionRepository textSubmissionRepository, TextSubmissionService textSubmissionService) { this.textSubmissionRepository = textSubmissionRepository; - this.textExerciseImportService = textExerciseImportService; this.textSubmissionService = textSubmissionService; } - public TextSubmission importStudentSubmission(long submissionId, long exerciseId, Map gradingInstructionCopyTracker) { - TextSubmission textSubmission = textSubmissionRepository.findByIdWithEagerResultsAndFeedbackAndTextBlocksElseThrow(submissionId); - checkGivenExerciseIdSameForSubmissionParticipation(exerciseId, textSubmission.getParticipation().getExercise().getId()); - - // example submission does not need participation - textSubmission.setParticipation(null); - return textExerciseImportService.copySubmission(textSubmission, gradingInstructionCopyTracker); - } - public TextSubmission saveTextSubmission(TextSubmission textSubmission) { return textSubmissionRepository.save(textSubmission); } @@ -50,10 +33,4 @@ public TextSubmission handleTextSubmission(TextSubmission textSubmission, TextEx textSubmissionService.hideDetails(submission, user); return submission; } - - private void checkGivenExerciseIdSameForSubmissionParticipation(long originalExerciseId, long exerciseIdInSubmission) { - if (!Objects.equals(originalExerciseId, exerciseIdInSubmission)) { - throw new IllegalArgumentException("ExerciseId does not match with the exerciseId in submission participation"); - } - } } diff --git a/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionImportApi.java b/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionImportApi.java new file mode 100644 index 000000000000..22b26ee5c6d6 --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionImportApi.java @@ -0,0 +1,43 @@ +package de.tum.cit.aet.artemis.text.api; + +import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_CORE; + +import java.util.Map; +import java.util.Objects; + +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Controller; + +import de.tum.cit.aet.artemis.assessment.domain.GradingInstruction; +import de.tum.cit.aet.artemis.text.domain.TextSubmission; +import de.tum.cit.aet.artemis.text.repository.TextSubmissionRepository; +import de.tum.cit.aet.artemis.text.service.TextExerciseImportService; + +@Controller +@Profile(PROFILE_CORE) +public class TextSubmissionImportApi extends AbstractTextApi { + + private final TextSubmissionRepository textSubmissionRepository; + + private final TextExerciseImportService textExerciseImportService; + + public TextSubmissionImportApi(TextSubmissionRepository textSubmissionRepository, TextExerciseImportService textExerciseImportService) { + this.textSubmissionRepository = textSubmissionRepository; + this.textExerciseImportService = textExerciseImportService; + } + + public TextSubmission importStudentSubmission(long submissionId, long exerciseId, Map gradingInstructionCopyTracker) { + TextSubmission textSubmission = textSubmissionRepository.findByIdWithEagerResultsAndFeedbackAndTextBlocksElseThrow(submissionId); + checkGivenExerciseIdSameForSubmissionParticipation(exerciseId, textSubmission.getParticipation().getExercise().getId()); + + // example submission does not need participation + textSubmission.setParticipation(null); + return textExerciseImportService.copySubmission(textSubmission, gradingInstructionCopyTracker); + } + + private void checkGivenExerciseIdSameForSubmissionParticipation(long originalExerciseId, long exerciseIdInSubmission) { + if (!Objects.equals(originalExerciseId, exerciseIdInSubmission)) { + throw new IllegalArgumentException("ExerciseId does not match with the exerciseId in submission participation"); + } + } +} From 84780b63876a3afe861114447779601c53c171dd Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Tue, 17 Dec 2024 15:48:53 +0100 Subject: [PATCH 15/22] replace with api in ExampleSubmissionResource --- .../web/ExampleSubmissionResource.java | 26 +++++++------------ .../text/api/TextSubmissionExportApi.java | 26 ++++++++++++++++++- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/main/java/de/tum/cit/aet/artemis/assessment/web/ExampleSubmissionResource.java b/src/main/java/de/tum/cit/aet/artemis/assessment/web/ExampleSubmissionResource.java index 358d50b21c24..ad2d483a9fdc 100644 --- a/src/main/java/de/tum/cit/aet/artemis/assessment/web/ExampleSubmissionResource.java +++ b/src/main/java/de/tum/cit/aet/artemis/assessment/web/ExampleSubmissionResource.java @@ -24,6 +24,7 @@ import de.tum.cit.aet.artemis.assessment.domain.ExampleSubmission; import de.tum.cit.aet.artemis.assessment.repository.ExampleSubmissionRepository; import de.tum.cit.aet.artemis.assessment.service.ExampleSubmissionService; +import de.tum.cit.aet.artemis.core.exception.ApiNotPresentException; import de.tum.cit.aet.artemis.core.exception.BadRequestAlertException; import de.tum.cit.aet.artemis.core.exception.EntityNotFoundException; import de.tum.cit.aet.artemis.core.security.Role; @@ -35,10 +36,9 @@ import de.tum.cit.aet.artemis.exercise.domain.Exercise; import de.tum.cit.aet.artemis.exercise.domain.ExerciseType; import de.tum.cit.aet.artemis.exercise.repository.ExerciseRepository; +import de.tum.cit.aet.artemis.text.api.TextSubmissionExportApi; import de.tum.cit.aet.artemis.text.domain.TextExercise; import de.tum.cit.aet.artemis.text.domain.TextSubmission; -import de.tum.cit.aet.artemis.text.repository.TextSubmissionRepository; -import de.tum.cit.aet.artemis.text.service.TextBlockService; /** * REST controller for managing ExampleSubmission. @@ -63,19 +63,15 @@ public class ExampleSubmissionResource { private final ExerciseRepository exerciseRepository; - private final TextSubmissionRepository textSubmissionRepository; - - private final TextBlockService textBlockService; + private final Optional textSubmissionExportApi; public ExampleSubmissionResource(ExampleSubmissionService exampleSubmissionService, ExampleSubmissionRepository exampleSubmissionRepository, - AuthorizationCheckService authCheckService, ExerciseRepository exerciseRepository, TextSubmissionRepository textSubmissionRepository, - TextBlockService textBlockService) { + AuthorizationCheckService authCheckService, ExerciseRepository exerciseRepository, Optional textSubmissionExportApi) { this.exampleSubmissionService = exampleSubmissionService; this.exampleSubmissionRepository = exampleSubmissionRepository; this.authCheckService = authCheckService; this.exerciseRepository = exerciseRepository; - this.textSubmissionRepository = textSubmissionRepository; - this.textBlockService = textBlockService; + this.textSubmissionExportApi = textSubmissionExportApi; } /** @@ -135,13 +131,8 @@ public ResponseEntity prepareExampleAssessment(@PathVariable Long exercise // Prepare text blocks for fresh assessment if (exampleSubmission.getExercise().getExerciseType() == ExerciseType.TEXT && exampleSubmission.getSubmission() != null) { - Optional textSubmission = textSubmissionRepository.findWithEagerResultsAndFeedbackAndTextBlocksById(exampleSubmission.getSubmission().getId()); - if (textSubmission.isPresent() && textSubmission.get().getLatestResult() == null - && (textSubmission.get().getBlocks() == null || textSubmission.get().getBlocks().isEmpty())) { - TextSubmission submission = textSubmission.get(); - textBlockService.computeTextBlocksForSubmissionBasedOnSyntax(submission); - textBlockService.saveAll(submission.getBlocks()); - } + textSubmissionExportApi.orElseThrow(() -> new ApiNotPresentException(TextSubmissionExportApi.class, PROFILE_CORE)) + .prepareTextBlockForExampleSubmission(exampleSubmission.getSubmission().getId()); } return ResponseEntity.ok(null); @@ -172,7 +163,8 @@ public ResponseEntity getExampleSubmission(@PathVariable Long // For TextExercise, we need to load the text blocks as well if (exampleSubmission.getExercise().getExerciseType() == ExerciseType.TEXT && exampleSubmission.getSubmission() != null) { - Optional textSubmission = textSubmissionRepository.findWithEagerResultsAndFeedbackAndTextBlocksById(exampleSubmission.getSubmission().getId()); + Optional textSubmission = textSubmissionExportApi.orElseThrow(() -> new ApiNotPresentException(TextSubmissionExportApi.class, PROFILE_CORE)) + .getSubmissionForExampleSubmission(exampleSubmission.getSubmission().getId()); textSubmission.ifPresent(exampleSubmission::setSubmission); } diff --git a/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionExportApi.java b/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionExportApi.java index 48ae66398e68..f107592666e5 100644 --- a/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionExportApi.java +++ b/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionExportApi.java @@ -5,6 +5,7 @@ import java.io.IOException; import java.nio.file.Path; import java.util.List; +import java.util.Optional; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Controller; @@ -13,6 +14,8 @@ import de.tum.cit.aet.artemis.exercise.dto.SubmissionExportOptionsDTO; import de.tum.cit.aet.artemis.text.domain.TextExercise; import de.tum.cit.aet.artemis.text.domain.TextSubmission; +import de.tum.cit.aet.artemis.text.repository.TextSubmissionRepository; +import de.tum.cit.aet.artemis.text.service.TextBlockService; import de.tum.cit.aet.artemis.text.service.TextExerciseWithSubmissionsExportService; import de.tum.cit.aet.artemis.text.service.TextSubmissionExportService; @@ -24,9 +27,16 @@ public class TextSubmissionExportApi extends AbstractTextApi { private final TextExerciseWithSubmissionsExportService textExerciseWithSubmissionsExportService; - public TextSubmissionExportApi(TextSubmissionExportService textSubmissionExportService, TextExerciseWithSubmissionsExportService textExerciseWithSubmissionsExportService) { + private final TextSubmissionRepository textSubmissionRepository; + + private final TextBlockService textBlockService; + + public TextSubmissionExportApi(TextSubmissionExportService textSubmissionExportService, TextExerciseWithSubmissionsExportService textExerciseWithSubmissionsExportService, + TextSubmissionRepository textSubmissionRepository, TextBlockService textBlockService) { this.textSubmissionExportService = textSubmissionExportService; this.textExerciseWithSubmissionsExportService = textExerciseWithSubmissionsExportService; + this.textSubmissionRepository = textSubmissionRepository; + this.textBlockService = textBlockService; } public void saveSubmissionToFile(TextSubmission submission, String studentLogin, String submissionsFolderName) throws IOException { @@ -37,4 +47,18 @@ public Path exportTextExerciseWithSubmissions(TextExercise exercise, SubmissionE List reportEntries) { return textExerciseWithSubmissionsExportService.exportTextExerciseWithSubmissions(exercise, optionsDTO, exportDir, exportErrors, reportEntries); } + + public void prepareTextBlockForExampleSubmission(long exampleSubmissionId) { + Optional textSubmission = textSubmissionRepository.findWithEagerResultsAndFeedbackAndTextBlocksById(exampleSubmissionId); + if (textSubmission.isPresent() && textSubmission.get().getLatestResult() == null + && (textSubmission.get().getBlocks() == null || textSubmission.get().getBlocks().isEmpty())) { + TextSubmission submission = textSubmission.get(); + textBlockService.computeTextBlocksForSubmissionBasedOnSyntax(submission); + textBlockService.saveAll(submission.getBlocks()); + } + } + + public Optional getSubmissionForExampleSubmission(long exampleSubmissionId) { + return textSubmissionRepository.findWithEagerResultsAndFeedbackAndTextBlocksById(exampleSubmissionId); + } } From fdb396ca943a9c21a1cc94df942b1dead27303ed Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Tue, 17 Dec 2024 15:54:36 +0100 Subject: [PATCH 16/22] replace with api for iris module --- .../IrisTextExerciseChatSessionService.java | 13 ++++++++----- .../service/settings/IrisSettingsService.java | 13 +++++++------ .../IrisTextExerciseChatSessionResource.java | 18 +++++++++++------- .../tum/cit/aet/artemis/text/api/TextApi.java | 9 +++++++++ 4 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/main/java/de/tum/cit/aet/artemis/iris/service/session/IrisTextExerciseChatSessionService.java b/src/main/java/de/tum/cit/aet/artemis/iris/service/session/IrisTextExerciseChatSessionService.java index 2c2875295cf8..8cd8f8bb6146 100644 --- a/src/main/java/de/tum/cit/aet/artemis/iris/service/session/IrisTextExerciseChatSessionService.java +++ b/src/main/java/de/tum/cit/aet/artemis/iris/service/session/IrisTextExerciseChatSessionService.java @@ -1,5 +1,7 @@ package de.tum.cit.aet.artemis.iris.service.session; +import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_CORE; + import java.util.Comparator; import java.util.Optional; @@ -8,6 +10,7 @@ import de.tum.cit.aet.artemis.core.domain.User; import de.tum.cit.aet.artemis.core.exception.AccessForbiddenException; +import de.tum.cit.aet.artemis.core.exception.ApiNotPresentException; import de.tum.cit.aet.artemis.core.exception.ConflictException; import de.tum.cit.aet.artemis.core.security.Role; import de.tum.cit.aet.artemis.core.service.AuthorizationCheckService; @@ -30,8 +33,8 @@ import de.tum.cit.aet.artemis.iris.service.pyris.job.TextExerciseChatJob; 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.text.api.TextApi; import de.tum.cit.aet.artemis.text.domain.TextSubmission; -import de.tum.cit.aet.artemis.text.repository.TextExerciseRepository; @Service @Profile("iris") @@ -45,7 +48,7 @@ public class IrisTextExerciseChatSessionService implements IrisChatBasedFeatureI private final IrisMessageService irisMessageService; - private final TextExerciseRepository textExerciseRepository; + private final Optional textApi; private final StudentParticipationRepository studentParticipationRepository; @@ -58,14 +61,14 @@ public class IrisTextExerciseChatSessionService implements IrisChatBasedFeatureI private final AuthorizationCheckService authCheckService; public IrisTextExerciseChatSessionService(IrisSettingsService irisSettingsService, IrisSessionRepository irisSessionRepository, IrisRateLimitService rateLimitService, - IrisMessageService irisMessageService, TextExerciseRepository textExerciseRepository, StudentParticipationRepository studentParticipationRepository, + IrisMessageService irisMessageService, Optional textApi, StudentParticipationRepository studentParticipationRepository, PyrisPipelineService pyrisPipelineService, PyrisJobService pyrisJobService, IrisChatWebsocketService irisChatWebsocketService, AuthorizationCheckService authCheckService) { this.irisSettingsService = irisSettingsService; this.irisSessionRepository = irisSessionRepository; this.rateLimitService = rateLimitService; this.irisMessageService = irisMessageService; - this.textExerciseRepository = textExerciseRepository; + this.textApi = textApi; this.studentParticipationRepository = studentParticipationRepository; this.pyrisPipelineService = pyrisPipelineService; this.pyrisJobService = pyrisJobService; @@ -84,7 +87,7 @@ public void requestAndHandleResponse(IrisTextExerciseChatSession irisSession) { if (session.getExercise().isExamExercise()) { throw new ConflictException("Iris is not supported for exam exercises", "Iris", "irisExamExercise"); } - var exercise = textExerciseRepository.findByIdElseThrow(session.getExercise().getId()); + var exercise = textApi.orElseThrow(() -> new ApiNotPresentException(TextApi.class, PROFILE_CORE)).findByIdElseThrow(session.getExercise().getId()); if (!irisSettingsService.isEnabledFor(IrisSubSettingsType.TEXT_EXERCISE_CHAT, exercise)) { throw new ConflictException("Iris is not enabled for this exercise", "Iris", "irisDisabled"); } diff --git a/src/main/java/de/tum/cit/aet/artemis/iris/service/settings/IrisSettingsService.java b/src/main/java/de/tum/cit/aet/artemis/iris/service/settings/IrisSettingsService.java index 8ed823adee2c..b2ae41a2993b 100644 --- a/src/main/java/de/tum/cit/aet/artemis/iris/service/settings/IrisSettingsService.java +++ b/src/main/java/de/tum/cit/aet/artemis/iris/service/settings/IrisSettingsService.java @@ -10,6 +10,7 @@ import java.util.Comparator; import java.util.HashSet; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; @@ -46,8 +47,8 @@ import de.tum.cit.aet.artemis.iris.repository.IrisSettingsRepository; import de.tum.cit.aet.artemis.programming.domain.ProgrammingExercise; import de.tum.cit.aet.artemis.programming.repository.ProgrammingExerciseRepository; +import de.tum.cit.aet.artemis.text.api.TextApi; import de.tum.cit.aet.artemis.text.domain.TextExercise; -import de.tum.cit.aet.artemis.text.repository.TextExerciseRepository; /** * Service for managing {@link IrisSettings}. @@ -70,16 +71,16 @@ public class IrisSettingsService { private final ObjectMapper objectMapper; - private final TextExerciseRepository textExerciseRepository; + private final Optional textApi; public IrisSettingsService(IrisSettingsRepository irisSettingsRepository, IrisSubSettingsService irisSubSettingsService, AuthorizationCheckService authCheckService, - ProgrammingExerciseRepository programmingExerciseRepository, ObjectMapper objectMapper, TextExerciseRepository textExerciseRepository) { + ProgrammingExerciseRepository programmingExerciseRepository, ObjectMapper objectMapper, Optional textApi) { this.irisSettingsRepository = irisSettingsRepository; this.irisSubSettingsService = irisSubSettingsService; this.authCheckService = authCheckService; this.programmingExerciseRepository = programmingExerciseRepository; this.objectMapper = objectMapper; - this.textExerciseRepository = textExerciseRepository; + this.textApi = textApi; } /** @@ -329,8 +330,8 @@ private IrisCourseSettings updateCourseSettings(IrisCourseSettings existingSetti var newEnabledForCategoriesTextExerciseChat = existingSettings.getIrisTextExerciseChatSettings() == null ? new TreeSet() : existingSettings.getIrisTextExerciseChatSettings().getEnabledForCategories(); if (!Objects.equals(oldEnabledForCategoriesTextExerciseChat, newEnabledForCategoriesTextExerciseChat)) { - textExerciseRepository.findAllWithCategoriesByCourseId(existingSettings.getCourse().getId()) - .forEach(exercise -> setEnabledForExerciseByCategories(exercise, oldEnabledForCategoriesTextExerciseChat, newEnabledForCategoriesTextExerciseChat)); + textApi.ifPresent(api -> api.findAllWithCategoriesByCourseId(existingSettings.getCourse().getId()) + .forEach(exercise -> setEnabledForExerciseByCategories(exercise, oldEnabledForCategoriesTextExerciseChat, newEnabledForCategoriesTextExerciseChat))); } return irisSettingsRepository.save(existingSettings); diff --git a/src/main/java/de/tum/cit/aet/artemis/iris/web/IrisTextExerciseChatSessionResource.java b/src/main/java/de/tum/cit/aet/artemis/iris/web/IrisTextExerciseChatSessionResource.java index 9ebb7aa647a2..e84958b6ad11 100644 --- a/src/main/java/de/tum/cit/aet/artemis/iris/web/IrisTextExerciseChatSessionResource.java +++ b/src/main/java/de/tum/cit/aet/artemis/iris/web/IrisTextExerciseChatSessionResource.java @@ -1,8 +1,11 @@ package de.tum.cit.aet.artemis.iris.web; +import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_CORE; + import java.net.URI; import java.net.URISyntaxException; import java.util.List; +import java.util.Optional; import org.springframework.context.annotation.Profile; import org.springframework.data.domain.Pageable; @@ -13,6 +16,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import de.tum.cit.aet.artemis.core.exception.ApiNotPresentException; import de.tum.cit.aet.artemis.core.exception.ConflictException; import de.tum.cit.aet.artemis.core.repository.UserRepository; import de.tum.cit.aet.artemis.core.security.annotations.enforceRoleInExercise.EnforceAtLeastStudentInExercise; @@ -22,8 +26,8 @@ import de.tum.cit.aet.artemis.iris.service.IrisSessionService; import de.tum.cit.aet.artemis.iris.service.session.IrisTextExerciseChatSessionService; import de.tum.cit.aet.artemis.iris.service.settings.IrisSettingsService; +import de.tum.cit.aet.artemis.text.api.TextApi; import de.tum.cit.aet.artemis.text.domain.TextExercise; -import de.tum.cit.aet.artemis.text.repository.TextExerciseRepository; /** * REST controller for managing {@link IrisTextExerciseChatSession}. @@ -39,20 +43,20 @@ public class IrisTextExerciseChatSessionResource { private final IrisSettingsService irisSettingsService; - private final TextExerciseRepository textExerciseRepository; + private final Optional textApi; private final IrisTextExerciseChatSessionService irisTextExerciseChatSessionService; private final IrisTextExerciseChatSessionRepository irisTextExerciseChatSessionRepository; protected IrisTextExerciseChatSessionResource(IrisTextExerciseChatSessionRepository irisTextExerciseChatSessionRepository, UserRepository userRepository, - TextExerciseRepository textExerciseRepository, IrisSessionService irisSessionService, IrisSettingsService irisSettingsService, + IrisSessionService irisSessionService, IrisSettingsService irisSettingsService, Optional textApi, IrisTextExerciseChatSessionService irisTextExerciseChatSessionService) { this.irisTextExerciseChatSessionRepository = irisTextExerciseChatSessionRepository; this.userRepository = userRepository; this.irisSessionService = irisSessionService; this.irisSettingsService = irisSettingsService; - this.textExerciseRepository = textExerciseRepository; + this.textApi = textApi; this.irisTextExerciseChatSessionService = irisTextExerciseChatSessionService; } @@ -65,7 +69,7 @@ protected IrisTextExerciseChatSessionResource(IrisTextExerciseChatSessionReposit @PostMapping("{exerciseId}/sessions/current") @EnforceAtLeastStudentInExercise public ResponseEntity getCurrentSessionOrCreateIfNotExists(@PathVariable Long exerciseId) throws URISyntaxException { - var exercise = textExerciseRepository.findByIdElseThrow(exerciseId); + var exercise = textApi.orElseThrow(() -> new ApiNotPresentException(TextApi.class, PROFILE_CORE)).findByIdElseThrow(exerciseId); validateExercise(exercise); irisSettingsService.isEnabledForElseThrow(IrisSubSettingsType.TEXT_EXERCISE_CHAT, exercise); @@ -93,7 +97,7 @@ public ResponseEntity getCurrentSessionOrCreateIfNo @PostMapping("{exerciseId}/sessions") @EnforceAtLeastStudentInExercise public ResponseEntity createSessionForExercise(@PathVariable Long exerciseId) throws URISyntaxException { - var textExercise = textExerciseRepository.findByIdElseThrow(exerciseId); + var textExercise = textApi.orElseThrow(() -> new ApiNotPresentException(TextApi.class, PROFILE_CORE)).findByIdElseThrow(exerciseId); validateExercise(textExercise); irisSettingsService.isEnabledForElseThrow(IrisSubSettingsType.TEXT_EXERCISE_CHAT, textExercise); @@ -115,7 +119,7 @@ public ResponseEntity createSessionForExercise(@Pat @GetMapping("{exerciseId}/sessions") @EnforceAtLeastStudentInExercise public ResponseEntity> getAllSessions(@PathVariable Long exerciseId) { - var exercise = textExerciseRepository.findByIdElseThrow(exerciseId); + var exercise = textApi.orElseThrow(() -> new ApiNotPresentException(TextApi.class, PROFILE_CORE)).findByIdElseThrow(exerciseId); validateExercise(exercise); irisSettingsService.isEnabledForElseThrow(IrisSubSettingsType.TEXT_EXERCISE_CHAT, exercise); diff --git a/src/main/java/de/tum/cit/aet/artemis/text/api/TextApi.java b/src/main/java/de/tum/cit/aet/artemis/text/api/TextApi.java index 44d3bd9a8753..d80b4e873f38 100644 --- a/src/main/java/de/tum/cit/aet/artemis/text/api/TextApi.java +++ b/src/main/java/de/tum/cit/aet/artemis/text/api/TextApi.java @@ -2,6 +2,7 @@ import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_CORE; +import java.util.List; import java.util.Optional; import org.springframework.context.annotation.Profile; @@ -32,4 +33,12 @@ public TextExercise findWithGradingCriteriaByIdElseThrow(long exerciseId) { public Optional findById(String reference) { return textBlockRepository.findById(reference); } + + public TextExercise findByIdElseThrow(long exerciseId) { + return textExerciseRepository.findByIdElseThrow(exerciseId); + } + + public List findAllWithCategoriesByCourseId(Long courseId) { + return textExerciseRepository.findAllWithCategoriesByCourseId(courseId); + } } From 283440c109ea1be4ac0981c920da8578e30035ed Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Tue, 17 Dec 2024 16:06:41 +0100 Subject: [PATCH 17/22] replace remaining occurrences with API usage --- .../artemis/athena/web/AthenaResource.java | 22 ++++++++++------ .../service/ExerciseDeletionService.java | 13 +++++----- .../exercise/web/ParticipationResource.java | 11 ++++---- .../TextPlagiarismDetectionService.java | 8 ++---- .../tum/cit/aet/artemis/text/api/TextApi.java | 10 +++++++- .../aet/artemis/text/api/TextFeedbackApi.java | 25 +++++++++++++++++++ .../artemis/text/api/TextSubmissionApi.java | 4 +++ 7 files changed, 66 insertions(+), 27 deletions(-) create mode 100644 src/main/java/de/tum/cit/aet/artemis/text/api/TextFeedbackApi.java diff --git a/src/main/java/de/tum/cit/aet/artemis/athena/web/AthenaResource.java b/src/main/java/de/tum/cit/aet/artemis/athena/web/AthenaResource.java index 177447b6b724..7a9d0f8e3b28 100644 --- a/src/main/java/de/tum/cit/aet/artemis/athena/web/AthenaResource.java +++ b/src/main/java/de/tum/cit/aet/artemis/athena/web/AthenaResource.java @@ -1,9 +1,11 @@ package de.tum.cit.aet.artemis.athena.web; import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_ATHENA; +import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_CORE; import java.io.IOException; import java.util.List; +import java.util.Optional; import java.util.function.Function; import org.slf4j.Logger; @@ -27,6 +29,7 @@ import de.tum.cit.aet.artemis.athena.service.AthenaRepositoryExportService; import de.tum.cit.aet.artemis.core.domain.Course; import de.tum.cit.aet.artemis.core.exception.AccessForbiddenException; +import de.tum.cit.aet.artemis.core.exception.ApiNotPresentException; import de.tum.cit.aet.artemis.core.exception.InternalServerErrorException; import de.tum.cit.aet.artemis.core.exception.NetworkingException; import de.tum.cit.aet.artemis.core.repository.CourseRepository; @@ -45,8 +48,8 @@ import de.tum.cit.aet.artemis.programming.domain.RepositoryType; import de.tum.cit.aet.artemis.programming.repository.ProgrammingExerciseRepository; import de.tum.cit.aet.artemis.programming.repository.ProgrammingSubmissionRepository; -import de.tum.cit.aet.artemis.text.repository.TextExerciseRepository; -import de.tum.cit.aet.artemis.text.repository.TextSubmissionRepository; +import de.tum.cit.aet.artemis.text.api.TextApi; +import de.tum.cit.aet.artemis.text.api.TextSubmissionApi; /** * REST controller for Athena feedback suggestions. @@ -63,9 +66,9 @@ public class AthenaResource { private final CourseRepository courseRepository; - private final TextExerciseRepository textExerciseRepository; + private final Optional textApi; - private final TextSubmissionRepository textSubmissionRepository; + private final Optional textSubmissionApi; private final ProgrammingExerciseRepository programmingExerciseRepository; @@ -86,14 +89,14 @@ public class AthenaResource { /** * The AthenaResource provides an endpoint for the client to fetch feedback suggestions from Athena. */ - public AthenaResource(CourseRepository courseRepository, TextExerciseRepository textExerciseRepository, TextSubmissionRepository textSubmissionRepository, + public AthenaResource(CourseRepository courseRepository, Optional textApi, Optional textSubmissionApi, ProgrammingExerciseRepository programmingExerciseRepository, ProgrammingSubmissionRepository programmingSubmissionRepository, ModelingExerciseRepository modelingExerciseRepository, ModelingSubmissionRepository modelingSubmissionRepository, AuthorizationCheckService authCheckService, AthenaFeedbackSuggestionsService athenaFeedbackSuggestionsService, AthenaRepositoryExportService athenaRepositoryExportService, AthenaModuleService athenaModuleService) { this.courseRepository = courseRepository; - this.textExerciseRepository = textExerciseRepository; - this.textSubmissionRepository = textSubmissionRepository; + this.textSubmissionApi = textSubmissionApi; + this.textApi = textApi; this.programmingExerciseRepository = programmingExerciseRepository; this.programmingSubmissionRepository = programmingSubmissionRepository; this.modelingExerciseRepository = modelingExerciseRepository; @@ -162,7 +165,10 @@ private ResponseEntity> getAvailableModules(long courseId, Exercise @GetMapping("athena/text-exercises/{exerciseId}/submissions/{submissionId}/feedback-suggestions") @EnforceAtLeastTutor public ResponseEntity> getTextFeedbackSuggestions(@PathVariable long exerciseId, @PathVariable long submissionId) { - return getFeedbackSuggestions(exerciseId, submissionId, textExerciseRepository::findByIdElseThrow, textSubmissionRepository::findByIdElseThrow, + var api = textApi.orElseThrow(() -> new ApiNotPresentException(TextApi.class, PROFILE_CORE)); + var submissionApi = textSubmissionApi.orElseThrow(() -> new ApiNotPresentException(TextSubmissionApi.class, PROFILE_CORE)); + + return getFeedbackSuggestions(exerciseId, submissionId, api::findByIdElseThrow, submissionApi::findByIdElseThrow, athenaFeedbackSuggestionsService::getTextFeedbackSuggestions); } diff --git a/src/main/java/de/tum/cit/aet/artemis/exercise/service/ExerciseDeletionService.java b/src/main/java/de/tum/cit/aet/artemis/exercise/service/ExerciseDeletionService.java index 313ee6308bce..368a9355d10f 100644 --- a/src/main/java/de/tum/cit/aet/artemis/exercise/service/ExerciseDeletionService.java +++ b/src/main/java/de/tum/cit/aet/artemis/exercise/service/ExerciseDeletionService.java @@ -38,8 +38,8 @@ import de.tum.cit.aet.artemis.programming.service.ProgrammingExerciseService; import de.tum.cit.aet.artemis.quiz.domain.QuizExercise; import de.tum.cit.aet.artemis.quiz.service.QuizExerciseService; +import de.tum.cit.aet.artemis.text.api.TextApi; import de.tum.cit.aet.artemis.text.domain.TextExercise; -import de.tum.cit.aet.artemis.text.service.TextExerciseService; /** * Service Implementation for managing Exercise. @@ -72,7 +72,7 @@ public class ExerciseDeletionService { private final PlagiarismResultRepository plagiarismResultRepository; - private final TextExerciseService textExerciseService; + private final Optional textApi; private final ChannelRepository channelRepository; @@ -85,9 +85,8 @@ public class ExerciseDeletionService { public ExerciseDeletionService(ExerciseRepository exerciseRepository, ExerciseUnitRepository exerciseUnitRepository, ParticipationService participationService, ProgrammingExerciseService programmingExerciseService, ModelingExerciseService modelingExerciseService, QuizExerciseService quizExerciseService, TutorParticipationRepository tutorParticipationRepository, ExampleSubmissionService exampleSubmissionService, StudentExamRepository studentExamRepository, - LectureUnitService lectureUnitService, PlagiarismResultRepository plagiarismResultRepository, TextExerciseService textExerciseService, - ChannelRepository channelRepository, ChannelService channelService, Optional competencyProgressApi, - Optional irisSettingsService) { + LectureUnitService lectureUnitService, PlagiarismResultRepository plagiarismResultRepository, Optional textApi, ChannelRepository channelRepository, + ChannelService channelService, Optional competencyProgressApi, Optional irisSettingsService) { this.exerciseRepository = exerciseRepository; this.participationService = participationService; this.programmingExerciseService = programmingExerciseService; @@ -99,7 +98,7 @@ public ExerciseDeletionService(ExerciseRepository exerciseRepository, ExerciseUn this.exerciseUnitRepository = exerciseUnitRepository; this.lectureUnitService = lectureUnitService; this.plagiarismResultRepository = plagiarismResultRepository; - this.textExerciseService = textExerciseService; + this.textApi = textApi; this.channelRepository = channelRepository; this.channelService = channelService; this.competencyProgressApi = competencyProgressApi; @@ -167,7 +166,7 @@ public void delete(long exerciseId, boolean deleteStudentReposBuildPlans, boolea if (exercise instanceof TextExercise) { log.info("Cancel scheduled operations of exercise {}", exercise.getId()); - textExerciseService.cancelScheduledOperations(exerciseId); + textApi.ifPresent(api -> api.cancelScheduledOperations(exerciseId)); } // delete all exercise units linking to the exercise diff --git a/src/main/java/de/tum/cit/aet/artemis/exercise/web/ParticipationResource.java b/src/main/java/de/tum/cit/aet/artemis/exercise/web/ParticipationResource.java index 3a8c0b6368b9..f68dc98570a8 100644 --- a/src/main/java/de/tum/cit/aet/artemis/exercise/web/ParticipationResource.java +++ b/src/main/java/de/tum/cit/aet/artemis/exercise/web/ParticipationResource.java @@ -97,8 +97,8 @@ import de.tum.cit.aet.artemis.quiz.repository.SubmittedAnswerRepository; import de.tum.cit.aet.artemis.quiz.service.QuizBatchService; import de.tum.cit.aet.artemis.quiz.service.QuizSubmissionService; +import de.tum.cit.aet.artemis.text.api.TextFeedbackApi; import de.tum.cit.aet.artemis.text.domain.TextExercise; -import de.tum.cit.aet.artemis.text.service.TextExerciseFeedbackService; /** * REST controller for managing Participation. @@ -165,7 +165,7 @@ public class ParticipationResource { private final ProgrammingExerciseCodeReviewFeedbackService programmingExerciseCodeReviewFeedbackService; - private final TextExerciseFeedbackService textExerciseFeedbackService; + private final Optional textFeedbackApi; private final ModelingExerciseFeedbackService modelingExerciseFeedbackService; @@ -178,7 +178,7 @@ public ParticipationResource(ParticipationService participationService, Programm ProgrammingExerciseStudentParticipationRepository programmingExerciseStudentParticipationRepository, SubmissionRepository submissionRepository, ResultRepository resultRepository, ExerciseDateService exerciseDateService, InstanceMessageSendService instanceMessageSendService, QuizBatchService quizBatchService, SubmittedAnswerRepository submittedAnswerRepository, QuizSubmissionService quizSubmissionService, GradingScaleService gradingScaleService, - ProgrammingExerciseCodeReviewFeedbackService programmingExerciseCodeReviewFeedbackService, TextExerciseFeedbackService textExerciseFeedbackService, + ProgrammingExerciseCodeReviewFeedbackService programmingExerciseCodeReviewFeedbackService, Optional textFeedbackApi, ModelingExerciseFeedbackService modelingExerciseFeedbackService) { this.participationService = participationService; this.programmingExerciseParticipationService = programmingExerciseParticipationService; @@ -205,7 +205,7 @@ public ParticipationResource(ParticipationService participationService, Programm this.quizSubmissionService = quizSubmissionService; this.gradingScaleService = gradingScaleService; this.programmingExerciseCodeReviewFeedbackService = programmingExerciseCodeReviewFeedbackService; - this.textExerciseFeedbackService = textExerciseFeedbackService; + this.textFeedbackApi = textFeedbackApi; this.modelingExerciseFeedbackService = modelingExerciseFeedbackService; } @@ -417,7 +417,8 @@ else if (exercise instanceof ProgrammingExercise) { // Process feedback request StudentParticipation updatedParticipation; if (exercise instanceof TextExercise) { - updatedParticipation = textExerciseFeedbackService.handleNonGradedFeedbackRequest(participation, (TextExercise) exercise); + StudentParticipation finalParticipation = participation; + updatedParticipation = textFeedbackApi.map(a -> a.handleNonGradedFeedbackRequest(finalParticipation, (TextExercise) exercise)).orElse(participation); } else if (exercise instanceof ModelingExercise) { updatedParticipation = modelingExerciseFeedbackService.handleNonGradedFeedbackRequest(participation, (ModelingExercise) exercise); diff --git a/src/main/java/de/tum/cit/aet/artemis/plagiarism/service/TextPlagiarismDetectionService.java b/src/main/java/de/tum/cit/aet/artemis/plagiarism/service/TextPlagiarismDetectionService.java index 2523ee8784d3..466715e73256 100644 --- a/src/main/java/de/tum/cit/aet/artemis/plagiarism/service/TextPlagiarismDetectionService.java +++ b/src/main/java/de/tum/cit/aet/artemis/plagiarism/service/TextPlagiarismDetectionService.java @@ -35,7 +35,6 @@ import de.tum.cit.aet.artemis.text.api.TextSubmissionExportApi; import de.tum.cit.aet.artemis.text.domain.TextExercise; import de.tum.cit.aet.artemis.text.domain.TextSubmission; -import de.tum.cit.aet.artemis.text.service.TextSubmissionExportService; @Profile(PROFILE_CORE) @Service @@ -45,18 +44,15 @@ public class TextPlagiarismDetectionService { private final Optional textSubmissionExportApi; - private final TextSubmissionExportService textSubmissionExportService; - private final PlagiarismWebsocketService plagiarismWebsocketService; private final PlagiarismCacheService plagiarismCacheService; private final PlagiarismService plagiarismService; - public TextPlagiarismDetectionService(Optional textSubmissionExportApi, TextSubmissionExportService textSubmissionExportService, - PlagiarismWebsocketService plagiarismWebsocketService, PlagiarismCacheService plagiarismCacheService, PlagiarismService plagiarismService) { + public TextPlagiarismDetectionService(Optional textSubmissionExportApi, PlagiarismWebsocketService plagiarismWebsocketService, + PlagiarismCacheService plagiarismCacheService, PlagiarismService plagiarismService) { this.textSubmissionExportApi = textSubmissionExportApi; - this.textSubmissionExportService = textSubmissionExportService; this.plagiarismWebsocketService = plagiarismWebsocketService; this.plagiarismCacheService = plagiarismCacheService; this.plagiarismService = plagiarismService; diff --git a/src/main/java/de/tum/cit/aet/artemis/text/api/TextApi.java b/src/main/java/de/tum/cit/aet/artemis/text/api/TextApi.java index d80b4e873f38..dd09142857c6 100644 --- a/src/main/java/de/tum/cit/aet/artemis/text/api/TextApi.java +++ b/src/main/java/de/tum/cit/aet/artemis/text/api/TextApi.java @@ -9,6 +9,7 @@ import org.springframework.stereotype.Controller; import de.tum.cit.aet.artemis.assessment.repository.TextBlockRepository; +import de.tum.cit.aet.artemis.core.service.messaging.InstanceMessageSendService; import de.tum.cit.aet.artemis.text.domain.TextBlock; import de.tum.cit.aet.artemis.text.domain.TextExercise; import de.tum.cit.aet.artemis.text.repository.TextExerciseRepository; @@ -21,9 +22,12 @@ public class TextApi extends AbstractTextApi { private final TextBlockRepository textBlockRepository; - public TextApi(TextExerciseRepository textExerciseRepository, TextBlockRepository textBlockRepository) { + private final InstanceMessageSendService instanceMessageSendService; + + public TextApi(TextExerciseRepository textExerciseRepository, TextBlockRepository textBlockRepository, InstanceMessageSendService instanceMessageSendService) { this.textExerciseRepository = textExerciseRepository; this.textBlockRepository = textBlockRepository; + this.instanceMessageSendService = instanceMessageSendService; } public TextExercise findWithGradingCriteriaByIdElseThrow(long exerciseId) { @@ -41,4 +45,8 @@ public TextExercise findByIdElseThrow(long exerciseId) { public List findAllWithCategoriesByCourseId(Long courseId) { return textExerciseRepository.findAllWithCategoriesByCourseId(courseId); } + + public void cancelScheduledOperations(long exerciseId) { + instanceMessageSendService.sendTextExerciseScheduleCancel(exerciseId); + } } diff --git a/src/main/java/de/tum/cit/aet/artemis/text/api/TextFeedbackApi.java b/src/main/java/de/tum/cit/aet/artemis/text/api/TextFeedbackApi.java new file mode 100644 index 000000000000..4d2bd76776f0 --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/text/api/TextFeedbackApi.java @@ -0,0 +1,25 @@ +package de.tum.cit.aet.artemis.text.api; + +import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_CORE; + +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Controller; + +import de.tum.cit.aet.artemis.exercise.domain.participation.StudentParticipation; +import de.tum.cit.aet.artemis.text.domain.TextExercise; +import de.tum.cit.aet.artemis.text.service.TextExerciseFeedbackService; + +@Controller +@Profile(PROFILE_CORE) +public class TextFeedbackApi extends AbstractTextApi { + + private final TextExerciseFeedbackService feedbackService; + + public TextFeedbackApi(TextExerciseFeedbackService feedbackService) { + this.feedbackService = feedbackService; + } + + public StudentParticipation handleNonGradedFeedbackRequest(StudentParticipation participation, TextExercise textExercise) { + return feedbackService.handleNonGradedFeedbackRequest(participation, textExercise); + } +} diff --git a/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionApi.java b/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionApi.java index 3879d412fc18..f3eafd33cabe 100644 --- a/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionApi.java +++ b/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionApi.java @@ -24,6 +24,10 @@ public TextSubmissionApi(TextSubmissionRepository textSubmissionRepository, Text this.textSubmissionService = textSubmissionService; } + public TextSubmission findByIdElseThrow(long id) { + return textSubmissionRepository.findByIdElseThrow(id); + } + public TextSubmission saveTextSubmission(TextSubmission textSubmission) { return textSubmissionRepository.save(textSubmission); } From fbced3e7f025cf2d6e4aacb212ab50a10994fe25 Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Tue, 17 Dec 2024 16:06:59 +0100 Subject: [PATCH 18/22] implement AbstractModuleAccessArchitectureTest in text --- .../text/architecture/TextApiArchitectureTest.java | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/test/java/de/tum/cit/aet/artemis/text/architecture/TextApiArchitectureTest.java diff --git a/src/test/java/de/tum/cit/aet/artemis/text/architecture/TextApiArchitectureTest.java b/src/test/java/de/tum/cit/aet/artemis/text/architecture/TextApiArchitectureTest.java new file mode 100644 index 000000000000..5585aa7de8c8 --- /dev/null +++ b/src/test/java/de/tum/cit/aet/artemis/text/architecture/TextApiArchitectureTest.java @@ -0,0 +1,11 @@ +package de.tum.cit.aet.artemis.text.architecture; + +import de.tum.cit.aet.artemis.shared.architecture.module.AbstractModuleAccessArchitectureTest; + +class TextApiArchitectureTest extends AbstractModuleAccessArchitectureTest { + + @Override + public String getModulePackage() { + return ARTEMIS_PACKAGE + ".text"; + } +} From 990e967073644d692dc1e5d83950ce795baef2ba Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Tue, 17 Dec 2024 16:20:46 +0100 Subject: [PATCH 19/22] instantiate TextExerciseService lazily in TextApi --- .../de/tum/cit/aet/artemis/text/api/TextApi.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/tum/cit/aet/artemis/text/api/TextApi.java b/src/main/java/de/tum/cit/aet/artemis/text/api/TextApi.java index dd09142857c6..6936c09255c3 100644 --- a/src/main/java/de/tum/cit/aet/artemis/text/api/TextApi.java +++ b/src/main/java/de/tum/cit/aet/artemis/text/api/TextApi.java @@ -5,14 +5,15 @@ import java.util.List; import java.util.Optional; +import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Controller; import de.tum.cit.aet.artemis.assessment.repository.TextBlockRepository; -import de.tum.cit.aet.artemis.core.service.messaging.InstanceMessageSendService; import de.tum.cit.aet.artemis.text.domain.TextBlock; import de.tum.cit.aet.artemis.text.domain.TextExercise; import de.tum.cit.aet.artemis.text.repository.TextExerciseRepository; +import de.tum.cit.aet.artemis.text.service.TextExerciseService; @Controller @Profile(PROFILE_CORE) @@ -22,12 +23,13 @@ public class TextApi extends AbstractTextApi { private final TextBlockRepository textBlockRepository; - private final InstanceMessageSendService instanceMessageSendService; + private final TextExerciseService textExerciseService; - public TextApi(TextExerciseRepository textExerciseRepository, TextBlockRepository textBlockRepository, InstanceMessageSendService instanceMessageSendService) { + // TextExerciseService needs to be initialized lazy because of the dependency to InstanceMessageSendService + public TextApi(TextExerciseRepository textExerciseRepository, TextBlockRepository textBlockRepository, @Lazy TextExerciseService textExerciseService) { this.textExerciseRepository = textExerciseRepository; this.textBlockRepository = textBlockRepository; - this.instanceMessageSendService = instanceMessageSendService; + this.textExerciseService = textExerciseService; } public TextExercise findWithGradingCriteriaByIdElseThrow(long exerciseId) { @@ -47,6 +49,6 @@ public List findAllWithCategoriesByCourseId(Long courseId) { } public void cancelScheduledOperations(long exerciseId) { - instanceMessageSendService.sendTextExerciseScheduleCancel(exerciseId); + textExerciseService.cancelScheduledOperations(exerciseId); } } From cd4613f3fb549889c3a52bf41b7a70d33d169ac4 Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Tue, 17 Dec 2024 17:32:25 +0100 Subject: [PATCH 20/22] Use BadRequestAlertException over IllegalArgumentException --- .../tum/cit/aet/artemis/text/api/TextSubmissionImportApi.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionImportApi.java b/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionImportApi.java index 22b26ee5c6d6..f5624c6c29a5 100644 --- a/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionImportApi.java +++ b/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionImportApi.java @@ -9,6 +9,7 @@ import org.springframework.stereotype.Controller; import de.tum.cit.aet.artemis.assessment.domain.GradingInstruction; +import de.tum.cit.aet.artemis.core.exception.BadRequestAlertException; import de.tum.cit.aet.artemis.text.domain.TextSubmission; import de.tum.cit.aet.artemis.text.repository.TextSubmissionRepository; import de.tum.cit.aet.artemis.text.service.TextExerciseImportService; @@ -37,7 +38,7 @@ public TextSubmission importStudentSubmission(long submissionId, long exerciseId private void checkGivenExerciseIdSameForSubmissionParticipation(long originalExerciseId, long exerciseIdInSubmission) { if (!Objects.equals(originalExerciseId, exerciseIdInSubmission)) { - throw new IllegalArgumentException("ExerciseId does not match with the exerciseId in submission participation"); + throw new BadRequestAlertException("ExerciseId does not match with the exerciseId in submission participation", "exampleSubmission", "idNotMatched"); } } } From 02e28b8d817c9b25c1173c17a77e54af1f963edd Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Tue, 17 Dec 2024 17:42:55 +0100 Subject: [PATCH 21/22] add javadoc --- .../cit/aet/artemis/text/api/TextSubmissionExportApi.java | 5 +++++ .../cit/aet/artemis/text/api/TextSubmissionImportApi.java | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionExportApi.java b/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionExportApi.java index f107592666e5..82ddcc51c4b5 100644 --- a/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionExportApi.java +++ b/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionExportApi.java @@ -48,6 +48,11 @@ public Path exportTextExerciseWithSubmissions(TextExercise exercise, SubmissionE return textExerciseWithSubmissionsExportService.exportTextExerciseWithSubmissions(exercise, optionsDTO, exportDir, exportErrors, reportEntries); } + /** + * Prepares a text block for export as an example submission + * + * @param exampleSubmissionId the submission id to be exported + */ public void prepareTextBlockForExampleSubmission(long exampleSubmissionId) { Optional textSubmission = textSubmissionRepository.findWithEagerResultsAndFeedbackAndTextBlocksById(exampleSubmissionId); if (textSubmission.isPresent() && textSubmission.get().getLatestResult() == null diff --git a/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionImportApi.java b/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionImportApi.java index f5624c6c29a5..b564d189d04c 100644 --- a/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionImportApi.java +++ b/src/main/java/de/tum/cit/aet/artemis/text/api/TextSubmissionImportApi.java @@ -27,6 +27,14 @@ public TextSubmissionImportApi(TextSubmissionRepository textSubmissionRepository this.textExerciseImportService = textExerciseImportService; } + /** + * Imports a student submission to an exercise. + * + * @param submissionId of the submission to be imported + * @param exerciseId of the exercise to import the submission into + * @param gradingInstructionCopyTracker mapping of the gradingInstructionID to the gradingInstruction + * @return the imported text submission + */ public TextSubmission importStudentSubmission(long submissionId, long exerciseId, Map gradingInstructionCopyTracker) { TextSubmission textSubmission = textSubmissionRepository.findByIdWithEagerResultsAndFeedbackAndTextBlocksElseThrow(submissionId); checkGivenExerciseIdSameForSubmissionParticipation(exerciseId, textSubmission.getParticipation().getExercise().getId()); From c1ab348f4bb973219133ca176aba9f6fd7b90410 Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Tue, 17 Dec 2024 20:55:42 +0100 Subject: [PATCH 22/22] fix missing call to TextSubmissionApi#saveTextSubmission --- .../de/tum/cit/aet/artemis/exam/service/StudentExamService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/tum/cit/aet/artemis/exam/service/StudentExamService.java b/src/main/java/de/tum/cit/aet/artemis/exam/service/StudentExamService.java index 5dfd90e72c04..b23b9834729a 100644 --- a/src/main/java/de/tum/cit/aet/artemis/exam/service/StudentExamService.java +++ b/src/main/java/de/tum/cit/aet/artemis/exam/service/StudentExamService.java @@ -314,7 +314,7 @@ else if (submittedAnswer instanceof ShortAnswerSubmittedAnswer) { TextSubmission existingSubmissionInDatabase = (TextSubmission) existingParticipationInDatabase.findLatestSubmission().orElse(null); TextSubmission textSubmissionFromClient = (TextSubmission) submissionFromClient; if (!isContentEqualTo(existingSubmissionInDatabase, textSubmissionFromClient)) { - textSubmissionApi.orElseThrow(() -> new ApiNotPresentException(TextSubmissionApi.class, PROFILE_CORE)); + textSubmissionApi.orElseThrow(() -> new ApiNotPresentException(TextSubmissionApi.class, PROFILE_CORE)).saveTextSubmission(textSubmissionFromClient); saveSubmissionVersion(currentUser, submissionFromClient); } }