From bb052261a269580a37af6f463f56d0596b7977b1 Mon Sep 17 00:00:00 2001 From: Timor Morrien Date: Tue, 10 Dec 2024 14:10:48 +0100 Subject: [PATCH] Iris: Add course chat settings (#9866) --- build.gradle | 2 +- .../settings/IrisCourseChatSubSettings.java | 44 +++++ .../domain/settings/IrisCourseSettings.java | 14 ++ .../domain/settings/IrisExerciseSettings.java | 11 ++ .../domain/settings/IrisGlobalSettings.java | 14 ++ .../iris/domain/settings/IrisSettings.java | 4 + .../iris/domain/settings/IrisSubSettings.java | 1 + .../domain/settings/IrisSubSettingsType.java | 4 +- .../IrisCombinedCourseChatSubSettingsDTO.java | 13 ++ .../iris/dto/IrisCombinedSettingsDTO.java | 1 + .../session/IrisCourseChatSessionService.java | 8 +- .../service/settings/IrisSettingsService.java | 158 ++++++++++-------- .../settings/IrisSubSettingsService.java | 66 +++++++- .../web/IrisCourseChatSessionResource.java | 2 +- .../changelog/20241119191919_changelog.xml | 18 ++ .../resources/config/liquibase/master.xml | 1 + .../manage/detail/course-detail.component.ts | 1 + .../iris/settings/iris-settings.model.ts | 4 + .../iris/settings/iris-sub-settings.model.ts | 11 +- ...is-common-sub-settings-update.component.ts | 2 +- .../iris-settings-update.component.html | 21 ++- .../iris-settings-update.component.ts | 4 + .../settings/shared/iris-enabled.component.ts | 6 + .../course-dashboard.component.ts | 2 +- src/main/webapp/i18n/de/iris.json | 1 + src/main/webapp/i18n/en/iris.json | 1 + .../iris/AbstractIrisIntegrationTest.java | 9 +- .../settings/IrisSettingsIntegrationTest.java | 31 +++- ...s-course-settings-update.component.spec.ts | 5 +- ...s-global-settings-update.component.spec.ts | 2 +- .../component/iris/settings/mock-settings.ts | 5 + 31 files changed, 368 insertions(+), 98 deletions(-) create mode 100644 src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisCourseChatSubSettings.java create mode 100644 src/main/java/de/tum/cit/aet/artemis/iris/dto/IrisCombinedCourseChatSubSettingsDTO.java create mode 100644 src/main/resources/config/liquibase/changelog/20241119191919_changelog.xml diff --git a/build.gradle b/build.gradle index 27099c72db3d..4baffa384852 100644 --- a/build.gradle +++ b/build.gradle @@ -80,7 +80,7 @@ spotless { } } importOrderFile "artemis-spotless.importorder" - eclipse("4.28").configFile "artemis-spotless-style.xml" + eclipse("4.33").configFile "artemis-spotless-style.xml" removeUnusedImports() trimTrailingWhitespace() diff --git a/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisCourseChatSubSettings.java b/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisCourseChatSubSettings.java new file mode 100644 index 000000000000..7428f7feb3b3 --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisCourseChatSubSettings.java @@ -0,0 +1,44 @@ +package de.tum.cit.aet.artemis.iris.domain.settings; + +import jakarta.annotation.Nullable; +import jakarta.persistence.Column; +import jakarta.persistence.DiscriminatorValue; +import jakarta.persistence.Entity; + +import com.fasterxml.jackson.annotation.JsonInclude; + +/** + * An {@link IrisSubSettings} implementation for course chat settings. + * Chat settings notably provide settings for the rate limit. + */ +@Entity +@DiscriminatorValue("COURSE_CHAT") +@JsonInclude(JsonInclude.Include.NON_EMPTY) +public class IrisCourseChatSubSettings extends IrisSubSettings { + + @Nullable + @Column(name = "rate_limit") + private Integer rateLimit; + + @Nullable + @Column(name = "rate_limit_timeframe_hours") + private Integer rateLimitTimeframeHours; + + @Nullable + public Integer getRateLimit() { + return rateLimit; + } + + public void setRateLimit(@Nullable Integer rateLimit) { + this.rateLimit = rateLimit; + } + + @Nullable + public Integer getRateLimitTimeframeHours() { + return rateLimitTimeframeHours; + } + + public void setRateLimitTimeframeHours(@Nullable Integer rateLimitTimeframeHours) { + this.rateLimitTimeframeHours = rateLimitTimeframeHours; + } +} diff --git a/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisCourseSettings.java b/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisCourseSettings.java index fce389a7b95f..8320f2b6d708 100644 --- a/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisCourseSettings.java +++ b/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisCourseSettings.java @@ -32,6 +32,10 @@ public class IrisCourseSettings extends IrisSettings { @JoinColumn(name = "iris_text_exercise_chat_settings_id") private IrisTextExerciseChatSubSettings irisTextExerciseChatSettings; + @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, optional = false) + @JoinColumn(name = "iris_course_chat_settings_id") + private IrisCourseChatSubSettings irisCourseChatSettings; + @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) @JoinColumn(name = "iris_lecture_ingestion_settings_id") private IrisLectureIngestionSubSettings irisLectureIngestionSettings; @@ -78,6 +82,16 @@ public void setIrisTextExerciseChatSettings(IrisTextExerciseChatSubSettings iris this.irisTextExerciseChatSettings = irisTextExerciseChatSettings; } + @Override + public IrisCourseChatSubSettings getIrisCourseChatSettings() { + return irisCourseChatSettings; + } + + @Override + public void setIrisCourseChatSettings(IrisCourseChatSubSettings irisCourseChatSettings) { + this.irisCourseChatSettings = irisCourseChatSettings; + } + @Override public IrisCompetencyGenerationSubSettings getIrisCompetencyGenerationSettings() { return irisCompetencyGenerationSettings; diff --git a/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisExerciseSettings.java b/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisExerciseSettings.java index ba095a018808..8048a76e976b 100644 --- a/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisExerciseSettings.java +++ b/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisExerciseSettings.java @@ -69,6 +69,17 @@ public void setIrisTextExerciseChatSettings(IrisTextExerciseChatSubSettings iris this.irisTextExerciseChatSettings = irisTextExerciseChatSettings; } + @Override + public IrisCourseChatSubSettings getIrisCourseChatSettings() { + // Empty because exercises don't have course chat settings + return null; + } + + @Override + public void setIrisCourseChatSettings(IrisCourseChatSubSettings irisCourseChatSettings) { + // Empty because exercises don't have course chat settings + } + @Override public IrisCompetencyGenerationSubSettings getIrisCompetencyGenerationSettings() { return null; diff --git a/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisGlobalSettings.java b/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisGlobalSettings.java index ddb156da0038..5531f65584ff 100644 --- a/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisGlobalSettings.java +++ b/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisGlobalSettings.java @@ -27,6 +27,10 @@ public class IrisGlobalSettings extends IrisSettings { @JoinColumn(name = "iris_text_exercise_chat_settings_id") private IrisTextExerciseChatSubSettings irisTextExerciseChatSettings; + @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, optional = false) + @JoinColumn(name = "iris_course_chat_settings_id") + private IrisCourseChatSubSettings irisCourseChatSettings; + @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, optional = false) @JoinColumn(name = "iris_lecture_ingestion_settings_id") private IrisLectureIngestionSubSettings irisLectureIngestionSettings; @@ -65,6 +69,16 @@ public void setIrisTextExerciseChatSettings(IrisTextExerciseChatSubSettings iris this.irisTextExerciseChatSettings = irisTextExerciseChatSettings; } + @Override + public IrisCourseChatSubSettings getIrisCourseChatSettings() { + return irisCourseChatSettings; + } + + @Override + public void setIrisCourseChatSettings(IrisCourseChatSubSettings irisCourseChatSettings) { + this.irisCourseChatSettings = irisCourseChatSettings; + } + @Override public IrisCompetencyGenerationSubSettings getIrisCompetencyGenerationSettings() { return irisCompetencyGenerationSettings; diff --git a/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisSettings.java b/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisSettings.java index 61b2912d5cf6..d67d49caeab0 100644 --- a/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisSettings.java +++ b/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisSettings.java @@ -49,6 +49,10 @@ public abstract class IrisSettings extends DomainObject { public abstract void setIrisTextExerciseChatSettings(IrisTextExerciseChatSubSettings irisTextExerciseChatSettings); + public abstract IrisCourseChatSubSettings getIrisCourseChatSettings(); + + public abstract void setIrisCourseChatSettings(IrisCourseChatSubSettings irisCourseChatSettings); + public abstract IrisLectureIngestionSubSettings getIrisLectureIngestionSettings(); public abstract void setIrisLectureIngestionSettings(IrisLectureIngestionSubSettings irisLectureIngestionSettings); diff --git a/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisSubSettings.java b/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisSubSettings.java index c9fc576311db..86e77fc9c034 100644 --- a/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisSubSettings.java +++ b/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisSubSettings.java @@ -40,6 +40,7 @@ @JsonSubTypes({ @JsonSubTypes.Type(value = IrisChatSubSettings.class, name = "chat"), @JsonSubTypes.Type(value = IrisTextExerciseChatSubSettings.class, name = "text-exercise-chat"), + @JsonSubTypes.Type(value = IrisCourseChatSubSettings.class, name = "course-chat"), @JsonSubTypes.Type(value = IrisLectureIngestionSubSettings.class, name = "lecture-ingestion"), @JsonSubTypes.Type(value = IrisCompetencyGenerationSubSettings.class, name = "competency-generation") }) diff --git a/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisSubSettingsType.java b/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisSubSettingsType.java index dafdd1edcfb9..fe3561f12c2a 100644 --- a/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisSubSettingsType.java +++ b/src/main/java/de/tum/cit/aet/artemis/iris/domain/settings/IrisSubSettingsType.java @@ -1,6 +1,6 @@ package de.tum.cit.aet.artemis.iris.domain.settings; public enum IrisSubSettingsType { - CHAT, // TODO: Split into PROGRAMMING_EXERCISE_CHAT and COURSE_CHAT - TEXT_EXERCISE_CHAT, COMPETENCY_GENERATION, LECTURE_INGESTION + CHAT, // TODO: Rename to PROGRAMMING_EXERCISE_CHAT + TEXT_EXERCISE_CHAT, COURSE_CHAT, COMPETENCY_GENERATION, LECTURE_INGESTION } diff --git a/src/main/java/de/tum/cit/aet/artemis/iris/dto/IrisCombinedCourseChatSubSettingsDTO.java b/src/main/java/de/tum/cit/aet/artemis/iris/dto/IrisCombinedCourseChatSubSettingsDTO.java new file mode 100644 index 000000000000..3c1cf365763d --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/iris/dto/IrisCombinedCourseChatSubSettingsDTO.java @@ -0,0 +1,13 @@ +package de.tum.cit.aet.artemis.iris.dto; + +import java.util.SortedSet; + +import jakarta.annotation.Nullable; + +import com.fasterxml.jackson.annotation.JsonInclude; + +@JsonInclude(JsonInclude.Include.NON_EMPTY) +public record IrisCombinedCourseChatSubSettingsDTO(boolean enabled, Integer rateLimit, Integer rateLimitTimeframeHours, @Nullable SortedSet allowedVariants, + @Nullable String selectedVariant) { + +} diff --git a/src/main/java/de/tum/cit/aet/artemis/iris/dto/IrisCombinedSettingsDTO.java b/src/main/java/de/tum/cit/aet/artemis/iris/dto/IrisCombinedSettingsDTO.java index b05645603dbe..294f2e836140 100644 --- a/src/main/java/de/tum/cit/aet/artemis/iris/dto/IrisCombinedSettingsDTO.java +++ b/src/main/java/de/tum/cit/aet/artemis/iris/dto/IrisCombinedSettingsDTO.java @@ -7,6 +7,7 @@ public record IrisCombinedSettingsDTO( IrisCombinedChatSubSettingsDTO irisChatSettings, IrisCombinedTextExerciseChatSubSettingsDTO irisTextExerciseChatSettings, + IrisCombinedCourseChatSubSettingsDTO irisCourseChatSettings, IrisCombinedLectureIngestionSubSettingsDTO irisLectureIngestionSettings, IrisCombinedCompetencyGenerationSubSettingsDTO irisCompetencyGenerationSettings ) {} 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 d2743c2e71a5..7e6693991430 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 @@ -90,7 +90,7 @@ public void checkHasAccessTo(User user, IrisCourseChatSession session) { */ @Override public void checkIsFeatureActivatedFor(IrisCourseChatSession session) { - irisSettingsService.isEnabledForElseThrow(IrisSubSettingsType.CHAT, session.getCourse()); + irisSettingsService.isEnabledForElseThrow(IrisSubSettingsType.COURSE_CHAT, session.getCourse()); } @Override @@ -134,7 +134,7 @@ protected void setLLMTokenUsageParameters(LLMTokenUsageService.LLMTokenUsageBuil */ public void onJudgementOfLearningSet(CompetencyJol competencyJol) { var course = competencyJol.getCompetency().getCourse(); - if (!irisSettingsService.isEnabledFor(IrisSubSettingsType.CHAT, course)) { + if (!irisSettingsService.isEnabledFor(IrisSubSettingsType.COURSE_CHAT, course)) { return; } var user = competencyJol.getUser(); @@ -154,7 +154,7 @@ public void onJudgementOfLearningSet(CompetencyJol competencyJol) { */ public IrisCourseChatSession getCurrentSessionOrCreateIfNotExists(Course course, User user, boolean sendInitialMessageIfCreated) { user.hasAcceptedIrisElseThrow(); - irisSettingsService.isEnabledForElseThrow(IrisSubSettingsType.CHAT, course); + irisSettingsService.isEnabledForElseThrow(IrisSubSettingsType.COURSE_CHAT, course); return getCurrentSessionOrCreateIfNotExistsInternal(course, user, sendInitialMessageIfCreated); } @@ -184,7 +184,7 @@ private IrisCourseChatSession getCurrentSessionOrCreateIfNotExistsInternal(Cours */ public IrisCourseChatSession createSession(Course course, User user, boolean sendInitialMessage) { user.hasAcceptedIrisElseThrow(); - irisSettingsService.isEnabledForElseThrow(IrisSubSettingsType.CHAT, course); + irisSettingsService.isEnabledForElseThrow(IrisSubSettingsType.COURSE_CHAT, course); return createSessionInternal(course, user, sendInitialMessage); } 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 6047631fb5bf..d286def04e19 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 @@ -32,6 +32,7 @@ import de.tum.cit.aet.artemis.exercise.domain.Exercise; import de.tum.cit.aet.artemis.iris.domain.settings.IrisChatSubSettings; import de.tum.cit.aet.artemis.iris.domain.settings.IrisCompetencyGenerationSubSettings; +import de.tum.cit.aet.artemis.iris.domain.settings.IrisCourseChatSubSettings; import de.tum.cit.aet.artemis.iris.domain.settings.IrisCourseSettings; import de.tum.cit.aet.artemis.iris.domain.settings.IrisExerciseSettings; import de.tum.cit.aet.artemis.iris.domain.settings.IrisGlobalSettings; @@ -107,6 +108,7 @@ private void createInitialGlobalSettings() { initializeIrisChatSettings(settings); initializeIrisTextExerciseChatSettings(settings); + initializeIrisCourseChatSettings(settings); initializeIrisLectureIngestionSettings(settings); initializeIrisCompetencyGenerationSettings(settings); @@ -135,6 +137,12 @@ private void initializeIrisTextExerciseChatSettings(IrisGlobalSettings settings) settings.setIrisTextExerciseChatSettings(irisChatSettings); } + private void initializeIrisCourseChatSettings(IrisGlobalSettings settings) { + var irisChatSettings = settings.getIrisCourseChatSettings(); + irisChatSettings = initializeSettings(irisChatSettings, IrisCourseChatSubSettings::new); + settings.setIrisCourseChatSettings(irisChatSettings); + } + private void initializeIrisLectureIngestionSettings(IrisGlobalSettings settings) { var irisLectureIngestionSettings = settings.getIrisLectureIngestionSettings(); irisLectureIngestionSettings = initializeSettings(irisLectureIngestionSettings, IrisLectureIngestionSubSettings::new); @@ -207,18 +215,15 @@ private T updateIrisSettings(long existingSettingsId, T var existingSettings = irisSettingsRepository.findByIdElseThrow(existingSettingsId); - if (existingSettings instanceof IrisGlobalSettings globalSettings && settingsUpdate instanceof IrisGlobalSettings globalSettingsUpdate) { - return (T) updateGlobalSettings(globalSettings, globalSettingsUpdate); - } - else if (existingSettings instanceof IrisCourseSettings courseSettings && settingsUpdate instanceof IrisCourseSettings courseSettingsUpdate) { - return (T) updateCourseSettings(courseSettings, courseSettingsUpdate); - } - else if (existingSettings instanceof IrisExerciseSettings exerciseSettings && settingsUpdate instanceof IrisExerciseSettings exerciseSettingsUpdate) { - return (T) updateExerciseSettings(exerciseSettings, exerciseSettingsUpdate); - } - else { - throw new BadRequestAlertException("Unknown Iris settings type", "IrisSettings", "unknownType"); - } + return switch (existingSettings) { + case IrisGlobalSettings globalSettings when settingsUpdate instanceof IrisGlobalSettings globalSettingsUpdate -> + (T) updateGlobalSettings(globalSettings, globalSettingsUpdate); + case IrisCourseSettings courseSettings when settingsUpdate instanceof IrisCourseSettings courseSettingsUpdate -> + (T) updateCourseSettings(courseSettings, courseSettingsUpdate); + case IrisExerciseSettings exerciseSettings when settingsUpdate instanceof IrisExerciseSettings exerciseSettingsUpdate -> + (T) updateExerciseSettings(exerciseSettings, exerciseSettingsUpdate); + case null, default -> throw new BadRequestAlertException("Unknown Iris settings type", "IrisSettings", "unknownType"); + }; } /** @@ -230,29 +235,35 @@ else if (existingSettings instanceof IrisExerciseSettings exerciseSettings && se */ private IrisGlobalSettings updateGlobalSettings(IrisGlobalSettings existingSettings, IrisGlobalSettings settingsUpdate) { // @formatter:off - existingSettings.setIrisLectureIngestionSettings(irisSubSettingsService.update( - existingSettings.getIrisLectureIngestionSettings(), - settingsUpdate.getIrisLectureIngestionSettings(), - null, - GLOBAL + existingSettings.setIrisChatSettings(irisSubSettingsService.update( + existingSettings.getIrisChatSettings(), + settingsUpdate.getIrisChatSettings(), + null, + GLOBAL )); existingSettings.setIrisTextExerciseChatSettings(irisSubSettingsService.update( - existingSettings.getIrisTextExerciseChatSettings(), - settingsUpdate.getIrisTextExerciseChatSettings(), - null, - GLOBAL + existingSettings.getIrisTextExerciseChatSettings(), + settingsUpdate.getIrisTextExerciseChatSettings(), + null, + GLOBAL )); - existingSettings.setIrisChatSettings(irisSubSettingsService.update( - existingSettings.getIrisChatSettings(), - settingsUpdate.getIrisChatSettings(), - null, - GLOBAL + existingSettings.setIrisCourseChatSettings(irisSubSettingsService.update( + existingSettings.getIrisCourseChatSettings(), + settingsUpdate.getIrisCourseChatSettings(), + null, + GLOBAL + )); + existingSettings.setIrisLectureIngestionSettings(irisSubSettingsService.update( + existingSettings.getIrisLectureIngestionSettings(), + settingsUpdate.getIrisLectureIngestionSettings(), + null, + GLOBAL )); existingSettings.setIrisCompetencyGenerationSettings(irisSubSettingsService.update( - existingSettings.getIrisCompetencyGenerationSettings(), - settingsUpdate.getIrisCompetencyGenerationSettings(), - null, - GLOBAL + existingSettings.getIrisCompetencyGenerationSettings(), + settingsUpdate.getIrisCompetencyGenerationSettings(), + null, + GLOBAL )); // @formatter:on @@ -275,28 +286,34 @@ private IrisCourseSettings updateCourseSettings(IrisCourseSettings existingSetti var parentSettings = getCombinedIrisGlobalSettings(); // @formatter:off existingSettings.setIrisChatSettings(irisSubSettingsService.update( - existingSettings.getIrisChatSettings(), - settingsUpdate.getIrisChatSettings(), - parentSettings.irisChatSettings(), - COURSE + existingSettings.getIrisChatSettings(), + settingsUpdate.getIrisChatSettings(), + parentSettings.irisChatSettings(), + COURSE )); existingSettings.setIrisTextExerciseChatSettings(irisSubSettingsService.update( - existingSettings.getIrisTextExerciseChatSettings(), - settingsUpdate.getIrisTextExerciseChatSettings(), - parentSettings.irisTextExerciseChatSettings(), - COURSE + existingSettings.getIrisTextExerciseChatSettings(), + settingsUpdate.getIrisTextExerciseChatSettings(), + parentSettings.irisTextExerciseChatSettings(), + COURSE + )); + existingSettings.setIrisCourseChatSettings(irisSubSettingsService.update( + existingSettings.getIrisCourseChatSettings(), + settingsUpdate.getIrisCourseChatSettings(), + parentSettings.irisCourseChatSettings(), + COURSE )); existingSettings.setIrisLectureIngestionSettings(irisSubSettingsService.update( - existingSettings.getIrisLectureIngestionSettings(), - settingsUpdate.getIrisLectureIngestionSettings(), - parentSettings.irisLectureIngestionSettings(), - COURSE + existingSettings.getIrisLectureIngestionSettings(), + settingsUpdate.getIrisLectureIngestionSettings(), + parentSettings.irisLectureIngestionSettings(), + COURSE )); existingSettings.setIrisCompetencyGenerationSettings(irisSubSettingsService.update( - existingSettings.getIrisCompetencyGenerationSettings(), - settingsUpdate.getIrisCompetencyGenerationSettings(), - parentSettings.irisCompetencyGenerationSettings(), - COURSE + existingSettings.getIrisCompetencyGenerationSettings(), + settingsUpdate.getIrisCompetencyGenerationSettings(), + parentSettings.irisCompetencyGenerationSettings(), + COURSE )); // @formatter:on @@ -430,16 +447,16 @@ private IrisExerciseSettings updateExerciseSettings(IrisExerciseSettings existin var parentSettings = getCombinedIrisSettingsFor(existingSettings.getExercise().getCourseViaExerciseGroupOrCourseMember(), false); // @formatter:off existingSettings.setIrisChatSettings(irisSubSettingsService.update( - existingSettings.getIrisChatSettings(), - settingsUpdate.getIrisChatSettings(), - parentSettings.irisChatSettings(), - EXERCISE + existingSettings.getIrisChatSettings(), + settingsUpdate.getIrisChatSettings(), + parentSettings.irisChatSettings(), + EXERCISE )); existingSettings.setIrisTextExerciseChatSettings(irisSubSettingsService.update( - existingSettings.getIrisTextExerciseChatSettings(), - settingsUpdate.getIrisTextExerciseChatSettings(), - parentSettings.irisTextExerciseChatSettings(), - EXERCISE + existingSettings.getIrisTextExerciseChatSettings(), + settingsUpdate.getIrisTextExerciseChatSettings(), + parentSettings.irisTextExerciseChatSettings(), + EXERCISE )); // @formatter:on return irisSettingsRepository.save(existingSettings); @@ -507,10 +524,11 @@ public IrisCombinedSettingsDTO getCombinedIrisGlobalSettings() { // @formatter:off return new IrisCombinedSettingsDTO( - irisSubSettingsService.combineChatSettings(settingsList, false), - irisSubSettingsService.combineTextExerciseChatSettings(settingsList, false), - irisSubSettingsService.combineLectureIngestionSubSettings(settingsList, false), - irisSubSettingsService.combineCompetencyGenerationSettings(settingsList, false) + irisSubSettingsService.combineChatSettings(settingsList, false), + irisSubSettingsService.combineTextExerciseChatSettings(settingsList, false), + irisSubSettingsService.combineCourseChatSettings(settingsList, false), + irisSubSettingsService.combineLectureIngestionSubSettings(settingsList, false), + irisSubSettingsService.combineCompetencyGenerationSettings(settingsList, false) ); // @formatter:on } @@ -532,10 +550,11 @@ public IrisCombinedSettingsDTO getCombinedIrisSettingsFor(Course course, boolean // @formatter:off return new IrisCombinedSettingsDTO( - irisSubSettingsService.combineChatSettings(settingsList, minimal), - irisSubSettingsService.combineTextExerciseChatSettings(settingsList, minimal), - irisSubSettingsService.combineLectureIngestionSubSettings(settingsList, minimal), - irisSubSettingsService.combineCompetencyGenerationSettings(settingsList, minimal) + irisSubSettingsService.combineChatSettings(settingsList, minimal), + irisSubSettingsService.combineTextExerciseChatSettings(settingsList, minimal), + irisSubSettingsService.combineCourseChatSettings(settingsList, minimal), + irisSubSettingsService.combineLectureIngestionSubSettings(settingsList, minimal), + irisSubSettingsService.combineCompetencyGenerationSettings(settingsList, minimal) ); // @formatter:on } @@ -558,10 +577,11 @@ public IrisCombinedSettingsDTO getCombinedIrisSettingsFor(Exercise exercise, boo // @formatter:off return new IrisCombinedSettingsDTO( - irisSubSettingsService.combineChatSettings(settingsList, minimal), - irisSubSettingsService.combineTextExerciseChatSettings(settingsList, minimal), - irisSubSettingsService.combineLectureIngestionSubSettings(settingsList, minimal), - irisSubSettingsService.combineCompetencyGenerationSettings(settingsList, minimal) + irisSubSettingsService.combineChatSettings(settingsList, minimal), + irisSubSettingsService.combineTextExerciseChatSettings(settingsList, minimal), + irisSubSettingsService.combineCourseChatSettings(settingsList, minimal), + irisSubSettingsService.combineLectureIngestionSubSettings(settingsList, minimal), + irisSubSettingsService.combineCompetencyGenerationSettings(settingsList, minimal) ); // @formatter:on } @@ -587,10 +607,11 @@ public boolean shouldShowMinimalSettings(Exercise exercise, User user) { public IrisCourseSettings getDefaultSettingsFor(Course course) { var settings = new IrisCourseSettings(); settings.setCourse(course); - settings.setIrisLectureIngestionSettings(new IrisLectureIngestionSubSettings()); settings.setIrisChatSettings(new IrisChatSubSettings()); - settings.setIrisCompetencyGenerationSettings(new IrisCompetencyGenerationSubSettings()); settings.setIrisTextExerciseChatSettings(new IrisTextExerciseChatSubSettings()); + settings.setIrisCourseChatSettings(new IrisCourseChatSubSettings()); + settings.setIrisLectureIngestionSettings(new IrisLectureIngestionSubSettings()); + settings.setIrisCompetencyGenerationSettings(new IrisCompetencyGenerationSubSettings()); return settings; } @@ -664,6 +685,7 @@ private boolean isFeatureEnabledInSettings(IrisCombinedSettingsDTO settings, Iri return switch (type) { case CHAT -> settings.irisChatSettings().enabled(); case TEXT_EXERCISE_CHAT -> settings.irisTextExerciseChatSettings().enabled(); + case COURSE_CHAT -> settings.irisCourseChatSettings().enabled(); case COMPETENCY_GENERATION -> settings.irisCompetencyGenerationSettings().enabled(); case LECTURE_INGESTION -> settings.irisLectureIngestionSettings().enabled(); }; diff --git a/src/main/java/de/tum/cit/aet/artemis/iris/service/settings/IrisSubSettingsService.java b/src/main/java/de/tum/cit/aet/artemis/iris/service/settings/IrisSubSettingsService.java index 2c284b6ea1f8..c6c17601e5af 100644 --- a/src/main/java/de/tum/cit/aet/artemis/iris/service/settings/IrisSubSettingsService.java +++ b/src/main/java/de/tum/cit/aet/artemis/iris/service/settings/IrisSubSettingsService.java @@ -17,6 +17,7 @@ import de.tum.cit.aet.artemis.core.service.AuthorizationCheckService; import de.tum.cit.aet.artemis.iris.domain.settings.IrisChatSubSettings; import de.tum.cit.aet.artemis.iris.domain.settings.IrisCompetencyGenerationSubSettings; +import de.tum.cit.aet.artemis.iris.domain.settings.IrisCourseChatSubSettings; import de.tum.cit.aet.artemis.iris.domain.settings.IrisCourseSettings; import de.tum.cit.aet.artemis.iris.domain.settings.IrisExerciseSettings; import de.tum.cit.aet.artemis.iris.domain.settings.IrisLectureIngestionSubSettings; @@ -26,6 +27,7 @@ import de.tum.cit.aet.artemis.iris.domain.settings.IrisTextExerciseChatSubSettings; import de.tum.cit.aet.artemis.iris.dto.IrisCombinedChatSubSettingsDTO; import de.tum.cit.aet.artemis.iris.dto.IrisCombinedCompetencyGenerationSubSettingsDTO; +import de.tum.cit.aet.artemis.iris.dto.IrisCombinedCourseChatSubSettingsDTO; import de.tum.cit.aet.artemis.iris.dto.IrisCombinedLectureIngestionSubSettingsDTO; import de.tum.cit.aet.artemis.iris.dto.IrisCombinedTextExerciseChatSubSettingsDTO; @@ -123,6 +125,37 @@ public IrisTextExerciseChatSubSettings update(IrisTextExerciseChatSubSettings cu return currentSettings; } + /** + * Updates a course chat sub settings object. + * + * @param currentSettings Current chat sub settings. + * @param newSettings Updated chat sub settings. + * @param parentSettings Parent chat sub settings. + * @param settingsType Type of the settings the sub settings belong to. + * @return Updated chat sub settings. + */ + public IrisCourseChatSubSettings update(IrisCourseChatSubSettings currentSettings, IrisCourseChatSubSettings newSettings, IrisCombinedCourseChatSubSettingsDTO parentSettings, + IrisSettingsType settingsType) { + if (newSettings == null) { + if (parentSettings == null) { + throw new IllegalArgumentException("Cannot delete the course chat settings"); + } + return null; + } + if (currentSettings == null) { + currentSettings = new IrisCourseChatSubSettings(); + } + if (authCheckService.isAdmin()) { + currentSettings.setEnabled(newSettings.isEnabled()); + currentSettings.setRateLimit(newSettings.getRateLimit()); + currentSettings.setRateLimitTimeframeHours(newSettings.getRateLimitTimeframeHours()); + } + currentSettings.setAllowedVariants(selectAllowedVariants(currentSettings.getAllowedVariants(), newSettings.getAllowedVariants())); + currentSettings.setSelectedVariant(validateSelectedVariant(currentSettings.getSelectedVariant(), newSettings.getSelectedVariant(), currentSettings.getAllowedVariants(), + parentSettings != null ? parentSettings.allowedVariants() : null)); + return currentSettings; + } + /** * Updates a Lecture Ingestion sub settings object. * If the new settings are null, the current settings will be deleted (except if the parent settings are null == if the settings are global). @@ -224,6 +257,24 @@ private String validateSelectedVariant(String selectedVariant, String newSelecte return selectedVariant; } + /** + * Combines the chat settings of multiple {@link IrisSettings} objects. + * If minimal is true, the returned object will only contain the enabled and rateLimit fields. + * The minimal version can safely be sent to students. + * + * @param settingsList List of {@link IrisSettings} objects to combine. + * @param minimal Whether to return a minimal version of the combined settings. + * @return Combined chat settings. + */ + public IrisCombinedChatSubSettingsDTO combineChatSettings(ArrayList settingsList, boolean minimal) { + var enabled = getCombinedEnabled(settingsList, IrisSettings::getIrisChatSettings); + var rateLimit = getCombinedRateLimit(settingsList); + var allowedVariants = !minimal ? getCombinedAllowedVariants(settingsList, IrisSettings::getIrisChatSettings) : null; + var selectedVariant = !minimal ? getCombinedSelectedVariant(settingsList, IrisSettings::getIrisChatSettings) : null; + var enabledForCategories = !minimal ? getCombinedEnabledForCategories(settingsList, IrisSettings::getIrisChatSettings) : null; + return new IrisCombinedChatSubSettingsDTO(enabled, rateLimit, null, allowedVariants, selectedVariant, enabledForCategories); + } + /** * Combines the chat settings of multiple {@link IrisSettings} objects. * If minimal is true, the returned object will only contain the enabled and rateLimit fields. @@ -251,13 +302,12 @@ public IrisCombinedTextExerciseChatSubSettingsDTO combineTextExerciseChatSetting * @param minimal Whether to return a minimal version of the combined settings. * @return Combined chat settings. */ - public IrisCombinedChatSubSettingsDTO combineChatSettings(ArrayList settingsList, boolean minimal) { - var enabled = getCombinedEnabled(settingsList, IrisSettings::getIrisChatSettings); + public IrisCombinedCourseChatSubSettingsDTO combineCourseChatSettings(ArrayList settingsList, boolean minimal) { + var enabled = getCombinedEnabled(settingsList, IrisSettings::getIrisCourseChatSettings); var rateLimit = getCombinedRateLimit(settingsList); var allowedVariants = !minimal ? getCombinedAllowedVariants(settingsList, IrisSettings::getIrisChatSettings) : null; var selectedVariant = !minimal ? getCombinedSelectedVariant(settingsList, IrisSettings::getIrisChatSettings) : null; - var enabledForCategories = !minimal ? getCombinedEnabledForCategories(settingsList, IrisSettings::getIrisChatSettings) : null; - return new IrisCombinedChatSubSettingsDTO(enabled, rateLimit, null, allowedVariants, selectedVariant, enabledForCategories); + return new IrisCombinedCourseChatSubSettingsDTO(enabled, rateLimit, null, allowedVariants, selectedVariant); } /** @@ -350,6 +400,14 @@ private String getCombinedSelectedVariant(List settingsList, Funct .filter(model -> model != null && !model.isBlank()).reduce((first, second) -> second).orElse(null); } + /** + * Combines the enabledForCategories field of multiple {@link IrisSettings} objects. + * Simply &&s all enabledForCategories fields together. + * + * @param settingsList List of {@link IrisSettings} objects to combine. + * @param subSettingsFunction Function to get the sub settings from an IrisSettings object. + * @return Combined enabledForCategories field. + */ private SortedSet getCombinedEnabledForCategories(List settingsList, Function subSettingsFunction) { return settingsList.stream().filter(Objects::nonNull).filter(settings -> settings instanceof IrisCourseSettings).map(subSettingsFunction).filter(Objects::nonNull) .map(IrisChatSubSettings::getEnabledForCategories).filter(Objects::nonNull).filter(models -> !models.isEmpty()).reduce((first, second) -> second) diff --git a/src/main/java/de/tum/cit/aet/artemis/iris/web/IrisCourseChatSessionResource.java b/src/main/java/de/tum/cit/aet/artemis/iris/web/IrisCourseChatSessionResource.java index 13c7a1b5894d..583776c922c7 100644 --- a/src/main/java/de/tum/cit/aet/artemis/iris/web/IrisCourseChatSessionResource.java +++ b/src/main/java/de/tum/cit/aet/artemis/iris/web/IrisCourseChatSessionResource.java @@ -91,7 +91,7 @@ public ResponseEntity getCurrentSessionOrCreateIfNotExist public ResponseEntity> getAllSessions(@PathVariable Long courseId) { var course = courseRepository.findByIdElseThrow(courseId); - irisSettingsService.isEnabledForElseThrow(IrisSubSettingsType.CHAT, course); + irisSettingsService.isEnabledForElseThrow(IrisSubSettingsType.COURSE_CHAT, course); var user = userRepository.getUserWithGroupsAndAuthorities(); user.hasAcceptedIrisElseThrow(); diff --git a/src/main/resources/config/liquibase/changelog/20241119191919_changelog.xml b/src/main/resources/config/liquibase/changelog/20241119191919_changelog.xml new file mode 100644 index 000000000000..4ad2d701458c --- /dev/null +++ b/src/main/resources/config/liquibase/changelog/20241119191919_changelog.xml @@ -0,0 +1,18 @@ + + + + + + + + + + diff --git a/src/main/resources/config/liquibase/master.xml b/src/main/resources/config/liquibase/master.xml index 4f682ca9b8e0..a2f522a1674c 100644 --- a/src/main/resources/config/liquibase/master.xml +++ b/src/main/resources/config/liquibase/master.xml @@ -38,6 +38,7 @@ + diff --git a/src/main/webapp/app/course/manage/detail/course-detail.component.ts b/src/main/webapp/app/course/manage/detail/course-detail.component.ts index 515b1b37e291..d61213a17626 100644 --- a/src/main/webapp/app/course/manage/detail/course-detail.component.ts +++ b/src/main/webapp/app/course/manage/detail/course-detail.component.ts @@ -92,6 +92,7 @@ export class CourseDetailComponent implements OnInit, OnDestroy { this.irisEnabled = profileInfo?.activeProfiles.includes(PROFILE_IRIS); if (this.irisEnabled) { const irisSettings = await firstValueFrom(this.irisSettingsService.getGlobalSettings()); + // TODO: Outdated, as we now have a bunch more sub settings this.irisChatEnabled = irisSettings?.irisChatSettings?.enabled ?? false; } this.route.data.subscribe(({ course }) => { diff --git a/src/main/webapp/app/entities/iris/settings/iris-settings.model.ts b/src/main/webapp/app/entities/iris/settings/iris-settings.model.ts index 2bc612cde7b0..270a2d5132e9 100644 --- a/src/main/webapp/app/entities/iris/settings/iris-settings.model.ts +++ b/src/main/webapp/app/entities/iris/settings/iris-settings.model.ts @@ -2,6 +2,7 @@ import { BaseEntity } from 'app/shared/model/base-entity'; import { IrisChatSubSettings, IrisCompetencyGenerationSubSettings, + IrisCourseChatSubSettings, IrisLectureIngestionSubSettings, IrisTextExerciseChatSubSettings, } from 'app/entities/iris/settings/iris-sub-settings.model'; @@ -17,6 +18,7 @@ export abstract class IrisSettings implements BaseEntity { type: IrisSettingsType; irisChatSettings?: IrisChatSubSettings; irisTextExerciseChatSettings?: IrisTextExerciseChatSubSettings; + irisCourseChatSettings?: IrisCourseChatSubSettings; irisLectureIngestionSettings?: IrisLectureIngestionSubSettings; irisCompetencyGenerationSettings?: IrisCompetencyGenerationSubSettings; } @@ -26,6 +28,7 @@ export class IrisGlobalSettings implements IrisSettings { type = IrisSettingsType.GLOBAL; irisChatSettings?: IrisChatSubSettings; irisTextExerciseChatSettings?: IrisTextExerciseChatSubSettings; + irisCourseChatSettings?: IrisCourseChatSubSettings; irisLectureIngestionSettings?: IrisLectureIngestionSubSettings; irisCompetencyGenerationSettings?: IrisCompetencyGenerationSubSettings; } @@ -36,6 +39,7 @@ export class IrisCourseSettings implements IrisSettings { courseId?: number; irisChatSettings?: IrisChatSubSettings; irisTextExerciseChatSettings?: IrisTextExerciseChatSubSettings; + irisCourseChatSettings?: IrisCourseChatSubSettings; irisLectureIngestionSettings?: IrisLectureIngestionSubSettings; irisCompetencyGenerationSettings?: IrisCompetencyGenerationSubSettings; } diff --git a/src/main/webapp/app/entities/iris/settings/iris-sub-settings.model.ts b/src/main/webapp/app/entities/iris/settings/iris-sub-settings.model.ts index 2225f8d6bbe1..6b99edff0804 100644 --- a/src/main/webapp/app/entities/iris/settings/iris-sub-settings.model.ts +++ b/src/main/webapp/app/entities/iris/settings/iris-sub-settings.model.ts @@ -1,10 +1,11 @@ import { BaseEntity } from 'app/shared/model/base-entity'; export enum IrisSubSettingsType { + CHAT = 'chat', // TODO: Rename to PROGRAMMING_EXERCISE_CHAT TEXT_EXERCISE_CHAT = 'text-exercise-chat', - CHAT = 'chat', // TODO: Split into PROGRAMMING_EXERCISE_CHAT and COURSE_CHAT - COMPETENCY_GENERATION = 'competency-generation', + COURSE_CHAT = 'course-chat', LECTURE_INGESTION = 'lecture-ingestion', + COMPETENCY_GENERATION = 'competency-generation', } export abstract class IrisSubSettings implements BaseEntity { @@ -28,6 +29,12 @@ export class IrisTextExerciseChatSubSettings extends IrisSubSettings { rateLimitTimeframeHours?: number; } +export class IrisCourseChatSubSettings extends IrisSubSettings { + type = IrisSubSettingsType.COURSE_CHAT; + rateLimit?: number; + rateLimitTimeframeHours?: number; +} + export class IrisLectureIngestionSubSettings extends IrisSubSettings { type = IrisSubSettingsType.LECTURE_INGESTION; autoIngestOnLectureAttachmentUpload: boolean; diff --git a/src/main/webapp/app/iris/settings/iris-settings-update/iris-common-sub-settings-update/iris-common-sub-settings-update.component.ts b/src/main/webapp/app/iris/settings/iris-settings-update/iris-common-sub-settings-update/iris-common-sub-settings-update.component.ts index 0d4f1898653b..78e23b9dbaa6 100644 --- a/src/main/webapp/app/iris/settings/iris-settings-update/iris-common-sub-settings-update/iris-common-sub-settings-update.component.ts +++ b/src/main/webapp/app/iris/settings/iris-settings-update/iris-common-sub-settings-update/iris-common-sub-settings-update.component.ts @@ -75,7 +75,7 @@ export class IrisCommonSubSettingsUpdateComponent implements OnInit, OnChanges { } ngOnChanges(changes: SimpleChanges): void { - if (changes.availableVariants) { + if (!this.inheritAllowedVariants && changes.availableVariants) { this.allowedVariants = this.getAllowedVariants(); } if (changes.subSettings) { diff --git a/src/main/webapp/app/iris/settings/iris-settings-update/iris-settings-update.component.html b/src/main/webapp/app/iris/settings/iris-settings-update/iris-settings-update.component.html index a2b7109c01c2..f97278bc7a90 100644 --- a/src/main/webapp/app/iris/settings/iris-settings-update/iris-settings-update.component.html +++ b/src/main/webapp/app/iris/settings/iris-settings-update/iris-settings-update.component.html @@ -21,7 +21,9 @@

(onChanges)="isDirty = true" /> +
+

@if (settingsType !== EXERCISE) { +
+ +

+
+ +
+ +
+
-

+
-

{ if (profileInfo?.activeProfiles.includes(PROFILE_IRIS)) { this.irisSettingsService.getCombinedCourseSettings(this.courseId).subscribe((settings) => { - this.irisEnabled = !!settings?.irisChatSettings?.enabled; + this.irisEnabled = !!settings?.irisCourseChatSettings?.enabled; }); } }); diff --git a/src/main/webapp/i18n/de/iris.json b/src/main/webapp/i18n/de/iris.json index 1f302a833001..6d1200737895 100644 --- a/src/main/webapp/i18n/de/iris.json +++ b/src/main/webapp/i18n/de/iris.json @@ -26,6 +26,7 @@ "subSettings": { "chatSettings": "Chat Einstellungen", "textExerciseChatSettings": "Textaufgaben Chat Einstellungen", + "courseChatSettings": "Kurs Chat Einstellungen", "lectureIngestionSettings": { "title": "Vorlesungen Erfassung Einstellungen", "autoIngestOnAttachmentUpload": "Vorlesungen automatisch an Pyris senden" diff --git a/src/main/webapp/i18n/en/iris.json b/src/main/webapp/i18n/en/iris.json index 65f153b89c54..f0e4072441be 100644 --- a/src/main/webapp/i18n/en/iris.json +++ b/src/main/webapp/i18n/en/iris.json @@ -26,6 +26,7 @@ "subSettings": { "chatSettings": "Chat Settings", "textExerciseChatSettings": "Text Exercise Chat Settings", + "courseChatSettings": "Course Chat Settings", "lectureIngestionSettings": { "title": "Lecture Ingestion Settings", "autoIngestOnAttachmentUpload": "Send Lectures To Pyris Automatically" diff --git a/src/test/java/de/tum/cit/aet/artemis/iris/AbstractIrisIntegrationTest.java b/src/test/java/de/tum/cit/aet/artemis/iris/AbstractIrisIntegrationTest.java index c887cffce4d9..7820ffe46931 100644 --- a/src/test/java/de/tum/cit/aet/artemis/iris/AbstractIrisIntegrationTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/iris/AbstractIrisIntegrationTest.java @@ -59,9 +59,10 @@ void tearDown() throws Exception { protected void activateIrisGlobally() { var globalSettings = irisSettingsService.getGlobalSettings(); activateSubSettings(globalSettings.getIrisChatSettings()); + activateSubSettings(globalSettings.getIrisTextExerciseChatSettings()); + activateSubSettings(globalSettings.getIrisCourseChatSettings()); activateSubSettings(globalSettings.getIrisLectureIngestionSettings()); activateSubSettings(globalSettings.getIrisCompetencyGenerationSettings()); - activateSubSettings(globalSettings.getIrisTextExerciseChatSettings()); irisSettingsRepository.save(globalSettings); } @@ -80,13 +81,11 @@ protected void activateIrisFor(Course course) { var courseSettings = irisSettingsService.getDefaultSettingsFor(course); activateSubSettings(courseSettings.getIrisChatSettings()); - + activateSubSettings(courseSettings.getIrisTextExerciseChatSettings()); + activateSubSettings(courseSettings.getIrisCourseChatSettings()); activateSubSettings(courseSettings.getIrisCompetencyGenerationSettings()); - activateSubSettings(courseSettings.getIrisLectureIngestionSettings()); - activateSubSettings(courseSettings.getIrisTextExerciseChatSettings()); - irisSettingsRepository.save(courseSettings); } diff --git a/src/test/java/de/tum/cit/aet/artemis/iris/settings/IrisSettingsIntegrationTest.java b/src/test/java/de/tum/cit/aet/artemis/iris/settings/IrisSettingsIntegrationTest.java index 8e877d1e50e2..7912b732a639 100644 --- a/src/test/java/de/tum/cit/aet/artemis/iris/settings/IrisSettingsIntegrationTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/iris/settings/IrisSettingsIntegrationTest.java @@ -26,10 +26,12 @@ import de.tum.cit.aet.artemis.iris.AbstractIrisIntegrationTest; import de.tum.cit.aet.artemis.iris.domain.settings.IrisChatSubSettings; import de.tum.cit.aet.artemis.iris.domain.settings.IrisCompetencyGenerationSubSettings; +import de.tum.cit.aet.artemis.iris.domain.settings.IrisCourseChatSubSettings; import de.tum.cit.aet.artemis.iris.domain.settings.IrisCourseSettings; import de.tum.cit.aet.artemis.iris.domain.settings.IrisExerciseSettings; import de.tum.cit.aet.artemis.iris.domain.settings.IrisLectureIngestionSubSettings; import de.tum.cit.aet.artemis.iris.domain.settings.IrisSettings; +import de.tum.cit.aet.artemis.iris.domain.settings.IrisTextExerciseChatSubSettings; import de.tum.cit.aet.artemis.iris.dto.IrisCombinedSettingsDTO; import de.tum.cit.aet.artemis.iris.repository.IrisSettingsRepository; import de.tum.cit.aet.artemis.iris.repository.IrisSubSettingsRepository; @@ -158,6 +160,8 @@ void updateCourseSettings1() throws Exception { var loadedSettings1 = request.get("/api/courses/" + course.getId() + "/raw-iris-settings", HttpStatus.OK, IrisSettings.class); loadedSettings1.getIrisChatSettings().setEnabled(false); + loadedSettings1.getIrisTextExerciseChatSettings().setEnabled(false); + loadedSettings1.getIrisCourseChatSettings().setEnabled(false); loadedSettings1.getIrisCompetencyGenerationSettings().setEnabled(false); loadedSettings1.getIrisLectureIngestionSettings().setEnabled(false); @@ -167,9 +171,11 @@ void updateCourseSettings1() throws Exception { assertThat(updatedSettings).isNotNull().isEqualTo(loadedSettings2); // Ids of settings should not have changed assertThat(updatedSettings.getId()).isEqualTo(loadedSettings1.getId()); - assertThat(updatedSettings.getIrisLectureIngestionSettings().getId()).isEqualTo(loadedSettings1.getIrisLectureIngestionSettings().getId()); assertThat(updatedSettings.getIrisChatSettings().getId()).isEqualTo(loadedSettings1.getIrisChatSettings().getId()); + assertThat(updatedSettings.getIrisTextExerciseChatSettings().getId()).isEqualTo(loadedSettings1.getIrisTextExerciseChatSettings().getId()); + assertThat(updatedSettings.getIrisCourseChatSettings().getId()).isEqualTo(loadedSettings1.getIrisCourseChatSettings().getId()); assertThat(updatedSettings.getIrisCompetencyGenerationSettings().getId()).isEqualTo(loadedSettings1.getIrisCompetencyGenerationSettings().getId()); + assertThat(updatedSettings.getIrisLectureIngestionSettings().getId()).isEqualTo(loadedSettings1.getIrisLectureIngestionSettings().getId()); } @Test @@ -182,11 +188,15 @@ void updateCourseSettings2() throws Exception { var loadedSettings1 = request.get("/api/courses/" + course.getId() + "/raw-iris-settings", HttpStatus.OK, IrisSettings.class); var chatSubSettingsId = loadedSettings1.getIrisChatSettings().getId(); + var textExerciseChatSubSettingsId = loadedSettings1.getIrisTextExerciseChatSettings().getId(); + var courseChatSubSettingsId = loadedSettings1.getIrisCourseChatSettings().getId(); var competencyGenerationSubSettingsId = loadedSettings1.getIrisCompetencyGenerationSettings().getId(); var lectureIngestionSubSettingsId = loadedSettings1.getIrisLectureIngestionSettings().getId(); - loadedSettings1.setIrisLectureIngestionSettings(null); loadedSettings1.setIrisChatSettings(null); + loadedSettings1.setIrisTextExerciseChatSettings(null); + loadedSettings1.setIrisCourseChatSettings(null); loadedSettings1.setIrisCompetencyGenerationSettings(null); + loadedSettings1.setIrisLectureIngestionSettings(null); var updatedSettings = request.putWithResponseBody("/api/courses/" + course.getId() + "/raw-iris-settings", loadedSettings1, IrisSettings.class, HttpStatus.OK); var loadedSettings2 = request.get("/api/courses/" + course.getId() + "/raw-iris-settings", HttpStatus.OK, IrisSettings.class); @@ -194,9 +204,11 @@ void updateCourseSettings2() throws Exception { assertThat(updatedSettings).isNotNull().usingRecursiveComparison().ignoringFields("course").isEqualTo(loadedSettings1); assertThat(updatedSettings).isNotNull().usingRecursiveComparison().ignoringFields("course").isEqualTo(loadedSettings2); // Original subsettings should not exist anymore - assertThat(irisSubSettingsRepository.findById(lectureIngestionSubSettingsId)).isEmpty(); assertThat(irisSubSettingsRepository.findById(chatSubSettingsId)).isEmpty(); + assertThat(irisSubSettingsRepository.findById(textExerciseChatSubSettingsId)).isEmpty(); + assertThat(irisSubSettingsRepository.findById(courseChatSubSettingsId)).isEmpty(); assertThat(irisSubSettingsRepository.findById(competencyGenerationSubSettingsId)).isEmpty(); + assertThat(irisSubSettingsRepository.findById(lectureIngestionSubSettingsId)).isEmpty(); } @Test @@ -211,19 +223,28 @@ void updateCourseSettings3() throws Exception { courseSettings.getIrisChatSettings().setEnabled(true); courseSettings.getIrisChatSettings().setSelectedVariant(null); + courseSettings.setIrisTextExerciseChatSettings(new IrisTextExerciseChatSubSettings()); + courseSettings.getIrisTextExerciseChatSettings().setEnabled(true); + courseSettings.getIrisTextExerciseChatSettings().setSelectedVariant(null); + + courseSettings.setIrisCourseChatSettings(new IrisCourseChatSubSettings()); + courseSettings.getIrisCourseChatSettings().setEnabled(true); + courseSettings.getIrisCourseChatSettings().setSelectedVariant(null); + courseSettings.setIrisCompetencyGenerationSettings(new IrisCompetencyGenerationSubSettings()); courseSettings.getIrisCompetencyGenerationSettings().setEnabled(true); courseSettings.getIrisCompetencyGenerationSettings().setSelectedVariant(null); courseSettings.setIrisLectureIngestionSettings(new IrisLectureIngestionSubSettings()); courseSettings.getIrisLectureIngestionSettings().setEnabled(true); + courseSettings.getIrisLectureIngestionSettings().setSelectedVariant(null); var updatedSettings = request.putWithResponseBody("/api/courses/" + course.getId() + "/raw-iris-settings", courseSettings, IrisSettings.class, HttpStatus.OK); var loadedSettings1 = request.get("/api/courses/" + course.getId() + "/raw-iris-settings", HttpStatus.OK, IrisSettings.class); assertThat(updatedSettings).usingRecursiveComparison().ignoringFields("course").isEqualTo(loadedSettings1); - assertThat(loadedSettings1).usingRecursiveComparison().ignoringFields("id", "course", "irisChatSettings.id", "irisChatSettings.template.id", - "irisLectureIngestionSettings.id", "irisCompetencyGenerationSettings.id", "irisCompetencyGenerationSettings.template.id").isEqualTo(courseSettings); + assertThat(loadedSettings1).usingRecursiveComparison().ignoringFields("id", "course", "irisChatSettings.id", "irisTextExerciseChatSettings.id", + "irisLectureIngestionSettings.id", "irisCompetencyGenerationSettings.id", "irisCourseChatSettings.id").isEqualTo(courseSettings); } /** diff --git a/src/test/javascript/spec/component/iris/settings/iris-course-settings-update.component.spec.ts b/src/test/javascript/spec/component/iris/settings/iris-course-settings-update.component.spec.ts index 8e721fcc7653..6271fd91f52e 100644 --- a/src/test/javascript/spec/component/iris/settings/iris-course-settings-update.component.spec.ts +++ b/src/test/javascript/spec/component/iris/settings/iris-course-settings-update.component.spec.ts @@ -64,7 +64,7 @@ describe('IrisCourseSettingsUpdateComponent Component', () => { expect(getSettingsSpy).toHaveBeenCalledWith(1); expect(getParentSettingsSpy).toHaveBeenCalledOnce(); - expect(fixture.debugElement.queryAll(By.directive(IrisCommonSubSettingsUpdateComponent))).toHaveLength(4); + expect(fixture.debugElement.queryAll(By.directive(IrisCommonSubSettingsUpdateComponent))).toHaveLength(5); }); it('Can deactivate correctly', () => { @@ -87,11 +87,14 @@ describe('IrisCourseSettingsUpdateComponent Component', () => { expect(setSettingsSpy).toHaveBeenCalledWith(1, irisSettings); expect(comp.settingsUpdateComponent!.irisSettings).toEqual(irisSettingsSaved); }); + it('Fills the settings if they are empty', () => { fixture.detectChanges(); comp.settingsUpdateComponent!.irisSettings = mockEmptySettings(); comp.settingsUpdateComponent!.fillEmptyIrisSubSettings(); expect(comp.settingsUpdateComponent!.irisSettings.irisChatSettings).toBeTruthy(); + expect(comp.settingsUpdateComponent!.irisSettings.irisTextExerciseChatSettings).toBeTruthy(); + expect(comp.settingsUpdateComponent!.irisSettings.irisCourseChatSettings).toBeTruthy(); expect(comp.settingsUpdateComponent!.irisSettings.irisLectureIngestionSettings).toBeTruthy(); expect(comp.settingsUpdateComponent!.irisSettings.irisCompetencyGenerationSettings).toBeTruthy(); }); diff --git a/src/test/javascript/spec/component/iris/settings/iris-global-settings-update.component.spec.ts b/src/test/javascript/spec/component/iris/settings/iris-global-settings-update.component.spec.ts index 0478f3ad2f7a..9c325fbea0d0 100644 --- a/src/test/javascript/spec/component/iris/settings/iris-global-settings-update.component.spec.ts +++ b/src/test/javascript/spec/component/iris/settings/iris-global-settings-update.component.spec.ts @@ -52,7 +52,7 @@ describe('IrisGlobalSettingsUpdateComponent Component', () => { expect(comp.settingsUpdateComponent).toBeTruthy(); expect(getSettingsSpy).toHaveBeenCalledOnce(); - expect(fixture.debugElement.queryAll(By.directive(IrisCommonSubSettingsUpdateComponent))).toHaveLength(4); + expect(fixture.debugElement.queryAll(By.directive(IrisCommonSubSettingsUpdateComponent))).toHaveLength(5); }); it('Can deactivate correctly', () => { diff --git a/src/test/javascript/spec/component/iris/settings/mock-settings.ts b/src/test/javascript/spec/component/iris/settings/mock-settings.ts index 109fb0fdc04f..ef7c75f48a9e 100644 --- a/src/test/javascript/spec/component/iris/settings/mock-settings.ts +++ b/src/test/javascript/spec/component/iris/settings/mock-settings.ts @@ -2,6 +2,7 @@ import { IrisVariant } from 'app/entities/iris/settings/iris-variant'; import { IrisChatSubSettings, IrisCompetencyGenerationSubSettings, + IrisCourseChatSubSettings, IrisLectureIngestionSubSettings, IrisTextExerciseChatSubSettings, } from 'app/entities/iris/settings/iris-sub-settings.model'; @@ -14,6 +15,9 @@ export function mockSettings() { const mockTextExerciseChatSettings = new IrisTextExerciseChatSubSettings(); mockTextExerciseChatSettings.id = 13; mockTextExerciseChatSettings.enabled = true; + const mockCourseChatSettings = new IrisCourseChatSubSettings(); + mockCourseChatSettings.id = 3; + mockCourseChatSettings.enabled = true; const mockLectureIngestionSettings = new IrisLectureIngestionSubSettings(); mockLectureIngestionSettings.id = 7; mockLectureIngestionSettings.enabled = true; @@ -25,6 +29,7 @@ export function mockSettings() { irisSettings.id = 1; irisSettings.irisChatSettings = mockChatSettings; irisSettings.irisTextExerciseChatSettings = mockTextExerciseChatSettings; + irisSettings.irisCourseChatSettings = mockCourseChatSettings; irisSettings.irisCompetencyGenerationSettings = mockCompetencyGenerationSettings; irisSettings.irisLectureIngestionSettings = mockLectureIngestionSettings; return irisSettings;