diff --git a/src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CompetencyJolService.java b/src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CompetencyJolService.java index 7fa11b6f69b9..60238c811ddd 100644 --- a/src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CompetencyJolService.java +++ b/src/main/java/de/tum/cit/aet/artemis/atlas/service/competency/CompetencyJolService.java @@ -23,7 +23,7 @@ import de.tum.cit.aet.artemis.atlas.repository.CompetencyRepository; import de.tum.cit.aet.artemis.core.exception.BadRequestAlertException; import de.tum.cit.aet.artemis.core.repository.UserRepository; -import de.tum.cit.aet.artemis.iris.service.pyris.PyrisEventService; +import de.tum.cit.aet.artemis.iris.service.pyris.PyrisEventPublisherService; import de.tum.cit.aet.artemis.iris.service.pyris.event.CompetencyJolSetEvent; /** @@ -45,15 +45,15 @@ public class CompetencyJolService { private final UserRepository userRepository; - private final Optional pyrisEventService; + private final Optional pyrisEventPublisher; public CompetencyJolService(CompetencyJolRepository competencyJolRepository, CompetencyRepository competencyRepository, - CompetencyProgressRepository competencyProgressRepository, UserRepository userRepository, Optional pyrisEventService) { + CompetencyProgressRepository competencyProgressRepository, UserRepository userRepository, Optional pyrisEventPublisher) { this.competencyJolRepository = competencyJolRepository; this.competencyRepository = competencyRepository; this.competencyProgressRepository = competencyProgressRepository; this.userRepository = userRepository; - this.pyrisEventService = pyrisEventService; + this.pyrisEventPublisher = pyrisEventPublisher; } /** @@ -84,10 +84,10 @@ public void setJudgementOfLearning(long competencyId, long userId, short jolValu final var jol = createCompetencyJol(competencyId, userId, jolValue, ZonedDateTime.now(), competencyProgress); competencyJolRepository.save(jol); - pyrisEventService.ifPresent(service -> { - // Inform Iris so it can send a message to the user + // Inform Iris so it can send a message to the user + pyrisEventPublisher.ifPresent(service -> { try { - service.trigger(new CompetencyJolSetEvent(jol)); + service.publishEvent(new CompetencyJolSetEvent(this, jol)); } catch (Exception e) { log.warn("Something went wrong while sending the judgement of learning to Iris", e); diff --git a/src/main/java/de/tum/cit/aet/artemis/iris/repository/IrisExerciseSettingsRepository.java b/src/main/java/de/tum/cit/aet/artemis/iris/repository/IrisExerciseSettingsRepository.java index 74b3e5abf57c..ee1e1863e5ee 100644 --- a/src/main/java/de/tum/cit/aet/artemis/iris/repository/IrisExerciseSettingsRepository.java +++ b/src/main/java/de/tum/cit/aet/artemis/iris/repository/IrisExerciseSettingsRepository.java @@ -18,7 +18,8 @@ public interface IrisExerciseSettingsRepository extends ArtemisJpaRepository 0 FROM IrisExerciseSettings s WHERE s.exercise.id = :exerciseId - AND s.irisTextExerciseChatSettings.enabled = TRUE + AND ((s.irisTextExerciseChatSettings IS NOT NULL AND s.irisTextExerciseChatSettings.enabled = TRUE) + OR (s.irisChatSettings IS NOT NULL AND s.irisChatSettings.enabled = TRUE)) """) boolean isExerciseChatEnabled(@Param("exerciseId") long exerciseId); } diff --git a/src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisEventPublisherService.java b/src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisEventPublisherService.java new file mode 100644 index 000000000000..f31fa6e960d7 --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisEventPublisherService.java @@ -0,0 +1,112 @@ +package de.tum.cit.aet.artemis.iris.service.pyris; + +import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_IRIS; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.annotation.Profile; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import de.tum.cit.aet.artemis.iris.domain.settings.event.IrisEventType; +import de.tum.cit.aet.artemis.iris.service.pyris.event.CompetencyJolSetEvent; +import de.tum.cit.aet.artemis.iris.service.pyris.event.NewResultEvent; +import de.tum.cit.aet.artemis.iris.service.pyris.event.PyrisEvent; +import de.tum.cit.aet.artemis.iris.service.settings.IrisSettingsService; +import de.tum.cit.aet.artemis.programming.domain.ProgrammingSubmission; + +/** + * Service for publishing Pyris events. + */ +@Service +@Profile(PROFILE_IRIS) +public class PyrisEventPublisherService { + + private static final Logger log = LoggerFactory.getLogger(PyrisEventPublisherService.class); + + private final ApplicationEventPublisher eventPublisher; + + private final IrisSettingsService irisSettingsService; + + public PyrisEventPublisherService(ApplicationEventPublisher eventPublisher, IrisSettingsService irisSettingsService) { + this.eventPublisher = eventPublisher; + this.irisSettingsService = irisSettingsService; + } + + /** + * Publishes the given event. + * + * @param event the event to publish + */ + @Async + public void publishEvent(PyrisEvent event) { + if (!isEventEnabled(event)) { + log.debug("Skipping event publication as conditions are not met: {}", event.getClass().getSimpleName()); + return; + } + try { + eventPublisher.publishEvent(event); + } + catch (Exception e) { + log.error("Failed to publish event: {}", event, e); + throw e; + } + } + + /** + * Checks if the given event is enabled. + * + * @param event the event to check + * @return true if the event is enabled and conditions are met, false otherwise + */ + private boolean isEventEnabled(PyrisEvent event) { + return switch (event) { + case NewResultEvent newResultEvent -> { + var result = newResultEvent.getResult(); + if (result == null) { + yield false; + } + var submission = result.getSubmission(); + if (submission == null) { + yield false; + } + if (submission instanceof ProgrammingSubmission programmingSubmission) { + var participation = programmingSubmission.getParticipation(); + if (participation == null) { + yield false; + } + var programmingExercise = participation.getExercise(); + if (programmingExercise == null) { + yield false; + } + if (programmingSubmission.isBuildFailed()) { + yield irisSettingsService.isActivatedFor(IrisEventType.BUILD_FAILED, programmingExercise); + } + else { + yield irisSettingsService.isActivatedFor(IrisEventType.PROGRESS_STALLED, programmingExercise); + } + } + else { + yield false; + } + } + case CompetencyJolSetEvent competencyJolSetEvent -> { + var competencyJol = competencyJolSetEvent.getCompetencyJol(); + if (competencyJol == null) { + yield false; + } + var competency = competencyJol.getCompetency(); + if (competency == null) { + yield false; + } + var course = competency.getCourse(); + if (course == null) { + yield false; + } + yield irisSettingsService.isActivatedFor(IrisEventType.JOL, course); + } + default -> throw new UnsupportedPyrisEventException("Unsupported Pyris event: " + event.getClass().getSimpleName()); + }; + } +} diff --git a/src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisEventService.java b/src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisEventService.java index e2a8a785fc77..3ed043c627c7 100644 --- a/src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisEventService.java +++ b/src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisEventService.java @@ -5,19 +5,17 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Profile; -import org.springframework.scheduling.annotation.Async; +import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; -import de.tum.cit.aet.artemis.iris.domain.session.IrisChatSession; import de.tum.cit.aet.artemis.iris.service.pyris.event.CompetencyJolSetEvent; import de.tum.cit.aet.artemis.iris.service.pyris.event.NewResultEvent; -import de.tum.cit.aet.artemis.iris.service.pyris.event.PyrisEvent; -import de.tum.cit.aet.artemis.iris.service.session.AbstractIrisChatSessionService; import de.tum.cit.aet.artemis.iris.service.session.IrisCourseChatSessionService; import de.tum.cit.aet.artemis.iris.service.session.IrisExerciseChatSessionService; +import de.tum.cit.aet.artemis.programming.domain.ProgrammingSubmission; /** - * Service to handle Pyris events. + * Service for handling Pyris events. */ @Service @Profile(PROFILE_IRIS) @@ -35,33 +33,53 @@ public PyrisEventService(IrisCourseChatSessionService irisCourseChatSessionServi } /** - * Triggers a Pyris pipeline based on the received {@link PyrisEvent}. + * Handles a CompetencyJolSetEvent. The event is passed to the {@link de.tum.cit.aet.artemis.iris.service.session.IrisCourseChatSessionService} to handle the judgement of + * learning set. * - * @param event The event object received to trigger the matching pipeline - * @throws UnsupportedPyrisEventException if the event is not supported + * @see IrisCourseChatSessionService#onJudgementOfLearningSet + * @param event the {@link CompetencyJolSetEvent} to handle + */ + @EventListener + public void handleCompetencyJolSetEvent(CompetencyJolSetEvent event) { + log.debug("Processing CompetencyJolSetEvent"); + try { + irisCourseChatSessionService.onJudgementOfLearningSet(event.getCompetencyJol()); + log.debug("Successfully processed CompetencyJolSetEvent"); + } + catch (Exception e) { + log.error("Failed to process CompetencyJolSetEvent: {}", event, e); + throw e; + } + } + + /** + * Handles a NewResultEvent. A new result represents a new submission result. + * Depending on whether there was a build failure or not, the result is passed to the appropriate handler method inside the + * {@link de.tum.cit.aet.artemis.iris.service.session.IrisExerciseChatSessionService}. * - * @see PyrisEvent + * @see IrisExerciseChatSessionService#onBuildFailure + * @see IrisExerciseChatSessionService#onNewResult + * @param event the {@link NewResultEvent} to handle */ - @Async - public void trigger(PyrisEvent, ?> event) { - log.debug("Starting to process event of type: {}", event.getClass().getSimpleName()); + @EventListener + public void handleNewResultEvent(NewResultEvent event) { + log.debug("Processing NewResultEvent"); try { - switch (event) { - case CompetencyJolSetEvent competencyJolSetEvent -> { - log.debug("Processing CompetencyJolSetEvent: {}", competencyJolSetEvent); - competencyJolSetEvent.handleEvent(irisCourseChatSessionService); - log.debug("Successfully processed CompetencyJolSetEvent"); + var result = event.getResult(); + var submission = result.getSubmission(); + + if (submission instanceof ProgrammingSubmission programmingSubmission) { + if (programmingSubmission.isBuildFailed()) { + irisExerciseChatSessionService.onBuildFailure(result); } - case NewResultEvent newResultEvent -> { - log.debug("Processing NewResultEvent: {}", newResultEvent); - newResultEvent.handleEvent(irisExerciseChatSessionService); - log.debug("Successfully processed NewResultEvent"); + else { + irisExerciseChatSessionService.onNewResult(result); } - default -> throw new UnsupportedPyrisEventException("Unsupported event type: " + event.getClass().getSimpleName()); } + log.debug("Successfully processed NewResultEvent"); } catch (Exception e) { - log.error("Failed to process event: {}", event, e); + log.error("Failed to process NewResultEvent: {}", event, e); throw e; } } diff --git a/src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/event/CompetencyJolSetEvent.java b/src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/event/CompetencyJolSetEvent.java index 9ee7448811b4..8ad3710df44b 100644 --- a/src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/event/CompetencyJolSetEvent.java +++ b/src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/event/CompetencyJolSetEvent.java @@ -1,21 +1,28 @@ package de.tum.cit.aet.artemis.iris.service.pyris.event; +import java.util.Optional; + import de.tum.cit.aet.artemis.atlas.domain.competency.CompetencyJol; -import de.tum.cit.aet.artemis.iris.service.session.IrisCourseChatSessionService; +import de.tum.cit.aet.artemis.core.domain.User; -public class CompetencyJolSetEvent extends PyrisEvent { +public class CompetencyJolSetEvent extends PyrisEvent { - private final CompetencyJol eventObject; + private final CompetencyJol competencyJol; - public CompetencyJolSetEvent(CompetencyJol eventObject) { - if (eventObject == null) { - throw new IllegalArgumentException("Event object cannot be null"); + public CompetencyJolSetEvent(Object source, CompetencyJol competencyJol) { + super(source); + if (competencyJol == null) { + throw new IllegalArgumentException("CompetencyJol cannot be null"); } - this.eventObject = eventObject; + this.competencyJol = competencyJol; + } + + public CompetencyJol getCompetencyJol() { + return competencyJol; } @Override - public void handleEvent(IrisCourseChatSessionService service) { - service.onJudgementOfLearningSet(eventObject); + public Optional getUser() { + return Optional.ofNullable(competencyJol.getUser()); } } diff --git a/src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/event/NewResultEvent.java b/src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/event/NewResultEvent.java index 27516dff283a..a2b010b5d76b 100644 --- a/src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/event/NewResultEvent.java +++ b/src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/event/NewResultEvent.java @@ -1,34 +1,32 @@ package de.tum.cit.aet.artemis.iris.service.pyris.event; +import java.util.Optional; + import de.tum.cit.aet.artemis.assessment.domain.Result; -import de.tum.cit.aet.artemis.iris.service.session.IrisExerciseChatSessionService; -import de.tum.cit.aet.artemis.programming.domain.ProgrammingSubmission; +import de.tum.cit.aet.artemis.core.domain.User; +import de.tum.cit.aet.artemis.programming.domain.ProgrammingExerciseStudentParticipation; -public class NewResultEvent extends PyrisEvent { +public class NewResultEvent extends PyrisEvent { - private final Result eventObject; + private final Result result; - public NewResultEvent(Result eventObject) { - if (eventObject == null) { - throw new IllegalArgumentException("Event object cannot be null"); + public NewResultEvent(Object source, Result result) { + super(source); + if (result == null) { + throw new IllegalArgumentException("Result cannot be null"); } - this.eventObject = eventObject; + this.result = result; + } + + public Result getResult() { + return result; } @Override - public void handleEvent(IrisExerciseChatSessionService service) { - if (service == null) { - throw new IllegalArgumentException("Service cannot be null"); - } - var submission = eventObject.getSubmission(); - // We only care about programming submissions - if (submission instanceof ProgrammingSubmission programmingSubmission) { - if (programmingSubmission.isBuildFailed()) { - service.onBuildFailure(eventObject); - } - else { - service.onNewResult(eventObject); - } + public Optional getUser() { + if (result.getSubmission() != null && result.getSubmission().getParticipation() instanceof ProgrammingExerciseStudentParticipation studentParticipation) { + return studentParticipation.getStudent(); } + return Optional.empty(); } } diff --git a/src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/event/PyrisEvent.java b/src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/event/PyrisEvent.java index 0f4a723653d6..ba6d4d5b94e0 100644 --- a/src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/event/PyrisEvent.java +++ b/src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/event/PyrisEvent.java @@ -1,14 +1,24 @@ package de.tum.cit.aet.artemis.iris.service.pyris.event; -import de.tum.cit.aet.artemis.iris.domain.session.IrisChatSession; -import de.tum.cit.aet.artemis.iris.service.session.AbstractIrisChatSessionService; +import java.util.Optional; -public abstract class PyrisEvent, T> { +import org.springframework.context.ApplicationEvent; + +import de.tum.cit.aet.artemis.core.domain.User; + +/** + * Base class for Pyris events. + */ +public abstract class PyrisEvent extends ApplicationEvent { + + public PyrisEvent(Object source) { + super(source); + } /** - * Handles the event using the given service. + * Returns the user associated with this event. * - * @param service The service to handle the event for + * @return the user */ - public abstract void handleEvent(S service); + public abstract Optional getUser(); } diff --git a/src/main/java/de/tum/cit/aet/artemis/iris/service/session/IrisCourseChatSessionService.java b/src/main/java/de/tum/cit/aet/artemis/iris/service/session/IrisCourseChatSessionService.java index f6a97190142c..00b5379f1496 100644 --- a/src/main/java/de/tum/cit/aet/artemis/iris/service/session/IrisCourseChatSessionService.java +++ b/src/main/java/de/tum/cit/aet/artemis/iris/service/session/IrisCourseChatSessionService.java @@ -133,9 +133,6 @@ protected void setLLMTokenUsageParameters(LLMTokenUsageService.LLMTokenUsageBuil */ public void onJudgementOfLearningSet(CompetencyJol competencyJol) { var course = competencyJol.getCompetency().getCourse(); - if (!irisSettingsService.isEnabledFor(IrisSubSettingsType.COURSE_CHAT, course)) { - return; - } var user = competencyJol.getUser(); user.hasAcceptedIrisElseThrow(); var session = getCurrentSessionOrCreateIfNotExistsInternal(course, user, false); diff --git a/src/main/java/de/tum/cit/aet/artemis/iris/service/session/IrisExerciseChatSessionService.java b/src/main/java/de/tum/cit/aet/artemis/iris/service/session/IrisExerciseChatSessionService.java index d422970401e0..91b7c643258f 100644 --- a/src/main/java/de/tum/cit/aet/artemis/iris/service/session/IrisExerciseChatSessionService.java +++ b/src/main/java/de/tum/cit/aet/artemis/iris/service/session/IrisExerciseChatSessionService.java @@ -188,8 +188,6 @@ public void onBuildFailure(Result result) { } var exercise = validateExercise(participation.getExercise()); - irisSettingsService.isActivatedForElseThrow(IrisEventType.BUILD_FAILED, exercise); - var participant = studentParticipation.getParticipant(); if (participant instanceof User user) { var session = getCurrentSessionOrCreateIfNotExistsInternal(exercise, user, false); @@ -215,8 +213,6 @@ public void onNewResult(Result result) { var exercise = validateExercise(participation.getExercise()); - irisSettingsService.isActivatedForElseThrow(IrisEventType.PROGRESS_STALLED, exercise); - var recentSubmissions = submissionRepository.findAllWithResultsByParticipationIdOrderBySubmissionDateAsc(studentParticipation.getId()); double successThreshold = 100.0; // TODO: Retrieve configuration from Iris settings 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..ff5891a219c6 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 @@ -15,6 +15,8 @@ import java.util.TreeSet; import java.util.function.Supplier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.annotation.Profile; import org.springframework.context.event.EventListener; @@ -60,6 +62,8 @@ @Profile(PROFILE_IRIS) public class IrisSettingsService { + private static final Logger log = LoggerFactory.getLogger(IrisSettingsService.class); + private final IrisSettingsRepository irisSettingsRepository; private final IrisSubSettingsService irisSubSettingsService; @@ -476,38 +480,6 @@ public void isEnabledForElseThrow(IrisSubSettingsType type, Course course) { } } - /** - * Checks whether an Iris event is enabled for a course. - * Throws an exception if the chat feature is disabled. - * Throws an exception if the event is disabled. - * - * @param type The Iris event to check - * @param course The course to check - */ - public void isActivatedForElseThrow(IrisEventType type, Course course) { - isEnabledForElseThrow(IrisSubSettingsType.CHAT, course); - - if (!isActivatedFor(type, course)) { - throw new AccessForbiddenAlertException("The Iris " + type.name() + " event is disabled for this course.", "Iris", "iris." + type.name().toLowerCase() + "Disabled"); - } - } - - /** - * Checks whether an Iris event is enabled for an exercise. - * Throws an exception if the chat feature is disabled. - * Throws an exception if the event is disabled. - * - * @param type The Iris event to check - * @param exercise The exercise to check - */ - public void isActivatedForElseThrow(IrisEventType type, Exercise exercise) { - isEnabledForElseThrow(IrisSubSettingsType.CHAT, exercise); - - if (!isActivatedFor(type, exercise)) { - throw new AccessForbiddenAlertException("The Iris " + type.name() + " event is disabled for this exercise.", "Iris", "iris." + type.name().toLowerCase() + "Disabled"); - } - } - /** * Checks whether an Iris feature is enabled for a course. * @@ -540,6 +512,10 @@ public boolean isEnabledFor(IrisSubSettingsType type, Exercise exercise) { * @return Whether the Iris event is active for the course */ public boolean isActivatedFor(IrisEventType type, Course course) { + if (!isEnabledFor(IrisSubSettingsType.CHAT, course)) { + log.debug("Chat is disabled for course {}", course.getId()); + return false; + } var settings = getCombinedIrisSettingsFor(course, false); return isEventEnabledInSettings(settings, type); } @@ -552,6 +528,10 @@ public boolean isActivatedFor(IrisEventType type, Course course) { * @return Whether the Iris event is active for the exercise */ public boolean isActivatedFor(IrisEventType type, Exercise exercise) { + if (!isEnabledFor(IrisSubSettingsType.CHAT, exercise)) { + log.debug("Chat is disabled for exercise {}", exercise.getId()); + return false; + } var settings = getCombinedIrisSettingsFor(exercise, false); return isEventEnabledInSettings(settings, type); } @@ -760,7 +740,9 @@ private boolean isEventEnabledInSettings(IrisCombinedSettingsDTO settings, IrisE return switch (type) { case PROGRESS_STALLED -> { if (settings.irisChatSettings().disabledProactiveEvents() != null) { - yield !settings.irisChatSettings().disabledProactiveEvents().contains(IrisEventType.PROGRESS_STALLED.name().toLowerCase()); + var isEventEnabled = !settings.irisChatSettings().disabledProactiveEvents().contains(IrisEventType.PROGRESS_STALLED.name().toLowerCase()); + log.debug("Event PROGRESS_STALLED enabled: {}", isEventEnabled); + yield isEventEnabled; } else { yield true; @@ -768,13 +750,24 @@ private boolean isEventEnabledInSettings(IrisCombinedSettingsDTO settings, IrisE } case BUILD_FAILED -> { if (settings.irisChatSettings().disabledProactiveEvents() != null) { - yield !settings.irisChatSettings().disabledProactiveEvents().contains(IrisEventType.BUILD_FAILED.name().toLowerCase()); + var isEventEnabled = !settings.irisChatSettings().disabledProactiveEvents().contains(IrisEventType.BUILD_FAILED.name().toLowerCase()); + log.debug("Event BUILD_FAILED enabled: {}", isEventEnabled); + yield isEventEnabled; + } + else { + yield true; + } + } + case JOL -> { + if (settings.irisChatSettings().disabledProactiveEvents() != null) { + var isEventEnabled = !settings.irisChatSettings().disabledProactiveEvents().contains(IrisEventType.JOL.name().toLowerCase()); + log.debug("Event JOL enabled: {}", isEventEnabled); + yield isEventEnabled; } else { yield true; } } - default -> throw new IllegalStateException("Unexpected value: " + type); // TODO: Add JOL event, once Course Chat Settings are implemented }; } } diff --git a/src/main/java/de/tum/cit/aet/artemis/programming/service/ProgrammingMessagingService.java b/src/main/java/de/tum/cit/aet/artemis/programming/service/ProgrammingMessagingService.java index 7a7861cbcbcc..bff8155d8f1b 100644 --- a/src/main/java/de/tum/cit/aet/artemis/programming/service/ProgrammingMessagingService.java +++ b/src/main/java/de/tum/cit/aet/artemis/programming/service/ProgrammingMessagingService.java @@ -29,7 +29,7 @@ import de.tum.cit.aet.artemis.exercise.repository.ParticipationRepository; import de.tum.cit.aet.artemis.exercise.repository.TeamRepository; import de.tum.cit.aet.artemis.iris.repository.IrisExerciseSettingsRepository; -import de.tum.cit.aet.artemis.iris.service.pyris.PyrisEventService; +import de.tum.cit.aet.artemis.iris.service.pyris.PyrisEventPublisherService; import de.tum.cit.aet.artemis.iris.service.pyris.event.NewResultEvent; import de.tum.cit.aet.artemis.lti.service.LtiNewResultService; import de.tum.cit.aet.artemis.programming.domain.ProgrammingExercise; @@ -56,7 +56,7 @@ public class ProgrammingMessagingService { private final TeamRepository teamRepository; - private final Optional pyrisEventService; + private final Optional pyrisEventPublisher; private final Optional irisExerciseSettingsRepository; @@ -64,7 +64,7 @@ public class ProgrammingMessagingService { public ProgrammingMessagingService(GroupNotificationService groupNotificationService, WebsocketMessagingService websocketMessagingService, ResultWebsocketService resultWebsocketService, Optional ltiNewResultService, TeamRepository teamRepository, - Optional pyrisEventService, Optional irisExerciseSettingsRepository, + Optional pyrisEventPublisher, Optional irisExerciseSettingsRepository, ParticipationRepository participationRepository) { this.groupNotificationService = groupNotificationService; this.websocketMessagingService = websocketMessagingService; @@ -72,8 +72,8 @@ public ProgrammingMessagingService(GroupNotificationService groupNotificationSer this.ltiNewResultService = ltiNewResultService; this.teamRepository = teamRepository; this.irisExerciseSettingsRepository = irisExerciseSettingsRepository; + this.pyrisEventPublisher = pyrisEventPublisher; this.participationRepository = participationRepository; - this.pyrisEventService = pyrisEventService; } private static String getExerciseTopicForTAAndAbove(long exerciseId) { @@ -186,7 +186,8 @@ public void notifyInstructorGroupAboutIllegalSubmissionsForExercise(ProgrammingE * @param participation the participation for which the result was created. */ public void notifyUserAboutNewResult(Result result, ProgrammingExerciseParticipation participation) { - log.debug("Send result to client over websocket. Result: {}, Submission: {}, Participation: {}", result, result.getSubmission(), result.getParticipation()); + var submission = result.getSubmission(); + log.debug("Send result to client over websocket. Result: {}, Submission: {}, Participation: {}", result, submission, submission.getParticipation()); // notify user via websocket resultWebsocketService.broadcastNewResult((Participation) participation, result); @@ -212,13 +213,13 @@ public void notifyUserAboutNewResult(Result result, ProgrammingExerciseParticipa */ private void notifyIrisAboutSubmissionStatus(Result result, ProgrammingExerciseStudentParticipation studentParticipation) { if (studentParticipation.getParticipant() instanceof User user) { - pyrisEventService.ifPresent(eventService -> { + pyrisEventPublisher.ifPresent(eventPublisherService -> { final var exercise = studentParticipation.getExercise(); if (user.hasAcceptedIris() && !exercise.isExamExercise() && irisExerciseSettingsRepository.get().isExerciseChatEnabled(exercise.getId())) { // Inform event service about the new result try { // This is done asynchronously to prevent blocking the current thread - eventService.trigger(new NewResultEvent(result)); + eventPublisherService.publishEvent(new NewResultEvent(this, result)); } catch (Exception e) { log.error("Could not trigger service for result {}", result.getId(), e); diff --git a/src/test/java/de/tum/cit/aet/artemis/iris/PyrisEventSystemIntegrationTest.java b/src/test/java/de/tum/cit/aet/artemis/iris/PyrisEventSystemIntegrationTest.java index 44aa312cc340..0f0e24481a0a 100644 --- a/src/test/java/de/tum/cit/aet/artemis/iris/PyrisEventSystemIntegrationTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/iris/PyrisEventSystemIntegrationTest.java @@ -185,7 +185,7 @@ void testShouldFireProgressStalledEvent() { pipelineDone.set(true); }); - pyrisEventService.trigger(new NewResultEvent(result)); + pyrisEventPublisherService.publishEvent(new NewResultEvent(this, result)); // Wrap the following code into await() to ensure that the pipeline is executed before the test finishes. await().atMost(2, TimeUnit.SECONDS).untilAsserted(() -> verify(irisExerciseChatSessionService, times(1)).onNewResult(eq(result))); @@ -207,7 +207,7 @@ void testShouldFireBuildFailedEvent() { pipelineDone.set(true); }); - pyrisEventService.trigger(new NewResultEvent(result)); + pyrisEventPublisherService.publishEvent(new NewResultEvent(this, result)); await().atMost(2, TimeUnit.SECONDS).untilAsserted(() -> verify(irisExerciseChatSessionService, times(1)).onBuildFailure(eq(result))); @@ -245,7 +245,7 @@ void testShouldNotFireProgressStalledEventWithEventDisabled() { createSubmissionWithScore(studentParticipation, 40); createSubmissionWithScore(studentParticipation, 40); var result = createSubmissionWithScore(studentParticipation, 40); - verify(pyrisEventService, never()).trigger(new NewResultEvent(result)); + verify(pyrisEventPublisherService, never()).publishEvent(new NewResultEvent(this, result)); } @Test @@ -260,7 +260,7 @@ void testShouldNotFireBuildFailedEventWhenEventSettingDisabled() { // Create a failing submission for the student. var result = createFailingSubmission(studentParticipation); // very that the event is not fired - verify(pyrisEventService, never()).trigger(new NewResultEvent(result)); + verify(pyrisEventPublisherService, never()).publishEvent(new NewResultEvent(this, result)); } @Test @@ -274,13 +274,13 @@ void testShouldShouldNotFireProgressStalledEventWithExistingSuccessfulSubmission createSubmissionWithScore(studentParticipation, 100); var result = createSubmissionWithScore(studentParticipation, 50); - pyrisEventService.trigger(new NewResultEvent(result)); + pyrisEventPublisherService.publishEvent(new NewResultEvent(this, result)); await().atMost(2, TimeUnit.SECONDS); result = createSubmissionWithScore(studentParticipation, 50); - pyrisEventService.trigger(new NewResultEvent(result)); + pyrisEventPublisherService.publishEvent(new NewResultEvent(this, result)); await().atMost(2, TimeUnit.SECONDS); await().atMost(2, TimeUnit.SECONDS).untilAsserted(() -> { @@ -297,7 +297,7 @@ void testShouldNotFireProgressStalledEventWithLessThanThreeSubmissions() { createSubmissionWithScore(studentParticipation, 20); var result = createSubmissionWithScore(studentParticipation, 20); - pyrisEventService.trigger(new NewResultEvent(result)); + pyrisEventPublisherService.publishEvent(new NewResultEvent(this, result)); verify(irisExerciseChatSessionService, never()).onNewResult(any(Result.class)); verify(pyrisPipelineService, never()).executeExerciseChatPipeline(any(), any(), any(), any(), any()); @@ -312,7 +312,7 @@ void testShouldNotFireProgressStalledEventWithIncreasingScores() { createSubmissionWithScore(studentParticipation, 30); var result = createSubmissionWithScore(studentParticipation, 40); - pyrisEventService.trigger(new NewResultEvent(result)); + pyrisEventPublisherService.publishEvent(new NewResultEvent(this, result)); verify(irisExerciseChatSessionService, never()).onNewResult(any(Result.class)); verify(pyrisPipelineService, never()).executeExerciseChatPipeline(any(), any(), any(), any(), any()); diff --git a/src/test/java/de/tum/cit/aet/artemis/shared/base/AbstractSpringIntegrationLocalCILocalVCTest.java b/src/test/java/de/tum/cit/aet/artemis/shared/base/AbstractSpringIntegrationLocalCILocalVCTest.java index 2538b01761f7..f7605f46e5cb 100644 --- a/src/test/java/de/tum/cit/aet/artemis/shared/base/AbstractSpringIntegrationLocalCILocalVCTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/shared/base/AbstractSpringIntegrationLocalCILocalVCTest.java @@ -73,7 +73,7 @@ import de.tum.cit.aet.artemis.core.user.util.UserUtilService; import de.tum.cit.aet.artemis.exam.service.ExamLiveEventsService; import de.tum.cit.aet.artemis.exercise.domain.Team; -import de.tum.cit.aet.artemis.iris.service.pyris.PyrisEventService; +import de.tum.cit.aet.artemis.iris.service.pyris.PyrisEventPublisherService; import de.tum.cit.aet.artemis.iris.service.pyris.PyrisPipelineService; import de.tum.cit.aet.artemis.iris.service.session.IrisCourseChatSessionService; import de.tum.cit.aet.artemis.iris.service.session.IrisExerciseChatSessionService; @@ -187,7 +187,7 @@ public abstract class AbstractSpringIntegrationLocalCILocalVCTest extends Abstra protected IrisExerciseChatSessionService irisExerciseChatSessionService; @MockitoSpyBean - protected PyrisEventService pyrisEventService; + protected PyrisEventPublisherService pyrisEventPublisherService; @Value("${artemis.version-control.url}") protected URL localVCBaseUrl;