From e2a4df3b4469644edfb625f9118d8653af2204f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20=C3=87ayl=C4=B1?= <38523756+kaancayli@users.noreply.github.com> Date: Sun, 1 Sep 2024 19:31:11 +0200 Subject: [PATCH 01/16] chore: Reset to develop --- .../iris/settings/IrisCourseSettings.java | 14 ++ .../iris/settings/IrisExerciseSettings.java | 9 + .../iris/settings/IrisGlobalSettings.java | 27 ++- .../settings/IrisProactivitySubSettings.java | 35 +++ .../domain/iris/settings/IrisSettings.java | 4 + .../domain/iris/settings/IrisSubSettings.java | 3 +- .../iris/settings/IrisSubSettingsType.java | 2 +- .../event/IrisBuildFailedEventSettings.java | 25 +++ .../settings/event/IrisEventSettings.java | 107 +++++++++ .../iris/settings/event/IrisEventTarget.java | 8 + .../iris/settings/event/IrisEventType.java | 8 + .../settings/event/IrisJolEventSettings.java | 25 +++ .../IrisProgressStalledEventSettings.java | 25 +++ .../repository/SubmissionRepository.java | 9 + .../iris/IrisSettingsRepository.java | 2 + .../competency/CompetencyJolService.java | 13 +- .../pyris/PyrisPipelineService.java | 126 +++++++++-- .../pyris/dto/chat/PyrisEventDTO.java | 8 + .../PyrisCourseChatPipelineExecutionDTO.java | 4 +- .../pyris/event/CompetencyJolSetEvent.java | 18 ++ .../pyris/event/NewResultEvent.java | 28 +++ .../connectors/pyris/event/PyrisEvent.java | 14 ++ .../pyris/event/PyrisEventService.java | 52 +++++ .../dto/IrisCombinedEventSettingsDTO.java | 16 ++ ...IrisCombinedProactivitySubSettingsDTO.java | 11 + .../iris/dto/IrisCombinedSettingsDTO.java | 3 +- .../session/IrisCourseChatSessionService.java | 98 ++++++++- .../IrisExerciseChatSessionService.java | 205 +++++++++++++++++- .../iris/settings/IrisSettingsService.java | 178 +++++++++++++-- .../iris/settings/IrisSubSettingsService.java | 134 ++++++++++++ .../ProgrammingMessagingService.java | 62 ++++-- .../iris/IrisExerciseChatSessionResource.java | 24 +- .../changelog/20240714145600_changelog.xml | 56 +++++ .../resources/config/liquibase/master.xml | 1 + .../settings/iris-event-settings.model.ts | 37 ++++ .../iris/settings/iris-settings.model.ts | 5 + .../iris/settings/iris-sub-settings.model.ts | 7 + src/main/webapp/app/iris/iris.module.ts | 2 + .../iris-event-settings-update.component.html | 18 ++ .../iris-event-settings-update.component.ts | 52 +++++ ...-autoupdate-settings-update.component.html | 4 + .../iris-settings-update.component.html | 48 ++++ .../iris-settings-update.component.ts | 31 +++ src/main/webapp/i18n/de/iris.json | 19 ++ src/main/webapp/i18n/en/iris.json | 22 +- ...ctSpringIntegrationLocalCILocalVCTest.java | 16 ++ .../connector/IrisRequestMockProvider.java | 28 +++ .../iris/AbstractIrisIntegrationTest.java | 59 +++++ .../artemis/iris/PyrisEventSystemTest.java | 200 +++++++++++++++++ .../settings/IrisSettingsIntegrationTest.java | 12 +- 50 files changed, 1815 insertions(+), 99 deletions(-) create mode 100644 src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisProactivitySubSettings.java create mode 100644 src/main/java/de/tum/in/www1/artemis/domain/iris/settings/event/IrisBuildFailedEventSettings.java create mode 100644 src/main/java/de/tum/in/www1/artemis/domain/iris/settings/event/IrisEventSettings.java create mode 100644 src/main/java/de/tum/in/www1/artemis/domain/iris/settings/event/IrisEventTarget.java create mode 100644 src/main/java/de/tum/in/www1/artemis/domain/iris/settings/event/IrisEventType.java create mode 100644 src/main/java/de/tum/in/www1/artemis/domain/iris/settings/event/IrisJolEventSettings.java create mode 100644 src/main/java/de/tum/in/www1/artemis/domain/iris/settings/event/IrisProgressStalledEventSettings.java create mode 100644 src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/dto/chat/PyrisEventDTO.java create mode 100644 src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/event/CompetencyJolSetEvent.java create mode 100644 src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/event/NewResultEvent.java create mode 100644 src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/event/PyrisEvent.java create mode 100644 src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/event/PyrisEventService.java create mode 100644 src/main/java/de/tum/in/www1/artemis/service/iris/dto/IrisCombinedEventSettingsDTO.java create mode 100644 src/main/java/de/tum/in/www1/artemis/service/iris/dto/IrisCombinedProactivitySubSettingsDTO.java create mode 100644 src/main/resources/config/liquibase/changelog/20240714145600_changelog.xml create mode 100644 src/main/webapp/app/entities/iris/settings/iris-event-settings.model.ts create mode 100644 src/main/webapp/app/iris/settings/iris-settings-update/iris-event-settings-update/iris-event-settings-update.component.html create mode 100644 src/main/webapp/app/iris/settings/iris-settings-update/iris-event-settings-update/iris-event-settings-update.component.ts create mode 100644 src/test/java/de/tum/in/www1/artemis/iris/PyrisEventSystemTest.java diff --git a/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisCourseSettings.java b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisCourseSettings.java index f4b28bbd6ae6..5f2885e8f242 100644 --- a/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisCourseSettings.java +++ b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisCourseSettings.java @@ -32,6 +32,10 @@ public class IrisCourseSettings extends IrisSettings { @JoinColumn(name = "iris_lecture_ingestion_settings_id") private IrisLectureIngestionSubSettings irisLectureIngestionSettings; + @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, optional = false) + @JoinColumn(name = "iris_proactivity_settings_id") + private IrisProactivitySubSettings irisProactivitySettings; + @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) @JoinColumn(name = "iris_hestia_settings_id") private IrisHestiaSubSettings irisHestiaSettings; @@ -63,6 +67,16 @@ public void setIrisLectureIngestionSettings(IrisLectureIngestionSubSettings iris this.irisLectureIngestionSettings = irisLectureIngestionSettings; } + @Override + public IrisProactivitySubSettings getIrisProactivitySettings() { + return irisProactivitySettings; + } + + @Override + public void setIrisProactivitySettings(IrisProactivitySubSettings irisProactivitySettings) { + this.irisProactivitySettings = irisProactivitySettings; + } + @Override public IrisChatSubSettings getIrisChatSettings() { return irisChatSettings; diff --git a/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisExerciseSettings.java b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisExerciseSettings.java index 404ef246b7ed..9135d949d558 100644 --- a/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisExerciseSettings.java +++ b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisExerciseSettings.java @@ -50,6 +50,15 @@ public IrisLectureIngestionSubSettings getIrisLectureIngestionSettings() { public void setIrisLectureIngestionSettings(IrisLectureIngestionSubSettings irisLectureIngestionSettings) { } + @Override + public IrisProactivitySubSettings getIrisProactivitySettings() { + return null; + } + + @Override + public void setIrisProactivitySettings(IrisProactivitySubSettings irisProactivitySettings) { + } + @Override public IrisChatSubSettings getIrisChatSettings() { return irisChatSettings; diff --git a/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisGlobalSettings.java b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisGlobalSettings.java index 1a69d221cfe3..06ff19f3679a 100644 --- a/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisGlobalSettings.java +++ b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisGlobalSettings.java @@ -34,6 +34,9 @@ public class IrisGlobalSettings extends IrisSettings { @Column(name = "enable_auto_update_lecture_ingestion") private boolean enableAutoUpdateLectureIngestion; + @Column(name = "enable_auto_update_proactivity") + private boolean enableAutoUpdateProactivity; + @Column(name = "enable_auto_update_competency_generation") private boolean enableAutoUpdateCompetencyGeneration; @@ -45,6 +48,10 @@ public class IrisGlobalSettings extends IrisSettings { @JoinColumn(name = "iris_lecture_ingestion_settings_id") private IrisLectureIngestionSubSettings irisLectureIngestionSettings; + @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, optional = false) + @JoinColumn(name = "iris_proactivity_settings_id") + private IrisProactivitySubSettings irisProactivitySettings; + @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, optional = false) @JoinColumn(name = "iris_hestia_settings_id") private IrisHestiaSubSettings irisHestiaSettings; @@ -62,7 +69,9 @@ public boolean isValid() { var competencyGenerationSettingsValid = !Hibernate.isInitialized(irisCompetencyGenerationSettings) || irisCompetencyGenerationSettings == null || (irisCompetencyGenerationSettings.getTemplate() != null && irisCompetencyGenerationSettings.getTemplate().getContent() != null && !irisCompetencyGenerationSettings.getTemplate().getContent().isEmpty()); - return chatSettingsValid && hestiaSettingsValid && competencyGenerationSettingsValid; + var proactivitySettingsValid = !Hibernate.isInitialized(irisProactivitySettings) || irisProactivitySettings == null + || (irisProactivitySettings.getEventSettings() != null && !irisProactivitySettings.getEventSettings().isEmpty()); + return chatSettingsValid && hestiaSettingsValid && competencyGenerationSettingsValid && proactivitySettingsValid; } public int getCurrentVersion() { @@ -105,6 +114,22 @@ public void setEnableAutoUpdateCompetencyGeneration(boolean enableAutoUpdateComp this.enableAutoUpdateCompetencyGeneration = enableAutoUpdateCompetencyGeneration; } + public boolean isEnableAutoUpdateProactivity() { + return enableAutoUpdateProactivity; + } + + public void setEnableAutoUpdateProactivity(boolean enableAutoUpdateProactivity) { + this.enableAutoUpdateProactivity = enableAutoUpdateProactivity; + } + + public IrisProactivitySubSettings getIrisProactivitySettings() { + return irisProactivitySettings; + } + + public void setIrisProactivitySettings(IrisProactivitySubSettings irisProactivitySettings) { + this.irisProactivitySettings = irisProactivitySettings; + } + @Override public IrisLectureIngestionSubSettings getIrisLectureIngestionSettings() { return irisLectureIngestionSettings; diff --git a/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisProactivitySubSettings.java b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisProactivitySubSettings.java new file mode 100644 index 000000000000..cb892e8488c6 --- /dev/null +++ b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisProactivitySubSettings.java @@ -0,0 +1,35 @@ +package de.tum.in.www1.artemis.domain.iris.settings; + +import java.util.HashSet; +import java.util.Set; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.DiscriminatorValue; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.OneToMany; + +import com.fasterxml.jackson.annotation.JsonInclude; + +import de.tum.in.www1.artemis.domain.iris.settings.event.IrisEventSettings; + +/** + * Represents the specific ingestion sub-settings of lectures for Iris. + * This class extends {@link IrisSubSettings} to provide settings required for lecture data ingestion. + */ +@Entity +@DiscriminatorValue("PROACTIVITY") +@JsonInclude(JsonInclude.Include.NON_EMPTY) +public class IrisProactivitySubSettings extends IrisSubSettings { + + @OneToMany(mappedBy = "proactivitySubSettings", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) + private Set eventSettings = new HashSet<>(); + + public Set getEventSettings() { + return eventSettings; + } + + public void setEventSettings(Set proactivityStatuses) { + this.eventSettings = proactivityStatuses; + } +} diff --git a/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisSettings.java b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisSettings.java index 6a5d82b4d4c4..7bf403304157 100644 --- a/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisSettings.java +++ b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisSettings.java @@ -49,6 +49,10 @@ public abstract class IrisSettings extends DomainObject { public abstract void setIrisLectureIngestionSettings(IrisLectureIngestionSubSettings irisLectureIngestionSettings); + public abstract IrisProactivitySubSettings getIrisProactivitySettings(); + + public abstract void setIrisProactivitySettings(IrisProactivitySubSettings irisProactivitySettings); + public abstract IrisHestiaSubSettings getIrisHestiaSettings(); public abstract void setIrisHestiaSettings(IrisHestiaSubSettings irisHestiaSettings); diff --git a/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisSubSettings.java b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisSubSettings.java index 50598cc4f8b3..88c13d6e80fe 100644 --- a/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisSubSettings.java +++ b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisSubSettings.java @@ -42,7 +42,8 @@ @JsonSubTypes.Type(value = IrisChatSubSettings.class, name = "chat"), @JsonSubTypes.Type(value = IrisLectureIngestionSubSettings.class, name = "lecture-ingestion"), @JsonSubTypes.Type(value = IrisHestiaSubSettings.class, name = "hestia"), - @JsonSubTypes.Type(value = IrisCompetencyGenerationSubSettings.class, name = "competency-generation") + @JsonSubTypes.Type(value = IrisCompetencyGenerationSubSettings.class, name = "competency-generation"), + @JsonSubTypes.Type(value = IrisProactivitySubSettings.class, name = "proactivity") }) // @formatter:on @JsonInclude(JsonInclude.Include.NON_EMPTY) diff --git a/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisSubSettingsType.java b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisSubSettingsType.java index 73e214c48da0..eec1148bc14e 100644 --- a/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisSubSettingsType.java +++ b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/IrisSubSettingsType.java @@ -1,5 +1,5 @@ package de.tum.in.www1.artemis.domain.iris.settings; public enum IrisSubSettingsType { - CHAT, HESTIA, COMPETENCY_GENERATION, LECTURE_INGESTION + CHAT, HESTIA, COMPETENCY_GENERATION, LECTURE_INGESTION, PROACTIVITY } diff --git a/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/event/IrisBuildFailedEventSettings.java b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/event/IrisBuildFailedEventSettings.java new file mode 100644 index 000000000000..b980961ad895 --- /dev/null +++ b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/event/IrisBuildFailedEventSettings.java @@ -0,0 +1,25 @@ +package de.tum.in.www1.artemis.domain.iris.settings.event; + +import jakarta.persistence.DiscriminatorValue; +import jakarta.persistence.Entity; + +import com.fasterxml.jackson.annotation.JsonInclude; + +/** + * The settings for the Iris event of type BUILD_FAILED. + */ +@Entity +@DiscriminatorValue("BUILD_FAILED") +@JsonInclude(JsonInclude.Include.NON_EMPTY) +public class IrisBuildFailedEventSettings extends IrisEventSettings { + + @Override + public IrisEventTarget getDefaultLevel() { + return IrisEventTarget.EXERCISE; + } + + @Override + public String getDefaultPipelineVariant() { + return "build_failed"; + } +} diff --git a/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/event/IrisEventSettings.java b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/event/IrisEventSettings.java new file mode 100644 index 000000000000..291f6dcf2120 --- /dev/null +++ b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/event/IrisEventSettings.java @@ -0,0 +1,107 @@ +package de.tum.in.www1.artemis.domain.iris.settings.event; + +import jakarta.persistence.Column; +import jakarta.persistence.DiscriminatorColumn; +import jakarta.persistence.DiscriminatorType; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.Inheritance; +import jakarta.persistence.InheritanceType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.PrePersist; +import jakarta.persistence.PreUpdate; +import jakarta.persistence.Table; + +import javax.annotation.Nullable; + +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +import de.tum.in.www1.artemis.domain.DomainObject; +import de.tum.in.www1.artemis.domain.iris.settings.IrisProactivitySubSettings; + +@Entity +@Table(name = "iris_event_settings") +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorColumn(name = "discriminator", discriminatorType = DiscriminatorType.STRING) +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") +// @formatter:off +@JsonSubTypes({ + @JsonSubTypes.Type(value = IrisProgressStalledEventSettings.class, name = "progress_stalled"), + @JsonSubTypes.Type(value = IrisBuildFailedEventSettings.class, name = "build_failed"), + @JsonSubTypes.Type(value = IrisJolEventSettings.class, name = "jol") +}) +@JsonInclude(JsonInclude.Include.NON_EMPTY) +public abstract class IrisEventSettings extends DomainObject { + // Is event active + @Column(name = "is_active", nullable = false) + private boolean isActive; + + // The variant of the pipeline the event is associated with + @Column(name = "pipeline_variant", nullable = false) + private String pipelineVariant; + + // The level of the event which type of session the event will be triggered in + @Nullable + @Enumerated(EnumType.STRING) + @Column(name = "target") + private IrisEventTarget target; + + @JsonIgnore + @ManyToOne + @JoinColumn(name = "iris_proactivity_settings_id") + private IrisProactivitySubSettings proactivitySubSettings; + + @PrePersist + @PreUpdate + protected void onCreate() { + if (target == null) { + target = getDefaultLevel(); + } + if (pipelineVariant == null) { + pipelineVariant = getDefaultPipelineVariant(); + } + } + + public IrisProactivitySubSettings getProactivitySubSettings() { + return proactivitySubSettings; + } + + public void setProactivitySubSettings(IrisProactivitySubSettings proactivitySubSettings) { + this.proactivitySubSettings = proactivitySubSettings; + } + + public boolean isActive() { + return isActive; + } + + public void setActive(boolean active) { + isActive = active; + } + + public String getPipelineVariant() { + return pipelineVariant; + } + + public void setPipelineVariant(String pipelineVariant) { + this.pipelineVariant = pipelineVariant; + } + + public IrisEventTarget getTarget() { + return target; + } + + @JsonIgnore + protected abstract IrisEventTarget getDefaultLevel(); + + @JsonIgnore + protected abstract String getDefaultPipelineVariant(); +} diff --git a/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/event/IrisEventTarget.java b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/event/IrisEventTarget.java new file mode 100644 index 000000000000..c80aab278dd2 --- /dev/null +++ b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/event/IrisEventTarget.java @@ -0,0 +1,8 @@ +package de.tum.in.www1.artemis.domain.iris.settings.event; + +/** + * The target session type of Iris event. Currently, only EXERCISE and COURSE are supported. + */ +public enum IrisEventTarget { + EXERCISE, COURSE +} diff --git a/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/event/IrisEventType.java b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/event/IrisEventType.java new file mode 100644 index 000000000000..dcf30334d154 --- /dev/null +++ b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/event/IrisEventType.java @@ -0,0 +1,8 @@ +package de.tum.in.www1.artemis.domain.iris.settings.event; + +/** + * The type of event that can be triggered by the Iris system. + */ +public enum IrisEventType { + BUILD_FAILED, PROGRESS_STALLED, JOL +} diff --git a/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/event/IrisJolEventSettings.java b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/event/IrisJolEventSettings.java new file mode 100644 index 000000000000..d7e5e0166e37 --- /dev/null +++ b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/event/IrisJolEventSettings.java @@ -0,0 +1,25 @@ +package de.tum.in.www1.artemis.domain.iris.settings.event; + +import jakarta.persistence.DiscriminatorValue; +import jakarta.persistence.Entity; + +import com.fasterxml.jackson.annotation.JsonInclude; + +/** + * The settings for the Iris event of type JOL. + */ +@Entity +@DiscriminatorValue("JOL") +@JsonInclude(JsonInclude.Include.NON_EMPTY) +public class IrisJolEventSettings extends IrisEventSettings { + + @Override + public IrisEventTarget getDefaultLevel() { + return IrisEventTarget.COURSE; + } + + @Override + public String getDefaultPipelineVariant() { + return "jol"; + } +} diff --git a/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/event/IrisProgressStalledEventSettings.java b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/event/IrisProgressStalledEventSettings.java new file mode 100644 index 000000000000..d99b7d0df91d --- /dev/null +++ b/src/main/java/de/tum/in/www1/artemis/domain/iris/settings/event/IrisProgressStalledEventSettings.java @@ -0,0 +1,25 @@ +package de.tum.in.www1.artemis.domain.iris.settings.event; + +import jakarta.persistence.DiscriminatorValue; +import jakarta.persistence.Entity; + +import com.fasterxml.jackson.annotation.JsonInclude; + +/** + * The settings for the Iris event of type PROGRESS_STALLED. + */ +@Entity +@DiscriminatorValue("PROGRESS_STALLED") +@JsonInclude(JsonInclude.Include.NON_EMPTY) +public class IrisProgressStalledEventSettings extends IrisEventSettings { + + @Override + public IrisEventTarget getDefaultLevel() { + return IrisEventTarget.EXERCISE; + } + + @Override + public String getDefaultPipelineVariant() { + return "progress_stalled"; + } +} diff --git a/src/main/java/de/tum/in/www1/artemis/repository/SubmissionRepository.java b/src/main/java/de/tum/in/www1/artemis/repository/SubmissionRepository.java index 0a5d49596525..b826dd27700f 100644 --- a/src/main/java/de/tum/in/www1/artemis/repository/SubmissionRepository.java +++ b/src/main/java/de/tum/in/www1/artemis/repository/SubmissionRepository.java @@ -82,6 +82,15 @@ public interface SubmissionRepository extends ArtemisJpaRepository findAllWithResultsAndAssessorByParticipationId(Long participationId); + /** + * Get all submissions of a participation and eagerly load results and assessor ordered by submission date in ascending order + * + * @param participationId the id of the participation + * @return a list of the participation's submissions + */ + @EntityGraph(type = LOAD, attributePaths = { "results", "results.assessor" }) + List findAllWithResultsAndAssessorByParticipationIdOrderBySubmissionDateAsc(Long participationId); + /** * Get all submissions with their results by the submission ids * diff --git a/src/main/java/de/tum/in/www1/artemis/repository/iris/IrisSettingsRepository.java b/src/main/java/de/tum/in/www1/artemis/repository/iris/IrisSettingsRepository.java index a56d0504e114..ca67ad443675 100644 --- a/src/main/java/de/tum/in/www1/artemis/repository/iris/IrisSettingsRepository.java +++ b/src/main/java/de/tum/in/www1/artemis/repository/iris/IrisSettingsRepository.java @@ -25,6 +25,7 @@ public interface IrisSettingsRepository extends ArtemisJpaRepository findAllGlobalSettings(); @@ -39,6 +40,7 @@ default IrisGlobalSettings findGlobalSettingsElseThrow() { LEFT JOIN FETCH irisSettings.irisLectureIngestionSettings LEFT JOIN FETCH irisSettings.irisHestiaSettings LEFT JOIN FETCH irisSettings.irisCompetencyGenerationSettings + LEFT JOIN FETCH irisSettings.irisProactivitySettings WHERE irisSettings.course.id = :courseId """) Optional findCourseSettings(@Param("courseId") long courseId); diff --git a/src/main/java/de/tum/in/www1/artemis/service/competency/CompetencyJolService.java b/src/main/java/de/tum/in/www1/artemis/service/competency/CompetencyJolService.java index c1d296cf9b53..a292f9b10e1b 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/competency/CompetencyJolService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/competency/CompetencyJolService.java @@ -20,7 +20,8 @@ import de.tum.in.www1.artemis.repository.CompetencyRepository; import de.tum.in.www1.artemis.repository.UserRepository; import de.tum.in.www1.artemis.repository.competency.CompetencyJolRepository; -import de.tum.in.www1.artemis.service.iris.session.IrisCourseChatSessionService; +import de.tum.in.www1.artemis.service.connectors.pyris.event.CompetencyJolSetEvent; +import de.tum.in.www1.artemis.service.connectors.pyris.event.PyrisEventService; import de.tum.in.www1.artemis.web.rest.dto.competency.CompetencyJolDTO; import de.tum.in.www1.artemis.web.rest.dto.competency.CompetencyJolPairDTO; import de.tum.in.www1.artemis.web.rest.errors.BadRequestAlertException; @@ -44,15 +45,15 @@ public class CompetencyJolService { private final UserRepository userRepository; - private final Optional irisCourseChatSessionService; + private final Optional pyrisEventService; public CompetencyJolService(CompetencyJolRepository competencyJolRepository, CompetencyRepository competencyRepository, - CompetencyProgressRepository competencyProgressRepository, UserRepository userRepository, Optional irisCourseChatSessionService) { + CompetencyProgressRepository competencyProgressRepository, UserRepository userRepository, Optional pyrisEventService) { this.competencyJolRepository = competencyJolRepository; this.competencyRepository = competencyRepository; this.competencyProgressRepository = competencyProgressRepository; this.userRepository = userRepository; - this.irisCourseChatSessionService = irisCourseChatSessionService; + this.pyrisEventService = pyrisEventService; } /** @@ -83,11 +84,11 @@ public void setJudgementOfLearning(long competencyId, long userId, short jolValu final var jol = createCompetencyJol(competencyId, userId, jolValue, ZonedDateTime.now(), competencyProgress); competencyJolRepository.save(jol); - irisCourseChatSessionService.ifPresent(service -> { + pyrisEventService.ifPresent(service -> { // Inform Iris so it can send a message to the user try { if (userId % 3 > 0) { // HD3-GROUPS: Iris groups are 1 & 2 - service.onJudgementOfLearningSet(jol); + service.trigger(new CompetencyJolSetEvent(jol)); } } catch (Exception e) { diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/PyrisPipelineService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/PyrisPipelineService.java index a2fc3f1c3ce4..d9f19507bfcd 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/PyrisPipelineService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/PyrisPipelineService.java @@ -1,5 +1,7 @@ package de.tum.in.www1.artemis.service.connectors.pyris; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -16,6 +18,7 @@ import org.springframework.stereotype.Service; import de.tum.in.www1.artemis.domain.Course; +import de.tum.in.www1.artemis.domain.Exercise; import de.tum.in.www1.artemis.domain.ProgrammingExercise; import de.tum.in.www1.artemis.domain.ProgrammingSubmission; import de.tum.in.www1.artemis.domain.competency.CompetencyJol; @@ -26,9 +29,11 @@ import de.tum.in.www1.artemis.repository.StudentParticipationRepository; import de.tum.in.www1.artemis.service.connectors.pyris.dto.PyrisPipelineExecutionDTO; import de.tum.in.www1.artemis.service.connectors.pyris.dto.PyrisPipelineExecutionSettingsDTO; +import de.tum.in.www1.artemis.service.connectors.pyris.dto.chat.PyrisEventDTO; import de.tum.in.www1.artemis.service.connectors.pyris.dto.chat.course.PyrisCourseChatPipelineExecutionDTO; import de.tum.in.www1.artemis.service.connectors.pyris.dto.chat.exercise.PyrisExerciseChatPipelineExecutionDTO; import de.tum.in.www1.artemis.service.connectors.pyris.dto.data.PyrisCourseDTO; +import de.tum.in.www1.artemis.service.connectors.pyris.dto.data.PyrisExerciseWithStudentSubmissionsDTO; import de.tum.in.www1.artemis.service.connectors.pyris.dto.data.PyrisExtendedCourseDTO; import de.tum.in.www1.artemis.service.connectors.pyris.dto.data.PyrisUserDTO; import de.tum.in.www1.artemis.service.connectors.pyris.dto.status.PyrisStageDTO; @@ -164,39 +169,51 @@ public void executeExerciseChatPipeline(String variant, Optional + * - Event-specific data if this is due to a specific event * * @param variant the variant of the pipeline * @param session the chat session - * @param competencyJol if this is due to a JoL set event, this must be the newly created competencyJoL - * @see PyrisPipelineService#executePipeline for more details on the pipeline execution process. + * @param eventObject if this function triggers a pipeline execution due to a specific event, this object is the event payload + * @param eventDtoClass the class of the DTO that should be generated from the object + * @param the type of the object + * @param the type of the DTO */ - public void executeCourseChatPipeline(String variant, IrisCourseChatSession session, CompetencyJol competencyJol) { - // @formatter:off + private void executeCourseChatPipeline(String variant, IrisCourseChatSession session, T eventObject, Class eventDtoClass) { var courseId = session.getCourse().getId(); var studentId = session.getUser().getId(); - executePipeline( - "course-chat", - variant, - pyrisJobService.addCourseChatJob(courseId, session.getId()), - executionDto -> { - var fullCourse = loadCourseWithParticipationOfStudent(courseId, studentId); - return new PyrisCourseChatPipelineExecutionDTO( - PyrisExtendedCourseDTO.of(fullCourse), - learningMetricsService.getStudentCourseMetrics(session.getUser().getId(), courseId), - competencyJol == null ? null : CompetencyJolDTO.of(competencyJol), - pyrisDTOService.toPyrisMessageDTOList(session.getMessages()), - new PyrisUserDTO(session.getUser()), - executionDto.settings(), // flatten the execution dto here - executionDto.initialStages() - ); - }, - stages -> irisChatWebsocketService.sendStatusUpdate(session, stages) - ); + executePipeline("course-chat", variant, pyrisJobService.addCourseChatJob(courseId, session.getId()), executionDto -> { + var fullCourse = loadCourseWithParticipationOfStudent(courseId, studentId); + return new PyrisCourseChatPipelineExecutionDTO(PyrisExtendedCourseDTO.of(fullCourse), + learningMetricsService.getStudentCourseMetrics(session.getUser().getId(), courseId), generateEventPayloadFromObjectType(eventDtoClass, eventObject), + pyrisDTOService.toPyrisMessageDTOList(session.getMessages()), new PyrisUserDTO(session.getUser()), executionDto.settings(), // flatten the execution dto here + executionDto.initialStages()); + }, stages -> irisChatWebsocketService.sendStatusUpdate(session, stages)); // @formatter:on } + /** + * Execute the course chat pipeline for the given session. + * It provides specific data for the course chat pipeline, including: + * - The full course with the participation of the student + * - The metrics of the student in the course + * - The competency JoL if this is due to a JoL set event + *

+ * + * @param variant the variant of the pipeline + * @param session the chat session + * @param object if this function triggers a pipeline execution due to a specific event, this object is the event payload + * @see PyrisPipelineService#executeChatPipeline for more details on the pipeline execution process. + */ + public void executeCourseChatPipeline(String variant, IrisCourseChatSession session, Object object) { + log.debug("Executing course chat pipeline variant {} with object {}", variant, object); + switch (object) { + case null -> executeCourseChatPipeline(variant, session, null, null); + case CompetencyJol competencyJol -> executeCourseChatPipeline(variant, session, competencyJol, CompetencyJolDTO.class); + case Exercise exercise -> executeCourseChatPipeline(variant, session, exercise, PyrisExerciseWithStudentSubmissionsDTO.class); + default -> throw new UnsupportedOperationException("Unsupported Pyris event payload type: " + object); + } + } + /** * Load the course with the participation of the student and set the participations on the exercises. *

@@ -223,4 +240,65 @@ private Course loadCourseWithParticipationOfStudent(long courseId, long studentI return course; } + + /** + * Generate an PyrisEventDTO from an object type by invoking the 'of' method of the DTO class. + * The 'of' method must be a static method that accepts the object type as argument and returns a subclass of PyrisEventDTO. + *

+ * This method is used to generate DTOs from object types that are not known at compile time. + * It is used to generate DTOs from Pyris event objects that are passed to the chat pipeline. + * The DTO classes must have a static 'of' method that accepts the object type as argument. + * The return type of the 'of' method must be a subclass of PyrisEventDTO. + *

+ * + * @param dtoClass the class of the DTO that should be generated + * @param object the object to generate the DTO from + * @param the type of the object + * @param the type of the DTO + * @return PyrisEventDTO + */ + private PyrisEventDTO generateEventPayloadFromObjectType(Class dtoClass, T object) { + + if (object == null) { + return null; + } + // Get the 'of' method from the DTO class + Method ofMethod = null; + Class currentClass = object.getClass(); + + // Traverse up the class hierarchy + while (currentClass != null && ofMethod == null) { + for (Method method : dtoClass.getMethods()) { + if (method.getName().equals("of") && method.getParameterCount() == 1) { + if (method.getParameters()[0].getType().isAssignableFrom(currentClass)) { + ofMethod = method; + break; + } + } + } + currentClass = currentClass.getSuperclass(); + } + + if (ofMethod == null) { + throw new UnsupportedOperationException("Failed to find suitable 'of' method in " + dtoClass.getSimpleName() + " for " + object.getClass().getSimpleName()); + } + + // Invoke the 'of' method with the object as argument + try { + Object result = ofMethod.invoke(null, object); + return new PyrisEventDTO<>(dtoClass.cast(result), object.getClass().getSimpleName()); + } + catch (IllegalArgumentException e) { + throw new UnsupportedOperationException("The 'of' method's parameter type doesn't match the provided object", e); + } + catch (IllegalAccessException e) { + throw new UnsupportedOperationException("The 'of' method is not accessible", e); + } + catch (InvocationTargetException e) { + throw new UnsupportedOperationException("The 'of' method threw an exception", e.getCause()); + } + catch (ClassCastException e) { + throw new UnsupportedOperationException("The 'of' method's return type is not compatible with " + dtoClass.getSimpleName(), e); + } + } } diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/dto/chat/PyrisEventDTO.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/dto/chat/PyrisEventDTO.java new file mode 100644 index 000000000000..e60b5b7f828a --- /dev/null +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/dto/chat/PyrisEventDTO.java @@ -0,0 +1,8 @@ +package de.tum.in.www1.artemis.service.connectors.pyris.dto.chat; + +import com.fasterxml.jackson.annotation.JsonInclude; + +@JsonInclude(JsonInclude.Include.NON_EMPTY) +public record PyrisEventDTO(T event, String eventType) { + +} diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/dto/chat/course/PyrisCourseChatPipelineExecutionDTO.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/dto/chat/course/PyrisCourseChatPipelineExecutionDTO.java index 9edfe9bc73f7..3155eee69552 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/dto/chat/course/PyrisCourseChatPipelineExecutionDTO.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/dto/chat/course/PyrisCourseChatPipelineExecutionDTO.java @@ -5,14 +5,14 @@ import com.fasterxml.jackson.annotation.JsonInclude; import de.tum.in.www1.artemis.service.connectors.pyris.dto.PyrisPipelineExecutionSettingsDTO; +import de.tum.in.www1.artemis.service.connectors.pyris.dto.chat.PyrisEventDTO; import de.tum.in.www1.artemis.service.connectors.pyris.dto.data.PyrisExtendedCourseDTO; import de.tum.in.www1.artemis.service.connectors.pyris.dto.data.PyrisMessageDTO; import de.tum.in.www1.artemis.service.connectors.pyris.dto.data.PyrisUserDTO; import de.tum.in.www1.artemis.service.connectors.pyris.dto.status.PyrisStageDTO; -import de.tum.in.www1.artemis.web.rest.dto.competency.CompetencyJolDTO; import de.tum.in.www1.artemis.web.rest.dto.metrics.StudentMetricsDTO; @JsonInclude(JsonInclude.Include.NON_EMPTY) -public record PyrisCourseChatPipelineExecutionDTO(PyrisExtendedCourseDTO course, StudentMetricsDTO metrics, CompetencyJolDTO competencyJol, List chatHistory, +public record PyrisCourseChatPipelineExecutionDTO(PyrisExtendedCourseDTO course, StudentMetricsDTO metrics, PyrisEventDTO eventPayload, List chatHistory, PyrisUserDTO user, PyrisPipelineExecutionSettingsDTO settings, List initialStages) { } diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/event/CompetencyJolSetEvent.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/event/CompetencyJolSetEvent.java new file mode 100644 index 000000000000..798fa4e78e13 --- /dev/null +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/event/CompetencyJolSetEvent.java @@ -0,0 +1,18 @@ +package de.tum.in.www1.artemis.service.connectors.pyris.event; + +import de.tum.in.www1.artemis.domain.competency.CompetencyJol; +import de.tum.in.www1.artemis.service.iris.session.IrisCourseChatSessionService; + +public class CompetencyJolSetEvent extends PyrisEvent { + + private final CompetencyJol eventObject; + + public CompetencyJolSetEvent(CompetencyJol eventObject) { + this.eventObject = eventObject; + } + + @Override + public void handleEvent(IrisCourseChatSessionService service) { + service.onJudgementOfLearningSet(eventObject); + } +} diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/event/NewResultEvent.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/event/NewResultEvent.java new file mode 100644 index 000000000000..2521a3aa02e7 --- /dev/null +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/event/NewResultEvent.java @@ -0,0 +1,28 @@ +package de.tum.in.www1.artemis.service.connectors.pyris.event; + +import de.tum.in.www1.artemis.domain.ProgrammingSubmission; +import de.tum.in.www1.artemis.domain.Result; +import de.tum.in.www1.artemis.service.iris.session.IrisExerciseChatSessionService; + +public class NewResultEvent extends PyrisEvent { + + private final Result eventObject; + + public NewResultEvent(Result eventObject) { + this.eventObject = eventObject; + } + + @Override + public void handleEvent(IrisExerciseChatSessionService service) { + 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); + } + } + } +} diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/event/PyrisEvent.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/event/PyrisEvent.java new file mode 100644 index 000000000000..85bfb8a072cc --- /dev/null +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/event/PyrisEvent.java @@ -0,0 +1,14 @@ +package de.tum.in.www1.artemis.service.connectors.pyris.event; + +import de.tum.in.www1.artemis.domain.iris.session.IrisChatSession; +import de.tum.in.www1.artemis.service.iris.session.AbstractIrisChatSessionService; + +public abstract class PyrisEvent, T> { + + /** + * Handles the event using the given service. + * + * @param service The service to handle the event for + */ + public abstract void handleEvent(S service); +} diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/event/PyrisEventService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/event/PyrisEventService.java new file mode 100644 index 000000000000..2b1309c4d8c3 --- /dev/null +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/pyris/event/PyrisEventService.java @@ -0,0 +1,52 @@ +package de.tum.in.www1.artemis.service.connectors.pyris.event; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import de.tum.in.www1.artemis.domain.iris.session.IrisChatSession; +import de.tum.in.www1.artemis.service.iris.session.AbstractIrisChatSessionService; +import de.tum.in.www1.artemis.service.iris.session.IrisCourseChatSessionService; +import de.tum.in.www1.artemis.service.iris.session.IrisExerciseChatSessionService; + +/** + * Service to handle Pyris events. + */ +@Service +@Profile("iris") +public class PyrisEventService { + + private static final Logger log = LoggerFactory.getLogger(PyrisEventService.class); + + private final IrisCourseChatSessionService irisCourseChatSessionService; + + private final IrisExerciseChatSessionService irisExerciseChatSessionService; + + public PyrisEventService(IrisCourseChatSessionService irisCourseChatSessionService, IrisExerciseChatSessionService irisExerciseChatSessionService) { + this.irisCourseChatSessionService = irisCourseChatSessionService; + this.irisExerciseChatSessionService = irisExerciseChatSessionService; + } + + /** + * Triggers a Pyris pipeline based on the received {@link PyrisEvent}. + * + * @param event The event object received to trigger the matching pipeline + * @throws UnsupportedOperationException if the event is not supported + * + * @see PyrisEvent + */ + public void trigger(PyrisEvent, ?> event) { + switch (event) { + case CompetencyJolSetEvent competencyJolSetEvent -> { + log.info("Received CompetencyJolSetEvent: {}", competencyJolSetEvent); + competencyJolSetEvent.handleEvent(irisCourseChatSessionService); + } + case NewResultEvent newResultEvent -> { + log.info("Received NewResultEvent: {}", newResultEvent); + newResultEvent.handleEvent(irisExerciseChatSessionService); + } + default -> throw new UnsupportedOperationException("Unsupported event: " + event); + } + } +} diff --git a/src/main/java/de/tum/in/www1/artemis/service/iris/dto/IrisCombinedEventSettingsDTO.java b/src/main/java/de/tum/in/www1/artemis/service/iris/dto/IrisCombinedEventSettingsDTO.java new file mode 100644 index 000000000000..c517f64603c7 --- /dev/null +++ b/src/main/java/de/tum/in/www1/artemis/service/iris/dto/IrisCombinedEventSettingsDTO.java @@ -0,0 +1,16 @@ +package de.tum.in.www1.artemis.service.iris.dto; + +import jakarta.annotation.Nullable; + +import com.fasterxml.jackson.annotation.JsonInclude; + +import de.tum.in.www1.artemis.domain.iris.settings.event.IrisEventSettings; +import de.tum.in.www1.artemis.domain.iris.settings.event.IrisEventTarget; + +@JsonInclude(JsonInclude.Include.NON_EMPTY) +public record IrisCombinedEventSettingsDTO(boolean isActive, String pipelineVariant, @Nullable IrisEventTarget target) { + + public static IrisCombinedEventSettingsDTO of(IrisEventSettings eventSettings) { + return new IrisCombinedEventSettingsDTO(eventSettings.isActive(), eventSettings.getPipelineVariant(), eventSettings.getTarget()); + } +} diff --git a/src/main/java/de/tum/in/www1/artemis/service/iris/dto/IrisCombinedProactivitySubSettingsDTO.java b/src/main/java/de/tum/in/www1/artemis/service/iris/dto/IrisCombinedProactivitySubSettingsDTO.java new file mode 100644 index 000000000000..4d1ce4a7d2ad --- /dev/null +++ b/src/main/java/de/tum/in/www1/artemis/service/iris/dto/IrisCombinedProactivitySubSettingsDTO.java @@ -0,0 +1,11 @@ +package de.tum.in.www1.artemis.service.iris.dto; + +import java.util.Set; + +import jakarta.annotation.Nullable; + +import com.fasterxml.jackson.annotation.JsonInclude; + +@JsonInclude(JsonInclude.Include.NON_EMPTY) +public record IrisCombinedProactivitySubSettingsDTO(boolean enabled, @Nullable Set eventSettings) { +} diff --git a/src/main/java/de/tum/in/www1/artemis/service/iris/dto/IrisCombinedSettingsDTO.java b/src/main/java/de/tum/in/www1/artemis/service/iris/dto/IrisCombinedSettingsDTO.java index 80c662d9d6a1..0cbf7ea398f4 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/iris/dto/IrisCombinedSettingsDTO.java +++ b/src/main/java/de/tum/in/www1/artemis/service/iris/dto/IrisCombinedSettingsDTO.java @@ -4,5 +4,6 @@ @JsonInclude(JsonInclude.Include.NON_EMPTY) public record IrisCombinedSettingsDTO(IrisCombinedChatSubSettingsDTO irisChatSettings, IrisCombinedLectureIngestionSubSettingsDTO irisLectureIngestionSettings, - IrisCombinedHestiaSubSettingsDTO irisHestiaSettings, IrisCombinedCompetencyGenerationSubSettingsDTO irisCompetencyGenerationSettings) { + IrisCombinedHestiaSubSettingsDTO irisHestiaSettings, IrisCombinedCompetencyGenerationSubSettingsDTO irisCompetencyGenerationSettings, + IrisCombinedProactivitySubSettingsDTO irisProactivitySettings) { } diff --git a/src/main/java/de/tum/in/www1/artemis/service/iris/session/IrisCourseChatSessionService.java b/src/main/java/de/tum/in/www1/artemis/service/iris/session/IrisCourseChatSessionService.java index bd5a4c25887b..71f6d9375676 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/iris/session/IrisCourseChatSessionService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/iris/session/IrisCourseChatSessionService.java @@ -2,9 +2,13 @@ import java.time.LocalDate; import java.time.ZoneId; +import java.util.HashSet; +import java.util.List; import java.util.Objects; import java.util.concurrent.CompletableFuture; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Profile; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; @@ -12,6 +16,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; import de.tum.in.www1.artemis.domain.Course; +import de.tum.in.www1.artemis.domain.ProgrammingExercise; +import de.tum.in.www1.artemis.domain.Result; +import de.tum.in.www1.artemis.domain.Team; import de.tum.in.www1.artemis.domain.User; import de.tum.in.www1.artemis.domain.competency.CompetencyJol; import de.tum.in.www1.artemis.domain.iris.message.IrisMessage; @@ -19,6 +26,10 @@ import de.tum.in.www1.artemis.domain.iris.message.IrisTextMessageContent; import de.tum.in.www1.artemis.domain.iris.session.IrisCourseChatSession; import de.tum.in.www1.artemis.domain.iris.settings.IrisSubSettingsType; +import de.tum.in.www1.artemis.domain.iris.settings.event.IrisEventType; +import de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseStudentParticipation; +import de.tum.in.www1.artemis.repository.StudentParticipationRepository; +import de.tum.in.www1.artemis.repository.SubmissionRepository; import de.tum.in.www1.artemis.repository.iris.IrisCourseChatSessionRepository; import de.tum.in.www1.artemis.repository.iris.IrisSessionRepository; import de.tum.in.www1.artemis.security.Role; @@ -30,7 +41,9 @@ import de.tum.in.www1.artemis.service.iris.IrisRateLimitService; import de.tum.in.www1.artemis.service.iris.settings.IrisSettingsService; import de.tum.in.www1.artemis.service.iris.websocket.IrisChatWebsocketService; +import de.tum.in.www1.artemis.web.rest.errors.AccessForbiddenAlertException; import de.tum.in.www1.artemis.web.rest.errors.AccessForbiddenException; +import de.tum.in.www1.artemis.web.rest.errors.ConflictException; /** * Service to handle the course chat subsystem of Iris. @@ -39,6 +52,8 @@ @Profile("iris") public class IrisCourseChatSessionService extends AbstractIrisChatSessionService { + private static final Logger log = LoggerFactory.getLogger(IrisCourseChatSessionService.class); + private final IrisMessageService irisMessageService; private final IrisSettingsService irisSettingsService; @@ -53,11 +68,18 @@ public class IrisCourseChatSessionService extends AbstractIrisChatSessionService private final IrisCourseChatSessionRepository irisCourseChatSessionRepository; + private final StudentParticipationRepository studentParticipationRepository; + private final PyrisPipelineService pyrisPipelineService; + private final SubmissionRepository submissionRepository; + + private final double SUCCESS_THRESHOLD = 80.0; // TODO: Retrieve configuration from Iris settings + public IrisCourseChatSessionService(IrisMessageService irisMessageService, IrisSettingsService irisSettingsService, IrisChatWebsocketService irisChatWebsocketService, AuthorizationCheckService authCheckService, IrisSessionRepository irisSessionRepository, IrisRateLimitService rateLimitService, - IrisCourseChatSessionRepository irisCourseChatSessionRepository, PyrisPipelineService pyrisPipelineService, ObjectMapper objectMapper) { + IrisCourseChatSessionRepository irisCourseChatSessionRepository, PyrisPipelineService pyrisPipelineService, ObjectMapper objectMapper, + StudentParticipationRepository studentParticipationRepository, SubmissionRepository submissionRepository) { super(irisSessionRepository, objectMapper); this.irisMessageService = irisMessageService; this.irisSettingsService = irisSettingsService; @@ -67,6 +89,8 @@ public IrisCourseChatSessionService(IrisMessageService irisMessageService, IrisS this.rateLimitService = rateLimitService; this.irisCourseChatSessionRepository = irisCourseChatSessionRepository; this.pyrisPipelineService = pyrisPipelineService; + this.studentParticipationRepository = studentParticipationRepository; + this.submissionRepository = submissionRepository; } /** @@ -117,10 +141,9 @@ public void requestAndHandleResponse(IrisCourseChatSession session) { requestAndHandleResponse(session, "default", null); } - private void requestAndHandleResponse(IrisCourseChatSession session, String variant, CompetencyJol competencyJol) { + private void requestAndHandleResponse(IrisCourseChatSession session, String variant, Object object) { var chatSession = (IrisCourseChatSession) irisSessionRepository.findByIdWithMessagesAndContents(session.getId()); - - pyrisPipelineService.executeCourseChatPipeline(variant, chatSession, competencyJol); + pyrisPipelineService.executeCourseChatPipeline(variant, chatSession, object); } /** @@ -151,15 +174,76 @@ public void handleStatusUpdate(CourseChatJob job, PyrisChatStatusUpdateDTO statu */ public void onJudgementOfLearningSet(CompetencyJol competencyJol) { var course = competencyJol.getCompetency().getCourse(); - if (!irisSettingsService.isEnabledFor(IrisSubSettingsType.CHAT, course)) { - return; - } + + irisSettingsService.isActivatedForElseThrow(IrisEventType.JOL, course); + var user = competencyJol.getUser(); user.hasAcceptedIrisElseThrow(); var session = getCurrentSessionOrCreateIfNotExistsInternal(course, user, false); CompletableFuture.runAsync(() -> requestAndHandleResponse(session, "jol", competencyJol)); } + /** + * Triggers the course chat in response to a new submission for a non-exam exercise. + * Triggers the pipeline only the first time a user successfully submits an exercise. + * Subsequent successful submissions are ignored. + * + * @param result The submission event to trigger the course chat for + * @throws ConflictException If the exercise is an exam exercise + * @throws AccessForbiddenAlertException If the course chat is not enabled for the course + */ + public void onSubmissionSuccess(Result result) { + var participation = result.getParticipation(); + if (!(participation instanceof ProgrammingExerciseStudentParticipation studentParticipation)) { + return; + } + var exercise = (ProgrammingExercise) participation.getExercise(); + + if (exercise.isExamExercise()) { + throw new ConflictException("Iris is not supported for exam exercises", "Iris", "irisExamExercise"); + } + var course = exercise.getCourseViaExerciseGroupOrCourseMember(); + + irisSettingsService.isActivatedForElseThrow(IrisEventType.PROGRESS_STALLED, course); + + log.info("Submission was successful for user {}", studentParticipation.getParticipant().getName()); + // The submission was successful, so we inform Iris about the successful submission, + // but before we do that, we check if this is the first successful time out of all submissions out of all submissions for this exercise + var allSubmissions = submissionRepository.findAllWithResultsAndAssessorByParticipationId(studentParticipation.getId()); + var latestSubmission = allSubmissions.getLast(); + var allSuccessful = allSubmissions.stream().filter(submission -> submission.getLatestResult() != null && submission.getLatestResult().getScore() >= SUCCESS_THRESHOLD) + .count(); + if (allSuccessful == 1 && Objects.requireNonNull(latestSubmission.getLatestResult()).getScore() >= SUCCESS_THRESHOLD) { + log.info("First successful submission for user {}", studentParticipation.getParticipant().getName()); + var participant = studentParticipation.getParticipant(); + if (participant instanceof User user) { + setStudentParticipationsToExercise(user.getId(), exercise); + var session = getCurrentSessionOrCreateIfNotExistsInternal(course, user, false); + CompletableFuture.runAsync(() -> requestAndHandleResponse(session, "submission_successful", exercise)); + } + else { + var team = (Team) participant; + var teamMembers = team.getStudents(); + for (var user : teamMembers) { + setStudentParticipationsToExercise(user.getId(), exercise); + var session = getCurrentSessionOrCreateIfNotExistsInternal(course, user, false); + CompletableFuture.runAsync(() -> requestAndHandleResponse(session, "submission_successful", exercise)); + } + } + } + else { + log.info("User {} has already successfully submitted before, so we do not inform Iris about the successful submission", + studentParticipation.getParticipant().getName()); + } + } + + private void setStudentParticipationsToExercise(Long studentId, ProgrammingExercise exercise) { + // TODO: Write a repository function to pull student participations for a specific exercise instead of a list of exercises + var studentParticipation = new HashSet<>( + studentParticipationRepository.findByStudentIdAndIndividualExercisesWithEagerSubmissionsResultIgnoreTestRuns(studentId, List.of(exercise))); + exercise.setStudentParticipations(studentParticipation); + } + /** * Gets the current Iris session for the course and user. * If no session exists or if the last session is from a different day, a new one is created. diff --git a/src/main/java/de/tum/in/www1/artemis/service/iris/session/IrisExerciseChatSessionService.java b/src/main/java/de/tum/in/www1/artemis/service/iris/session/IrisExerciseChatSessionService.java index 36508d8b0934..f90b3d552742 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/iris/session/IrisExerciseChatSessionService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/iris/session/IrisExerciseChatSessionService.java @@ -1,15 +1,23 @@ package de.tum.in.www1.artemis.service.iris.session; +import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.stream.IntStream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Profile; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import com.fasterxml.jackson.databind.ObjectMapper; +import de.tum.in.www1.artemis.domain.Exercise; import de.tum.in.www1.artemis.domain.ProgrammingExercise; import de.tum.in.www1.artemis.domain.ProgrammingSubmission; +import de.tum.in.www1.artemis.domain.Result; import de.tum.in.www1.artemis.domain.Submission; import de.tum.in.www1.artemis.domain.User; import de.tum.in.www1.artemis.domain.iris.message.IrisMessage; @@ -17,9 +25,13 @@ import de.tum.in.www1.artemis.domain.iris.message.IrisTextMessageContent; import de.tum.in.www1.artemis.domain.iris.session.IrisExerciseChatSession; import de.tum.in.www1.artemis.domain.iris.settings.IrisSubSettingsType; +import de.tum.in.www1.artemis.domain.iris.settings.event.IrisEventType; +import de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseStudentParticipation; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseStudentParticipationRepository; import de.tum.in.www1.artemis.repository.ProgrammingSubmissionRepository; +import de.tum.in.www1.artemis.repository.SubmissionRepository; +import de.tum.in.www1.artemis.repository.iris.IrisExerciseChatSessionRepository; import de.tum.in.www1.artemis.repository.iris.IrisSessionRepository; import de.tum.in.www1.artemis.security.Role; import de.tum.in.www1.artemis.service.AuthorizationCheckService; @@ -40,6 +52,8 @@ @Profile("iris") public class IrisExerciseChatSessionService extends AbstractIrisChatSessionService implements IrisRateLimitedFeatureInterface { + private static final Logger log = LoggerFactory.getLogger(IrisExerciseChatSessionService.class); + private final IrisMessageService irisMessageService; private final IrisSettingsService irisSettingsService; @@ -60,11 +74,17 @@ public class IrisExerciseChatSessionService extends AbstractIrisChatSessionServi private final ProgrammingExerciseRepository programmingExerciseRepository; + private final IrisExerciseChatSessionRepository irisExerciseChatSessionRepository; + + private final SubmissionRepository submissionRepository; + + private final double SUCCESS_THRESHOLD = 100.0; // TODO: Retrieve configuration from Iris settings + public IrisExerciseChatSessionService(IrisMessageService irisMessageService, IrisSettingsService irisSettingsService, IrisChatWebsocketService irisChatWebsocketService, AuthorizationCheckService authCheckService, IrisSessionRepository irisSessionRepository, ProgrammingExerciseStudentParticipationRepository programmingExerciseStudentParticipationRepository, ProgrammingSubmissionRepository programmingSubmissionRepository, IrisRateLimitService rateLimitService, PyrisPipelineService pyrisPipelineService, ProgrammingExerciseRepository programmingExerciseRepository, - ObjectMapper objectMapper) { + ObjectMapper objectMapper, IrisExerciseChatSessionRepository irisExerciseChatSessionRepository, SubmissionRepository submissionRepository) { super(irisSessionRepository, objectMapper); this.irisMessageService = irisMessageService; this.irisSettingsService = irisSettingsService; @@ -76,6 +96,8 @@ public IrisExerciseChatSessionService(IrisMessageService irisMessageService, Iri this.rateLimitService = rateLimitService; this.pyrisPipelineService = pyrisPipelineService; this.programmingExerciseRepository = programmingExerciseRepository; + this.irisExerciseChatSessionRepository = irisExerciseChatSessionRepository; + this.submissionRepository = submissionRepository; } /** @@ -85,6 +107,7 @@ public IrisExerciseChatSessionService(IrisMessageService irisMessageService, Iri * @param user The user the session belongs to * @return The created session */ + // TODO: This function is only used in tests. Replace with createSession once the tests are refactored. public IrisExerciseChatSession createChatSessionForProgrammingExercise(ProgrammingExercise exercise, User user) { if (exercise.isExamExercise()) { throw new ConflictException("Iris is not supported for exam exercises", "Iris", "irisExamExercise"); @@ -102,12 +125,16 @@ public IrisExerciseChatSession createChatSessionForProgrammingExercise(Programmi */ @Override public void checkHasAccessTo(User user, IrisExerciseChatSession session) { - authCheckService.checkHasAtLeastRoleForExerciseElseThrow(Role.STUDENT, session.getExercise(), user); + checkHasTheMinimalRequiredRoleForExerciseElseThrow(user, session.getExercise()); if (!Objects.equals(session.getUser(), user)) { throw new AccessForbiddenException("Iris Session", session.getId()); } } + private void checkHasTheMinimalRequiredRoleForExerciseElseThrow(User user, Exercise exercise) { + authCheckService.checkHasAtLeastRoleForExerciseElseThrow(Role.STUDENT, exercise, user); + } + /** * Checks if the exercise connected to IrisChatSession has Iris enabled * @@ -130,23 +157,109 @@ public void checkRateLimit(User user) { /** * Sends all messages of the session to an LLM and handles the response by saving the message - * and sending it to the student via the Websocket. + * and sending it to the student via the Websocket. Uses the default pipeline variant. * * @param session The chat session to send to the LLM */ @Override public void requestAndHandleResponse(IrisExerciseChatSession session) { + requestAndHandleResponse(session, "default"); + } + + /** + * Sends all messages of the session to an LLM and handles the response by saving the message + * and sending it to the student via the Websocket. + * + * @param session The chat session to send to the LLM + * @param variant The variant of the pipeline to use + */ + public void requestAndHandleResponse(IrisExerciseChatSession session, String variant) { var chatSession = (IrisExerciseChatSession) irisSessionRepository.findByIdWithMessagesAndContents(session.getId()); if (chatSession.getExercise().isExamExercise()) { throw new ConflictException("Iris is not supported for exam exercises", "Iris", "irisExamExercise"); } - // TODO support more exercise types var exercise = programmingExerciseRepository.findByIdWithTemplateAndSolutionParticipationElseThrow(chatSession.getExercise().getId()); var latestSubmission = getLatestSubmissionIfExists(exercise, chatSession.getUser()); + pyrisPipelineService.executeExerciseChatPipeline(variant, latestSubmission, exercise, chatSession); + } + + /** + * Handles the build failure event by sending a message to the student via Iris. + * + * @param result The result of the submission + */ + public void onBuildFailure(Result result) { + var submission = result.getSubmission(); + if (submission instanceof ProgrammingSubmission programmingSubmission) { + var participation = programmingSubmission.getParticipation(); + if (!(participation instanceof ProgrammingExerciseStudentParticipation studentParticipation)) { + return; + } + var exercise = (ProgrammingExercise) participation.getExercise(); + if (exercise.isExamExercise()) { + throw new ConflictException("Iris is not supported for exam exercises", "Iris", "irisExamExercise"); + } + + irisSettingsService.isActivatedForElseThrow(IrisEventType.BUILD_FAILED, exercise); + + var participant = studentParticipation.getParticipant(); + if (participant instanceof User user) { + var session = getCurrentSessionOrCreateIfNotExistsInternal(exercise, user, false); + log.info("Build failed for user {}", user.getName()); + CompletableFuture.runAsync(() -> requestAndHandleResponse(session, "build_failed")); + } + else { + throw new ConflictException("Build failure event is not supported for team participations", "Iris", "irisTeamParticipation"); + } + } + } + + /** + * Informs Iris about a progress stall event, if the student has not improved their in the last 3 submissions. + * + * @param result The result of the submission + */ + public void onNewResult(Result result) { + var participation = result.getParticipation(); + if (!(participation instanceof ProgrammingExerciseStudentParticipation studentParticipation)) { + return; + } + var exercise = (ProgrammingExercise) participation.getExercise(); + if (exercise.isExamExercise()) { + throw new ConflictException("Iris is not supported for exam exercises", "Iris", "irisExamExercise"); + } - // TODO: Use settings to determine the variant - // var irisSettings = irisSettingsService.getCombinedIrisSettingsFor(chatSession.getExercise(), false); - pyrisPipelineService.executeExerciseChatPipeline("default", latestSubmission, exercise, chatSession); + irisSettingsService.isActivatedForElseThrow(IrisEventType.PROGRESS_STALLED, exercise); + + var recentSubmissions = submissionRepository.findAllWithResultsAndAssessorByParticipationIdOrderBySubmissionDateAsc(studentParticipation.getId()); + + // Check if the user has already successfully submitted before + var successfulSubmission = recentSubmissions.stream() + .anyMatch(submission -> submission.getLatestResult() != null && submission.getLatestResult().getScore() == SUCCESS_THRESHOLD); + if (!successfulSubmission && recentSubmissions.size() >= 3) { + var listOfScores = recentSubmissions.stream().map(Submission::getLatestResult).map(Result::getScore).toList(); + + // Check if the student needs intervention based on their recent score trajectory + var needsIntervention = needsIntervention(listOfScores, 3); + if (needsIntervention) { + log.info("Scores in the last 3 submissions did not improve for user {}", studentParticipation.getParticipant().getName()); + var participant = ((ProgrammingExerciseStudentParticipation) participation).getParticipant(); + if (participant instanceof User user) { + var session = getCurrentSessionOrCreateIfNotExistsInternal(exercise, user, false); + CompletableFuture.runAsync(() -> requestAndHandleResponse(session, "progress_stalled")); + } + else { + throw new ConflictException("Progress stalled event is not supported for team participations", "Iris", "irisTeamParticipation"); + } + } + } + else { + log.info("Submission was not successful for user {}", studentParticipation.getParticipant().getName()); + if (successfulSubmission) { + log.info("User {} has already successfully submitted before, so we do not inform Iris about the submission failure", + studentParticipation.getParticipant().getName()); + } + } } private Optional getLatestSubmissionIfExists(ProgrammingExercise exercise, User user) { @@ -158,6 +271,84 @@ private Optional getLatestSubmissionIfExists(ProgrammingE .flatMap(sub -> programmingSubmissionRepository.findWithEagerResultsAndFeedbacksAndBuildLogsById(sub.getId())); } + /** + * Checks if there's overall improvement in the given interval [i, j] of the list. + * + * @param scores The list of scores. + * @param i The starting index of the interval (inclusive). + * @param j The ending index of the interval (inclusive). + * @return true if there's overall improvement (last score > first score), false otherwise. + */ + private boolean hasOverallImprovement(List scores, int i, int j) { + if (i >= j || i < 0 || j >= scores.size()) { + throw new IllegalArgumentException("Invalid interval"); + } + + return scores.get(j) > scores.get(i) && IntStream.range(i, j).allMatch(index -> scores.get(index) <= scores.get(index + 1)); + } + + /** + * Checks if the student needs intervention based on their recent score trajectory. + * + * @param scores The list of all scores for the student. + * @param intervalSize The number of recent submissions to consider. + * @return true if intervention is needed, false otherwise. + */ + private boolean needsIntervention(List scores, int intervalSize) { + if (scores.size() < intervalSize) { + return false; // Not enough data to make a decision + } + + int lastIndex = scores.size() - 1; + int startIndex = lastIndex - intervalSize + 1; + + return !hasOverallImprovement(scores, startIndex, lastIndex); + } + + /** + * Gets the current Iris session for the exercise and user. + * If no session exists or if the last session is from a different day, a new one is created. + * + * @param exercise Programming exercise to get the session for + * @param user The user to get the session for + * @param sendInitialMessageIfCreated Whether to send an initial message from Iris if a new session is created + * @return The current Iris session + */ + public IrisExerciseChatSession getCurrentSessionOrCreateIfNotExists(ProgrammingExercise exercise, User user, boolean sendInitialMessageIfCreated) { + user.hasAcceptedIrisElseThrow(); + irisSettingsService.isEnabledForElseThrow(IrisSubSettingsType.CHAT, exercise); + return getCurrentSessionOrCreateIfNotExistsInternal(exercise, user, sendInitialMessageIfCreated); + } + + private IrisExerciseChatSession getCurrentSessionOrCreateIfNotExistsInternal(ProgrammingExercise exercise, User user, boolean sendInitialMessageIfCreated) { + var sessionOptional = irisExerciseChatSessionRepository.findLatestByExerciseIdAndUserIdWithMessages(exercise.getId(), user.getId(), Pageable.ofSize(1)).stream() + .findFirst(); + + return sessionOptional.orElseGet(() -> createSessionInternal(exercise, user, sendInitialMessageIfCreated)); + } + + public IrisExerciseChatSession createSession(ProgrammingExercise exercise, User user, boolean sendInitialMessage) { + user.hasAcceptedIrisElseThrow(); + irisSettingsService.isEnabledForElseThrow(IrisSubSettingsType.CHAT, exercise); + checkHasTheMinimalRequiredRoleForExerciseElseThrow(user, exercise); + return createSessionInternal(exercise, user, sendInitialMessage); + } + + private IrisExerciseChatSession createSessionInternal(ProgrammingExercise exercise, User user, boolean sendInitialMessage) { + if (exercise.isExamExercise()) { + throw new ConflictException("Iris is not supported for exam exercises", "Iris", "irisExamExercise"); + } + + var session = irisExerciseChatSessionRepository.save(new IrisExerciseChatSession(exercise, user)); + + if (sendInitialMessage) { + // Run async to allow the session to be returned immediately + CompletableFuture.runAsync(() -> requestAndHandleResponse(session)); + } + + return session; + } + /** * Handles the status update of a ExerciseChatJob by sending the result to the student via the Websocket. * diff --git a/src/main/java/de/tum/in/www1/artemis/service/iris/settings/IrisSettingsService.java b/src/main/java/de/tum/in/www1/artemis/service/iris/settings/IrisSettingsService.java index 0024704cf0d0..51fd488f4ed9 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/iris/settings/IrisSettingsService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/iris/settings/IrisSettingsService.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.Comparator; +import java.util.HashSet; import java.util.Objects; import java.util.Optional; import java.util.function.Supplier; @@ -27,12 +28,19 @@ import de.tum.in.www1.artemis.domain.iris.settings.IrisGlobalSettings; import de.tum.in.www1.artemis.domain.iris.settings.IrisHestiaSubSettings; import de.tum.in.www1.artemis.domain.iris.settings.IrisLectureIngestionSubSettings; +import de.tum.in.www1.artemis.domain.iris.settings.IrisProactivitySubSettings; import de.tum.in.www1.artemis.domain.iris.settings.IrisSettings; import de.tum.in.www1.artemis.domain.iris.settings.IrisSubSettings; import de.tum.in.www1.artemis.domain.iris.settings.IrisSubSettingsType; +import de.tum.in.www1.artemis.domain.iris.settings.event.IrisBuildFailedEventSettings; +import de.tum.in.www1.artemis.domain.iris.settings.event.IrisEventSettings; +import de.tum.in.www1.artemis.domain.iris.settings.event.IrisEventType; +import de.tum.in.www1.artemis.domain.iris.settings.event.IrisJolEventSettings; +import de.tum.in.www1.artemis.domain.iris.settings.event.IrisProgressStalledEventSettings; import de.tum.in.www1.artemis.repository.iris.IrisSettingsRepository; import de.tum.in.www1.artemis.service.AuthorizationCheckService; import de.tum.in.www1.artemis.service.iris.IrisDefaultTemplateService; +import de.tum.in.www1.artemis.service.iris.dto.IrisCombinedEventSettingsDTO; import de.tum.in.www1.artemis.service.iris.dto.IrisCombinedSettingsDTO; import de.tum.in.www1.artemis.web.rest.errors.AccessForbiddenAlertException; import de.tum.in.www1.artemis.web.rest.errors.BadRequestAlertException; @@ -65,6 +73,14 @@ public IrisSettingsService(IrisSettingsRepository irisSettingsRepository, IrisSu this.authCheckService = authCheckService; } + private static T initializeSettings(T settings, Supplier constructor) { + if (settings == null) { + settings = constructor.get(); + settings.setEnabled(false); + } + return settings; + } + private Optional loadGlobalTemplateVersion() { return irisDefaultTemplateService.loadGlobalTemplateVersion(); } @@ -84,11 +100,11 @@ private IrisTemplate loadDefaultCompetencyGenerationTemplate() { /** * Hooks into the {@link ApplicationReadyEvent} and creates or updates the global IrisSettings object on startup. * - * @param event Unused event param used to specify when the method should be executed + * @param ignoredEvent Unused event param used to specify when the method should be executed */ @Profile(PROFILE_SCHEDULING) @EventListener - public void execute(ApplicationReadyEvent event) throws Exception { + public void execute(ApplicationReadyEvent ignoredEvent) throws Exception { var allGlobalSettings = irisSettingsRepository.findAllGlobalSettings(); if (allGlobalSettings.isEmpty()) { createInitialGlobalSettings(); @@ -115,6 +131,7 @@ private void createInitialGlobalSettings() { initializeIrisLectureIngestionSettings(settings); initializeIrisHestiaSettings(settings); initializeIrisCompetencyGenerationSettings(settings); + initializeIrisProactiveSettings(settings); irisSettingsRepository.save(settings); } @@ -139,20 +156,15 @@ private void autoUpdateGlobalSettings(IrisGlobalSettings settings) { if (settings.isEnableAutoUpdateCompetencyGeneration() || settings.getIrisCompetencyGenerationSettings() == null) { initializeIrisCompetencyGenerationSettings(settings); } + if (settings.isEnableAutoUpdateProactivity() || settings.getIrisProactivitySettings() == null) { + initializeIrisProactiveSettings(settings); + } globalVersion.ifPresent(settings::setCurrentVersion); saveIrisSettings(settings); } } - private static T initializeSettings(T settings, Supplier constructor) { - if (settings == null) { - settings = constructor.get(); - settings.setEnabled(false); - } - return settings; - } - private void initializeIrisChatSettings(IrisGlobalSettings settings) { var irisChatSettings = settings.getIrisChatSettings(); irisChatSettings = initializeSettings(irisChatSettings, IrisChatSubSettings::new); @@ -173,6 +185,32 @@ private void initializeIrisHestiaSettings(IrisGlobalSettings settings) { settings.setIrisHestiaSettings(irisHestiaSettings); } + private void initializeIrisProactiveSettings(IrisGlobalSettings settings) { + var irisProactivitySettings = settings.getIrisProactivitySettings(); + irisProactivitySettings = initializeSettings(irisProactivitySettings, IrisProactivitySubSettings::new); + initializeIrisEventSettings(irisProactivitySettings); + settings.setIrisProactivitySettings(irisProactivitySettings); + } + + private void initializeIrisEventSettings(IrisProactivitySubSettings settings) { + HashSet eventSettings = new HashSet<>(); + + var jolEventSettings = new IrisJolEventSettings(); + jolEventSettings.setActive(false); + eventSettings.add(jolEventSettings); + + var submissionFailedEventSettings = new IrisBuildFailedEventSettings(); + submissionFailedEventSettings.setActive(false); + eventSettings.add(submissionFailedEventSettings); + + var submissionSuccessfulEventSettings = new IrisProgressStalledEventSettings(); + submissionSuccessfulEventSettings.setActive(false); + eventSettings.add(submissionSuccessfulEventSettings); + + eventSettings.forEach(event -> event.setProactivitySubSettings(settings)); + settings.setEventSettings(eventSettings); + } + private void initializeIrisCompetencyGenerationSettings(IrisGlobalSettings settings) { var irisCompetencyGenerationSettings = settings.getIrisCompetencyGenerationSettings(); irisCompetencyGenerationSettings = initializeSettings(irisCompetencyGenerationSettings, IrisCompetencyGenerationSubSettings::new); @@ -274,14 +312,21 @@ private IrisGlobalSettings updateGlobalSettings(IrisGlobalSettings existingSetti existingSettings.setEnableAutoUpdateLectureIngestion(settingsUpdate.isEnableAutoUpdateLectureIngestion()); existingSettings.setEnableAutoUpdateHestia(settingsUpdate.isEnableAutoUpdateHestia()); existingSettings.setEnableAutoUpdateCompetencyGeneration(settingsUpdate.isEnableAutoUpdateCompetencyGeneration()); + existingSettings.setEnableAutoUpdateProactivity(settingsUpdate.isEnableAutoUpdateProactivity()); existingSettings.setIrisLectureIngestionSettings( irisSubSettingsService.update(existingSettings.getIrisLectureIngestionSettings(), settingsUpdate.getIrisLectureIngestionSettings(), null, GLOBAL)); + existingSettings.setIrisChatSettings(irisSubSettingsService.update(existingSettings.getIrisChatSettings(), settingsUpdate.getIrisChatSettings(), null, GLOBAL)); + existingSettings.setIrisHestiaSettings(irisSubSettingsService.update(existingSettings.getIrisHestiaSettings(), settingsUpdate.getIrisHestiaSettings(), null, GLOBAL)); + existingSettings.setIrisCompetencyGenerationSettings( irisSubSettingsService.update(existingSettings.getIrisCompetencyGenerationSettings(), settingsUpdate.getIrisCompetencyGenerationSettings(), null, GLOBAL)); + existingSettings.setIrisProactivitySettings( + irisSubSettingsService.update(existingSettings.getIrisProactivitySettings(), settingsUpdate.getIrisProactivitySettings(), null, GLOBAL)); + return irisSettingsRepository.save(existingSettings); } @@ -303,6 +348,9 @@ private IrisCourseSettings updateCourseSettings(IrisCourseSettings existingSetti existingSettings.setIrisCompetencyGenerationSettings(irisSubSettingsService.update(existingSettings.getIrisCompetencyGenerationSettings(), settingsUpdate.getIrisCompetencyGenerationSettings(), parentSettings.irisCompetencyGenerationSettings(), COURSE)); + existingSettings.setIrisProactivitySettings(irisSubSettingsService.update(existingSettings.getIrisProactivitySettings(), settingsUpdate.getIrisProactivitySettings(), + parentSettings.irisProactivitySettings(), COURSE)); + return irisSettingsRepository.save(existingSettings); } @@ -333,6 +381,38 @@ 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. * @@ -357,6 +437,30 @@ public boolean isEnabledFor(IrisSubSettingsType type, Exercise exercise) { return isFeatureEnabledInSettings(settings, type); } + /** + * Checks whether an Iris event is enabled for a course. + * + * @param type The Iris event to check + * @param course The course to check + * @return Whether the Iris event is active for the course + */ + public boolean isActivatedFor(IrisEventType type, Course course) { + var settings = getCombinedIrisEventSettingsFor(course, type, true); + return isEventEnabledInSettings(settings, type); + } + + /** + * Checks whether an Iris event is enabled for an exercise. + * + * @param type The Iris event to check + * @param exercise The exercise to check + * @return Whether the Iris event is active for the exercise + */ + public boolean isActivatedFor(IrisEventType type, Exercise exercise) { + var settings = getCombinedIrisEventSettingsFor(exercise.getCourseViaExerciseGroupOrCourseMember(), type, true); + return isEventEnabledInSettings(settings, type); + } + /** * Checks whether an Iris feature is enabled for an exercise. * Throws an exception if the feature is disabled. @@ -382,7 +486,7 @@ public IrisCombinedSettingsDTO getCombinedIrisGlobalSettings() { return new IrisCombinedSettingsDTO(irisSubSettingsService.combineChatSettings(settingsList, false), irisSubSettingsService.combineLectureIngestionSubSettings(settingsList, false), irisSubSettingsService.combineHestiaSettings(settingsList, false), - irisSubSettingsService.combineCompetencyGenerationSettings(settingsList, false)); + irisSubSettingsService.combineCompetencyGenerationSettings(settingsList, false), irisSubSettingsService.combineProactivitySettings(settingsList, false)); } /** @@ -402,7 +506,7 @@ public IrisCombinedSettingsDTO getCombinedIrisSettingsFor(Course course, boolean return new IrisCombinedSettingsDTO(irisSubSettingsService.combineChatSettings(settingsList, minimal), irisSubSettingsService.combineLectureIngestionSubSettings(settingsList, minimal), irisSubSettingsService.combineHestiaSettings(settingsList, minimal), - irisSubSettingsService.combineCompetencyGenerationSettings(settingsList, minimal)); + irisSubSettingsService.combineCompetencyGenerationSettings(settingsList, minimal), irisSubSettingsService.combineProactivitySettings(settingsList, minimal)); } /** @@ -423,7 +527,30 @@ public IrisCombinedSettingsDTO getCombinedIrisSettingsFor(Exercise exercise, boo return new IrisCombinedSettingsDTO(irisSubSettingsService.combineChatSettings(settingsList, minimal), irisSubSettingsService.combineLectureIngestionSubSettings(settingsList, minimal), irisSubSettingsService.combineHestiaSettings(settingsList, minimal), - irisSubSettingsService.combineCompetencyGenerationSettings(settingsList, minimal)); + irisSubSettingsService.combineCompetencyGenerationSettings(settingsList, minimal), irisSubSettingsService.combineProactivitySettings(settingsList, minimal)); + } + + /** + * Get the combined Iris event settings of a specific type for a course as an {@link IrisCombinedEventSettingsDTO}. + * Combines the global Iris settings with the course Iris settings and the exercise Iris settings. + * If minimal is true, only certain attributes are returned. The minimal version can safely be passed to the students. + * See also {@link IrisSubSettingsService} for how the combining works in detail + * + * @param course The course to get the Iris event settings for + * @param type The type of the event {@link IrisEventType} + * @param minimal Whether to return the minimal version of the settings + * @return The combined Iris event settings for the course + */ + public IrisCombinedEventSettingsDTO getCombinedIrisEventSettingsFor(Course course, IrisEventType type, boolean minimal) { + var settingsList = new ArrayList(); + settingsList.add(getGlobalSettings()); + settingsList.add(irisSettingsRepository.findCourseSettings(course.getId()).orElse(null)); + + return switch (type) { + case JOL -> irisSubSettingsService.combineEventSettingsOf(IrisJolEventSettings.class, settingsList, minimal); + case PROGRESS_STALLED -> irisSubSettingsService.combineEventSettingsOf(IrisProgressStalledEventSettings.class, settingsList, minimal); + case BUILD_FAILED -> irisSubSettingsService.combineEventSettingsOf(IrisBuildFailedEventSettings.class, settingsList, minimal); + }; } /** @@ -451,6 +578,17 @@ public IrisCourseSettings getDefaultSettingsFor(Course course) { settings.setIrisChatSettings(new IrisChatSubSettings()); settings.setIrisHestiaSettings(new IrisHestiaSubSettings()); settings.setIrisCompetencyGenerationSettings(new IrisCompetencyGenerationSubSettings()); + + var eventSettings = new HashSet(); + eventSettings.add(new IrisJolEventSettings()); + eventSettings.add(new IrisBuildFailedEventSettings()); + eventSettings.add(new IrisProgressStalledEventSettings()); + + var proactivitySettings = new IrisProactivitySubSettings(); + proactivitySettings.setEventSettings(eventSettings); + eventSettings.forEach(event -> event.setProactivitySubSettings(proactivitySettings)); + + settings.setIrisProactivitySettings(proactivitySettings); return settings; } @@ -525,6 +663,20 @@ private boolean isFeatureEnabledInSettings(IrisCombinedSettingsDTO settings, Iri case HESTIA -> settings.irisHestiaSettings().enabled(); case COMPETENCY_GENERATION -> settings.irisCompetencyGenerationSettings().enabled(); case LECTURE_INGESTION -> settings.irisLectureIngestionSettings().enabled(); + case PROACTIVITY -> settings.irisProactivitySettings().enabled(); + }; + } + + /** + * Checks if whether an Iris event is enabled in the given settings + * + * @param settings the settings + * @param type the type of the event + * @return Whether the settings type is enabled + */ + private boolean isEventEnabledInSettings(IrisCombinedEventSettingsDTO settings, IrisEventType type) { + return switch (type) { + case JOL, PROGRESS_STALLED, BUILD_FAILED -> settings.isActive(); }; } } diff --git a/src/main/java/de/tum/in/www1/artemis/service/iris/settings/IrisSubSettingsService.java b/src/main/java/de/tum/in/www1/artemis/service/iris/settings/IrisSubSettingsService.java index e4a609a23b56..29a4b10f16fd 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/iris/settings/IrisSubSettingsService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/iris/settings/IrisSubSettingsService.java @@ -2,12 +2,16 @@ import java.util.ArrayList; import java.util.Comparator; +import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; @@ -18,14 +22,21 @@ import de.tum.in.www1.artemis.domain.iris.settings.IrisExerciseSettings; import de.tum.in.www1.artemis.domain.iris.settings.IrisHestiaSubSettings; import de.tum.in.www1.artemis.domain.iris.settings.IrisLectureIngestionSubSettings; +import de.tum.in.www1.artemis.domain.iris.settings.IrisProactivitySubSettings; import de.tum.in.www1.artemis.domain.iris.settings.IrisSettings; import de.tum.in.www1.artemis.domain.iris.settings.IrisSettingsType; import de.tum.in.www1.artemis.domain.iris.settings.IrisSubSettings; +import de.tum.in.www1.artemis.domain.iris.settings.event.IrisBuildFailedEventSettings; +import de.tum.in.www1.artemis.domain.iris.settings.event.IrisEventSettings; +import de.tum.in.www1.artemis.domain.iris.settings.event.IrisJolEventSettings; +import de.tum.in.www1.artemis.domain.iris.settings.event.IrisProgressStalledEventSettings; import de.tum.in.www1.artemis.service.AuthorizationCheckService; import de.tum.in.www1.artemis.service.iris.dto.IrisCombinedChatSubSettingsDTO; import de.tum.in.www1.artemis.service.iris.dto.IrisCombinedCompetencyGenerationSubSettingsDTO; +import de.tum.in.www1.artemis.service.iris.dto.IrisCombinedEventSettingsDTO; import de.tum.in.www1.artemis.service.iris.dto.IrisCombinedHestiaSubSettingsDTO; import de.tum.in.www1.artemis.service.iris.dto.IrisCombinedLectureIngestionSubSettingsDTO; +import de.tum.in.www1.artemis.service.iris.dto.IrisCombinedProactivitySubSettingsDTO; /** * Service for handling {@link IrisSubSettings} objects. @@ -112,6 +123,38 @@ public IrisLectureIngestionSubSettings update(IrisLectureIngestionSubSettings cu return currentSettings; } + /** + * Updates a Proactivity 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). + * Special notes: + * - If the user is not an admin the enabled field will not be updated. + * + * @param currentSettings Current Proactivity sub settings. + * @param newSettings Updated Proactivity sub settings. + * @param parentSettings Parent Proactivity sub settings. + * @param settingsType Type of the settings the sub settings belong to. + * @return Updated Proactivity sub settings. + */ + public IrisProactivitySubSettings update(IrisProactivitySubSettings currentSettings, IrisProactivitySubSettings newSettings, + IrisCombinedProactivitySubSettingsDTO parentSettings, IrisSettingsType settingsType) { + if (newSettings == null) { + if (parentSettings == null) { + throw new IllegalArgumentException("Cannot delete the Proactivity settings"); + } + return null; + } + if (currentSettings == null) { + currentSettings = new IrisProactivitySubSettings(); + } + if (authCheckService.isAdmin() && (settingsType == IrisSettingsType.COURSE || settingsType == IrisSettingsType.GLOBAL)) { + currentSettings.setEnabled(newSettings.isEnabled()); + } + IrisProactivitySubSettings finalCurrentSettings = currentSettings; + newSettings.getEventSettings().forEach(eventSettings -> eventSettings.setProactivitySubSettings(finalCurrentSettings)); + finalCurrentSettings.setEventSettings(newSettings.getEventSettings()); + return finalCurrentSettings; + } + /** * Updates a Hestia 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). @@ -286,6 +329,22 @@ public IrisCombinedCompetencyGenerationSubSettingsDTO combineCompetencyGeneratio return new IrisCombinedCompetencyGenerationSubSettingsDTO(enabled, allowedModels, preferredModel, template); } + /** + * Combines the proactivity settings of multiple {@link IrisSettings} objects. + * If minimal is true, the returned object will only contain the enabled field. + * 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 proactivity settings. + */ + public IrisCombinedProactivitySubSettingsDTO combineProactivitySettings(ArrayList settingsList, boolean minimal) { + var actualSettingsList = settingsList.stream().filter(settings -> !(settings instanceof IrisExerciseSettings)).toList(); + var enabled = getCombinedEnabled(actualSettingsList, IrisSettings::getIrisProactivitySettings); + var eventSettings = minimal ? getCombinedEventSettings(actualSettingsList, IrisSettings::getIrisProactivitySettings) : null; + return new IrisCombinedProactivitySubSettingsDTO(enabled, eventSettings); + } + /** * Combines the enabled field of multiple {@link IrisSettings} objects. * Simply &&s all enabled fields together. @@ -359,4 +418,79 @@ private IrisTemplate getCombinedTemplate(List template != null && template.getContent() != null && !template.getContent().isBlank()).reduce((first, second) -> second).orElse(null); } + + /** + * Combines the event settings of multiple {@link IrisSettings} objects. + * Simply takes the last of each event type. + * + * @param settingsList List of {@link IrisSettings} objects to combine. + * @param proactivitySubSettingsFunction Function to get the proactivity settings from the sub settings from an IrisSettings object. + * @return Combined event settings. + */ + private Set getCombinedEventSettings(List settingsList, + Function proactivitySubSettingsFunction) { + var combinedSet = new HashSet(); + + // Create a supplier for the stream instead of a single stream + Supplier>> streamSupplier = () -> settingsList.stream().filter(Objects::nonNull).map(proactivitySubSettingsFunction).filter(Objects::nonNull) + .map(IrisProactivitySubSettings::getEventSettings).filter(Objects::nonNull); + + combinedSet.addAll(getCombinedEventSettingsOf(IrisProgressStalledEventSettings.class, streamSupplier.get(), IrisCombinedEventSettingsDTO::of)); + combinedSet.addAll(getCombinedEventSettingsOf(IrisBuildFailedEventSettings.class, streamSupplier.get(), IrisCombinedEventSettingsDTO::of)); + combinedSet.addAll(getCombinedEventSettingsOf(IrisJolEventSettings.class, streamSupplier.get(), IrisCombinedEventSettingsDTO::of)); + + return combinedSet; + } + + /** + * Combines the event settings of multiple {@link IrisSettings} objects of a specific type. + * Simply takes the last event settings of the specified type. + * + * @param eventSettingsClass Subclass of {@link IrisEventSettings} to combine. + * @param settingsList List of {@link IrisSettings} objects to combine. + * @param proactivitySubSettingsFunction Function to get the proactivity settings from the sub settings from an IrisSettings object. + * @param Subclass of {@link IrisEventSettings} to combine. + * @return Combined event settings. + */ + private IrisCombinedEventSettingsDTO getCombinedEventSettingsOf(Class eventSettingsClass, List settingsList, + Function proactivitySubSettingsFunction) { + Supplier>> streamSupplier = () -> settingsList.stream().filter(Objects::nonNull).map(proactivitySubSettingsFunction).filter(Objects::nonNull) + .map(IrisProactivitySubSettings::getEventSettings).filter(Objects::nonNull); + + return getCombinedEventSettingsOf(eventSettingsClass, streamSupplier.get(), IrisCombinedEventSettingsDTO::of).stream().findFirst().orElse(null); + + } + + /** + * Combines the event settings of multiple {@link IrisEventSettings} objects of a specific type. + * If minimal is true, the returned object will only contain the enabled field. + * The minimal version can safely be sent to students. + * + * @param settingClass Subclass of {@link IrisEventSettings} to combine. + * @param settingsList List of {@link IrisSettings} objects to combine. + * @param minimal Whether to return a minimal version of the combined settings. + * @param Subclass of {@link IrisEventSettings} to combine. + * @return Combined event settings of the specific type. + */ + public IrisCombinedEventSettingsDTO combineEventSettingsOf(Class settingClass, ArrayList settingsList, boolean minimal) { + var actualSettingsList = settingsList.stream().filter(settings -> !(settings instanceof IrisExerciseSettings)).toList(); + return minimal ? getCombinedEventSettingsOf(settingClass, actualSettingsList, IrisSettings::getIrisProactivitySettings) : null; + } + + /** + * Combines the event settings of multiple {@link IrisEventSettings} objects of a specific type. + * Simply takes the last event settings of the specified type. + * + * @param settingClass Subclass of {@link IrisEventSettings} to combine. + * @param settingsStream Stream of {@link IrisEventSettings} objects to combine. + * @param eventSettingsFunction Function to convert an event settings object to a combined event settings object. + * @param Subclass of {@link IrisEventSettings} to combine. + * @return Combined event settings. + */ + private Set getCombinedEventSettingsOf(Class settingClass, Stream> settingsStream, + Function eventSettingsFunction) { + return settingsStream + .map(s -> s.stream().filter(e -> e != null && e.getClass() == settingClass).map(settingClass::cast).map(eventSettingsFunction).collect(Collectors.toSet())) + .reduce((first, second) -> second).orElse(new HashSet<>()); + } } diff --git a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingMessagingService.java b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingMessagingService.java index d6b6835f6aee..0a644c3ea5d4 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingMessagingService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingMessagingService.java @@ -20,6 +20,7 @@ import de.tum.in.www1.artemis.domain.ProgrammingSubmission; import de.tum.in.www1.artemis.domain.Result; import de.tum.in.www1.artemis.domain.Team; +import de.tum.in.www1.artemis.domain.User; import de.tum.in.www1.artemis.domain.participation.Participation; import de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseParticipation; import de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseStudentParticipation; @@ -27,6 +28,8 @@ import de.tum.in.www1.artemis.repository.TeamRepository; import de.tum.in.www1.artemis.service.WebsocketMessagingService; import de.tum.in.www1.artemis.service.connectors.lti.LtiNewResultService; +import de.tum.in.www1.artemis.service.connectors.pyris.event.NewResultEvent; +import de.tum.in.www1.artemis.service.connectors.pyris.event.PyrisEventService; import de.tum.in.www1.artemis.service.notifications.GroupNotificationService; import de.tum.in.www1.artemis.web.rest.dto.SubmissionDTO; import de.tum.in.www1.artemis.web.websocket.ResultWebsocketService; @@ -48,13 +51,29 @@ public class ProgrammingMessagingService { private final TeamRepository teamRepository; + private final Optional pyrisEventService; + public ProgrammingMessagingService(GroupNotificationService groupNotificationService, WebsocketMessagingService websocketMessagingService, - ResultWebsocketService resultWebsocketService, Optional ltiNewResultService, TeamRepository teamRepository) { + ResultWebsocketService resultWebsocketService, Optional ltiNewResultService, TeamRepository teamRepository, + Optional pyrisEventService) { this.groupNotificationService = groupNotificationService; this.websocketMessagingService = websocketMessagingService; this.resultWebsocketService = resultWebsocketService; this.ltiNewResultService = ltiNewResultService; this.teamRepository = teamRepository; + this.pyrisEventService = pyrisEventService; + } + + private static String getExerciseTopicForTAAndAbove(long exerciseId) { + return EXERCISE_TOPIC_ROOT + exerciseId + PROGRAMMING_SUBMISSION_TOPIC; + } + + public static String getProgrammingExerciseTestCaseChangedTopic(Long programmingExerciseId) { + return "/topic/programming-exercises/" + programmingExerciseId + "/test-cases-changed"; + } + + private static String getProgrammingExerciseAllExerciseBuildsTriggeredTopic(Long programmingExerciseId) { + return "/topic/programming-exercises/" + programmingExerciseId + "/all-builds-triggered"; } public void notifyInstructorAboutStartedExerciseBuildRun(ProgrammingExercise programmingExercise) { @@ -144,18 +163,6 @@ public void notifyInstructorGroupAboutIllegalSubmissionsForExercise(ProgrammingE groupNotificationService.notifyInstructorGroupAboutIllegalSubmissionsForExercise(exercise, notificationText); } - private static String getExerciseTopicForTAAndAbove(long exerciseId) { - return EXERCISE_TOPIC_ROOT + exerciseId + PROGRAMMING_SUBMISSION_TOPIC; - } - - public static String getProgrammingExerciseTestCaseChangedTopic(Long programmingExerciseId) { - return "/topic/programming-exercises/" + programmingExerciseId + "/test-cases-changed"; - } - - private static String getProgrammingExerciseAllExerciseBuildsTriggeredTopic(Long programmingExerciseId) { - return "/topic/programming-exercises/" + programmingExerciseId + "/all-builds-triggered"; - } - /** * Notify user about new result. * @@ -167,9 +174,34 @@ public void notifyUserAboutNewResult(Result result, ProgrammingExerciseParticipa // notify user via websocket resultWebsocketService.broadcastNewResult((Participation) participation, result); - if (participation instanceof ProgrammingExerciseStudentParticipation studentParticipation && ltiNewResultService.isPresent()) { + if (participation instanceof ProgrammingExerciseStudentParticipation studentParticipation) { // do not try to report results for template or solution participations - ltiNewResultService.get().onNewResult(studentParticipation); + ltiNewResultService.ifPresent(newResultService -> newResultService.onNewResult(studentParticipation)); + // Inform Iris about the submission status + notifyIrisAboutSubmissionStatus(result, studentParticipation); + } + } + + /** + * Notify Iris about the submission status for the given result and student participation. + * If the submission was successful, Iris will be informed about the successful submission. + * If the submission failed, Iris will be informed about the submission failure. + * Iris will only be informed about the submission status if the participant is a user. + * + * @param result the result for which Iris should be informed about the submission status + * @param studentParticipation the student participation for which Iris should be informed about the submission status + */ + private void notifyIrisAboutSubmissionStatus(Result result, ProgrammingExerciseStudentParticipation studentParticipation) { + if (studentParticipation.getParticipant() instanceof User) { + pyrisEventService.ifPresent(eventService -> { + // Inform event service about the new result + try { + eventService.trigger(new NewResultEvent(result)); + } + catch (Exception e) { + log.error("Could not trigger service for result {}", result.getId(), e); + } + }); } } } diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/iris/IrisExerciseChatSessionResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/iris/IrisExerciseChatSessionResource.java index f3bf07426305..08c2d79a9f55 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/iris/IrisExerciseChatSessionResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/iris/IrisExerciseChatSessionResource.java @@ -5,7 +5,6 @@ import java.util.List; import org.springframework.context.annotation.Profile; -import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -24,6 +23,7 @@ import de.tum.in.www1.artemis.service.connectors.pyris.PyrisHealthIndicator; import de.tum.in.www1.artemis.service.iris.IrisRateLimitService; import de.tum.in.www1.artemis.service.iris.IrisSessionService; +import de.tum.in.www1.artemis.service.iris.session.IrisExerciseChatSessionService; import de.tum.in.www1.artemis.service.iris.settings.IrisSettingsService; import de.tum.in.www1.artemis.web.rest.errors.ConflictException; @@ -49,9 +49,11 @@ public class IrisExerciseChatSessionResource { private final IrisExerciseChatSessionRepository irisExerciseChatSessionRepository; + private final IrisExerciseChatSessionService irisExerciseChatSessionService; + protected IrisExerciseChatSessionResource(IrisExerciseChatSessionRepository irisExerciseChatSessionRepository, UserRepository userRepository, ExerciseRepository exerciseRepository, IrisSessionService irisSessionService, IrisSettingsService irisSettingsService, PyrisHealthIndicator pyrisHealthIndicator, - IrisRateLimitService irisRateLimitService) { + IrisRateLimitService irisRateLimitService, IrisExerciseChatSessionService irisExerciseChatSessionService) { this.irisExerciseChatSessionRepository = irisExerciseChatSessionRepository; this.userRepository = userRepository; this.irisSessionService = irisSessionService; @@ -59,6 +61,7 @@ protected IrisExerciseChatSessionResource(IrisExerciseChatSessionRepository iris this.pyrisHealthIndicator = pyrisHealthIndicator; this.irisRateLimitService = irisRateLimitService; this.exerciseRepository = exerciseRepository; + this.irisExerciseChatSessionService = irisExerciseChatSessionService; } /** @@ -76,15 +79,8 @@ public ResponseEntity getCurrentSessionOrCreateIfNotExi irisSettingsService.isEnabledForElseThrow(IrisSubSettingsType.CHAT, exercise); var user = userRepository.getUserWithGroupsAndAuthorities(); - var sessionOptional = irisExerciseChatSessionRepository.findLatestByExerciseIdAndUserIdWithMessages(exercise.getId(), user.getId(), Pageable.ofSize(1)).stream() - .findFirst(); - if (sessionOptional.isPresent()) { - var session = sessionOptional.get(); - irisSessionService.checkHasAccessToIrisSession(session, user); - return ResponseEntity.ok(session); - } - - return createSessionForExercise(exerciseId); + var session = irisExerciseChatSessionService.getCurrentSessionOrCreateIfNotExists((ProgrammingExercise) exercise, user, false); + return ResponseEntity.ok(session); } /** @@ -99,7 +95,7 @@ public ResponseEntity> getAllSessions(@PathVariabl var exercise = exerciseRepository.findByIdElseThrow(exerciseId); ProgrammingExercise programmingExercise = validateExercise(exercise); - irisSettingsService.isEnabledForElseThrow(IrisSubSettingsType.CHAT, exercise); + irisSettingsService.isEnabledForElseThrow(IrisSubSettingsType.CHAT, programmingExercise); var user = userRepository.getUserWithGroupsAndAuthorities(); var sessions = irisExerciseChatSessionRepository.findByExerciseIdAndUserIdElseThrow(exercise.getId(), user.getId()); @@ -121,10 +117,10 @@ public ResponseEntity createSessionForExercise(@PathVar var exercise = exerciseRepository.findByIdElseThrow(exerciseId); ProgrammingExercise programmingExercise = validateExercise(exercise); - irisSettingsService.isEnabledForElseThrow(IrisSubSettingsType.CHAT, exercise); + irisSettingsService.isEnabledForElseThrow(IrisSubSettingsType.CHAT, programmingExercise); var user = userRepository.getUserWithGroupsAndAuthorities(); - var session = irisExerciseChatSessionRepository.save(new IrisExerciseChatSession(programmingExercise, user)); + var session = irisExerciseChatSessionService.createSession((ProgrammingExercise) exercise, user, false); var uriString = "/api/iris/sessions/" + session.getId(); return ResponseEntity.created(new URI(uriString)).body(session); diff --git a/src/main/resources/config/liquibase/changelog/20240714145600_changelog.xml b/src/main/resources/config/liquibase/changelog/20240714145600_changelog.xml new file mode 100644 index 000000000000..43d11fda41ea --- /dev/null +++ b/src/main/resources/config/liquibase/changelog/20240714145600_changelog.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/config/liquibase/master.xml b/src/main/resources/config/liquibase/master.xml index c5be79948d2f..881099ec5980 100644 --- a/src/main/resources/config/liquibase/master.xml +++ b/src/main/resources/config/liquibase/master.xml @@ -18,6 +18,7 @@ + diff --git a/src/main/webapp/app/entities/iris/settings/iris-event-settings.model.ts b/src/main/webapp/app/entities/iris/settings/iris-event-settings.model.ts new file mode 100644 index 000000000000..8d18b562b927 --- /dev/null +++ b/src/main/webapp/app/entities/iris/settings/iris-event-settings.model.ts @@ -0,0 +1,37 @@ +import { BaseEntity } from 'app/shared/model/base-entity'; + +export enum IrisEventLevel { + COURSE = 'COURSE', + EXERCISE = 'EXERCISE', +} + +export enum IrisEventType { + JOL = 'jol', + PROGRESS_STALLED = 'progress_stalled', + BUILD_FAILED = 'build_failed', +} + +export class IrisEventSettings implements BaseEntity { + id?: number; + type: IrisEventType; + active = false; + pipelineVariant: string; + target: IrisEventLevel; +} +export class JolEventSettings extends IrisEventSettings { + target = IrisEventLevel.COURSE; + type = IrisEventType.JOL; + pipelineVariant = 'jol'; +} + +export class ProgressStalledEventSettings extends IrisEventSettings { + target = IrisEventLevel.COURSE; + type = IrisEventType.PROGRESS_STALLED; + pipelineVariant = 'progress_stalled'; +} + +export class BuildFailedEventSettings extends IrisEventSettings { + target = IrisEventLevel.EXERCISE; + type = IrisEventType.BUILD_FAILED; + pipelineVariant = 'build_failed'; +} 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 017c3ea2cffa..e0c3ec8bd9b0 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 @@ -4,6 +4,7 @@ import { IrisCompetencyGenerationSubSettings, IrisHestiaSubSettings, IrisLectureIngestionSubSettings, + IrisProactivitySubSettings, } from 'app/entities/iris/settings/iris-sub-settings.model'; export enum IrisSettingsType { @@ -19,6 +20,7 @@ export abstract class IrisSettings implements BaseEntity { irisLectureIngestionSettings?: IrisLectureIngestionSubSettings; irisHestiaSettings?: IrisHestiaSubSettings; irisCompetencyGenerationSettings?: IrisCompetencyGenerationSubSettings; + irisProactivitySettings?: IrisProactivitySubSettings; } export class IrisGlobalSettings implements IrisSettings { @@ -29,10 +31,12 @@ export class IrisGlobalSettings implements IrisSettings { enableAutoUpdateLectureIngestion?: boolean; enableAutoUpdateHestia?: boolean; enableAutoUpdateCompetencyGeneration?: boolean; + enableAutoUpdateProactivity?: boolean; irisChatSettings?: IrisChatSubSettings; irisLectureIngestionSettings?: IrisLectureIngestionSubSettings; irisHestiaSettings?: IrisHestiaSubSettings; irisCompetencyGenerationSettings?: IrisCompetencyGenerationSubSettings; + irisProactivitySettings?: IrisProactivitySubSettings; } export class IrisCourseSettings implements IrisSettings { @@ -43,6 +47,7 @@ export class IrisCourseSettings implements IrisSettings { irisLectureIngestionSettings?: IrisLectureIngestionSubSettings; irisHestiaSettings?: IrisHestiaSubSettings; irisCompetencyGenerationSettings?: IrisCompetencyGenerationSubSettings; + irisProactivitySettings?: IrisProactivitySubSettings; } export class IrisExerciseSettings implements IrisSettings { 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 8848394f1350..33490de08879 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,11 +1,13 @@ import { BaseEntity } from 'app/shared/model/base-entity'; import { IrisTemplate } from 'app/entities/iris/settings/iris-template'; +import { IrisEventSettings } from 'app/entities/iris/settings/iris-event-settings.model'; export enum IrisSubSettingsType { CHAT = 'chat', HESTIA = 'hestia', COMPETENCY_GENERATION = 'competency-generation', LECTURE_INGESTION = 'lecture-ingestion', + PROACTIVITY = 'proactivity', } export abstract class IrisSubSettings implements BaseEntity { @@ -28,6 +30,11 @@ export class IrisLectureIngestionSubSettings extends IrisSubSettings { autoIngestOnLectureAttachmentUpload: boolean; } +export class IrisProactivitySubSettings extends IrisSubSettings { + type = IrisSubSettingsType.PROACTIVITY; + eventSettings: IrisEventSettings[]; +} + export class IrisHestiaSubSettings extends IrisSubSettings { type = IrisSubSettingsType.HESTIA; template?: IrisTemplate; diff --git a/src/main/webapp/app/iris/iris.module.ts b/src/main/webapp/app/iris/iris.module.ts index 5473966d0275..76424cccb0eb 100644 --- a/src/main/webapp/app/iris/iris.module.ts +++ b/src/main/webapp/app/iris/iris.module.ts @@ -23,6 +23,7 @@ import { FeatureToggleModule } from 'app/shared/feature-toggle/feature-toggle.mo import { IrisBaseChatbotComponent } from 'app/iris/base-chatbot/iris-base-chatbot.component'; import { ChatStatusBarComponent } from 'app/iris/base-chatbot/chat-status-bar/chat-status-bar.component'; import { CourseChatbotComponent } from 'app/iris/course-chatbot/course-chatbot.component'; +import { IrisEventSettingsUpdateComponent } from 'app/iris/settings/iris-settings-update/iris-event-settings-update/iris-event-settings-update.component'; @NgModule({ declarations: [ @@ -52,6 +53,7 @@ import { CourseChatbotComponent } from 'app/iris/course-chatbot/course-chatbot.c ArtemisSharedComponentModule, RouterModule, FeatureToggleModule, + IrisEventSettingsUpdateComponent, ], exports: [IrisExerciseChatbotButtonComponent, IrisEnabledComponent, IrisLogoButtonComponent, IrisBaseChatbotComponent, CourseChatbotComponent], }) diff --git a/src/main/webapp/app/iris/settings/iris-settings-update/iris-event-settings-update/iris-event-settings-update.component.html b/src/main/webapp/app/iris/settings/iris-settings-update/iris-event-settings-update/iris-event-settings-update.component.html new file mode 100644 index 000000000000..a4f36ddaeead --- /dev/null +++ b/src/main/webapp/app/iris/settings/iris-settings-update/iris-event-settings-update/iris-event-settings-update.component.html @@ -0,0 +1,18 @@ +
+
+ {{ 'artemisApp.iris.settings.subSettings.proactivitySettings.eventSettings.active' | artemisTranslate }} +
+
+ {{ 'artemisApp.iris.settings.subSettings.proactivitySettings.eventSettings.inactive' | artemisTranslate }} +
+
diff --git a/src/main/webapp/app/iris/settings/iris-settings-update/iris-event-settings-update/iris-event-settings-update.component.ts b/src/main/webapp/app/iris/settings/iris-settings-update/iris-event-settings-update/iris-event-settings-update.component.ts new file mode 100644 index 000000000000..97e84d2ba7ef --- /dev/null +++ b/src/main/webapp/app/iris/settings/iris-settings-update/iris-event-settings-update/iris-event-settings-update.component.ts @@ -0,0 +1,52 @@ +import { Component, EventEmitter, Input, Output, computed, signal } from '@angular/core'; +import { IrisEventSettings } from 'app/entities/iris/settings/iris-event-settings.model'; +import { ButtonType } from 'app/shared/components/button.component'; +import { AccountService } from 'app/core/auth/account.service'; +import { IrisSettingsType } from 'app/entities/iris/settings/iris-settings.model'; +import { ArtemisSharedCommonModule } from 'app/shared/shared-common.module'; + +@Component({ + selector: 'jhi-iris-event-settings-update', + standalone: true, + imports: [ArtemisSharedCommonModule], + templateUrl: './iris-event-settings-update.component.html', +}) +export class IrisEventSettingsUpdateComponent { + @Input({ required: true }) set eventSettings(value: IrisEventSettings) { + this.settingsSignal.set(value); + } + + @Input({ required: true }) set proactivityDisabled(value: boolean) { + this.proactivityDisabledSignal.set(value); + } + @Input() settingsType!: IrisSettingsType; + @Input() parentEventSettings?: IrisEventSettings; + + @Output() eventSettingsChange = new EventEmitter(); + + private settingsSignal = signal({} as IrisEventSettings); + private proactivityDisabledSignal = signal(false); + + inheritDisabled = computed(() => + this.parentEventSettings !== undefined ? this.proactivityDisabledSignal() || !this.parentEventSettings.active : this.proactivityDisabledSignal(), + ); + isSettingsSwitchDisabled = computed(() => (!this.isAdmin() && this.settingsType !== IrisSettingsType.EXERCISE) || this.inheritDisabled()); + + // Computed properties + settings = computed(() => this.settingsSignal()); + active = computed(() => this.settings().active); + isAdmin = signal(false); + + // Constants + readonly WARNING = ButtonType.WARNING; + + constructor(private readonly accountService: AccountService) { + this.isAdmin.set(this.accountService.isAdmin()); + } + + updateSetting(key: keyof IrisEventSettings, value: any) { + const updatedSettings = { ...this.settings(), [key]: value }; + this.settingsSignal.set(updatedSettings); + this.eventSettingsChange.emit(updatedSettings); + } +} diff --git a/src/main/webapp/app/iris/settings/iris-settings-update/iris-global-autoupdate-settings-update/iris-global-autoupdate-settings-update.component.html b/src/main/webapp/app/iris/settings/iris-settings-update/iris-global-autoupdate-settings-update/iris-global-autoupdate-settings-update.component.html index efb780138e8c..256d121d5819 100644 --- a/src/main/webapp/app/iris/settings/iris-settings-update/iris-global-autoupdate-settings-update/iris-global-autoupdate-settings-update.component.html +++ b/src/main/webapp/app/iris/settings/iris-settings-update/iris-global-autoupdate-settings-update/iris-global-autoupdate-settings-update.component.html @@ -16,5 +16,9 @@ +
+ + +
} 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 b28a3a4c690c..0a8508204fdc 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 @@ -76,5 +76,53 @@

+

+ + + @if (irisSettings.irisProactivitySettings?.eventSettings) { +
+

+
+
+ @for (eventSettings of irisSettings.irisProactivitySettings!.eventSettings; track eventSettings.id) { + @switch (eventSettings.type) { + @case (IrisEventType.BUILD_FAILED) { +
+
+
+ } + @case (IrisEventType.PROGRESS_STALLED) { +
+
+
+ } + @case (IrisEventType.JOL) { +
+
+
+ } + } +
+ +
+
+ } + } + } } diff --git a/src/main/webapp/app/iris/settings/iris-settings-update/iris-settings-update.component.ts b/src/main/webapp/app/iris/settings/iris-settings-update/iris-settings-update.component.ts index 5bde2f10f791..9b79acc12950 100644 --- a/src/main/webapp/app/iris/settings/iris-settings-update/iris-settings-update.component.ts +++ b/src/main/webapp/app/iris/settings/iris-settings-update/iris-settings-update.component.ts @@ -14,8 +14,10 @@ import { IrisCompetencyGenerationSubSettings, IrisHestiaSubSettings, IrisLectureIngestionSubSettings, + IrisProactivitySubSettings, } from 'app/entities/iris/settings/iris-sub-settings.model'; import { AccountService } from 'app/core/auth/account.service'; +import { BuildFailedEventSettings, IrisEventSettings, IrisEventType, JolEventSettings, ProgressStalledEventSettings } from 'app/entities/iris/settings/iris-event-settings.model'; @Component({ selector: 'jhi-iris-settings-update', @@ -31,6 +33,7 @@ export class IrisSettingsUpdateComponent implements OnInit, DoCheck, ComponentCa public irisSettings?: IrisSettings; public parentIrisSettings?: IrisSettings; public allIrisModels?: IrisModel[]; + public parentIrisEventSettings?: { [key: string]: IrisEventSettings }; originalIrisSettings?: IrisSettings; @@ -103,6 +106,12 @@ export class IrisSettingsUpdateComponent implements OnInit, DoCheck, ComponentCa this.alertService.error('artemisApp.iris.settings.error.noParentSettings'); } this.parentIrisSettings = settings; + this.parentIrisEventSettings = {}; + if (settings?.irisProactivitySettings?.eventSettings) { + settings.irisProactivitySettings.eventSettings.forEach((eventSetting) => { + this.parentIrisEventSettings![eventSetting.type] = eventSetting; + }); + } }); } @@ -122,6 +131,15 @@ export class IrisSettingsUpdateComponent implements OnInit, DoCheck, ComponentCa if (!this.irisSettings.irisCompetencyGenerationSettings) { this.irisSettings.irisCompetencyGenerationSettings = new IrisCompetencyGenerationSubSettings(); } + if (!this.irisSettings.irisProactivitySettings) { + this.irisSettings.irisProactivitySettings = new IrisProactivitySubSettings(); + } + if (!this.irisSettings.irisProactivitySettings.eventSettings) { + const jolEventSettings = new JolEventSettings(); + const progressStalledEventSettings = new ProgressStalledEventSettings(); + const buildFailedEventSettings = new BuildFailedEventSettings(); + this.irisSettings.irisProactivitySettings.eventSettings = [jolEventSettings, progressStalledEventSettings, buildFailedEventSettings]; + } } saveIrisSettings(): void { @@ -183,4 +201,17 @@ export class IrisSettingsUpdateComponent implements OnInit, DoCheck, ComponentCa return this.irisSettingsService.setProgrammingExerciseSettings(this.exerciseId!, this.irisSettings!); } } + + eventSettingsChanged(eventSettings: IrisEventSettings): void { + if (!this.irisSettings?.irisProactivitySettings) { + return; + } + const eventSettingsIndex = this.irisSettings.irisProactivitySettings.eventSettings.findIndex((setting) => setting.type === eventSettings.type); + if (eventSettingsIndex >= 0) { + this.irisSettings.irisProactivitySettings.eventSettings[eventSettingsIndex] = eventSettings; + this.isDirty = true; + } + } + + protected readonly IrisEventType = IrisEventType; } diff --git a/src/main/webapp/i18n/de/iris.json b/src/main/webapp/i18n/de/iris.json index 34572e7581bd..8447cdedd46a 100644 --- a/src/main/webapp/i18n/de/iris.json +++ b/src/main/webapp/i18n/de/iris.json @@ -27,6 +27,25 @@ }, "hestiaSettings": "Hestia Einstellungen", "competencyGenerationSettings": "Kompetenzgenerierung Einstellungen", + "proactivitySettings": { + "title": "Proaktivitätseinstellungen", + "eventSettings": { + "title": "Ereigniseinstellungen", + "progressStalled": "Fortschritt-verzögert Ereignis", + "buildFailed": "Fehlgeschlagenes Build-Ereignis", + "jol": "Lernbeurteilungsereignis", + "active": "Aktiv", + "inactive": "Inaktiv", + "target": "Ziel", + "pipelineVariant": "Pipeline-Variante", + "tooltips": { + "active": "Wenn das Ereignis aktiv ist, wird es für Proaktivität berücksichtigt.", + "inactive": "Wenn das Ereignis inaktiv ist, wird es nicht für Proaktivität berücksichtigt.", + "target": "Das Ziel des Ereignisses. Das Ziel bestimmt den Typ der Iris-Chat-Sitzung, an die die Ereignisantwort übermittelt wird.", + "pipelineVariant": "Die Pyris-Pipeline-Variante, die für das Ereignis verwendet werden soll." + } + } + }, "enabled-disabled": "Aktiviert/Deaktiviert", "models": { "title": "Modelle", diff --git a/src/main/webapp/i18n/en/iris.json b/src/main/webapp/i18n/en/iris.json index 6afbb928d5c9..aa6af6fbd078 100644 --- a/src/main/webapp/i18n/en/iris.json +++ b/src/main/webapp/i18n/en/iris.json @@ -27,6 +27,25 @@ }, "hestiaSettings": "Hestia Settings", "competencyGenerationSettings": "Competency Generation Settings", + "proactivitySettings": { + "title": "Proactivity Settings", + "eventSettings": { + "title": "Event Settings", + "progressStalled": "Progress Stalled Event", + "buildFailed": "Build Failed Event", + "jol": "Judgement of Learning Event", + "active": "Active", + "inactive": "Inactive", + "target": "Target", + "pipelineVariant": "Pipeline Variant", + "tooltips": { + "active": "If the event is active, it will be considered for proactivity.", + "inactive": "If the event is inactive, it will not be considered for proactivity.", + "target": "The target of the event. Target determines the type of Iris Chat session that the event response will be delivered.", + "pipelineVariant": "The Pyris pipeline variant that should be used for the event." + } + } + }, "enabled-disabled": "Enabled/Disabled", "models": { "title": "Models", @@ -70,7 +89,8 @@ "chatLabel": "Auto Update Chat Settings", "hestiaLabel": "Auto Update Hestia Settings", "lectureIngestionLabel": "Auto Update Lecture Ingestion Settings", - "competencyGenerationLabel": "Auto Update Competency Generation Settings" + "competencyGenerationLabel": "Auto Update Competency Generation Settings", + "proactivityLabel": "Auto Update Proactivity Settings" } }, "error": { diff --git a/src/test/java/de/tum/in/www1/artemis/AbstractSpringIntegrationLocalCILocalVCTest.java b/src/test/java/de/tum/in/www1/artemis/AbstractSpringIntegrationLocalCILocalVCTest.java index 056a664010ef..1abfa061d3e4 100644 --- a/src/test/java/de/tum/in/www1/artemis/AbstractSpringIntegrationLocalCILocalVCTest.java +++ b/src/test/java/de/tum/in/www1/artemis/AbstractSpringIntegrationLocalCILocalVCTest.java @@ -42,9 +42,13 @@ import de.tum.in.www1.artemis.repository.SolutionProgrammingExerciseParticipationRepository; import de.tum.in.www1.artemis.repository.TemplateProgrammingExerciseParticipationRepository; import de.tum.in.www1.artemis.service.ResourceLoaderService; +import de.tum.in.www1.artemis.service.competency.CompetencyJolService; import de.tum.in.www1.artemis.service.connectors.localci.LocalCIService; import de.tum.in.www1.artemis.service.connectors.localvc.LocalVCService; +import de.tum.in.www1.artemis.service.connectors.pyris.PyrisPipelineService; import de.tum.in.www1.artemis.service.exam.ExamLiveEventsService; +import de.tum.in.www1.artemis.service.iris.session.IrisCourseChatSessionService; +import de.tum.in.www1.artemis.service.iris.session.IrisExerciseChatSessionService; import de.tum.in.www1.artemis.service.ldap.LdapUserService; import de.tum.in.www1.artemis.service.notifications.GroupNotificationScheduleService; import de.tum.in.www1.artemis.service.programming.ProgrammingMessagingService; @@ -121,6 +125,18 @@ public abstract class AbstractSpringIntegrationLocalCILocalVCTest extends Abstra @SpyBean protected GroupNotificationScheduleService groupNotificationScheduleService; + @SpyBean + protected IrisCourseChatSessionService irisCourseChatSessionService; + + @SpyBean + protected CompetencyJolService competencyJolService; + + @SpyBean + protected PyrisPipelineService pyrisPipelineService; + + @SpyBean + protected IrisExerciseChatSessionService irisExerciseChatSessionService; + @Value("${artemis.version-control.url}") protected URL localVCBaseUrl; diff --git a/src/test/java/de/tum/in/www1/artemis/connector/IrisRequestMockProvider.java b/src/test/java/de/tum/in/www1/artemis/connector/IrisRequestMockProvider.java index 3f248a9e598c..dc160823f4b4 100644 --- a/src/test/java/de/tum/in/www1/artemis/connector/IrisRequestMockProvider.java +++ b/src/test/java/de/tum/in/www1/artemis/connector/IrisRequestMockProvider.java @@ -29,6 +29,7 @@ import de.tum.in.www1.artemis.service.connectors.pyris.dto.PyrisHealthStatusDTO; import de.tum.in.www1.artemis.service.connectors.pyris.dto.PyrisModelDTO; +import de.tum.in.www1.artemis.service.connectors.pyris.dto.chat.course.PyrisCourseChatPipelineExecutionDTO; import de.tum.in.www1.artemis.service.connectors.pyris.dto.chat.exercise.PyrisExerciseChatPipelineExecutionDTO; import de.tum.in.www1.artemis.service.connectors.pyris.dto.competency.PyrisCompetencyExtractionPipelineExecutionDTO; import de.tum.in.www1.artemis.service.connectors.pyris.dto.lectureingestionwebhook.PyrisWebhookLectureIngestionExecutionDTO; @@ -120,6 +121,33 @@ public void mockIngestionWebhookRunResponse(Consumer responseConsumer) { + mockServer.expect(ExpectedCount.max(2), requestTo(pipelinesApiURL + "/tutor-chat/submission_failed/run")).andExpect(method(HttpMethod.POST)).andRespond(request -> { + var mockRequest = (MockClientHttpRequest) request; + var dto = mapper.readValue(mockRequest.getBodyAsString(), PyrisExerciseChatPipelineExecutionDTO.class); + responseConsumer.accept(dto); + return MockRestResponseCreators.withRawStatus(HttpStatus.ACCEPTED.value()).createResponse(request); + }); + } + + public void mockSubmissionSuccessfulEventRunResponse(Consumer responseConsumer) { + mockServer.expect(ExpectedCount.max(2), requestTo(pipelinesApiURL + "/course-chat/submission_successful/run")).andExpect(method(HttpMethod.POST)).andRespond(request -> { + var mockRequest = (MockClientHttpRequest) request; + var dto = mapper.readValue(mockRequest.getBodyAsString(), PyrisCourseChatPipelineExecutionDTO.class); + responseConsumer.accept(dto); + return MockRestResponseCreators.withRawStatus(HttpStatus.ACCEPTED.value()).createResponse(request); + }); + } + + public void mockJolEventRunResponse(Consumer responseConsumer) { + mockServer.expect(ExpectedCount.once(), requestTo(pipelinesApiURL + "/course-chat/jol/run")).andExpect(method(HttpMethod.POST)).andRespond(request -> { + var mockRequest = (MockClientHttpRequest) request; + var dto = mapper.readValue(mockRequest.getBodyAsString(), PyrisCourseChatPipelineExecutionDTO.class); + responseConsumer.accept(dto); + return MockRestResponseCreators.withRawStatus(HttpStatus.ACCEPTED.value()).createResponse(request); + }); + } + public void mockRunError(int httpStatus) { // @formatter:off mockServer diff --git a/src/test/java/de/tum/in/www1/artemis/iris/AbstractIrisIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/iris/AbstractIrisIntegrationTest.java index dba05fa055cd..590490f62e2d 100644 --- a/src/test/java/de/tum/in/www1/artemis/iris/AbstractIrisIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/iris/AbstractIrisIntegrationTest.java @@ -22,6 +22,10 @@ import de.tum.in.www1.artemis.domain.ProgrammingExercise; import de.tum.in.www1.artemis.domain.iris.IrisTemplate; import de.tum.in.www1.artemis.domain.iris.settings.IrisSubSettings; +import de.tum.in.www1.artemis.domain.iris.settings.event.IrisBuildFailedEventSettings; +import de.tum.in.www1.artemis.domain.iris.settings.event.IrisEventSettings; +import de.tum.in.www1.artemis.domain.iris.settings.event.IrisJolEventSettings; +import de.tum.in.www1.artemis.domain.iris.settings.event.IrisProgressStalledEventSettings; import de.tum.in.www1.artemis.exercise.programming.ProgrammingExerciseUtilService; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.iris.IrisSettingsRepository; @@ -67,6 +71,15 @@ protected void activateIrisGlobally() { activateSubSettings(globalSettings.getIrisHestiaSettings()); activateSubSettings(globalSettings.getIrisLectureIngestionSettings()); activateSubSettings(globalSettings.getIrisCompetencyGenerationSettings()); + activateSubSettings(globalSettings.getIrisProactivitySettings()); + + // Active Iris events + var eventSettings = globalSettings.getIrisProactivitySettings().getEventSettings(); + + activateEventSettingsFor(IrisProgressStalledEventSettings.class, eventSettings); + activateEventSettingsFor(IrisBuildFailedEventSettings.class, eventSettings); + activateEventSettingsFor(IrisJolEventSettings.class, eventSettings); + irisSettingsRepository.save(globalSettings); } @@ -79,6 +92,43 @@ private void activateSubSettings(IrisSubSettings settings) { settings.setEnabled(true); settings.setPreferredModel(null); settings.setAllowedModels(new TreeSet<>(Set.of("dummy"))); + + } + + /** + * Activates the given event settings for the given type of event. + * + * @param eventSettingsClass the type of event settings + * @param settings the settings to be activated + */ + private void activateEventSettingsFor(Class eventSettingsClass, Set settings) { + settings.stream().filter(e -> e != null && e.getClass() == eventSettingsClass).forEach(e -> { + e.setActive(true); + }); + } + + /** + * Deactivates the given event settings for the given type of event on the course. + * + * @param eventSettingsClass the type of event settings + * @param course the course for which the settings should be deactivated + */ + public void deactivateEventSettingsFor(Class eventSettingsClass, Course course) { + var courseSettings = irisSettingsService.getRawIrisSettingsFor(course); + var eventSettings = courseSettings.getIrisProactivitySettings().getEventSettings(); + + deactivateEventSettingsFor(eventSettingsClass, eventSettings); + irisSettingsRepository.save(courseSettings); + } + + /** + * Deactivates the given event settings for the given type of event. + * + * @param eventSettingsClass the type of event settings + * @param settings the settings to be deactivated + */ + private void deactivateEventSettingsFor(Class eventSettingsClass, Set settings) { + settings.stream().filter(e -> e != null && e.getClass() == eventSettingsClass).forEach(e -> e.setActive(false)); } protected void activateIrisFor(Course course) { @@ -95,6 +145,15 @@ protected void activateIrisFor(Course course) { activateSubSettings(courseSettings.getIrisLectureIngestionSettings()); + activateSubSettings(courseSettings.getIrisProactivitySettings()); + + // Active Iris events + var eventSettings = courseSettings.getIrisProactivitySettings().getEventSettings(); + + activateEventSettingsFor(IrisProgressStalledEventSettings.class, eventSettings); + activateEventSettingsFor(IrisBuildFailedEventSettings.class, eventSettings); + activateEventSettingsFor(IrisJolEventSettings.class, eventSettings); + irisSettingsRepository.save(courseSettings); } diff --git a/src/test/java/de/tum/in/www1/artemis/iris/PyrisEventSystemTest.java b/src/test/java/de/tum/in/www1/artemis/iris/PyrisEventSystemTest.java new file mode 100644 index 000000000000..ed47f49ae819 --- /dev/null +++ b/src/test/java/de/tum/in/www1/artemis/iris/PyrisEventSystemTest.java @@ -0,0 +1,200 @@ +package de.tum.in.www1.artemis.iris; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.awaitility.Awaitility.await; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.time.ZonedDateTime; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.eclipse.jgit.api.errors.GitAPIException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.test.context.support.WithMockUser; + +import de.tum.in.www1.artemis.competency.CompetencyUtilService; +import de.tum.in.www1.artemis.domain.Course; +import de.tum.in.www1.artemis.domain.ProgrammingExercise; +import de.tum.in.www1.artemis.domain.ProgrammingSubmission; +import de.tum.in.www1.artemis.domain.Result; +import de.tum.in.www1.artemis.domain.Submission; +import de.tum.in.www1.artemis.domain.competency.Competency; +import de.tum.in.www1.artemis.domain.competency.CompetencyJol; +import de.tum.in.www1.artemis.domain.enumeration.AssessmentType; +import de.tum.in.www1.artemis.domain.enumeration.ProjectType; +import de.tum.in.www1.artemis.domain.enumeration.SubmissionType; +import de.tum.in.www1.artemis.domain.iris.settings.event.IrisJolEventSettings; +import de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseStudentParticipation; +import de.tum.in.www1.artemis.domain.participation.SolutionProgrammingExerciseParticipation; +import de.tum.in.www1.artemis.domain.participation.TemplateProgrammingExerciseParticipation; +import de.tum.in.www1.artemis.exercise.programming.ProgrammingExerciseUtilService; +import de.tum.in.www1.artemis.participation.ParticipationFactory; +import de.tum.in.www1.artemis.participation.ParticipationUtilService; +import de.tum.in.www1.artemis.repository.SubmissionRepository; +import de.tum.in.www1.artemis.repository.iris.IrisSettingsRepository; +import de.tum.in.www1.artemis.service.connectors.pyris.PyrisJobService; +import de.tum.in.www1.artemis.service.connectors.pyris.PyrisStatusUpdateService; +import de.tum.in.www1.artemis.service.connectors.pyris.event.CompetencyJolSetEvent; +import de.tum.in.www1.artemis.service.connectors.pyris.event.PyrisEvent; +import de.tum.in.www1.artemis.service.connectors.pyris.event.PyrisEventService; +import de.tum.in.www1.artemis.service.iris.session.IrisExerciseChatSessionService; +import de.tum.in.www1.artemis.user.UserUtilService; +import de.tum.in.www1.artemis.web.rest.errors.AccessForbiddenAlertException; + +class PyrisEventSystemTest extends AbstractIrisIntegrationTest { + + private static final String TEST_PREFIX = "pyriseventsystemtest"; + + @Autowired + protected PyrisStatusUpdateService pyrisStatusUpdateService; + + @Autowired + protected PyrisJobService pyrisJobService; + + @Autowired + protected IrisSettingsRepository irisSettingsRepository; + + @Autowired + private ProgrammingExerciseUtilService programmingExerciseUtilService; + + @Autowired + private SubmissionRepository submissionRepository; + + @Autowired + private PyrisEventService pyrisEventService; + + @Autowired + private ParticipationUtilService participationUtilService; + + @Autowired + private UserUtilService userUtilService; + + @Autowired + private CompetencyUtilService competencyUtilService; + + private ProgrammingExercise exercise; + + private Course course; + + private ProgrammingExerciseStudentParticipation studentParticipation; + + private AtomicBoolean pipelineDone; + + private Competency competency; + + @BeforeEach + void initTestCase() throws GitAPIException, IOException, URISyntaxException { + userUtilService.addUsers(TEST_PREFIX, 2, 0, 0, 1); + + course = programmingExerciseUtilService.addCourseWithOneProgrammingExercise(); + competency = competencyUtilService.createCompetency(course); + exercise = exerciseUtilService.getFirstExerciseWithType(course, ProgrammingExercise.class); + String projectKey = exercise.getProjectKey(); + exercise.setProjectType(ProjectType.PLAIN_GRADLE); + exercise.setTestRepositoryUri(localVCBaseUrl + "/git/" + projectKey + "/" + projectKey.toLowerCase() + "-tests.git"); + programmingExerciseRepository.save(exercise); + exercise = programmingExerciseRepository.findWithAllParticipationsById(exercise.getId()).orElseThrow(); + + // Set the correct repository URIs for the template and the solution participation. + String templateRepositorySlug = projectKey.toLowerCase() + "-exercise"; + TemplateProgrammingExerciseParticipation templateParticipation = exercise.getTemplateParticipation(); + templateParticipation.setRepositoryUri(localVCBaseUrl + "/git/" + projectKey + "/" + templateRepositorySlug + ".git"); + templateProgrammingExerciseParticipationRepository.save(templateParticipation); + String solutionRepositorySlug = projectKey.toLowerCase() + "-solution"; + SolutionProgrammingExerciseParticipation solutionParticipation = exercise.getSolutionParticipation(); + solutionParticipation.setRepositoryUri(localVCBaseUrl + "/git/" + projectKey + "/" + solutionRepositorySlug + ".git"); + solutionProgrammingExerciseParticipationRepository.save(solutionParticipation); + + String assignmentRepositorySlug = projectKey.toLowerCase() + "-" + TEST_PREFIX + "student1"; + + // Add a participation for student1. + studentParticipation = participationUtilService.addStudentParticipationForProgrammingExercise(exercise, TEST_PREFIX + "student1"); + studentParticipation.setRepositoryUri(String.format(localVCBaseUrl + "/git/%s/%s.git", projectKey, assignmentRepositorySlug)); + studentParticipation.setBranch(defaultBranch); + + programmingExerciseStudentParticipationRepository.save(studentParticipation); + + // Prepare the repositories. + localVCLocalCITestService.createAndConfigureLocalRepository(projectKey, templateRepositorySlug); + localVCLocalCITestService.createAndConfigureLocalRepository(projectKey, projectKey.toLowerCase() + "-tests"); + localVCLocalCITestService.createAndConfigureLocalRepository(projectKey, solutionRepositorySlug); + localVCLocalCITestService.createAndConfigureLocalRepository(projectKey, assignmentRepositorySlug); + + // Check that the repository folders were created in the file system for all base repositories. + localVCLocalCITestService.verifyRepositoryFoldersExist(exercise, localVCBasePath); + + activateIrisGlobally(); + activateIrisFor(course); + activateIrisFor(exercise); + + pipelineDone = new AtomicBoolean(false); + } + + private Result createSubmission(ProgrammingExerciseStudentParticipation studentParticipation, boolean successful) { + // Create a failing submission for the student. + Submission submission = new ProgrammingSubmission(); + + submission.setType(SubmissionType.MANUAL); + submission.setParticipation(studentParticipation); + submission = submissionRepository.saveAndFlush(submission); + + Result result = ParticipationFactory.generateResult(true, successful ? 100 : 10); + result.setParticipation(studentParticipation); + result.setSubmission(submission); + result.completionDate(ZonedDateTime.now()); + result.setAssessmentType(AssessmentType.AUTOMATIC); + submission.addResult(result); + submissionRepository.saveAndFlush(submission); + + return resultRepository.save(result); + } + + @Test + @WithMockUser(username = TEST_PREFIX + "student1", roles = "USER") + void testShouldFireJolEvent() { + var irisSession = irisCourseChatSessionService.createSession(course, userUtilService.getUserByLogin(TEST_PREFIX + "student1"), false); + var jolValue = 3; + irisRequestMockProvider.mockJolEventRunResponse((dto) -> { + assertThat(dto.settings().authenticationToken()).isNotNull(); + pipelineDone.set(true); + }); + competencyJolService.setJudgementOfLearning(competency.getId(), userUtilService.getUserByLogin(TEST_PREFIX + "student1").getId(), (short) jolValue); + + await().atMost(2, TimeUnit.SECONDS).until(() -> pipelineDone.get()); + + verify(irisCourseChatSessionService, times(1)).onJudgementOfLearningSet(any(CompetencyJol.class)); + verify(pyrisPipelineService, times(1)).executeCourseChatPipeline(eq("jol"), eq(irisSession), any(CompetencyJol.class)); + + } + + @Test + @WithMockUser(username = TEST_PREFIX + "student1", roles = "USER") + void testShouldThrowUnsupportedEventException() { + assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> pyrisEventService.trigger(new PyrisEvent() { + + @Override + public void handleEvent(IrisExerciseChatSessionService service) { + // Do nothing + } + })).withMessageStartingWith("Unsupported event"); + + } + + @Test + @WithMockUser(username = TEST_PREFIX + "student1", roles = "USER") + void testShouldNotFireJolEventWhenEventSettingDisabled() throws AccessForbiddenAlertException { + deactivateEventSettingsFor(IrisJolEventSettings.class, course); + var jol = competencyUtilService.createJol(competency, userUtilService.getUserByLogin(TEST_PREFIX + "student1"), (short) 3, ZonedDateTime.now(), 0.0D, 0.0D); + assertThatExceptionOfType(AccessForbiddenAlertException.class).isThrownBy(() -> pyrisEventService.trigger(new CompetencyJolSetEvent(jol))) + .withMessageContaining("The Iris JOL event is disabled for this course"); + } + +} diff --git a/src/test/java/de/tum/in/www1/artemis/iris/settings/IrisSettingsIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/iris/settings/IrisSettingsIntegrationTest.java index 300e9ae14d0d..d6d11daa05db 100644 --- a/src/test/java/de/tum/in/www1/artemis/iris/settings/IrisSettingsIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/iris/settings/IrisSettingsIntegrationTest.java @@ -56,8 +56,9 @@ void getMissingSettingsForCourse() throws Exception { assertThat(loadedSettings2).isNotNull().usingRecursiveComparison().ignoringFieldsOfTypes(HashSet.class, TreeSet.class).ignoringActualNullFields() .isEqualTo(irisSettingsService.getCombinedIrisSettingsFor(course, false)); assertThat(loadedSettings1).isNotNull().usingRecursiveComparison() - .ignoringFields("id", "course", "irisChatSettings.id", "iris_lecture_ingestion_settings_id", "irisHestiaSettings.id", "irisCompetencyGenerationSettings.id") - .isEqualTo(irisSettingsService.getDefaultSettingsFor(course)); + .ignoringFields("id", "course", "irisChatSettings.id", "iris_lecture_ingestion_settings_id", "irisHestiaSettings.id", "irisCompetencyGenerationSettings.id", + "irisProactivitySettings.id") + .ignoringFieldsOfTypes(HashSet.class, TreeSet.class).ignoringActualNullFields().isEqualTo(irisSettingsService.getDefaultSettingsFor(course)); } @Test @@ -70,10 +71,9 @@ void getCourseSettings() throws Exception { var loadedSettings1 = request.get("/api/courses/" + course.getId() + "/raw-iris-settings", HttpStatus.OK, IrisSettings.class); var loadedSettings2 = request.get("/api/courses/" + course.getId() + "/iris-settings", HttpStatus.OK, IrisCombinedSettingsDTO.class); - assertThat(loadedSettings1).isNotNull().usingRecursiveComparison() - .ignoringFields("id", "course", "irisChatSettings.id", "irisLectureIngestionSettings.id", "irisHestiaSettings.id", "irisCompetencyGenerationSettings.id") - .ignoringExpectedNullFields().isEqualTo(loadedSettings2); - assertThat(loadedSettings1).isNotNull().usingRecursiveComparison().ignoringFields("course") + assertThat(loadedSettings1).isNotNull().usingRecursiveComparison().ignoringFields("id", "course", "irisChatSettings.id", "irisLectureIngestionSettings.id", + "irisHestiaSettings.id", "irisCompetencyGenerationSettings.id", "irisProactivitySettings.id").ignoringExpectedNullFields().isEqualTo(loadedSettings2); + assertThat(loadedSettings1).isNotNull().usingRecursiveComparison().ignoringFields("course").ignoringFieldsOfTypes(HashSet.class, TreeSet.class).ignoringActualNullFields() .isEqualTo(irisSettingsRepository.findCourseSettings(course.getId()).orElseThrow()); } From 05069f0d7fc24fd188d216529d8b955886429dca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20=C3=87ayl=C4=B1?= <38523756+kaancayli@users.noreply.github.com> Date: Thu, 5 Sep 2024 22:04:39 +0200 Subject: [PATCH 02/16] chore: Readd missing test --- .../www1/artemis/repository/ProgrammingExerciseRepository.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java b/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java index 821d7a6932f0..e1c2208c46d1 100644 --- a/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java +++ b/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java @@ -273,6 +273,9 @@ default ProgrammingExercise findOneByProjectKeyOrThrow(String projectKey, boolea @EntityGraph(type = LOAD, attributePaths = { "templateParticipation", "solutionParticipation", "studentParticipations.team.students", "buildConfig" }) Optional findWithAllParticipationsAndBuildConfigById(long exerciseId); + @EntityGraph(type = LOAD, attributePaths = { "templateParticipation", "solutionParticipation", "studentParticipations.team.students", "buildConfig" }) + Optional findWithAllParticipationsById(long exerciseId); + @Query(""" SELECT pe FROM ProgrammingExercise pe From ae36c6e66d0087442a409220dd719b963766feec Mon Sep 17 00:00:00 2001 From: Stephan Krusche Date: Sun, 1 Sep 2024 23:25:11 +0200 Subject: [PATCH 03/16] Development: Downgrade Hibernate to avoid issues --- build.gradle | 5 ++++- gradle.properties | 4 ++-- .../in/www1/artemis/service/AuthorizationCheckService.java | 4 ++-- src/test/java/de/tum/in/www1/artemis/exam/ExamStartTest.java | 3 +-- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index 9c73ed190045..9a023c709654 100644 --- a/build.gradle +++ b/build.gradle @@ -284,7 +284,7 @@ dependencies { implementation "org.apache.sshd:sshd-sftp:${sshd_version}" // https://mvnrepository.com/artifact/net.sourceforge.plantuml/plantuml - implementation "net.sourceforge.plantuml:plantuml:1.2024.6" + implementation "net.sourceforge.plantuml:plantuml:1.2024.5" implementation "org.jasypt:jasypt:1.9.3" implementation "me.xdrop:fuzzywuzzy:1.4.0" implementation("org.yaml:snakeyaml") { @@ -448,6 +448,9 @@ dependencies { // use newest version of gson to avoid security issues through outdated dependencies implementation "com.google.code.gson:gson:2.11.0" + + implementation "com.google.errorprone:error_prone_annotations:2.31.0" + annotationProcessor "org.hibernate:hibernate-jpamodelgen:${hibernate_version}" annotationProcessor("org.glassfish.jaxb:jaxb-runtime:${jaxb_runtime_version}") { exclude group: "jakarta.ws.rs", module: "jsr311-api" diff --git a/gradle.properties b/gradle.properties index 6a83d1c9b699..80dbe5279b3e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,8 +9,8 @@ npm_version=10.7.0 jhipster_dependencies_version=8.7.0 spring_boot_version=3.3.3 spring_security_version=6.3.3 -# TODO: before we upgrade to 6.5.x, we need to make sure that there are no performance issues with empty sets or lists -hibernate_version=6.6.0.Final +# TODO: upgrading to 6.6.0 currently leads to issues due to internal changes in Hibernate and potentially wrong use in Artemis server code +hibernate_version=6.4.10.Final # TODO: can we update to 5.x? opensaml_version=4.3.2 jwt_version=0.12.6 diff --git a/src/main/java/de/tum/in/www1/artemis/service/AuthorizationCheckService.java b/src/main/java/de/tum/in/www1/artemis/service/AuthorizationCheckService.java index 4143a0e00bbe..724a8f98e347 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/AuthorizationCheckService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/AuthorizationCheckService.java @@ -10,8 +10,6 @@ import jakarta.annotation.Nullable; import jakarta.validation.constraints.NotNull; -import javax.annotation.CheckReturnValue; - import org.hibernate.Hibernate; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Profile; @@ -19,6 +17,8 @@ import org.springframework.stereotype.Service; import org.springframework.web.server.ResponseStatusException; +import com.google.errorprone.annotations.CheckReturnValue; + import de.tum.in.www1.artemis.domain.Authority; import de.tum.in.www1.artemis.domain.Course; import de.tum.in.www1.artemis.domain.Exercise; diff --git a/src/test/java/de/tum/in/www1/artemis/exam/ExamStartTest.java b/src/test/java/de/tum/in/www1/artemis/exam/ExamStartTest.java index 3086bb22234e..5181383dbf1f 100644 --- a/src/test/java/de/tum/in/www1/artemis/exam/ExamStartTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exam/ExamStartTest.java @@ -36,7 +36,6 @@ import de.tum.in.www1.artemis.domain.User; import de.tum.in.www1.artemis.domain.enumeration.DiagramType; import de.tum.in.www1.artemis.domain.exam.Exam; -import de.tum.in.www1.artemis.domain.exam.ExamUser; import de.tum.in.www1.artemis.domain.exam.ExerciseGroup; import de.tum.in.www1.artemis.domain.exam.StudentExam; import de.tum.in.www1.artemis.domain.modeling.ModelingExercise; @@ -124,7 +123,6 @@ void initTestCase() throws GitAPIException { User student1 = userUtilService.getUserByLogin(TEST_PREFIX + "student1"); User student2 = userUtilService.getUserByLogin(TEST_PREFIX + "student2"); registeredUsers = Set.of(student1, student2); - exam.setExamUsers(Set.of(new ExamUser())); // setting dates exam.setStartDate(ZonedDateTime.now().plusHours(2)); exam.setEndDate(ZonedDateTime.now().plusHours(3)); @@ -137,6 +135,7 @@ void tearDown() throws Exception { programmingExerciseTestService.tearDown(); } + // TODO: why do we remove the student exams here? This is not really necessary // Cleanup of Bidirectional Relationships for (StudentExam studentExam : createdStudentExams) { exam.removeStudentExam(studentExam); From 10ef0e4cf5a8e09015d8fe510cfec6d8abdabb3b Mon Sep 17 00:00:00 2001 From: Stephan Krusche Date: Mon, 2 Sep 2024 10:25:38 +0200 Subject: [PATCH 04/16] Development: Update dependencies for coverage supporting script --- supporting_scripts/generate_code_cov_table/README.md | 2 +- .../generate_code_cov_table/requirements.txt | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/supporting_scripts/generate_code_cov_table/README.md b/supporting_scripts/generate_code_cov_table/README.md index 925e16d3d61c..1953c39aef5a 100644 --- a/supporting_scripts/generate_code_cov_table/README.md +++ b/supporting_scripts/generate_code_cov_table/README.md @@ -7,7 +7,7 @@ The generated report is copied to the clipboard and pasted into a pull request o ### Prerequisites -- Python 3.6 or higher +- Python 3.12 or higher - pip - git diff --git a/supporting_scripts/generate_code_cov_table/requirements.txt b/supporting_scripts/generate_code_cov_table/requirements.txt index 7472e56611de..78379bda1531 100644 --- a/supporting_scripts/generate_code_cov_table/requirements.txt +++ b/supporting_scripts/generate_code_cov_table/requirements.txt @@ -1,6 +1,6 @@ -requests==2.31.0 -gitpython==3.1.41 -beautifulsoup4==4.12.2 -pyperclip==1.8.2 -python-dotenv==1.0.0 -tqdm==4.65.0 +requests==2.32.3 +gitpython==3.1.43 +beautifulsoup4==4.12.3 +pyperclip==1.9.0 +python-dotenv==1.0.1 +tqdm==4.66.5 From 3850102fe52eb31b5fd8c8724379ae9d4c834368 Mon Sep 17 00:00:00 2001 From: Yannik S Date: Mon, 2 Sep 2024 11:08:39 +0200 Subject: [PATCH 05/16] Programming exercises: Add online IDE settings (#8965) --- .../de/tum/in/www1/artemis/ArtemisApp.java | 3 +- .../artemis/config/TheiaConfiguration.java | 43 ++++++ .../artemis/domain/ProgrammingExercise.java | 10 +- .../ProgrammingExerciseResource.java | 32 ++++- .../theia/TheiaConfigurationResource.java | 41 ++++++ src/main/resources/config/application-dev.yml | 11 +- .../resources/config/application-theia.yml | 13 +- .../entities/programming-exercise.model.ts | 3 + ...ramming-exercise-group-cell.component.html | 9 +- .../programming-exercise-detail.component.ts | 9 +- .../programming-exercise.component.html | 12 +- .../programming-exercise-creation-config.ts | 1 + .../programming-exercise-update.component.ts | 133 +++++++++++------- .../programming-exercise-update.module.ts | 2 + ...ramming-exercise-difficulty.component.html | 57 +++++++- ...ogramming-exercise-difficulty.component.ts | 16 ++- ...ogramming-exercise-language.component.html | 7 + ...programming-exercise-language.component.ts | 2 + .../programming-exercise-theia.component.html | 21 +++ .../programming-exercise-theia.component.ts | 82 +++++++++++ .../shared/service/theia.service.ts | 25 ++++ ...rcise-details-student-actions.component.ts | 28 ++-- .../webapp/i18n/de/programmingExercise.json | 17 ++- .../webapp/i18n/en/programmingExercise.json | 17 ++- ...tractSpringIntegrationIndependentTest.java | 3 +- .../config/TheiaConfigurationTest.java | 41 ++++++ .../theia/TheiaInfoContributorTest.java | 7 +- ...ming-exercise-group-cell.component.spec.ts | 9 +- ...-details-student-actions.component.spec.ts | 55 +++++++- ...gramming-exercise-update.component.spec.ts | 63 ++++++++- ...ogramming-exercise-creation-config-mock.ts | 3 + ...ming-exercise-difficulty.component.spec.ts | 29 +++- ...amming-exercise-language.component.spec.ts | 29 ++++ ...ogramming-exercise-theia.component.spec.ts | 90 ++++++++++++ .../programming-exercise.service.spec.ts | 2 + .../resources/config/application-theia.yml | 9 ++ 36 files changed, 823 insertions(+), 111 deletions(-) create mode 100644 src/main/java/de/tum/in/www1/artemis/config/TheiaConfiguration.java create mode 100644 src/main/java/de/tum/in/www1/artemis/web/rest/theia/TheiaConfigurationResource.java create mode 100644 src/main/webapp/app/exercises/programming/manage/update/update-components/theia/programming-exercise-theia.component.html create mode 100644 src/main/webapp/app/exercises/programming/manage/update/update-components/theia/programming-exercise-theia.component.ts create mode 100644 src/main/webapp/app/exercises/programming/shared/service/theia.service.ts create mode 100644 src/test/java/de/tum/in/www1/artemis/config/TheiaConfigurationTest.java create mode 100644 src/test/javascript/spec/component/programming-exercise/update-components/theia/programming-exercise-theia.component.spec.ts create mode 100644 src/test/resources/config/application-theia.yml diff --git a/src/main/java/de/tum/in/www1/artemis/ArtemisApp.java b/src/main/java/de/tum/in/www1/artemis/ArtemisApp.java index e64bb62fccbb..674012737006 100644 --- a/src/main/java/de/tum/in/www1/artemis/ArtemisApp.java +++ b/src/main/java/de/tum/in/www1/artemis/ArtemisApp.java @@ -19,11 +19,12 @@ import org.springframework.core.env.Environment; import de.tum.in.www1.artemis.config.ProgrammingLanguageConfiguration; +import de.tum.in.www1.artemis.config.TheiaConfiguration; import tech.jhipster.config.DefaultProfileUtil; import tech.jhipster.config.JHipsterConstants; @SpringBootApplication -@EnableConfigurationProperties({ LiquibaseProperties.class, ProgrammingLanguageConfiguration.class }) +@EnableConfigurationProperties({ LiquibaseProperties.class, ProgrammingLanguageConfiguration.class, TheiaConfiguration.class }) public class ArtemisApp { private static final Logger log = LoggerFactory.getLogger(ArtemisApp.class); diff --git a/src/main/java/de/tum/in/www1/artemis/config/TheiaConfiguration.java b/src/main/java/de/tum/in/www1/artemis/config/TheiaConfiguration.java new file mode 100644 index 000000000000..02a50a5201ed --- /dev/null +++ b/src/main/java/de/tum/in/www1/artemis/config/TheiaConfiguration.java @@ -0,0 +1,43 @@ +package de.tum.in.www1.artemis.config; + +import static de.tum.in.www1.artemis.config.Constants.PROFILE_THEIA; + +import java.util.Map; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +import de.tum.in.www1.artemis.domain.enumeration.ProgrammingLanguage; + +@Profile(PROFILE_THEIA) +@Configuration +@ConfigurationProperties(prefix = "theia") +public class TheiaConfiguration { + + private Map> images; + + public void setImages(final Map> images) { + this.images = images; + } + + /** + * Get the images for all languages + * + * @return a map of language -> [flavor/name -> image-link] + */ + public Map> getImagesForAllLanguages() { + return images; + } + + /** + * Get the images for a specific language + * + * @param language the language for which the images should be retrieved + * @return a map of flavor/name -> image-link + */ + public Map getImagesForLanguage(ProgrammingLanguage language) { + return images.get(language); + } + +} diff --git a/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExercise.java b/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExercise.java index b44ce90a2e67..ccb797194f8d 100644 --- a/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExercise.java +++ b/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExercise.java @@ -732,8 +732,9 @@ public String toString() { public void validateProgrammingSettings() { // Check if a participation mode was selected - if (!Boolean.TRUE.equals(isAllowOnlineEditor()) && !Boolean.TRUE.equals(isAllowOfflineIde())) { - throw new BadRequestAlertException("You need to allow at least one participation mode, the online editor or the offline IDE", "Exercise", "noParticipationModeAllowed"); + if (!Boolean.TRUE.equals(isAllowOnlineEditor()) && !Boolean.TRUE.equals(isAllowOfflineIde()) && !isAllowOnlineIde()) { + throw new BadRequestAlertException("You need to allow at least one participation mode, the online editor, the offline IDE, or the online IDE", "Exercise", + "noParticipationModeAllowed"); } // Check if Xcode has no online code editor enabled @@ -745,6 +746,11 @@ public void validateProgrammingSettings() { if (getProgrammingLanguage() == null) { throw new BadRequestAlertException("No programming language was specified", "Exercise", "programmingLanguageNotSet"); } + + // Check if theia image was selected if the online IDE is enabled + if (isAllowOnlineIde() && buildConfig.getTheiaImage() == null) { + throw new BadRequestAlertException("The Theia image must be selected if the online IDE is enabled", "Exercise", "theiaImageNotSet"); + } } /** diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java index 180d2ca8e077..2620f59f6a5d 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java @@ -1,6 +1,7 @@ package de.tum.in.www1.artemis.web.rest.programming; import static de.tum.in.www1.artemis.config.Constants.PROFILE_CORE; +import static de.tum.in.www1.artemis.config.Constants.PROFILE_THEIA; import java.io.IOException; import java.net.URI; @@ -18,6 +19,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Profile; +import org.springframework.core.env.Environment; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -89,6 +91,7 @@ import de.tum.in.www1.artemis.web.rest.errors.EntityNotFoundException; import de.tum.in.www1.artemis.web.rest.util.HeaderUtil; import de.tum.in.www1.artemis.web.websocket.dto.ProgrammingExerciseTestCaseStateDTO; +import io.jsonwebtoken.lang.Arrays; /** * REST controller for managing ProgrammingExercise. @@ -151,6 +154,8 @@ public class ProgrammingExerciseResource { private final Optional athenaModuleService; + private final Environment environment; + public ProgrammingExerciseResource(ProgrammingExerciseRepository programmingExerciseRepository, ProgrammingExerciseTestCaseRepository programmingExerciseTestCaseRepository, UserRepository userRepository, AuthorizationCheckService authCheckService, CourseService courseService, Optional continuousIntegrationService, Optional versionControlService, ExerciseService exerciseService, @@ -160,7 +165,8 @@ public ProgrammingExerciseResource(ProgrammingExerciseRepository programmingExer GradingCriterionRepository gradingCriterionRepository, CourseRepository courseRepository, GitService gitService, AuxiliaryRepositoryService auxiliaryRepositoryService, SolutionProgrammingExerciseParticipationRepository solutionProgrammingExerciseParticipationRepository, TemplateProgrammingExerciseParticipationRepository templateProgrammingExerciseParticipationRepository, - BuildLogStatisticsEntryRepository buildLogStatisticsEntryRepository, ChannelRepository channelRepository, Optional athenaModuleService) { + BuildLogStatisticsEntryRepository buildLogStatisticsEntryRepository, ChannelRepository channelRepository, Optional athenaModuleService, + Environment environment) { this.programmingExerciseTaskService = programmingExerciseTaskService; this.programmingExerciseRepository = programmingExerciseRepository; this.programmingExerciseTestCaseRepository = programmingExerciseTestCaseRepository; @@ -184,6 +190,7 @@ public ProgrammingExerciseResource(ProgrammingExerciseRepository programmingExer this.buildLogStatisticsEntryRepository = buildLogStatisticsEntryRepository; this.channelRepository = channelRepository; this.athenaModuleService = athenaModuleService; + this.environment = environment; } /** @@ -303,9 +310,26 @@ public ResponseEntity updateProgrammingExercise(@RequestBod updatedProgrammingExercise.getBuildConfig().isTestwiseCoverageEnabled())) { throw new BadRequestAlertException("Testwise coverage enabled flag must not be changed", ENTITY_NAME, "testwiseCoverageCannotChange"); } - if (!Boolean.TRUE.equals(updatedProgrammingExercise.isAllowOnlineEditor()) && !Boolean.TRUE.equals(updatedProgrammingExercise.isAllowOfflineIde())) { - return ResponseEntity.badRequest().headers(HeaderUtil.createAlert(applicationName, - "You need to allow at least one participation mode, the online editor or the offline IDE", "noParticipationModeAllowed")).body(null); + // Check if theia Profile is enabled + if (Arrays.asList(this.environment.getActiveProfiles()).contains(PROFILE_THEIA)) { + // Require 1 / 3 participation modes to be enabled + if (!Boolean.TRUE.equals(updatedProgrammingExercise.isAllowOnlineEditor()) && !Boolean.TRUE.equals(updatedProgrammingExercise.isAllowOfflineIde()) + && !updatedProgrammingExercise.isAllowOnlineIde()) { + throw new BadRequestAlertException("You need to allow at least one participation mode, the online editor, the offline IDE, or the online IDE", ENTITY_NAME, + "noParticipationModeAllowed"); + } + } + else { + // Require 1 / 2 participation modes to be enabled + if (!Boolean.TRUE.equals(updatedProgrammingExercise.isAllowOnlineEditor()) && !Boolean.TRUE.equals(updatedProgrammingExercise.isAllowOfflineIde())) { + throw new BadRequestAlertException("You need to allow at least one participation mode, the online editor or the offline IDE", ENTITY_NAME, + "noParticipationModeAllowed"); + } + } + + // Verify that a theia image is provided when the online IDE is enabled + if (updatedProgrammingExercise.isAllowOnlineIde() && updatedProgrammingExercise.getBuildConfig().getTheiaImage() == null) { + throw new BadRequestAlertException("You need to provide a Theia image when the online IDE is enabled", ENTITY_NAME, "noTheiaImageProvided"); } // Forbid changing the course the exercise belongs to. if (!Objects.equals(programmingExerciseBeforeUpdate.getCourseViaExerciseGroupOrCourseMember().getId(), diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/theia/TheiaConfigurationResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/theia/TheiaConfigurationResource.java new file mode 100644 index 000000000000..24a6977afa5b --- /dev/null +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/theia/TheiaConfigurationResource.java @@ -0,0 +1,41 @@ +package de.tum.in.www1.artemis.web.rest.theia; + +import static de.tum.in.www1.artemis.config.Constants.PROFILE_THEIA; + +import java.util.Map; + +import org.springframework.context.annotation.Profile; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import de.tum.in.www1.artemis.config.TheiaConfiguration; +import de.tum.in.www1.artemis.domain.enumeration.ProgrammingLanguage; +import de.tum.in.www1.artemis.security.annotations.EnforceAtLeastInstructor; + +@Profile(PROFILE_THEIA) +@RestController +@RequestMapping("api/theia/") +public class TheiaConfigurationResource { + + private final TheiaConfiguration theiaConfiguration; + + public TheiaConfigurationResource(TheiaConfiguration theiaConfiguration) { + this.theiaConfiguration = theiaConfiguration; + } + + /** + * GET /api/theia/images?language=: Get the images for a specific language + * + * @param language the language for which the images should be retrieved + * @return a map of flavor/name -> image-link + */ + @GetMapping("images") + @EnforceAtLeastInstructor + public ResponseEntity> getImagesForLanguage(@RequestParam("language") ProgrammingLanguage language) { + return ResponseEntity.ok(this.theiaConfiguration.getImagesForLanguage(language)); + } + +} diff --git a/src/main/resources/config/application-dev.yml b/src/main/resources/config/application-dev.yml index 242f427c6a8e..ec007df2f264 100644 --- a/src/main/resources/config/application-dev.yml +++ b/src/main/resources/config/application-dev.yml @@ -129,4 +129,13 @@ eureka: # Theia configuration theia: - portal-url: https://theia-test.k8s.ase.cit.tum.de + portal-url: https://theia-test.k8s.ase.cit.tum.de + + images: + java: + Java-17: "ghcr.io/ls1intum/theia/java-17:latest" + Java-Test: "ghcr.io/ls1intum/theia/java-test:latest" + Java-Test2: "ghcr.io/ls1intum/theia/java-test:2" + c: + C: "ghcr.io/ls1intum/theia/c:latest" + diff --git a/src/main/resources/config/application-theia.yml b/src/main/resources/config/application-theia.yml index 2b8e1346d008..95b058f66e20 100644 --- a/src/main/resources/config/application-theia.yml +++ b/src/main/resources/config/application-theia.yml @@ -1,2 +1,13 @@ theia: - portal-url: https://your-theia-instance.com + portal-url: https://your-theia-instance.com + + # Theia IDE images available for the different programming languages + images: + # Upper level key is the language category (must match the language key in the programming-exercise configuration) + java: + # Lower level key can be multiple flavors of the image, e.g. version, tag, or additional dependencies + Java-17: "my-registry/my-image:my-tag" + # Add more flavors here (e.g. Java-11, Java-8, etc.) + # Add more languages here (e.g. c, python, etc.) + c: + C: "my-registry/my-image:my-tag" diff --git a/src/main/webapp/app/entities/programming-exercise.model.ts b/src/main/webapp/app/entities/programming-exercise.model.ts index a2e6a093f9a1..daf1bf77e907 100644 --- a/src/main/webapp/app/entities/programming-exercise.model.ts +++ b/src/main/webapp/app/entities/programming-exercise.model.ts @@ -68,6 +68,7 @@ export class ProgrammingExerciseBuildConfig { public dockerFlags?: string; public windfile?: WindFile; public testwiseCoverageEnabled?: boolean; + public theiaImage?: string; constructor() { this.checkoutSolutionRepository = false; // default value @@ -114,6 +115,7 @@ export class ProgrammingExercise extends Exercise { */ public maxStaticCodeAnalysisPenalty?: number; public allowOfflineIde?: boolean; + public allowOnlineIde?: boolean; public programmingLanguage?: ProgrammingLanguage; public packageName?: string; public showTestNamesToStudents?: boolean; @@ -148,6 +150,7 @@ export class ProgrammingExercise extends Exercise { this.templateParticipation = new TemplateProgrammingExerciseParticipation(); this.solutionParticipation = new SolutionProgrammingExerciseParticipation(); this.allowOnlineEditor = false; // default value + this.allowOnlineIde = false; // default value this.staticCodeAnalysisEnabled = false; // default value this.allowOfflineIde = true; // default value this.programmingLanguage = ProgrammingLanguage.JAVA; // default value diff --git a/src/main/webapp/app/exam/manage/exercise-groups/programming-exercise-cell/programming-exercise-group-cell.component.html b/src/main/webapp/app/exam/manage/exercise-groups/programming-exercise-cell/programming-exercise-group-cell.component.html index 7194d5a9f141..e59af00e81b9 100644 --- a/src/main/webapp/app/exam/manage/exercise-groups/programming-exercise-cell/programming-exercise-group-cell.component.html +++ b/src/main/webapp/app/exam/manage/exercise-groups/programming-exercise-cell/programming-exercise-group-cell.component.html @@ -84,12 +84,13 @@ @if (displayEditorModus) {
- {{ 'artemisApp.programmingExercise.offlineIde' | artemisTranslate }} - : {{ programmingExercise.allowOfflineIde || false }} + : {{ programmingExercise.allowOfflineIde || false }}
- {{ 'artemisApp.programmingExercise.onlineEditor' | artemisTranslate }} - : {{ programmingExercise.allowOnlineEditor || false }} + : {{ programmingExercise.allowOnlineEditor || false }} +
+
+ : {{ programmingExercise.allowOnlineIde || false }}
} diff --git a/src/main/webapp/app/exercises/programming/manage/programming-exercise-detail.component.ts b/src/main/webapp/app/exercises/programming/manage/programming-exercise-detail.component.ts index a2f1e2174227..6576932d20e1 100644 --- a/src/main/webapp/app/exercises/programming/manage/programming-exercise-detail.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/programming-exercise-detail.component.ts @@ -332,12 +332,17 @@ export class ProgrammingExerciseDetailComponent implements OnInit, OnDestroy { { type: DetailType.Boolean, title: 'artemisApp.programmingExercise.allowOfflineIde.title', - data: { boolean: exercise.allowOfflineIde }, + data: { boolean: exercise.allowOfflineIde ?? false }, }, { type: DetailType.Boolean, title: 'artemisApp.programmingExercise.allowOnlineEditor.title', - data: { boolean: exercise.allowOnlineEditor }, + data: { boolean: exercise.allowOnlineEditor ?? false }, + }, + { + type: DetailType.Boolean, + title: 'artemisApp.programmingExercise.allowOnlineIde.title', + data: { boolean: exercise.allowOnlineIde ?? false }, }, ], }; diff --git a/src/main/webapp/app/exercises/programming/manage/programming-exercise.component.html b/src/main/webapp/app/exercises/programming/manage/programming-exercise.component.html index 89d72f95b7ef..39f4a28bbff0 100644 --- a/src/main/webapp/app/exercises/programming/manage/programming-exercise.component.html +++ b/src/main/webapp/app/exercises/programming/manage/programming-exercise.component.html @@ -139,12 +139,16 @@ }
- {{ 'artemisApp.programmingExercise.offlineIde' | artemisTranslate }}: - {{ programmingExercise.allowOfflineIde ? ('artemisApp.exercise.yes' | artemisTranslate) : ('artemisApp.exercise.no' | artemisTranslate) }} + : +
- {{ 'artemisApp.programmingExercise.onlineEditor' | artemisTranslate }}: - {{ programmingExercise.allowOnlineEditor ? ('artemisApp.exercise.yes' | artemisTranslate) : ('artemisApp.exercise.no' | artemisTranslate) }} + : + +
+
+ : +
@if (course.presentationScore !== 0) { diff --git a/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-creation-config.ts b/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-creation-config.ts index 6f7e4b3332c3..8ab3314ac388 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-creation-config.ts +++ b/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-creation-config.ts @@ -44,6 +44,7 @@ export type ProgrammingExerciseCreationConfig = { hasUnsavedChanges: boolean; rerenderSubject: Observable; validIdeSelection: () => boolean | undefined; + validOnlineIdeSelection: () => boolean | undefined; inProductionEnvironment: boolean; recreateBuildPlans: boolean; onRecreateBuildPlanOrUpdateTemplateChange: () => void; diff --git a/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-update.component.ts b/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-update.component.ts index e48803fc9c81..5fe22b0b6ff9 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-update.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-update.component.ts @@ -29,7 +29,7 @@ import { ModePickerOption } from 'app/exercises/shared/mode-picker/mode-picker.c import { DocumentationType } from 'app/shared/components/documentation-button/documentation-button.component'; import { ProgrammingExerciseCreationConfig } from 'app/exercises/programming/manage/update/programming-exercise-creation-config'; import { loadCourseExerciseCategories } from 'app/exercises/shared/course-exercises/course-utils'; -import { PROFILE_AEOLUS, PROFILE_LOCALCI } from 'app/app.constants'; +import { PROFILE_AEOLUS, PROFILE_LOCALCI, PROFILE_THEIA } from 'app/app.constants'; import { AeolusService } from 'app/exercises/programming/shared/service/aeolus.service'; import { FormSectionStatus } from 'app/forms/form-status-bar/form-status-bar.component'; import { ProgrammingExerciseInformationComponent } from 'app/exercises/programming/manage/update/update-components/programming-exercise-information.component'; @@ -134,6 +134,7 @@ export class ProgrammingExerciseUpdateComponent implements AfterViewInit, OnDest public auxiliaryRepositoriesSupported = false; public auxiliaryRepositoriesValid = true; public customBuildPlansSupported: string = ''; + public theiaEnabled = false; // Additional options for import // This is a wrapper to allow modifications from the other subcomponents @@ -402,50 +403,52 @@ export class ProgrammingExerciseUpdateComponent implements AfterViewInit, OnDest }); // If it is an import from this instance, just get the course, otherwise handle the edit and new cases - this.activatedRoute.url - .pipe( - tap((segments) => { - this.isImportFromExistingExercise = segments.some((segment) => segment.path === 'import'); - this.isImportFromFile = segments.some((segment) => segment.path === 'import-from-file'); - }), - switchMap(() => this.activatedRoute.params), - tap((params) => { - if (this.isImportFromFile) { - this.createProgrammingExerciseForImportFromFile(); - } - if (this.isImportFromExistingExercise) { - this.createProgrammingExerciseForImport(params); - } else { - if (params['courseId'] && params['examId'] && params['exerciseGroupId']) { - this.isExamMode = true; - this.exerciseGroupService.find(params['courseId'], params['examId'], params['exerciseGroupId']).subscribe((res) => { - this.programmingExercise.exerciseGroup = res.body!; - if (!params['exerciseId'] && this.programmingExercise.exerciseGroup.exam?.course?.defaultProgrammingLanguage && !this.isImportFromFile) { - this.selectedProgrammingLanguage = this.programmingExercise.exerciseGroup.exam.course.defaultProgrammingLanguage; + if (this.activatedRoute && this.activatedRoute.url) { + this.activatedRoute.url + .pipe( + tap((segments) => { + this.isImportFromExistingExercise = segments.some((segment) => segment.path === 'import'); + this.isImportFromFile = segments.some((segment) => segment.path === 'import-from-file'); + }), + switchMap(() => this.activatedRoute.params), + tap((params) => { + if (this.isImportFromFile) { + this.createProgrammingExerciseForImportFromFile(); + } + if (this.isImportFromExistingExercise) { + this.createProgrammingExerciseForImport(params); + } else { + if (params['courseId'] && params['examId'] && params['exerciseGroupId']) { + this.isExamMode = true; + this.exerciseGroupService.find(params['courseId'], params['examId'], params['exerciseGroupId']).subscribe((res) => { + this.programmingExercise.exerciseGroup = res.body!; + if (!params['exerciseId'] && this.programmingExercise.exerciseGroup.exam?.course?.defaultProgrammingLanguage && !this.isImportFromFile) { + this.selectedProgrammingLanguage = this.programmingExercise.exerciseGroup.exam.course.defaultProgrammingLanguage; + } + }); + // we need the course id to make the request to the server if it's an import from file + if (this.isImportFromFile) { + this.courseId = params['courseId']; + this.loadCourseExerciseCategories(params['courseId']); } - }); - // we need the course id to make the request to the server if it's an import from file - if (this.isImportFromFile) { + } else if (params['courseId']) { this.courseId = params['courseId']; - this.loadCourseExerciseCategories(params['courseId']); + this.isExamMode = false; + this.courseService.find(this.courseId).subscribe((res) => { + this.programmingExercise.course = res.body!; + if (!params['exerciseId'] && this.programmingExercise.course?.defaultProgrammingLanguage && !this.isImportFromFile) { + this.selectedProgrammingLanguage = this.programmingExercise.course.defaultProgrammingLanguage!; + } + this.exerciseCategories = this.programmingExercise.categories || []; + + this.loadCourseExerciseCategories(this.programmingExercise.course!.id!); + }); } - } else if (params['courseId']) { - this.courseId = params['courseId']; - this.isExamMode = false; - this.courseService.find(this.courseId).subscribe((res) => { - this.programmingExercise.course = res.body!; - if (!params['exerciseId'] && this.programmingExercise.course?.defaultProgrammingLanguage && !this.isImportFromFile) { - this.selectedProgrammingLanguage = this.programmingExercise.course.defaultProgrammingLanguage!; - } - this.exerciseCategories = this.programmingExercise.categories || []; - - this.loadCourseExerciseCategories(this.programmingExercise.course!.id!); - }); } - } - }), - ) - .subscribe(); + }), + ) + .subscribe(); + } // If an exercise is created, load our readme template so the problemStatement is not empty this.selectedProgrammingLanguage = this.programmingExercise.programmingLanguage!; @@ -470,6 +473,9 @@ export class ProgrammingExerciseUpdateComponent implements AfterViewInit, OnDest if (profileInfo?.activeProfiles.includes(PROFILE_AEOLUS)) { this.customBuildPlansSupported = PROFILE_AEOLUS; } + if (profileInfo?.activeProfiles.includes(PROFILE_THEIA)) { + this.theiaEnabled = true; + } }); this.defineSupportedProgrammingLanguages(); } @@ -500,13 +506,9 @@ export class ProgrammingExerciseUpdateComponent implements AfterViewInit, OnDest }, { title: 'artemisApp.programmingExercise.wizardMode.detailedSteps.languageStepTitle', - valid: this.exerciseLanguageComponent?.formValid ?? false, - }, - { - title: 'artemisApp.programmingExercise.wizardMode.detailedSteps.problemStepTitle', - valid: true, - empty: !this.programmingExercise.problemStatement, + valid: (this.exerciseLanguageComponent?.formValid && this.validOnlineIdeSelection()) ?? false, }, + { title: 'artemisApp.programmingExercise.wizardMode.detailedSteps.problemStepTitle', valid: true, empty: !this.programmingExercise.problemStatement }, { title: 'artemisApp.programmingExercise.wizardMode.detailedSteps.gradingStepTitle', valid: Boolean(this.exerciseGradingComponent?.formValid && (this.isExamMode || this.exercisePlagiarismComponent?.formValid)), @@ -676,8 +678,12 @@ export class ProgrammingExerciseUpdateComponent implements AfterViewInit, OnDest private subscribeToSaveResponse(result: Observable>) { result.subscribe({ - next: (response: HttpResponse) => this.onSaveSuccess(response.body!), - error: (error: HttpErrorResponse) => this.onSaveError(error), + next: (response: HttpResponse) => { + this.onSaveSuccess(response.body!); + }, + error: (error: HttpErrorResponse) => { + this.onSaveError(error); + }, }); } @@ -821,10 +827,21 @@ export class ProgrammingExerciseUpdateComponent implements AfterViewInit, OnDest } /** - * checking if at least one of Online Editor or Offline Ide is selected + * checking if at least one of Online Editor, Offline Ide, or Online Ide is selected */ validIdeSelection = () => { - return this.programmingExercise?.allowOnlineEditor || this.programmingExercise?.allowOfflineIde; + if (this.theiaEnabled) { + return this.programmingExercise?.allowOnlineEditor || this.programmingExercise?.allowOfflineIde || this.programmingExercise?.allowOnlineIde; + } else { + return this.programmingExercise?.allowOnlineEditor || this.programmingExercise?.allowOfflineIde; + } + }; + + /** + * Checking if the online IDE is selected and a valid image is selected + */ + validOnlineIdeSelection = () => { + return !this.programmingExercise?.allowOnlineIde || this.programmingExercise?.buildConfig!.theiaImage !== undefined; }; isEventInsideTextArea(event: Event): boolean { @@ -846,6 +863,7 @@ export class ProgrammingExerciseUpdateComponent implements AfterViewInit, OnDest this.validateExerciseAuxiliaryRepositories(validationErrorReasons); this.validateExercisePackageName(validationErrorReasons); this.validateExerciseIdeSelection(validationErrorReasons); + this.validateExerciseOnlineIdeSelection(validationErrorReasons); this.validateExercisePoints(validationErrorReasons); this.validateExerciseBonusPoints(validationErrorReasons); this.validateExerciseSCAMaxPenalty(validationErrorReasons); @@ -1044,8 +1062,18 @@ export class ProgrammingExerciseUpdateComponent implements AfterViewInit, OnDest private validateExerciseIdeSelection(validationErrorReasons: ValidationReason[]): void { if (!this.validIdeSelection()) { + const translateKey = this.theiaEnabled ? 'artemisApp.programmingExercise.allowOnlineEditor.alert' : 'artemisApp.programmingExercise.allowOnlineEditor.alertNoTheia'; + validationErrorReasons.push({ + translateKey: translateKey, + translateValues: {}, + }); + } + } + + private validateExerciseOnlineIdeSelection(validationErrorReasons: ValidationReason[]): void { + if (!this.validOnlineIdeSelection()) { validationErrorReasons.push({ - translateKey: 'artemisApp.programmingExercise.allowOnlineEditor.alert', + translateKey: 'artemisApp.programmingExercise.theiaImage.alert', translateValues: {}, }); } @@ -1110,6 +1138,7 @@ export class ProgrammingExerciseUpdateComponent implements AfterViewInit, OnDest hasUnsavedChanges: this.hasUnsavedChanges, rerenderSubject: this.rerenderSubject.asObservable(), validIdeSelection: this.validIdeSelection, + validOnlineIdeSelection: this.validOnlineIdeSelection, inProductionEnvironment: this.inProductionEnvironment, recreateBuildPlans: this.importOptions.recreateBuildPlans, onRecreateBuildPlanOrUpdateTemplateChange: this.onRecreateBuildPlanOrUpdateTemplateChange, diff --git a/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-update.module.ts b/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-update.module.ts index 8c5fa972cd92..7ac399d6daeb 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-update.module.ts +++ b/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-update.module.ts @@ -31,6 +31,7 @@ import { ProgrammingExerciseDockerImageComponent } from 'app/exercises/programmi import { FormsModule } from 'app/forms/forms.module'; import { ProgrammingExerciseBuildPlanCheckoutDirectoriesComponent } from 'app/exercises/programming/shared/build-details/programming-exercise-build-plan-checkout-directories.component'; import { ProgrammingExerciseRepositoryAndBuildPlanDetailsComponent } from 'app/exercises/programming/shared/build-details/programming-exercise-repository-and-build-plan-details.component'; +import { ProgrammingExerciseTheiaComponent } from 'app/exercises/programming/manage/update/update-components/theia/programming-exercise-theia.component'; import { MonacoEditorModule } from 'app/shared/monaco-editor/monaco-editor.module'; @NgModule({ @@ -57,6 +58,7 @@ import { MonacoEditorModule } from 'app/shared/monaco-editor/monaco-editor.modul ProgrammingExerciseBuildPlanCheckoutDirectoriesComponent, ProgrammingExerciseRepositoryAndBuildPlanDetailsComponent, MonacoEditorModule, + ProgrammingExerciseTheiaComponent, ], declarations: [ ProgrammingExerciseUpdateComponent, diff --git a/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-difficulty.component.html b/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-difficulty.component.html index addc823095a9..8f66c32f99dd 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-difficulty.component.html +++ b/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-difficulty.component.html @@ -27,12 +27,21 @@ /> @if (!programmingExerciseCreationConfig.validIdeSelection()) { - + @if (theiaEnabled) { + + } @else { + + } } @@ -49,12 +58,46 @@ (ngModelChange)="triggerValidation.emit()" /> + @if (!programmingExerciseCreationConfig.validIdeSelection()) { + @if (theiaEnabled) { + + } @else { + + } + } + + + } + + @if (!programmingExercise.exerciseGroup && theiaEnabled) { +
+ diff --git a/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-difficulty.component.ts b/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-difficulty.component.ts index 77e30693bff9..5c3f1eb64302 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-difficulty.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-difficulty.component.ts @@ -1,15 +1,17 @@ -import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core'; +import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; import { ProgrammingExercise, ProjectType } from 'app/entities/programming-exercise.model'; import { faQuestionCircle } from '@fortawesome/free-solid-svg-icons'; import { ProgrammingExerciseCreationConfig } from 'app/exercises/programming/manage/update/programming-exercise-creation-config'; import { TeamConfigFormGroupComponent } from 'app/exercises/shared/team-config-form-group/team-config-form-group.component'; +import { PROFILE_THEIA } from 'app/app.constants'; +import { ProfileService } from 'app/shared/layouts/profiles/profile.service'; @Component({ selector: 'jhi-programming-exercise-difficulty', templateUrl: './programming-exercise-difficulty.component.html', styleUrls: ['../../programming-exercise-form.scss'], }) -export class ProgrammingExerciseDifficultyComponent { +export class ProgrammingExerciseDifficultyComponent implements OnInit { @Input() programmingExercise: ProgrammingExercise; @Input() programmingExerciseCreationConfig: ProgrammingExerciseCreationConfig; @ViewChild(TeamConfigFormGroupComponent) teamConfigComponent: TeamConfigFormGroupComponent; @@ -18,5 +20,15 @@ export class ProgrammingExerciseDifficultyComponent { protected readonly ProjectType = ProjectType; + theiaEnabled: boolean = false; + + constructor(private profileService: ProfileService) {} + + ngOnInit(): void { + this.profileService.getProfileInfo().subscribe((profileInfo) => { + this.theiaEnabled = profileInfo.activeProfiles?.includes(PROFILE_THEIA); + }); + } + faQuestionCircle = faQuestionCircle; } diff --git a/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-language.component.html b/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-language.component.html index 1e4c258dfd16..e801f1a04d85 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-language.component.html +++ b/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-language.component.html @@ -111,6 +111,13 @@ }
} + + + @if (programmingExercise.allowOnlineIde && programmingExercise.programmingLanguage) { + + + } + @if (programmingExercise.programmingLanguage && programmingExerciseCreationConfig.staticCodeAnalysisAllowed) {
diff --git a/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-language.component.ts b/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-language.component.ts index 51bb90eb46d8..5bcf49abc770 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-language.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-language.component.ts @@ -7,6 +7,7 @@ import { NgModel } from '@angular/forms'; import { Subject, Subscription } from 'rxjs'; import { ProgrammingExerciseCustomAeolusBuildPlanComponent } from 'app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-aeolus-build-plan.component'; import { ProgrammingExerciseCustomBuildPlanComponent } from 'app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-build-plan.component'; +import { ProgrammingExerciseTheiaComponent } from 'app/exercises/programming/manage/update/update-components/theia/programming-exercise-theia.component'; @Component({ selector: 'jhi-programming-exercise-language', @@ -24,6 +25,7 @@ export class ProgrammingExerciseLanguageComponent implements AfterViewChecked, A @ViewChild('packageName') packageNameField?: NgModel; @ViewChild(ProgrammingExerciseCustomAeolusBuildPlanComponent) programmingExerciseCustomAeolusBuildPlanComponent?: ProgrammingExerciseCustomAeolusBuildPlanComponent; @ViewChild(ProgrammingExerciseCustomBuildPlanComponent) programmingExerciseCustomBuildPlanComponent?: ProgrammingExerciseCustomBuildPlanComponent; + @ViewChild(ProgrammingExerciseTheiaComponent) programmingExerciseTheiaComponent?: ProgrammingExerciseTheiaComponent; formValid: boolean; formValidChanges = new Subject(); diff --git a/src/main/webapp/app/exercises/programming/manage/update/update-components/theia/programming-exercise-theia.component.html b/src/main/webapp/app/exercises/programming/manage/update/update-components/theia/programming-exercise-theia.component.html new file mode 100644 index 000000000000..96d23fa998e8 --- /dev/null +++ b/src/main/webapp/app/exercises/programming/manage/update/update-components/theia/programming-exercise-theia.component.html @@ -0,0 +1,21 @@ +
+ +
diff --git a/src/main/webapp/app/exercises/programming/manage/update/update-components/theia/programming-exercise-theia.component.ts b/src/main/webapp/app/exercises/programming/manage/update/update-components/theia/programming-exercise-theia.component.ts new file mode 100644 index 000000000000..98849723625d --- /dev/null +++ b/src/main/webapp/app/exercises/programming/manage/update/update-components/theia/programming-exercise-theia.component.ts @@ -0,0 +1,82 @@ +import { Component, Input, OnChanges, SimpleChanges } from '@angular/core'; +import { ProgrammingExercise, ProgrammingLanguage } from 'app/entities/programming-exercise.model'; +import { ProgrammingExerciseCreationConfig } from 'app/exercises/programming/manage/update/programming-exercise-creation-config'; +import { TheiaService } from 'app/exercises/programming/shared/service/theia.service'; +import { ArtemisSharedLibsModule } from 'app/shared/shared-libs.module'; + +@Component({ + selector: 'jhi-programming-exercise-theia', + templateUrl: './programming-exercise-theia.component.html', + styleUrls: ['../../../programming-exercise-form.scss'], + standalone: true, + imports: [ArtemisSharedLibsModule], +}) +export class ProgrammingExerciseTheiaComponent implements OnChanges { + @Input() programmingExercise: ProgrammingExercise; + @Input() programmingExerciseCreationConfig: ProgrammingExerciseCreationConfig; + + programmingLanguage?: ProgrammingLanguage; + theiaImages = {}; + + constructor(private theiaService: TheiaService) {} + + ngOnChanges(changes: SimpleChanges) { + if ((changes.programmingExerciseCreationConfig || changes.programmingExercise) && this.shouldReloadTemplate()) { + this.loadTheiaImages(); + } + } + + onTheiaImageChange(theiaImage: string) { + if (this.programmingExercise.buildConfig) { + this.programmingExercise.buildConfig.theiaImage = theiaImage; + } + } + + shouldReloadTemplate(): boolean { + return this.programmingExercise.programmingLanguage !== this.programmingLanguage; + } + + /** + * In case the programming language or project type changes, we need to reset the template and the build plan + * @private + */ + resetImageSelection() { + if (this.programmingExercise.buildConfig) { + this.programmingExercise.buildConfig.theiaImage = undefined; + } + } + + /** + * Loads the predefined template for the selected programming language if there is one available. + * @private + */ + loadTheiaImages() { + if (!this.programmingExercise || !this.programmingExercise.programmingLanguage) { + return; + } + + this.programmingLanguage = this.programmingExercise.programmingLanguage; + + this.theiaService.getTheiaImages(this.programmingLanguage).subscribe({ + next: (images) => { + if (!images) { + // Remove selection if no image is available + this.theiaImages = {}; + this.resetImageSelection(); + return; + } + + this.theiaImages = images; + + // Set the first image as default if none is selected + if (this.programmingExercise && this.programmingExercise.buildConfig && !this.programmingExercise.buildConfig.theiaImage && Object.values(images).length > 0) { + this.programmingExercise.buildConfig.theiaImage = Object.values(images).first() as string; + } + }, + error: () => { + this.theiaImages = {}; + this.resetImageSelection(); + }, + }); + } +} diff --git a/src/main/webapp/app/exercises/programming/shared/service/theia.service.ts b/src/main/webapp/app/exercises/programming/shared/service/theia.service.ts new file mode 100644 index 000000000000..d59673d738ac --- /dev/null +++ b/src/main/webapp/app/exercises/programming/shared/service/theia.service.ts @@ -0,0 +1,25 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; + +import { ProgrammingLanguage } from 'app/entities/programming-exercise.model'; + +@Injectable({ providedIn: 'root' }) +export class TheiaService { + private resourceUrl = 'api/theia'; + + constructor(private http: HttpClient) {} + + /** + * Fetches the theia images for the given programming language + * @param {ProgrammingLanguage} language + * @returns the theia images or undefined if no images are available for this language + */ + getTheiaImages(language: ProgrammingLanguage): Observable<{ [key: string]: string } | undefined> { + return this.http.get<{ [key: string]: string }>(`${this.resourceUrl}/images`, { + params: { + language: language, + }, + }); + } +} diff --git a/src/main/webapp/app/overview/exercise-details/exercise-details-student-actions.component.ts b/src/main/webapp/app/overview/exercise-details/exercise-details-student-actions.component.ts index f2e251a81804..87e74ad54d11 100644 --- a/src/main/webapp/app/overview/exercise-details/exercise-details-student-actions.component.ts +++ b/src/main/webapp/app/overview/exercise-details/exercise-details-student-actions.component.ts @@ -61,14 +61,14 @@ export class ExerciseDetailsStudentActionsComponent implements OnInit, OnChanges theiaPortalURL: string; // Icons - faFolderOpen = faFolderOpen; - faUsers = faUsers; - faEye = faEye; - faPlayCircle = faPlayCircle; - faRedo = faRedo; - faCodeBranch = faCodeBranch; - faDesktop = faDesktop; - faPenSquare = faPenSquare; + readonly faFolderOpen = faFolderOpen; + readonly faUsers = faUsers; + readonly faEye = faEye; + readonly faPlayCircle = faPlayCircle; + readonly faRedo = faRedo; + readonly faCodeBranch = faCodeBranch; + readonly faDesktop = faDesktop; + readonly faPenSquare = faPenSquare; private feedbackSent = false; @@ -109,7 +109,7 @@ export class ExerciseDetailsStudentActionsComponent implements OnInit, OnChanges this.athenaEnabled = profileInfo.activeProfiles?.includes(PROFILE_ATHENA); // The online IDE is only available with correct SpringProfile and if it's enabled for this exercise - if (profileInfo.activeProfiles?.includes(PROFILE_THEIA)) { + if (profileInfo.activeProfiles?.includes(PROFILE_THEIA) && this.programmingExercise) { this.theiaEnabled = true; // Set variables now, sanitize later on @@ -119,6 +119,16 @@ export class ExerciseDetailsStudentActionsComponent implements OnInit, OnChanges if (this.theiaPortalURL === '') { this.theiaEnabled = false; } + + // Verify that the exercise allows the online IDE + if (!this.programmingExercise.allowOnlineIde) { + this.theiaEnabled = false; + } + + // Verify that the exercise has a theia blueprint configured + if (!this.programmingExercise.buildConfig?.theiaImage) { + this.theiaEnabled = false; + } } }); } else if (this.exercise.type === ExerciseType.MODELING) { diff --git a/src/main/webapp/i18n/de/programmingExercise.json b/src/main/webapp/i18n/de/programmingExercise.json index ae25116ddc7a..9409c371c61a 100644 --- a/src/main/webapp/i18n/de/programmingExercise.json +++ b/src/main/webapp/i18n/de/programmingExercise.json @@ -118,14 +118,22 @@ "workdir": "Verzeichnis", "allowOnlineEditor": { "title": "Online-Editor erlauben", - "alert": "Es muss mindestens eine Option (Offline-IDE oder Online-Editor) ausgewählt sein" + "alert": "Es muss mindestens eine Option (Offline-IDE, Online-Editor oder Online-IDE) ausgewählt sein", + "alertNoTheia": "Es muss mindestens eine Option (Offline-IDE oder Online-Editor) ausgewählt sein" }, "onlineEditor": "Online", "allowOfflineIde": { "title": "Offline-IDE erlauben", - "alert": "Es muss mindestens eine Option (Offline-IDE oder Online-Editor) ausgewählt sein" + "alert": "Es muss mindestens eine Option (Offline-IDE, Online-Editor oder Online-IDE) ausgewählt sein", + "alertNoTheia": "Es muss mindestens eine Option (Offline-IDE oder Online-Editor) ausgewählt sein" }, "offlineIde": "IDE", + "allowOnlineIde": { + "title": "Online-IDE erlauben", + "alert": "Es muss mindestens eine Option (Offline-IDE, Online-Editor oder Online-IDE) ausgewählt sein.", + "alertNoTheia": "Es muss mindestens eine Option (Offline-IDE oder Online-Editor) ausgewählt sein" + }, + "onlineIde": "Online IDE", "showTestNamesToStudents": "Zeige die Test Namen den Studierenden", "showTestNamesToStudentsTooltip": "Durch Aktivierung dieser Option werden die Namen der automatischen Tests den Studierenden angezeigt. Lasse die Option deaktiviert, um keine visuelle Unterscheidung zwischen manuellem und automatischem Feedback für die Studierenden vorzunehmen.", "participationMode": "Teilnahmemodus", @@ -170,6 +178,11 @@ "projectType": "Projekttyp", "testRepositoryProjectType": "Projekttyp des Test-Repository", "packageName": "Package-Name", + "theiaImage": { + "title": "Konfiguration für Online IDE", + "noImageAvailable": "Die Online IDE ist für diese Programmiersprache noch nicht verfügbar.", + "alert": "Es muss eine gültige Konfiguration für die Online IDE ausgewählt werden." + }, "appName": "App-Name", "templateResult": "Ergebnis der Vorlage", "solutionResult": "Ergebnis der Musterlösung", diff --git a/src/main/webapp/i18n/en/programmingExercise.json b/src/main/webapp/i18n/en/programmingExercise.json index e199355c4a82..06f826607ba7 100644 --- a/src/main/webapp/i18n/en/programmingExercise.json +++ b/src/main/webapp/i18n/en/programmingExercise.json @@ -130,14 +130,22 @@ "customizeDockerImage": "You can customize the Docker image. Make sure to provide it in amd64 and arm64 and include all build dependencies to guarantee a short build duration.", "allowOnlineEditor": { "title": "Allow Online Editor", - "alert": "At least one option (Offline IDE or Online Editor) must be selected" + "alert": "At least one option (Offline IDE, Online Editor, or Online IDE) must be selected", + "alertNoTheia": "At least one option (Offline IDE or Online Editor) must be selected" }, "onlineEditor": "Online", "allowOfflineIde": { "title": "Allow Offline IDE", - "alert": "At least one option (Offline IDE or Online Editor) must be selected" + "alert": "At least one option (Offline IDE, Online Editor, or Online IDE) must be selected", + "alertNoTheia": "At least one option (Offline IDE or Online Editor) must be selected" }, "offlineIde": "IDE", + "allowOnlineIde": { + "title": "Allow Online IDE", + "alert": "At least one option (Offline IDE, Online Editor, or Online IDE) must be selected.", + "alertNoTheia": "At least one option (Offline IDE or Online Editor) must be selected" + }, + "onlineIde": "Online IDE", "showTestNamesToStudents": "Show Test Names to Students", "showTestNamesToStudentsTooltip": "Activate this option to show the names of the automated test cases to the students. Leave the option disabled to make no visual distinction between manual and automated feedback for the students.", "participationMode": "Participation Mode", @@ -172,6 +180,11 @@ "projectType": "Project Type", "testRepositoryProjectType": "Test Repository Project Type", "packageName": "Package Name", + "theiaImage": { + "title": "Configuration for Online IDE", + "noImageAvailable": "The Online IDE is not yet available for this programming language.", + "alert": "A valid configuration for the Online IDE must be selected." + }, "appName": "App Name", "templateResult": "Template Result", "solutionResult": "Solution Result", diff --git a/src/test/java/de/tum/in/www1/artemis/AbstractSpringIntegrationIndependentTest.java b/src/test/java/de/tum/in/www1/artemis/AbstractSpringIntegrationIndependentTest.java index c72bb2a37e0f..d2b41249721c 100644 --- a/src/test/java/de/tum/in/www1/artemis/AbstractSpringIntegrationIndependentTest.java +++ b/src/test/java/de/tum/in/www1/artemis/AbstractSpringIntegrationIndependentTest.java @@ -2,6 +2,7 @@ import static de.tum.in.www1.artemis.config.Constants.PROFILE_CORE; import static de.tum.in.www1.artemis.config.Constants.PROFILE_SCHEDULING; +import static de.tum.in.www1.artemis.config.Constants.PROFILE_THEIA; import static tech.jhipster.config.JHipsterConstants.SPRING_PROFILE_TEST; import java.util.Set; @@ -34,7 +35,7 @@ */ @ResourceLock("AbstractSpringIntegrationIndependentTest") // NOTE: we use a common set of active profiles to reduce the number of application launches during testing. This significantly saves time and memory! -@ActiveProfiles({ SPRING_PROFILE_TEST, "artemis", PROFILE_SCHEDULING, "athena", "apollon", "lti", "aeolus", PROFILE_CORE }) +@ActiveProfiles({ SPRING_PROFILE_TEST, "artemis", PROFILE_SCHEDULING, "athena", "apollon", "lti", "aeolus", PROFILE_THEIA, PROFILE_CORE }) @TestPropertySource(properties = { "artemis.user-management.use-external=false" }) public abstract class AbstractSpringIntegrationIndependentTest extends AbstractArtemisIntegrationTest { diff --git a/src/test/java/de/tum/in/www1/artemis/config/TheiaConfigurationTest.java b/src/test/java/de/tum/in/www1/artemis/config/TheiaConfigurationTest.java new file mode 100644 index 000000000000..41852515b971 --- /dev/null +++ b/src/test/java/de/tum/in/www1/artemis/config/TheiaConfigurationTest.java @@ -0,0 +1,41 @@ +package de.tum.in.www1.artemis.config; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Map; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import de.tum.in.www1.artemis.AbstractSpringIntegrationIndependentTest; +import de.tum.in.www1.artemis.domain.enumeration.ProgrammingLanguage; + +class TheiaConfigurationTest extends AbstractSpringIntegrationIndependentTest { + + @Autowired + private TheiaConfiguration theiaConfiguration; + + @Test + void testAutowired() { + assertThat(theiaConfiguration).isNotNull(); + } + + @Test + void testAmountOfLanguageImages() { + assertThat(theiaConfiguration.getImagesForAllLanguages()).hasSize(2); + } + + @Test + void testFlavorsForLanguage() { + Map images = theiaConfiguration.getImagesForLanguage(ProgrammingLanguage.valueOf("JAVA")); + assertThat(images).hasSize(2); + assertThat(images).containsKey("Java-17"); + assertThat(images).containsValue("ghcr.io/ls1intum/theia/java-17:latest"); + assertThat(images.get("Java-Non-Existent")).isEqualTo("this-is-not-a-valid-image"); + } + + @Test + void testNonExistentLanguage() { + assertThat(theiaConfiguration.getImagesForLanguage(null)).isNull(); + } +} diff --git a/src/test/java/de/tum/in/www1/artemis/theia/TheiaInfoContributorTest.java b/src/test/java/de/tum/in/www1/artemis/theia/TheiaInfoContributorTest.java index 04c75c487a6f..8b3b6738b219 100644 --- a/src/test/java/de/tum/in/www1/artemis/theia/TheiaInfoContributorTest.java +++ b/src/test/java/de/tum/in/www1/artemis/theia/TheiaInfoContributorTest.java @@ -23,14 +23,9 @@ class TheiaInfoContributorTest { void testContribute() { Info.Builder builder = new Info.Builder(); theiaInfoContributor = new TheiaInfoContributor(); - try { - theiaInfoContributor.contribute(builder); - } - catch (NullPointerException e) { - } + theiaInfoContributor.contribute(builder); Info info = builder.build(); assertThat(info.getDetails().get(Constants.THEIA_PORTAL_URL)).isEqualTo(expectedValue); - } } diff --git a/src/test/javascript/spec/component/exam/manage/exercise-groups/programming-exercise-group-cell.component.spec.ts b/src/test/javascript/spec/component/exam/manage/exercise-groups/programming-exercise-group-cell.component.spec.ts index fe38c8c71ae0..43d15f8f8634 100644 --- a/src/test/javascript/spec/component/exam/manage/exercise-groups/programming-exercise-group-cell.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/exercise-groups/programming-exercise-group-cell.component.spec.ts @@ -30,6 +30,7 @@ describe('Programming Exercise Group Cell Component', () => { }, allowOfflineIde: true, allowOnlineEditor: true, + allowOnlineIde: false, } as any as ProgrammingExercise; let mockedProfileService: ProfileService; @@ -93,11 +94,15 @@ describe('Programming Exercise Group Cell Component', () => { const div0 = fixture.debugElement.query(By.css('div > div > div:first-child')); expect(div0).not.toBeNull(); - expect(div0.nativeElement.textContent?.trim()).toBe('artemisApp.programmingExercise.offlineIde : true'); + expect(div0.nativeElement.textContent?.trim()).toBe(': true'); const div1 = fixture.debugElement.query(By.css('div > div > div:nth-child(2)')); expect(div1).not.toBeNull(); - expect(div1.nativeElement.textContent?.trim()).toBe('artemisApp.programmingExercise.onlineEditor : true'); + expect(div1.nativeElement.textContent?.trim()).toBe(': true'); + + const div2 = fixture.debugElement.query(By.css('div > div > div:nth-child(3)')); + expect(div2).not.toBeNull(); + expect(div2.nativeElement.textContent?.trim()).toBe(': false'); }); it('should download the repository', () => { diff --git a/src/test/javascript/spec/component/overview/exercise-details/exercise-details-student-actions.component.spec.ts b/src/test/javascript/spec/component/overview/exercise-details/exercise-details-student-actions.component.spec.ts index 9a0a2327c015..1a770b4e5002 100644 --- a/src/test/javascript/spec/component/overview/exercise-details/exercise-details-student-actions.component.spec.ts +++ b/src/test/javascript/spec/component/overview/exercise-details/exercise-details-student-actions.component.spec.ts @@ -55,6 +55,7 @@ describe('ExerciseDetailsStudentActionsComponent', () => { secondCorrectionEnabled: false, studentAssignedTeamIdComputed: false, }; + const teamExerciseWithoutTeamAssigned: Exercise = { ...exercise, mode: ExerciseMode.TEAM, @@ -607,18 +608,58 @@ describe('ExerciseDetailsStudentActionsComponent', () => { it.each([ [ - 'start theia button should be visible when profile is active and url is set', + 'start theia button should be visible when profile is active and theia is configured', { activeProfiles: [PROFILE_THEIA], theiaPortalURL: 'https://theia.test', }, + { + allowOnlineIde: true, + }, + { + theiaImage: 'this-is-a-theia-image', + }, true, ], + [ + 'start theia button should not be visible when profile is active but theia is ill-configured', + { + activeProfiles: [PROFILE_THEIA], + theiaPortalURL: 'https://theia.test', + }, + { + allowOnlineIde: true, + }, + { + theiaImage: undefined, + }, + false, + ], + [ + 'start theia button should not be visible when profile is active but onlineIde is not activated', + { + activeProfiles: [PROFILE_THEIA], + theiaPortalURL: 'https://theia.test', + }, + { + allowOnlineIde: false, + }, + { + theiaImage: 'this-is-an-old-image', + }, + false, + ], [ 'start theia button should not be visible when profile is active but url is not set', { activeProfiles: [PROFILE_THEIA], }, + { + allowOnlineIde: true, + }, + { + theiaImage: 'this-is-a-theia-image', + }, false, ], [ @@ -626,12 +667,20 @@ describe('ExerciseDetailsStudentActionsComponent', () => { { theiaPortalURL: 'https://theia.test', }, + { + allowOnlineIde: true, + }, + { + theiaImage: 'this-is-a-theia-image', + }, false, ], - ])('%s', (description, profileInfo, expectedVisibility) => { + ])('%s', (description, profileInfo, programmingExercise, buildConfig, expectedVisibility) => { getProfileInfoSub = jest.spyOn(profileService, 'getProfileInfo'); getProfileInfoSub.mockReturnValue(of(profileInfo as ProfileInfo)); - comp.exercise = exercise; + + // Expand the programmingExercise by given properties + comp.exercise = { ...exercise, ...programmingExercise, buildConfig: buildConfig } as ProgrammingExercise; fixture.detectChanges(); diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-update.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-update.component.spec.ts index c4f40f4b79dc..5441500fe1a3 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-update.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-update.component.spec.ts @@ -67,6 +67,9 @@ import { AlertService, AlertType } from 'app/core/util/alert.service'; import { FormStatusBarComponent } from 'app/forms/form-status-bar/form-status-bar.component'; import { FormFooterComponent } from 'app/forms/form-footer/form-footer.component'; import { ProgrammingExerciseRepositoryAndBuildPlanDetailsComponent } from 'app/exercises/programming/shared/build-details/programming-exercise-repository-and-build-plan-details.component'; +import { ProfileInfo } from 'app/shared/layouts/profiles/profile-info.model'; +import { ProfileService } from 'app/shared/layouts/profiles/profile.service'; +import { PROFILE_THEIA } from 'app/app.constants'; describe('ProgrammingExerciseUpdateComponent', () => { const courseId = 1; @@ -80,6 +83,9 @@ describe('ProgrammingExerciseUpdateComponent', () => { let exerciseGroupService: ExerciseGroupService; let programmingExerciseFeatureService: ProgrammingLanguageFeatureService; let alertService: AlertService; + let profileService: ProfileService; + + let getProfileInfoSub: jest.SpyInstance; beforeEach(() => { TestBed.configureTestingModule({ @@ -147,6 +153,12 @@ describe('ProgrammingExerciseUpdateComponent', () => { exerciseGroupService = debugElement.injector.get(ExerciseGroupService); programmingExerciseFeatureService = debugElement.injector.get(ProgrammingLanguageFeatureService); alertService = debugElement.injector.get(AlertService); + profileService = debugElement.injector.get(ProfileService); + + getProfileInfoSub = jest.spyOn(profileService, 'getProfileInfo'); + const newProfileInfo = new ProfileInfo(); + newProfileInfo.activeProfiles = []; + getProfileInfoSub.mockReturnValue(of(newProfileInfo)); }); }); @@ -792,11 +804,56 @@ describe('ProgrammingExerciseUpdateComponent', () => { }); }); - it('find validation errors for invalid ide selection', () => { + it.each([ + [ + 'find validation errors for invalid ide selection', + { + activeProfiles: [PROFILE_THEIA], + }, + { + translateKey: 'artemisApp.programmingExercise.allowOnlineEditor.alert', + translateValues: {}, + }, + ], + [ + 'find validation errors for invalid ide selection without theia profile', + { + activeProfiles: [], + }, + { + translateKey: 'artemisApp.programmingExercise.allowOnlineEditor.alertNoTheia', + translateValues: {}, + }, + ], + ])('%s', (description, profileInfo, expectedException) => { + getProfileInfoSub = jest.spyOn(profileService, 'getProfileInfo'); + + const newProfileInfo = new ProfileInfo(); + newProfileInfo.activeProfiles = profileInfo.activeProfiles; + + getProfileInfoSub.mockReturnValue(of(newProfileInfo)); + + const route = TestBed.inject(ActivatedRoute); + route.params = of({ courseId }); + route.url = of([{ path: 'new' } as UrlSegment]); + route.data = of({ programmingExercise: comp.programmingExercise }); + + jest.spyOn(programmingExerciseFeatureService, 'getProgrammingLanguageFeature').mockReturnValue(getProgrammingLanguageFeature(ProgrammingLanguage.JAVA)); + comp.programmingExercise.allowOnlineEditor = false; comp.programmingExercise.allowOfflineIde = false; + comp.programmingExercise.allowOnlineIde = false; + + fixture.detectChanges(); + + expect(comp.getInvalidReasons()).toContainEqual(expectedException); + }); + + it('find validation errors for invalid online IDE image', () => { + comp.programmingExercise.allowOnlineIde = true; + comp.programmingExercise.buildConfig!.theiaImage = undefined; expect(comp.getInvalidReasons()).toContainEqual({ - translateKey: 'artemisApp.programmingExercise.allowOnlineEditor.alert', + translateKey: 'artemisApp.programmingExercise.theiaImage.alert', translateValues: {}, }); }); @@ -832,6 +889,7 @@ describe('ProgrammingExerciseUpdateComponent', () => { comp.programmingExercise.maxStaticCodeAnalysisPenalty = 60; comp.programmingExercise.allowOfflineIde = true; comp.programmingExercise.allowOnlineEditor = false; + comp.programmingExercise.allowOnlineIde = false; comp.programmingExercise.packageName = 'de.tum.in'; comp.programmingExercise.programmingLanguage = ProgrammingLanguage.JAVA; @@ -1017,6 +1075,7 @@ describe('ProgrammingExerciseUpdateComponent', () => { comp.programmingExercise.allowOfflineIde = false; comp.programmingExercise.allowOnlineEditor = false; + comp.programmingExercise.allowOnlineIde = false; comp.calculateFormStatusSections(); expect(comp.formStatusSections[1].valid).toBeFalse(); comp.programmingExercise.allowOnlineEditor = true; diff --git a/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-creation-config-mock.ts b/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-creation-config-mock.ts index d33537559cbd..7879f1f5c0b5 100644 --- a/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-creation-config-mock.ts +++ b/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-creation-config-mock.ts @@ -69,5 +69,8 @@ export const programmingExerciseCreationConfigMock: ProgrammingExerciseCreationC validIdeSelection(): boolean | undefined { return true; }, + validOnlineIdeSelection(): boolean | undefined { + return true; + }, withDependencies: false, }; diff --git a/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-difficulty.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-difficulty.component.spec.ts index 11d63911cc2c..ce4ba0bc736f 100644 --- a/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-difficulty.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-difficulty.component.spec.ts @@ -1,5 +1,6 @@ -import { ComponentFixture, TestBed, fakeAsync } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MockComponent, MockPipe } from 'ng-mocks'; +import { DebugElement } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { of } from 'rxjs'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; @@ -9,14 +10,21 @@ import { DifficultyPickerComponent } from 'app/exercises/shared/difficulty-picke import { TeamConfigFormGroupComponent } from 'app/exercises/shared/team-config-form-group/team-config-form-group.component'; import { programmingExerciseCreationConfigMock } from './programming-exercise-creation-config-mock'; import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProfileInfo } from 'app/shared/layouts/profiles/profile-info.model'; +import { ProfileService } from 'app/shared/layouts/profiles/profile.service'; +import { PROFILE_THEIA } from 'app/app.constants'; +import { ArtemisTestModule } from '../../../test.module'; describe('ProgrammingExerciseDifficultyComponent', () => { let fixture: ComponentFixture; let comp: ProgrammingExerciseDifficultyComponent; + let debugElement: DebugElement; + let profileService: ProfileService; + let getProfileInfoSub: jest.SpyInstance; beforeEach(() => { TestBed.configureTestingModule({ - imports: [], + imports: [ArtemisTestModule], declarations: [ CheckboxControlValueAccessor, DefaultValueAccessor, @@ -42,6 +50,11 @@ describe('ProgrammingExerciseDifficultyComponent', () => { comp = fixture.componentInstance; comp.programmingExercise = new ProgrammingExercise(undefined, undefined); comp.programmingExerciseCreationConfig = programmingExerciseCreationConfigMock; + + debugElement = fixture.debugElement; + profileService = debugElement.injector.get(ProfileService); + getProfileInfoSub = jest.spyOn(profileService, 'getProfileInfo'); + getProfileInfoSub.mockReturnValue(of({ inProduction: false, sshCloneURLTemplate: 'ssh://git@testserver.com:1234/' } as ProfileInfo)); }); }); @@ -49,8 +62,16 @@ describe('ProgrammingExerciseDifficultyComponent', () => { jest.restoreAllMocks(); }); - it('should initialize', fakeAsync(() => { + it('should initialize', () => { fixture.detectChanges(); expect(comp).not.toBeNull(); - })); + }); + + it('should initialize theiaEnabled', () => { + getProfileInfoSub = jest.spyOn(profileService, 'getProfileInfo'); + getProfileInfoSub.mockReturnValue(of({ activeProfiles: [PROFILE_THEIA] } as ProfileInfo)); + + fixture.detectChanges(); + expect(comp.theiaEnabled).toBeTrue(); + }); }); diff --git a/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-language.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-language.component.spec.ts index 399f1969f22d..4d21b3741ce6 100644 --- a/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-language.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-language.component.spec.ts @@ -8,16 +8,25 @@ import { RemoveKeysPipe } from 'app/shared/pipes/remove-keys.pipe'; import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; import { ProgrammingExerciseLanguageComponent } from 'app/exercises/programming/manage/update/update-components/programming-exercise-language.component'; import { programmingExerciseCreationConfigMock } from './programming-exercise-creation-config-mock'; +import { ProgrammingExerciseTheiaComponent } from 'app/exercises/programming/manage/update/update-components/theia/programming-exercise-theia.component'; +import { provideHttpClient } from '@angular/common/http'; +import { TheiaService } from 'app/exercises/programming/shared/service/theia.service'; describe('ProgrammingExerciseLanguageComponent', () => { let fixture: ComponentFixture; let comp: ProgrammingExerciseLanguageComponent; + let theiaServiceMock!: { getTheiaImages: jest.Mock }; + beforeEach(() => { + theiaServiceMock = { + getTheiaImages: jest.fn(), + }; TestBed.configureTestingModule({ imports: [], declarations: [ ProgrammingExerciseLanguageComponent, + ProgrammingExerciseTheiaComponent, CheckboxControlValueAccessor, DefaultValueAccessor, SelectControlValueAccessor, @@ -27,10 +36,15 @@ describe('ProgrammingExerciseLanguageComponent', () => { MockPipe(RemoveKeysPipe), ], providers: [ + provideHttpClient(), { provide: ActivatedRoute, useValue: { queryParams: of({}) }, }, + { + provide: TheiaService, + useValue: theiaServiceMock, + }, ], schemas: [], }) @@ -52,4 +66,19 @@ describe('ProgrammingExerciseLanguageComponent', () => { tick(); expect(comp).not.toBeNull(); })); + + it('should not load TheiaComponent when online IDE is not allowed', fakeAsync(() => { + comp.programmingExercise.allowOnlineIde = false; + fixture.detectChanges(); + tick(); + expect(comp.programmingExerciseTheiaComponent).toBeUndefined(); + })); + + it('should load TheiaComponent when online IDE is allowed', fakeAsync(() => { + theiaServiceMock.getTheiaImages.mockReturnValue(of({})); + comp.programmingExercise.allowOnlineIde = true; + fixture.detectChanges(); + tick(); + expect(comp.programmingExerciseTheiaComponent).not.toBeNull(); + })); }); diff --git a/src/test/javascript/spec/component/programming-exercise/update-components/theia/programming-exercise-theia.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/update-components/theia/programming-exercise-theia.component.spec.ts new file mode 100644 index 000000000000..13f4e23cbbcd --- /dev/null +++ b/src/test/javascript/spec/component/programming-exercise/update-components/theia/programming-exercise-theia.component.spec.ts @@ -0,0 +1,90 @@ +import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; +import { MockPipe } from 'ng-mocks'; +import { ActivatedRoute } from '@angular/router'; +import { of } from 'rxjs'; +import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; +import { RemoveKeysPipe } from 'app/shared/pipes/remove-keys.pipe'; +import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { programmingExerciseCreationConfigMock } from '../programming-exercise-creation-config-mock'; +import { ProgrammingExerciseTheiaComponent } from 'app/exercises/programming/manage/update/update-components/theia/programming-exercise-theia.component'; +import { TheiaService } from 'app/exercises/programming/shared/service/theia.service'; +import { ArtemisSharedLibsModule } from 'app/shared/shared-libs.module'; + +describe('ProgrammingExerciseTheiaComponent', () => { + let fixture: ComponentFixture; + let comp: ProgrammingExerciseTheiaComponent; + + let theiaServiceMock!: { getTheiaImages: jest.Mock }; + + beforeEach(() => { + theiaServiceMock = { + getTheiaImages: jest.fn(), + }; + TestBed.configureTestingModule({ + imports: [ProgrammingExerciseTheiaComponent, ArtemisSharedLibsModule], + declarations: [MockPipe(ArtemisTranslatePipe), MockPipe(RemoveKeysPipe)], + providers: [ + { + provide: ActivatedRoute, + useValue: { queryParams: of({}) }, + }, + { + provide: TheiaService, + useValue: theiaServiceMock, + }, + ], + schemas: [], + }).compileComponents(); + + fixture = TestBed.createComponent(ProgrammingExerciseTheiaComponent); + comp = fixture.componentInstance; + comp.programmingExerciseCreationConfig = programmingExerciseCreationConfigMock; + comp.programmingExercise = new ProgrammingExercise(undefined, undefined); + comp.programmingExercise.allowOnlineIde = true; + }); + + afterEach(() => { + jest.restoreAllMocks(); + }); + + it('should initialize', fakeAsync(() => { + fixture.detectChanges(); + tick(); + expect(comp).not.toBeNull(); + })); + + it('should have no selectedImage when no image is available', fakeAsync(() => { + theiaServiceMock.getTheiaImages.mockReturnValue(of({})); + fixture.detectChanges(); + comp.loadTheiaImages(); + tick(); + expect(comp.programmingExercise.buildConfig?.theiaImage).toBeUndefined(); + })); + + it('should select first image when none was selected', fakeAsync(() => { + theiaServiceMock.getTheiaImages.mockReturnValue( + of({ + 'Java-17': 'test-url', + 'Java-Test': 'test-url-2', + }), + ); + fixture.detectChanges(); + comp.loadTheiaImages(); + tick(); + expect(comp.programmingExercise.buildConfig?.theiaImage).toMatch('test-url'); + })); + + it('should not overwrite selected image when others are loaded', fakeAsync(() => { + comp.programmingExercise.buildConfig!.theiaImage = 'test-url-2'; + theiaServiceMock.getTheiaImages.mockReturnValue( + of({ + 'Java-17': 'test-url', + 'Java-Test': 'test-url-2', + }), + ); + fixture.detectChanges(); + comp.loadTheiaImages(); + tick(); + expect(comp.programmingExercise.buildConfig?.theiaImage).toMatch('test-url-2'); + })); +}); diff --git a/src/test/javascript/spec/service/programming-exercise.service.spec.ts b/src/test/javascript/spec/service/programming-exercise.service.spec.ts index 66ca8a1e0d44..fd2ab5d925e7 100644 --- a/src/test/javascript/spec/service/programming-exercise.service.spec.ts +++ b/src/test/javascript/spec/service/programming-exercise.service.spec.ts @@ -179,6 +179,7 @@ describe('ProgrammingExercise Service', () => { solutionRepositoryUri: 'BBBBBB', templateBuildPlanId: 'BBBBBB', allowOnlineEditor: true, + allowOnlineIde: true, releaseDate: undefined, dueDate: undefined, assessmentDueDate: undefined, @@ -222,6 +223,7 @@ describe('ProgrammingExercise Service', () => { solutionRepositoryUri: 'BBBBBB', templateBuildPlanId: 'BBBBBB', allowOnlineEditor: true, + allowOnlineIde: true, releaseDate: undefined, dueDate: undefined, assessmentDueDate: undefined, diff --git a/src/test/resources/config/application-theia.yml b/src/test/resources/config/application-theia.yml new file mode 100644 index 000000000000..883dea41098f --- /dev/null +++ b/src/test/resources/config/application-theia.yml @@ -0,0 +1,9 @@ +theia: + portal-url: https://your-theia-instance.com + + images: + java: + Java-17: "ghcr.io/ls1intum/theia/java-17:latest" + Java-Non-Existent: "this-is-not-a-valid-image" + c: + C: "ghcr.io/ls1intum/theia/c:latest" From 15f890ff958b18c4c7217595feb657a3b845d2e7 Mon Sep 17 00:00:00 2001 From: Stephan Krusche Date: Mon, 2 Sep 2024 12:09:57 +0200 Subject: [PATCH 06/16] Development: Remove cypress (#9267) --- .ci/E2E-tests/cleanup.sh | 4 - .ci/E2E-tests/execute.sh | 37 +- .github/labeler.yml | 4 +- .gitignore | 7 - docker/artemis-migration-check-postgres.yml | 4 +- ...cypress-local.env => playwright-local.env} | 2 +- ...s-postgres.env => playwright-postgres.env} | 2 +- .../config/{cypress.env => playwright.env} | 2 +- docker/cypress-E2E-tests-local.yml | 62 - docker/cypress-E2E-tests-multi-node.yml | 134 - docker/cypress-E2E-tests-mysql.yml | 60 - docker/cypress-E2E-tests-postgres.yml | 61 - docker/cypress.yml | 41 - docker/nginx.yml | 2 - ...ess.conf => artemis-nginx-playwright.conf} | 0 docker/playwright-E2E-tests-multi-node.yml | 14 +- docker/playwright-E2E-tests-mysql-localci.yml | 8 +- docker/playwright-E2E-tests-mysql.yml | 8 +- docker/playwright-E2E-tests-postgres.yml | 8 +- docker/sorry-cypress/.htpasswd | 4 - docker/sorry-cypress/README.md | 40 - docker/sorry-cypress/SETUP.md | 25 - docker/sorry-cypress/minio-user-policy.json | 21 - docker/sorry-cypress/nginx.conf | 129 - docker/sorry-cypress/sorry-cypress.env | 22 - docker/sorry-cypress/sorry-cypress.yml | 107 - .../test-server-multi-node-mysql-localci.yml | 4 +- ...t-server-multi-node-postgresql-localci.yml | 4 +- docker/test-server-mysql-localci.yml | 4 +- docker/test-server-mysql.yml | 4 +- docker/test-server-postgresql-localci.yml | 4 +- docker/test-server-postgresql.yml | 4 +- eslint.config.js | 15 +- .../security/jwt/JWTCookieService.java | 5 +- src/test/cypress/README.md | 83 - .../cypress/certs/artemis-nginx+4-key.pem | 28 - src/test/cypress/certs/artemis-nginx+4.pem | 25 - src/test/cypress/certs/rootCA.pem | 27 - src/test/cypress/currents.config.js | 5 - src/test/cypress/cypress.config.ts | 87 - src/test/cypress/cypress.env.json | 12 - src/test/cypress/e2e/Login.cy.ts | 47 - src/test/cypress/e2e/Logout.cy.ts | 64 - src/test/cypress/e2e/SystemHealth.cy.ts | 43 - .../cypress/e2e/course/CourseExercise.cy.ts | 57 - .../cypress/e2e/course/CourseManagement.cy.ts | 308 -- .../cypress/e2e/course/CourseMessages.cy.ts | 428 --- .../cypress/e2e/exam/ExamAssessment.cy.ts | 255 -- .../e2e/exam/ExamCreationDeletion.cy.ts | 184 - .../e2e/exam/ExamDateVerification.cy.ts | 151 - .../cypress/e2e/exam/ExamManagement.cy.ts | 184 - .../cypress/e2e/exam/ExamParticipation.cy.ts | 305 -- src/test/cypress/e2e/exam/ExamTestRun.cy.ts | 151 - .../test-exam/TestExamCreationDeletion.cy.ts | 107 - .../exam/test-exam/TestExamManagement.cy.ts | 156 - .../test-exam/TestExamParticipation.cy.ts | 175 - .../exam/test-exam/TestExamStudentExams.cy.ts | 148 - .../e2e/exam/test-exam/TestExamTestRun.cy.ts | 150 - .../e2e/exercises/ExerciseImport.cy.ts | 177 - .../FileUploadExerciseAssessment.cy.ts | 82 - .../FileUploadExerciseManagement.cy.ts | 71 - .../FileUploadExerciseParticipation.cy.ts | 45 - .../modeling/ModelingExerciseAssessment.cy.ts | 93 - .../modeling/ModelingExerciseManagement.cy.ts | 155 - .../ModelingExerciseParticipation.cy.ts | 36 - .../ProgrammingExerciseAssessment.cy.ts | 116 - .../ProgrammingExerciseManagement.cy.ts | 64 - .../ProgrammingExerciseParticipation.cy.ts | 107 - ...rogrammingExerciseStaticCodeAnalysis.cy.ts | 49 - .../QuizExerciseAssessment.cy.ts | 69 - .../QuizExerciseDropLocation.cy.ts | 61 - .../QuizExerciseManagement.cy.ts | 77 - .../QuizExerciseParticipation.cy.ts | 102 - .../text/TextExerciseAssessment.cy.ts | 92 - .../text/TextExerciseManagement.cy.ts | 93 - .../text/TextExerciseParticipation.cy.ts | 52 - .../e2e/lecture/LectureManagement.cy.ts | 91 - src/test/cypress/fixtures/course/icon.png | Bin 61311 -> 0 bytes src/test/cypress/fixtures/exam/template.json | 18 - .../exercise/file-upload/submission.json | 8 - .../exercise/file-upload/template.json | 24 - .../exercise/modeling/submission.json | 9 - .../fixtures/exercise/modeling/template.json | 33 - .../programming/c/all_successful/exercise.txt | 9 - .../c/all_successful/submission.json | 11 - .../exercise/programming/c/template.json | 37 - .../java/all_successful/BubbleSort.txt | 23 - .../java/all_successful/Client.txt | 109 - .../java/all_successful/Context.txt | 34 - .../java/all_successful/MergeSort.txt | 53 - .../java/all_successful/Policy.txt | 25 - .../java/all_successful/SortStrategy.txt | 14 - .../java/all_successful/submission.json | 32 - .../java/assessment/submission.json | 14 - .../java/build_error/BubbleSort.txt | 1 - .../java/build_error/submission.json | 12 - .../java/partially_successful/submission.json | 20 - .../java/static_code_analysis/BubbleSort.txt | 28 - .../java/static_code_analysis/submission.json | 32 - .../exercise/programming/java/template.json | 37 - .../python/all_successful/context.txt | 6 - .../python/all_successful/policy.txt | 16 - .../python/all_successful/sort_strategy.txt | 8 - .../all_successful/sorting_algorithms.txt | 58 - .../python/all_successful/submission.json | 23 - .../exercise/programming/python/template.json | 40 - .../quiz/drag_and_drop/background.jpg | Bin 9492 -> 0 bytes .../exercise/quiz/drag_and_drop/question.txt | 2 - .../quiz/multiple_choice/question.txt | 14 - .../quiz/multiple_choice/submission.json | 11 - .../quiz/multiple_choice/template.json | 41 - .../exercise/quiz/short_answer/question.txt | 14 - .../quiz/short_answer/submission.json | 11 - .../exercise/quiz/short_answer/template.json | 168 - .../fixtures/exercise/quiz/template.json | 27 - .../fixtures/exercise/text/submission.json | 3 - .../fixtures/exercise/text/template.json | 29 - .../cypress/fixtures/lecture/template.json | 8 - .../cypress/fixtures/loremIpsum-short.txt | 1 - src/test/cypress/fixtures/loremIpsum.txt | 1 - src/test/cypress/fixtures/pdf-test-file.pdf | Bin 10855 -> 0 bytes src/test/cypress/init/ImportUsers.cy.ts | 29 - src/test/cypress/package-lock.json | 3222 ----------------- src/test/cypress/package.json | 37 - src/test/cypress/support/artemis.ts | 78 - src/test/cypress/support/commands.ts | 156 - src/test/cypress/support/constants.ts | 81 - src/test/cypress/support/index.ts | 73 - .../support/pageobjects/ArtemisPageobjects.ts | 124 - .../cypress/support/pageobjects/LoginPage.ts | 48 - .../support/pageobjects/NavigationBar.ts | 33 - .../AbstractExerciseAssessmentPage.ts | 63 - .../CourseAssessmentDashboardPage.ts | 26 - .../assessment/ExamAssessmentPage.ts | 16 - .../ExerciseAssessmentDashboardPage.ts | 31 - .../FileUploadExerciseAssessmentPage.ts | 23 - .../ModelingExerciseAssessmentEditor.ts | 58 - .../ProgrammingExerciseAssessmentPage.ts | 46 - .../assessment/StudentAssessmentPage.ts | 24 - .../assessment/TextExerciseAssessmentPage.ts | 52 - .../pageobjects/course/CourseCreationPage.ts | 243 -- .../course/CourseManagementExercisesPage.ts | 120 - .../course/CourseManagementPage.ts | 232 -- .../pageobjects/course/CourseMessages.ts | 220 -- .../pageobjects/course/CourseOverviewPage.ts | 48 - .../support/pageobjects/course/CoursesPage.ts | 9 - .../pageobjects/exam/ExamCreationPage.ts | 124 - .../pageobjects/exam/ExamDetailsPage.ts | 15 - .../exam/ExamExerciseGroupCreationPage.ts | 83 - .../exam/ExamExerciseGroupsPage.ts | 59 - .../pageobjects/exam/ExamManagementPage.ts | 136 - .../pageobjects/exam/ExamNavigationBar.ts | 27 - .../pageobjects/exam/ExamParticipation.ts | 144 - .../pageobjects/exam/ExamStartEndPage.ts | 54 - .../pageobjects/exam/ExamTestRunPage.ts | 95 - .../exam/StudentExamManagementPage.ts | 57 - .../exercises/AbstractExerciseFeedbackPage.ts | 35 - .../exercises/ExerciseResultPage.ts | 29 - .../file-upload/FileUploadEditorPage.ts | 38 - .../FileUploadExerciseCreationPage.ts | 59 - .../FileUploadExerciseFeedbackPage.ts | 12 - .../modeling/CreateModelingExercisePage.ts | 80 - .../exercises/modeling/ModelingEditor.ts | 50 - .../modeling/ModelingExerciseFeedbackPage.ts | 10 - .../programming/CodeAnalysisGradingPage.ts | 23 - .../exercises/programming/OnlineEditorPage.ts | 217 -- .../ProgrammingExerciseCreationPage.ts | 98 - .../ProgrammingExerciseFeedbackPage.ts | 26 - .../exercises/programming/ScaFeedbackModal.ts | 26 - .../exercises/quiz/DragAndDropQuiz.ts | 87 - .../exercises/quiz/MultipleChoiceQuiz.ts | 19 - .../quiz/QuizExerciseCreationPage.ts | 73 - .../exercises/quiz/ShortAnswerQuiz.ts | 18 - .../exercises/text/TextEditorPage.ts | 52 - .../text/TextExerciseCreationPage.ts | 61 - ...xtExerciseExampleSubmissionCreationPage.ts | 32 - .../TextExerciseExampleSubmissionsPage.ts | 8 - .../text/TextExerciseFeedbackPage.ts | 12 - .../lecture/LectureCreationPage.ts | 31 - .../lecture/LectureManagementPage.ts | 73 - .../support/requests/ArtemisRequests.ts | 16 - .../requests/CommunicationAPIRequests.ts | 246 -- .../requests/CourseManagementAPIRequests.ts | 181 - .../support/requests/ExamAPIRequests.ts | 168 - .../support/requests/ExerciseAPIRequests.ts | 616 ---- .../requests/UserManagementAPIRequest.ts | 37 - src/test/cypress/support/users.ts | 135 - src/test/cypress/support/utils.ts | 121 - src/test/cypress/tsconfig.json | 11 - .../{cypress => playwright}/certs/Dockerfile | 0 .../{cypress => playwright}/certs/README.md | 10 +- .../playwright/certs/artemis-nginx+4-key.pem | 52 +- src/test/playwright/certs/artemis-nginx+4.pem | 46 +- .../certs/generate-certs.sh | 0 src/test/playwright/certs/rootCA.pem | 50 +- .../ModelingExerciseManagement.spec.ts | 2 +- 196 files changed, 126 insertions(+), 15348 deletions(-) rename docker/artemis/config/{cypress-local.env => playwright-local.env} (91%) rename docker/artemis/config/{cypress-postgres.env => playwright-postgres.env} (95%) rename docker/artemis/config/{cypress.env => playwright.env} (95%) delete mode 100644 docker/cypress-E2E-tests-local.yml delete mode 100644 docker/cypress-E2E-tests-multi-node.yml delete mode 100644 docker/cypress-E2E-tests-mysql.yml delete mode 100644 docker/cypress-E2E-tests-postgres.yml delete mode 100644 docker/cypress.yml rename docker/nginx/{artemis-nginx-cypress.conf => artemis-nginx-playwright.conf} (100%) delete mode 100644 docker/sorry-cypress/.htpasswd delete mode 100644 docker/sorry-cypress/README.md delete mode 100644 docker/sorry-cypress/SETUP.md delete mode 100644 docker/sorry-cypress/minio-user-policy.json delete mode 100644 docker/sorry-cypress/nginx.conf delete mode 100644 docker/sorry-cypress/sorry-cypress.env delete mode 100644 docker/sorry-cypress/sorry-cypress.yml delete mode 100644 src/test/cypress/README.md delete mode 100644 src/test/cypress/certs/artemis-nginx+4-key.pem delete mode 100644 src/test/cypress/certs/artemis-nginx+4.pem delete mode 100644 src/test/cypress/certs/rootCA.pem delete mode 100644 src/test/cypress/currents.config.js delete mode 100644 src/test/cypress/cypress.config.ts delete mode 100644 src/test/cypress/cypress.env.json delete mode 100644 src/test/cypress/e2e/Login.cy.ts delete mode 100644 src/test/cypress/e2e/Logout.cy.ts delete mode 100644 src/test/cypress/e2e/SystemHealth.cy.ts delete mode 100644 src/test/cypress/e2e/course/CourseExercise.cy.ts delete mode 100644 src/test/cypress/e2e/course/CourseManagement.cy.ts delete mode 100644 src/test/cypress/e2e/course/CourseMessages.cy.ts delete mode 100644 src/test/cypress/e2e/exam/ExamAssessment.cy.ts delete mode 100644 src/test/cypress/e2e/exam/ExamCreationDeletion.cy.ts delete mode 100644 src/test/cypress/e2e/exam/ExamDateVerification.cy.ts delete mode 100644 src/test/cypress/e2e/exam/ExamManagement.cy.ts delete mode 100644 src/test/cypress/e2e/exam/ExamParticipation.cy.ts delete mode 100644 src/test/cypress/e2e/exam/ExamTestRun.cy.ts delete mode 100644 src/test/cypress/e2e/exam/test-exam/TestExamCreationDeletion.cy.ts delete mode 100644 src/test/cypress/e2e/exam/test-exam/TestExamManagement.cy.ts delete mode 100644 src/test/cypress/e2e/exam/test-exam/TestExamParticipation.cy.ts delete mode 100644 src/test/cypress/e2e/exam/test-exam/TestExamStudentExams.cy.ts delete mode 100644 src/test/cypress/e2e/exam/test-exam/TestExamTestRun.cy.ts delete mode 100644 src/test/cypress/e2e/exercises/ExerciseImport.cy.ts delete mode 100644 src/test/cypress/e2e/exercises/file-upload/FileUploadExerciseAssessment.cy.ts delete mode 100644 src/test/cypress/e2e/exercises/file-upload/FileUploadExerciseManagement.cy.ts delete mode 100644 src/test/cypress/e2e/exercises/file-upload/FileUploadExerciseParticipation.cy.ts delete mode 100644 src/test/cypress/e2e/exercises/modeling/ModelingExerciseAssessment.cy.ts delete mode 100644 src/test/cypress/e2e/exercises/modeling/ModelingExerciseManagement.cy.ts delete mode 100644 src/test/cypress/e2e/exercises/modeling/ModelingExerciseParticipation.cy.ts delete mode 100644 src/test/cypress/e2e/exercises/programming/ProgrammingExerciseAssessment.cy.ts delete mode 100644 src/test/cypress/e2e/exercises/programming/ProgrammingExerciseManagement.cy.ts delete mode 100644 src/test/cypress/e2e/exercises/programming/ProgrammingExerciseParticipation.cy.ts delete mode 100644 src/test/cypress/e2e/exercises/programming/ProgrammingExerciseStaticCodeAnalysis.cy.ts delete mode 100644 src/test/cypress/e2e/exercises/quiz-exercise/QuizExerciseAssessment.cy.ts delete mode 100644 src/test/cypress/e2e/exercises/quiz-exercise/QuizExerciseDropLocation.cy.ts delete mode 100644 src/test/cypress/e2e/exercises/quiz-exercise/QuizExerciseManagement.cy.ts delete mode 100644 src/test/cypress/e2e/exercises/quiz-exercise/QuizExerciseParticipation.cy.ts delete mode 100644 src/test/cypress/e2e/exercises/text/TextExerciseAssessment.cy.ts delete mode 100644 src/test/cypress/e2e/exercises/text/TextExerciseManagement.cy.ts delete mode 100644 src/test/cypress/e2e/exercises/text/TextExerciseParticipation.cy.ts delete mode 100644 src/test/cypress/e2e/lecture/LectureManagement.cy.ts delete mode 100644 src/test/cypress/fixtures/course/icon.png delete mode 100644 src/test/cypress/fixtures/exam/template.json delete mode 100644 src/test/cypress/fixtures/exercise/file-upload/submission.json delete mode 100644 src/test/cypress/fixtures/exercise/file-upload/template.json delete mode 100644 src/test/cypress/fixtures/exercise/modeling/submission.json delete mode 100644 src/test/cypress/fixtures/exercise/modeling/template.json delete mode 100644 src/test/cypress/fixtures/exercise/programming/c/all_successful/exercise.txt delete mode 100644 src/test/cypress/fixtures/exercise/programming/c/all_successful/submission.json delete mode 100644 src/test/cypress/fixtures/exercise/programming/c/template.json delete mode 100644 src/test/cypress/fixtures/exercise/programming/java/all_successful/BubbleSort.txt delete mode 100644 src/test/cypress/fixtures/exercise/programming/java/all_successful/Client.txt delete mode 100644 src/test/cypress/fixtures/exercise/programming/java/all_successful/Context.txt delete mode 100644 src/test/cypress/fixtures/exercise/programming/java/all_successful/MergeSort.txt delete mode 100644 src/test/cypress/fixtures/exercise/programming/java/all_successful/Policy.txt delete mode 100644 src/test/cypress/fixtures/exercise/programming/java/all_successful/SortStrategy.txt delete mode 100644 src/test/cypress/fixtures/exercise/programming/java/all_successful/submission.json delete mode 100644 src/test/cypress/fixtures/exercise/programming/java/assessment/submission.json delete mode 100644 src/test/cypress/fixtures/exercise/programming/java/build_error/BubbleSort.txt delete mode 100644 src/test/cypress/fixtures/exercise/programming/java/build_error/submission.json delete mode 100644 src/test/cypress/fixtures/exercise/programming/java/partially_successful/submission.json delete mode 100644 src/test/cypress/fixtures/exercise/programming/java/static_code_analysis/BubbleSort.txt delete mode 100644 src/test/cypress/fixtures/exercise/programming/java/static_code_analysis/submission.json delete mode 100644 src/test/cypress/fixtures/exercise/programming/java/template.json delete mode 100644 src/test/cypress/fixtures/exercise/programming/python/all_successful/context.txt delete mode 100644 src/test/cypress/fixtures/exercise/programming/python/all_successful/policy.txt delete mode 100644 src/test/cypress/fixtures/exercise/programming/python/all_successful/sort_strategy.txt delete mode 100644 src/test/cypress/fixtures/exercise/programming/python/all_successful/sorting_algorithms.txt delete mode 100644 src/test/cypress/fixtures/exercise/programming/python/all_successful/submission.json delete mode 100644 src/test/cypress/fixtures/exercise/programming/python/template.json delete mode 100644 src/test/cypress/fixtures/exercise/quiz/drag_and_drop/background.jpg delete mode 100644 src/test/cypress/fixtures/exercise/quiz/drag_and_drop/question.txt delete mode 100644 src/test/cypress/fixtures/exercise/quiz/multiple_choice/question.txt delete mode 100644 src/test/cypress/fixtures/exercise/quiz/multiple_choice/submission.json delete mode 100644 src/test/cypress/fixtures/exercise/quiz/multiple_choice/template.json delete mode 100644 src/test/cypress/fixtures/exercise/quiz/short_answer/question.txt delete mode 100644 src/test/cypress/fixtures/exercise/quiz/short_answer/submission.json delete mode 100644 src/test/cypress/fixtures/exercise/quiz/short_answer/template.json delete mode 100644 src/test/cypress/fixtures/exercise/quiz/template.json delete mode 100644 src/test/cypress/fixtures/exercise/text/submission.json delete mode 100644 src/test/cypress/fixtures/exercise/text/template.json delete mode 100644 src/test/cypress/fixtures/lecture/template.json delete mode 100644 src/test/cypress/fixtures/loremIpsum-short.txt delete mode 100644 src/test/cypress/fixtures/loremIpsum.txt delete mode 100644 src/test/cypress/fixtures/pdf-test-file.pdf delete mode 100644 src/test/cypress/init/ImportUsers.cy.ts delete mode 100644 src/test/cypress/package-lock.json delete mode 100644 src/test/cypress/package.json delete mode 100644 src/test/cypress/support/artemis.ts delete mode 100644 src/test/cypress/support/commands.ts delete mode 100644 src/test/cypress/support/constants.ts delete mode 100644 src/test/cypress/support/index.ts delete mode 100644 src/test/cypress/support/pageobjects/ArtemisPageobjects.ts delete mode 100644 src/test/cypress/support/pageobjects/LoginPage.ts delete mode 100644 src/test/cypress/support/pageobjects/NavigationBar.ts delete mode 100644 src/test/cypress/support/pageobjects/assessment/AbstractExerciseAssessmentPage.ts delete mode 100644 src/test/cypress/support/pageobjects/assessment/CourseAssessmentDashboardPage.ts delete mode 100644 src/test/cypress/support/pageobjects/assessment/ExamAssessmentPage.ts delete mode 100644 src/test/cypress/support/pageobjects/assessment/ExerciseAssessmentDashboardPage.ts delete mode 100644 src/test/cypress/support/pageobjects/assessment/FileUploadExerciseAssessmentPage.ts delete mode 100644 src/test/cypress/support/pageobjects/assessment/ModelingExerciseAssessmentEditor.ts delete mode 100644 src/test/cypress/support/pageobjects/assessment/ProgrammingExerciseAssessmentPage.ts delete mode 100644 src/test/cypress/support/pageobjects/assessment/StudentAssessmentPage.ts delete mode 100644 src/test/cypress/support/pageobjects/assessment/TextExerciseAssessmentPage.ts delete mode 100644 src/test/cypress/support/pageobjects/course/CourseCreationPage.ts delete mode 100644 src/test/cypress/support/pageobjects/course/CourseManagementExercisesPage.ts delete mode 100644 src/test/cypress/support/pageobjects/course/CourseManagementPage.ts delete mode 100644 src/test/cypress/support/pageobjects/course/CourseMessages.ts delete mode 100644 src/test/cypress/support/pageobjects/course/CourseOverviewPage.ts delete mode 100644 src/test/cypress/support/pageobjects/course/CoursesPage.ts delete mode 100644 src/test/cypress/support/pageobjects/exam/ExamCreationPage.ts delete mode 100644 src/test/cypress/support/pageobjects/exam/ExamDetailsPage.ts delete mode 100644 src/test/cypress/support/pageobjects/exam/ExamExerciseGroupCreationPage.ts delete mode 100644 src/test/cypress/support/pageobjects/exam/ExamExerciseGroupsPage.ts delete mode 100644 src/test/cypress/support/pageobjects/exam/ExamManagementPage.ts delete mode 100644 src/test/cypress/support/pageobjects/exam/ExamNavigationBar.ts delete mode 100644 src/test/cypress/support/pageobjects/exam/ExamParticipation.ts delete mode 100644 src/test/cypress/support/pageobjects/exam/ExamStartEndPage.ts delete mode 100644 src/test/cypress/support/pageobjects/exam/ExamTestRunPage.ts delete mode 100644 src/test/cypress/support/pageobjects/exam/StudentExamManagementPage.ts delete mode 100644 src/test/cypress/support/pageobjects/exercises/AbstractExerciseFeedbackPage.ts delete mode 100644 src/test/cypress/support/pageobjects/exercises/ExerciseResultPage.ts delete mode 100644 src/test/cypress/support/pageobjects/exercises/file-upload/FileUploadEditorPage.ts delete mode 100644 src/test/cypress/support/pageobjects/exercises/file-upload/FileUploadExerciseCreationPage.ts delete mode 100644 src/test/cypress/support/pageobjects/exercises/file-upload/FileUploadExerciseFeedbackPage.ts delete mode 100644 src/test/cypress/support/pageobjects/exercises/modeling/CreateModelingExercisePage.ts delete mode 100644 src/test/cypress/support/pageobjects/exercises/modeling/ModelingEditor.ts delete mode 100644 src/test/cypress/support/pageobjects/exercises/modeling/ModelingExerciseFeedbackPage.ts delete mode 100644 src/test/cypress/support/pageobjects/exercises/programming/CodeAnalysisGradingPage.ts delete mode 100644 src/test/cypress/support/pageobjects/exercises/programming/OnlineEditorPage.ts delete mode 100644 src/test/cypress/support/pageobjects/exercises/programming/ProgrammingExerciseCreationPage.ts delete mode 100644 src/test/cypress/support/pageobjects/exercises/programming/ProgrammingExerciseFeedbackPage.ts delete mode 100644 src/test/cypress/support/pageobjects/exercises/programming/ScaFeedbackModal.ts delete mode 100644 src/test/cypress/support/pageobjects/exercises/quiz/DragAndDropQuiz.ts delete mode 100644 src/test/cypress/support/pageobjects/exercises/quiz/MultipleChoiceQuiz.ts delete mode 100644 src/test/cypress/support/pageobjects/exercises/quiz/QuizExerciseCreationPage.ts delete mode 100644 src/test/cypress/support/pageobjects/exercises/quiz/ShortAnswerQuiz.ts delete mode 100644 src/test/cypress/support/pageobjects/exercises/text/TextEditorPage.ts delete mode 100644 src/test/cypress/support/pageobjects/exercises/text/TextExerciseCreationPage.ts delete mode 100644 src/test/cypress/support/pageobjects/exercises/text/TextExerciseExampleSubmissionCreationPage.ts delete mode 100644 src/test/cypress/support/pageobjects/exercises/text/TextExerciseExampleSubmissionsPage.ts delete mode 100644 src/test/cypress/support/pageobjects/exercises/text/TextExerciseFeedbackPage.ts delete mode 100644 src/test/cypress/support/pageobjects/lecture/LectureCreationPage.ts delete mode 100644 src/test/cypress/support/pageobjects/lecture/LectureManagementPage.ts delete mode 100644 src/test/cypress/support/requests/ArtemisRequests.ts delete mode 100644 src/test/cypress/support/requests/CommunicationAPIRequests.ts delete mode 100644 src/test/cypress/support/requests/CourseManagementAPIRequests.ts delete mode 100644 src/test/cypress/support/requests/ExamAPIRequests.ts delete mode 100644 src/test/cypress/support/requests/ExerciseAPIRequests.ts delete mode 100644 src/test/cypress/support/requests/UserManagementAPIRequest.ts delete mode 100644 src/test/cypress/support/users.ts delete mode 100644 src/test/cypress/support/utils.ts delete mode 100644 src/test/cypress/tsconfig.json rename src/test/{cypress => playwright}/certs/Dockerfile (100%) rename src/test/{cypress => playwright}/certs/README.md (74%) rename src/test/{cypress => playwright}/certs/generate-certs.sh (100%) diff --git a/.ci/E2E-tests/cleanup.sh b/.ci/E2E-tests/cleanup.sh index 49750033d2f1..59956fa455e5 100755 --- a/.ci/E2E-tests/cleanup.sh +++ b/.ci/E2E-tests/cleanup.sh @@ -12,12 +12,8 @@ docker container stop $(docker ps -a -q) || true docker container rm $(docker ps -a -q) || true docker volume rm $(docker volume ls -q) || true -docker compose -f ./docker/cypress-E2E-tests-mysql.yml down -v -docker compose -f ./docker/cypress-E2E-tests-postgres.yml down -v docker compose -f ./docker/playwright-E2E-tests-mysql.yml down -v -docker compose -f ./docker/cypress-E2E-tests-local.yml down -v docker compose -f ./docker/playwright-E2E-tests-multi-node.yml down -v -docker compose -f ./docker/cypress-E2E-tests-multi-node.yml down -v # show all running docker containers and volumes after the cleanup to detect issues echo "SHOW RUNNING Docker containers and volumes:" diff --git a/.ci/E2E-tests/execute.sh b/.ci/E2E-tests/execute.sh index 18fbd4ebfa7d..e98ca13b5c28 100755 --- a/.ci/E2E-tests/execute.sh +++ b/.ci/E2E-tests/execute.sh @@ -6,11 +6,8 @@ DB="mysql" echo "CONFIGURATION:" echo "$CONFIGURATION" -echo "Test framework:" -echo "$TEST_FRAMEWORK" -if [ "$TEST_FRAMEWORK" = "playwright" ]; then - if [ "$CONFIGURATION" = "mysql" ]; then +if [ "$CONFIGURATION" = "mysql" ]; then COMPOSE_FILE="playwright-E2E-tests-mysql.yml" elif [ "$CONFIGURATION" = "postgres" ]; then COMPOSE_FILE="playwright-E2E-tests-postgres.yml" @@ -22,21 +19,6 @@ if [ "$TEST_FRAMEWORK" = "playwright" ]; then else echo "Invalid configuration. Please choose among mysql, postgres, mysql-localci or multi-node." exit 1 - fi -else - if [ "$CONFIGURATION" = "mysql" ]; then - COMPOSE_FILE="cypress-E2E-tests-mysql.yml" - elif [ "$CONFIGURATION" = "postgres" ]; then - COMPOSE_FILE="cypress-E2E-tests-postgres.yml" - DB="postgres" - elif [ "$CONFIGURATION" = "local" ]; then - COMPOSE_FILE="cypress-E2E-tests-local.yml" - elif [ "$CONFIGURATION" = "multi-node" ]; then - COMPOSE_FILE="cypress-E2E-tests-multi-node.yml" - else - echo "Invalid configuration. Please choose among mysql, postgres, local or multi-node." - exit 1 - fi fi echo "Compose file:" @@ -51,8 +33,7 @@ export HOST_HOSTNAME=$(hostname) cd docker #just pull everything else than artemis-app as we build it later either way -if [ "$TEST_FRAMEWORK" = "playwright" ]; then - if [ "$CONFIGURATION" = "multi-node" ]; then +if [ "$CONFIGURATION" = "multi-node" ]; then echo "Building for playwright (multi-node)" docker compose -f $COMPOSE_FILE pull artemis-playwright $DB nginx docker compose -f $COMPOSE_FILE build --build-arg WAR_FILE_STAGE=external_builder --no-cache --pull artemis-app-node-1 artemis-app-node-2 artemis-app-node-3 @@ -62,20 +43,8 @@ if [ "$TEST_FRAMEWORK" = "playwright" ]; then docker compose -f $COMPOSE_FILE pull artemis-playwright $DB nginx docker compose -f $COMPOSE_FILE build --build-arg WAR_FILE_STAGE=external_builder --no-cache --pull artemis-app docker compose -f $COMPOSE_FILE up --exit-code-from artemis-playwright - fi -else - if [ "$CONFIGURATION" = "multi-node" ]; then - echo "Building for cypress (multi-node)" - docker compose -f $COMPOSE_FILE pull artemis-cypress $DB nginx - docker compose -f $COMPOSE_FILE build --build-arg WAR_FILE_STAGE=external_builder --no-cache --pull artemis-app-node-1 artemis-app-node-2 artemis-app-node-3 - docker compose -f $COMPOSE_FILE up --exit-code-from artemis-cypress - else - echo "Building for cypress" - docker compose -f $COMPOSE_FILE pull artemis-cypress $DB nginx - docker compose -f $COMPOSE_FILE build --build-arg WAR_FILE_STAGE=external_builder --no-cache --pull artemis-app - docker compose -f $COMPOSE_FILE up --exit-code-from artemis-cypress - fi fi + exitCode=$? cd .. echo "Container exit code: $exitCode" diff --git a/.github/labeler.yml b/.github/labeler.yml index 5dd34c477214..d9295deb1372 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -10,9 +10,9 @@ tests: - changed-files: - any-glob-to-any-file: src/test/**/* -cypress: +playwright: - changed-files: - - any-glob-to-any-file: src/test/cypress/**/* + - any-glob-to-any-file: src/test/playwright/**/* database: - changed-files: diff --git a/.gitignore b/.gitignore index 13cfd9a24518..8f71a8ae13d5 100644 --- a/.gitignore +++ b/.gitignore @@ -188,13 +188,6 @@ data-exports/ /docker/.docker-data/artemis-postgres-data/* !/docker/.docker-data/artemis-postgres-data/.gitkeep -###################### -# Cypress -###################### -/src/test/cypress/screenshots/ -/src/test/cypress/videos/ -/src/test/cypress/build - ###################### # Playwright ###################### diff --git a/docker/artemis-migration-check-postgres.yml b/docker/artemis-migration-check-postgres.yml index 5f7cf661c39f..1ac60ab3ef45 100644 --- a/docker/artemis-migration-check-postgres.yml +++ b/docker/artemis-migration-check-postgres.yml @@ -9,8 +9,8 @@ services: service: artemis-app env_file: - ./artemis/config/postgres.env - - ./artemis/config/cypress.env - - ./artemis/config/cypress-postgres.env + - ./artemis/config/playwright.env + - ./artemis/config/playwright-postgres.env - ./artemis/config/migration-check.env depends_on: postgresql: diff --git a/docker/artemis/config/cypress-local.env b/docker/artemis/config/playwright-local.env similarity index 91% rename from docker/artemis/config/cypress-local.env rename to docker/artemis/config/playwright-local.env index 5ca5931297ad..6b7805deacca 100644 --- a/docker/artemis/config/cypress-local.env +++ b/docker/artemis/config/playwright-local.env @@ -1,5 +1,5 @@ # ---------------------------------------------------------------------------------------------------------------------- -# Artemis configuration overrides for the Cypress E2E Postgres setups +# Artemis configuration overrides for the Playwright E2E Postgres setups # ---------------------------------------------------------------------------------------------------------------------- SPRING_PROFILES_ACTIVE="artemis,scheduling,localvc,localci,buildagent,core,prod,docker" diff --git a/docker/artemis/config/cypress-postgres.env b/docker/artemis/config/playwright-postgres.env similarity index 95% rename from docker/artemis/config/cypress-postgres.env rename to docker/artemis/config/playwright-postgres.env index ae155aca2873..9cfcc9ade6a6 100644 --- a/docker/artemis/config/cypress-postgres.env +++ b/docker/artemis/config/playwright-postgres.env @@ -1,5 +1,5 @@ # ---------------------------------------------------------------------------------------------------------------------- -# Artemis configuration overrides for the Cypress E2E Postgres setups +# Artemis configuration overrides for the Playwright E2E Postgres setups # ---------------------------------------------------------------------------------------------------------------------- SPRING_PROFILES_ACTIVE="artemis,scheduling,jenkins,gitlab,core,prod,docker" diff --git a/docker/artemis/config/cypress.env b/docker/artemis/config/playwright.env similarity index 95% rename from docker/artemis/config/cypress.env rename to docker/artemis/config/playwright.env index c056a8d9004c..c57d79d581c7 100644 --- a/docker/artemis/config/cypress.env +++ b/docker/artemis/config/playwright.env @@ -1,5 +1,5 @@ # ---------------------------------------------------------------------------------------------------------------------- -# Common Artemis configurations for the Cypress E2E MySQL and Postgres setups +# Common Artemis configurations for the Playwright E2E MySQL and Postgres setups # ---------------------------------------------------------------------------------------------------------------------- SPRING_DATASOURCE_PASSWORD="" diff --git a/docker/cypress-E2E-tests-local.yml b/docker/cypress-E2E-tests-local.yml deleted file mode 100644 index cf69e47df760..000000000000 --- a/docker/cypress-E2E-tests-local.yml +++ /dev/null @@ -1,62 +0,0 @@ -# ---------------------------------------------------------------------------------------------------------------------- -# Cypress Setup MySQL -# ---------------------------------------------------------------------------------------------------------------------- - -services: - mysql: - extends: - file: ./mysql.yml - service: mysql - - artemis-app: - extends: - file: ./artemis.yml - service: artemis-app - user: 0:0 - depends_on: - mysql: - condition: service_healthy - env_file: - - ./artemis/config/cypress.env - - ./artemis/config/cypress-local.env - volumes: - - /var/run/docker.sock:/var/run/docker.sock - - nginx: - extends: - file: ./nginx.yml - service: nginx - # the artemis-app service needs to be started, otherwise there are problems with name resolution in docker - depends_on: - artemis-app: - condition: service_started - volumes: - - ./nginx/artemis-nginx-cypress.conf:/etc/nginx/conf.d/artemis-nginx-cypress.conf:ro - ports: - - "80:80" - - "443:443" - # see comments in artemis/config/cypress.env why this port is necessary - - "54321:54321" - - artemis-cypress: - extends: - file: ./cypress.yml - service: artemis-cypress - depends_on: - artemis-app: - condition: service_healthy - environment: - CYPRESS_DB_TYPE: "Local" - SORRY_CYPRESS_PROJECT_ID: "artemis-local" - CYPRESS_createUsers: "true" - command: sh -c "cd /app/artemis/src/test/cypress && chmod 777 /root && npm ci && npm run cypress:setup && (npm run cypress:record:local & sleep 60 && npm run cypress:record:local & wait)" - -networks: - artemis: - driver: "bridge" - name: artemis -volumes: - artemis-mysql-data: - name: artemis-mysql-data - artemis-data: - name: artemis-data diff --git a/docker/cypress-E2E-tests-multi-node.yml b/docker/cypress-E2E-tests-multi-node.yml deleted file mode 100644 index 5fb326f75f60..000000000000 --- a/docker/cypress-E2E-tests-multi-node.yml +++ /dev/null @@ -1,134 +0,0 @@ -# ---------------------------------------------------------------------------------------------------------------------- -# Cypress setup for multi-node -# ---------------------------------------------------------------------------------------------------------------------- - -services: - artemis-app-node-1: - &artemis-app-base - container_name: artemis-app-node-1 - extends: - file: ./artemis.yml - service: artemis-app - image: ghcr.io/ls1intum/artemis:${ARTEMIS_DOCKER_TAG:-latest} - depends_on: - &depends-on-base - mysql: - condition: service_healthy - jhipster-registry: - condition: service_healthy - activemq-broker: - condition: service_healthy - pull_policy: always - restart: always - group_add: - - ${DOCKER_GROUP_ID:-0} - env_file: - - ./artemis/config/prod-multinode.env - - ./artemis/config/node1.env - - ./artemis/config/cypress.env - volumes: - - /var/run/docker.sock:/var/run/docker.sock - - artemis-app-node-2: - <<: *artemis-app-base - container_name: artemis-app-node-2 - depends_on: - <<: *depends-on-base - artemis-app-node-1: - condition: service_healthy - env_file: - - ./artemis/config/prod-multinode.env - - ./artemis/config/node2.env - - ./artemis/config/cypress.env - - artemis-app-node-3: - <<: *artemis-app-base - container_name: artemis-app-node-3 - depends_on: - <<: *depends-on-base - artemis-app-node-1: - condition: service_healthy - env_file: - - ./artemis/config/prod-multinode.env - - ./artemis/config/node3.env - - ./artemis/config/cypress.env - - jhipster-registry: - extends: - file: ./broker-registry.yml - service: jhipster-registry - networks: - - artemis - - activemq-broker: - extends: - file: ./broker-registry.yml - service: activemq-broker - networks: - - artemis - - mysql: - extends: - file: ./mysql.yml - service: mysql - restart: always - - nginx: - extends: - file: ./nginx.yml - service: nginx - depends_on: - artemis-app-node-1: - condition: service_started - artemis-app-node-2: - condition: service_started - artemis-app-node-3: - condition: service_started - restart: always - ports: - - '80:80' - - '443:443' - # see comments in artemis/config/cypress.env why this port is necessary - - '54321:54321' - volumes: - - ./nginx/artemis-upstream-multi-node.conf:/etc/nginx/includes/artemis-upstream.conf:ro - - ./nginx/artemis-nginx-cypress.conf:/etc/nginx/conf.d/artemis-nginx-cypress.conf:ro - - type: bind - source: ${NGINX_PROXY_SSL_CERTIFICATE_PATH:-../src/test/cypress/certs/artemis-nginx+4.pem} - target: "/certs/fullchain.pem" - - type: bind - source: ${NGINX_PROXY_SSL_CERTIFICATE_KEY_PATH:-../src/test/cypress/certs/artemis-nginx+4-key.pem} - target: "/certs/priv_key.pem" - - - artemis-cypress: - extends: - file: ./cypress.yml - service: artemis-cypress - depends_on: - nginx: - condition: service_healthy - environment: - CYPRESS_DB_TYPE: "Local" - SORRY_CYPRESS_PROJECT_ID: "artemis-local" - CYPRESS_createUsers: "true" - command: > - sh -c ' - cd /app/artemis/src/test/cypress && - chmod 777 /root && - npm ci && - npm run cypress:setup && - (npm run cypress:record:local & sleep 60 && npm run cypress:record:local & wait) - ' - -networks: - artemis: - driver: "bridge" - name: artemis - -volumes: - artemis-mysql-data: - name: artemis-mysql-data - artemis-data: - name: artemis-data - diff --git a/docker/cypress-E2E-tests-mysql.yml b/docker/cypress-E2E-tests-mysql.yml deleted file mode 100644 index a14c4c163ce7..000000000000 --- a/docker/cypress-E2E-tests-mysql.yml +++ /dev/null @@ -1,60 +0,0 @@ -# ---------------------------------------------------------------------------------------------------------------------- -# Cypress Setup MySQL -# ---------------------------------------------------------------------------------------------------------------------- - -services: - mysql: - extends: - file: ./mysql.yml - service: mysql - - artemis-app: - extends: - file: ./artemis.yml - service: artemis-app - depends_on: - mysql: - condition: service_healthy - env_file: - - ./artemis/config/cypress.env - - ./artemis/config/cypress-mysql.env - - nginx: - extends: - file: ./nginx.yml - service: nginx - # the artemis-app service needs to be started, otherwise there are problems with name resolution in docker - depends_on: - artemis-app: - condition: service_started - volumes: - - ./nginx/artemis-nginx-cypress.conf:/etc/nginx/conf.d/artemis-nginx-cypress.conf:ro - ports: - - "80:80" - - "443:443" - # see comments in artemis/config/cypress.env why this port is necessary - - "54321:54321" - - artemis-cypress: - extends: - file: ./cypress.yml - service: artemis-cypress - depends_on: - artemis-app: - condition: service_healthy - environment: - CYPRESS_DB_TYPE: "MySQL" - SORRY_CYPRESS_PROJECT_ID: "artemis-mysql" - command: sh -c "cd /app/artemis/src/test/cypress && chmod 777 /root && npm ci && npm run cypress:setup && (npm run cypress:record:mysql & sleep 60 && npm run cypress:record:mysql & wait)" -# Old run method using plain cypress kept here as backup -# command: sh -c "cd /app/artemis/src/test/cypress && chmod 777 /root && npm ci && npm run cypress:run" - -networks: - artemis: - driver: "bridge" - name: artemis -volumes: - artemis-mysql-data: - name: artemis-mysql-data - artemis-data: - name: artemis-data diff --git a/docker/cypress-E2E-tests-postgres.yml b/docker/cypress-E2E-tests-postgres.yml deleted file mode 100644 index 41fe8edf5faa..000000000000 --- a/docker/cypress-E2E-tests-postgres.yml +++ /dev/null @@ -1,61 +0,0 @@ -# ---------------------------------------------------------------------------------------------------------------------- -# Cypress Setup Postgres -# ---------------------------------------------------------------------------------------------------------------------- - -services: - postgres: - extends: - file: ./postgres.yml - service: postgres - - artemis-app: - extends: - file: ./artemis.yml - service: artemis-app - depends_on: - postgres: - condition: service_healthy - env_file: - - ./artemis/config/postgres.env - - ./artemis/config/cypress.env - - ./artemis/config/cypress-postgres.env - - nginx: - extends: - file: ./nginx.yml - service: nginx - # the artemis-app service needs to be started, otherwise there are problems with name resolution in docker - depends_on: - artemis-app: - condition: service_started - volumes: - - ./nginx/artemis-nginx-cypress.conf:/etc/nginx/conf.d/artemis-nginx-cypress.conf:ro - ports: - - "80:80" - - "443:443" - # see comments in artemis/config/cypress.env why this port is necessary - - "54321:54321" - - artemis-cypress: - extends: - file: ./cypress.yml - service: artemis-cypress - depends_on: - artemis-app: - condition: service_healthy - environment: - CYPRESS_DB_TYPE: "Postgres" - SORRY_CYPRESS_PROJECT_ID: "artemis-postgres" - command: sh -c "cd /app/artemis/src/test/cypress && chmod 777 /root && npm ci && npm run cypress:setup && (npm run cypress:record:postgres & sleep 60 && npm run cypress:record:postgres & wait)" -# Old run method using plain cypress kept here as backup -# command: sh -c "cd /app/artemis/src/test/cypress && chmod 777 /root && npm ci && npm run cypress:run" - -networks: - artemis: - driver: "bridge" - name: artemis -volumes: - artemis-postgres-data: - name: artemis-postgres-data - artemis-data: - name: artemis-data diff --git a/docker/cypress.yml b/docker/cypress.yml deleted file mode 100644 index c4dd1aa58bbb..000000000000 --- a/docker/cypress.yml +++ /dev/null @@ -1,41 +0,0 @@ -# ---------------------------------------------------------------------------------------------------------------------- -# Cypress base service -# ---------------------------------------------------------------------------------------------------------------------- - -services: - artemis-cypress: - # Cypress image with node and chrome browser installed (Cypress installation needs to be done separately because we require additional dependencies) - image: docker.io/cypress/browsers:node-20.6.1-chrome-116.0.5845.187-1-ff-117.0-edge-116.0.1938.76-1 - pull_policy: if_not_present - environment: - CYPRESS_baseUrl: "https://artemis-nginx" - CYPRESS_video: "${bamboo_cypress_video_enabled}" - CYPRESS_adminUsername: "${bamboo_artemis_admin_username}" - CYPRESS_adminPassword: "${bamboo_artemis_admin_password}" - CYPRESS_username: "${bamboo_cypress_username_template}" - CYPRESS_password: "${bamboo_cypress_password_template}" - CYPRESS_allowGroupCustomization: "true" - CYPRESS_studentGroupName: "artemis-e2etest-students" - CYPRESS_tutorGroupName: "artemis-e2etest-tutors" - CYPRESS_editorGroupName: "artemis-e2etest-editors" - CYPRESS_instructorGroupName: "artemis-e2etest-instructors" - CYPRESS_createUsers: "${bamboo_cypress_create_users}" - # use alternative cypress version to avoid blocking sorry cypress (see https://currents.dev/readme/integration-with-cypress/alternative-cypress-binaries) - CYPRESS_DOWNLOAD_MIRROR: "https://cy-cdn.currents.dev" - SORRY_CYPRESS_KEY: "${bamboo_sorry_cypress_record_secret}" - SORRY_CYPRESS_URL: "${bamboo_sorry_cypress_url}" - SORRY_CYPRESS_BUILD_ID: "${bamboo_buildNumber}" - SORRY_CYPRESS_BRANCH_NAME: "${bamboo_planRepository_branchName}" - SORRY_CYPRESS_RERUN_COUNT: "${bamboo_RerunBuildTriggerReason_noOfRetries}" - SORRY_CYPRESS_PROJECT_ID: "artemis-mysql" - NO_COLOR: "1" - command: sh -c "cd /app/artemis/src/test/cypress && chmod 777 /root && npm ci && npm run cypress:run" - volumes: - - ..:/app/artemis - networks: - - artemis - -networks: - artemis: - driver: "bridge" - name: artemis diff --git a/docker/nginx.yml b/docker/nginx.yml index b7fbc47288cd..6e111a256a91 100644 --- a/docker/nginx.yml +++ b/docker/nginx.yml @@ -18,8 +18,6 @@ services: - ./nginx/dhparam.pem:/etc/nginx/dhparam.pem:ro - ./nginx/nginx_503.html:/usr/share/nginx/html/503.html:ro - ./nginx/70-artemis-setup.sh:/docker-entrypoint.d/70-artemis-setup.sh - - ../src/test/cypress/certs/artemis-nginx+4.pem:/certs/fullchain.pem:ro - - ../src/test/cypress/certs/artemis-nginx+4-key.pem:/certs/priv_key.pem:ro - ../src/test/playwright/certs/artemis-nginx+4.pem:/certs/fullchain.pem:ro - ../src/test/playwright/certs/artemis-nginx+4-key.pem:/certs/priv_key.pem:ro # ulimits adopted from the nginx_security_limits.conf in the Artemis ansible collection diff --git a/docker/nginx/artemis-nginx-cypress.conf b/docker/nginx/artemis-nginx-playwright.conf similarity index 100% rename from docker/nginx/artemis-nginx-cypress.conf rename to docker/nginx/artemis-nginx-playwright.conf diff --git a/docker/playwright-E2E-tests-multi-node.yml b/docker/playwright-E2E-tests-multi-node.yml index 576a695d37ca..bd8a0f52ff05 100644 --- a/docker/playwright-E2E-tests-multi-node.yml +++ b/docker/playwright-E2E-tests-multi-node.yml @@ -25,7 +25,7 @@ services: env_file: - ./artemis/config/prod-multinode.env - ./artemis/config/node1.env - - ./artemis/config/cypress.env + - ./artemis/config/playwright.env artemis-app-node-2: <<: *artemis-app-base @@ -37,7 +37,7 @@ services: env_file: - ./artemis/config/prod-multinode.env - ./artemis/config/node2.env - - ./artemis/config/cypress.env + - ./artemis/config/playwright.env artemis-app-node-3: <<: *artemis-app-base @@ -49,7 +49,7 @@ services: env_file: - ./artemis/config/prod-multinode.env - ./artemis/config/node3.env - - ./artemis/config/cypress.env + - ./artemis/config/playwright.env jhipster-registry: extends: @@ -86,17 +86,17 @@ services: ports: - '80:80' - '443:443' - # see comments in artemis/config/cypress.env why this port is necessary + # see comments in artemis/config/playwright.env why this port is necessary - '54321:54321' volumes: - ./nginx/artemis-upstream-multi-node.conf:/etc/nginx/includes/artemis-upstream.conf:ro - ./nginx/artemis-ssh-upstream-multi-node.conf:/etc/nginx/includes/artemis-ssh-upstream.conf:ro - - ./nginx/artemis-nginx-cypress.conf:/etc/nginx/conf.d/artemis-nginx-cypress.conf:ro + - ./nginx/artemis-nginx-playwright.conf:/etc/nginx/conf.d/artemis-nginx-playwright.conf:ro - type: bind - source: ${NGINX_PROXY_SSL_CERTIFICATE_PATH:-../src/test/cypress/certs/artemis-nginx+4.pem} + source: ${NGINX_PROXY_SSL_CERTIFICATE_PATH:-../src/test/playwright/certs/artemis-nginx+4.pem} target: "/certs/fullchain.pem" - type: bind - source: ${NGINX_PROXY_SSL_CERTIFICATE_KEY_PATH:-../src/test/cypress/certs/artemis-nginx+4-key.pem} + source: ${NGINX_PROXY_SSL_CERTIFICATE_KEY_PATH:-../src/test/playwright/certs/artemis-nginx+4-key.pem} target: "/certs/priv_key.pem" diff --git a/docker/playwright-E2E-tests-mysql-localci.yml b/docker/playwright-E2E-tests-mysql-localci.yml index a5536baabbb9..aa501ae75192 100644 --- a/docker/playwright-E2E-tests-mysql-localci.yml +++ b/docker/playwright-E2E-tests-mysql-localci.yml @@ -17,8 +17,8 @@ services: mysql: condition: service_healthy env_file: - - ./artemis/config/cypress.env - - ./artemis/config/cypress-local.env + - ./artemis/config/playwright.env + - ./artemis/config/playwright-local.env volumes: - /var/run/docker.sock:/var/run/docker.sock @@ -31,11 +31,11 @@ services: artemis-app: condition: service_started volumes: - - ./nginx/artemis-nginx-cypress.conf:/etc/nginx/conf.d/artemis-nginx-cypress.conf:ro + - ./nginx/artemis-nginx-playwright.conf:/etc/nginx/conf.d/artemis-nginx-playwright.conf:ro ports: - '80:80' - '443:443' - # see comments in artemis/config/cypress.env why this port is necessary + # see comments in artemis/config/playwright.env why this port is necessary - '54321:54321' artemis-playwright: diff --git a/docker/playwright-E2E-tests-mysql.yml b/docker/playwright-E2E-tests-mysql.yml index 65f9a343b515..c269ce9b206e 100644 --- a/docker/playwright-E2E-tests-mysql.yml +++ b/docker/playwright-E2E-tests-mysql.yml @@ -16,8 +16,8 @@ services: mysql: condition: service_healthy env_file: - - ./artemis/config/cypress.env - - ./artemis/config/cypress-mysql.env + - ./artemis/config/playwright.env + - ./artemis/config/playwright-mysql.env nginx: extends: @@ -28,11 +28,11 @@ services: artemis-app: condition: service_started volumes: - - ./nginx/artemis-nginx-cypress.conf:/etc/nginx/conf.d/artemis-nginx-cypress.conf:ro + - ./nginx/artemis-nginx-playwright.conf:/etc/nginx/conf.d/artemis-nginx-playwright.conf:ro ports: - '80:80' - '443:443' - # see comments in artemis/config/cypress.env why this port is necessary + # see comments in artemis/config/playwright.env why this port is necessary - '54321:54321' artemis-playwright: diff --git a/docker/playwright-E2E-tests-postgres.yml b/docker/playwright-E2E-tests-postgres.yml index b2f1aa201bbf..92bde9b2cfe0 100644 --- a/docker/playwright-E2E-tests-postgres.yml +++ b/docker/playwright-E2E-tests-postgres.yml @@ -17,8 +17,8 @@ services: condition: service_healthy env_file: - ./artemis/config/postgres.env - - ./artemis/config/cypress.env - - ./artemis/config/cypress-postgres.env + - ./artemis/config/playwright.env + - ./artemis/config/playwright-postgres.env nginx: extends: @@ -29,11 +29,11 @@ services: artemis-app: condition: service_started volumes: - - ./nginx/artemis-nginx-cypress.conf:/etc/nginx/conf.d/artemis-nginx-cypress.conf:ro + - ./nginx/artemis-nginx-playwright.conf:/etc/nginx/conf.d/artemis-nginx-playwright.conf:ro ports: - '80:80' - '443:443' - # see comments in artemis/config/cypress.env why this port is necessary + # see comments in artemis/config/playwright.env why this port is necessary - '54321:54321' artemis-playwright: diff --git a/docker/sorry-cypress/.htpasswd b/docker/sorry-cypress/.htpasswd deleted file mode 100644 index 5122db186396..000000000000 --- a/docker/sorry-cypress/.htpasswd +++ /dev/null @@ -1,4 +0,0 @@ -# Sample .htaccess file with credentials artemis_admin:artemis_admin -# Change for production! - -artemis_admin: $apr1$95ecxdaf$I1MlWdUoSYOfjdlPqZRGq/ diff --git a/docker/sorry-cypress/README.md b/docker/sorry-cypress/README.md deleted file mode 100644 index 4ed3fb156daf..000000000000 --- a/docker/sorry-cypress/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# Sorry Cypress - -Sorry Cypress is an open-source, self-hosted alternative to the Cypress Dashboard, which allows you to manage, execute, and observe your Cypress test runs and results. - -## Usage - -The dashboard is available on https://sorry-cypress.ase.cit.tum.de, which is secured with a basic authentication. The credentials can be found on [Confluence](https://confluence.ase.in.tum.de/display/ArTEMiS/Sorry+Cypress+Dashboard). - -After login, you can see the active projects for artemis. One for the MySQL and one for the Postgres runs. Clicking on either project will reveal the last runs. Each run is named with a combination of the branch name and the run number. E.g for the 4th run of the branch `feature/add-awesomeness` the name would be `feature/add-awesomeness #4`. On the run overview page, each run shows some basic information, like the run time, if the run is currently running (red dot in front of the run name), the passed and failed tests etc. -To debug one of the recent runs, click on the single run and sorry cypress now shows a table with all the different test files that were tested. Select a failed test and you can now see a video of this run. Since cypress is a graphical testing tool, analyzing a video is ofter much more helpful then analyzing the corresponding logs. - -*Hint*: Sometimes it takes a while until the videos are available. So if no video is shown for the run, just visit the page again some minutes later. - -## Tech Stack - -Also visit the sorry cypress docs for more information: https://docs.sorry-cypress.dev/ - -### Dashboard - -As mentioned earlier the dashboard allows the developers to get an overview of the last test runs and helps them debug the runs. - -### API - -The API service is used to gather information from the CI and also provide them to the dashboard. - -### MongoDB - -This service is used as a database to store all the run information. - -### Director - -A service that accepts data from the api and saves it into the database. - -### Minio - -A AWS S3 and Google Cloud compatible dropin replacement, that is used as a storage provider, storing the videos and screenshots of the run. - -### Nginx - -Used as a reverse proxy, that allows to access the different endpoints via HTTPS. diff --git a/docker/sorry-cypress/SETUP.md b/docker/sorry-cypress/SETUP.md deleted file mode 100644 index 7d2027c5af6b..000000000000 --- a/docker/sorry-cypress/SETUP.md +++ /dev/null @@ -1,25 +0,0 @@ -# Setup Sorry Cypress - -1. Use the docker compose file (called `sorry-cypress.yml`) in this folder as base. -2. Copy the `sorry-cypress.env` file to the folder, where the compose files is placed. Now change all the values in the env file accordingly. - 1. Replace the `` and `` with applicable values (e.g random). These values are needed to manage the minio instance. - 2. Set a random key for the `ALLOWED_KEYS` (by replacing ``). This key is needed to authorize bamboo against the sorry-cypress dashboard. -3. Place all the necessary NGINX config files in their locations - 1. Place the `nginx.conf` file from this folder into this path `files/nginx/nginx.conf` - 2. Place a generated `.htpasswd` file into this path `files/nginx/.htpasswd` (e.g. use a online htpasswd generator). This file is used for the basic auth part of the main dashboard. - 3. Place/link a public SSL certificate file in this path `files/nginx/fullchain.pem` - 4. Place/link a private SSL certificate file in this path `files/nginx/privkey.pem` -4. Ensure that all the URLs within the `nginx.conf` and the `sorry-cypress.yml` file are still valid -5. Start the containers by using `docker compose up -f sorry-cypress.yml` -6. Login into the minio dashboard (https://minio.sorry-cypress.ase.cit.tum.de) -7. Create a new user called "sorry-cypress" (Minio Dashboard -> Identity -> Users) -8. Assign this user only the `writeOnly` policy -9. Generate a random access key and a random secret key (e.g by using `openssl rand -base64 24`) -10. Create and set the just generated `ACCESSKEY` and `SECRETKEY` for this user in the `sorry-cypress.env` file (select the user -> Service Accounts --> Create Access Key) -11. Insert the `ACCESSKEY` into the .env file by replacing the `` value -12. Insert the `SECRETKEY` into the .env file by replacing the `` value -13. Within the bucket settings, set the lifecycle to delete files ("Expiry") after 14 days. -14. Under `Policies` create a new policy called `sorry-cypress` with the content of the `minio-user-policy.json` file. Now assign this policy to the `sorry-cypress` user (under `Identity` -> `Users`). This will allow the `sorry-cypress` user to upload and delete files to/from the bucket. -15. Recreate the director container, since the new keys need to be applied (e.g with the following commands `docker compose pull -f sorry-cypress.yml` & `docker compose up -f sorry-cypress.yml`) -16. Access the sorry-cypress dashboard (https://sorry-cypress.ase.cit.tum.de) and create two new projects `artemis-mysql` and `artemis-postgresql`. Set the timeout to a reasonable number (e.g 150 min) -17. Now everything should be setup diff --git a/docker/sorry-cypress/minio-user-policy.json b/docker/sorry-cypress/minio-user-policy.json deleted file mode 100644 index ed036808944a..000000000000 --- a/docker/sorry-cypress/minio-user-policy.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Action": [ - "s3:DeleteObject", - "s3:GetBucketLocation", - "s3:GetObject", - "s3:ListBucket", - "s3:ListMultipartUploadParts", - "s3:PutObject", - "s3:AbortMultipartUpload" - ], - "Resource": [ - "arn:aws:s3:::sorry-cypress", - "arn:aws:s3:::sorry-cypress/*" - ] - } - ] -} diff --git a/docker/sorry-cypress/nginx.conf b/docker/sorry-cypress/nginx.conf deleted file mode 100644 index 4230e2b6961f..000000000000 --- a/docker/sorry-cypress/nginx.conf +++ /dev/null @@ -1,129 +0,0 @@ -http { - server { - listen 80; - server_name ${NGINX_MAIN_URL}; - - location / { - return 301 https://$host$request_uri; - } - } - - server { - listen 443 ssl; - server_name ${NGINX_MAIN_URL}; - - ssl_certificate /etc/certificates/fullchain.pem; - ssl_certificate_key /etc/certificates/privkey.pem; - ssl_protocols TLSv1.2 TLSv1.3; - ssl_ciphers 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384'; - ssl_prefer_server_ciphers on; - - location / { - proxy_pass http://sry-cypress-dashboard:8080; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_buffering off; - proxy_redirect off; - - auth_basic "Restricted"; - auth_basic_user_file /etc/nginx/.htpasswd; - } - - location /api { - proxy_pass http://sry-cypress-api:4000; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_buffering off; - proxy_redirect off; - - auth_basic "Restricted"; - auth_basic_user_file /etc/nginx/.htpasswd; - } - - location /director { - rewrite ^/director(/?.*)$ $1 break; - proxy_pass http://sry-cypress-director:1234; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_buffering off; - proxy_redirect off; - } - } - - server { - listen 80; - server_name ${NGINX_STORAGE_URL}; - - location / { - return 301 https://$host$request_uri; - } - } - - server { - listen 443 ssl; - server_name ${NGINX_STORAGE_URL}; - - ssl_certificate /etc/certificates/fullchain.pem; - ssl_certificate_key /etc/certificates/privkey.pem; - ssl_protocols TLSv1.2 TLSv1.3; - ssl_ciphers 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384'; - ssl_prefer_server_ciphers on; - - # This is needed to allow video file uploads, that are greater than 1MB - client_max_body_size 100M; - - location / { - proxy_pass http://sry-cypress-minio:9000; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_buffering off; - proxy_redirect off; - } - } - - server { - listen 80; - server_name ${NGINX_MINIO_URL}; - - location / { - return 301 https://$host$request_uri; - } - } - - server { - listen 443 ssl; - server_name ${NGINX_MINIO_URL}; - - ssl_certificate /etc/certificates/fullchain.pem; - ssl_certificate_key /etc/certificates/privkey.pem; - ssl_protocols TLSv1.2 TLSv1.3; - ssl_ciphers 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384'; - ssl_prefer_server_ciphers on; - - # This is needed to allow video file uploads, that are greater than 1MB - client_max_body_size 100M; - - location / { - proxy_pass http://sry-cypress-minio:9090; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_buffering off; - proxy_redirect off; - } - } -} - -events { } diff --git a/docker/sorry-cypress/sorry-cypress.env b/docker/sorry-cypress/sorry-cypress.env deleted file mode 100644 index 13dda8bd8c07..000000000000 --- a/docker/sorry-cypress/sorry-cypress.env +++ /dev/null @@ -1,22 +0,0 @@ -SORRY_CYPRESS_TAG="2.5.4" - -MONGO_INITDB_ROOT_USERNAME="sorry-cypress" -MONGO_INITDB_ROOT_PASSWORD="sorry-cypress" -MONGODB_URI="mongodb://${MONGO_INITDB_ROOT_USERNAME}:${MONGO_INITDB_ROOT_PASSWORD}@mongo:27017" -MONGODB_DATABASE="sorry-cypress" - -DASHBOARD_URL="https://sorry-cypress.ase.cit.tum.de" -ALLOWED_KEYS="" -MINIO_ACCESS_KEY="" -MINIO_SECRET_KEY="" -MINIO_ENDPOINT="storage.sorry-cypress.ase.cit.tum.de" -MINIO_URL="https://storage.sorry-cypress.ase.cit.tum.de" - -GRAPHQL_SCHEMA_URL="https://sorry-cypress.ase.cit.tum.de/api" - -MINIO_ROOT_USER="artemis" -MINIO_ROOT_PASSWORD="" - -NGINX_MAIN_URL="sorry-cypress.ase.cit.tum.de" -NGINX_STORAGE_URL="storage.sorry-cypress.ase.cit.tum.de" -NGINX_MINIO_URL="minio.sorry-cypress.ase.cit.tum.de" diff --git a/docker/sorry-cypress/sorry-cypress.yml b/docker/sorry-cypress/sorry-cypress.yml deleted file mode 100644 index baa7ef99bc32..000000000000 --- a/docker/sorry-cypress/sorry-cypress.yml +++ /dev/null @@ -1,107 +0,0 @@ -# ---------------------------------------------------------------------------------------------------------------------- -# Sorry Cypress Setup -# ---------------------------------------------------------------------------------------------------------------------- - -services: - mongo: - image: docker.io/library/mongo:4.4 - container_name: sry-cypress-mongo - restart: always - volumes: - - ${MONGO_VOLUME_MOUNT:-./files/mongo}:/data/db - env_file: - - ${SORRY_CYPRESS_ENV_FILE:-./sorry-cypress.env} - - director: - image: docker.io/agoldis/sorry-cypress-director:${SORRY_CYPRESS_TAG:-latest} - container_name: sry-cypress-director - restart: always - env_file: - - ${SORRY_CYPRESS_ENV_FILE:-./sorry-cypress.env} - environment: - EXECUTION_DRIVER: '../execution/mongo/driver' - SCREENSHOTS_DRIVER: '../screenshots/minio.driver' - MINIO_PORT: '443' - MINIO_USESSL: 'true' - MINIO_BUCKET: 'sorry-cypress' - PROBE_LOGGER: 'false' - depends_on: - - mongo - - api: - image: docker.io/agoldis/sorry-cypress-api:${SORRY_CYPRESS_TAG:-latest} - container_name: sry-cypress-api - restart: always - env_file: - - ${SORRY_CYPRESS_ENV_FILE:-./sorry-cypress.env} - environment: - APOLLO_PLAYGROUND: 'false' - depends_on: - - mongo - - dashboard: - image: docker.io/agoldis/sorry-cypress-dashboard:${SORRY_CYPRESS_TAG:-latest} - container_name: sry-cypress-dashboard - restart: always - env_file: - - ${SORRY_CYPRESS_ENV_FILE:-./sorry-cypress.env} - environment: - GRAPHQL_CLIENT_CREDENTIALS: 'include' - PORT: 8080 - CI_URL: '' - expose: - - '8080' - depends_on: - - mongo - - api - - storage: - image: docker.io/minio/minio - container_name: sry-cypress-minio - restart: always - env_file: - - ${SORRY_CYPRESS_ENV_FILE:-./sorry-cypress.env} - volumes: - - ${MINIO_VOLUME_MOUNT:-./files/minio}:/data - command: minio server --console-address ":9090" /data - - createbuckets: - image: docker.io/minio/mc - container_name: sry-cypress-minio-bucket-creator - depends_on: - - storage - env_file: - - ${SORRY_CYPRESS_ENV_FILE:-./sorry-cypress.env} - entrypoint: > - /bin/sh -c " - sleep 3; - /usr/bin/mc config host add myminio http://storage:9000 $MINIO_ROOT_USER $MINIO_ROOT_PASSWORD; - /usr/bin/mc mb myminio/sorry-cypress; - /usr/bin/mc anonymous set download myminio/sorry-cypress; - exit 0; - " - - nginx: - image: docker.io/library/nginx - container_name: sry-cypress-nginx - restart: always - ports: - - 80:80 - - 443:443 - env_file: - - ${SORRY_CYPRESS_ENV_FILE:-./sorry-cypress.env} - environment: - NGINX_ENVSUBST_OUTPUT_DIR: /etc/nginx - volumes: - - type: bind - source: ${NGINX_PROXY_CONFIG_PATH:-./nginx.conf} - target: '/etc/nginx/templates/nginx.conf.template' - - type: bind - source: ${NGINX_PROXY_SSL_CERTIFICATE_PATH:-../../src/test/cypress/certs/artemis-nginx+4.pem} - target: '/etc/certificates/fullchain.pem' - - type: bind - source: ${NGINX_PROXY_SSL_CERTIFICATE_KEY_PATH:-../../src/test/cypress/certs/artemis-nginx+4-key.pem} - target: '/etc/certificates/privkey.pem' - - type: bind - source: ${NGINX_PROXY_HTPASSWD:-./.htpasswd} - target: '/etc/nginx/.htpasswd' diff --git a/docker/test-server-multi-node-mysql-localci.yml b/docker/test-server-multi-node-mysql-localci.yml index 5bfc08a9c1fe..8de8a926068b 100644 --- a/docker/test-server-multi-node-mysql-localci.yml +++ b/docker/test-server-multi-node-mysql-localci.yml @@ -128,10 +128,10 @@ services: - ./nginx/artemis-upstream-multi-node.conf:/etc/nginx/includes/artemis-upstream.conf:ro - ./nginx/artemis-ssh-upstream-multi-node.conf:/etc/nginx/includes/artemis-ssh-upstream.conf:ro - type: bind - source: ${NGINX_PROXY_SSL_CERTIFICATE_PATH:-../src/test/cypress/certs/artemis-nginx+4.pem} + source: ${NGINX_PROXY_SSL_CERTIFICATE_PATH:-../src/test/playwright/certs/artemis-nginx+4.pem} target: "/certs/fullchain.pem" - type: bind - source: ${NGINX_PROXY_SSL_CERTIFICATE_KEY_PATH:-../src/test/cypress/certs/artemis-nginx+4-key.pem} + source: ${NGINX_PROXY_SSL_CERTIFICATE_KEY_PATH:-../src/test/playwright/certs/artemis-nginx+4-key.pem} target: "/certs/priv_key.pem" networks: diff --git a/docker/test-server-multi-node-postgresql-localci.yml b/docker/test-server-multi-node-postgresql-localci.yml index 8e0dc02bb592..124a1936aab2 100644 --- a/docker/test-server-multi-node-postgresql-localci.yml +++ b/docker/test-server-multi-node-postgresql-localci.yml @@ -100,10 +100,10 @@ services: - ./nginx/artemis-upstream-multi-node.conf:/etc/nginx/includes/artemis-upstream.conf:ro - ./nginx/artemis-ssh-upstream-multi-node.conf:/etc/nginx/includes/artemis-ssh-upstream.conf:ro - type: bind - source: ${NGINX_PROXY_SSL_CERTIFICATE_PATH:-../src/test/cypress/certs/artemis-nginx+4.pem} + source: ${NGINX_PROXY_SSL_CERTIFICATE_PATH:-../src/test/playwright/certs/artemis-nginx+4.pem} target: "/certs/fullchain.pem" - type: bind - source: ${NGINX_PROXY_SSL_CERTIFICATE_KEY_PATH:-../src/test/cypress/certs/artemis-nginx+4-key.pem} + source: ${NGINX_PROXY_SSL_CERTIFICATE_KEY_PATH:-../src/test/playwright/certs/artemis-nginx+4-key.pem} target: "/certs/priv_key.pem" networks: diff --git a/docker/test-server-mysql-localci.yml b/docker/test-server-mysql-localci.yml index 29b1881c6bb7..91c7c353bab0 100644 --- a/docker/test-server-mysql-localci.yml +++ b/docker/test-server-mysql-localci.yml @@ -47,10 +47,10 @@ services: restart: always volumes: - type: bind - source: ${NGINX_PROXY_SSL_CERTIFICATE_PATH:-../src/test/cypress/certs/artemis-nginx+4.pem} + source: ${NGINX_PROXY_SSL_CERTIFICATE_PATH:-../src/test/playwright/certs/artemis-nginx+4.pem} target: "/certs/fullchain.pem" - type: bind - source: ${NGINX_PROXY_SSL_CERTIFICATE_KEY_PATH:-../src/test/cypress/certs/artemis-nginx+4-key.pem} + source: ${NGINX_PROXY_SSL_CERTIFICATE_KEY_PATH:-../src/test/playwright/certs/artemis-nginx+4-key.pem} target: "/certs/priv_key.pem" networks: diff --git a/docker/test-server-mysql.yml b/docker/test-server-mysql.yml index bcd82539e146..5f8c10981cc5 100644 --- a/docker/test-server-mysql.yml +++ b/docker/test-server-mysql.yml @@ -44,10 +44,10 @@ services: restart: always volumes: - type: bind - source: ${NGINX_PROXY_SSL_CERTIFICATE_PATH:-../src/test/cypress/certs/artemis-nginx+4.pem} + source: ${NGINX_PROXY_SSL_CERTIFICATE_PATH:-../src/test/playwright/certs/artemis-nginx+4.pem} target: "/certs/fullchain.pem" - type: bind - source: ${NGINX_PROXY_SSL_CERTIFICATE_KEY_PATH:-../src/test/cypress/certs/artemis-nginx+4-key.pem} + source: ${NGINX_PROXY_SSL_CERTIFICATE_KEY_PATH:-../src/test/playwright/certs/artemis-nginx+4-key.pem} target: "/certs/priv_key.pem" networks: diff --git a/docker/test-server-postgresql-localci.yml b/docker/test-server-postgresql-localci.yml index 600cd29bf261..d93058788912 100644 --- a/docker/test-server-postgresql-localci.yml +++ b/docker/test-server-postgresql-localci.yml @@ -46,10 +46,10 @@ services: restart: always volumes: - type: bind - source: ${NGINX_PROXY_SSL_CERTIFICATE_PATH:-../src/test/cypress/certs/artemis-nginx+4.pem} + source: ${NGINX_PROXY_SSL_CERTIFICATE_PATH:-../src/test/playwright/certs/artemis-nginx+4.pem} target: "/certs/fullchain.pem" - type: bind - source: ${NGINX_PROXY_SSL_CERTIFICATE_KEY_PATH:-../src/test/cypress/certs/artemis-nginx+4-key.pem} + source: ${NGINX_PROXY_SSL_CERTIFICATE_KEY_PATH:-../src/test/playwright/certs/artemis-nginx+4-key.pem} target: "/certs/priv_key.pem" networks: diff --git a/docker/test-server-postgresql.yml b/docker/test-server-postgresql.yml index d09cb52dce53..0e3c37e95627 100644 --- a/docker/test-server-postgresql.yml +++ b/docker/test-server-postgresql.yml @@ -43,10 +43,10 @@ services: restart: always volumes: - type: bind - source: ${NGINX_PROXY_SSL_CERTIFICATE_PATH:-../src/test/cypress/certs/artemis-nginx+4.pem} + source: ${NGINX_PROXY_SSL_CERTIFICATE_PATH:-../src/test/playwright/certs/artemis-nginx+4.pem} target: "/certs/fullchain.pem" - type: bind - source: ${NGINX_PROXY_SSL_CERTIFICATE_KEY_PATH:-../src/test/cypress/certs/artemis-nginx+4-key.pem} + source: ${NGINX_PROXY_SSL_CERTIFICATE_KEY_PATH:-../src/test/playwright/certs/artemis-nginx+4-key.pem} target: "/certs/priv_key.pem" networks: diff --git a/eslint.config.js b/eslint.config.js index 14d17e283ee0..622299e984e1 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -27,7 +27,6 @@ module.exports = [ 'repos-download/', 'src/main/generated/', 'src/main/resources/', - 'src/test/cypress/', // until we delete those files, we ignore them 'target/', 'uploads/', ], @@ -37,19 +36,13 @@ module.exports = [ languageOptions: { parser: typescriptParser, parserOptions: { - project: [ - './tsconfig.json', - './tsconfig.app.json', - './tsconfig.spec.json', - 'src/test/cypress/tsconfig.json', - 'src/test/playwright/tsconfig.json', - ], + project: ['./tsconfig.json', './tsconfig.app.json', './tsconfig.spec.json', 'src/test/playwright/tsconfig.json'], }, }, plugins: { '@typescript-eslint': tsPlugin, '@angular-eslint': angularPlugin, - 'prettier': prettierPlugin, + prettier: prettierPlugin, }, rules: { ...prettierPlugin.configs.recommended.rules, @@ -102,7 +95,7 @@ module.exports = [ }, plugins: { '@angular-eslint': angularPlugin, - 'prettier': prettierPlugin, + prettier: prettierPlugin, }, rules: { // ...angularPlugin.configs['template/recommended'].rules, @@ -126,7 +119,7 @@ module.exports = [ { files: ['src/test/javascript/**'], plugins: { - 'jest': jestPlugin, + jest: jestPlugin, 'jest-extended': jestExtendedPlugin, }, rules: { diff --git a/src/main/java/de/tum/in/www1/artemis/security/jwt/JWTCookieService.java b/src/main/java/de/tum/in/www1/artemis/security/jwt/JWTCookieService.java index 6fb44f9e1bec..3fd9d62c03e1 100644 --- a/src/main/java/de/tum/in/www1/artemis/security/jwt/JWTCookieService.java +++ b/src/main/java/de/tum/in/www1/artemis/security/jwt/JWTCookieService.java @@ -18,8 +18,6 @@ @Service public class JWTCookieService { - private static final String CYPRESS_PROFILE = "cypress"; - private static final String DEVELOPMENT_PROFILE = "dev"; private final TokenProvider tokenProvider; @@ -61,9 +59,8 @@ public ResponseCookie buildLogoutCookie() { */ private ResponseCookie buildJWTCookie(String jwt, Duration duration) { - // TODO - Remove cypress workaround once cypress uses https and find a better solution for testing locally in Safari Collection activeProfiles = Arrays.asList(environment.getActiveProfiles()); - boolean isSecure = !activeProfiles.contains(CYPRESS_PROFILE) && !activeProfiles.contains(DEVELOPMENT_PROFILE); + boolean isSecure = !activeProfiles.contains(DEVELOPMENT_PROFILE); return ResponseCookie.from(JWT_COOKIE_NAME, jwt).httpOnly(true) // Must be httpOnly .sameSite("Lax") // Must be Lax to allow navigation links to Artemis to work diff --git a/src/test/cypress/README.md b/src/test/cypress/README.md deleted file mode 100644 index b59bc697c404..000000000000 --- a/src/test/cypress/README.md +++ /dev/null @@ -1,83 +0,0 @@ -# Artemis Cypress test suite -This folder contains the End-to-End test suite for Artemis. -The test suite only contains End-to-End tests. Therefore it cannot be run out of the box and has some requirements. Those will be listed in the following. - -# Requirements -1. Running (and reachable) test environment: The Artemis Server and Client have to be deployed somewhere, where the tests can access them. This can be a local setup or a remote one (the Artemis test servers for example) -2. Prepared user accounts on the test environment: See the [corresponding section](#prepared-users) below -3. Node and Chrome installed on the machine, which executes the test suite - -## Prepared users -Currently the test suite does not automatically create the required users with their roles, but expects existing ones. There are several user accounts the test suite requires: -| ROLE | ID(s) | AMOUNT | -|:------------------:|:-------------:|:------:| -| `ADMIN` | - | 1 | -| `USER` | 100, 102, 104 | 3 | -| `TEACHING ASSISTANT` | 101 | 1 | -| `INSTRUCTOR` | 103 | 1 | - -The test suite expects two templates (one for usernames and one for passwords) in its configuration (see the [general configuration section](#general-configuration)), which contain the text `USERID`. When authenticating as one of the non-admin users a test will substitute the `USERID` text in the username and password templates with the required ID (seen in the table) of the user. - -For example, a basic template for a username and password could be `user_USERID` and `password_USERID`. Hence, a test which requires the authentication of an `INSTRUCTOR` would then use `user_103`:`password_103` as credentials. - -An `ADMIN` user is required to create and delete courses. The credentials for an `ADMIN` user are not generated by the templates. Therefore no `ID` is specified in the table above. The `ADMIN` credentials are configured separately. See the [General configuration section](#general-configuration) for details. - -:warning: **The guided tour should be disabled for every user required by the test suite. Otherwise some/all tests in the suite will fail!** - -## Test suite configuration -### General configuration -Once the test environment is running and the required users are added in the test environment the test suite needs to be configured. The configuration is done via two files: -1. `cypress.json`: Contains general settings for Cypress -2. `cypress.env.json`: Contains settings specific for Artemis - -Both configuration files can be found in the cypress subfolder (`src/test/cypress`). - -In the following we will explain what setting in the configuration files has to be adjusted to be able to execute the test suite. Example configurations are shown in the [Example configuration section](#example-configurations) below. - -For `cypress.json`: -* `baseUrl`: The url pointing to the test environment here (make sure that there is no trailing slash) - -For `cypress.env.json`: -* `username`: The username template (as described in the [prepared users section](#prepared-users)) -* `password`: The password template -* `adminUsername`: The admin username (no template) -* `adminPassword`: The admin password (no template) - -### Example configurations -In the following we show example configurations of the test suite for imaginary Artemis setups. For readability we will leave out settings in the configuration files, which do not require the user to adjust them in order to run the tests. -#### Test environment using Gitlab + Jenkins -`cypress.json`: -```json -{ - "baseUrl": "https://imaginary-artemis-server.com" -} -``` -`cypress.env.json`: -```json -{ - "username": "username_USERID", - "password": "password_USERID", - "adminUsername": "admin_username", - "adminPassword": "admin_password" -} - -``` - -# Executing the test suite -Before executing the test suite Cypress with all of its dependencies has to be installed via `npm`. Make sure that the command is executed in the Cypress subfolder of Artemis (`src/test/cypress`). -```bash -npm install - -``` -The test suite can be executed with via the predefined commands in the `package.json`: -1. `npm run cypress:open`: This opens a Cypress Dashboard from where all or individual tests can be executed -2. `npm run cypress:run`: This executes the complete test suite in headless mode - -Individual test specs in the test suite can be executed by passing the `--spec` parameter like so: -```bash -npm run cypress:run -- --spec integration/path/to/spec/file.spec.ts - -``` - -For more information about Cypress and its configuration see the [Cypress documentation](https://docs.cypress.io/guides/getting-started/installing-cypress) - diff --git a/src/test/cypress/certs/artemis-nginx+4-key.pem b/src/test/cypress/certs/artemis-nginx+4-key.pem deleted file mode 100644 index eb2d95da1e9c..000000000000 --- a/src/test/cypress/certs/artemis-nginx+4-key.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQCuCJSHStSQd02f -j+IlQFes7pVUcYv2r0qm5qicGwPcKQf1/nmsy6k4WhE9HQV9VO9LQ4doSNp9NuYX -P/JQqdYLZYYQvxHS+fR7ofIPjirsrbQYAkG5F6imM8H7MkkueG3HGqaKD54PBmC4 -BgBJDFWiF8jSNSYNKOE2L5SaYG/g3LLIkWBlhBQHgrprkio4pv5Y44+nf+hGWkSj -bkRo2+PmIsNmQrpDB2o0O7uoyswa71HE967n9K17SWZ7Hi4kP6BGUWn65P5JB10a -6kz0y8183Uzz99bx8hzxLPg6VNiJZQ+dH4M1Jn6kysKiyV4x24JsM9s6t+Vhln9E -KX5ktosdAgMBAAECggEBAJs3ddkwqWLrtOSR/H2C5G+NHsyAtPdgIfG3mTwZcBjk -03/X5gdyYUusMOHTx3ifzwjOgq9FAvFYjGDCHMlKoGfrtWWsNCZ53k6CApVTE/+h -cRVUte9yJW2Ojf0PPWvf5vEEWPKbuTnnU03ttEVyZdG66tZoprZn9m1QhHYnesEO -PMPvYMd3Oyko8MD/Rr1A/KS/rmc0yfUvgLsqF6PLxq3NKxyVD/8Tp4u9aXbPMnd2 -vugVxjjvt5ubscF1Owi8EjqjVkXlw94JzLcy70XfBzsS2EvUtX/hmHgBEsViXUOQ -KGVyeFTvuReq0RvLQi1LA8vs2q6UC0ZYX75wGDfWWnUCgYEAyP6FY6xdP+N83qEM -TzAf2a33bBCcD5zbrfsvYwHwdzcAz9HBdf3TN1ZcbgfIzIWvuo+hFdjZd32E2+b7 -tSGpcs21iZ3dn1aWxngNs/h94h6cNak/02iCbOsmMX9rHfKZd1ODnQyA8q0s9PQY -uWWWMUfqPse7mSYbgU0aYOVFraMCgYEA3ak3N2mTgTVsUqhNyZCJlmtafp0tsT6b -/7GKSqkl741wokM6un3wx1eo6Q95mngxOlY2xxq9OChnNSEa9ZQnzdUDtQ0YE4QD -09awTIMHNCeSqpV2n3Yv2fT3C5Ya5/WEtYGpVAtqgxwWPij8+VMOa8MVzy+/v6Hg -N1Tpww+Y8D8CgYEAhbEGeK4FuKFQRaVJ0sJn7RrSIIdLxvbHCIqzkl+P2zwyxgj3 -bcxP2dcP1ABJiADESouO0kFTJS/QV5TkiC7DzyEVR1xCNeIamBjyxGrdELLbpLXX -Rn+VgW1IElR2o4zil4RtXuEaRFD8PlK+v1La/ByhqvCfz9aRJQhsK1dVaZECgYEA -jRYR0TFf89P/OLVrnapkCNwX45ND7Bc/0AY/UbpMLSfH02AbV2yl/xvqpT12Vz29 -h7Ysc5qvabk9x/FkaX99vmOhUnIdKv7SONnjqS+VPDsb/XvY3zKozoA/Zp6KTa5W -Y/k9wALsLruH5NTOABw/h5PKo+9uixkLz+w6Ri/9Vp0CgYEAqfkZJe7vCOIwtIwj -Mq5knkJgR+Vq30i4jRoFU0yxIcWA1hODVBnK39+mtA++/3+r5DY5fGRTc9mMyXU/ -y2N2nfSnvPMAUaRmisB7NhmvinEgymlrX+WE+7S9/+nOQADxzWSc6Hxg/ub6mTYV -k2/hv9uG1gbm2+OBP/EBOr48jz0= ------END PRIVATE KEY----- diff --git a/src/test/cypress/certs/artemis-nginx+4.pem b/src/test/cypress/certs/artemis-nginx+4.pem deleted file mode 100644 index 6492786845eb..000000000000 --- a/src/test/cypress/certs/artemis-nginx+4.pem +++ /dev/null @@ -1,25 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIERjCCAq6gAwIBAgIQSQ2vfdquHAQcrzbEKx46mzANBgkqhkiG9w0BAQsFADBf -MR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExGjAYBgNVBAsMEXJvb3RA -MWY0ZmQzNzYzNmMyMSEwHwYDVQQDDBhta2NlcnQgcm9vdEAxZjRmZDM3NjM2YzIw -HhcNMjIxMjA1MDk0NTEzWhcNMjUwMzA1MDk0NTEzWjBFMScwJQYDVQQKEx5ta2Nl -cnQgZGV2ZWxvcG1lbnQgY2VydGlmaWNhdGUxGjAYBgNVBAsMEXJvb3RAMWY0ZmQz -NzYzNmMyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArgiUh0rUkHdN -n4/iJUBXrO6VVHGL9q9KpuaonBsD3CkH9f55rMupOFoRPR0FfVTvS0OHaEjafTbm -Fz/yUKnWC2WGEL8R0vn0e6HyD44q7K20GAJBuReopjPB+zJJLnhtxxqmig+eDwZg -uAYASQxVohfI0jUmDSjhNi+UmmBv4NyyyJFgZYQUB4K6a5IqOKb+WOOPp3/oRlpE -o25EaNvj5iLDZkK6QwdqNDu7qMrMGu9RxPeu5/Ste0lmex4uJD+gRlFp+uT+SQdd -GupM9MvNfN1M8/fW8fIc8Sz4OlTYiWUPnR+DNSZ+pMrCosleMduCbDPbOrflYZZ/ -RCl+ZLaLHQIDAQABo4GXMIGUMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggr -BgEFBQcDATAfBgNVHSMEGDAWgBSpuKALkiwfLnQmm7+JNG2bxGAIgzBMBgNVHREE -RTBDgg1hcnRlbWlzLW5naW54gg9hcnRlbWlzLmV4YW1wbGWCCWxvY2FsaG9zdIcE -fwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAYEApG8ZADQe -SsH/nqH9WpR3ZkYg0rm8pw+YquBNUdDFG2/4IQtaaxrgsvNPrEEMXfCO4vvnC0cH -6Tgay8LzFZxU9D1F06VZ9S1C7KNnYSsjgwhW7wxem1JXgauoutA8D0uHLr/2bVnz -rTShQT7gRp9SRunqDylaSkgpXlfZQRlEANrYT8Jh6LIHRjkxLh/etw7VdFA6Tywh -iQGBE/EbQcGpmqHBoMytblku0D8H+pcFHZ03AZq0FTMbByM9GekQ8HJV88epqvqJ -7pWyQPX9lr7yC6n121dPoA0ylP8D7jIBCmlFeF+QWCiRAgdeb1w+JONHMgI97IR+ -9HBm6gGE+Da/TRq82w02tUN/F7NHdzqwKGx/GKLrEsdNlfP6D9iiVtfBGBoAUm+C -2t3jbQEgqYHA+mzadS75RGJsRnVdY24IHvNjEnESW6KCaSfQyMmp3trRH6JeOttU -2JeqRPjmOzNvzIcB76w1/hB2ljhimyfoxB8Gbrts+GFPRZE+AXg1mvCn ------END CERTIFICATE----- diff --git a/src/test/cypress/certs/rootCA.pem b/src/test/cypress/certs/rootCA.pem deleted file mode 100644 index df27e7384ca9..000000000000 --- a/src/test/cypress/certs/rootCA.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEjTCCAvWgAwIBAgIQU1RC58hYfDrlnkOa5hWT9TANBgkqhkiG9w0BAQsFADBf -MR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExGjAYBgNVBAsMEXJvb3RA -MWY0ZmQzNzYzNmMyMSEwHwYDVQQDDBhta2NlcnQgcm9vdEAxZjRmZDM3NjM2YzIw -HhcNMjIxMjA1MDk0NTEzWhcNMzIxMjA1MDk0NTEzWjBfMR4wHAYDVQQKExVta2Nl -cnQgZGV2ZWxvcG1lbnQgQ0ExGjAYBgNVBAsMEXJvb3RAMWY0ZmQzNzYzNmMyMSEw -HwYDVQQDDBhta2NlcnQgcm9vdEAxZjRmZDM3NjM2YzIwggGiMA0GCSqGSIb3DQEB -AQUAA4IBjwAwggGKAoIBgQC6XajL1Rz5RQW0D+TxZ16msa5xAcKt5hEclOUB+oK+ -ychkUiDDSeh4EpkA2txu823n8BLqdNrIZ2A/TW3OVRXcD/hYFTbODI+FZ4DFEHoP -b8QnMlbZfo1AVNOR5ZFAVuneytaauhznnd1+Y49ieeX2v81hmBUKTuwDGVwp69rS -WUqANAKuGim7yOyBX6oRaUPg42xIBVHdDXkWr06zcFC6Z1O5zUYmFYHyn/sP2ZRN -BzMM+lVHCbZlw9Yi5TGLDC4wUAmMS9rColE5E76UNuOvfUERZffdLCzkmbS+VqOI -28fWvO/C8qEB10lcjxxplah4JZSyveH3Q5aFzLK2FbnXfLa/ypr3Mn9rBm06CtaL -Moy6h5gxNFDDB4RTpP7kjz32RRbl5xxqgkTEEAGDr/bk/C3DT6pyvGX5k6cj0zWd -o2bAO42Uk4ehMEHEUhnmvJ1yeOLSabgzfTJ3dM1NkdPI3Ss7dJGfraPx0sGet4SB -KMKw3mqJIizd1vV19TA/oRECAwEAAaNFMEMwDgYDVR0PAQH/BAQDAgIEMBIGA1Ud -EwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFKm4oAuSLB8udCabv4k0bZvEYAiDMA0G -CSqGSIb3DQEBCwUAA4IBgQBSPmSTP6Twe1T5UNqxfLSG/aKtT9yR1gAOW1zmM8KN -IZEwa1k6AH+y+dBT1MdFtSORVRagKNBwNsqqUMgPlXp9INpo+a5GFT4oAv73CrWu -bmXq7oiKkfk9UcdBNp3n8J+h+urXm4jEcUzTdNt8R631+seKOjYZz1SKOzpV5iz5 -20Mjk36RkiaiH3sxYvVo9ayXATz4Yq+0jWOHuQpYmFe2mH6wlle8hT/bRQb6/2z0 -wG/kKZl/CYbgRhc39np06mQ7FmAyXTtQORfjfhAUEu568JzPl/r2jYX1YgtEP4IL -GZXOdSYdtVC1vfpoWIo1YY+xqg3WRA/qgPFW33pZBk/qTaWE4ISMr0ewv613JDdK -ZOttGRDm2EDmh/FoeRoO5niydjb9DP915xObGMrYXKkPBpoIsQCfcmmFNQBAN4e4 -OQwSP9r/hh1cS8Usk6Ch0/iRhq7lv2Z5irLl/nQ4tPUZDVbBOhJ936t0gySVHbCl -GVOog28PQ8wI3fRZ2FZg6IM= ------END CERTIFICATE----- diff --git a/src/test/cypress/currents.config.js b/src/test/cypress/currents.config.js deleted file mode 100644 index c5cadf96dc1c..000000000000 --- a/src/test/cypress/currents.config.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - projectId: process.env.SORRY_CYPRESS_PROJECT_ID, - recordKey: process.env.SORRY_CYPRESS_KEY, - cloudServiceUrl: process.env.SORRY_CYPRESS_URL, -}; diff --git a/src/test/cypress/cypress.config.ts b/src/test/cypress/cypress.config.ts deleted file mode 100644 index fa5c941d1de5..000000000000 --- a/src/test/cypress/cypress.config.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { defineConfig } from 'cypress'; -import { cloudPlugin } from 'cypress-cloud/plugin'; -import fs from 'fs'; - -export default defineConfig({ - clientCertificates: [ - { - url: 'https://artemis-nginx', - ca: ['certs/rootCA.pem'], - certs: [ - { - cert: 'certs/artemis-nginx+4.pem', - key: 'certs/artemis-nginx+4-key.pem', - }, - ], - }, - { - url: 'https://artemis.example', - ca: ['certs/rootCA.pem'], - certs: [ - { - cert: 'certs/artemis-nginx+4.pem', - key: 'certs/artemis-nginx+4-key.pem', - }, - ], - }, - { - url: 'https://localhost', - ca: ['certs/rootCA.pem'], - certs: [ - { - cert: 'certs/artemis-nginx+4.pem', - key: 'certs/artemis-nginx+4-key.pem', - }, - ], - }, - ], - fixturesFolder: 'fixtures', - screenshotsFolder: 'screenshots', - videosFolder: 'videos', - video: true, - screenshotOnRunFailure: true, - viewportWidth: 1920, - viewportHeight: 1080, - defaultCommandTimeout: 20000, - responseTimeout: 120000, - reporter: 'junit', - reporterOptions: { - mochaFile: 'build/cypress/test-reports/test-results.[hash].xml', - toConsole: true, - }, - e2e: { - setupNodeEvents(on, config) { - on('task', { - error(message: string) { - console.error('\x1b[31m', 'ERROR: ', message, '\x1b[0m'); - return null; - }, - warn(message: string) { - console.error('\x1b[33m', 'WARNING: ', message, '\x1b[0m'); - return null; - }, - log(message: string) { - console.log('\x1b[37m', 'LOG: ', message, '\x1b[0m'); - return null; - }, - }); - on('after:spec', (spec: Cypress.Spec, results: CypressCommandLine.RunResult) => { - if (results && results.video) { - const failures = results.tests.some((test) => test.attempts.some((attempt) => attempt.state === 'failed')); - if (!failures) { - fs.unlinkSync(results.video); - } - } - }); - on('before:browser:launch', (browser, launchOptions) => { - launchOptions.args.push('--lang=en'); - return launchOptions; - }); - return cloudPlugin(on, config); - }, - specPattern: ['init/ImportUsers.cy.ts', 'e2e/**/*.cy.ts'], - supportFile: 'support/index.ts', - baseUrl: 'http://localhost:8080', - testIsolation: false, - }, -}); diff --git a/src/test/cypress/cypress.env.json b/src/test/cypress/cypress.env.json deleted file mode 100644 index 0904cff1191c..000000000000 --- a/src/test/cypress/cypress.env.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "username": "", - "password": "", - "adminUsername": "", - "adminPassword": "", - "allowGroupCustomization": false, - "studentGroupName": null, - "tutorGroupName": null, - "editorGroupName": null, - "instructorGroupName": null, - "createUsers": false -} diff --git a/src/test/cypress/e2e/Login.cy.ts b/src/test/cypress/e2e/Login.cy.ts deleted file mode 100644 index c34e9cb687f8..000000000000 --- a/src/test/cypress/e2e/Login.cy.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { loginPage, navigationBar } from '../support/artemis'; -import { studentOne } from '../support/users'; - -describe.skip('Login page tests', () => { - it('Logs in via the UI', () => { - cy.visit('/'); - loginPage.login(studentOne); - cy.url().should('include', '/courses'); - cy.getCookie('jwt').should('exist'); - cy.getCookie('jwt').should('have.property', 'value'); - cy.getCookie('jwt').should('have.property', 'httpOnly', true); - cy.getCookie('jwt').should('have.property', 'sameSite', 'lax'); - // TODO: Uncomment once cypress is using https - cy.getCookie('jwt').should('have.property', 'secure', true); - }); - - it('Logs in programmatically and logs out via the UI', () => { - cy.login(studentOne, '/courses'); - cy.url().should('include', '/courses'); - navigationBar.logout(); - cy.url().should('equal', Cypress.config().baseUrl + '/'); - cy.getCookie('jwt').should('not.exist'); - }); - - it('Displays error messages on wrong password', () => { - cy.visit('/'); - loginPage.login({ username: 'some_user_name', password: 'lorem-ipsum' }); - cy.location('pathname').should('eq', '/'); - cy.get('.alert').should('exist').and('have.text', 'Failed to sign in! Please check your username and password and try again.'); - cy.get('#login-button').click(); - cy.get('#login-button').click(); - }); - - it('Fails to access protected resource without login', () => { - cy.visit('/course-management'); - cy.location('pathname').should('eq', '/'); - }); - - it('Verify footer content', () => { - cy.visit('/'); - loginPage.shouldShowFooter(); - loginPage.shouldShowAboutUsInFooter(); - loginPage.shouldShowRequestChangeInFooter(); - loginPage.shouldShowReleaseNotesInFooter(); - loginPage.shouldShowPrivacyStatementInFooter(); - loginPage.shouldShowImprintInFooter(); - }); -}); diff --git a/src/test/cypress/e2e/Logout.cy.ts b/src/test/cypress/e2e/Logout.cy.ts deleted file mode 100644 index d9c988f2b449..000000000000 --- a/src/test/cypress/e2e/Logout.cy.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { Course } from 'app/entities/course.model'; -import { ModelingExercise } from 'app/entities/modeling-exercise.model'; - -import { courseManagementAPIRequest, courseOverview, exerciseAPIRequest, modelingExerciseEditor, navigationBar } from '../support/artemis'; -import { admin, studentOne, studentTwo } from '../support/users'; -import { convertModelAfterMultiPart } from '../support/utils'; - -describe.skip('Logout tests', () => { - let course: Course; - let modelingExercise: ModelingExercise; - - before('Login as admin and create a course with a modeling exercise', () => { - cy.login(admin); - - courseManagementAPIRequest.createCourse().then((response) => { - course = convertModelAfterMultiPart(response); - courseManagementAPIRequest.addStudentToCourse(course, studentOne); - courseManagementAPIRequest.addStudentToCourse(course, studentTwo); - exerciseAPIRequest.createModelingExercise({ course }).then((resp: Cypress.Response) => { - modelingExercise = resp.body; - }); - }); - }); - - it('Logs out by pressing OK when unsaved changes on exercise mode', () => { - cy.login(studentOne); - - const exerciseID = modelingExercise.id!; - cy.visit(`/courses/${course.id}/exercises`); - courseOverview.startExercise(exerciseID); - courseOverview.openRunningExercise(exerciseID); - modelingExerciseEditor.addComponentToModel(exerciseID, 1); - modelingExerciseEditor.addComponentToModel(exerciseID, 2); - navigationBar.logout(); - - cy.on('window:confirm', (text) => { - expect(text).to.contains('You have unsaved changes'); - return true; - }); - cy.url().should('equal', Cypress.config().baseUrl + '/'); - }); - - it('Stays logged in by pressing cancel when trying to logout during unsaved changes on exercise mode', () => { - cy.login(studentTwo); - - const exerciseID = modelingExercise.id!; - cy.visit(`/courses/${course.id}/exercises`); - courseOverview.startExercise(exerciseID); - courseOverview.openRunningExercise(exerciseID); - modelingExerciseEditor.addComponentToModel(exerciseID, 1); - modelingExerciseEditor.addComponentToModel(exerciseID, 2); - navigationBar.logout(); - - cy.on('window:confirm', (text) => { - expect(text).to.contains('You have unsaved changes'); - return false; - }); - cy.url().should('not.equal', Cypress.config().baseUrl + '/'); - }); - - after(() => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/SystemHealth.cy.ts b/src/test/cypress/e2e/SystemHealth.cy.ts deleted file mode 100644 index 21a8d1b46943..000000000000 --- a/src/test/cypress/e2e/SystemHealth.cy.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { admin } from '../support/users'; - -describe.skip('Check artemis system health', () => { - beforeEach('Login as admin and visit system health page', () => { - cy.login(admin, '/admin/health'); - }); - - it('Checks continuous integration health', () => { - cy.get('#healthCheck #continuousIntegrationServer .status').contains('UP'); - }); - - it('Checks version control health', () => { - cy.get('#healthCheck #versionControlServer .status').contains('UP'); - }); - - it('Checks user management health', () => { - cy.get('#healthCheck #userManagement .status').contains('UP'); - }); - - it('Checks database health', () => { - cy.get('#healthCheck #db .status').contains('UP'); - }); - - it('Checks hazelcast health', () => { - cy.get('#healthCheck #hazelcast .status').contains('UP'); - }); - - it('Checks ping health', () => { - cy.get('#healthCheck #ping .status').contains('UP'); - }); - - it('Checks readiness health', () => { - cy.get('#healthCheck #readinessState .status').contains('UP'); - }); - - it('Checks websocket broker health', () => { - cy.get('#healthCheck #websocketBroker .status').contains('UP'); - }); - - it('Checks websocket connection health', () => { - cy.get('#healthCheck #websocketConnection .status').contains('Connected'); - }); -}); diff --git a/src/test/cypress/e2e/course/CourseExercise.cy.ts b/src/test/cypress/e2e/course/CourseExercise.cy.ts deleted file mode 100644 index f07bb65a0551..000000000000 --- a/src/test/cypress/e2e/course/CourseExercise.cy.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Course } from 'app/entities/course.model'; -import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; - -import multipleChoiceQuizTemplate from '../../fixtures/exercise/quiz/multiple_choice/template.json'; -import { courseManagementAPIRequest, courseOverview, exerciseAPIRequest } from '../../support/artemis'; -import { admin } from '../../support/users'; -import { convertModelAfterMultiPart } from '../../support/utils'; - -describe.skip('Course Exercise', () => { - let course: Course; - - before('Create course', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse().then((response) => { - course = convertModelAfterMultiPart(response); - }); - }); - - describe('Search Exercise', () => { - let exercise1: QuizExercise; - let exercise2: QuizExercise; - let exercise3: QuizExercise; - - before('Create Exercises', () => { - exerciseAPIRequest.createQuizExercise({ course }, [multipleChoiceQuizTemplate], 'Course Exercise Quiz 1').then((response) => { - exercise1 = convertModelAfterMultiPart(response); - }); - exerciseAPIRequest.createQuizExercise({ course }, [multipleChoiceQuizTemplate], 'Course Exercise Quiz 2').then((response) => { - exercise2 = convertModelAfterMultiPart(response); - }); - exerciseAPIRequest.createQuizExercise({ course }, [multipleChoiceQuizTemplate], 'Course Exercise 3').then((response) => { - exercise3 = convertModelAfterMultiPart(response); - }); - }); - - it('should filter exercises based on title', () => { - cy.visit(`/courses/${course.id}/exercises`); - courseOverview.getExercise(exercise1.title!).should('be.visible'); - courseOverview.getExercise(exercise2.title!).should('be.visible'); - courseOverview.getExercise(exercise3.title!).should('be.visible'); - courseOverview.search('Course Exercise Quiz'); - courseOverview.getExercise(exercise1.title!).should('be.visible'); - courseOverview.getExercise(exercise2.title!).should('be.visible'); - courseOverview.getExercise(exercise3.title!).should('not.exist'); - }); - - after('Delete Exercises', () => { - exerciseAPIRequest.deleteQuizExercise(exercise1.id!); - exerciseAPIRequest.deleteQuizExercise(exercise2.id!); - exerciseAPIRequest.deleteQuizExercise(exercise3.id!); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/course/CourseManagement.cy.ts b/src/test/cypress/e2e/course/CourseManagement.cy.ts deleted file mode 100644 index 9c565a66a275..000000000000 --- a/src/test/cypress/e2e/course/CourseManagement.cy.ts +++ /dev/null @@ -1,308 +0,0 @@ -import { Interception } from 'cypress/types/net-stubbing'; -import dayjs from 'dayjs/esm'; - -import { Course } from 'app/entities/course.model'; - -import { courseCreation, courseManagement, courseManagementAPIRequest, navigationBar } from '../../support/artemis'; -import { admin, studentOne } from '../../support/users'; -import { convertBooleanToCheckIconClass, convertModelAfterMultiPart, dayjsToString, generateUUID, trimDate } from '../../support/utils'; - -// Common primitives -const courseData = { - title: '', - shortName: '', - description: 'Lore Impsum', - startDate: dayjs(), - endDate: dayjs().add(1, 'day'), - testCourse: true, - semester: 'SS23', - maxPoints: 40, - programmingLanguage: 'JAVA', - customizeGroupNames: false, - studentGroupName: Cypress.env('studentGroupName'), - tutorGroupName: Cypress.env('tutorGroupName'), - editorGroupName: Cypress.env('editorGroupName'), - instructorGroupName: Cypress.env('instructorGroupName'), - enableComplaints: true, - maxComplaints: 5, - maxTeamComplaints: 3, - maxComplaintTimeDays: 6, - enableMoreFeedback: true, - maxRequestMoreFeedbackTimeDays: 4, - presentationScoreEnabled: true, - presentationScore: 10, -}; - -const editedCourseData = { - title: '', - testCourse: false, -}; - -const allowGroupCustomization: boolean = Cypress.env('allowGroupCustomization'); -const dateFormat = 'MMM D, YYYY HH:mm'; - -describe.skip('Course management', () => { - describe('Manual student selection', () => { - let course: Course; - - before('Create course', () => { - cy.login(admin, '/'); - const uid = generateUUID(); - courseData.title = 'Course ' + uid; - courseData.shortName = 'cypress' + uid; - courseManagementAPIRequest.createCourse({ courseName: courseData.title, courseShortName: courseData.shortName }).then((response) => { - course = convertModelAfterMultiPart(response); - }); - }); - - it('Manually adds and removes a student', () => { - const username = studentOne.username; - navigationBar.openCourseManagement(); - courseManagement.openCourse(course.id!); - courseManagement.addStudentToCourse(studentOne); - courseManagement.getRegisteredStudents().contains(username).should('be.visible'); - navigationBar.openCourseManagement(); - courseManagement.openCourse(course.id!); - courseManagement.getCourseStudentGroupName().contains(`artemis-${course.shortName}-students (1)`); - - navigationBar.openCourseManagement(); - courseManagement.openStudentOverviewOfCourse(course.id!); - courseManagement.removeFirstUser(); - courseManagement.getRegisteredStudents().contains(username).should('not.exist'); - navigationBar.openCourseManagement(); - courseManagement.openCourse(course.id!); - courseManagement.getCourseStudentGroupName().contains(`artemis-${course.shortName}-students (0)`); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); - }); - - describe('Course creation', () => { - let course: Course; - let course2: Course; - - beforeEach('Set course title and shortname', () => { - cy.login(admin, '/'); - const uid = generateUUID(); - courseData.title = 'Course ' + uid; - courseData.shortName = 'cypress' + uid; - }); - - it('Creates a new course', () => { - navigationBar.openCourseManagement(); - courseManagement.openCourseCreation(); - courseCreation.setTitle(courseData.title); - courseCreation.setShortName(courseData.shortName); - courseCreation.setDescription(courseData.description); - courseCreation.setStartDate(courseData.startDate); - courseCreation.setEndDate(courseData.endDate); - courseCreation.setTestCourse(courseData.testCourse); - courseCreation.setSemester(courseData.semester); - courseCreation.setCourseMaxPoints(courseData.maxPoints); - courseCreation.setProgrammingLanguage(courseData.programmingLanguage); - courseCreation.setCustomizeGroupNames(courseData.customizeGroupNames); - courseCreation.setEnableComplaints(courseData.enableComplaints); - courseCreation.setMaxComplaints(courseData.maxComplaints); - courseCreation.setMaxTeamComplaints(courseData.maxTeamComplaints); - courseCreation.setMaxComplaintsTimeDays(courseData.maxComplaintTimeDays); - courseCreation.setEnableMoreFeedback(courseData.enableMoreFeedback); - courseCreation.setMaxRequestMoreFeedbackTimeDays(courseData.maxRequestMoreFeedbackTimeDays); - courseCreation.submit().then((request: Interception) => { - const courseBody = request.response!.body; - course = courseBody; - expect(courseBody.title).to.eq(courseData.title); - expect(courseBody.shortName).to.eq(courseData.shortName); - expect(courseBody.description).to.eq(courseData.description); - expect(courseBody.testCourse).to.eq(courseData.testCourse); - expect(trimDate(courseBody.startDate)).to.eq(trimDate(dayjsToString(courseData.startDate))); - expect(trimDate(courseBody.endDate)).to.eq(trimDate(dayjsToString(courseData.endDate))); - expect(courseBody.semester).to.eq(courseData.semester); - expect(courseBody.maxPoints).to.eq(courseData.maxPoints); - expect(courseBody.defaultProgrammingLanguage).to.eq(courseData.programmingLanguage); - expect(courseBody.complaintsEnabled).to.eq(courseData.enableComplaints); - expect(courseBody.maxComplaints).to.eq(courseData.maxComplaints); - expect(courseBody.maxTeamComplaints).to.eq(courseData.maxTeamComplaints); - expect(courseBody.maxComplaintTimeDays).to.eq(courseData.maxComplaintTimeDays); - expect(courseBody.requestMoreFeedbackEnabled).to.eq(courseData.enableMoreFeedback); - expect(courseBody.studentGroupName).to.eq(`artemis-${courseData.shortName}-students`); - expect(courseBody.editorGroupName).to.eq(`artemis-${courseData.shortName}-editors`); - expect(courseBody.instructorGroupName).to.eq(`artemis-${courseData.shortName}-instructors`); - expect(courseBody.teachingAssistantGroupName).to.eq(`artemis-${courseData.shortName}-tutors`); - }); - courseManagement.getCourseHeaderTitle().scrollIntoView(); - courseManagement.getCourseHeaderTitle().contains(courseData.title).should('be.visible'); - courseManagement.getCourseHeaderDescription().contains(courseData.description); - courseManagement.getCourseTitle().contains(courseData.title); - courseManagement.getCourseShortName().contains(courseData.shortName); - courseManagement.getCourseStudentGroupName().contains(`artemis-${courseData.shortName}-students (0)`); - courseManagement.getCourseTutorGroupName().contains(`artemis-${courseData.shortName}-tutors (0)`); - courseManagement.getCourseEditorGroupName().contains(`artemis-${courseData.shortName}-editors (0)`); - courseManagement.getCourseInstructorGroupName().contains(`artemis-${courseData.shortName}-instructors (0)`); - courseManagement.getCourseStartDate().contains(courseData.startDate.format(dateFormat)); - courseManagement.getCourseEndDate().contains(courseData.endDate.format(dateFormat)); - courseManagement.getCourseSemester().contains(courseData.semester); - courseManagement.getCourseProgrammingLanguage().contains(courseData.programmingLanguage); - courseManagement.getCourseTestCourse().find(convertBooleanToCheckIconClass(courseData.testCourse)).should('exist'); - courseManagement.getCourseMaxComplaints().contains(courseData.maxComplaints); - courseManagement.getCourseMaxTeamComplaints().contains(courseData.maxTeamComplaints); - courseManagement.getMaxComplaintTimeDays().contains(courseData.maxComplaintTimeDays); - courseManagement.getMaxRequestMoreFeedbackTimeDays().contains(courseData.maxRequestMoreFeedbackTimeDays); - }); - - if (allowGroupCustomization) { - it('Creates a new course with custom groups', () => { - navigationBar.openCourseManagement(); - courseManagement.openCourseCreation(); - courseCreation.setTitle(courseData.title); - courseCreation.setShortName(courseData.shortName); - courseCreation.setTestCourse(courseData.testCourse); - courseCreation.setCustomizeGroupNames(true); - courseCreation.setStudentGroup(courseData.studentGroupName); - courseCreation.setTutorGroup(courseData.tutorGroupName); - courseCreation.setEditorGroup(courseData.editorGroupName); - courseCreation.setInstructorGroup(courseData.instructorGroupName); - courseCreation.submit().then((request: Interception) => { - const courseBody = request.response!.body; - course2 = courseBody; - expect(courseBody.title).to.eq(courseData.title); - expect(courseBody.shortName).to.eq(courseData.shortName); - expect(courseBody.testCourse).to.eq(courseData.testCourse); - expect(courseBody.studentGroupName).to.eq(courseData.studentGroupName); - expect(courseBody.teachingAssistantGroupName).to.eq(courseData.tutorGroupName); - expect(courseBody.editorGroupName).to.eq(courseData.editorGroupName); - expect(courseBody.instructorGroupName).to.eq(courseData.instructorGroupName); - }); - courseManagement.getCourseHeaderTitle().scrollIntoView(); - courseManagement.getCourseHeaderTitle().contains(courseData.title).should('be.visible'); - courseManagement.getCourseTitle().contains(courseData.title); - courseManagement.getCourseShortName().contains(courseData.shortName); - courseManagement.getCourseTestCourse().find(convertBooleanToCheckIconClass(courseData.testCourse)).should('exist'); - courseManagement.getCourseStudentGroupName().contains(courseData.studentGroupName); - courseManagement.getCourseTutorGroupName().contains(courseData.tutorGroupName); - courseManagement.getCourseEditorGroupName().contains(courseData.editorGroupName); - courseManagement.getCourseInstructorGroupName().contains(courseData.instructorGroupName); - }); - } - - after('Delete courses', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - courseManagementAPIRequest.deleteCourse(course2, admin); - }); - }); - - describe('Course edit', () => { - let course: Course; - - before('Create course', () => { - cy.login(admin, '/'); - const uid = generateUUID(); - courseData.title = 'Course ' + uid; - courseData.shortName = 'cypress' + uid; - courseManagementAPIRequest.createCourse({ courseName: courseData.title, courseShortName: courseData.shortName }).then((response) => { - course = convertModelAfterMultiPart(response); - }); - }); - - it('Edits a existing course', () => { - const uid = generateUUID(); - editedCourseData.title = 'Course ' + uid; - - navigationBar.openCourseManagement(); - courseManagement.openCourse(course.id!); - courseManagement.openCourseEdit(); - - courseCreation.setTitle(editedCourseData.title); - courseCreation.setTestCourse(editedCourseData.testCourse); - - courseCreation.update().then((request: Interception) => { - course = request.response!.body; - expect(course.title).to.eq(editedCourseData.title); - expect(course.shortName).to.eq(courseData.shortName); - expect(course.testCourse).to.eq(editedCourseData.testCourse); - }); - courseManagement.getCourseHeaderTitle().scrollIntoView(); - courseManagement.getCourseHeaderTitle().contains(editedCourseData.title).should('be.visible'); - courseManagement.getCourseTitle().contains(editedCourseData.title); - courseManagement.getCourseShortName().contains(courseData.shortName); - courseManagement.getCourseTestCourse().find(convertBooleanToCheckIconClass(editedCourseData.testCourse)).should('exist'); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); - }); - - describe('Course deletion', () => { - let course: Course; - - before('Create course', () => { - cy.login(admin, '/'); - courseManagementAPIRequest.createCourse().then((response) => { - course = convertModelAfterMultiPart(response); - }); - }); - - it('Deletes an existing course', () => { - navigationBar.openCourseManagement(); - courseManagement.openCourse(course.id!); - courseManagement.deleteCourse(course); - courseManagement.getCourse(course.id!).should('not.exist'); - }); - }); - - describe.only('Course icon deletion', () => { - describe('Course within icon', () => { - let course: Course; - - before('Creates course with icon', () => { - cy.login(admin, '/'); - cy.fixture('course/icon.png', 'base64') - .then(Cypress.Blob.base64StringToBlob) - .then((blob) => { - courseManagementAPIRequest.createCourse({ iconFileName: 'icon.png', iconFile: blob }).then((response) => { - course = convertModelAfterMultiPart(response); - }); - }); - }); - - it('Deletes an existing course icon', () => { - navigationBar.openCourseManagement(); - courseManagement.openCourse(course.id!); - courseManagement.clickEditCourse(); - courseManagement.removeIconFromCourse(); - courseManagement.updateCourse(course).then(() => { - courseManagement.clickEditCourse(); - courseManagement.checkCourseHasNoIcon(); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); - }); - - describe('Course without icon', () => { - let course: Course; - - before('Creates course without icon', () => { - cy.login(admin, '/'); - courseManagementAPIRequest.createCourse().then((response) => { - course = convertModelAfterMultiPart(response); - }); - }); - - it('Deletes not existing course icon', () => { - navigationBar.openCourseManagement(); - courseManagement.openCourse(course.id!); - courseManagement.clickEditCourse(); - courseManagement.checkCourseHasNoIcon(); - }); - - after('Delete courses', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); - }); - }); -}); diff --git a/src/test/cypress/e2e/course/CourseMessages.cy.ts b/src/test/cypress/e2e/course/CourseMessages.cy.ts deleted file mode 100644 index 3c156e961df5..000000000000 --- a/src/test/cypress/e2e/course/CourseMessages.cy.ts +++ /dev/null @@ -1,428 +0,0 @@ -import { Course } from 'app/entities/course.model'; -import { Channel } from 'app/entities/metis/conversation/channel.model'; -import { GroupChat } from 'app/entities/metis/conversation/group-chat.model'; - -import { communicationAPIRequest, courseManagementAPIRequest, courseMessages, examAPIRequests, exerciseAPIRequest } from '../../support/artemis'; -import { admin, instructor, studentOne, studentTwo, tutor, users } from '../../support/users'; -import { convertModelAfterMultiPart, generateUUID, titleLowercase } from '../../support/utils'; - -describe.skip('Course messages', () => { - let course: Course; - - before('Create course', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse().then((response) => { - course = convertModelAfterMultiPart(response); - courseManagementAPIRequest.addInstructorToCourse(course, instructor); - courseManagementAPIRequest.addTutorToCourse(course, tutor); - courseManagementAPIRequest.addStudentToCourse(course, studentOne); - courseManagementAPIRequest.addStudentToCourse(course, studentTwo); - }); - }); - - it('accepts code of conduct', () => { - cy.login(instructor, `/courses/${course.id}/messages`); - courseMessages.acceptCodeOfConductButton(); - cy.login(studentOne, `/courses/${course.id}/messages`); - courseMessages.acceptCodeOfConductButton(); - cy.login(studentTwo, `/courses/${course.id}/messages`); - courseMessages.acceptCodeOfConductButton(); - cy.login(tutor, `/courses/${course.id}/messages`); - courseMessages.acceptCodeOfConductButton(); - }); - - describe('Channel messages', () => { - describe('Create channel', () => { - it('check for pre-created channels', () => { - cy.login(instructor, `/courses/${course.id}/messages`); - courseMessages.browseChannelsButton(); - courseMessages.checkChannelsExists('tech-support'); - courseMessages.checkChannelsExists('organization'); - courseMessages.checkChannelsExists('random'); - courseMessages.checkChannelsExists('announcement'); - }); - - it('instructors should be able to create public announcement channel', () => { - cy.login(instructor, `/courses/${course.id}/messages`); - const name = 'public-ancmnt-ch'; - courseMessages.createChannelButton(); - courseMessages.setName(name); - courseMessages.setDescription('A public announcement channel'); - courseMessages.setPublic(); - courseMessages.setAnnouncementChannel(); - courseMessages.createChannel(true, true); - courseMessages.getName().contains(name); - }); - - it('instructors should be able to create private announcement channel', () => { - cy.login(instructor, `/courses/${course.id}/messages`); - const name = 'private-ancmnt-ch'; - courseMessages.createChannelButton(); - courseMessages.setName(name); - courseMessages.setDescription('A private announcement channel'); - courseMessages.setPrivate(); - courseMessages.setAnnouncementChannel(); - courseMessages.createChannel(true, false); - courseMessages.getName().contains(name); - }); - - it('instructors should be able to create public unrestricted channel', () => { - cy.login(instructor, `/courses/${course.id}/messages`); - const name = 'public-unrstct-ch'; - courseMessages.createChannelButton(); - courseMessages.setName(name); - courseMessages.setDescription('A public unrestricted channel'); - courseMessages.setPublic(); - courseMessages.setUnrestrictedChannel(); - courseMessages.createChannel(false, true); - courseMessages.getName().contains(name); - }); - - it('instructors should be able to create private unrestricted channel', () => { - cy.login(instructor, `/courses/${course.id}/messages`); - const name = 'private-unrstct-ch'; - courseMessages.createChannelButton(); - courseMessages.setName(name); - courseMessages.setDescription('A public unrestricted channel'); - courseMessages.setPrivate(); - courseMessages.setUnrestrictedChannel(); - courseMessages.createChannel(false, false); - courseMessages.getName().contains(name); - }); - - it('instructors should not be able to create channel with uppercase name', () => { - cy.login(instructor, `/courses/${course.id}/messages`); - const name = 'Forbidden Name'; - courseMessages.createChannelButton(); - courseMessages.setName(name); - courseMessages.getError().contains('Names can only contain lowercase letters'); - }); - - it('instructors should not be able to create channel with name longer than 30 chars', () => { - cy.login(instructor, `/courses/${course.id}/messages`); - const name = 'way-way-way-too-long-channel-title'; - courseMessages.createChannelButton(); - courseMessages.setName(name); - courseMessages.getError().contains('Name can be max 30 characters long!'); - }); - - it('check that channel is created, when a lecture is created', () => { - cy.login(admin); - courseManagementAPIRequest.createLecture(course, 'Test Lecture'); - cy.login(instructor, `/courses/${course.id}/messages`); - courseMessages.browseLectureChannelsButton(); - courseMessages.checkChannelsExists('lecture-test-lecture'); - }); - - it('check that channel is created, when an exercise is created', () => { - cy.login(admin); - exerciseAPIRequest.createTextExercise({ course }, 'Test Exercise'); - cy.login(instructor, `/courses/${course.id}/messages`); - courseMessages.browseExerciseChannelsButton(); - courseMessages.checkChannelsExists('exercise-test-exercise'); - }); - - it('check that channel is created, when an exam is created', () => { - cy.login(admin); - const examTitle = 'exam' + generateUUID(); - examAPIRequests.createExam({ course, title: examTitle }); - cy.login(instructor, `/courses/${course.id}/messages`); - courseMessages.browseExamChannelsButton(); - courseMessages.checkChannelsExists(titleLowercase(examTitle)); - }); - }); - - describe('Edit channel', () => { - let channel: Channel; - before('create channel', () => { - cy.login(admin); - communicationAPIRequest.createCourseMessageChannel(course, 'test-channel', 'Test Channel', true, true).then((response) => { - channel = response.body; - communicationAPIRequest.joinUserIntoChannel(course, channel.id!, instructor); - }); - }); - - it('instructors should be able to edit a channel', () => { - cy.login(instructor, `/courses/${course.id}/messages?conversationId=${channel.id}`); - const newName = 'new-test-name'; - const topic = 'test-topic'; - courseMessages.getName().click(); - courseMessages.editName(newName); - courseMessages.editTopic(topic); - courseMessages.editDescription('New Description'); - courseMessages.closeEditPanel(); - cy.reload(); - courseMessages.getName().contains(newName); - courseMessages.getTopic().contains(topic); - }); - }); - - describe('Join channel', () => { - let channel: Channel; - before('create channel', () => { - cy.login(admin); - communicationAPIRequest.createCourseMessageChannel(course, 'join-test-channel', 'Join Test Channel', true, true).then((response) => { - channel = response.body; - }); - }); - - it('student should be joined into pre-created channels automatically', () => { - cy.login(studentOne, `/courses/${course.id}/messages`); - courseMessages.browseChannelsButton(); - courseMessages.getChannelIdByName('tech-support').then((response) => { - const techSupportChannelId = Number(response!); - courseMessages.checkBadgeJoined(techSupportChannelId).should('exist').contains('Joined'); - }); - courseMessages.getChannelIdByName('random').then((response) => { - const techSupportChannelId = Number(response!); - courseMessages.checkBadgeJoined(techSupportChannelId).should('exist').contains('Joined'); - }); - courseMessages.getChannelIdByName('announcement').then((response) => { - const techSupportChannelId = Number(response!); - courseMessages.checkBadgeJoined(techSupportChannelId).should('exist').contains('Joined'); - }); - courseMessages.getChannelIdByName('organization').then((response) => { - const techSupportChannelId = Number(response!); - courseMessages.checkBadgeJoined(techSupportChannelId).should('exist').contains('Joined'); - }); - }); - - it('student should be able to join a public channel', () => { - cy.login(studentOne, `/courses/${course.id}/messages`); - courseMessages.browseChannelsButton(); - courseMessages.joinChannel(channel.id!); - courseMessages.checkBadgeJoined(channel.id!).should('exist').contains('Joined'); - }); - - it('student should be able to leave a public channel', () => { - cy.login(studentOne, `/courses/${course.id}/messages`); - courseMessages.browseChannelsButton(); - courseMessages.leaveChannel(channel.id!); - courseMessages.checkBadgeJoined(channel.id!).should('not.exist'); - }); - }); - - describe('Write/edit/delete message in channel', () => { - let channel: Channel; - before('create channel', () => { - cy.login(admin); - communicationAPIRequest.createCourseMessageChannel(course, 'write-test-channel', 'Write Test Channel', false, true).then((response) => { - channel = response.body; - communicationAPIRequest.joinUserIntoChannel(course, channel.id!, studentOne); - }); - }); - - it('student should be able to write message in channel', () => { - cy.login(studentOne, `/courses/${course.id}/messages?conversationId=${channel.id}`); - const messageText = 'Student Test Message'; - courseMessages.writeMessage(messageText); - courseMessages.save().then((interception) => { - const message = interception.response!.body; - courseMessages.checkMessage(message.id, messageText); - }); - }); - - it('student should be able to edit message in channel', () => { - cy.login(studentOne, `/courses/${course.id}/messages?conversationId=${channel.id}`); - const messageText = 'Student Edit Test Message'; - communicationAPIRequest.createCourseMessage(course, channel.id!, 'channel', messageText).then((response) => { - const message = response.body; - const newMessage = 'Edited Text'; - courseMessages.editMessage(message.id, newMessage); - courseMessages.checkMessage(message.id, newMessage); - courseMessages.getSinglePost(message.id).find('.edited-text').should('exist'); - }); - }); - - it('student should be able to delete message in channel', () => { - cy.login(studentOne, `/courses/${course.id}/messages?conversationId=${channel.id}`); - const messageText = 'Student Edit Test Message'; - communicationAPIRequest.createCourseMessage(course, channel.id!, 'channel', messageText).then((response) => { - const message = response.body; - courseMessages.checkMessage(message.id, messageText); - courseMessages.deleteMessage(message.id); - courseMessages.getSinglePost(message.id).should('not.exist'); - }); - }); - }); - }); - - describe('Group chats', () => { - let instructorName: string; - let tutorName: string; - let studentOneName: string; - let studentTwoName: string; - - before('Get usernames', () => { - cy.login(admin); - users.getUserInfo(instructor.username, (userInfo) => { - instructorName = userInfo.name; - }); - users.getUserInfo(tutor.username, (userInfo) => { - tutorName = userInfo.name; - }); - users.getUserInfo(studentOne.username, (userInfo) => { - studentOneName = userInfo.name; - }); - users.getUserInfo(studentTwo.username, (userInfo) => { - studentTwoName = userInfo.name; - }); - }); - - describe('Create group chat', () => { - it('instructors should be able to create group chat', () => { - cy.login(instructor, `/courses/${course.id}/messages`); - courseMessages.createGroupChatButton(); - courseMessages.addUserToGroupChat(studentOne.username); - courseMessages.addUserToGroupChat(studentTwo.username); - courseMessages.createGroupChat().then((interception) => { - const group = interception.response!.body; - courseMessages.listMembersButton(course.id!, group.id); - courseMessages.checkMemberList(studentOneName); - courseMessages.checkMemberList(studentTwoName); - courseMessages.closeEditPanel(); - }); - }); - - it('tutor should be able to create group chat', () => { - cy.login(tutor, `/courses/${course.id}/messages`); - courseMessages.createGroupChatButton(); - courseMessages.addUserToGroupChat(studentOne.username); - courseMessages.addUserToGroupChat(instructor.username); - courseMessages.createGroupChat().then((interception) => { - const group = interception.response!.body; - courseMessages.listMembersButton(course.id!, group.id); - courseMessages.checkMemberList(studentOneName); - courseMessages.checkMemberList(instructorName); - courseMessages.closeEditPanel(); - }); - }); - - it('student should be able to create group chat', () => { - cy.login(studentOne, `/courses/${course.id}/messages`); - courseMessages.createGroupChatButton(); - courseMessages.addUserToGroupChat(studentTwo.username); - courseMessages.addUserToGroupChat(tutor.username); - courseMessages.createGroupChat().then((interception) => { - const group = interception.response!.body; - courseMessages.listMembersButton(course.id!, group.id); - courseMessages.checkMemberList(studentTwoName); - courseMessages.checkMemberList(tutorName); - courseMessages.closeEditPanel(); - }); - }); - }); - - describe('Add to group chat', () => { - let groupChat: GroupChat; - before('create group chat', () => { - cy.login(admin); - communicationAPIRequest.createCourseMessageGroupChat(course, [studentOne.username, tutor.username]).then((response) => { - groupChat = response.body; - }); - }); - - it('tutor should be able to add user to group chat', () => { - cy.login(tutor, `/courses/${course.id}/messages?conversationId=${groupChat.id}`); - courseMessages.addUserToGroupChatButton(); - courseMessages.addUserToGroupChat(instructor.username); - courseMessages.updateGroupChat(); - - courseMessages.listMembersButton(course.id!, groupChat.id!); - courseMessages.checkMemberList(instructorName); - courseMessages.closeEditPanel(); - }); - - it('student should be able to add user to group chat', () => { - cy.login(studentOne, `/courses/${course.id}/messages?conversationId=${groupChat.id}`); - courseMessages.addUserToGroupChatButton(); - courseMessages.addUserToGroupChat(studentTwo.username); - courseMessages.updateGroupChat(); - - courseMessages.listMembersButton(course.id!, groupChat.id!); - courseMessages.checkMemberList(studentTwoName); - courseMessages.closeEditPanel(); - }); - }); - - describe('Leave group chat', () => { - let groupChat: GroupChat; - const groupChatName = 'leave-test'; - - before('create group chat', () => { - cy.login(admin); - communicationAPIRequest.createCourseMessageGroupChat(course, [studentOne.username, tutor.username]).then((response) => { - groupChat = response.body; - communicationAPIRequest.updateCourseMessageGroupChatName(course, groupChat, groupChatName); - }); - }); - - it('tutor should be able to leave group chat', () => { - cy.login(tutor, `/courses/${course.id}/messages?conversationId=${groupChat.id}`); - courseMessages.checkGroupChatExists(groupChatName, true); - courseMessages.listMembersButton(course.id!, groupChat.id!); - courseMessages.openSettingsTab(); - courseMessages.leaveGroupChat(); - cy.visit(`/courses/${course.id}/messages`); - courseMessages.checkGroupChatExists(groupChatName, false); - }); - - it('student should be able to leave group chat', () => { - cy.login(studentOne, `/courses/${course.id}/messages?conversationId=${groupChat.id}`); - courseMessages.checkGroupChatExists(groupChatName, true); - courseMessages.listMembersButton(course.id!, groupChat.id!); - courseMessages.openSettingsTab(); - courseMessages.leaveGroupChat(); - cy.visit(`/courses/${course.id}/messages`); - courseMessages.checkGroupChatExists(groupChatName, false); - }); - }); - - describe('Write/edit/delete message in group chat', () => { - let groupChat: GroupChat; - before('create group chat', () => { - cy.login(admin); - communicationAPIRequest.createCourseMessageGroupChat(course, [studentOne.username, tutor.username]).then((response) => { - groupChat = response.body; - }); - }); - - it('student should be able to write message in group chat', () => { - cy.login(studentOne, `/courses/${course.id}/messages?conversationId=${groupChat.id}`); - const messageText = 'Student Test Message'; - courseMessages.writeMessage(messageText); - courseMessages.save(true).then((interception) => { - const message = interception.response!.body; - courseMessages.checkMessage(message.id, messageText); - }); - }); - - it('student should be able to edit message in group chat', () => { - cy.login(studentOne, `/courses/${course.id}/messages?conversationId=${groupChat.id}`); - const messageText = 'Student Edit Test Message'; - communicationAPIRequest.createCourseMessage(course, groupChat.id!, 'groupChat', messageText).then((response) => { - const message = response.body; - const newMessage = 'Edited Text'; - courseMessages.editMessage(message.id, newMessage); - courseMessages.checkMessage(message.id, newMessage); - courseMessages.getSinglePost(message.id).find('.edited-text').should('exist'); - }); - }); - - it('student should be able to delete message in group chat', () => { - cy.login(studentOne, `/courses/${course.id}/messages?conversationId=${groupChat.id}`); - const messageText = 'Student Edit Test Message'; - communicationAPIRequest.createCourseMessage(course, groupChat.id!, 'groupChat', messageText).then((response) => { - const message = response.body; - courseMessages.checkMessage(message.id, messageText); - courseMessages.deleteMessage(message.id); - courseMessages.getSinglePost(message.id).should('not.exist'); - }); - }); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exam/ExamAssessment.cy.ts b/src/test/cypress/e2e/exam/ExamAssessment.cy.ts deleted file mode 100644 index 37c6a20822bc..000000000000 --- a/src/test/cypress/e2e/exam/ExamAssessment.cy.ts +++ /dev/null @@ -1,255 +0,0 @@ -import { Interception } from 'cypress/types/net-stubbing'; -import dayjs, { Dayjs } from 'dayjs/esm'; - -import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; - -import javaPartiallySuccessful from '../../fixtures/exercise/programming/java/partially_successful/submission.json'; -import { - courseAssessment, - courseManagementAPIRequest, - examAPIRequests, - examAssessment, - examExerciseGroupCreation, - examManagement, - examNavigation, - examParticipation, - examStartEnd, - exerciseAssessment, - modelingExerciseAssessment, - studentAssessment, -} from '../../support/artemis'; -import { Exercise, ExerciseType, ProgrammingExerciseAssessmentType } from '../../support/constants'; -import { admin, instructor, studentOne, tutor, users } from '../../support/users'; -import { convertModelAfterMultiPart } from '../../support/utils'; - -let exam: Exam; - -describe('Exam assessment', () => { - let course: Course; - let examEnd: Dayjs; - let programmingAssessmentSuccessful = false; - let modelingAssessmentSuccessful = false; - let textAssessmentSuccessful = false; - let studentOneName: string; - - before('Create course', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse({ customizeGroups: true }).then((response) => { - course = convertModelAfterMultiPart(response); - courseManagementAPIRequest.addStudentToCourse(course, studentOne); - courseManagementAPIRequest.addTutorToCourse(course, tutor); - courseManagementAPIRequest.addInstructorToCourse(course, instructor); - }); - users.getUserInfo(studentOne.username, (userInfo) => { - studentOneName = userInfo.name; - }); - }); - - // For some reason the typing of cypress gets slower the longer the test runs, so we test the programming exercise first - describe('Programming exercise assessment', () => { - before('Prepare exam', () => { - examEnd = dayjs().add(2, 'minutes'); - prepareExam(course, examEnd, ExerciseType.PROGRAMMING); - }); - - it('Assess a programming exercise submission (MANUAL)', () => { - cy.login(instructor); - examManagement.verifySubmitted(course.id!, exam.id!, studentOneName); - cy.login(tutor); - startAssessing(course.id!, exam.id!, 175000); - examAssessment.addNewFeedback(2, 'Good job'); - examAssessment.submit(); - cy.login(studentOne, '/courses/' + course.id + '/exams/' + exam.id); - examParticipation.getResultScore().should('contain.text', '66.2%').and('be.visible'); - programmingAssessmentSuccessful = true; - }); - - it('Complaints about programming exercises assessment', () => { - if (programmingAssessmentSuccessful) { - handleComplaint(course, exam, false, ExerciseType.PROGRAMMING); - } - }); - }); - - describe('Modeling exercise assessment', () => { - before('Prepare exam', () => { - examEnd = dayjs().add(45, 'seconds'); - prepareExam(course, examEnd, ExerciseType.MODELING); - }); - - it('Assess a modeling exercise submission', () => { - cy.login(instructor); - examManagement.verifySubmitted(course.id!, exam.id!, studentOneName); - cy.login(tutor); - startAssessing(course.id!, exam.id!, 60000); - modelingExerciseAssessment.addNewFeedback(5, 'Good'); - modelingExerciseAssessment.openAssessmentForComponent(1); - modelingExerciseAssessment.assessComponent(-1, 'Wrong'); - modelingExerciseAssessment.clickNextAssessment(); - modelingExerciseAssessment.assessComponent(0, 'Neutral'); - modelingExerciseAssessment.clickNextAssessment(); - examAssessment.submitModelingAssessment().then((assessmentResponse: Interception) => { - expect(assessmentResponse.response?.statusCode).to.equal(200); - }); - cy.login(studentOne, '/courses/' + course.id + '/exams/' + exam.id); - examParticipation.getResultScore().should('contain.text', '40%').and('be.visible'); - modelingAssessmentSuccessful = true; - }); - - it('Complaints about modeling exercises assessment', () => { - if (modelingAssessmentSuccessful) { - handleComplaint(course, exam, true, ExerciseType.MODELING); - } - }); - }); - - describe('Text exercise assessment', () => { - before('Prepare exam', () => { - examEnd = dayjs().add(40, 'seconds'); - prepareExam(course, examEnd, ExerciseType.TEXT); - }); - - it('Assess a text exercise submission', () => { - cy.login(instructor); - examManagement.verifySubmitted(course.id!, exam.id!, studentOneName); - cy.login(tutor); - startAssessing(course.id!, exam.id!, 60000); - examAssessment.addNewFeedback(7, 'Good job'); - examAssessment.submitTextAssessment().then((assessmentResponse: Interception) => { - expect(assessmentResponse.response!.statusCode).to.equal(200); - }); - cy.login(studentOne, '/courses/' + course.id + '/exams/' + exam.id); - examParticipation.getResultScore().should('contain.text', '70%').and('be.visible'); - textAssessmentSuccessful = true; - }); - - it('Complaints about text exercises assessment', () => { - if (textAssessmentSuccessful) { - handleComplaint(course, exam, false, ExerciseType.TEXT); - } - }); - }); - - describe.only('Quiz exercise assessment', () => { - let resultDate: Dayjs; - - before('Prepare exam', () => { - examEnd = dayjs().add(30, 'seconds'); - resultDate = examEnd.add(5, 'seconds'); - prepareExam(course, examEnd, ExerciseType.QUIZ); - }); - - it.skip('Assesses quiz automatically', () => { - cy.login(instructor); - examManagement.verifySubmitted(course.id!, exam.id!, studentOneName); - if (dayjs().isBefore(examEnd)) { - cy.wait(examEnd.diff(dayjs(), 'ms') + 1000); - } - examManagement.openAssessmentDashboard(course.id!, exam.id!, 60000); - cy.visit(`/course-management/${course.id}/exams/${exam.id}/assessment-dashboard`); - courseAssessment.clickEvaluateQuizzes().its('response.statusCode').should('eq', 200); - if (dayjs().isBefore(resultDate)) { - cy.wait(resultDate.diff(dayjs(), 'ms') + 1000); - } - examManagement.checkQuizSubmission(course.id!, exam.id!, studentOneName, '50%'); - cy.login(studentOne, '/courses/' + course.id + '/exams/' + exam.id); - examParticipation.getResultScore().should('contain.text', '50%').and('be.visible'); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); - -function prepareExam(course: Course, end: dayjs.Dayjs, exerciseType: ExerciseType) { - cy.login(admin); - const resultDate = end.add(1, 'second'); - const examConfig: Exam = { - course, - startDate: dayjs(), - endDate: end, - numberOfCorrectionRoundsInExam: 1, - examStudentReviewStart: resultDate, - examStudentReviewEnd: resultDate.add(1, 'minute'), - publishResultsDate: resultDate, - gracePeriod: 10, - }; - examAPIRequests.createExam(examConfig).then((examResponse) => { - exam = examResponse.body; - examAPIRequests.registerStudentForExam(exam, studentOne); - let additionalData = {}; - switch (exerciseType) { - case ExerciseType.PROGRAMMING: - additionalData = { submission: javaPartiallySuccessful, progExerciseAssessmentType: ProgrammingExerciseAssessmentType.SEMI_AUTOMATIC }; - break; - case ExerciseType.TEXT: - additionalData = { textFixture: 'loremIpsum-short.txt' }; - break; - case ExerciseType.QUIZ: - additionalData = { quizExerciseID: 0 }; - break; - } - - examExerciseGroupCreation.addGroupWithExercise(exam, exerciseType, additionalData).then((response) => { - examAPIRequests.generateMissingIndividualExams(exam); - examAPIRequests.prepareExerciseStartForExam(exam); - makeExamSubmission(course, exam, response); - }); - }); -} - -function makeExamSubmission(course: Course, exam: Exam, exercise: Exercise) { - examParticipation.startParticipation(studentOne, course, exam); - examNavigation.openExerciseAtIndex(0); - examParticipation.makeSubmission(exercise.id, exercise.type, exercise.additionalData); - cy.wait(2000); - examNavigation.handInEarly(); - examStartEnd.finishExam(); -} - -function startAssessing(courseID: number, examID: number, timeout: number) { - examManagement.openAssessmentDashboard(courseID, examID, timeout); - courseAssessment.clickExerciseDashboardButton(); - exerciseAssessment.clickHaveReadInstructionsButton(); - exerciseAssessment.clickStartNewAssessment(); - exerciseAssessment.getLockedMessage(); -} - -function handleComplaint(course: Course, exam: Exam, reject: boolean, exerciseType: ExerciseType) { - const complaintText = 'Lorem ipsum dolor sit amet'; - const complaintResponseText = ' consetetur sadipscing elitr'; - - cy.login(studentOne, '/courses/' + course.id + '/exams/' + exam.id); - studentAssessment.startComplaint(); - studentAssessment.enterComplaint(complaintText); - studentAssessment.submitComplaint(); - cy.get('.message').should('contain.text', 'Your complaint has been submitted'); - - cy.login(instructor, '/course-management/' + course.id + '/exams'); - examManagement.openAssessmentDashboard(course.id!, exam.id!); - courseAssessment.clickExerciseDashboardButton(); - exerciseAssessment.clickHaveReadInstructionsButton(); - - exerciseAssessment.clickEvaluateComplaint(); - exerciseAssessment.getComplaintText().should('have.value', complaintText); - if (reject) { - examAssessment.rejectComplaint(complaintResponseText, true, exerciseType); - } else { - examAssessment.acceptComplaint(complaintResponseText, true, exerciseType); - } - if (exerciseType == ExerciseType.MODELING) { - cy.get('.message').should('contain.text', 'Response to complaint has been submitted'); - } else { - cy.get('.message').should('contain.text', 'The assessment was updated successfully.'); - } - - cy.login(studentOne, '/courses/' + course.id + '/exams/' + exam.id); - if (reject) { - studentAssessment.getComplaintBadge().should('contain.text', 'Complaint was rejected'); - } else { - studentAssessment.getComplaintBadge().should('contain.text', 'Complaint was accepted'); - } - studentAssessment.getComplaintResponse().should('have.value', complaintResponseText); -} diff --git a/src/test/cypress/e2e/exam/ExamCreationDeletion.cy.ts b/src/test/cypress/e2e/exam/ExamCreationDeletion.cy.ts deleted file mode 100644 index 9622cfd6fce4..000000000000 --- a/src/test/cypress/e2e/exam/ExamCreationDeletion.cy.ts +++ /dev/null @@ -1,184 +0,0 @@ -import { Interception } from 'cypress/types/net-stubbing'; -import dayjs from 'dayjs/esm'; - -import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; - -import { courseManagement, courseManagementAPIRequest, examAPIRequests, examCreation, examDetails, examManagement, navigationBar } from '../../support/artemis'; -import { admin } from '../../support/users'; -import { convertModelAfterMultiPart, dayjsToString, generateUUID, trimDate } from '../../support/utils'; - -// Common primitives -const examData = { - title: 'exam' + generateUUID(), - visibleDate: dayjs(), - startDate: dayjs().add(1, 'day'), - endDate: dayjs().add(2, 'day'), - numberOfExercisesInExam: 4, - examMaxPoints: 40, - startText: 'Exam start text', - endText: 'Exam end text', - confirmationStartText: 'Exam confirmation start text', - confirmationEndText: 'Exam confirmation end text', -}; - -const editedExamData = { - title: 'exam' + generateUUID(), - visibleDate: dayjs(), - startDate: dayjs().add(2, 'day'), - endDate: dayjs().add(4, 'day'), - numberOfExercisesInExam: 3, - examMaxPoints: 30, - startText: 'Edited exam start text', - endText: 'Edited exam end text', - confirmationStartText: 'Edited exam confirmation start text', - confirmationEndText: 'Edited exam confirmation end text', -}; - -const dateFormat = 'MMM D, YYYY HH:mm'; - -describe.skip('Exam creation/deletion', () => { - let course: Course; - let examId: number; - - before('Create course', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse().then((response) => { - course = convertModelAfterMultiPart(response); - }); - }); - - beforeEach(() => { - cy.login(admin, '/'); - }); - - it('Creates an exam', () => { - navigationBar.openCourseManagement(); - courseManagement.openExamsOfCourse(course.id!); - - examManagement.createNewExam(); - examCreation.setTitle(examData.title); - examCreation.setVisibleDate(examData.visibleDate); - examCreation.setStartDate(examData.startDate); - examCreation.setEndDate(examData.endDate); - examCreation.setNumberOfExercises(examData.numberOfExercisesInExam); - examCreation.setExamMaxPoints(examData.examMaxPoints); - - examCreation.setStartText(examData.startText); - examCreation.setEndText(examData.endText); - examCreation.setConfirmationStartText(examData.confirmationStartText); - examCreation.setConfirmationEndText(examData.confirmationEndText); - examCreation.submit().then((examResponse: Interception) => { - const examBody = examResponse.response!.body; - examId = examBody.id; - expect(examResponse.response!.statusCode).to.eq(201); - expect(examBody.testExam).to.be.false; - expect(trimDate(examBody.visibleDate)).to.eq(trimDate(dayjsToString(examData.visibleDate))); - expect(trimDate(examBody.startDate)).to.eq(trimDate(dayjsToString(examData.startDate))); - expect(trimDate(examBody.endDate)).to.eq(trimDate(dayjsToString(examData.endDate))); - expect(examBody.numberOfExercisesInExam).to.eq(examData.numberOfExercisesInExam); - expect(examBody.examMaxPoints).to.eq(examData.examMaxPoints); - expect(examBody.startText).to.eq(examData.startText); - expect(examBody.endText).to.eq(examData.endText); - expect(examBody.confirmationStartText).to.eq(examData.confirmationStartText); - expect(examBody.confirmationEndText).to.eq(examData.confirmationEndText); - cy.url().should('contain', `/exams/${examId}`); - }); - examManagement.getExamTitle().contains(examData.title); - examManagement.getExamVisibleDate().contains(examData.visibleDate.format(dateFormat)); - examManagement.getExamStartDate().contains(examData.startDate.format(dateFormat)); - examManagement.getExamEndDate().contains(examData.endDate.format(dateFormat)); - examManagement.getExamNumberOfExercises().contains(examData.numberOfExercisesInExam); - examManagement.getExamMaxPoints().contains(examData.examMaxPoints); - examManagement.getExamStartText().contains(examData.startText); - examManagement.getExamEndText().contains(examData.endText); - examManagement.getExamConfirmationStartText().contains(examData.confirmationStartText); - examManagement.getExamConfirmationEndText().contains(examData.confirmationEndText); - examManagement.getExamWorkingTime().contains('1d 0h'); - }); - - describe('Exam deletion', () => { - before('Create exam', () => { - examData.title = 'exam' + generateUUID(); - const examConfig: Exam = { - course, - title: examData.title, - }; - examAPIRequests.createExam(examConfig).then((examResponse) => { - examId = examResponse.body.id!; - }); - }); - - it('Deletes an existing exam', () => { - navigationBar.openCourseManagement(); - courseManagement.openExamsOfCourse(course.id!); - examManagement.openExam(examId); - examDetails.deleteExam(examData.title); - examManagement.getExamSelector(examData.title).should('not.exist'); - }); - }); - - describe('Edits an exam', () => { - before('Create exam', () => { - examData.title = 'exam' + generateUUID(); - const examConfig: Exam = { - course, - title: examData.title, - }; - examAPIRequests.createExam(examConfig).then((examResponse) => { - examId = examResponse.body.id!; - }); - }); - - it('Edits an existing exam', () => { - navigationBar.openCourseManagement(); - courseManagement.openExamsOfCourse(course.id!); - examManagement.openExam(examId); - examManagement.getExamTitle().contains(examData.title); - examManagement.clickEdit(); - - examCreation.setTitle(editedExamData.title); - examCreation.setVisibleDate(editedExamData.visibleDate); - examCreation.setStartDate(editedExamData.startDate); - examCreation.setEndDate(editedExamData.endDate); - examCreation.setNumberOfExercises(editedExamData.numberOfExercisesInExam); - examCreation.setExamMaxPoints(editedExamData.examMaxPoints); - - examCreation.setStartText(editedExamData.startText); - examCreation.setEndText(editedExamData.endText); - examCreation.setConfirmationStartText(editedExamData.confirmationStartText); - examCreation.setConfirmationEndText(editedExamData.confirmationEndText); - examCreation.update().then((examResponse: Interception) => { - const examBody = examResponse.response!.body; - examId = examBody.id; - expect(examResponse.response!.statusCode).to.eq(200); - expect(examBody.testExam).to.be.false; - expect(trimDate(examBody.visibleDate)).to.eq(trimDate(dayjsToString(editedExamData.visibleDate))); - expect(trimDate(examBody.startDate)).to.eq(trimDate(dayjsToString(editedExamData.startDate))); - expect(trimDate(examBody.endDate)).to.eq(trimDate(dayjsToString(editedExamData.endDate))); - expect(examBody.numberOfExercisesInExam).to.eq(editedExamData.numberOfExercisesInExam); - expect(examBody.examMaxPoints).to.eq(editedExamData.examMaxPoints); - expect(examBody.startText).to.eq(editedExamData.startText); - expect(examBody.endText).to.eq(editedExamData.endText); - expect(examBody.confirmationStartText).to.eq(editedExamData.confirmationStartText); - expect(examBody.confirmationEndText).to.eq(editedExamData.confirmationEndText); - cy.url().should('contain', `/exams/${examId}`); - }); - examManagement.getExamTitle().contains(editedExamData.title); - examManagement.getExamVisibleDate().contains(editedExamData.visibleDate.format(dateFormat)); - examManagement.getExamStartDate().contains(editedExamData.startDate.format(dateFormat)); - examManagement.getExamEndDate().contains(editedExamData.endDate.format(dateFormat)); - examManagement.getExamNumberOfExercises().contains(editedExamData.numberOfExercisesInExam); - examManagement.getExamMaxPoints().contains(editedExamData.examMaxPoints); - examManagement.getExamStartText().contains(editedExamData.startText); - examManagement.getExamEndText().contains(editedExamData.endText); - examManagement.getExamConfirmationStartText().contains(editedExamData.confirmationStartText); - examManagement.getExamConfirmationEndText().contains(editedExamData.confirmationEndText); - examManagement.getExamWorkingTime().contains('2d 0h'); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exam/ExamDateVerification.cy.ts b/src/test/cypress/e2e/exam/ExamDateVerification.cy.ts deleted file mode 100644 index f6cc2ee0bdea..000000000000 --- a/src/test/cypress/e2e/exam/ExamDateVerification.cy.ts +++ /dev/null @@ -1,151 +0,0 @@ -import dayjs from 'dayjs/esm'; - -import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; -import { ExerciseGroup } from 'app/entities/exercise-group.model'; - -import { - courseManagementAPIRequest, - courseOverview, - examAPIRequests, - examNavigation, - examParticipation, - examStartEnd, - exerciseAPIRequest, - textExerciseEditor, -} from '../../support/artemis'; -import { admin, studentOne } from '../../support/users'; -import { convertModelAfterMultiPart, generateUUID } from '../../support/utils'; - -describe.skip('Exam date verification', () => { - let course: Course; - let examTitle: string; - - before('Create course', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse().then((response) => { - course = convertModelAfterMultiPart(response); - courseManagementAPIRequest.addStudentToCourse(course, studentOne); - }); - }); - - beforeEach(() => { - examTitle = 'exam' + generateUUID(); - cy.login(admin, '/'); - }); - - describe('Exam timing', () => { - let exam: Exam; - it('Does not show exam before visible date', () => { - const examConfig: Exam = { - course, - title: examTitle, - visibleDate: dayjs().add(1, 'day'), - startDate: dayjs().add(2, 'days'), - endDate: dayjs().add(3, 'days'), - }; - examAPIRequests.createExam(examConfig).then((response) => { - exam = response.body; - }); - cy.login(studentOne, `/courses`); - cy.contains(examTitle).should('not.exist'); - cy.visit(`/courses/${course.id}`); - cy.url().should('contain', `${course.id}`); - cy.contains(examTitle).should('not.exist'); - }); - - it('Shows after visible date', () => { - const examConfig: Exam = { - course, - title: examTitle, - visibleDate: dayjs().subtract(5, 'days'), - startDate: dayjs().add(2, 'days'), - endDate: dayjs().add(3, 'days'), - }; - examAPIRequests.createExam(examConfig).then((response) => { - exam = response.body; - examAPIRequests.registerStudentForExam(exam, studentOne); - cy.login(studentOne, `/courses/${course.id}`); - cy.url().should('contain', `${course.id}`); - courseOverview.openExamsTab(); - courseOverview.openExam(exam.id!); - cy.url({ timeout: 40000 }).should('contain', `/exams/${exam.id}`); - }); - }); - - it('Student can start after start Date', () => { - let exerciseGroup: ExerciseGroup; - const examConfig: Exam = { - course, - title: examTitle, - visibleDate: dayjs().subtract(3, 'days'), - startDate: dayjs().subtract(2, 'days'), - endDate: dayjs().add(3, 'days'), - }; - examAPIRequests.createExam(examConfig).then((examResponse) => { - exam = examResponse.body; - examAPIRequests.registerStudentForExam(exam, studentOne); - examAPIRequests.addExerciseGroupForExam(exam).then((groupResponse) => { - exerciseGroup = groupResponse.body; - exerciseAPIRequest.createTextExercise({ exerciseGroup }).then((exerciseResponse) => { - const exercise = exerciseResponse.body; - examAPIRequests.generateMissingIndividualExams(exam); - examAPIRequests.prepareExerciseStartForExam(exam); - cy.login(studentOne, `/courses/${course.id}/exams`); - courseOverview.openExam(exam.id!); - cy.url().should('contain', `/exams/${exam.id}`); - cy.contains(exam.title!).should('be.visible'); - examStartEnd.startExam(); - examNavigation.openExerciseAtIndex(0); - cy.fixture('loremIpsum-short.txt').then((submission) => { - textExerciseEditor.typeSubmission(exercise.id!, submission); - }); - examNavigation.clickSave(); - }); - }); - }); - }); - - it('Exam ends after end time', () => { - let exerciseGroup: ExerciseGroup; - const examEnd = dayjs().add(30, 'seconds'); - const examConfig: Exam = { - course, - title: examTitle, - visibleDate: dayjs().subtract(3, 'days'), - startDate: dayjs().subtract(2, 'days'), - endDate: examEnd, - }; - examAPIRequests.createExam(examConfig).then((examResponse) => { - exam = examResponse.body; - examAPIRequests.registerStudentForExam(exam, studentOne); - examAPIRequests.addExerciseGroupForExam(exam).then((groupResponse) => { - exerciseGroup = groupResponse.body; - exerciseAPIRequest.createTextExercise({ exerciseGroup }).then((exerciseResponse) => { - const exercise = exerciseResponse.body; - examAPIRequests.generateMissingIndividualExams(exam); - examAPIRequests.prepareExerciseStartForExam(exam); - cy.login(studentOne, `/courses/${course.id}/exams`); - courseOverview.openExam(exam.id!); - cy.contains(exam.title!).should('be.visible'); - examStartEnd.startExam(); - examNavigation.openExerciseAtIndex(0); - cy.fixture('loremIpsum-short.txt').then((submissionText) => { - textExerciseEditor.typeSubmission(exercise.id!, submissionText); - }); - examNavigation.clickSave(); - if (examEnd.isAfter(dayjs())) { - cy.wait(examEnd.diff(dayjs())); - } - examParticipation.checkExamFinishedTitle(exam.title!); - examStartEnd.finishExam(); - }); - }); - }); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exam/ExamManagement.cy.ts b/src/test/cypress/e2e/exam/ExamManagement.cy.ts deleted file mode 100644 index f86fa782374e..000000000000 --- a/src/test/cypress/e2e/exam/ExamManagement.cy.ts +++ /dev/null @@ -1,184 +0,0 @@ -import { Interception } from 'cypress/types/net-stubbing'; - -import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; -import { ExerciseGroup } from 'app/entities/exercise-group.model'; - -import { - courseManagement, - courseManagementAPIRequest, - examAPIRequests, - examExerciseGroupCreation, - examExerciseGroups, - examManagement, - modelingExerciseCreation, - navigationBar, - programmingExerciseCreation, - quizExerciseCreation, - studentExamManagement, - textExerciseCreation, -} from '../../support/artemis'; -import { admin, instructor, studentOne } from '../../support/users'; -import { convertModelAfterMultiPart, generateUUID } from '../../support/utils'; - -describe.skip('Exam management', () => { - let course: Course; - let exam: Exam; - let createdGroup: ExerciseGroup; - let groupCount = 0; - - before('Create course', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse({ customizeGroups: true }).then((response) => { - course = convertModelAfterMultiPart(response); - courseManagementAPIRequest.addStudentToCourse(course, studentOne); - const examConfig: Exam = { - course, - title: 'Exam ' + generateUUID(), - }; - examAPIRequests.createExam(examConfig).then((examResponse) => { - exam = examResponse.body; - }); - }); - }); - - describe('Manage Group', () => { - let exerciseGroup: ExerciseGroup; - - before(() => { - cy.login(instructor); - examAPIRequests.addExerciseGroupForExam(exam).then((response) => { - exerciseGroup = response.body; - groupCount++; - }); - }); - - beforeEach(() => { - cy.login(instructor); - }); - - it('Create exercise group', () => { - cy.visit('/'); - navigationBar.openCourseManagement(); - courseManagement.openExamsOfCourse(course.id!); - examManagement.openExerciseGroups(exam.id!); - examExerciseGroups.shouldShowNumberOfExerciseGroups(groupCount); - examExerciseGroups.clickAddExerciseGroup(); - const groupName = 'Group 1'; - examExerciseGroupCreation.typeTitle(groupName); - examExerciseGroupCreation.isMandatoryBoxShouldBeChecked(); - examExerciseGroupCreation.clickSave().then((interception) => { - const group = interception.response!.body; - groupCount++; - examExerciseGroups.shouldHaveTitle(group.id, groupName); - examExerciseGroups.shouldShowNumberOfExerciseGroups(groupCount); - createdGroup = group; - }); - }); - - it('Adds a text exercise', { scrollBehavior: 'center' }, () => { - cy.visit(`/course-management/${course.id}/exams`); - examManagement.openExerciseGroups(exam.id!); - examExerciseGroups.clickAddTextExercise(exerciseGroup.id!); - const textExerciseTitle = 'Text ' + generateUUID(); - textExerciseCreation.typeTitle(textExerciseTitle); - textExerciseCreation.typeMaxPoints(10); - textExerciseCreation.create().its('response.statusCode').should('eq', 201); - examExerciseGroups.visitPageViaUrl(course.id!, exam.id!); - examExerciseGroups.shouldContainExerciseWithTitle(exerciseGroup.id!, textExerciseTitle); - }); - - it('Adds a quiz exercise', () => { - cy.visit(`/course-management/${course.id}/exams`); - examManagement.openExerciseGroups(exam.id!); - examExerciseGroups.clickAddQuizExercise(exerciseGroup.id!); - const quizExerciseTitle = 'Quiz ' + generateUUID(); - quizExerciseCreation.setTitle(quizExerciseTitle); - quizExerciseCreation.addMultipleChoiceQuestion(quizExerciseTitle, 10); - quizExerciseCreation.saveQuiz().its('response.statusCode').should('eq', 201); - examExerciseGroups.visitPageViaUrl(course.id!, exam.id!); - examExerciseGroups.shouldContainExerciseWithTitle(exerciseGroup.id!, quizExerciseTitle); - }); - - it('Adds a modeling exercise', { scrollBehavior: 'center' }, () => { - cy.visit(`/course-management/${course.id}/exams`); - examManagement.openExerciseGroups(exam.id!); - examExerciseGroups.clickAddModelingExercise(exerciseGroup.id!); - const modelingExerciseTitle = 'Modeling ' + generateUUID(); - modelingExerciseCreation.setTitle(modelingExerciseTitle); - modelingExerciseCreation.setPoints(10); - modelingExerciseCreation.save().its('response.statusCode').should('eq', 201); - examExerciseGroups.visitPageViaUrl(course.id!, exam.id!); - examExerciseGroups.shouldContainExerciseWithTitle(exerciseGroup.id!, modelingExerciseTitle); - }); - - it('Adds a programming exercise', { scrollBehavior: 'center' }, () => { - cy.visit(`/course-management/${course.id}/exams`); - examManagement.openExerciseGroups(exam.id!); - examExerciseGroups.clickAddProgrammingExercise(exerciseGroup.id!); - const uid = generateUUID(); - const programmingExerciseTitle = 'Programming ' + uid; - const programmingExerciseShortName = 'programming' + uid; - programmingExerciseCreation.setTitle(programmingExerciseTitle); - programmingExerciseCreation.setShortName(programmingExerciseShortName); - programmingExerciseCreation.setPackageName('de.test'); - programmingExerciseCreation.setPoints(10); - programmingExerciseCreation.generate().its('response.statusCode').should('eq', 201); - examExerciseGroups.visitPageViaUrl(course.id!, exam.id!); - examExerciseGroups.shouldContainExerciseWithTitle(exerciseGroup.id!, programmingExerciseTitle); - }); - - it('Edits an exercise group', () => { - cy.visit(`/course-management/${course.id}/exams`); - examManagement.openExerciseGroups(exam.id!); - examExerciseGroups.shouldHaveTitle(exerciseGroup.id!, exerciseGroup.title!); - examExerciseGroups.clickEditGroup(exerciseGroup.id!); - const newGroupName = 'Group 3'; - examExerciseGroupCreation.typeTitle(newGroupName); - examExerciseGroupCreation.update(); - examExerciseGroups.shouldHaveTitle(exerciseGroup.id!, newGroupName); - exerciseGroup.title = newGroupName; - }); - - it('Delete an exercise group', () => { - cy.visit('/'); - navigationBar.openCourseManagement(); - courseManagement.openExamsOfCourse(course.id!); - examManagement.openExerciseGroups(exam.id!); - // If the group in the "Create group test" was created successfully, we delete it so there is no group with no exercise - let group = exerciseGroup; - if (createdGroup) { - group = createdGroup; - } - examExerciseGroups.clickDeleteGroup(group.id!, group.title!); - examExerciseGroups.shouldNotExist(group.id!); - }); - }); - - describe('Manage Students', () => { - beforeEach(() => { - cy.login(instructor); - }); - - it('Registers the course students for the exam', () => { - // We already verified in the previous test that we can navigate here - cy.visit(`/course-management/${course.id}/exams`); - examManagement.openStudentRegistration(exam.id!); - studentExamManagement.clickRegisterCourseStudents().then((request: Interception) => { - expect(request.response!.statusCode).to.eq(200); - }); - studentExamManagement.getRegisteredStudents().contains(studentOne.username).should('be.visible'); - }); - - it('Generates student exams', () => { - cy.visit(`/course-management/${course.id}/exams`); - examManagement.openStudentExams(exam.id!); - studentExamManagement.clickGenerateStudentExams(); - studentExamManagement.getGenerateStudentExamsButton().should('be.disabled'); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exam/ExamParticipation.cy.ts b/src/test/cypress/e2e/exam/ExamParticipation.cy.ts deleted file mode 100644 index a0c047580ada..000000000000 --- a/src/test/cypress/e2e/exam/ExamParticipation.cy.ts +++ /dev/null @@ -1,305 +0,0 @@ -import { Interception } from 'cypress/types/net-stubbing'; -import dayjs from 'dayjs/esm'; - -import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; - -import javaAllSuccessfulSubmission from '../../fixtures/exercise/programming/java/all_successful/submission.json'; -import { - courseManagementAPIRequest, - examAPIRequests, - examExerciseGroupCreation, - examManagement, - examNavigation, - examParticipation, - examStartEnd, - textExerciseEditor, -} from '../../support/artemis'; -import { Exercise, ExerciseType } from '../../support/constants'; -import { admin, instructor, studentFour, studentThree, studentTwo, tutor, users } from '../../support/users'; -import { convertModelAfterMultiPart, generateUUID } from '../../support/utils'; - -// Common primitives -const textFixture = 'loremIpsum.txt'; -const textFixtureShort = 'loremIpsum-short.txt'; - -describe.skip('Exam participation', () => { - let course: Course; - let exerciseArray: Array = []; - let studentTwoName: string; - let studentThreeName: string; - let studentFourName: string; - - before('Create course', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse({ customizeGroups: true }).then((response) => { - course = convertModelAfterMultiPart(response); - courseManagementAPIRequest.addStudentToCourse(course, studentTwo); - courseManagementAPIRequest.addStudentToCourse(course, studentThree); - courseManagementAPIRequest.addStudentToCourse(course, studentFour); - courseManagementAPIRequest.addTutorToCourse(course, tutor); - courseManagementAPIRequest.addInstructorToCourse(course, instructor); - }); - users.getUserInfo(studentTwo.username, (userInfo) => { - studentTwoName = userInfo.name; - }); - users.getUserInfo(studentThree.username, (userInfo) => { - studentThreeName = userInfo.name; - }); - users.getUserInfo(studentFour.username, (userInfo) => { - studentFourName = userInfo.name; - }); - }); - - describe('Early Hand-in', () => { - let exam: Exam; - const examTitle = 'exam' + generateUUID(); - - before('Create exam', () => { - cy.login(admin); - const examConfig: Exam = { - course, - title: examTitle, - visibleDate: dayjs().subtract(3, 'minutes'), - startDate: dayjs().subtract(2, 'minutes'), - endDate: dayjs().add(1, 'hour'), - examMaxPoints: 40, - numberOfExercisesInExam: 4, - }; - examAPIRequests.createExam(examConfig).then((examResponse) => { - exam = examResponse.body; - Promise.all([ - examExerciseGroupCreation.addGroupWithExercise(exam, ExerciseType.TEXT, { textFixture }), - examExerciseGroupCreation.addGroupWithExercise(exam, ExerciseType.PROGRAMMING, { submission: javaAllSuccessfulSubmission }), - examExerciseGroupCreation.addGroupWithExercise(exam, ExerciseType.QUIZ, { quizExerciseID: 0 }), - examExerciseGroupCreation.addGroupWithExercise(exam, ExerciseType.MODELING), - ]).then((responses) => { - exerciseArray = exerciseArray.concat(responses); - }); - - examAPIRequests.registerStudentForExam(exam, studentTwo); - examAPIRequests.registerStudentForExam(exam, studentThree); - examAPIRequests.registerStudentForExam(exam, studentFour); - examAPIRequests.generateMissingIndividualExams(exam); - examAPIRequests.prepareExerciseStartForExam(exam); - }); - }); - - it('Participates as a student in a registered exam', () => { - examParticipation.startParticipation(studentTwo, course, exam); - for (let j = 0; j < exerciseArray.length; j++) { - const exercise = exerciseArray[j]; - examNavigation.openExerciseAtIndex(j); - examParticipation.makeSubmission(exercise.id, exercise.type, exercise.additionalData); - } - examParticipation.handInEarly(); - examStartEnd.pressShowSummary(); - for (let j = 0; j < exerciseArray.length; j++) { - const exercise = exerciseArray[j]; - examParticipation.verifyExerciseTitleOnFinalPage(exercise.id, exercise.exerciseGroup!.title!); - if (exercise.type === ExerciseType.TEXT) { - examParticipation.verifyTextExerciseOnFinalPage(exercise.additionalData!.textFixture!); - } - } - examParticipation.checkExamTitle(examTitle); - - cy.login(instructor); - examManagement.verifySubmitted(course.id!, exam.id!, studentTwoName); - }); - - it('Using save and continue to navigate within exam', () => { - examParticipation.startParticipation(studentThree, course, exam); - examNavigation.openExerciseAtIndex(0); - for (let j = 0; j < exerciseArray.length; j++) { - const exercise = exerciseArray[j]; - // Skip programming exercise this time to save execution time - // (we also need to use the navigation bar here, since programming exercises do not have a "Save and continue" button) - if (exercise.type == ExerciseType.PROGRAMMING) { - examNavigation.openExerciseAtIndex(j + 1); - } else { - examParticipation.makeSubmission(exercise.id, exercise.type, exercise.additionalData); - examParticipation.clickSaveAndContinue(); - } - } - examParticipation.handInEarly(); - - cy.login(instructor); - examManagement.verifySubmitted(course.id!, exam.id!, studentThreeName); - }); - - it('Using exercise overview to navigate within exam', () => { - examParticipation.startParticipation(studentFour, course, exam); - for (let j = 0; j < exerciseArray.length; j++) { - const exercise = exerciseArray[j]; - // Skip programming exercise this time to save execution time - // (we also need to use the navigation bar here, since programming exercises do not have a "Save and continue" button) - if (exercise.type == ExerciseType.PROGRAMMING) { - continue; - } else { - examNavigation.openExerciseOverview(); - examParticipation.selectExerciseOnOverview(j + 1); - examParticipation.makeSubmission(exercise.id, exercise.type, exercise.additionalData); - } - } - examParticipation.handInEarly(); - - cy.login(instructor); - examManagement.verifySubmitted(course.id!, exam.id!, studentFourName); - }); - }); - - describe('Early hand-in with continue and reload page', () => { - let exam: Exam; - const examTitle = 'exam' + generateUUID(); - - before('Create exam', () => { - exerciseArray = []; - - cy.login(admin); - - const examConfig: Exam = { - course, - title: examTitle, - visibleDate: dayjs().subtract(3, 'minutes'), - startDate: dayjs().subtract(2, 'minutes'), - endDate: dayjs().add(1, 'hour'), - examMaxPoints: 10, - numberOfExercisesInExam: 1, - }; - examAPIRequests.createExam(examConfig).then((examResponse) => { - exam = examResponse.body; - examExerciseGroupCreation.addGroupWithExercise(exam, ExerciseType.TEXT, { textFixture }).then((response) => { - exerciseArray.push(response); - }); - - examAPIRequests.registerStudentForExam(exam, studentTwo); - examAPIRequests.registerStudentForExam(exam, studentThree); - examAPIRequests.registerStudentForExam(exam, studentFour); - examAPIRequests.generateMissingIndividualExams(exam); - examAPIRequests.prepareExerciseStartForExam(exam); - }); - }); - - it('Participates in the exam, hand-in early, but instead continues', () => { - examParticipation.startParticipation(studentTwo, course, exam); - const textExerciseIndex = 0; - const textExercise = exerciseArray[textExerciseIndex]; - examNavigation.openExerciseAtIndex(textExerciseIndex); - examParticipation.makeTextExerciseSubmission(textExercise.id, textExercise.additionalData!.textFixture!); - examParticipation.clickSaveAndContinue(); - examNavigation.handInEarly(); - - examStartEnd.clickContinue(); - examNavigation.openExerciseAtIndex(textExerciseIndex); - textExerciseEditor.clearSubmission(textExercise.id); - examParticipation.makeTextExerciseSubmission(textExercise.id, textFixtureShort); - examParticipation.clickSaveAndContinue(); - - examParticipation.handInEarly(); - examStartEnd.pressShowSummary(); - examParticipation.verifyTextExerciseOnFinalPage(textFixtureShort); - examParticipation.checkExamTitle(examTitle); - - cy.login(instructor); - examManagement.verifySubmitted(course.id!, exam.id!, studentTwoName); - }); - - it('Reloads exam page during participation and ensures that everything is as expected', () => { - examParticipation.startParticipation(studentThree, course, exam); - const textExerciseIndex = 0; - const textExercise = exerciseArray[textExerciseIndex]; - examNavigation.openExerciseAtIndex(textExerciseIndex); - examParticipation.makeTextExerciseSubmission(textExercise.id, textExercise.additionalData!.textFixture!); - examParticipation.clickSaveAndContinue(); - - cy.reload(); - examParticipation.startParticipation(studentThree, course, exam); - examNavigation.openExerciseAtIndex(textExerciseIndex); - textExerciseEditor.checkCurrentContent(textExercise.id, textExercise.additionalData!.textFixture!); - examParticipation.clickSaveAndContinue(); - examParticipation.handInEarly(); - examStartEnd.pressShowSummary(); - examParticipation.verifyTextExerciseOnFinalPage(textExercise.additionalData!.textFixture!); - examParticipation.checkExamTitle(examTitle); - - cy.login(instructor); - examManagement.verifySubmitted(course.id!, exam.id!, studentThreeName); - }); - - it('Reloads exam result page and ensures that everything is as expected', () => { - examParticipation.startParticipation(studentFour, course, exam); - const textExerciseIndex = 0; - const textExercise = exerciseArray[textExerciseIndex]; - examNavigation.openExerciseAtIndex(textExerciseIndex); - examParticipation.makeTextExerciseSubmission(textExercise.id, textExercise.additionalData!.textFixture!); - examParticipation.clickSaveAndContinue(); - examParticipation.handInEarly(); - examStartEnd.pressShowSummary(); - examParticipation.verifyTextExerciseOnFinalPage(textExercise.additionalData!.textFixture!); - examParticipation.checkExamTitle(examTitle); - - cy.reload(); - - examParticipation.verifyTextExerciseOnFinalPage(textExercise.additionalData!.textFixture!); - examParticipation.checkExamTitle(examTitle); - - cy.login(instructor); - examManagement.verifySubmitted(course.id!, exam.id!, studentFourName); - }); - }); - - describe('Normal Hand-in', () => { - let exam: Exam; - const examTitle = 'exam' + generateUUID(); - - before('Create exam', () => { - exerciseArray = []; - - cy.login(admin); - - const examConfig: Exam = { - course, - title: examTitle, - visibleDate: dayjs().subtract(3, 'minutes'), - startDate: dayjs().subtract(2, 'minutes'), - endDate: dayjs().add(30, 'seconds'), - examMaxPoints: 10, - numberOfExercisesInExam: 1, - }; - examAPIRequests.createExam(examConfig).then((examResponse) => { - exam = examResponse.body; - examExerciseGroupCreation.addGroupWithExercise(exam, ExerciseType.TEXT, { textFixture }).then((response) => { - exerciseArray.push(response); - }); - - examAPIRequests.registerStudentForExam(exam, studentFour); - examAPIRequests.generateMissingIndividualExams(exam); - examAPIRequests.prepareExerciseStartForExam(exam); - }); - }); - - it('Participates as a student in a registered exam', () => { - examParticipation.startParticipation(studentFour, course, exam); - const textExerciseIndex = 0; - const textExercise = exerciseArray[textExerciseIndex]; - examNavigation.openExerciseAtIndex(textExerciseIndex); - examParticipation.makeSubmission(textExercise.id, textExercise.type, textExercise.additionalData); - examParticipation.clickSaveAndContinue(); - examParticipation.checkExamFullnameInputExists(); - examParticipation.checkYourFullname(studentFourName); - examStartEnd.finishExam().then((request: Interception) => { - expect(request.response!.statusCode).to.eq(200); - }); - examStartEnd.pressShowSummary(); - examParticipation.verifyTextExerciseOnFinalPage(textExercise.additionalData!.textFixture!); - examParticipation.checkExamTitle(examTitle); - - cy.login(instructor); - examManagement.verifySubmitted(course.id!, exam.id!, studentFourName); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exam/ExamTestRun.cy.ts b/src/test/cypress/e2e/exam/ExamTestRun.cy.ts deleted file mode 100644 index f835fa27a288..000000000000 --- a/src/test/cypress/e2e/exam/ExamTestRun.cy.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { Interception } from 'cypress/types/net-stubbing'; -import dayjs from 'dayjs/esm'; - -import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; - -import javaBuildErrorSubmission from '../../fixtures/exercise/programming/java/build_error/submission.json'; -import { courseManagementAPIRequest, examAPIRequests, examExerciseGroupCreation, examManagement, examNavigation, examParticipation, examTestRun } from '../../support/artemis'; -import { Exercise, ExerciseType } from '../../support/constants'; -import { admin, instructor } from '../../support/users'; -import { convertModelAfterMultiPart, generateUUID } from '../../support/utils'; - -// Common primitives -const textFixture = 'loremIpsum-short.txt'; -const examTitle = 'exam' + generateUUID(); - -describe.skip('Exam test run', () => { - let course: Course; - let exam: Exam; - let testRun: any; - let exerciseArray: Array = []; - - before('Create course', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse({ customizeGroups: true }).then((response) => { - course = convertModelAfterMultiPart(response); - const examConfig: Exam = { - course, - title: examTitle, - visibleDate: dayjs().subtract(3, 'days'), - startDate: dayjs().add(1, 'days'), - endDate: dayjs().add(3, 'days'), - examMaxPoints: 40, - numberOfExercisesInExam: 4, - }; - examAPIRequests.createExam(examConfig).then((examResponse) => { - exam = examResponse.body; - Promise.all([ - examExerciseGroupCreation.addGroupWithExercise(exam, ExerciseType.TEXT, { textFixture }), - examExerciseGroupCreation.addGroupWithExercise(exam, ExerciseType.PROGRAMMING, { submission: javaBuildErrorSubmission, practiceMode: true }), - examExerciseGroupCreation.addGroupWithExercise(exam, ExerciseType.QUIZ, { quizExerciseID: 0 }), - examExerciseGroupCreation.addGroupWithExercise(exam, ExerciseType.MODELING), - ]).then((responses) => { - exerciseArray = exerciseArray.concat(responses); - }); - }); - }); - }); - - beforeEach('Create test run instance', () => { - cy.login(instructor); - // TODO: API call does not work yet, for now we use the UI to create the test run - // courseManagementAPIRequests.createExamTestRun(exam, exerciseArray).then((response: any) => { - // testRun = response.body; - // }); - cy.visit(`/course-management/${course.id}/exams/${exam.id}`); - examManagement.openTestRun(); - examTestRun.createTestRun(); - examTestRun.setWorkingTimeMinutes(2); - examTestRun.confirmTestRun().then((testRunResponse: Interception) => { - testRun = testRunResponse.response!.body; - }); - }); - - it('Create a test run', () => { - cy.login(instructor); - - let testRunID: number; - const minutes = 40; - const seconds = 30; - - cy.visit(`/course-management/${course.id}/exams/${exam.id}`); - examManagement.openTestRun(); - examTestRun.createTestRun(); - examTestRun.setWorkingTimeMinutes(minutes); - examTestRun.setWorkingTimeSeconds(seconds); - examTestRun.confirmTestRun().then((testRunResponse: Interception) => { - const testRun = testRunResponse.response!.body; - testRunID = testRun.id; - - expect(testRunResponse.response!.statusCode).to.eq(200); - expect(testRun.testRun).to.be.true; - expect(testRun.submitted).to.be.false; - expect(testRun.workingTime).to.eq(minutes * 60 + seconds); - - examTestRun.getWorkingTime(testRunID).contains('40min 30s'); - examTestRun.getStarted(testRunID).contains('No'); - examTestRun.getSubmitted(testRunID).contains('No'); - }); - }); - - it('Change test run working time', () => { - const hour = 1; - const minutes = 20; - const seconds = 45; - - cy.login(instructor); - examTestRun.openTestRunPage(course, exam); - examTestRun.changeWorkingTime(testRun.id); - examTestRun.setWorkingTimeHours(hour); - examTestRun.setWorkingTimeMinutes(minutes); - examTestRun.setWorkingTimeSeconds(seconds); - examTestRun.saveTestRun().then((testRunResponse: Interception) => { - const testRun = testRunResponse.response!.body; - - expect(testRun.id).to.eq(testRun.id); - expect(testRunResponse.response!.statusCode).to.eq(200); - expect(testRun.workingTime).to.eq(hour * 3600 + minutes * 60 + seconds); - - examTestRun.openTestRunPage(course, exam); - examTestRun.getWorkingTime(testRun.id).contains(`${hour}h ${minutes}min ${seconds}s`); - examTestRun.getStarted(testRun.id).contains('No'); - examTestRun.getSubmitted(testRun.id).contains('No'); - }); - }); - - it('Conducts a test run', () => { - examTestRun.startParticipation(instructor, course, exam, testRun.id); - examTestRun.getTestRunRibbon().contains('Test Run'); - - for (let j = 0; j < exerciseArray.length; j++) { - const exercise = exerciseArray[j]; - examNavigation.openExerciseAtIndex(j); - examParticipation.makeSubmission(exercise.id, exercise.type, exercise.additionalData); - } - examParticipation.handInEarly(); - for (let j = 0; j < exerciseArray.length; j++) { - const exercise = exerciseArray[j]; - examParticipation.verifyExerciseTitleOnFinalPage(exercise.id, exercise.exerciseGroup!.title!); - if (exercise.type === ExerciseType.TEXT) { - examParticipation.verifyTextExerciseOnFinalPage(exercise.additionalData!.textFixture!); - } - } - examParticipation.checkExamTitle(examTitle); - examTestRun.openTestRunPage(course, exam); - examTestRun.getStarted(testRun.id).contains('Yes'); - examTestRun.getSubmitted(testRun.id).contains('Yes'); - }); - - it('Deletes a test run', () => { - cy.login(instructor); - examTestRun.openTestRunPage(course, exam); - examTestRun.getTestRunIdElement(testRun.id).should('exist'); - examTestRun.deleteTestRun(testRun.id); - examTestRun.getTestRun(testRun.id).should('not.exist'); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exam/test-exam/TestExamCreationDeletion.cy.ts b/src/test/cypress/e2e/exam/test-exam/TestExamCreationDeletion.cy.ts deleted file mode 100644 index 66d49298a858..000000000000 --- a/src/test/cypress/e2e/exam/test-exam/TestExamCreationDeletion.cy.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { Interception } from 'cypress/types/net-stubbing'; -import dayjs from 'dayjs/esm'; - -import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; - -import { courseManagement, courseManagementAPIRequest, examAPIRequests, examCreation, examDetails, examManagement, navigationBar } from '../../../support/artemis'; -import { admin } from '../../../support/users'; -import { convertModelAfterMultiPart, dayjsToString, generateUUID, trimDate } from '../../../support/utils'; - -// Common primitives -const examData = { - title: 'exam' + generateUUID(), - visibleDate: dayjs(), - startDate: dayjs().add(1, 'day'), - endDate: dayjs().add(2, 'day'), - workingTime: 5, - numberOfExercises: 4, - maxPoints: 40, - startText: 'Exam start text', - endText: 'Exam end text', - confirmationStartText: 'Exam confirmation start text', - confirmationEndText: 'Exam confirmation end text', -}; - -describe.skip('Test Exam creation/deletion', () => { - let course: Course; - let exam: Exam; - - before('Create course', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse().then((response) => { - course = convertModelAfterMultiPart(response); - }); - }); - - beforeEach(() => { - cy.login(admin, '/'); - }); - - it('Creates a test exam', function () { - navigationBar.openCourseManagement(); - courseManagement.openExamsOfCourse(course.id!); - - examManagement.createNewExam(); - examCreation.setTitle(examData.title); - examCreation.setTestMode(); - examCreation.setVisibleDate(examData.visibleDate); - examCreation.setStartDate(examData.startDate); - examCreation.setEndDate(examData.endDate); - examCreation.setWorkingTime(examData.workingTime); - examCreation.setNumberOfExercises(examData.numberOfExercises); - examCreation.setExamMaxPoints(examData.maxPoints); - - examCreation.setStartText(examData.startText); - examCreation.setEndText(examData.endText); - examCreation.setConfirmationStartText(examData.confirmationStartText); - examCreation.setConfirmationEndText(examData.confirmationEndText); - - examCreation.submit().then((examResponse: Interception) => { - const examBody = examResponse.response!.body; - exam = examResponse.response!.body; - expect(examResponse.response!.statusCode).to.eq(201); - expect(examBody.title).to.eq(examData.title); - expect(examBody.testExam).to.be.true; - expect(trimDate(examBody.visibleDate)).to.eq(trimDate(dayjsToString(examData.visibleDate))); - expect(trimDate(examBody.startDate)).to.eq(trimDate(dayjsToString(examData.startDate))); - expect(trimDate(examBody.endDate)).to.eq(trimDate(dayjsToString(examData.endDate))); - expect(examBody.workingTime).to.eq(examData.workingTime * 60); - expect(examBody.numberOfExercisesInExam).to.eq(examData.numberOfExercises); - expect(examBody.examMaxPoints).to.eq(examData.maxPoints); - expect(examBody.startText).to.eq(examData.startText); - expect(examBody.endText).to.eq(examData.endText); - expect(examBody.confirmationStartText).to.eq(examData.confirmationStartText); - expect(examBody.confirmationEndText).to.eq(examData.confirmationEndText); - cy.url().should('contain', `/exams/${exam.id}`); - }); - examManagement.getExamTitle().contains(examData.title); - }); - - describe('Test exam deletion', () => { - beforeEach(() => { - examData.title = 'exam' + generateUUID(); - const examConfig: Exam = { - course, - title: examData.title, - testExam: true, - }; - examAPIRequests.createExam(examConfig).then((examResponse) => { - exam = examResponse.body; - }); - }); - - it('Deletes an existing test exam', () => { - navigationBar.openCourseManagement(); - courseManagement.openExamsOfCourse(course.id!); - examManagement.getExamSelector(examData.title).should('exist'); - examManagement.openExam(exam.id!); - examDetails.deleteExam(examData.title); - examManagement.getExamSelector(examData.title).should('not.exist'); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exam/test-exam/TestExamManagement.cy.ts b/src/test/cypress/e2e/exam/test-exam/TestExamManagement.cy.ts deleted file mode 100644 index 435595a7a2bc..000000000000 --- a/src/test/cypress/e2e/exam/test-exam/TestExamManagement.cy.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; -import { ExerciseGroup } from 'app/entities/exercise-group.model'; - -import { - courseManagement, - courseManagementAPIRequest, - examAPIRequests, - examExerciseGroupCreation, - examExerciseGroups, - examManagement, - modelingExerciseCreation, - navigationBar, - programmingExerciseCreation, - quizExerciseCreation, - textExerciseCreation, -} from '../../../support/artemis'; -import { admin, instructor, studentOne } from '../../../support/users'; -import { convertModelAfterMultiPart, generateUUID } from '../../../support/utils'; - -// Common primitives -const uid = generateUUID(); -const examTitle = 'test-exam' + uid; - -describe.skip('Test Exam management', () => { - let course: Course; - let exam: Exam; - let createdGroup: ExerciseGroup; - let groupCount = 0; - - before('Create course', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse({ customizeGroups: true }).then((response) => { - course = convertModelAfterMultiPart(response); - courseManagementAPIRequest.addStudentToCourse(course, studentOne); - examAPIRequests.createExam({ course, title: examTitle, testExam: true }).then((examResponse) => { - exam = examResponse.body; - }); - }); - }); - - describe('Manage Group', () => { - let exerciseGroup: ExerciseGroup; - - before(() => { - cy.login(instructor); - examAPIRequests.addExerciseGroupForExam(exam).then((response) => { - exerciseGroup = response.body; - groupCount++; - }); - }); - - beforeEach(() => { - cy.login(instructor); - }); - - it('Create exercise group', () => { - cy.visit('/'); - navigationBar.openCourseManagement(); - courseManagement.openExamsOfCourse(course.id!); - examManagement.openExerciseGroups(exam.id!); - examExerciseGroups.shouldShowNumberOfExerciseGroups(groupCount); - examExerciseGroups.clickAddExerciseGroup(); - const groupName = 'Group 1'; - examExerciseGroupCreation.typeTitle(groupName); - examExerciseGroupCreation.isMandatoryBoxShouldBeChecked(); - examExerciseGroupCreation.clickSave().then((interception) => { - const group = interception.response!.body; - groupCount++; - examExerciseGroups.shouldHaveTitle(group.id, groupName); - examExerciseGroups.shouldShowNumberOfExerciseGroups(groupCount); - createdGroup = group; - }); - }); - - it('Adds a text exercise', { scrollBehavior: 'center' }, () => { - cy.visit(`/course-management/${course.id}/exams`); - examManagement.openExerciseGroups(exam.id!); - examExerciseGroups.clickAddTextExercise(exerciseGroup.id!); - const textExerciseTitle = 'text' + uid; - textExerciseCreation.typeTitle(textExerciseTitle); - textExerciseCreation.typeMaxPoints(10); - textExerciseCreation.create().its('response.statusCode').should('eq', 201); - examExerciseGroups.visitPageViaUrl(course.id!, exam.id!); - examExerciseGroups.shouldContainExerciseWithTitle(exerciseGroup.id!, textExerciseTitle); - }); - - it('Adds a quiz exercise', () => { - cy.visit(`/course-management/${course.id}/exams`); - examManagement.openExerciseGroups(exam.id!); - examExerciseGroups.clickAddQuizExercise(exerciseGroup.id!); - const quizExerciseTitle = 'quiz' + uid; - quizExerciseCreation.setTitle(quizExerciseTitle); - quizExerciseCreation.addMultipleChoiceQuestion(quizExerciseTitle, 10); - quizExerciseCreation.saveQuiz().its('response.statusCode').should('eq', 201); - examExerciseGroups.visitPageViaUrl(course.id!, exam.id!); - examExerciseGroups.shouldContainExerciseWithTitle(exerciseGroup.id!, quizExerciseTitle); - }); - - it('Adds a modeling exercise', { scrollBehavior: 'center' }, () => { - cy.visit(`/course-management/${course.id}/exams`); - examManagement.openExerciseGroups(exam.id!); - examExerciseGroups.clickAddModelingExercise(exerciseGroup.id!); - const modelingExerciseTitle = 'modeling' + uid; - modelingExerciseCreation.setTitle(modelingExerciseTitle); - modelingExerciseCreation.setPoints(10); - modelingExerciseCreation.save().its('response.statusCode').should('eq', 201); - examExerciseGroups.visitPageViaUrl(course.id!, exam.id!); - examExerciseGroups.shouldContainExerciseWithTitle(exerciseGroup.id!, modelingExerciseTitle); - }); - - it('Adds a programming exercise', { scrollBehavior: 'center' }, () => { - cy.visit(`/course-management/${course.id}/exams`); - examManagement.openExerciseGroups(exam.id!); - examExerciseGroups.clickAddProgrammingExercise(exerciseGroup.id!); - const programmingExerciseTitle = 'programming' + uid; - programmingExerciseCreation.setTitle(programmingExerciseTitle); - programmingExerciseCreation.setShortName(programmingExerciseTitle); - programmingExerciseCreation.setPackageName('de.test'); - programmingExerciseCreation.setPoints(10); - programmingExerciseCreation.generate().its('response.statusCode').should('eq', 201); - examExerciseGroups.visitPageViaUrl(course.id!, exam.id!); - examExerciseGroups.shouldContainExerciseWithTitle(exerciseGroup.id!, programmingExerciseTitle); - }); - - it('Edits an exercise group', () => { - cy.visit(`/course-management/${course.id}/exams`); - examManagement.openExerciseGroups(exam.id!); - examExerciseGroups.shouldHaveTitle(exerciseGroup.id!, exerciseGroup.title!); - examExerciseGroups.clickEditGroup(exerciseGroup.id!); - const newGroupName = 'Group 3'; - examExerciseGroupCreation.typeTitle(newGroupName); - examExerciseGroupCreation.update(); - examExerciseGroups.shouldHaveTitle(exerciseGroup.id!, newGroupName); - exerciseGroup.title = newGroupName; - }); - - it('Delete an exercise group', () => { - cy.visit('/'); - navigationBar.openCourseManagement(); - courseManagement.openExamsOfCourse(course.id!); - examManagement.openExerciseGroups(exam.id!); - // If the group in the "Create group test" was created successfully, we delete it so there is no group with no exercise - let group = exerciseGroup; - if (createdGroup) { - group = createdGroup; - } - examExerciseGroups.clickDeleteGroup(group.id!, group.title!); - examExerciseGroups.shouldNotExist(group.id!); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exam/test-exam/TestExamParticipation.cy.ts b/src/test/cypress/e2e/exam/test-exam/TestExamParticipation.cy.ts deleted file mode 100644 index f22ab0fed6a2..000000000000 --- a/src/test/cypress/e2e/exam/test-exam/TestExamParticipation.cy.ts +++ /dev/null @@ -1,175 +0,0 @@ -import { Interception } from 'cypress/types/net-stubbing'; -import dayjs from 'dayjs/esm'; - -import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; - -import javaAllSuccessfulSubmission from '../../../fixtures/exercise/programming/java/all_successful/submission.json'; -import javaBuildErrorSubmission from '../../../fixtures/exercise/programming/java/build_error/submission.json'; -import { courseManagementAPIRequest, examAPIRequests, examExerciseGroupCreation, examNavigation, examParticipation, examStartEnd } from '../../../support/artemis'; -import { Exercise, ExerciseType } from '../../../support/constants'; -import { admin, studentFour, studentThree, studentTwo, users } from '../../../support/users'; -import { convertModelAfterMultiPart, generateUUID } from '../../../support/utils'; - -// Common primitives -const textFixture = 'loremIpsum-short.txt'; - -describe.skip('Test exam participation', () => { - let course: Course; - let exerciseArray: Array = []; - - before('Create course', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse({ customizeGroups: true }).then((response) => { - course = convertModelAfterMultiPart(response); - courseManagementAPIRequest.addStudentToCourse(course, studentTwo); - courseManagementAPIRequest.addStudentToCourse(course, studentThree); - courseManagementAPIRequest.addStudentToCourse(course, studentFour); - }); - }); - - describe('Early Hand-in', () => { - let exam: Exam; - const examTitle = 'test-exam' + generateUUID(); - - before('Create test exam', () => { - cy.login(admin); - const examConfig: Exam = { - course, - title: examTitle, - testExam: true, - startDate: dayjs().subtract(1, 'day'), - visibleDate: dayjs().subtract(2, 'days'), - examMaxPoints: 100, - numberOfExercisesInExam: 10, - numberOfCorrectionRoundsInExam: 0, - }; - examAPIRequests.createExam(examConfig).then((examResponse) => { - exam = examResponse.body; - Promise.all([ - examExerciseGroupCreation.addGroupWithExercise(exam, ExerciseType.TEXT, { textFixture }), - examExerciseGroupCreation.addGroupWithExercise(exam, ExerciseType.TEXT, { textFixture }), - examExerciseGroupCreation.addGroupWithExercise(exam, ExerciseType.TEXT, { textFixture }), - - examExerciseGroupCreation.addGroupWithExercise(exam, ExerciseType.PROGRAMMING, { submission: javaAllSuccessfulSubmission, expectedScore: 100 }), - examExerciseGroupCreation.addGroupWithExercise(exam, ExerciseType.PROGRAMMING, { submission: javaBuildErrorSubmission, expectedScore: 0 }), - - examExerciseGroupCreation.addGroupWithExercise(exam, ExerciseType.QUIZ, { quizExerciseID: 0 }), - examExerciseGroupCreation.addGroupWithExercise(exam, ExerciseType.QUIZ, { quizExerciseID: 0 }), - - examExerciseGroupCreation.addGroupWithExercise(exam, ExerciseType.MODELING), - examExerciseGroupCreation.addGroupWithExercise(exam, ExerciseType.MODELING), - ]).then((responses) => { - exerciseArray = exerciseArray.concat(responses); - }); - }); - }); - - it('Participates as a student in a registered test exam', () => { - examParticipation.startParticipation(studentTwo, course, exam); - for (let j = 0; j < exerciseArray.length; j++) { - const exercise = exerciseArray[j]; - examNavigation.openExerciseAtIndex(j); - examParticipation.makeSubmission(exercise.id, exercise.type, exercise.additionalData); - } - examParticipation.handInEarly(); - for (let j = 0; j < exerciseArray.length; j++) { - const exercise = exerciseArray[j]; - examParticipation.verifyExerciseTitleOnFinalPage(exercise.id, exercise.exerciseGroup!.title!); - if (exercise.type === ExerciseType.TEXT) { - examParticipation.verifyTextExerciseOnFinalPage(exercise.additionalData!.textFixture!); - } - } - examParticipation.checkExamTitle(examTitle); - }); - - it('Using save and continue to navigate within exam', () => { - examParticipation.startParticipation(studentThree, course, exam); - examNavigation.openExerciseAtIndex(0); - for (let j = 0; j < exerciseArray.length; j++) { - const exercise = exerciseArray[j]; - // Skip programming exercise this time to save execution time - // (we also need to use the navigation bar here, since programming exercises do not have a "Save and continue" button) - if (exercise.type == ExerciseType.PROGRAMMING) { - examNavigation.openExerciseAtIndex(j + 1); - } else { - examParticipation.checkExerciseTitle(exerciseArray[j].id, exerciseArray[j].exerciseGroup!.title!); - examParticipation.makeSubmission(exercise.id, exercise.type, exercise.additionalData); - examParticipation.clickSaveAndContinue(); - } - } - examParticipation.handInEarly(); - }); - - it('Using exercise overview to navigate within exam', () => { - examParticipation.startParticipation(studentFour, course, exam); - for (let j = 0; j < exerciseArray.length; j++) { - const exercise = exerciseArray[j]; - // Skip programming exercise this time to save execution time - // (we also need to use the navigation bar here, since programming exercises do not have a "Save and continue" button) - if (exercise.type === ExerciseType.PROGRAMMING) { - continue; - } else { - examNavigation.openExerciseOverview(); - examParticipation.selectExerciseOnOverview(j + 1); - examParticipation.checkExerciseTitle(exerciseArray[j].id, exerciseArray[j].exerciseGroup!.title!); - examParticipation.makeSubmission(exercise.id, exercise.type, exercise.additionalData); - } - } - examParticipation.handInEarly(); - }); - }); - - describe('Normal Hand-in', () => { - let exam: Exam; - let studentFourName: string; - const examTitle = 'exam' + generateUUID(); - - before('Create exam', () => { - exerciseArray = []; - - cy.login(admin); - - users.getUserInfo(studentFour.username, (userInfo) => { - studentFourName = userInfo.name; - }); - - const examConfig: Exam = { - course, - title: examTitle, - testExam: true, - startDate: dayjs().subtract(1, 'day'), - visibleDate: dayjs().subtract(2, 'days'), - workingTime: 15, - examMaxPoints: 10, - numberOfCorrectionRoundsInExam: 1, - }; - examAPIRequests.createExam(examConfig).then((examResponse) => { - exam = examResponse.body; - examExerciseGroupCreation.addGroupWithExercise(exam, ExerciseType.TEXT, { textFixture }).then((response) => { - exerciseArray.push(response); - }); - }); - }); - - it('Participates as a student in a registered exam', () => { - examParticipation.startParticipation(studentFour, course, exam); - const textExerciseIndex = 0; - const textExercise = exerciseArray[textExerciseIndex]; - examNavigation.openExerciseAtIndex(textExerciseIndex); - examParticipation.makeSubmission(textExercise.id, textExercise.type, textExercise.additionalData); - examParticipation.clickSaveAndContinue(); - examParticipation.checkExamFullnameInputExists(); - examParticipation.checkYourFullname(studentFourName); - examStartEnd.finishExam().then((request: Interception) => { - expect(request.response!.statusCode).to.eq(200); - }); - examParticipation.verifyTextExerciseOnFinalPage(textExercise.additionalData!.textFixture!); - examParticipation.checkExamTitle(examTitle); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exam/test-exam/TestExamStudentExams.cy.ts b/src/test/cypress/e2e/exam/test-exam/TestExamStudentExams.cy.ts deleted file mode 100644 index 63e7df7b6a31..000000000000 --- a/src/test/cypress/e2e/exam/test-exam/TestExamStudentExams.cy.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; -import { CypressUserManagement, admin, studentOne, studentThree, studentTwo } from '../../../support/users'; -import { - courseManagement, - courseManagementAPIRequest, - examAPIRequests, - examExerciseGroupCreation, - examManagement, - examNavigation, - examParticipation, - navigationBar, - studentExamManagement, -} from '../../../support/artemis'; -import { convertModelAfterMultiPart, generateUUID } from '../../../support/utils'; -import { CypressCredentials } from '../../../support/users'; -import { Exercise, ExerciseType } from '../../../support/constants'; -import dayjs from 'dayjs/esm'; - -// Common primitives -const uid = generateUUID(); -const examTitle = 'test-exam' + uid; -const textFixture = 'loremIpsum-short.txt'; -const students: Array = [studentOne, studentTwo, studentThree]; -const studentNames: string[] = []; - -const userManagement = new CypressUserManagement(); - -let examExercise: Exercise; - -describe.skip('Test Exam - student exams', () => { - let course: Course; - let exam: Exam; - - before('Create course and exam', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse().then((response) => { - course = convertModelAfterMultiPart(response); - - for (const student of students) { - courseManagementAPIRequest.addStudentToCourse(course, student); - } - - const examConfig: Exam = { - course, - title: examTitle, - testExam: true, - startDate: dayjs().subtract(1, 'day'), - visibleDate: dayjs().subtract(2, 'days'), - workingTime: 5, - examMaxPoints: 10, - numberOfCorrectionRoundsInExam: 1, - }; - - examAPIRequests.createExam(examConfig).then((examResponse) => { - exam = examResponse.body; - examExerciseGroupCreation.addGroupWithExercise(exam, ExerciseType.TEXT, { textFixture }).then((response) => { - examExercise = response; - participateInExam(students.at(0)!, course, exam, true, true); - participateInExam(students.at(1)!, course, exam, true, false); - participateInExam(students.at(2)!, course, exam, false, false); - }); - }); - }); - }); - - before('Get student names', () => { - cy.login(admin); - for (let index = 0; index < students.length; index++) { - userManagement.getUserInfo(students[index].username, (userInfo) => { - studentNames[index] = userInfo.name; - }); - } - }); - - beforeEach(() => { - cy.login(admin); - }); - - describe('Check exam participants and their submissions', () => { - it('Open the list of exam students', () => { - cy.visit('/'); - navigationBar.openCourseManagement(); - courseManagement.openExamsOfCourse(course.id!); - examManagement.openStudentExams(exam.id!); - for (const student of students) { - studentExamManagement.checkExamStudent(student.username); - } - studentExamManagement.getStudentExamRows().should('have.length', students.length); - - studentExamManagement.checkExamProperty(students.at(0)!.username, 'Started', 'Yes'); - studentExamManagement.checkExamProperty(students.at(1)!.username, 'Started', 'Yes'); - studentExamManagement.checkExamProperty(students.at(2)!.username, 'Started', 'No'); - - studentExamManagement.checkExamProperty(students.at(0)!.username, 'Submitted', 'Yes'); - studentExamManagement.checkExamProperty(students.at(1)!.username, 'Submitted', 'No'); - studentExamManagement.checkExamProperty(students.at(2)!.username, 'Submitted', 'No'); - - studentExamManagement.checkExamProperty(students.at(1)!.username, 'Used working time', '0s'); - studentExamManagement.checkExamProperty(students.at(2)!.username, 'Used working time', '0s'); - - studentExamManagement.checkExamProperty(students.at(0)!.username, 'Student', studentNames.at(0)!.trim()); - studentExamManagement.checkExamProperty(students.at(1)!.username, 'Student', studentNames.at(1)!.trim()); - studentExamManagement.checkExamProperty(students.at(2)!.username, 'Student', studentNames.at(2)!.trim()); - }); - - it('Search for a student in exams', () => { - cy.visit('/'); - navigationBar.openCourseManagement(); - courseManagement.openExamsOfCourse(course.id!); - examManagement.openStudentExams(exam.id!); - - let searchText = students.at(0)!.username + ', ' + students.at(1)!.username; - studentExamManagement.typeSearchText(searchText); - studentExamManagement.checkExamStudent(students.at(0)!.username); - studentExamManagement.checkExamStudent(students.at(1)!.username); - - searchText = studentNames.at(0)! + ', ' + studentNames.at(1)!; - studentExamManagement.typeSearchText(searchText); - studentExamManagement.checkExamStudent(students.at(0)!.username); - studentExamManagement.checkExamStudent(students.at(1)!.username); - - searchText = 'Artemis Test User'; - studentExamManagement.typeSearchText(searchText); - studentExamManagement.checkExamStudent(students.at(0)!.username); - studentExamManagement.checkExamStudent(students.at(1)!.username); - studentExamManagement.checkExamStudent(students.at(2)!.username); - }); - }); - - function participateInExam(student: CypressCredentials, course: Course, exam: Exam, toStart: boolean, toSubmit: boolean) { - if (!toStart) { - examParticipation.openExam(student, course, exam); - } else { - examParticipation.startParticipation(student, course, exam); - examNavigation.openExerciseAtIndex(0); - examParticipation.makeSubmission(examExercise.id, examExercise.type, examExercise.additionalData); - } - - if (toSubmit) { - examParticipation.handInEarly(); - } - } - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exam/test-exam/TestExamTestRun.cy.ts b/src/test/cypress/e2e/exam/test-exam/TestExamTestRun.cy.ts deleted file mode 100644 index 015700fb7a0f..000000000000 --- a/src/test/cypress/e2e/exam/test-exam/TestExamTestRun.cy.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { Interception } from 'cypress/types/net-stubbing'; - -import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; - -import javaBuildErrorSubmission from '../../../fixtures/exercise/programming/java/build_error/submission.json'; -import { courseManagementAPIRequest, examAPIRequests, examExerciseGroupCreation, examManagement, examNavigation, examParticipation, examTestRun } from '../../../support/artemis'; -import { Exercise, ExerciseType } from '../../../support/constants'; -import { admin, instructor } from '../../../support/users'; -import { convertModelAfterMultiPart, generateUUID } from '../../../support/utils'; - -// Common primitives -const textFixture = 'loremIpsum.txt'; -const examTitle = 'exam' + generateUUID(); - -describe.skip('Test exam test run', () => { - let course: Course; - let exam: Exam; - let testRun: any; - let exerciseArray: Array = []; - - before('Create course', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse({ customizeGroups: true }).then((response) => { - course = convertModelAfterMultiPart(response); - const examConfig: Exam = { - course, - title: examTitle, - testExam: true, - examMaxPoints: 40, - numberOfExercisesInExam: 4, - }; - examAPIRequests.createExam(examConfig).then((examResponse) => { - exam = examResponse.body; - Promise.all([ - examExerciseGroupCreation.addGroupWithExercise(exam, ExerciseType.TEXT, { textFixture }), - examExerciseGroupCreation.addGroupWithExercise(exam, ExerciseType.PROGRAMMING, { submission: javaBuildErrorSubmission, practiceMode: true }), - examExerciseGroupCreation.addGroupWithExercise(exam, ExerciseType.QUIZ, { quizExerciseID: 0 }), - examExerciseGroupCreation.addGroupWithExercise(exam, ExerciseType.MODELING), - ]).then((responses) => { - exerciseArray = exerciseArray.concat(responses); - }); - }); - }); - }); - - beforeEach('Create test run instance', () => { - cy.login(instructor); - // TODO: API call does not work yet, for now we use the UI to create the test run - // courseManagementAPIRequest.createExamTestRun(exam, exerciseArray).then((response: any) => { - // testRun = response.body; - // }); - cy.visit(`/course-management/${course.id}/exams/${exam.id}`); - examManagement.openTestRun(); - examTestRun.createTestRun(); - examTestRun.setWorkingTimeMinutes(2); - examTestRun.confirmTestRun().then((testRunResponse: Interception) => { - testRun = testRunResponse.response!.body; - }); - }); - - it('Create a test run', () => { - cy.login(instructor); - - let testRunID: number; - const minutes = 40; - const seconds = 30; - - cy.visit(`/course-management/${course.id}/exams/${exam.id}`); - examManagement.openTestRun(); - examTestRun.createTestRun(); - examTestRun.setWorkingTimeMinutes(minutes); - examTestRun.setWorkingTimeSeconds(seconds); - examTestRun.confirmTestRun().then((testRunResponse: Interception) => { - const testRun = testRunResponse.response!.body; - testRunID = testRun.id; - - expect(testRunResponse.response!.statusCode).to.eq(200); - expect(testRun.testRun).to.be.true; - expect(testRun.submitted).to.be.false; - expect(testRun.workingTime).to.eq(minutes * 60 + seconds); - - examTestRun.getWorkingTime(testRunID).contains('40min 30s'); - examTestRun.getStarted(testRunID).contains('No'); - examTestRun.getSubmitted(testRunID).contains('No'); - }); - }); - - // Skip since this functionality is not yet supported - // TODO: Activate test as soon as editing test run working times for test exams is possible - // it.skip('Change test run working time', () => { - // const hour = 1; - // const minutes = 20; - // const seconds = 45; - - // cy.login(instructor); - // examTestRun.openTestRunPage(course, exam); - // examTestRun.changeWorkingTime(testRun.id); - // examTestRun.setWorkingTimeHours(hour); - // examTestRun.setWorkingTimeMinutes(minutes); - // examTestRun.setWorkingTimeSeconds(seconds); - // examTestRun.saveTestRun().then((testRunResponse: Interception) => { - // const testRun = testRunResponse.response!.body; - - // expect(testRun.id).to.eq(testRun.id); - // expect(testRunResponse.response!.statusCode).to.eq(200); - // expect(testRun.workingTime).to.eq(hour * 3600 + minutes * 60 + seconds); - - // examTestRun.openTestRunPage(course, exam); - // examTestRun.getWorkingTime(testRun.id).contains(`${hour}h ${minutes}min ${seconds}s`); - // examTestRun.getStarted(testRun.id).contains('No'); - // examTestRun.getSubmitted(testRun.id).contains('No'); - // }); - // }); - - it('Conducts a test run', () => { - examTestRun.startParticipation(instructor, course, exam, testRun.id); - examTestRun.getTestRunRibbon().contains('Test Run'); - - for (let j = 0; j < exerciseArray.length; j++) { - const exercise = exerciseArray[j]; - examNavigation.openExerciseAtIndex(j); - examParticipation.makeSubmission(exercise.id, exercise.type, exercise.additionalData); - } - examParticipation.handInEarly(); - for (let j = 0; j < exerciseArray.length; j++) { - const exercise = exerciseArray[j]; - examParticipation.verifyExerciseTitleOnFinalPage(exercise.id, exercise.exerciseGroup!.title!); - if (exercise.type === ExerciseType.TEXT) { - examParticipation.verifyTextExerciseOnFinalPage(exercise.additionalData!.textFixture!); - } - } - examParticipation.checkExamTitle(examTitle); - examTestRun.openTestRunPage(course, exam); - examTestRun.getStarted(testRun.id).contains('Yes'); - examTestRun.getSubmitted(testRun.id).contains('Yes'); - }); - - it('Deletes a test run', () => { - cy.login(instructor); - examTestRun.openTestRunPage(course, exam); - examTestRun.getTestRunIdElement(testRun.id).should('exist'); - examTestRun.deleteTestRun(testRun.id); - examTestRun.getTestRun(testRun.id).should('not.exist'); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exercises/ExerciseImport.cy.ts b/src/test/cypress/e2e/exercises/ExerciseImport.cy.ts deleted file mode 100644 index 306a07bfd0a8..000000000000 --- a/src/test/cypress/e2e/exercises/ExerciseImport.cy.ts +++ /dev/null @@ -1,177 +0,0 @@ -import { Interception } from 'cypress/types/net-stubbing'; -import dayjs from 'dayjs/esm'; - -import { Course } from 'app/entities/course.model'; -import { ModelingExercise } from 'app/entities/modeling-exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; -import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; - -import javaPartiallySuccessfulSubmission from '../../fixtures/exercise/programming/java/partially_successful/submission.json'; -import multipleChoiceQuizTemplate from '../../fixtures/exercise/quiz/multiple_choice/template.json'; -import { - courseManagementAPIRequest, - courseManagementExercises, - courseOverview, - exerciseAPIRequest, - modelingExerciseCreation, - modelingExerciseEditor, - programmingExerciseCreation, - programmingExerciseEditor, - quizExerciseCreation, - quizExerciseMultipleChoice, - textExerciseCreation, - textExerciseEditor, -} from '../../support/artemis'; -import { admin, instructor, studentOne } from '../../support/users'; -import { checkField, convertModelAfterMultiPart, generateUUID } from '../../support/utils'; - -describe.skip('Import exercises', { scrollBehavior: 'center' }, () => { - let course: Course; - let secondCourse: Course; - let textExercise: TextExercise; - let quizExercise: QuizExercise; - let modelingExercise: ModelingExercise; - let programmingExercise: ProgrammingExercise; - - before('Setup course with exercises', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse({ customizeGroups: true }).then((response) => { - course = convertModelAfterMultiPart(response); - courseManagementAPIRequest.addInstructorToCourse(course, instructor); - exerciseAPIRequest.createTextExercise({ course }).then((response) => { - textExercise = response.body; - }); - exerciseAPIRequest.createQuizExercise({ course }, [multipleChoiceQuizTemplate]).then((response) => { - quizExercise = convertModelAfterMultiPart(response); - }); - exerciseAPIRequest.createModelingExercise({ course }).then((response) => { - modelingExercise = response.body; - }); - exerciseAPIRequest.createProgrammingExercise({ course }).then((response) => { - programmingExercise = response.body; - }); - courseManagementAPIRequest.createCourse({ customizeGroups: true }).then((response) => { - secondCourse = convertModelAfterMultiPart(response); - courseManagementAPIRequest.addStudentToCourse(secondCourse, studentOne); - courseManagementAPIRequest.addInstructorToCourse(secondCourse, instructor); - }); - }); - }); - - after('Delete Courses', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - courseManagementAPIRequest.deleteCourse(secondCourse, admin); - }); - - it('Imports text exercise', () => { - cy.login(instructor, `/course-management/${secondCourse.id}/exercises`); - courseManagementExercises.importTextExercise(); - courseManagementExercises.clickImportExercise(textExercise.id!); - - checkField('#field_title', textExercise.title!); - checkField('#field_points', textExercise.maxPoints!); - - textExerciseCreation.setReleaseDate(dayjs()); - textExerciseCreation.setDueDate(dayjs().add(1, 'days')); - textExerciseCreation.setAssessmentDueDate(dayjs().add(2, 'days')); - - textExerciseCreation.import().then((request: Interception) => { - const exercise = request.response!.body; - cy.login(studentOne, `/courses/${secondCourse.id}`); - courseOverview.openExerciseOverview(exercise.title!); - courseOverview.startExercise(exercise.id!); - courseOverview.openRunningExercise(exercise.id!); - cy.fixture('loremIpsum-short.txt').then((submission) => { - textExerciseEditor.shouldShowNumberOfWords(0); - textExerciseEditor.shouldShowNumberOfCharacters(0); - textExerciseEditor.typeSubmission(exercise.id!, submission); - textExerciseEditor.shouldShowNumberOfWords(16); - textExerciseEditor.shouldShowNumberOfCharacters(83); - textExerciseEditor.submit().then((request: Interception) => { - expect(request.response!.body.text).to.eq(submission); - expect(request.response!.body.submitted).to.be.true; - expect(request.response!.statusCode).to.eq(200); - }); - }); - }); - }); - - it('Imports quiz exercise', () => { - cy.login(instructor, `/course-management/${secondCourse.id}/exercises`); - courseManagementExercises.importQuizExercise(); - courseManagementExercises.clickImportExercise(quizExercise.id!); - - checkField('#field_title', quizExercise.title!); - checkField('#quiz-duration-minutes', quizExercise.duration! / 60); - - cy.wait(500); - - quizExerciseCreation.setVisibleFrom(dayjs()); - - quizExerciseCreation.import().then((request: Interception) => { - const exercise = request.response!.body; - courseManagementExercises.startQuiz(exercise.id!); - cy.login(studentOne, `/courses/${secondCourse.id}`); - courseOverview.openExerciseOverview(exercise.title!); - courseOverview.startExercise(exercise.id!); - quizExerciseMultipleChoice.tickAnswerOption(exercise.id!, 0); - quizExerciseMultipleChoice.tickAnswerOption(exercise.id!, 2); - quizExerciseMultipleChoice.submit().then((request: Interception) => { - expect(request.response!.body.submitted).to.be.true; - expect(request.response!.statusCode).to.eq(200); - }); - }); - }); - - it('Imports modeling exercise', () => { - cy.login(instructor, `/course-management/${secondCourse.id}/exercises`); - courseManagementExercises.importModelingExercise(); - courseManagementExercises.clickImportExercise(modelingExercise.id!); - - checkField('#field_title', modelingExercise.title!); - checkField('#field_points', modelingExercise.maxPoints!); - - modelingExerciseCreation.setReleaseDate(dayjs()); - modelingExerciseCreation.setDueDate(dayjs().add(1, 'days')); - modelingExerciseCreation.setAssessmentDueDate(dayjs().add(2, 'days')); - - modelingExerciseCreation.import().then((request: Interception) => { - const exercise = request.response!.body; - cy.login(studentOne, `/courses/${secondCourse.id}`); - courseOverview.openExerciseOverview(exercise.title!); - courseOverview.startExercise(exercise.id!); - courseOverview.openRunningExercise(exercise.id!); - modelingExerciseEditor.addComponentToModel(exercise.id!, 1); - modelingExerciseEditor.addComponentToModel(exercise.id!, 2); - modelingExerciseEditor.addComponentToModel(exercise.id!, 3); - modelingExerciseEditor.submit().then((request: Interception) => { - expect(request.response!.body.submitted).to.be.true; - expect(request.response!.statusCode).to.eq(200); - }); - }); - }); - - it('Imports programming exercise', () => { - cy.login(instructor, `/course-management/${secondCourse.id}/exercises`); - courseManagementExercises.importProgrammingExercise(); - courseManagementExercises.clickImportExercise(programmingExercise.id!); - - checkField('#field_points', programmingExercise.maxPoints!); - - programmingExerciseCreation.setTitle('Import Test'); - programmingExerciseCreation.setShortName('importtest' + generateUUID()); - programmingExerciseCreation.setDueDate(dayjs().add(3, 'days')); - - programmingExerciseCreation.import().then((request: Interception) => { - const exercise = request.response!.body; - cy.login(studentOne, `/courses/${secondCourse.id}`); - courseOverview.openExerciseOverview(exercise.title!); - courseOverview.startExercise(exercise.id!); - courseOverview.openRunningExercise(exercise.id!); - programmingExerciseEditor.makeSubmissionAndVerifyResults(exercise.id!, javaPartiallySuccessfulSubmission, () => { - programmingExerciseEditor.getResultScore().contains(javaPartiallySuccessfulSubmission.expectedResult).and('be.visible'); - }); - }); - }); -}); diff --git a/src/test/cypress/e2e/exercises/file-upload/FileUploadExerciseAssessment.cy.ts b/src/test/cypress/e2e/exercises/file-upload/FileUploadExerciseAssessment.cy.ts deleted file mode 100644 index fa19aa4b05f6..000000000000 --- a/src/test/cypress/e2e/exercises/file-upload/FileUploadExerciseAssessment.cy.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { Course } from 'app/entities/course.model'; -import { FileUploadExercise } from 'app/entities/file-upload-exercise.model'; - -import { - courseAssessment, - courseManagement, - courseManagementAPIRequest, - courseOverview, - exerciseAPIRequest, - exerciseAssessment, - exerciseResult, - fileUploadExerciseAssessment, - fileUploadExerciseEditor, - fileUploadExerciseFeedback, -} from '../../../support/artemis'; -import { admin, instructor, studentOne, tutor } from '../../../support/users'; -import { convertModelAfterMultiPart } from '../../../support/utils'; - -// Common primitives -const tutorFeedback = 'Try to use some newlines next time!'; -const tutorFeedbackPoints = 4; -const complaint = "That feedback wasn't very useful!"; - -describe.skip('File upload exercise assessment', () => { - let course: Course; - let exercise: FileUploadExercise; - - before('Creates a file upload exercise and makes a student submission', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse().then((response) => { - course = convertModelAfterMultiPart(response); - courseManagementAPIRequest.addStudentToCourse(course, studentOne); - courseManagementAPIRequest.addTutorToCourse(course, tutor); - courseManagementAPIRequest.addInstructorToCourse(course, instructor); - exerciseAPIRequest.createFileUploadExercise({ course }).then((textResponse) => { - exercise = textResponse.body; - cy.login(studentOne, `/courses/${course.id}/exercises`); - courseOverview.startExercise(exercise.id!); - courseOverview.openRunningExercise(exercise.id!); - fileUploadExerciseEditor.attachFile('pdf-test-file.pdf'); - fileUploadExerciseEditor.submit(); - }); - }); - }); - - it('Assesses the file upload exercise submission', () => { - cy.login(tutor, '/course-management'); - courseManagement.openAssessmentDashboardOfCourse(course.id!); - courseAssessment.clickExerciseDashboardButton(); - exerciseAssessment.clickHaveReadInstructionsButton(); - exerciseAssessment.clickStartNewAssessment(); - fileUploadExerciseAssessment.getInstructionsRootElement().contains(exercise.title!).should('be.visible'); - fileUploadExerciseAssessment.getInstructionsRootElement().contains(exercise.problemStatement!).should('be.visible'); - fileUploadExerciseAssessment.getInstructionsRootElement().contains(exercise.exampleSolution!).should('be.visible'); - fileUploadExerciseAssessment.getInstructionsRootElement().contains(exercise.gradingInstructions!).should('be.visible'); - fileUploadExerciseAssessment.addNewFeedback(tutorFeedbackPoints, tutorFeedback); - fileUploadExerciseAssessment.submitFeedback(); - }); - - describe('Feedback', () => { - it('Student sees feedback after assessment due date and complains', () => { - cy.login(studentOne, `/courses/${course.id}/exercises/${exercise.id}`); - const percentage = tutorFeedbackPoints * 10; - exerciseResult.shouldShowExerciseTitle(exercise.title!); - exerciseResult.shouldShowProblemStatement(exercise.problemStatement!); - exerciseResult.shouldShowScore(percentage); - exerciseResult.clickOpenExercise(exercise.id!); - fileUploadExerciseFeedback.shouldShowAdditionalFeedback(tutorFeedbackPoints, tutorFeedback); - fileUploadExerciseFeedback.shouldShowScore(percentage); - fileUploadExerciseFeedback.complain(complaint); - }); - - it('Instructor can see complaint and reject it', () => { - cy.login(instructor, `/course-management/${course.id}/complaints`); - fileUploadExerciseAssessment.acceptComplaint('Makes sense', false).its('response.statusCode').should('eq', 200); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exercises/file-upload/FileUploadExerciseManagement.cy.ts b/src/test/cypress/e2e/exercises/file-upload/FileUploadExerciseManagement.cy.ts deleted file mode 100644 index 199c15c05eb9..000000000000 --- a/src/test/cypress/e2e/exercises/file-upload/FileUploadExerciseManagement.cy.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { Interception } from 'cypress/types/net-stubbing'; -import dayjs from 'dayjs/esm'; - -import { Course } from 'app/entities/course.model'; -import { FileUploadExercise } from 'app/entities/file-upload-exercise.model'; - -import { courseManagement, courseManagementAPIRequest, courseManagementExercises, exerciseAPIRequest, fileUploadExerciseCreation, navigationBar } from '../../../support/artemis'; -import { admin } from '../../../support/users'; -import { convertModelAfterMultiPart, generateUUID } from '../../../support/utils'; - -describe.skip('File upload exercise management', () => { - let course: Course; - - before(() => { - cy.login(admin); - courseManagementAPIRequest.createCourse().then((response) => { - course = convertModelAfterMultiPart(response); - }); - }); - - it('Creates a file upload exercise in the UI', { scrollBehavior: 'center' }, () => { - cy.visit('/'); - navigationBar.openCourseManagement(); - courseManagement.openExercisesOfCourse(course.id!); - courseManagementExercises.createFileUploadExercise(); - - // Fill out file upload exercise form - const exerciseTitle = 'file upload exercise' + generateUUID(); - fileUploadExerciseCreation.typeTitle(exerciseTitle); - fileUploadExerciseCreation.setReleaseDate(dayjs()); - fileUploadExerciseCreation.setDueDate(dayjs().add(1, 'days')); - fileUploadExerciseCreation.setAssessmentDueDate(dayjs().add(2, 'days')); - fileUploadExerciseCreation.typeMaxPoints(10); - const problemStatement = 'This is a problem statement'; - const exampleSolution = 'E = mc^2'; - fileUploadExerciseCreation.typeProblemStatement(problemStatement); - fileUploadExerciseCreation.typeExampleSolution(exampleSolution); - let exercise: FileUploadExercise; - fileUploadExerciseCreation.create().then((request: Interception) => { - exercise = request.response!.body; - }); - - // Make sure file upload exercise is shown in exercises list - cy.visit(`course-management/${course.id}/exercises`).then(() => { - courseManagementExercises.getExercise(exercise.id!).should('be.visible'); - }); - }); - - describe('File upload exercise deletion', () => { - let exercise: FileUploadExercise; - - before(() => { - cy.login(admin, '/'); - exerciseAPIRequest.createFileUploadExercise({ course }).then((response) => { - exercise = response.body; - }); - }); - - it('Deletes an existing file upload exercise', () => { - cy.login(admin, '/'); - navigationBar.openCourseManagement(); - courseManagement.openExercisesOfCourse(course.id!); - courseManagementExercises.deleteFileUploadExercise(exercise); - courseManagementExercises.getExercise(exercise.id!).should('not.exist'); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exercises/file-upload/FileUploadExerciseParticipation.cy.ts b/src/test/cypress/e2e/exercises/file-upload/FileUploadExerciseParticipation.cy.ts deleted file mode 100644 index a8c35cc2c7e8..000000000000 --- a/src/test/cypress/e2e/exercises/file-upload/FileUploadExerciseParticipation.cy.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Interception } from 'cypress/types/net-stubbing'; - -import { Course } from 'app/entities/course.model'; -import { FileUploadExercise } from 'app/entities/file-upload-exercise.model'; - -import { courseManagementAPIRequest, courseOverview, exerciseAPIRequest, fileUploadExerciseEditor } from '../../../support/artemis'; -import { admin, studentOne } from '../../../support/users'; -import { convertModelAfterMultiPart } from '../../../support/utils'; - -describe.skip('File upload exercise participation', () => { - let course: Course; - let exercise: FileUploadExercise; - - before(() => { - cy.login(admin); - courseManagementAPIRequest.createCourse().then((response) => { - course = convertModelAfterMultiPart(response); - courseManagementAPIRequest.addStudentToCourse(course, studentOne); - exerciseAPIRequest.createFileUploadExercise({ course }).then((exerciseResponse) => { - exercise = exerciseResponse.body; - }); - }); - }); - - it('Creates a file upload exercise in the UI', () => { - cy.login(studentOne, `/courses/${course.id}/exercises`); - courseOverview.startExercise(exercise.id!); - courseOverview.openRunningExercise(exercise.id!); - - // Verify the initial state of the text editor - fileUploadExerciseEditor.shouldShowExerciseTitleInHeader(exercise.title!); - fileUploadExerciseEditor.shouldShowProblemStatement(); - - // Make a submission - fileUploadExerciseEditor.attachFile('pdf-test-file.pdf'); - fileUploadExerciseEditor.submit().then((request: Interception) => { - expect(request.response!.body.submitted).to.be.true; - expect(request.response!.statusCode).to.eq(200); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exercises/modeling/ModelingExerciseAssessment.cy.ts b/src/test/cypress/e2e/exercises/modeling/ModelingExerciseAssessment.cy.ts deleted file mode 100644 index 235cac1ddd9a..000000000000 --- a/src/test/cypress/e2e/exercises/modeling/ModelingExerciseAssessment.cy.ts +++ /dev/null @@ -1,93 +0,0 @@ -import dayjs from 'dayjs/esm'; - -import { Course } from 'app/entities/course.model'; -import { ModelingExercise } from 'app/entities/modeling-exercise.model'; - -import { - courseAssessment, - courseManagement, - courseManagementAPIRequest, - exerciseAPIRequest, - exerciseAssessment, - exerciseResult, - modelingExerciseAssessment, - modelingExerciseFeedback, -} from '../../../support/artemis'; -import { admin, instructor, studentOne, tutor } from '../../../support/users'; -import { convertModelAfterMultiPart } from '../../../support/utils'; - -describe.skip('Modeling Exercise Assessment', () => { - let course: Course; - let modelingExercise: ModelingExercise; - - before('Create course', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse().then((response) => { - course = convertModelAfterMultiPart(response); - courseManagementAPIRequest.addStudentToCourse(course, studentOne); - courseManagementAPIRequest.addTutorToCourse(course, tutor); - courseManagementAPIRequest.addInstructorToCourse(course, instructor); - exerciseAPIRequest.createModelingExercise({ course }).then((modelingResponse) => { - modelingExercise = modelingResponse.body; - cy.login(studentOne); - cy.wait(500); - exerciseAPIRequest.startExerciseParticipation(modelingExercise.id!).then((participation) => { - exerciseAPIRequest.makeModelingExerciseSubmission(modelingExercise.id!, participation.body); - cy.login(instructor); - exerciseAPIRequest.updateModelingExerciseDueDate(modelingExercise, dayjs().add(5, 'seconds')); - }); - }); - }); - }); - - it('Tutor can assess a submission', () => { - cy.login(tutor, '/course-management'); - courseManagement.openAssessmentDashboardOfCourse(course.id!); - cy.wait(500); - courseAssessment.clickExerciseDashboardButton(); - exerciseAssessment.clickHaveReadInstructionsButton(); - exerciseAssessment.clickStartNewAssessment(); - exerciseAssessment.getLockedMessage().should('be.visible'); - modelingExerciseAssessment.addNewFeedback(1, 'Thanks, good job.'); - modelingExerciseAssessment.openAssessmentForComponent(1); - modelingExerciseAssessment.assessComponent(-1, 'False'); - modelingExerciseAssessment.clickNextAssessment(); - modelingExerciseAssessment.assessComponent(2, 'Good'); - modelingExerciseAssessment.clickNextAssessment(); - modelingExerciseAssessment.assessComponent(0, 'Unnecessary'); - modelingExerciseAssessment.submit(); - }); - - describe('Handling complaints', () => { - before(() => { - cy.login(admin); - exerciseAPIRequest - .updateModelingExerciseAssessmentDueDate(modelingExercise, dayjs()) - .its('body') - .then((exercise) => { - modelingExercise = exercise; - }); - }); - - it('Student can view the assessment and complain', () => { - cy.login(studentOne, `/courses/${course.id}/exercises/${modelingExercise.id}`); - exerciseResult.shouldShowExerciseTitle(modelingExercise.title!); - exerciseResult.shouldShowScore(20); - exerciseResult.clickOpenExercise(modelingExercise.id!); - modelingExerciseFeedback.shouldShowScore(20); - modelingExerciseFeedback.shouldShowAdditionalFeedback(1, 'Thanks, good job.'); - modelingExerciseFeedback.shouldShowComponentFeedback(1, 2, 'Good'); - modelingExerciseFeedback.complain('I am not happy with your assessment.'); - }); - - it('Instructor can see complaint and reject it', () => { - cy.login(instructor, `/course-management/${course.id}/complaints`); - courseAssessment.showTheComplaint(); - modelingExerciseAssessment.rejectComplaint('You are wrong.', false); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exercises/modeling/ModelingExerciseManagement.cy.ts b/src/test/cypress/e2e/exercises/modeling/ModelingExerciseManagement.cy.ts deleted file mode 100644 index e453c5bbc4fb..000000000000 --- a/src/test/cypress/e2e/exercises/modeling/ModelingExerciseManagement.cy.ts +++ /dev/null @@ -1,155 +0,0 @@ -import dayjs from 'dayjs/esm'; -import { MODELING_EDITOR_CANVAS } from 'src/test/cypress/support/constants'; - -import { Course } from 'app/entities/course.model'; -import { ModelingExercise } from 'app/entities/modeling-exercise.model'; - -import { - courseManagement, - courseManagementAPIRequest, - courseManagementExercises, - courseOverview, - exerciseAPIRequest, - modelingExerciseAssessment, - modelingExerciseCreation, - modelingExerciseEditor, - navigationBar, -} from '../../../support/artemis'; -import { admin, instructor, studentOne } from '../../../support/users'; -import { convertModelAfterMultiPart, generateUUID } from '../../../support/utils'; - -describe.skip('Modeling Exercise Management', () => { - let course: Course; - let modelingExercise: ModelingExercise; - - before('Create course', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse().then((response: Cypress.Response) => { - course = convertModelAfterMultiPart(response); - courseManagementAPIRequest.addInstructorToCourse(course, instructor); - courseManagementAPIRequest.addStudentToCourse(course, studentOne); - }); - }); - - describe('Create Modeling Exercise', () => { - it('Create a new modeling exercise', { scrollBehavior: 'center' }, () => { - cy.login(instructor); - cy.visit(`/course-management/${course.id}/exercises`); - courseManagementExercises.createModelingExercise(); - modelingExerciseCreation.setTitle('Modeling ' + generateUUID()); - modelingExerciseCreation.addCategories(['e2e-testing', 'test2']); - modelingExerciseCreation.setPoints(10); - modelingExerciseCreation - .save() - .its('response.body') - .then((body: any) => { - modelingExercise = body; - cy.contains(modelingExercise.title!).should('exist'); - cy.log('Create Example Solution'); - cy.visit(`/course-management/${course.id}/modeling-exercises/${modelingExercise.id}/edit`); - modelingExerciseEditor.addComponentToExampleSolutionModel(1); - modelingExerciseCreation.save(); - cy.get(MODELING_EDITOR_CANVAS).children().eq(0).should('exist'); - - cy.log('Create Example Submission'); - cy.visit(`/course-management/${course.id}/modeling-exercises/${modelingExercise.id}/example-submissions`); - modelingExerciseEditor.clickCreateExampleSubmission(); - modelingExerciseEditor.addComponentToExampleSolutionModel(1); - modelingExerciseEditor.addComponentToExampleSolutionModel(2); - modelingExerciseEditor.addComponentToExampleSolutionModel(3); - modelingExerciseEditor.clickCreateNewExampleSubmission(); - modelingExerciseEditor.showExampleAssessment(); - modelingExerciseAssessment.openAssessmentForComponent(1); - modelingExerciseAssessment.assessComponent(-1, 'False'); - modelingExerciseAssessment.clickNextAssessment(); - modelingExerciseAssessment.assessComponent(2, 'Good'); - modelingExerciseAssessment.clickNextAssessment(); - modelingExerciseAssessment.assessComponent(0, 'Unnecessary'); - modelingExerciseAssessment.submitExample(); - cy.visit(`/course-management/${course.id}/modeling-exercises/${modelingExercise.id}`); - modelingExerciseEditor.getModelingCanvas().should('exist'); - }); - }); - - after('Delete modeling exercise', () => { - if (modelingExercise) { - cy.login(admin); - exerciseAPIRequest.deleteModelingExercise(modelingExercise.id!); - } - }); - }); - - describe('Edit Modeling Exercise', () => { - before('Create Modeling Exercise', () => { - cy.login(admin); - exerciseAPIRequest.createModelingExercise({ course }).then((resp) => { - modelingExercise = resp.body; - }); - }); - - it('Edit Existing Modeling Exercise', { scrollBehavior: 'center' }, () => { - cy.visit(`/course-management/${course.id}/modeling-exercises/${modelingExercise.id}/edit`); - const newTitle = 'New Modeling Exercise Title'; - const points = 100; - modelingExerciseCreation.setTitle(newTitle); - modelingExerciseCreation.pickDifficulty({ hard: true }); - modelingExerciseCreation.setReleaseDate(dayjs().add(1, 'day')); - modelingExerciseCreation.setDueDate(dayjs().add(2, 'day')); - modelingExerciseCreation.setAssessmentDueDate(dayjs().add(3, 'day')); - modelingExerciseCreation.includeInOverallScore(); - modelingExerciseCreation.setPoints(points); - modelingExerciseCreation.save(); - cy.visit(`/course-management/${course.id}/exercises`); - courseManagementExercises.getModelingExerciseTitle(modelingExercise.id!).contains(newTitle); - courseManagementExercises.getModelingExerciseMaxPoints(modelingExercise.id!).contains(points.toString()); - }); - - after('Delete exercise', () => { - exerciseAPIRequest.deleteModelingExercise(modelingExercise.id!); - }); - }); - - describe('Delete Modeling Exercise', () => { - let modelingExercise: ModelingExercise; - - before('Create Modeling exercise', () => { - cy.login(admin, '/'); - exerciseAPIRequest.createModelingExercise({ course }).then((resp) => { - modelingExercise = resp.body; - }); - }); - - it('Deletes an existing Modeling exercise', () => { - cy.login(instructor, '/'); - navigationBar.openCourseManagement(); - courseManagement.openExercisesOfCourse(course.id!); - courseManagementExercises.deleteModelingExercise(modelingExercise); - courseManagementExercises.getExercise(modelingExercise.id!).should('not.exist'); - }); - }); - - describe('Modeling Exercise Release', () => { - it('Student can not see unreleased Modeling Exercise', () => { - cy.login(instructor); - exerciseAPIRequest.createModelingExercise({ course }, 'Modeling ' + generateUUID(), dayjs().add(1, 'hour')).then((resp) => { - modelingExercise = resp.body; - }); - cy.login(studentOne, '/courses'); - cy.contains(course.title!).click({ force: true }); - courseOverview.getExercises().should('have.length', 0); - }); - - it('Student can see released Modeling Exercise', () => { - cy.login(instructor); - exerciseAPIRequest.createModelingExercise({ course }, 'Modeling ' + generateUUID(), dayjs().subtract(1, 'hour')).then((resp) => { - modelingExercise = resp.body; - }); - cy.login(studentOne, '/courses'); - cy.visit('/courses/' + course.id + '/exercises/' + modelingExercise.id); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exercises/modeling/ModelingExerciseParticipation.cy.ts b/src/test/cypress/e2e/exercises/modeling/ModelingExerciseParticipation.cy.ts deleted file mode 100644 index dcbf04bc2918..000000000000 --- a/src/test/cypress/e2e/exercises/modeling/ModelingExerciseParticipation.cy.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Course } from 'app/entities/course.model'; -import { ModelingExercise } from 'app/entities/modeling-exercise.model'; - -import { courseManagementAPIRequest, courseOverview, exerciseAPIRequest, modelingExerciseEditor } from '../../../support/artemis'; -import { admin, studentOne } from '../../../support/users'; -import { convertModelAfterMultiPart } from '../../../support/utils'; - -describe.skip('Modeling Exercise Participation', () => { - let course: Course; - let modelingExercise: ModelingExercise; - - before('Create course', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse().then((response: Cypress.Response) => { - course = convertModelAfterMultiPart(response); - courseManagementAPIRequest.addStudentToCourse(course, studentOne); - exerciseAPIRequest.createModelingExercise({ course }).then((resp: Cypress.Response) => { - modelingExercise = resp.body; - }); - }); - }); - - it('Student can start and submit their model', () => { - cy.login(studentOne, `/courses/${course.id}`); - courseOverview.startExercise(modelingExercise.id!); - courseOverview.openRunningExercise(modelingExercise.id!); - modelingExerciseEditor.addComponentToModel(modelingExercise.id!, 1, false, 310, 320); - modelingExerciseEditor.addComponentToModel(modelingExercise.id!, 2, false, 730, 500); - modelingExerciseEditor.addComponentToModel(modelingExercise.id!, 3, false, 1000, 100); - modelingExerciseEditor.submit(); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exercises/programming/ProgrammingExerciseAssessment.cy.ts b/src/test/cypress/e2e/exercises/programming/ProgrammingExerciseAssessment.cy.ts deleted file mode 100644 index c8ba45de348e..000000000000 --- a/src/test/cypress/e2e/exercises/programming/ProgrammingExerciseAssessment.cy.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { Interception } from 'cypress/types/net-stubbing'; -import dayjs from 'dayjs/esm'; - -import { Course } from 'app/entities/course.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; - -import { - courseAssessment, - courseManagement, - courseManagementAPIRequest, - exerciseAPIRequest, - exerciseAssessment, - exerciseResult, - programmingExerciseAssessment, - programmingExerciseEditor, - programmingExerciseFeedback, -} from '../../../support/artemis'; -import { ProgrammingExerciseAssessmentType } from '../../../support/constants'; -import { admin, instructor, studentOne, tutor } from '../../../support/users'; -import { convertModelAfterMultiPart } from '../../../support/utils'; - -// Common primitives -const tutorFeedback = 'You are missing some classes! The classes, which you implemented look good though.'; -const tutorFeedbackPoints = 5; -const tutorCodeFeedback = 'The input parameter should be mentioned in javadoc!'; -const tutorCodeFeedbackPoints = -2; -const complaint = "That feedback wasn't very useful!"; - -describe.skip('Programming exercise assessment', () => { - let course: Course; - let exercise: ProgrammingExercise; - let dueDate: dayjs.Dayjs; - let assessmentDueDate: dayjs.Dayjs; - - before('Creates a programming exercise and makes a student submission', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse({ customizeGroups: true }).then((response) => { - course = convertModelAfterMultiPart(response); - courseManagementAPIRequest.addStudentToCourse(course, studentOne); - courseManagementAPIRequest.addTutorToCourse(course, tutor); - courseManagementAPIRequest.addInstructorToCourse(course, instructor); - dueDate = dayjs().add(25, 'seconds'); - assessmentDueDate = dueDate.add(30, 'seconds'); - exerciseAPIRequest - .createProgrammingExercise({ - course, - recordTestwiseCoverage: false, - releaseDate: dayjs(), - dueDate: dueDate, - assessmentDate: assessmentDueDate, - assessmentType: ProgrammingExerciseAssessmentType.SEMI_AUTOMATIC, - }) - .then((programmingResponse) => { - exercise = programmingResponse.body; - cy.login(studentOne); - exerciseAPIRequest - .startExerciseParticipation(exercise.id!) - .its('body.id') - .then((participationId) => { - exerciseAPIRequest.makeProgrammingExerciseSubmission(participationId); - // Wait until the due date is in the past - const now = dayjs(); - if (now.isBefore(dueDate)) { - cy.wait(dueDate.diff(now, 'ms')); - } - }); - }); - }); - }); - - /* - * Skipped because the hovering behavior required to manually assess a submission is not supported by Cypress. - * Please refer to the playwright E2E test. - */ - it.skip('Assesses the programming exercise submission and verifies it', () => { - // Asses submission - cy.login(tutor, '/course-management'); - courseManagement.openAssessmentDashboardOfCourse(course.id!); - courseAssessment.clickExerciseDashboardButton(); - exerciseAssessment.clickHaveReadInstructionsButton(); - exerciseAssessment.clickStartNewAssessment(); - programmingExerciseEditor.openFileWithName(exercise.id!, 'BubbleSort.java'); - programmingExerciseAssessment.provideFeedbackOnCodeLine(9, tutorCodeFeedbackPoints, tutorCodeFeedback); - programmingExerciseAssessment.addNewFeedback(tutorFeedbackPoints, tutorFeedback); - programmingExerciseAssessment.submit().then((request: Interception) => { - expect(request.response!.statusCode).to.eq(200); - // Wait until the assessment due date is over - const now = dayjs(); - if (now.isBefore(assessmentDueDate)) { - cy.wait(assessmentDueDate.diff(now, 'ms')); - } - }); - - // Verify assessment as student - cy.login(studentOne, `/courses/${course.id}/exercises/${exercise.id}`); - const totalPoints = tutorFeedbackPoints + tutorCodeFeedbackPoints; - const percentage = totalPoints * 10; - exerciseResult.shouldShowExerciseTitle(exercise.title!); - programmingExerciseFeedback.complain(complaint); - exerciseResult.clickOpenCodeEditor(exercise.id!); - programmingExerciseFeedback.shouldShowRepositoryLockedWarning(); - programmingExerciseFeedback.shouldShowAdditionalFeedback(tutorFeedbackPoints, tutorFeedback); - programmingExerciseFeedback.shouldShowScore(percentage); - programmingExerciseFeedback.shouldShowCodeFeedback(exercise.id!, 'BubbleSort.java', tutorCodeFeedback, '-2', programmingExerciseEditor); - - // Accept complaint - cy.login(instructor, `/course-management/${course.id}/complaints`); - programmingExerciseAssessment.acceptComplaint('Makes sense', false).then((request: Interception) => { - expect(request.response!.statusCode).to.equal(200); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exercises/programming/ProgrammingExerciseManagement.cy.ts b/src/test/cypress/e2e/exercises/programming/ProgrammingExerciseManagement.cy.ts deleted file mode 100644 index e775d2174b3c..000000000000 --- a/src/test/cypress/e2e/exercises/programming/ProgrammingExerciseManagement.cy.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { Interception } from 'cypress/types/net-stubbing'; - -import { Course } from 'app/entities/course.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; - -import { courseManagement, courseManagementAPIRequest, courseManagementExercises, exerciseAPIRequest, navigationBar, programmingExerciseCreation } from '../../../support/artemis'; -import { admin } from '../../../support/users'; -import { convertModelAfterMultiPart, generateUUID } from '../../../support/utils'; - -describe.skip('Programming Exercise Management', () => { - let course: Course; - - before('Create course', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse({ customizeGroups: true }).then((response) => { - course = convertModelAfterMultiPart(response); - }); - }); - - describe('Programming exercise creation', () => { - it('Creates a new programming exercise', { scrollBehavior: 'center' }, () => { - cy.login(admin, '/'); - navigationBar.openCourseManagement(); - courseManagement.openExercisesOfCourse(course.id!); - courseManagementExercises.createProgrammingExercise(); - cy.url().should('include', '/programming-exercises/new'); - cy.log('Filling out programming exercise info...'); - const exerciseTitle = 'Programming exercise ' + generateUUID(); - programmingExerciseCreation.setTitle(exerciseTitle); - programmingExerciseCreation.setShortName('programming' + generateUUID()); - programmingExerciseCreation.setPackageName('de.test'); - programmingExerciseCreation.setPoints(100); - programmingExerciseCreation.checkAllowOnlineEditor(); - programmingExerciseCreation.generate().then((request: Interception) => { - const exercise = request.response!.body; - courseManagementExercises.getExerciseTitle().should('contain.text', exerciseTitle); - cy.url().should('include', `/programming-exercises/${exercise.id}`); - }); - }); - }); - - describe('Programming exercise deletion', () => { - let exercise: ProgrammingExercise; - - before(() => { - cy.login(admin, '/'); - exerciseAPIRequest.createProgrammingExercise({ course }).then((response) => { - exercise = response.body; - }); - }); - - it('Deletes an existing programming exercise', () => { - cy.login(admin, '/'); - navigationBar.openCourseManagement(); - courseManagement.openExercisesOfCourse(course.id!); - courseManagementExercises.deleteProgrammingExercise(exercise); - courseManagementExercises.getExercise(exercise.id!).should('not.exist'); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exercises/programming/ProgrammingExerciseParticipation.cy.ts b/src/test/cypress/e2e/exercises/programming/ProgrammingExerciseParticipation.cy.ts deleted file mode 100644 index 7f915290e41d..000000000000 --- a/src/test/cypress/e2e/exercises/programming/ProgrammingExerciseParticipation.cy.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { Course } from 'app/entities/course.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; - -import cAllSuccessful from '../../../fixtures/exercise/programming/c/all_successful/submission.json'; -import javaAllSuccessfulSubmission from '../../../fixtures/exercise/programming/java/all_successful/submission.json'; -import javaBuildErrorSubmission from '../../../fixtures/exercise/programming/java/build_error/submission.json'; -import javaPartiallySuccessfulSubmission from '../../../fixtures/exercise/programming/java/partially_successful/submission.json'; -import pythonAllSuccessful from '../../../fixtures/exercise/programming/python/all_successful/submission.json'; -import { courseManagementAPIRequest, exerciseAPIRequest, programmingExerciseEditor } from '../../../support/artemis'; -import { ProgrammingLanguage } from '../../../support/constants'; -import { admin, studentOne, studentThree, studentTwo } from '../../../support/users'; -import { convertModelAfterMultiPart } from '../../../support/utils'; - -describe.skip('Programming exercise participation', () => { - let course: Course; - - before('Create course', () => { - cy.login(admin, '/'); - courseManagementAPIRequest.createCourse({ customizeGroups: true }).then((response) => { - course = convertModelAfterMultiPart(response); - courseManagementAPIRequest.addStudentToCourse(course, studentOne); - courseManagementAPIRequest.addStudentToCourse(course, studentTwo); - courseManagementAPIRequest.addStudentToCourse(course, studentThree); - }); - }); - - describe('Java programming exercise', () => { - let exercise: ProgrammingExercise; - - before('Setup java programming exercise', () => { - cy.login(admin); - exerciseAPIRequest.createProgrammingExercise({ course, programmingLanguage: ProgrammingLanguage.JAVA }).then((exerciseResponse) => { - exercise = exerciseResponse.body; - }); - }); - - it('Makes a failing submission', () => { - programmingExerciseEditor.startParticipation(course.id!, exercise.id!, studentOne); - const submission = javaBuildErrorSubmission; - programmingExerciseEditor.makeSubmissionAndVerifyResults(exercise.id!, submission, () => { - programmingExerciseEditor.getResultScore().contains(submission.expectedResult).and('be.visible'); - }); - }); - - it('Makes a partially successful submission', () => { - programmingExerciseEditor.startParticipation(course.id!, exercise.id!, studentTwo); - const submission = javaPartiallySuccessfulSubmission; - programmingExerciseEditor.makeSubmissionAndVerifyResults(exercise.id!, submission, () => { - programmingExerciseEditor.getResultScore().contains(submission.expectedResult).and('be.visible'); - }); - }); - - it('Makes a successful submission', () => { - programmingExerciseEditor.startParticipation(course.id!, exercise.id!, studentThree); - const submission = javaAllSuccessfulSubmission; - programmingExerciseEditor.makeSubmissionAndVerifyResults(exercise.id!, submission, () => { - programmingExerciseEditor.getResultScore().contains(submission.expectedResult).and('be.visible'); - }); - }); - }); - - // Skip C tests within Jenkins used by the Postgres setup, since C is currently not supported there - // See https://github.com/ls1intum/Artemis/issues/6994 - if (Cypress.env('DB_TYPE') !== 'Postgres') { - describe('C programming exercise', () => { - let exercise: ProgrammingExercise; - - before('Setup c programming exercise', () => { - cy.login(admin); - exerciseAPIRequest.createProgrammingExercise({ course, programmingLanguage: ProgrammingLanguage.C }).then((exerciseResponse) => { - exercise = exerciseResponse.body; - }); - }); - - it('Makes a submission', () => { - programmingExerciseEditor.startParticipation(course.id!, exercise.id!, studentOne); - const submission = cAllSuccessful; - programmingExerciseEditor.makeSubmissionAndVerifyResults(exercise.id!, submission, () => { - programmingExerciseEditor.getResultScore().contains(submission.expectedResult).and('be.visible'); - }); - }); - }); - } - - describe('Python programming exercise', () => { - let exercise: ProgrammingExercise; - - before('Setup python programming exercise', () => { - cy.login(admin); - exerciseAPIRequest.createProgrammingExercise({ course, programmingLanguage: ProgrammingLanguage.PYTHON }).then((exerciseResponse) => { - exercise = exerciseResponse.body; - }); - }); - - it('Makes a submission', () => { - programmingExerciseEditor.startParticipation(course.id!, exercise.id!, studentOne); - const submission = pythonAllSuccessful; - programmingExerciseEditor.makeSubmissionAndVerifyResults(exercise.id!, submission, () => { - programmingExerciseEditor.getResultScore().contains(submission.expectedResult).and('be.visible'); - }); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exercises/programming/ProgrammingExerciseStaticCodeAnalysis.cy.ts b/src/test/cypress/e2e/exercises/programming/ProgrammingExerciseStaticCodeAnalysis.cy.ts deleted file mode 100644 index 9f06db6704d8..000000000000 --- a/src/test/cypress/e2e/exercises/programming/ProgrammingExerciseStaticCodeAnalysis.cy.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { Course } from 'app/entities/course.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; - -import javaScaSubmission from '../../../fixtures/exercise/programming/java/static_code_analysis/submission.json'; -import { courseManagementAPIRequest, exerciseAPIRequest, programmingExerciseEditor, programmingExerciseScaFeedback, programmingExercisesScaConfig } from '../../../support/artemis'; -import { admin, studentOne } from '../../../support/users'; -import { convertModelAfterMultiPart } from '../../../support/utils'; - -describe.skip('Static code analysis tests', () => { - let course: Course; - let exercise: ProgrammingExercise; - - before('Create course', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse({ customizeGroups: true }).then((response) => { - course = convertModelAfterMultiPart(response); - courseManagementAPIRequest.addStudentToCourse(course, studentOne); - exerciseAPIRequest.createProgrammingExercise({ course, scaMaxPenalty: 50 }).then((exerciseResponse) => { - exercise = exerciseResponse.body; - }); - }); - }); - - it('Configures SCA grading and makes a successful submission with SCA errors', () => { - // Configure SCA grading - cy.login(admin); - programmingExercisesScaConfig.visit(course.id!, exercise.id!); - programmingExercisesScaConfig.makeEveryScaCategoryInfluenceGrading(); - programmingExercisesScaConfig.saveChanges(); - - // Make submission with SCA errors - programmingExerciseEditor.startParticipation(course.id!, exercise.id!, studentOne); - programmingExerciseEditor.makeSubmissionAndVerifyResults(exercise.id!, javaScaSubmission, () => { - programmingExerciseEditor.getResultScore().contains(javaScaSubmission.expectedResult).and('be.visible').click(); - programmingExerciseScaFeedback.shouldShowPointChart(); - // We have to verify those static texts here. If we don't verify those messages the only difference between the SCA and normal programming exercise - // tests is the score, which hardly verifies the SCA functionality - programmingExerciseScaFeedback.shouldShowCodeIssue("Variable 'literal1' must be private and have accessor methods.", '5'); - programmingExerciseScaFeedback.shouldShowCodeIssue("Avoid unused private fields such as 'LITERAL_TWO'.", '0.5'); - programmingExerciseScaFeedback.shouldShowCodeIssue("de.test.BubbleSort.literal1 isn't final but should be", '2.5'); - programmingExerciseScaFeedback.shouldShowCodeIssue('Unread public/protected field: de.test.BubbleSort.literal1', '0.2'); - programmingExerciseScaFeedback.closeModal(); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exercises/quiz-exercise/QuizExerciseAssessment.cy.ts b/src/test/cypress/e2e/exercises/quiz-exercise/QuizExerciseAssessment.cy.ts deleted file mode 100644 index 2a76b25de58c..000000000000 --- a/src/test/cypress/e2e/exercises/quiz-exercise/QuizExerciseAssessment.cy.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Course } from 'app/entities/course.model'; -import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; -import multipleChoiceQuizTemplate from '../../../fixtures/exercise/quiz/multiple_choice/template.json'; -import shortAnswerQuizTemplate from '../../../fixtures/exercise/quiz/short_answer/template.json'; -import { courseManagementAPIRequest, exerciseAPIRequest, exerciseResult } from '../../../support/artemis'; -import { admin, studentOne, tutor } from '../../../support/users'; -import { convertModelAfterMultiPart } from '../../../support/utils'; - -describe.skip('Quiz Exercise Assessment', () => { - let course: Course; - let quizExercise: QuizExercise; - - before('Create course', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse().then((response) => { - course = convertModelAfterMultiPart(response); - courseManagementAPIRequest.addStudentToCourse(course, studentOne); - courseManagementAPIRequest.addTutorToCourse(course, tutor); - }); - }); - - describe( - 'MC Quiz assessment', - { - retries: 2, - }, - () => { - it('Assesses a mc quiz submission automatically', () => { - cy.login(admin); - exerciseAPIRequest.createQuizExercise({ course }, [multipleChoiceQuizTemplate], undefined, undefined, 10).then((quizResponse) => { - quizExercise = convertModelAfterMultiPart(quizResponse); - exerciseAPIRequest.setQuizVisible(quizExercise.id!); - exerciseAPIRequest.startQuizNow(quizExercise.id!); - cy.login(studentOne); - exerciseAPIRequest.startExerciseParticipation(quizExercise.id!); - exerciseAPIRequest.createMultipleChoiceSubmission(quizExercise, [0, 2]); - cy.visit('/courses/' + course.id + '/exercises/' + quizExercise.id); - exerciseResult.shouldShowScore(50); - }); - }); - }, - ); - - describe( - 'SA Quiz assessment', - { - retries: 2, - }, - () => { - it('Assesses a sa quiz submission automatically', () => { - cy.login(admin); - exerciseAPIRequest.createQuizExercise({ course }, [shortAnswerQuizTemplate], undefined, undefined, 10).then((quizResponse) => { - quizExercise = convertModelAfterMultiPart(quizResponse); - exerciseAPIRequest.setQuizVisible(quizExercise.id!); - exerciseAPIRequest.startQuizNow(quizExercise.id!); - cy.login(studentOne); - exerciseAPIRequest.startExerciseParticipation(quizExercise.id!); - exerciseAPIRequest.createShortAnswerSubmission(quizExercise, ['give', 'let', 'run', 'desert']); - cy.visit('/courses/' + course.id + '/exercises/' + quizExercise.id); - exerciseResult.shouldShowScore(66.7); - }); - }); - }, - ); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exercises/quiz-exercise/QuizExerciseDropLocation.cy.ts b/src/test/cypress/e2e/exercises/quiz-exercise/QuizExerciseDropLocation.cy.ts deleted file mode 100644 index f56ba79fc8f3..000000000000 --- a/src/test/cypress/e2e/exercises/quiz-exercise/QuizExerciseDropLocation.cy.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { Course } from 'app/entities/course.model'; - -import { courseManagementAPIRequest, courseManagementExercises, quizExerciseCreation, quizExerciseDragAndDropQuiz } from '../../../support/artemis'; -import { admin } from '../../../support/users'; -import { convertModelAfterMultiPart, generateUUID } from '../../../support/utils'; - -let course: Course; - -describe.skip('Quiz Exercise Drop Location Spec', () => { - before('Create course', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse().then((response) => { - course = convertModelAfterMultiPart(response); - }); - }); - - describe('DnD Quiz drop locations', () => { - before('Create DND quiz', () => { - cy.login(admin, '/course-management/' + course.id + '/exercises'); - courseManagementExercises.createQuizExercise(); - quizExerciseCreation.setTitle('Quiz Exercise ' + generateUUID()); - quizExerciseDragAndDropQuiz.createDnDQuiz('DnD Quiz Test'); - }); - - it('Checks drop locations', () => { - let containerBounds: DOMRect; - - quizExerciseDragAndDropQuiz.dragUsingCoordinates(310, 320); - quizExerciseDragAndDropQuiz.dragUsingCoordinates(730, 500); - quizExerciseDragAndDropQuiz.dragUsingCoordinates(730, 320); - - quizExerciseDragAndDropQuiz.activateInteractiveMode(); - - quizExerciseDragAndDropQuiz.markElementAsInteractive(0, 4); - quizExerciseDragAndDropQuiz.markElementAsInteractive(1, 3); - quizExerciseDragAndDropQuiz.markElementAsInteractive(2, 3); - quizExerciseDragAndDropQuiz.markElementAsInteractive(2, 4); - - quizExerciseDragAndDropQuiz.generateQuizExercise(); - quizExerciseDragAndDropQuiz.waitForQuizExerciseToBeGenerated(); - - cy.visit(`/course-management/${course.id}/exercises`); - quizExerciseDragAndDropQuiz.previewQuiz(); - quizExerciseDragAndDropQuiz.waitForQuizPreviewToLoad(); - - cy.get('.click-layer').then(($el) => { - containerBounds = $el[0].getBoundingClientRect(); - }); - - cy.get('.drop-location').then(($els) => { - const { minX, maxX } = quizExerciseDragAndDropQuiz.getXAxis($els); - expect(containerBounds.right - maxX).to.be.greaterThan(0); - expect(minX - containerBounds.left).to.be.greaterThan(0); - }); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exercises/quiz-exercise/QuizExerciseManagement.cy.ts b/src/test/cypress/e2e/exercises/quiz-exercise/QuizExerciseManagement.cy.ts deleted file mode 100644 index b26cec263fac..000000000000 --- a/src/test/cypress/e2e/exercises/quiz-exercise/QuizExerciseManagement.cy.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { Interception } from 'cypress/types/net-stubbing'; -import { Course } from 'app/entities/course.model'; -import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; -import multipleChoiceTemplate from '../../../fixtures/exercise/quiz/multiple_choice/template.json'; -import { courseManagement, courseManagementAPIRequest, courseManagementExercises, exerciseAPIRequest, navigationBar, quizExerciseCreation } from '../../../support/artemis'; -import { admin } from '../../../support/users'; -import { convertModelAfterMultiPart, generateUUID } from '../../../support/utils'; - -describe.skip('Quiz Exercise Management', () => { - let course: Course; - - before('Create course', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse().then((response) => { - course = convertModelAfterMultiPart(response); - }); - }); - - describe('Quiz Exercise Creation', () => { - beforeEach(() => { - cy.login(admin, '/course-management/'); - courseManagement.openExercisesOfCourse(course.id!); - courseManagementExercises.createQuizExercise(); - quizExerciseCreation.setTitle('Quiz Exercise ' + generateUUID()); - }); - - it('Creates a Quiz with Multiple Choice', () => { - const title = 'Multiple Choice Quiz'; - quizExerciseCreation.addMultipleChoiceQuestion(title); - quizExerciseCreation.saveQuiz().then((quizResponse: Interception) => { - cy.visit('/course-management/' + course.id + '/quiz-exercises/' + quizResponse.response!.body.id + '/preview'); - cy.contains(title).should('be.visible'); - }); - }); - - it('Creates a Quiz with Short Answer', () => { - const title = 'Short Answer Quiz'; - quizExerciseCreation.addShortAnswerQuestion(title); - quizExerciseCreation.saveQuiz().then((quizResponse: Interception) => { - cy.visit('/course-management/' + course.id + '/quiz-exercises/' + quizResponse.response!.body.id + '/preview'); - cy.contains(title).should('be.visible'); - }); - }); - - // TODO: Fix the drag and drop - // it.skip('Creates a Quiz with Drag and Drop', () => { - // quizExerciseCreation.addDragAndDropQuestion(quizQuestionTitle); - // quizExerciseCreation.saveQuiz().then((quizResponse: Interception) => { - // cy.visit('/course-management/' + course.id + '/quiz-exercises/' + quizResponse.response!.body.id + '/preview'); - // cy.contains(quizQuestionTitle).should('be.visible'); - // }); - // }); - }); - - describe('Quiz Exercise deletion', () => { - let quizExercise: QuizExercise; - - before('Create quiz Exercise', () => { - cy.login(admin); - exerciseAPIRequest.createQuizExercise({ course }, [multipleChoiceTemplate]).then((quizResponse) => { - quizExercise = convertModelAfterMultiPart(quizResponse); - }); - }); - - it('Deletes a quiz exercise', () => { - cy.login(admin, '/'); - navigationBar.openCourseManagement(); - courseManagement.openExercisesOfCourse(course.id!); - courseManagementExercises.deleteQuizExercise(quizExercise); - courseManagementExercises.getExercise(quizExercise.id!).should('not.exist'); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exercises/quiz-exercise/QuizExerciseParticipation.cy.ts b/src/test/cypress/e2e/exercises/quiz-exercise/QuizExerciseParticipation.cy.ts deleted file mode 100644 index ce5023b500cc..000000000000 --- a/src/test/cypress/e2e/exercises/quiz-exercise/QuizExerciseParticipation.cy.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { Course } from 'app/entities/course.model'; -import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; -import multipleChoiceQuizTemplate from '../../../fixtures/exercise/quiz/multiple_choice/template.json'; -import shortAnswerQuizTemplate from '../../../fixtures/exercise/quiz/short_answer/template.json'; -import { courseManagementAPIRequest, courseOverview, exerciseAPIRequest, quizExerciseMultipleChoice, quizExerciseShortAnswerQuiz } from '../../../support/artemis'; -import { admin, studentOne } from '../../../support/users'; -import { convertModelAfterMultiPart } from '../../../support/utils'; - -describe.skip('Quiz Exercise Participation', () => { - let course: Course; - let quizExercise: QuizExercise; - - before('Create course', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse().then((response) => { - course = convertModelAfterMultiPart(response); - courseManagementAPIRequest.addStudentToCourse(course, studentOne); - }); - }); - - describe('Quiz exercise participation', () => { - beforeEach('Create quiz exercise', () => { - cy.login(admin); - exerciseAPIRequest.createQuizExercise({ course }, [multipleChoiceQuizTemplate]).then((quizResponse) => { - quizExercise = convertModelAfterMultiPart(quizResponse); - }); - }); - - it('Student cannot see hidden quiz', () => { - cy.login(studentOne, '/courses/' + course.id); - courseOverview.getExercises().should('have.length', 0); - }); - - it('Student can see a visible quiz', () => { - cy.login(admin); - exerciseAPIRequest.setQuizVisible(quizExercise.id!); - cy.login(studentOne, '/courses/' + course.id); - courseOverview.openRunningExercise(quizExercise.id!); - }); - - it('Student can participate in MC quiz', () => { - cy.login(admin); - exerciseAPIRequest.setQuizVisible(quizExercise.id!); - exerciseAPIRequest.startQuizNow(quizExercise.id!); - cy.login(studentOne, '/courses/' + course.id); - courseOverview.startExercise(quizExercise.id!); - quizExerciseMultipleChoice.tickAnswerOption(quizExercise.id!, 0); - quizExerciseMultipleChoice.tickAnswerOption(quizExercise.id!, 2); - quizExerciseMultipleChoice.submit(); - }); - }); - - describe('SA quiz participation', () => { - before('Create SA quiz', () => { - cy.login(admin); - exerciseAPIRequest.createQuizExercise({ course }, [shortAnswerQuizTemplate]).then((quizResponse) => { - quizExercise = convertModelAfterMultiPart(quizResponse); - exerciseAPIRequest.setQuizVisible(quizExercise.id!); - exerciseAPIRequest.startQuizNow(quizExercise.id!); - }); - }); - - it('Student can participate in SA quiz', () => { - const quizQuestionId = quizExercise.quizQuestions![0].id!; - cy.login(studentOne, '/courses/' + course.id); - courseOverview.startExercise(quizExercise.id!); - quizExerciseShortAnswerQuiz.typeAnswer(0, 1, quizQuestionId, 'give'); - quizExerciseShortAnswerQuiz.typeAnswer(1, 1, quizQuestionId, 'let'); - quizExerciseShortAnswerQuiz.typeAnswer(2, 1, quizQuestionId, 'run'); - quizExerciseShortAnswerQuiz.typeAnswer(2, 3, quizQuestionId, 'desert'); - quizExerciseShortAnswerQuiz.typeAnswer(3, 1, quizQuestionId, 'cry'); - quizExerciseShortAnswerQuiz.typeAnswer(4, 1, quizQuestionId, 'goodbye'); - quizExerciseShortAnswerQuiz.submit(); - }); - }); - - // TODO: Fix the drag and drop - // describe.skip('DnD Quiz participation', () => { - // before('Create DND quiz', () => { - // cy.login(admin, '/course-management/' + course.id + '/exercises'); - // courseManagementExercises.createQuizExercise(); - // quizExerciseCreation.setTitle('Cypress Quiz'); - // quizExerciseCreation.addDragAndDropQuestion('DnD Quiz'); - // quizExerciseCreation.saveQuiz().then((quizResponse) => { - // quizExercise = quizResponse.response?.body; - // courseManagementAPIRequest.setQuizVisible(quizExercise.id!); - // courseManagementAPIRequest.startQuizNow(quizExercise.id!); - // }); - // }); - - // it('Student can participate in DnD Quiz', () => { - // cy.login(studentOne, '/courses/' + course.id); - // courseOverview.startExercise(quizExercise.id!); - // quizExerciseDragAndDropQuiz.dragItemIntoDragArea(0); - // quizExerciseDragAndDropQuiz.submit(); - // }); - // }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exercises/text/TextExerciseAssessment.cy.ts b/src/test/cypress/e2e/exercises/text/TextExerciseAssessment.cy.ts deleted file mode 100644 index 10c74b853808..000000000000 --- a/src/test/cypress/e2e/exercises/text/TextExerciseAssessment.cy.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { Interception } from 'cypress/types/net-stubbing'; - -import { Course } from 'app/entities/course.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; - -import { - courseAssessment, - courseManagement, - courseManagementAPIRequest, - exerciseAPIRequest, - exerciseAssessment, - exerciseResult, - textExerciseAssessment, - textExerciseFeedback, -} from '../../../support/artemis'; -import { admin, instructor, studentOne, tutor } from '../../../support/users'; -import { convertModelAfterMultiPart } from '../../../support/utils'; - -// Common primitives -const tutorFeedback = 'Try to use some newlines next time!'; -const tutorFeedbackPoints = 4; -const tutorTextFeedback = 'Nice ending of the sentence!'; -const tutorTextFeedbackPoints = 2; -const complaint = "That feedback wasn't very useful!"; - -describe.skip('Text exercise assessment', () => { - let course: Course; - let exercise: TextExercise; - - before('Create course', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse().then((response) => { - course = convertModelAfterMultiPart(response); - courseManagementAPIRequest.addStudentToCourse(course, studentOne); - courseManagementAPIRequest.addTutorToCourse(course, tutor); - courseManagementAPIRequest.addInstructorToCourse(course, instructor); - exerciseAPIRequest.createTextExercise({ course }).then((textResponse) => { - exercise = textResponse.body; - cy.login(studentOne); - exerciseAPIRequest.startExerciseParticipation(exercise.id!); - cy.fixture('loremIpsum-short.txt').then((submission) => { - exerciseAPIRequest.makeTextExerciseSubmission(exercise.id!, submission); - }); - }); - }); - }); - - it('Assesses the text exercise submission', () => { - cy.login(tutor, '/course-management'); - courseManagement.openAssessmentDashboardOfCourse(course.id!); - courseAssessment.clickExerciseDashboardButton(); - exerciseAssessment.clickHaveReadInstructionsButton(); - exerciseAssessment.clickStartNewAssessment(); - textExerciseAssessment.getInstructionsRootElement().contains(exercise.title!).should('be.visible'); - textExerciseAssessment.getInstructionsRootElement().contains(exercise.problemStatement!).should('be.visible'); - textExerciseAssessment.getInstructionsRootElement().contains(exercise.exampleSolution!).should('be.visible'); - textExerciseAssessment.getInstructionsRootElement().contains(exercise.gradingInstructions!).should('be.visible'); - // Assert the correct word and character count without relying on translations - textExerciseAssessment.getWordCountElement().should('contain.text', 16).and('be.visible'); - textExerciseAssessment.getCharacterCountElement().should('contain.text', 83).and('be.visible'); - textExerciseAssessment.provideFeedbackOnTextSection(1, tutorTextFeedbackPoints, tutorTextFeedback); - textExerciseAssessment.addNewFeedback(tutorFeedbackPoints, tutorFeedback); - textExerciseAssessment.submit().then((request: Interception) => { - expect(request.response!.statusCode).to.eq(200); - }); - }); - - describe('Feedback', () => { - it('Student sees feedback after assessment due date and complains', () => { - cy.login(studentOne, `/courses/${course.id}/exercises/${exercise.id}`); - const totalPoints = tutorFeedbackPoints + tutorTextFeedbackPoints; - const percentage = totalPoints * 10; - exerciseResult.shouldShowExerciseTitle(exercise.title!); - exerciseResult.shouldShowProblemStatement(exercise.problemStatement!); - exerciseResult.shouldShowScore(percentage); - exerciseResult.clickOpenExercise(exercise.id!); - textExerciseFeedback.shouldShowTextFeedback(1, tutorTextFeedback); - textExerciseFeedback.shouldShowAdditionalFeedback(tutorFeedbackPoints, tutorFeedback); - textExerciseFeedback.shouldShowScore(percentage); - textExerciseFeedback.complain(complaint); - }); - - it('Instructor can see complaint and reject it', () => { - cy.login(instructor, `/course-management/${course.id}/complaints`); - textExerciseAssessment.acceptComplaint('Makes sense', false).its('response.statusCode').should('eq', 200); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exercises/text/TextExerciseManagement.cy.ts b/src/test/cypress/e2e/exercises/text/TextExerciseManagement.cy.ts deleted file mode 100644 index 773136e8b727..000000000000 --- a/src/test/cypress/e2e/exercises/text/TextExerciseManagement.cy.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { Interception } from 'cypress/types/net-stubbing'; -import dayjs from 'dayjs/esm'; - -import { Course } from 'app/entities/course.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; - -import { - courseManagement, - courseManagementAPIRequest, - courseManagementExercises, - exerciseAPIRequest, - navigationBar, - textExerciseCreation, - textExerciseExampleSubmissionCreation, - textExerciseExampleSubmissions, -} from '../../../support/artemis'; -import { admin } from '../../../support/users'; -import { convertModelAfterMultiPart, generateUUID } from '../../../support/utils'; - -describe.skip('Text exercise management', () => { - let course: Course; - - before('Create course', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse().then((response) => { - course = convertModelAfterMultiPart(response); - }); - }); - - it('Creates a text exercise in the UI', { scrollBehavior: 'center' }, () => { - cy.visit('/'); - navigationBar.openCourseManagement(); - courseManagement.openExercisesOfCourse(course.id!); - courseManagementExercises.createTextExercise(); - - // Fill out text exercise form - const exerciseTitle = 'text exercise' + generateUUID(); - textExerciseCreation.typeTitle(exerciseTitle); - textExerciseCreation.setReleaseDate(dayjs()); - textExerciseCreation.setDueDate(dayjs().add(1, 'days')); - textExerciseCreation.setAssessmentDueDate(dayjs().add(2, 'days')); - textExerciseCreation.typeMaxPoints(10); - const problemStatement = 'This is a problem statement'; - const exampleSolution = 'E = mc^2'; - textExerciseCreation.typeProblemStatement(problemStatement); - textExerciseCreation.typeExampleSolution(exampleSolution); - let exercise: TextExercise; - textExerciseCreation.create().then((request: Interception) => { - exercise = request.response!.body; - }); - - // Create an example submission - courseManagementExercises.clickExampleSubmissionsButton(); - textExerciseExampleSubmissions.clickCreateExampleSubmission(); - textExerciseExampleSubmissionCreation.showsExerciseTitle(exerciseTitle); - textExerciseExampleSubmissionCreation.showsProblemStatement(problemStatement); - textExerciseExampleSubmissionCreation.showsExampleSolution(exampleSolution); - const submission = 'This is an\nexample\nsubmission'; - textExerciseExampleSubmissionCreation.typeExampleSubmission(submission); - textExerciseExampleSubmissionCreation.clickCreateNewExampleSubmission().then((request: Interception) => { - expect(request.response!.statusCode).to.eq(200); - expect(request.response!.body.submission.text).to.equal(submission); - }); - - // Make sure text exercise is shown in exercises list - cy.visit(`course-management/${course.id}/exercises`).then(() => { - courseManagementExercises.getExercise(exercise.id!).should('be.visible'); - }); - }); - - describe('Text exercise deletion', () => { - let exercise: TextExercise; - - before('Create text exercise', () => { - cy.login(admin, '/'); - exerciseAPIRequest.createTextExercise({ course }).then((response: Cypress.Response) => { - exercise = response.body; - }); - }); - - it('Deletes an existing text exercise', () => { - cy.login(admin, '/'); - navigationBar.openCourseManagement(); - courseManagement.openExercisesOfCourse(course.id!); - courseManagementExercises.deleteTextExercise(exercise); - courseManagementExercises.getExercise(exercise.id!).should('not.exist'); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/exercises/text/TextExerciseParticipation.cy.ts b/src/test/cypress/e2e/exercises/text/TextExerciseParticipation.cy.ts deleted file mode 100644 index 389fda0c887c..000000000000 --- a/src/test/cypress/e2e/exercises/text/TextExerciseParticipation.cy.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { Interception } from 'cypress/types/net-stubbing'; - -import { Course } from 'app/entities/course.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; - -import { courseManagementAPIRequest, courseOverview, exerciseAPIRequest, textExerciseEditor } from '../../../support/artemis'; -import { admin, studentOne } from '../../../support/users'; -import { convertModelAfterMultiPart } from '../../../support/utils'; - -describe.skip('Text exercise participation', () => { - let course: Course; - let exercise: TextExercise; - - before('Create course', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse().then((response) => { - course = convertModelAfterMultiPart(response); - courseManagementAPIRequest.addStudentToCourse(course, studentOne); - exerciseAPIRequest.createTextExercise({ course }).then((exerciseResponse: Cypress.Response) => { - exercise = exerciseResponse.body; - }); - }); - }); - - it('Makes a text exercise submission as student', () => { - cy.login(studentOne, `/courses/${course.id}/exercises`); - courseOverview.startExercise(exercise.id!); - courseOverview.openRunningExercise(exercise.id!); - - // Verify the initial state of the text editor - textExerciseEditor.shouldShowExerciseTitleInHeader(exercise.title!); - textExerciseEditor.shouldShowProblemStatement(); - - // Make a submission - cy.fixture('loremIpsum.txt').then((submission) => { - textExerciseEditor.shouldShowNumberOfWords(0); - textExerciseEditor.shouldShowNumberOfCharacters(0); - textExerciseEditor.typeSubmission(exercise.id!, submission); - textExerciseEditor.shouldShowNumberOfWords(74); - textExerciseEditor.shouldShowNumberOfCharacters(451); - textExerciseEditor.submit().then((request: Interception) => { - expect(request.response!.body.text).to.eq(submission); - expect(request.response!.body.submitted).to.be.true; - expect(request.response!.statusCode).to.eq(200); - }); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/e2e/lecture/LectureManagement.cy.ts b/src/test/cypress/e2e/lecture/LectureManagement.cy.ts deleted file mode 100644 index df4f85cbf740..000000000000 --- a/src/test/cypress/e2e/lecture/LectureManagement.cy.ts +++ /dev/null @@ -1,91 +0,0 @@ -import dayjs from 'dayjs/esm'; - -import { Course } from 'app/entities/course.model'; -import { Lecture } from 'app/entities/lecture.model'; - -import { courseManagementAPIRequest, exerciseAPIRequest, lectureCreation, lectureManagement } from '../../support/artemis'; -import { admin, instructor } from '../../support/users'; -import { convertModelAfterMultiPart, generateUUID } from '../../support/utils'; - -describe.skip('Lecture management', () => { - let course: Course; - - before('Create course', () => { - cy.login(admin); - courseManagementAPIRequest.createCourse().then((response) => { - course = convertModelAfterMultiPart(response); - courseManagementAPIRequest.addInstructorToCourse(course, instructor); - }); - }); - - it('Creates a lecture', () => { - const lectureTitle = 'Lecture ' + generateUUID(); - cy.login(instructor, '/course-management/' + course.id); - lectureManagement.getLectures().click(); - lectureManagement.clickCreateLecture(); - lectureCreation.setTitle(lectureTitle); - cy.fixture('loremIpsum-short.txt').then((text) => { - lectureCreation.typeDescription(text); - }); - lectureCreation.setVisibleDate(dayjs()); - lectureCreation.setStartDate(dayjs()); - lectureCreation.setEndDate(dayjs().add(1, 'hour')); - lectureCreation.save().then((lectureResponse) => { - expect(lectureResponse.response!.statusCode).to.eq(201); - }); - }); - - it('Deletes a lecture', () => { - let lecture: Lecture; - cy.login(instructor, '/'); - courseManagementAPIRequest.createLecture(course).then((lectureResponse) => { - lecture = lectureResponse.body; - cy.visit('/course-management/' + course.id + '/lectures'); - lectureManagement.deleteLecture(lecture).then((resp) => { - expect(resp.response!.statusCode).to.eq(200); - lectureManagement.getLecture(lecture.id!).should('not.exist'); - }); - }); - }); - - describe('Handle existing lecture', () => { - let lecture: Lecture; - - beforeEach('Create a lecture', () => { - cy.login(instructor, '/course-management/' + course.id + '/lectures'); - courseManagementAPIRequest.createLecture(course).then((lectureResponse) => { - lecture = lectureResponse.body; - }); - }); - - it('Deletes an existing lecture', () => { - lectureManagement.deleteLecture(lecture).then((resp) => { - expect(resp.response!.statusCode).to.eq(200); - lectureManagement.getLecture(lecture.id!).should('not.exist'); - }); - }); - - it('Adds a text unit to the lecture', () => { - cy.login(instructor, '/course-management/' + course.id + '/lectures'); - lectureManagement.openUnitsPage(lecture.id!); - cy.fixture('loremIpsum-short.txt').then((text) => { - lectureManagement.addTextUnit('Text unit', text); - }); - cy.contains('Text unit').should('be.visible'); - }); - - it('Adds a exercise unit to the lecture', () => { - cy.login(instructor, '/course-management/' + course.id + '/lectures'); - exerciseAPIRequest.createModelingExercise({ course }).then((model) => { - const exercise = model.body; - lectureManagement.openUnitsPage(lecture.id!); - lectureManagement.addExerciseUnit(exercise.id!); - cy.contains(exercise.title!); - }); - }); - }); - - after('Delete course', () => { - courseManagementAPIRequest.deleteCourse(course, admin); - }); -}); diff --git a/src/test/cypress/fixtures/course/icon.png b/src/test/cypress/fixtures/course/icon.png deleted file mode 100644 index 11078220190cae74133e5e03cd0153928a382a59..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61311 zcmeEv30zF;|NlwIKDO){*A}{0=u)T-*QIM~>{%PGB??KRQXPay%q7W^hLVtsrG(P7 zDOs9Q8I?@aqFu8$%QLi2; z-?Lr)XCn>&XtmL9+pfJ%hmM^(!yiO;N7`sa)c4#R%A6R*1{LonRv_nikicIwl&U;hCkM(U3mJ?7_$lZ;I!Pnq%S z%vlz{&7QM($Ur?cVXq@cy-)d`_B-Q$_T2fP z;42|lL$6)Gara(CH*_w)3&X4TOG}~wA$=}hjx#)?S2^FzUTCXI_n&I4V|#R zL+@WsUcM9GahTB}f$r}+GdlGd{xg4sP&2f;k$vC54*aE&eH_@QapfXiw6);oY4<=- zgv5_dHVq7YD7}&@MbBM+#Jo=KI;~Y2YoF5cgnQRz7?2}wM)?}hmf7F?`ly=x%DCV@!ff= z*R_h33v@0PE154|9oRY9%)+s9en{Qh5ceLMcg><*$6t=<{qME^o%4U!+P{13f7iB* z?t4wiD4mJ8juw`ss*$4$E3guYs~X{k=;QjqcuIjuozX0^(;#7NX@Z0ffh+H(FoVUZi0MTmKvFYNN94J1<{52bbqY45U z%63$|D-}O#y}SOha}ddP)9q8snK@o0+qC9BR$%B~LiiJp^VEo!{b)7Pp}QKnbX|?a z{h&rtcR6>y8YaCN(kk_go7NqRqzzIdDSxPu;ztz5wBguBJrgy;$WS9s{mPug ziB9NZyi7X-<(p9@olyAzRMFG_YtzUH;0DPXF0u=0I;Yy7T}?7&ls4zHOPpb)7fbh-(Pg#v#)K&To)ywu2u zjDoS}S+Acf)^IPU>jYA?km+Q$DHv~7we4ex4vF{5! zxVZ!^4~xz$mIZQn#idLU)f=4?!jBqM>effDTZ+C>BRMS9Tw=ot>@^xOA)x&hvYhZd zF0+2JehsDee87kE*FQLlEC>tp>}_fU?T+!l(aLWq__xCEVy}ikd>G-uuCY=?Vq0uc zu^QP6?r^ah5k8|;51v6{EL1QOBge*;lEa^@BD!QNlN@RAoVhniZe<`V zEAsS-q1{5sRTh<`R6jSIU0O&{5mYszOMjnD1Yg5A(o(W5M~ytmX#SHL>G``FDJwF> zA%em;NXavyIBkF$3Elv+I^LQtovS4EY?RxaJ5}TjU@3ncyp>%Nfk|q~Y*%Wt%alBU z5ANn)8%(~_teMm7+?5Pmjl6?^YzchwPKMkU){aGgtWY0*t}Vj%o<)LW!R zZqT^`F`DJrY{3Q&Xf`nHf|cwHL_cUPTds?$kwI5JyEor8S^wU3SiJw<^?&#JzkB`v zj)jlS-2O7s=HRI}$ee?xXb6%sT-oV@PC7Y@&9RfMWV7va*UMa&J&xXp4m9uECfsrS zBFgcIY17+19de?>kOL+YNx#{(eTi)H7j_$=Z-Sxx;MppM4tX21S0h{b(Q#36Nz{)lC!$Az*YVED^SWWjS5GD(tXNklSWe$agcIRX zW_U)p6_cql{z+#3GQ**yB<$r&kIlIpPE6Yl18&Wle76!@rBj(xX`tEgt_C`T-bvI* z)EsdPbFtz)zLt2Q)QfdlyVKc>w!ZQg-v+#Uz&>;5cnNxv^{b%!5Zj0S-als%kGYq* zfzFaYe!e-#ac?G>KT12jj1@S+o%Vjql7JJmg>RMVNL;bNH8AD1uV!Lmy;z>$e6Es{ zgjgc$4PACn7`iWJZnzwM@`!Ty=VKT9CIt@4x)pKUZq5V$C$ZGXQ+8cvJzKs#e8XOs z_xs){j4o} zmn^lMV=ngIVz>TjVV8IQl;X*+-K~$$n>omT^b1GZtkEXP;kGMw_q;zLWXw+H!vTIj z%uMKJUEyoFanQE$pmHU1qxPC-tCrxd4@9+F#U7)aAIi2T zS4T%KKAvY~Qn`OAoBs&i%2H0Do?yxyO;@Oq=W{f7<>-_`w$eZjK~YCXLvk5L#geK8 zUPKSK*=ppF3q&tJqOW>>oNam>1vjQu`+--UAqQiDrN&=4J;5Yag4*Yu&(_i<)vmZFsc(M}Ejw07!+(5^D%KIw0wwh+H^{j|_lc{0 z95-^wca^vVHXLJqkSLaMHrEnn;DSU(K1=X*MS4K3XLUI}sIvK@SX>Sy0SGMLoUR>8i>ctfUBzi~IeCa|)3&SCut7Oaunitbrl=8x#X%1-f* zwz(jj@q}}4xAC_88v)yMAEvDC6yEw68*fY9cy40CscwJ~{z~tO@vSwhf+9J{3S2%Y zkh1uVk}J?|Wlom)BfC~{{?H5(Sydet6qYCv`Td9$mdnf?rj$K~@MKQvoX58l&UQtPG zBN@A_6p!Iv@AAl@OLn1yQNerXd+^OqV~M-S&tFOk5W-Tz%`{8NUyY2R$S>XkNHxgt zC@NqXsF9M;TD+;{VDG2NopnAR!)92&`$)iKCA-lG9daJN{*vD11M$)rT&cA0ya z?7Cd)Q1T(?J-$HbSe1V~Z;x&0!27oxxNX8<> zdPYazGfQS3i6fdx`fNu0LevNaA)+AeufjG{@F{^X$tB^9^N&&7Za-we^0ef#p28N9 zH*S#^ni;0@tSOiACrD*Ton?Z zRakJoE@_Vm@~QW&h{2Q;8a_GjNBH6)R6#!a`Ab55Q_Wh!C>Vb%BxldST-i04D}!fh zM6rcXBjYBU>V@8sUa9jm1&c{Nt1vhn z`rY}t*ORNm0-WM*@LCyS!`}Efo|L*ZMy*?8x+P5fHl(d{6easp3#4X@a123P&dC-m zF%E^SS~-=P3#Oo3s1K^JYn*?2BJans>+`Y9$Vw6HkJ!fjaZfYDUbS4$GHjUj(Wavj zr?<8t!d80#5D@;36X}tS>fJJZoM+1O)*I`7;ZF4S>Lo?Hv(u&&fNid~TRYSU7%p?V zq=x%J+~TT%?AN@q+L_n|9&T*$xtp?R#dX10IGVKtW0B82hlwtM>Bw!gS)D{|awUen zXo{l9duxW^(R@$8X0&3!ASJJNt`9JcbEO)7aA8Nkpo6^~)?jZpY3!{T78NT4Tosk(!o2%M727``n}OOo;zyf zUw_`*$N%^Fa}vUV0xx!iP739OgU73FLf=A866I)V;siH+I)yq&9=2RKI%C#Nb`Q%? z;sO!2$4Q1pU7V6w?J&EY+2#X2H8}G?{gYu0zi*=@)EOGtCf%a}b^;g4%QfivFqM(6oVo=1nZ|=1{ zv;w<0!lnG{mDvS4Vi>Q^7%YWdwMUJtiJgj-Q9D#B*0IXPWVcD&*LxxTA$1=-P5ZkKJ+bOXEcK-a2bHbz=%Yp|?1QY7D?{JXYpoQW)X2}YoWt~C zvQu&`^L&z)%s4!uIxRoXbW70v{5M-|`lWT7QovQ3vKZ5rLIL@ZHk2Vl30EtDai%_L z5dd+^?>CFo$RdG_a)bl|v6FrE)X1B>k!mE%bZzV>Vvnn_p7CG_rwV)?J#bGRD(L%M zL_R0qRfDsRIt^h;2P}OFEF&<&#gE8w=tIWT2I`OX*Q$ln^t?W?fWXK$D^i}0aelie z6TL?vJY0BNp>jz#e6BK7?S&|y+q-F|@BLgE*GQ+bre(_J)$Dy{-Pn`iONG-#3`(vY z`DAckHL{r2)hahMdvgUd z$mK4Yr3^v&{NFz<JK-1;@=8Mve>xKjZ%cB+T?(R{WHj(2I4&-%|n8>)rZDP2`1O6Cu{z z!B#SIW{{8YEovm)yswpbKK&IJA2haur)|p|=AiyzeoHx$(?0 z|8y_%*VT~BuHSk=jVus)ePkunp$SdX4#^bFE;$hETxYf1DRk4@^|9Th_Mf;6PNl6R zEC_HIf&gu(d!t)BHPUVtOigDZh+Vbx6(;>jK)5&N2C;2mT?cEckuH5zGk0LcOJD89 zvhw&!6@`Ko#}+VD1`i-BwCZP67z6pXuTu(JHp{_+ygoif5Hhp3m1-R3wSQ*s1zP{X zhmI7Ioc7sJH(*yE)tKY95T{c68YoY(N}|ZFVL%JP@+f4qTSv{R8EYjSK`*g*WkJ#` z`YVg6%IC$Q%328>zWl&=y#QFk;me%INU00)vdbFlP`4&8HIP=8H58yk5Ixn~f0t(V zzhW=h4Qv<#ds73~1Ab1rc@M5AkzNs%5lzlZ(ZTW|l3M9jtVVu_Jxv$6$@4M~Lp{m& z=>gdAZy9m_#8#)c5NFWh_iP)c>L+$*Olq8AK>W1$gP|%6KZKpPs)B$@f1=71YEs+e ztJKK#*rW7vTc!h+PcJr*4=e{$G%QU=joex00KarLB6=#pB0oI_)@hqBR-rdeT%&iY zy`Sd^dsi$k#O0laTIs6KaNR;*#Vgrj?L<%3sU26MKg>64k9nkIqMM+ul&93&*GbH2 z@(H4?v)U7|;g;1b?b z49Tm316a2OwdC9n9n{F(Xw95Dc$ym|F%`y|y|lrmH&)?02xFRoPpyh4_5Q9y{nq=b zV3r1^|K=%U#e-RD_Xv9^oW;I^YtTQ^4&2E*hLjqK5l-@-fKlVNkX3HZe#W@MzynVh zNuQ!p|5Tc^rVQYOk;VtiOd!i%c~h{Xeo7-2)dw!P2_cazF3N!0)iXE?qVO_sK&&}U zxm>KN_2CSHO~C{X_hTnMMK`Sd$^4~ki-)n4nZ_&CPhcuH_Q{X6Qmx3(12)w-Cjt_m z_yhIWb6E&5?5joS`_9h4CebpJ4Ws14A>kVwR>RyWFyZL45DoWk& zsSzzVwqX^!`U4N2>OzxG^CH^ONG+f$1;?$KNDucHMMGj+q^&wDjxQL}0nH6PffYT4 z(z#Cas6aAB!LQ>zYe9_hi3B${<#>v_k!l>c+|r9O4&F|Lv+n{j7L5t2OVjK!+}dR> zRpwv@j}VmKhAPoTJq#>zQ78uIM7~^N@)w&SI-Gaq* z-QKIR$`lOhDb)eA>K30(tX|9U225u@7owJ&{!ggND=E~3i~my_DYFzG=zFQ_PD*a^ z1@=An^YjB$QKDw;KCxHYHCelsXcMX#{iPQ^5CR(b#`pD!-SS?VUACH4G3T4ROq@~h z!%09H7H474|IqBHM+WKKI=-gIAP=RRplM9v-o25^NV=jBA>K}@?yA~sAsFGIEqAow zG7_WYC*J9kT;WJxe$8D*Z^Hxa8O4|_O(z$xsp?95DeCN^x5Q(UX%?r5hMPo_o%%yo zT@%lf?=&3&8@dyj8{_)hfMwk#KZfPK-LKR|LzP!?+7UyYYxXe z%qkGoIv(!r&vkeckid!zvzU;W=@(XbBY9B7I$PWEZm%q9iqaDv$MvYro=+w-``VmM z8yRwb6K|37r73%STzY&;#bl3OKLuA^U-nEmahRKVH{a_oSGr{nDt@@wXFa}^DgOb( zdyi{_@z={!)$fFdeOD`cmca2)CI!(4;)s)teL;a7>#_*J&&%Pks^X zmu4;x$0R-{L-lAifb#g#JE3Lkk}>%n0Ps_ZHHuYoKLAAfV(~N3vWxPmkQrDUWGmK9 zhq$LNSi>2JKB>#|d;rDzlYB#Rxs_~wQ)k7HU%+5_mFXPB1l+S~L|mkd7J-ZHX~(x9 zx|nd_;}kY(WHK7YHo*GOTTIw1s(ffob+MLyoO$m!2wYO938L&(7^`N{c{Sp|&bKe# z!U|y@eHkLv>zN$_wBY)ou(3a|r1SEHFq_?sAc2Zqp+?eZ6*bRzCHz8GSKHVwLi9+? z54WBS8o)ag`O+#eH>vx}!AT1$TqjDDPWVDjkIh$4Obv5cIO6!Z;R^FVK4LjtSyH_Jzt0i4c6D6+xf&3{`JWb@5|GZmW1d`I=$G}$I57-_x9@H5#Sr5 zExQMKk3!&~UCqv6lO2Vsc^=t;9kXJG;DZFoN5h?M<_HJ#4%v^5H0-_k(U0Xf-;^si zg*tS~tuP+_l?Nz$(d#7>ED+)#Uw$<~l|8jA( z{>l*3G#~w`&#W9m+HHEAPm$<@KMdk}4cf?8Bb|h^?2Z?ncRAtYw>Y_w@A=|(?;Ur- zr}z!Y?&P%dy!408(^pOiTbR$@YlrD5_uxJH%G5}yxi`okpN~k&yRiFSB9f;b%I* z<$|opNuIWQl0&ACRF^2QYF65;vldeut%Vm@3sWYqm?|6@+Z#(y^nv`Z<_sqGh5Z#J zG=P0IRx>y(W2#^eIf&5_6D2^p+3JW{RTnf;BEQ*Bi=~4(0QpZM^&vE;K&;4TjR)(K z0@i0eIh>ooQ1)|Rl7mGYawlfxv5fqY&412}@+Uf&_l8ZjpKnjnSRB@IUb~pRDl>eJ zP$$9u=p*;5{zYgPHDWV(<+JAtBC~(GOlDC;^WJ7%qo&cCS(I!G z8FLv+AewA%r2p|^w z>31PQ>q_4>&taQo1@-9!){pu&C0#0h-cXk8U0>;jwW%deZc&GM+$~0&a%F$W+M)~Z zn6h%fgJ!x3o0{l-?HlSsg1)$JKdO8!JJ$e~%FtWBdE`|dgRfADI=(DtGN3#h|;-|2eZ`R_MOfisM(TkG7rav#OVe z=@XV;m~ubhE?d#!sj5}j8-s#U(hs*_rJ1fOe8JftV^*j)I<=fX=KbU)J9E}uJ`u9$ zeji%j3nlUav9B+V$r>{!%VFuD$+ijEy*GUDJw{B8kL~vCfhs9*0RP7iS0|iVae-rW zVvLKs?UL~h%S|tge=&ORn8<6tk4}~fP8XTm8a*~PxwT^A2u1$)ZC^+ZT5du1eO8ks zuiMsdZUHga7&1cHNjk>^|}(+&J6up zMQd|L+MyBtRriE|vkA8|3Yb2RCS44wRDL)RI4m<l^3sNUSAf$*IViEYU!q$J$t7biYuR3_kI4rAZhGq{?;Jp z8|SvqJ$rLxPv_jzmA{9~=HHgGti#7F8J*^qz47L#%w=~=UR8mW`@rEOG{UF>H`e&| zJ+r%0aOjWI2FZ#uZS63*+>?x+2@yoNe$cjE^X!)S?`CAP!JfxMPGnE(yXDOJ*kc8h zj-2)G>(^h)OEpZQcAmzuyB0V0r`1>d`F?>z`=37k)Ol^!UG$bW*g!Szm0WHk2pxny z(Y-7wBGtw+&@_4(Q-9IfkZHhx+5Id$h0#xUQv2;pDjL#Ye z5#03@UlkB+TJgdoF#Z#sU;#&|?*ZkK#JVti!I#EM_-@eXfUi#;6d3$a8cdGlB>@1e z#i!yE-=nx3EWph##4=C(TgEbymbQZa?jjI%zB{=Xo{bjxu%k9H_`DwStExDU-V6)D zt>f6ON+SkUzNXmAGIQ$(`&(DMbz>)3mfLSJ`f*{{)Z3jdok7T@x5qr8Egeq1W`c%e zS2)$yzsW}nsXA2QHjiPu0HNDd$bK0_lb*t2dCDHFa$azacg)}FV@&~oSd%iS#cw(DJde$RYt6fxZN2flqr2YmD)zPI9u ztIIpeMAk8vSi`Q~r)>^|9|)bfz}c-&*I&k(c%QJH6Owy8V9}Pl09KayDlUx*@e52RPu>CRYY=4Sm-;TSU- z9?PIBC0C$=)Km+HnC{J-qkN}E4CaV${3)%WR;gWr_xss!^Z{H9#VjDOaKqmN3 zsk^9p`+g&znL;p44Te$|(D5ocpDy&>YQv{G0k2q^0_5Xf&8sJ6dTkI-;)Zi6Y3c>K zz;vCFXP2ax5==hto_6`A^ zgad#QdH1IY^Dgdwb{7!7UxP5uhrsk;II>g&H=)XN%i%^#X~RF>?sTjmpQD(dQ2@wx zkYk{(LE%5~sO5?wJ8zFWpWV#9!%Z5vc%zJIR0JvveV&Y=KQM+O5KgKVjYu<%DIIoe zdY4HpRhe%awZmzQ;Oi)lG{Np;xYD6ACyN&nXzWYN?(R|(e9}?G_B=2zG zwr6LQxVg5u2HRj1tVJ`l@)di3>^W3qT7ao^ZKz6rPc*~uG6g^Kpq5O|F(xk;wG-CN zH>li;ha04YeZMG{E8I`KaLLt_Vk*mAzYerQMGF!M$*b5X_A`jezDLk3(klHqtZt(N zO3jl{qN@$!P~wz0=MfnRMBxGPd%(vu$j4bB(N3DGS$KpFC^=pA`1@4RU?QAd zr7M6{Fozt*6%q7I3O?}St>e8`5n;=7iO}i+^n@Q6Q&V$F*0{}3BUcxF$bXOB^V!3p z9wCNd#V>?RVs9!6%{e&lJbaiUHBKbp$KzlM+(Yo~3o(qOXI5brmaiGQYJF4M53zoBD3t%WmSLZ2{2 zPRx#ImDh5t!lp2nbPKEHklngx1A>g%8XoG4+Ng~E1&fk@3belv;GFVgTl5}(J#*Q3 z&&LqX9$c5Zz>s5NE5Qkb-=e>NTR3)TR)MAqlkFDNgA=}TXk>MOZjX1iJN}iS2Ubl+v zKS~&yh#?~_FA}~5oGxP>WNfs0<%mDhjJB0*RT<7pjmDPdaqK^v8Yl9H^=zI4Q>J?a zY-uL?E+(3sDW|Hm0o^J;@_jb)p=IKK+}&kZJG;4R4O5L0rr;jXkl-^@JWBgHYDZBF zW%f`bRp)UiTW2+of+W6j@erYZ9LUlpR8QF>LlY@_v!hU3l|`6rv!hkUIU#ZgAbvEh zCU?3mgWY&%TV4qkc`^SEM*{w_*(!D-m$(ndiX{%rTaZiMjGcqAF!)A_@i9HhlTc;0 zjn~Dx*uh(}utl*#P*j_lcHz2`SvuQtNE2NENa>ptu1uQ=4AQk4^!6YgXyi?&Yd5Jv ziDNXpa0yMTP5ZEuC$>IPBYFAY(}0*ntrzN_&!>Qg9<#Rrud&nij4#_uo#T-2%6dT& zvk3^5iuvXcMCDk^VY6NLxMOW-ouPt_k(%HJ2JG%*Ar&T=_&vs&oo5Pn{UHz{ASL)h z7()3JhD4(U2iT&`u~4wOD=f4peu>edNBPOYFtpWeOFoS?i_<3!Q;tSsS$+kbh?qLk ztH>yYqL{jR4{$7UdCE;k$(PPLP-=Bd#}Ad*1P! z#@|)2gZknDKBeT-DvZ1}!AQ}$9A>}BiG*oKX9t)!X zLRIu|s3DHuwI^mI>wRn{Q72Go#{HDXk?%Xz*FBviW^SSemifMcpE^)*FSgK4Xlyma zCk^k@Ky?Gjd4@6wVeVMXhHV~|D6MVODabpMoqQ8p`fEUJ~*o&E|u>YI+QG23|*#o@-+3(?GIzML!Z zgb#RGs6(89)pgBe96%@1dqTj8>xwnV^>C1|7E+YeeaXX-UFU;?p?1f(o7s|y*O~E# zg6E?3Cn~c&Y?LcJI8>2k%y=j$W1gtwS!9iF0hD2$4&!qVPk>i@W1g;HWc%B_Gr(u0 zV6jDLl>u1u(5u*Emp%9~0V>l0BqOtXD@*91WqjnPCNz+$e$L5I7 zmAnj$oM+$G)qz4rt|+LBTZ0a1!mJFs7d6(iuH($;RdvIjrUy;ZroFoD@Un)c+Qph$ zmu&y~DFnZ!^~};j|Jnz4yE0n^zm5SZF++5lOVygj)B8+on$}My)v+dbX-Ui`l111f z-qXzMtlELZYjRdY5}JXvOhRjExt^ruV%dI}{cPb3*st5R$Bbp?{dkQ0^&CV^e3BkDIXGDdDb|?tmp7nS#m8VDVnv%&g+>!$dY3dc$20 zFOqqy8JHVWH_FGo8nZx1GoLZIUZd-gB-Z7y(z*%frc01!g)4(*K@n0f@>|*fS>!I& z+@y4!bSX~3;x|Ltd>E=18;F3_cI2-l<#uu)DICZEvBs=eGs090V6@T%=sh3-5Zw1< z0JzM-;4!n4XJJ3M|BMyC*?`GbmcT;1%Aq}n(hWN!6HjVZ!YP$4hj*SQ0BpqzD8IRXp0;r;}8J=hdlwymF*4k}?4nt2S99Ea&OO2(u$!vUo7 z)kj^F6R=cafxS`{2od1;i_}b;CKZBK7L^DvF?z~Bw5(uA2sV%@aG>KCZ4zjzA6`?H z=j8X<%rT@VR#3=MOyL}4%4Xa|rAESSnE6ujz8sA0NXCA46=bPW!=Bi2@O}!@cSEo@ z6{ynFQ?sa6p#wjzsivvPf~?ojAOSjS>^=s>gO!VNl<3pCAP;iTd_%@ztdm0uzHlYg z5`C`|tX#TU!*`3kilrK9(Bj{hdBGku8*sx)e&~c6aZkqHEE}dqX!F#FtEfiNw*af6 zbcVkeGWlaohi+O&c8m48wfOd5Sw9+*>lPv`mD~PU6Jx z@{upcwB{rKC73qu@&8){Q*0h8*uMMG&-3kN;p^>W%!n;mhrDL59i$AN? z2>Q;qs@#a*ssz1b2+A$`X1NF=#d-)JT_>n%$4JAkD5IE@Su-0iR0d(=SCMLHkGVi6 z@bew!u$Er&l%Lc{o>05 z#QWv_>CvcwPE$-~9Ae5q$tN8vobS=gN|{$+fuA=A7~u{WsH~XTnYn78cPClgPY_Q&sx$f&Eq&ReNB$ z5p#bC*p&AyM`nG_cQ+Xp707FTTPnSYK(zRx^Li2rzwNPdzi%a)reCWIJ?_?^ui1Ig z>%ZWhwYN_>r{fc=gRk@7lF7b9_H!1^f2gv`HP7U`FT4}5O0mj3)u(WNp0X?O0xxU` z?)lVgxPxLmOL9UEN%inyMLgmZr$1IPy0DWPF&@o+4M@Qnz}|lOE&wzLWJByo8h=3} zCIHXcO1Hl(6;s@Xx5D}>;>qA%-Qu;uB$Q)*#B3|YLdi)8von%C9_o;H6{E?=L|<4` z$pVYe?hs@z4b*crZ94%iv~^`DcIvUEwKH7@)Jb+&i3}bsutQUgdr&ZH zX$y*_CQJK>=>0>avxwI^I-cn=b3e(<#%x&wldQ$gajIe7^*ahVC+7P@{Z zOEzV!_SJV6#jruCH;P&C0fXH3Z6#FK806Ju5UM|(k=hurqqlhSA=mU}Gld_tP@#wE z{5n%WiZ)SupjCW)DWr7NL~o*o^-WAPuxX1EO~TuRYu!LiS1eQt zo8WziK5BpvH(?7z6yy_4Z@>bb%Ncajrp%2?T3-f4CEBcly<}$#z|#85r4oS-8OH4N zon_G*c3Ktq>}48>$tPAU1^K7mKf zm&}2VbW2pn$O^~~ze8KX{Px`8YcWUa3@+!#dZqs6MfGj$=`$ASaQe0EI8uksd{SWn z7_Tc%)+n(Wb7-VrL;sUFx?ss#jDJ9lY`#Uoy&uu+l^5Jl`t4QJ-fy zAsM8JfFNh5@w?(O*N;6QI(U&_erg#U=kF zt{O7JId#u5`o5w^Qu;aa482thH7+97ygxn~XdyEoLlg?yQ@eU%rB_nm4KS zd{k^en*Gnrn!@vYpj643Z{+5GxhU5}5elF~Q$=WTDCnJsPghwLoK*1+bWXsc=ZXj>0Oog>w&aqdYQu zD%41XP0DpywK#Ty+dTj6j!`d!XYQ&T_XliG-eKfZV0DD6+IVuysSTC)muhG%BYNS3 zIpFyBUc}zyjfeR1Sv=IyZ@B!>P=VEvdDcrk{573Cn@T+b?d8TrNr^Lw6R|^bFBnEB zm{feBIb7bwB)Eyu>K0} zx@e~nQ#A}=8s&qhoMOYP4E#bD2Kjt7L@-No$`zh)8c;}BkSS3UiSKHqENi6Bo)xQQf+{B!oWOc#q=kSx_7{eXM$3FQYu?Y>1Wue zL$-FZKK>PDW=T_q7u$#OVSQSiG>|@n`;C_U5Z!?Ds=ewbeM~NEc2>aGGQU44lj~2h zan=7yJ9}_qtTaq+V1)-K%3!PBv6u;?%uHM=yWWi8#x}zW!t}-u@WOkkWT);8aPZ;? z0#C%+$5RiQ(6g^>P_n(A$8WG%~+sk9R6vHdH^vsl5~>Rp@9^Qu=S zbF0zKugD%CQ;jS&&BKGqqxD2FIuq>T^6`0v24hL5!L5KA_Io8`y7 zTk6OoHW>vgeLhvP{tTH+0W^xzdg27|985psSvKRGXr|P(@hYP}vkhN4V_}G%W4&}8 zj@0<17{1hub*Pc2xbU0ZnWl8LOO#@a?Dk`8fkiAP*m0Oe+*2)d8}(3y=ESfMoEg7W z?Dn=O+1y}TUd#hw?HwPza~u=ue!qVd<(F?PgE%+Ese)}p80_LGMq-_?syXSPwMYqG zI_I$<)#AAMK)Ke0T{TtA_Ri}Z8IfS-Z8Ls6>~O&z$TqHUU&^RK1r-z+kBf&HgiLh3eVeVS)9gef-;CM>GKO0V(gjFnL} zRBKi#jqIA5-u|IZ_0IV`O;4hDieg=vl~wI&fEmFxsJBcolILGMJyWplRaA(`j5vn{?89+-+Yg#r{9T7uof?%)?8u z_)UG%lev759%aTG<>LBG`y!BPsV!1%86y`ZEqfI)3BQ^n;HLa5bql3rPB9$d0uH0f z>dWEBwNK%PG)F@;g55e(SVQD%mSi3sl!R;Q~G?W zVp4x9apoaLUcZ+qo&%*32_$Xf+cZjTG(?PT#Cfc^kkrO<*2^JqxPIn1y=>QGopfxB z8Zo7RIpzMIJ|xh&epj}~efl$KEEywimgUv;AhD`HB?oByjg28Aklasiim7Rl9%^he zF!~zaw~t+LjVD@%MOYD#Hj^Q-R2KW}*R$$%{2JWWm^Byd#2meG~|&R5wT!)k5F&Sf2ltLA++tS5iW_9sK$jb4%T0t@Fp%qSFG3y*eukO zScUlpED*J%CEicyKS0oT^V$j6h1HAYOPa2&kII}oXj5U%eTd^DF=35r9elq1 zeiRyiJtMD#eY<;CyE;)$@4Cvox26qEJ-#}pu^C1yg5IY6fu?o)h;3PMI@b$r%8+JY zpjFdoS*xz^#m_hDft@W8b=0Rzl*{D}oTH2Lu?M^lQKFygQ_uIuT1h=y?QD>FK5zNJ4xk1E1Jef=UR-)-cqj zR2ogywiPbKr8dp<&el!Z-!&eB*&u$qTCXwM2Ut%laA|E~qY{0hu%=##-kbG3RMX|H zQB7;muMvyHbH37(>YH3s_a>NKOFCPahHpCPBZkEatUF(iJ|kVL8Q50`I5)^pMrqff zhm9@NGwbC9(*S@iMRDCQav@(eAA1uV1UB4;e}m}vg#=3v>hfRh<0mftb7|5gtRRn~ z=tjQg$vVj=tC0|_N2QQ@#U4KwXaww17kx6~++-Ce!u@M6W4<~^~TZjkY1ah^ot3M&a@Z#sRj)Yop1Fy0*umgPG0 zn4LldJ#O8}Gk#56j5 zH3}f6BWPs=T{+;@8BPW{qn>QKtlZ5F*hMGMLhp2?1GKO*qrSSKIS4j8+=!gbOkk>d zMxey_vg}3dq#yUFJ{XY+cc@BN8x_|dd&-9WxYn6YjBkw)x%1-wKfiu5X7<(+)4n0p zl=u@j(PD2mFzR>hgfL|bFTi9@I*PuYO{y>;qQ;Pi*&+jAfl!{ZrPK*1hZ?GbpU|)t z@7Q;THMwlbgx2i*8FsPq`GP6*9T+wh$&Wqb?0(6XdW6g z4#~vT5x}Y3%wa69&MS4>AU`+uZK?gaqMtU(O0`Y$eF|*)$FX{_Hn%E;pjQXNS{S;T zNj`DG$e@L2JZv!1;vttfeveAbyV-l;OjoZ{@ZY*dmDul~^R`bpdia=Xu-o*=N%SpZ zb5tJW4p$dBL_-oy>9w6Vbam15w4GCm205z2KkJF=hpQ1Rz8zMap`k)=EK1@j4>`AC z+Z*6M!bH-NI~dY%SrmCL2)k#k1$#6A`s$@BsY;KBWpBUIP4z3}2vM-~zm*&Dr*O^t zb;Jp7Yx0fn@tdtmG(KSWy2M&kj}WwRkH(qDsa-baU5vi(oH=t_^zAok;{ygc#j_+X zbiI8ypxJCE9neJ4loFPB-xm`rvb_=jv!~+yki;$xz$&b}Kv%KYgQ#dI;CBNz@RVLY zX4J2pg!-ieW$U`Kd;{o&$nAgQY|=lYyS#HjLz1U!Vet#u#R;%!SSsCJOkyq+MZYI~ zD{DP{16Swi7?}}dheg^Aq(>0JbLGE|FLjw}8pb+;NuI6Ai{Z!|PAG~LfglVdyH){6 z%Bco~b1ml}U=K@+Dq4d+r4q=t0s17D8Ugg_=&KC>(RqNiDMlNnZI z4sk8E_iBP!^^P7tx8Hr2*zFEQRNed4?^Zjj-Xv4zl?G7ao)G}N98hAZFWdkty*qIu z1QmO{?F8rlK^^8|^e~-|HRhIy{8NkpZpMN(8_Ib(=3N8{rBpjHnH{vEOVOlv%Q$x> zFD^t$*Tewq*Q5{OYO5+Cux=_7sWN>zL~!%MzL9+H|CVC*o5VcTdMP@-TgB zx>0}@b%_QkDnpQ%a%vkVH#S4Y>|Al&r;rB>t$8**xAW4smEw6L`kk3xK8%qHkm#Ny zL&XnN2%W3WI0O4=A+5XBKOnIAKhY;r%xNm2tZRY$sh3c_Qb3ceeH3ASOlm;VRCfYq zGti;M@lqgyHz@VdknS7RCyl3lT)k~#s^@h_!U`JQT&k0XZ3bnj3GDNn6Pj=PdY*qX4H*C1k7oOaeT*Vl$th_LKZQN9As7F{%vg3v^mn(JVdXTI)P}1 z(FFASD73hyUFy?P$okn`&?v|hMNQ>SNSCi6qnAFmcHpG2>RUT3`my4DJy_rKOE zy!7%{n)rW**Edx)!$@13IZZ>`|G>#)U+N)Fc(#&QbD(nhR}l`feKfv6oQ+9&Z zY=Mpt66AK0wjP<(&Kmt>pHJ#eY&yFY;m<#auZ}iIo*T0g*BQ*cfpa8xTftJT+l2@P z9KI!#*1Zj8l&9cv5^PRb-ANvWeZGvc?r)VS2prqL#diBNXD_JV1E^k!`bMh$*XnTB zYg*TIjsTVM^r4hoc3Z|fyiYkC3d|Odex_d#I?&U7?ya3fZp-qcx%F<7nAge-06BZbpl;zX-?EY>0Ne7;EDb>7NIh zpxs9M18myF%+knF=lSZdxqB06DyD)Z-=6SniRcZ>6&ckHK$!Hz7iseNlh9QqxVNI11DXdHdg zLx+qLu$8~-e4kkaW^~hz2u&$lAzub%{!E9lT~^=HZ6P8~ZX)?xXcDFx$?n0H_J6<< zZ}ufNFl(a7gLcGl@-OA%-!3X|g#DKrD!A5Int^Anx`RRfXwyIt_>`!NPR z?(N)R1D2E}rHYEpu*wg0#b@!=Ix*YgBTXbfmngqBD&|0%$7x!q2Z0>YvcUhRh#^;_ zW=POyfei$R^Kk_NSG|cycTa z%3|Lq?cubh8ul0paQ+ul?Qf&{U#4ZT$Dr1KlbPj&L!B?)8ZA~M=Em-(6i^&d4%?~R z8(Oo_lc3R0DI>48X!ploDp_TqRns2^1<<=wfw&ds<3s+UglSE^{S@Xe5>pEuDcPys6Q}seaUzxpfr-Olx&=5rRf9IUe?A5Ue_kq zHU2`*cx6n^NHi~is4Po?`;-WkhRXL)N~+V(eq}L%TlDywt7+Hi_suAU zIB+-O-Qlz=^FCP40AR{AG&j;nRi{~0j~Cn<_J&!& zAtr?Hed3H(i8{!g_&(5giCXZEEo;BB7V5m+g}j;v995?zth}6AW4#8#ew;$==VOwj zHZ6~G1HbbpI*WbQ7OFk^4X9OeTz)7ej>&L=-WWDMj{vKl5PAen@^B)zFUG?C$ww$S z78R$=4!&gUR3J#<#~?2f55tAZ9oW+%XqeUqbk`vpf8EteW4tCB902*6YH&JYvP*z%cm%@^D?hKVnpi-^&v7VN74tIm&ZrD*Duio=R0B0z{y)_wsZASqzMZU=Wva}lbA)|^+=lW5vptogS=FrSx>Jy z$?$ZkjposmW|TE?A{%#u=w%J?z|vozzVE>hH4sgs<`(gp2>}k!?PZx)CPT5mjP$e8 z)C|J6Fh%po-oT*ngI!k6n03SNt9@5n;X*=TuX&&RrYYhVPfCO@PdSg-iY(%3N8}J( z9|K}hC~@p_IRd+S9n>Qi7ox=fYwz5{V$A>lKRzLcW!52;LxU)48A^oewi{ZxFGokllWBmYE-Px_p{gU z@`p>;#nse(zwh_`e!X7L=i})|J$Z)H z{z*f=zk3`A0=Ti{dv=}G>HM>w^yd4Ca{h|8o**mld4zVJp!Rt8gu12}!DgF7v#lX` zM%7d@Lp-16#@NB0U80?syq7bZmZok;jx$tGsu#pN`vA1T8equ7nOvYN zJ53Khf)C_CfnuDBRoedvQ^3s|LAdzZ=tM|MP?uO0IszU>i>FbuD~bn%-xgEOz+vI( zkZQ4+pKk#Ws?Y5e4d!TAIi1W>D`Dh2$N{*cIAXkyF1Wgmf&PT7p#`r$-G?e-*RE*q zY28G;o9(~94YMGZI$L>DWwiIsvZCR?Gy`h^hue1POmyMht-gY8AvH+&OgI$pXHo+N zR6)H1J}N=<@)O&2j&dhfyeQKUSVUjj&5UW1l_~OObopNVjQhe#`sd~vS%#FRsg=J%#@ z$=AumWIEn|(=+%5j!BkCUAqLR_o}&vSoKrx0M< zvA@{@s;vo^^*8k)C(fZ0@DNZ6+pvb@xNyx3+kX`tPJZB(P}Q_q0@?jC`snd+OpsPJ zj~l`P(bbk3yx-cV(J%Q2L*A-;(&9q$0uucCb8MO*;)Hz<+&n4so zjRdvLxnLtjy)=ycc6ek8=y!zFRoiWc;h?axHU!+0rvp-!Ga>OdaluHB#dcCn<`^`& zkFXx>m(fYohNCVAzl~*vffW87M6f&Iku@$~dam-71SSWkH9*rc(?l1|SQ}eagXN}v z$mYl-=WT8dz8z_f!D(Z*=}Ktr9o)`EY30?FS)wb$xpNLS>rZ}fQqGh&p~qhV<*Q4m z%rqeMexz@ID;kf%fk%b4#`Mek2DMhfExsEkg*f*IpQ(M*G_%GfvuWJ~Emp+geRTRt zPtx4?QzTUS5V#THO@{~>R)`AbGwu$Kj{ zm{Tze_y1lzk)#zN}MNMJwo%a>}7eRN}G|39_t1%c6sj zzre5~=N;@I<7);;H%F=b7t~mOGT$rH8~ox&=|b`aO#v|D!5ta>(YDzDHXVibo^Q(f z`+b3x-iG3=!j_$6={q9W~Igny-pOH=y8+|M(mCdlGqg7tu% z)anfTiy-fFm0dKGjooOOO2=bemEvDHcB7z*Oq-&KaL3&G{^*e@9OqGA7)Pl$nUGb> zXi{O7n!Pf^DQ4;oZ%GX)Z^IhuYrzcUH{y}Tc~byvtZ~`*WAm$qv%lG4xwQ$Qcd@yW zwsNDn>7m7|+!&&LfZ2Pupq-b*pU_G*3E-^$B72C^zl5D~1^e5f-a<5--!_fQK;qW# z=J4goE0B`ut`=stN$D`sehs!JqWA&@q;Q`rtpe zBlU64eKmBriW6o>4#HmvWK4|Zd^g202e=weYa zv2V9QEB^;cT@`!=-VfM+6S&eVSmp9`v~C(VbKkW#qQ9s#s!)gJGas6(J#p!!>q+M~ z@u3?Rbw+^c?_jIBIP#+_lh0SN3Pw3~$IYV*K6ynj1}H>2gfN#jU{^r!H+#cytvK9Sjtf*ol-VY`d+9F>3yFyetho(=> zt7w6-;G?m^C?gLxHX^$9-!jp;WYJ9ZH0en=JD7(#%*mEM>r*`1|$c^J}0@iZRn8+ayUD`}{a^7V@0zEJIreX=OSX!+#= zcEOU;2rR(f?uY0Fx71_D$Z&cC1qY{Uw#9l7w zQ%kFrKB>`*OUS_#uf(FOWR{_1|7PL8VO;35;_LYtwp9f~T;3&m z{8-38uVLo@_FjNd#gIdZ#pBPiMooMbJUC$eGGEd)>nZ8W{kJ8j1TD$eofb*2&UnP; zuA*dH(oMZ?GKaM^m)u+ZoI+0r= z!FZc)O`6cJpjRUyBoN-4+%3x+38_!&(u6?{KceM6(<0QgEO1GP-Iu&v&#m zzk+c!s&Fzy-BVmt@uN#&4)y2^+}znpxVA+isbRbjfu9MWA9cuIVYmkD9z8{kgir=o zS;~)ufmkrT7Ddxy1g>zm4!MI57$~GkKLaZ zW;(1iHumgF=G+n1MjQeNw*1Y*Pwg9em#mq(>wLw4L?ep%Apb3EN4`3wlc^Us|MK?U zI;VAlW?fU?t@SQ-x4&(&VM+jVomQmly6Oz2=Tzk@HagzW%P3JmL#Y&Uh zpQ49dKC5L`kmH#(F?;$0)sHl=*&SLSkTBi^EqT(MAooJ9*SuAURIDmFL8qgFMMhAF zUJW~}EBX5h*vrV$-6%vOHO!a%Qc_4^CBTk5EIMg}OC#aT%0yBz0``q>lq~>*Dun?7 zHF@ydL9xKXs^I7?FD~m+SfJ7bGgBI)D@M9@Qpw^t&N90ZDRq> zlB<4(_t!)*tf-uALRe1cJjj>NZ#1a z0wTF?uc6DW!r!)n)JVCIXm$_glbhNG<;kWSp3cbI6nre2^F#;-@@0s(ikRKyh+dxH zZywZynhB9>2+3aPr5{rOXxx?@_WfU>Z@~^!3n!5zmuyS2G9Ho|B5Ar*_JCGhnOvxP zH_*e1oVPvXFvOjHO;r>Mhmte9kGThjiAHaLIo*S(Q1x`_beGx_)2@$na?il?6=@cm z+rZyQxG19=@?ZfdtALog1EfiYvGWVPgO3~mf#!R zkjtxOg3E~Ywh}+&5F!}A6>YFizjnDZ|Avx+tijURUx7%Io$AUMxd|t^D~nAABE`9q z`R_oQ*}eiIcMg30%C_z#^wEQ!hmmcP!H7H8B23JXkz1Q`JIgSIB~aIOjPie)BP8aH z{S=Hc&%{_A;prGtBuqNBp%w%RZLsGbgMqqBs1N=4VllnY%`x*F4G;tOg`(~PocbQ7 z1F6Qpv&bb{*{8SH1*NvdTzOlDbJoT5IT~%l!`pjAqm1P$s^+;R$5*^~5eH9aXoTg( zr3#aIdK>Pgvh|bJr&Oi(c8phln5uukO7q)HJ2Ae))fU01Y&~w{%W=0te<;@l2 z>2FJ%58xVF`OLZZSb^u??nyG_)LXO_DCvrDAfEJt=Qc!GkEgJXV0Hbty*vuKwv0NZ z-~GI{DXfj0DZOy=*{C-uq74x0EVGRMOKCq`cq{fgj^WS-ICx01`$0_t!_b9T?+zq$ z6Ahsig2m_u-4lnZvmT)K_OGQBzM``5YfC>_`PZ#KQSZF*0jXK@kKDjBuiJZM2z<#! zKeB?}R@Ou^$G}KoqVoLoag!{;6$NuBsLCPYVSbUTAcXGeME?ml`l zW8(kl9=#OuNAm(7HWGaFs%AM0kS9cq1#!qWu~{ySd~Le^F%;nMQ_nAmM}LlE@VEQ_ zwodudaYV}iKgsSqhr4V1p&97q1mO~$)+$T(H%eiAjq`9iiEB@lxZ~N3y1YUPet@?N z3)g|xg2^eQ#?3G-Ycv$5)bU6b1|o3Dp9OttA+TUu^piBR{a$90B@}pxO*YNKndMQY zO@@*tDg*zKoJq-`*7Rd#(e>1yAXnJ_^3kmVt-ub28*I_?ewR*W*R2*s=Hb?wqXk+x zQz4B|aj9W@vf`9YHM5&obg0gHs`SL4F^wN;<7C#6c=UCE42<6NTO^}R+=O;U7JR-- z5j?|o5Di@E4xORJ=}1l#0j74TGQhEolqf|kyTMPASr-2*2&JfE5O?xfRbpPeNw6}g zm?44`-@iv;s&_;K$kLvrqLs&?3VUCoiJV}bMQXO|A>v89pwGC{HmnqCGHUrd{5Po3 z=6vy=?~;^O;_P=x%6CahyK>^YB&BH2cS%Z9JjwqWzwxh-q!8q|4V`{%uGs&VQrF$s zWe?3-7#jQOC!uxK&>DZ^r;WHa=%LBnLI<6ecGrBl_TZQ3#hL<^`Tr8lSXX288tB3* z#Gtd0?h{VGCB==VSBsu#_NfQlZ`WM26550&F$PEoXW$G^@idxpkCiKFB*bhzZEE;3 zE+D${fxcFi)ZD=sYtt&o5*~t++P)+-dkx41D2p2jZZ*{+)k3tA*dL-dMt2h)RyzBC znYHy(7a;aml#&;oNmM0#O3IygY#0&$VC1Uxw=|-P^gEY%H9K{Z-Xp{FQ~zqd7yuh)5L=Ei)69)D}W#p5=`RCP4wQ@VOV@GNsqheyy!} z*%6TRDorvX9S;@2OfeGch1C*e0QW3@7>qjJmMd9$3hrrDSF*PR7J5r=^5aCwJPZ8n z(>R9!{EhQo7Lq}4dxN^pP~O`-14-{t%g92MXEl#S3_blGy>} zV)mJ>787&R5-Z4e`XjTSiOq5@@CBmaxiho%vEt$Jlm;VRx@77}7*FR!y_?Yng-MNF z)-cb7r;~WZd2!NFH29Rw@By6A4H^ez>m|1WwbK^d4bH19 zFryrtnu4YBvG>t(azn7}Cz0f!i3WQawJzo)p*1}GoM>uApT`tO~yWJXzz2 zT%WX^59hh@{uV>SwI!8_=o`GUzPGotlkU)WcXz zmShlX77?TZ^?Rm$XpBa)D8l(&TZWGJr>v^{U#8K7?p4DnmM4?a7X>CzwpL!|t3 zscV6G^>kNX@!mG7^@u+V^Nt9KdNch{`_sqo+&D~NGl&&yK)2UmL)Ew-+nRW z?)|A{5niDtE*ZY_lAm7*oj8%^J$xsrpUa`s%aZS6I(Syf&g@)Q-;w%BWojCWH|rR1 zYb)F><5WGPCa*U<%N00<>rfbH9zCDpj|MGKg2=g;H~1S$m7{T7PQr0UPwPN5h=XRX zrbFNy8>Csm$M7)`cR*|L_$~-L)JdSKIE(wy+IC195JhW9!otU+57`Z4Rq=6_=AdO- znMQtEk9_%qwiQ$yCwL6}m^Lh14fPtBway4E7JL8y`=p6<06{wM<~a0;c^XT)90vBH z@^o-h)LNkFS!r+;n)f2@7QfRaS-+ zYuDZPimXKWc_VA7ya5}+q#7zLT6~u-hc8yn+MklPp`G!^>-l!Wmjw7UFeC zOrn6jrDhgw(D4npb5J8;^%~=NS`1pW0K57H1sV7fNsC8Pf@9l); zN9E4I4UiYkmrEUs_p8$0q}UHyBm^4fg&Q&@|Z?*}_(u+(;<$_M&0$my`;b z&_WxG6*@=k=D?C>Brk^%zuTk(n)q<02lDyNB>Y;q6yz@gFmZ0ZoEts?r+?!M^DF7=B8N z3h;|A+e>eWX}UeU*{BGv-t@F&nO#61-J5=&otrF;)Q%O;IGIuCv#Xk)P~C9tR#jf9 zJ4c4MQz>k34upy47wk3d9}?L!nwbj=sK^p6@{#>cFVPi4;hqi|Q-Vl`QDi4meb@TdMLn^+~{k>?1HX|raU3}f_hnV#}k^H+-Zq7ss9 zOJc9j^eAvRm&8;T&yaYCNL$2E3%^fDLpa&k$o3~E>MIAibHIavn8mY%-8_odE}wz( zPC1%B+Pu!5wCUhu5cJrn(XAH+ubycftE(GzIK28fnA=ox^p$d*Kcq9b{v}Q?YEU# z9bXSwbrB!^uTd5X&WJ8-g@?p!G|_k%8=$YSJq0#Bg}dF9B_sUoZb+{)a*N#^qFqOs z^kD&ub9O2SZ6h@DndVGc9g}X=;e13_a3H>mCPoQIK(@^h zsN9o6f;Uc-{2Qlk%)BqzX5L-})#!s^4^K7{22c@F-MkXnIh#Vq2UNr!pX-MYzwdM_ zlh;V-XEinG`Up6<9}00iZ*6EG)slZWE=tE4*=|eoIk#jT+$-V_RbkC1V%2odhnWt- z$HUGn(Sk>;NI{({;|QX-Y){5^Ai~Q z&-per_4a(y2zn$;gZlhvVCmzuISVfU>?N;n>T2y-ezc76iA#6gHupd0A9QNLhSmi zJLp?4*vNA}6hrE2iWyGdZrLt)8hlrK0o?1xTo!(esAi|}rg)Ai@K7Aaj!Y+0Zf^3wyHjuks zXeu5m{F%1ZuzxXq@IFjziVwCzOVTRY@LD^KqaU#Ky6y0=dqn1g9kup6&3U7L*u`62 zdhz@gl6gY``MuDR9NQ2%%&VXGhbg;v3b*dsbhGw%{DaTTdowvNXD+1FeNZi;9rM&P zA`ajdD2r!|PhsAwGg5uy=z>|-C2XMW(3FObq7FG4UNv>?*-X@ZJuN|UqBIQJ1WjF- z3C-i^I6{T{>`iW68M!hTxr5Q|g3OKuIA|yz(Jr(JeTI@SU=) K`2w*q=l=nVpa0tc diff --git a/src/test/cypress/fixtures/exam/template.json b/src/test/cypress/fixtures/exam/template.json deleted file mode 100644 index 5f4ea802e6a7..000000000000 --- a/src/test/cypress/fixtures/exam/template.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "randomizeExerciseOrder": false, - "numberOfCorrectionRoundsInExam": 1, - "examMaxPoints": 10, - "visible": false, - "started": false, - "gracePeriod": 30, - "course": "", - "title": "", - "visibleDate": "", - "startDate": "", - "endDate": "", - "numberOfExercisesInExam": 1, - "startText": "Exam start text", - "endText": "Exam end text", - "confirmationStartText": "Exam confirmation start text", - "confirmationEndText": "Exam confirmation end text" -} diff --git a/src/test/cypress/fixtures/exercise/file-upload/submission.json b/src/test/cypress/fixtures/exercise/file-upload/submission.json deleted file mode 100644 index 6d588766c95a..000000000000 --- a/src/test/cypress/fixtures/exercise/file-upload/submission.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "files": [ - { - "name": "BubbleSort.java", - "path": "programming_exercise_submissions/build_error/BubbleSort.txt" - } - ] -} diff --git a/src/test/cypress/fixtures/exercise/file-upload/template.json b/src/test/cypress/fixtures/exercise/file-upload/template.json deleted file mode 100644 index add580f86f46..000000000000 --- a/src/test/cypress/fixtures/exercise/file-upload/template.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "mode": "INDIVIDUAL", - "includedInOverallScore": "INCLUDED_COMPLETELY", - "studentAssignedTeamIdComputed": false, - "secondCorrectionEnabled": false, - "type": "file-upload", - "bonusPoints": 0, - "isAtLeastTutor": false, - "isAtLeastEditor": false, - "isAtLeastInstructor": false, - "teamMode": false, - "assessmentDueDateError": false, - "dueDateError": false, - "exampleSolutionPublicationDateError": false, - "exampleSolutionPublicationDateWarning": false, - "presentationScoreEnabled": false, - "assessmentType": "MANUAL", - "title": "File Upload Exercise 1", - "filePattern": "pdf", - "maxPoints": 10, - "problemStatement": "Problem Statement", - "exampleSolution": "Example Solution", - "gradingInstructions": "Assessment Instructions" -} diff --git a/src/test/cypress/fixtures/exercise/modeling/submission.json b/src/test/cypress/fixtures/exercise/modeling/submission.json deleted file mode 100644 index 15f3e5c2b71d..000000000000 --- a/src/test/cypress/fixtures/exercise/modeling/submission.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "submissionExerciseType": "modeling", - "id": null, - "submitted": false, - "participation": null, - "empty": true, - "explanationText": "", - "model": "{\"version\":\"2.0.0\",\"type\":\"ClassDiagram\",\"size\":{\"width\":1000,\"height\":500},\"interactive\":{\"elements\":[],\"relationships\":[]},\"elements\":[{\"id\":\"ccf5edad-98d5-401d-9885-e332607dfa6a\",\"name\":\"Package\",\"type\":\"Package\",\"owner\":null,\"bounds\":{\"x\":240,\"y\":230,\"width\":200,\"height\":100}},{\"id\":\"59787b15-e81c-4710-99bf-e11104c22dbf\",\"name\":\"Class\",\"type\":\"Class\",\"owner\":null,\"bounds\":{\"x\":0,\"y\":0,\"width\":200,\"height\":102},\"attributes\":[\"c3469dd2-a822-45b2-823d-13bc5c8370da\"],\"methods\":[\"b6457544-7cbe-47f5-b704-523ce6e967f9\"]},{\"id\":\"c3469dd2-a822-45b2-823d-13bc5c8370da\",\"name\":\"+ attribute: Type\",\"type\":\"ClassAttribute\",\"owner\":\"59787b15-e81c-4710-99bf-e11104c22dbf\",\"bounds\":{\"x\":0.5,\"y\":40.5,\"width\":199,\"height\":30}},{\"id\":\"b6457544-7cbe-47f5-b704-523ce6e967f9\",\"name\":\"+ method()\",\"type\":\"ClassMethod\",\"owner\":\"59787b15-e81c-4710-99bf-e11104c22dbf\",\"bounds\":{\"x\":0.5,\"y\":71.5,\"width\":199,\"height\":30}},{\"id\":\"8786cede-a45c-4593-ac6a-b7ac235f1fae\",\"name\":\"Abstract\",\"type\":\"AbstractClass\",\"owner\":null,\"bounds\":{\"x\":0,\"y\":120,\"width\":200,\"height\":112},\"attributes\":[\"0aaf6115-8d34-4509-a179-26d7b7d22596\"],\"methods\":[\"9f285794-4e97-42d1-adcc-e5467977b76c\"]},{\"id\":\"0aaf6115-8d34-4509-a179-26d7b7d22596\",\"name\":\"+ attribute: Type\",\"type\":\"ClassAttribute\",\"owner\":\"8786cede-a45c-4593-ac6a-b7ac235f1fae\",\"bounds\":{\"x\":0.5,\"y\":170.5,\"width\":199,\"height\":30}},{\"id\":\"9f285794-4e97-42d1-adcc-e5467977b76c\",\"name\":\"+ method()\",\"type\":\"ClassMethod\",\"owner\":\"8786cede-a45c-4593-ac6a-b7ac235f1fae\",\"bounds\":{\"x\":0.5,\"y\":201.5,\"width\":199,\"height\":30}}],\"relationships\":[],\"assessments\":[]}" -} diff --git a/src/test/cypress/fixtures/exercise/modeling/template.json b/src/test/cypress/fixtures/exercise/modeling/template.json deleted file mode 100644 index 6173bb7cfe61..000000000000 --- a/src/test/cypress/fixtures/exercise/modeling/template.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "mode": "INDIVIDUAL", - "includedInOverallScore": "INCLUDED_COMPLETELY", - "numberOfAssessmentsOfCorrectionRounds": [ - { - "inTime": 0, - "late": 0 - } - ], - "studentAssignedTeamIdComputed": false, - "secondCorrectionEnabled": false, - "type": "modeling", - "bonusPoints": 10, - "isAtLeastTutor": false, - "isAtLeastEditor": false, - "isAtLeastInstructor": false, - "teamMode": false, - "assessmentDueDateError": false, - "dueDateError": false, - "exampleSolutionPublicationDateError": false, - "exampleSolutionPublicationDateWarning": false, - "presentationScoreEnabled": false, - "diagramType": "ClassDiagram", - "assessmentType": "MANUAL", - "title": "Modeling Exercise", - "categories": ["{\"category\":\"cypress-e2e\",\"color\":\"#6ae8ac\"}"], - "difficulty": "EASY", - "maxPoints": 10, - "problemStatement": "Problem Statement", - "gradingInstructions": "Grading Instruction ", - "exampleSolutionExplanation": "Example Solution Explanation", - "exampleSolutionModel": "{\"version\":\"2.0.0\",\"type\":\"ClassDiagram\",\"size\":{\"width\":640,\"height\":600},\"interactive\":{\"elements\":[],\"relationships\":[]},\"elements\":[{\"id\":\"6e1f57c6-cbc7-4b97-9df9-c5741dc905fa\",\"name\":\"Package\",\"type\":\"Package\",\"owner\":null,\"bounds\":{\"x\":230,\"y\":0,\"width\":200,\"height\":100}},{\"id\":\"ff7e3be0-9765-4301-baf5-cf9cf2f17c3c\",\"name\":\"Class\",\"type\":\"Class\",\"owner\":null,\"bounds\":{\"x\":0,\"y\":220,\"width\":200,\"height\":100},\"attributes\":[\"de2d464b-f969-4cf3-ac0d-2f300b3a6497\"],\"methods\":[\"084a59b9-3009-4ebd-885c-159b436581d9\"]},{\"id\":\"de2d464b-f969-4cf3-ac0d-2f300b3a6497\",\"name\":\"+ attribute: Type\",\"type\":\"ClassAttribute\",\"owner\":\"ff7e3be0-9765-4301-baf5-cf9cf2f17c3c\",\"bounds\":{\"x\":0,\"y\":260,\"width\":200,\"height\":30}},{\"id\":\"084a59b9-3009-4ebd-885c-159b436581d9\",\"name\":\"+ method()\",\"type\":\"ClassMethod\",\"owner\":\"ff7e3be0-9765-4301-baf5-cf9cf2f17c3c\",\"bounds\":{\"x\":0,\"y\":290,\"width\":200,\"height\":30}},{\"id\":\"1ad94aff-ee37-494f-8b99-9d861dc58e4a\",\"name\":\"Abstract\",\"type\":\"AbstractClass\",\"owner\":null,\"bounds\":{\"x\":380,\"y\":220,\"width\":200,\"height\":110},\"attributes\":[\"4d58287c-d4c0-42d1-9d02-ad239b701de6\"],\"methods\":[\"2de2a7c3-19c9-4534-8a71-f6607e93556c\"]},{\"id\":\"4d58287c-d4c0-42d1-9d02-ad239b701de6\",\"name\":\"+ attribute: Type\",\"type\":\"ClassAttribute\",\"owner\":\"1ad94aff-ee37-494f-8b99-9d861dc58e4a\",\"bounds\":{\"x\":380,\"y\":270,\"width\":200,\"height\":30}},{\"id\":\"2de2a7c3-19c9-4534-8a71-f6607e93556c\",\"name\":\"+ method()\",\"type\":\"ClassMethod\",\"owner\":\"1ad94aff-ee37-494f-8b99-9d861dc58e4a\",\"bounds\":{\"x\":380,\"y\":300,\"width\":200,\"height\":30}}],\"relationships\":[],\"assessments\":[]}" -} diff --git a/src/test/cypress/fixtures/exercise/programming/c/all_successful/exercise.txt b/src/test/cypress/fixtures/exercise/programming/c/all_successful/exercise.txt deleted file mode 100644 index 9fec30452413..000000000000 --- a/src/test/cypress/fixtures/exercise/programming/c/all_successful/exercise.txt +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include - -int main(void) { - int x = 6; - int y = 10; - printf("%d\n", x * x + 5 * y - 4); - return EXIT_SUCCESS; -} diff --git a/src/test/cypress/fixtures/exercise/programming/c/all_successful/submission.json b/src/test/cypress/fixtures/exercise/programming/c/all_successful/submission.json deleted file mode 100644 index b12cadde14e5..000000000000 --- a/src/test/cypress/fixtures/exercise/programming/c/all_successful/submission.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "deleteFiles": ["exercise.c"], - "createFilesInRootFolder": true, - "files": [ - { - "name": "exercise.c", - "path": "exercise/programming/c/all_successful/exercise.txt" - } - ], - "expectedResult": "100%" -} diff --git a/src/test/cypress/fixtures/exercise/programming/c/template.json b/src/test/cypress/fixtures/exercise/programming/c/template.json deleted file mode 100644 index ee82b71a9be9..000000000000 --- a/src/test/cypress/fixtures/exercise/programming/c/template.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "allowOfflineIde": true, - "allowOnlineEditor": true, - "assessmentDueDateError": false, - "assessmentType": "AUTOMATIC", - "bonusPoints": 0, - "checkoutSolutionRepository": false, - "dueDateError": false, - "exampleSolutionPublicationDateError": false, - "exampleSolutionPublicationDateWarning": false, - "includedInOverallScore": "INCLUDED_COMPLETELY", - "isAtLeastEditor": false, - "isAtLeastInstructor": false, - "isAtLeastTutor": false, - "maxPoints": 10, - "mode": "INDIVIDUAL", - "noVersionControlAndContinuousIntegrationAvailable": false, - "packageName": "", - "presentationScoreEnabled": false, - "problemStatement": "# Aufgabe (6 Punkte)\n\n## Beschreibung\n\nErstelle ein C-Programm, welches das Ergebnis des Terms $$ x^2 + 5 \\cdot y - 4 $$ berechnet und auf der\nStandardausgabe ausgibt. Verwende für die Variablen `x` und `y` den Datentyp `int` und wähle für beide\nVariablen einen beliebigen Wert!\n\n### Beispielausgaben\n\nBeispiel 1: `x = 3` und `y = 5`\n\n```text\n30\n```\n\nBeispiel 2: `x = -3` und `y = 5`\n\n```text\n30\n```\n\nBeispiel 3: `x = 5` und `y = -10`\n\n```text\n-29\n```\n\n## Hinweise\n\n- Bei den Ein-/Ausgabetests werden beim Testen die Werte der Variablen `x` und `y` in Ihrem Programm verändert!\n\n## Tests\n\n1. [task][Kompilieren](Compile)\n2. [task][Strukturtests](CodeStructure)\n3. [task][Ein-/Ausgabetests](InputOutput)\n", - "programmingLanguage": "C", - "projectType": "FACT", - "secondCorrectionEnabled": false, - "shortName": "", - "showTestNamesToStudents": false, - "solutionParticipation": { - "type": "solution" - }, - "staticCodeAnalysisEnabled": false, - "studentAssignedTeamIdComputed": false, - "teamMode": false, - "templateParticipation": { - "type": "template" - }, - "title": "", - "type": "programming" -} diff --git a/src/test/cypress/fixtures/exercise/programming/java/all_successful/BubbleSort.txt b/src/test/cypress/fixtures/exercise/programming/java/all_successful/BubbleSort.txt deleted file mode 100644 index 8484f2f2bc90..000000000000 --- a/src/test/cypress/fixtures/exercise/programming/java/all_successful/BubbleSort.txt +++ /dev/null @@ -1,23 +0,0 @@ -package de.test; - -import java.util.*; - -public class BubbleSort implements SortStrategy { - - /** - * Sorts dates with BubbleSort. - * - * @param input the List of Dates to be sorted - */ - public void performSort(List input) { - for (int i = input.size() - 1; i >= 0; i--) { - for (int j = 0; j < i; j++) { - if (input.get(j).compareTo(input.get(j + 1)) > 0) { - Date temp = input.get(j); - input.set(j, input.get(j + 1)); - input.set(j + 1, temp); - } - } - } - } -} diff --git a/src/test/cypress/fixtures/exercise/programming/java/all_successful/Client.txt b/src/test/cypress/fixtures/exercise/programming/java/all_successful/Client.txt deleted file mode 100644 index b4142dec7883..000000000000 --- a/src/test/cypress/fixtures/exercise/programming/java/all_successful/Client.txt +++ /dev/null @@ -1,109 +0,0 @@ -package de.test; - -import java.text.*; -import java.util.*; -import java.util.concurrent.ThreadLocalRandom; - -public final class Client { - - private static final int ITERATIONS = 10; - - private static final int RANDOM_FLOOR = 5; - - private static final int RANDOM_CEILING = 15; - - private Client() { - } - - /** - * Main method. - * Add code to demonstrate your implementation here. - * - * @param args command line arguments - */ - public static void main(String[] args) throws ParseException { - - Context sortingContext = new Context(); - Policy policy = new Policy(sortingContext); - - for (int i = 0; i < ITERATIONS; i++) { - List dates = createRandomDatesList(); - - sortingContext.setDates(dates); - policy.configure(); - - System.out.print("Unsorted Array of course dates = "); - printDateList(dates); - - sortingContext.sort(); - - System.out.print("Sorted Array of course dates = "); - printDateList(dates); - } - } - - /** - * Generates a List of random Date objects with random List size between - * {@link #RANDOM_FLOOR} and {@link #RANDOM_CEILING}. - * - * @return a List of random Date objects - * @throws ParserException if date string cannot be parsed - */ - private static List createRandomDatesList() throws ParseException { - int listLength = randomIntegerWithin(RANDOM_FLOOR, RANDOM_CEILING); - List list = new ArrayList<>(); - - SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy"); - Date lowestDate = dateFormat.parse("08.11.2016"); - Date highestDate = dateFormat.parse("03.11.2020"); - - for (int i = 0; i < listLength; i++) { - Date randomDate = randomDateWithin(lowestDate, highestDate); - list.add(randomDate); - } - return list; - } - - /** - * Creates a random Date within the given range. - * - * @param low the lower bound - * @param high the upper bound - * @return random Date within the given range - */ - private static Date randomDateWithin(Date low, Date high) { - long randomLong = randomLongWithin(low.getTime(), high.getTime()); - return new Date(randomLong); - } - - /** - * Creates a random long within the given range. - * - * @param low the lower bound - * @param high the upper bound - * @return random long within the given range - */ - private static long randomLongWithin(long low, long high) { - return ThreadLocalRandom.current().nextLong(low, high + 1); - } - - /** - * Creates a random int within the given range. - * - * @param low the lower bound - * @param high the upper bound - * @return random int within the given range - */ - private static int randomIntegerWithin(int low, int high) { - return ThreadLocalRandom.current().nextInt(low, high + 1); - } - - /** - * Prints out the given Array of Date objects. - * - * @param list of the dates to print - */ - private static void printDateList(List list) { - System.out.println(list.toString()); - } -} diff --git a/src/test/cypress/fixtures/exercise/programming/java/all_successful/Context.txt b/src/test/cypress/fixtures/exercise/programming/java/all_successful/Context.txt deleted file mode 100644 index c44eca71bc4c..000000000000 --- a/src/test/cypress/fixtures/exercise/programming/java/all_successful/Context.txt +++ /dev/null @@ -1,34 +0,0 @@ -package de.test; - -import java.util.*; - -public class Context { - private SortStrategy sortAlgorithm; - - private List dates; - - public List getDates() { - return dates; - } - - public void setDates(List dates) { - this.dates = dates; - } - - public void setSortAlgorithm(SortStrategy sa) { - sortAlgorithm = sa; - } - - public SortStrategy getSortAlgorithm() { - return sortAlgorithm; - } - - /** - * Runs the configured sort algorithm. - */ - public void sort() { - if (sortAlgorithm != null) { - sortAlgorithm.performSort(this.dates); - } - } -} diff --git a/src/test/cypress/fixtures/exercise/programming/java/all_successful/MergeSort.txt b/src/test/cypress/fixtures/exercise/programming/java/all_successful/MergeSort.txt deleted file mode 100644 index 449b265e261c..000000000000 --- a/src/test/cypress/fixtures/exercise/programming/java/all_successful/MergeSort.txt +++ /dev/null @@ -1,53 +0,0 @@ -package de.test; - -import java.util.*; - -public class MergeSort implements SortStrategy { - - /** - * Wrapper method for the real MergeSort algorithm. - * - * @param input the List of Dates to be sorted - */ - public void performSort(List input) { - mergesort(input, 0, input.size() - 1); - } - - private void mergesort(List input, int low, int high) { - if (high - low < 1) { - return; - } - int mid = (low + high) / 2; - mergesort(input, low, mid); - mergesort(input, mid + 1, high); - merge(input, low, mid, high); - } - - private void merge(List input, int low, int middle, int high) { - - Date[] temp = new Date[high - low + 1]; - int leftIndex = low; - int rightIndex = middle + 1; - int wholeIndex = 0; - while (leftIndex <= middle && rightIndex <= high) { - if (input.get(leftIndex).compareTo(input.get(rightIndex)) <= 0) { - temp[wholeIndex] = input.get(leftIndex++); - } else { - temp[wholeIndex] = input.get(rightIndex++); - } - wholeIndex++; - } - if (leftIndex <= middle && rightIndex > high) { - while (leftIndex <= middle) { - temp[wholeIndex++] = input.get(leftIndex++); - } - } else { - while (rightIndex <= high) { - temp[wholeIndex++] = input.get(rightIndex++); - } - } - for (wholeIndex = 0; wholeIndex < temp.length; wholeIndex++) { - input.set(wholeIndex + low, temp[wholeIndex]); - } - } -} diff --git a/src/test/cypress/fixtures/exercise/programming/java/all_successful/Policy.txt b/src/test/cypress/fixtures/exercise/programming/java/all_successful/Policy.txt deleted file mode 100644 index 1ed740f33d38..000000000000 --- a/src/test/cypress/fixtures/exercise/programming/java/all_successful/Policy.txt +++ /dev/null @@ -1,25 +0,0 @@ -package de.test; - -public class Policy { - - private static final int DATES_SIZE_THRESHOLD = 10; - - private Context context; - - public Policy(Context context) { - this.context = context; - } - - /** - * Chooses a strategy depending on the number of date objects. - */ - public void configure() { - if (this.context.getDates().size() > DATES_SIZE_THRESHOLD) { - System.out.println("More than " + DATES_SIZE_THRESHOLD + " dates, choosing merge sort!"); - this.context.setSortAlgorithm(new MergeSort()); - } else { - System.out.println("Less or equal than " + DATES_SIZE_THRESHOLD + " dates. choosing quick sort!"); - this.context.setSortAlgorithm(new BubbleSort()); - } - } -} diff --git a/src/test/cypress/fixtures/exercise/programming/java/all_successful/SortStrategy.txt b/src/test/cypress/fixtures/exercise/programming/java/all_successful/SortStrategy.txt deleted file mode 100644 index c721267ddb7a..000000000000 --- a/src/test/cypress/fixtures/exercise/programming/java/all_successful/SortStrategy.txt +++ /dev/null @@ -1,14 +0,0 @@ -package de.test; - -import java.util.Date; -import java.util.List; - -public interface SortStrategy { - - /** - * Sorts a list of Dates. - * - * @param input list of Dates - */ - void performSort(List input); -} diff --git a/src/test/cypress/fixtures/exercise/programming/java/all_successful/submission.json b/src/test/cypress/fixtures/exercise/programming/java/all_successful/submission.json deleted file mode 100644 index 8a4d1751131b..000000000000 --- a/src/test/cypress/fixtures/exercise/programming/java/all_successful/submission.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "deleteFiles": ["BubbleSort.java", "Client.java", "MergeSort.java"], - "createFilesInRootFolder": false, - "files": [ - { - "name": "BubbleSort.java", - "path": "exercise/programming/java/all_successful/BubbleSort.txt" - }, - { - "name": "Context.java", - "path": "exercise/programming/java/all_successful/Context.txt" - }, - { - "name": "Client.java", - "path": "exercise/programming/java/all_successful/Client.txt" - }, - { - "name": "MergeSort.java", - "path": "exercise/programming/java/all_successful/MergeSort.txt" - }, - { - "name": "Policy.java", - "path": "exercise/programming/java/all_successful/Policy.txt" - }, - { - "name": "SortStrategy.java", - "path": "exercise/programming/java/all_successful/SortStrategy.txt" - } - ], - "expectedResult": "100%", - "packageName": "de.test" -} diff --git a/src/test/cypress/fixtures/exercise/programming/java/assessment/submission.json b/src/test/cypress/fixtures/exercise/programming/java/assessment/submission.json deleted file mode 100644 index 00f63679dd36..000000000000 --- a/src/test/cypress/fixtures/exercise/programming/java/assessment/submission.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "fileName": "src/de/test/MergeSort.java", - "fileContent": "package de.test;\n\nimport java.util.*;\n\npublic class MergeSort implements SortStrategy {\n \n /**\n * Wrapper method for the real MergeSort algorithm.\n *\n * @param input the List of Dates to be sorted\n */\n public void performSort(List input) {\n mergesort(input, 0, input.size() - 1);\n }\n\n // Recursive merge sort method\n private void mergesort(List input, int low, int high) {\n if (high - low < 1) {\n return;\n }\n int mid = (low + high) / 2;\n mergesort(input, low, mid);\n mergesort(input, mid + 1, high);\n merge(input, low, mid, high);\n }\n\n // Merge method\n private void merge(List input, int low, int middle, int high) {\n\n Date[] temp = new Date[high - low + 1];\n int leftIndex = low;\n int rightIndex = middle + 1;\n int wholeIndex = 0;\n while (leftIndex <= middle && rightIndex <= high) {\n if (input.get(leftIndex).compareTo(input.get(rightIndex)) <= 0) {\n temp[wholeIndex] = input.get(leftIndex++);\n }\n else {\n temp[wholeIndex] = input.get(rightIndex++);\n }\n wholeIndex++;\n }\n if (leftIndex <= middle && rightIndex > high) {\n while (leftIndex <= middle) {\n temp[wholeIndex++] = input.get(leftIndex++);\n }\n }\n else {\n while (rightIndex <= high) {\n temp[wholeIndex++] = input.get(rightIndex++);\n }\n }\n for (wholeIndex = 0; wholeIndex < temp.length; wholeIndex++) {\n input.set(wholeIndex + low, temp[wholeIndex]);\n }\n }\n}\n" - }, - { - "fileName": "src/de/test/Client.java", - "fileContent": "package de.test;\n\nimport java.text.*;\nimport java.util.*;\nimport java.util.concurrent.ThreadLocalRandom;\n\npublic final class Client {\n\n private static final int ITERATIONS = 10;\n \n private static final int RANDOM_FLOOR = 5;\n \n private static final int RANDOM_CEILING = 15;\n\n private Client() {\n }\n\n /**\n * Main method.\n * Add code to demonstrate your implementation here.\n *\n * @param args command line arguments\n */\n public static void main(String[] args) throws ParseException {\n\n // Init Context and Policy\n\n Context sortingContext = new Context();\n Policy policy = new Policy(sortingContext);\n\n // Run multiple times to simulate different sorting strategies\n for (int i = 0; i < ITERATIONS; i++) {\n List dates = createRandomDatesList();\n\n sortingContext.setDates(dates);\n policy.configure();\n\n System.out.print(\"Unsorted Array of course dates = \");\n printDateList(dates);\n\n sortingContext.sort();\n\n System.out.print(\"Sorted Array of course dates = \");\n printDateList(dates);\n }\n }\n\n /**\n * Generates a List of random Date objects with random List size between\n * {@link #RANDOM_FLOOR} and {@link #RANDOM_CEILING}.\n *\n * @return a List of random Date objects\n * @throws ParserException if date string cannot be parsed\n */\n private static List createRandomDatesList() throws ParseException {\n int listLength = randomIntegerWithin(RANDOM_FLOOR, RANDOM_CEILING);\n List list = new ArrayList<>();\n\n SimpleDateFormat dateFormat = new SimpleDateFormat(\"dd.MM.yyyy\");\n Date lowestDate = dateFormat.parse(\"08.11.2016\");\n Date highestDate = dateFormat.parse(\"03.11.2020\");\n\n for (int i = 0; i < listLength; i++) {\n Date randomDate = randomDateWithin(lowestDate, highestDate);\n list.add(randomDate);\n }\n return list;\n }\n\n /**\n * Creates a random Date within the given range.\n *\n * @param low the lower bound\n * @param high the upper bound\n * @return random Date within the given range\n */\n private static Date randomDateWithin(Date low, Date high) {\n long randomLong = randomLongWithin(low.getTime(), high.getTime());\n return new Date(randomLong);\n }\n\n /**\n * Creates a random long within the given range.\n *\n * @param low the lower bound\n * @param high the upper bound\n * @return random long within the given range\n */\n private static long randomLongWithin(long low, long high) {\n return ThreadLocalRandom.current().nextLong(low, high + 1);\n }\n\n /**\n * Creates a random int within the given range.\n *\n * @param low the lower bound\n * @param high the upper bound\n * @return random int within the given range\n */\n private static int randomIntegerWithin(int low, int high) {\n return ThreadLocalRandom.current().nextInt(low, high + 1);\n }\n\n /**\n * Prints out the given Array of Date objects.\n *\n * @param list of the dates to print\n */\n private static void printDateList(List list) {\n System.out.println(list.toString());\n }\n}\n" - }, - { - "fileName": "src/de/test/BubbleSort.java", - "fileContent": "package de.test;\n\nimport java.util.*;\n\npublic class BubbleSort implements SortStrategy {\n /**\n * Sorts dates with BubbleSort.\n *\n */\n public void performSort(List input) {\n for (int i = input.size() - 1; i >= 0; i--) {\n for (int j = 0; j < i; j++) {\n if (input.get(j).compareTo(input.get(j + 1)) > 0) {\n Date temp = input.get(j);\n input.set(j, input.get(j + 1));\n input.set(j + 1, temp);\n }\n }\n }\n\n }\n}\n" - } -] diff --git a/src/test/cypress/fixtures/exercise/programming/java/build_error/BubbleSort.txt b/src/test/cypress/fixtures/exercise/programming/java/build_error/BubbleSort.txt deleted file mode 100644 index 030102a8e7c1..000000000000 --- a/src/test/cypress/fixtures/exercise/programming/java/build_error/BubbleSort.txt +++ /dev/null @@ -1 +0,0 @@ -this should fail \ No newline at end of file diff --git a/src/test/cypress/fixtures/exercise/programming/java/build_error/submission.json b/src/test/cypress/fixtures/exercise/programming/java/build_error/submission.json deleted file mode 100644 index 4a873094d884..000000000000 --- a/src/test/cypress/fixtures/exercise/programming/java/build_error/submission.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "deleteFiles": ["BubbleSort.java", "Client.java", "MergeSort.java"], - "createFilesInRootFolder": false, - "files": [ - { - "name": "BubbleSort.java", - "path": "exercise/programming/java/build_error/BubbleSort.txt" - } - ], - "expectedResult": "0%", - "packageName": "de.test" -} diff --git a/src/test/cypress/fixtures/exercise/programming/java/partially_successful/submission.json b/src/test/cypress/fixtures/exercise/programming/java/partially_successful/submission.json deleted file mode 100644 index 97560fee1f72..000000000000 --- a/src/test/cypress/fixtures/exercise/programming/java/partially_successful/submission.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "deleteFiles": ["BubbleSort.java", "Client.java", "MergeSort.java"], - "createFilesInRootFolder": false, - "files": [ - { - "name": "BubbleSort.java", - "path": "exercise/programming/java/all_successful/BubbleSort.txt" - }, - { - "name": "MergeSort.java", - "path": "exercise/programming/java/all_successful/MergeSort.txt" - }, - { - "name": "SortStrategy.java", - "path": "exercise/programming/java/all_successful/SortStrategy.txt" - } - ], - "expectedResult": "46.2%", - "packageName": "de.test" -} diff --git a/src/test/cypress/fixtures/exercise/programming/java/static_code_analysis/BubbleSort.txt b/src/test/cypress/fixtures/exercise/programming/java/static_code_analysis/BubbleSort.txt deleted file mode 100644 index e5c69849b14c..000000000000 --- a/src/test/cypress/fixtures/exercise/programming/java/static_code_analysis/BubbleSort.txt +++ /dev/null @@ -1,28 +0,0 @@ -package de.test; - -import java.util.*; - -public class BubbleSort implements SortStrategy { - - public static String literal1 = "Header"; - private static final String LITERAL_TWO = "Literal2"; - - /** - * Sorts dates with BubbleSort. - * - * @param input the List of Dates to be sorted - */ - public void performSort(List input) { - - for (int i = input.size() - 1; i >= 0; i--) { - for (int j = 0; j < i; j++) { - if (input.get(j).compareTo(input.get(j + 1)) > 0) { - Date temp = input.get(j); - input.set(j, input.get(j + 1)); - input.set(j + 1, temp); - } - } - } - - } -} diff --git a/src/test/cypress/fixtures/exercise/programming/java/static_code_analysis/submission.json b/src/test/cypress/fixtures/exercise/programming/java/static_code_analysis/submission.json deleted file mode 100644 index 330ddd0f554d..000000000000 --- a/src/test/cypress/fixtures/exercise/programming/java/static_code_analysis/submission.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "deleteFiles": ["BubbleSort.java", "Client.java", "MergeSort.java"], - "createFilesInRootFolder": false, - "files": [ - { - "name": "BubbleSort.java", - "path": "exercise/programming/java/static_code_analysis/BubbleSort.txt" - }, - { - "name": "Context.java", - "path": "exercise/programming/java/all_successful/Context.txt" - }, - { - "name": "Client.java", - "path": "exercise/programming/java/all_successful/Client.txt" - }, - { - "name": "MergeSort.java", - "path": "exercise/programming/java/all_successful/MergeSort.txt" - }, - { - "name": "Policy.java", - "path": "exercise/programming/java/all_successful/Policy.txt" - }, - { - "name": "SortStrategy.java", - "path": "exercise/programming/java/all_successful/SortStrategy.txt" - } - ], - "expectedResult": "50%", - "packageName": "de.test" -} diff --git a/src/test/cypress/fixtures/exercise/programming/java/template.json b/src/test/cypress/fixtures/exercise/programming/java/template.json deleted file mode 100644 index b5a45c605e12..000000000000 --- a/src/test/cypress/fixtures/exercise/programming/java/template.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "allowOfflineIde": true, - "allowOnlineEditor": true, - "assessmentDueDateError": false, - "assessmentType": "AUTOMATIC", - "bonusPoints": 0, - "checkoutSolutionRepository": false, - "dueDateError": false, - "exampleSolutionPublicationDateError": false, - "exampleSolutionPublicationDateWarning": false, - "includedInOverallScore": "INCLUDED_COMPLETELY", - "isAtLeastEditor": false, - "isAtLeastInstructor": false, - "isAtLeastTutor": false, - "maxPoints": 10, - "mode": "INDIVIDUAL", - "noVersionControlAndContinuousIntegrationAvailable": false, - "packageName": "", - "presentationScoreEnabled": false, - "problemStatement": "# Sorting with the Strategy Pattern\n\nIn this exercise, we want to implement sorting algorithms and choose them based on runtime specific variables.\n\n### Part 1: Sorting\n\nFirst, we need to implement two sorting algorithms, in this case `MergeSort` and `BubbleSort`.\n\n**You have the following tasks:**\n\n1. [task][Implement Bubble Sort](testBubbleSort)\nImplement the method `performSort(List)` in the class `BubbleSort`. Make sure to follow the Bubble Sort algorithm exactly.\n\n2. [task][Implement Merge Sort](testMergeSort)\nImplement the method `performSort(List)` in the class `MergeSort`. Make sure to follow the Merge Sort algorithm exactly.\n\n### Part 2: Strategy Pattern\n\nWe want the application to apply different algorithms for sorting a `List` of `Date` objects.\nUse the strategy pattern to select the right sorting algorithm at runtime.\n\n**You have the following tasks:**\n\n1. [task][SortStrategy Interface](testClass[SortStrategy],testMethods[SortStrategy])\nCreate a `SortStrategy` interface and adjust the sorting algorithms so that they implement this interface.\n\n2. [task][Context Class](testAttributes[Context],testMethods[Context])\nCreate and implement a `Context` class following the below class diagram\n\n3. [task][Context Policy](testConstructors[Policy],testAttributes[Policy],testMethods[Policy])\nCreate and implement a `Policy` class following the below class diagram with a simple configuration mechanism:\n\n 1. [task][Select MergeSort](testClass[MergeSort],testUseMergeSortForBigList)\n Select `MergeSort` when the List has more than 10 dates.\n\n 2. [task][Select BubbleSort](testClass[BubbleSort],testUseBubbleSortForSmallList)\n Select `BubbleSort` when the List has less or equal 10 dates.\n\n4. Complete the `Client` class which demonstrates switching between two strategies at runtime.\n\n@startuml\n\nclass Client {\n}\n\nclass Policy {\n +configure()\n}\n\nclass Context {\n -dates: List\n +sort()\n}\n\ninterface SortStrategy {\n +performSort(List)\n}\n\nclass BubbleSort {\n +performSort(List)\n}\n\nclass MergeSort {\n +performSort(List)\n}\n\nMergeSort -up-|> SortStrategy #testsColor(testClass[MergeSort])\nBubbleSort -up-|> SortStrategy #testsColor(testClass[BubbleSort])\nPolicy -right-> Context #testsColor(testAttributes[Policy]): context\nContext -right-> SortStrategy #testsColor(testAttributes[Context]): sortAlgorithm\nClient .down.> Policy\nClient .down.> Context\n\nhide empty fields\nhide empty methods\n\n@enduml\n\n\n### Part 3: Optional Challenges\n\n(These are not tested)\n\n1. Create a new class `QuickSort` that implements `SortStrategy` and implement the Quick Sort algorithm.\n\n2. Make the method `performSort(List)` generic, so that other objects can also be sorted by the same method.\n**Hint:** Have a look at Java Generics and the interface `Comparable`.\n\n3. Think about a useful decision in `Policy` when to use the new `QuickSort` algorithm.\n", - "programmingLanguage": "JAVA", - "projectType": "PLAIN_MAVEN", - "secondCorrectionEnabled": false, - "shortName": "", - "showTestNamesToStudents": false, - "solutionParticipation": { - "type": "solution" - }, - "staticCodeAnalysisEnabled": false, - "studentAssignedTeamIdComputed": false, - "teamMode": false, - "templateParticipation": { - "type": "template" - }, - "title": "", - "type": "programming" -} diff --git a/src/test/cypress/fixtures/exercise/programming/python/all_successful/context.txt b/src/test/cypress/fixtures/exercise/programming/python/all_successful/context.txt deleted file mode 100644 index b57df9cfc106..000000000000 --- a/src/test/cypress/fixtures/exercise/programming/python/all_successful/context.txt +++ /dev/null @@ -1,6 +0,0 @@ -class Context: - sorting_algorithm = None - numbers = None - - def sort(self): - self.sorting_algorithm.perform_sort(self.numbers) diff --git a/src/test/cypress/fixtures/exercise/programming/python/all_successful/policy.txt b/src/test/cypress/fixtures/exercise/programming/python/all_successful/policy.txt deleted file mode 100644 index 72517c91096d..000000000000 --- a/src/test/cypress/fixtures/exercise/programming/python/all_successful/policy.txt +++ /dev/null @@ -1,16 +0,0 @@ -from .sorting_algorithms import * - - -class Policy: - context = None - - def __init__(self, context): - self.context = context - - def configure(self): - if len(self.context.numbers) > 10: - print('More than 10 numbers, choosing merge sort!') - self.context.sorting_algorithm = MergeSort() - else: - print('Less or equal than 10 numbers, choosing bubble sort!') - self.context.sorting_algorithm = BubbleSort() diff --git a/src/test/cypress/fixtures/exercise/programming/python/all_successful/sort_strategy.txt b/src/test/cypress/fixtures/exercise/programming/python/all_successful/sort_strategy.txt deleted file mode 100644 index a1f8b65ee6a1..000000000000 --- a/src/test/cypress/fixtures/exercise/programming/python/all_successful/sort_strategy.txt +++ /dev/null @@ -1,8 +0,0 @@ -from abc import ABC, abstractmethod - - -class SortStrategy(ABC): - - @abstractmethod - def perform_sort(self, array): - pass diff --git a/src/test/cypress/fixtures/exercise/programming/python/all_successful/sorting_algorithms.txt b/src/test/cypress/fixtures/exercise/programming/python/all_successful/sorting_algorithms.txt deleted file mode 100644 index a51fe1b136c6..000000000000 --- a/src/test/cypress/fixtures/exercise/programming/python/all_successful/sorting_algorithms.txt +++ /dev/null @@ -1,58 +0,0 @@ -from .sort_strategy import SortStrategy - - -class BubbleSort(SortStrategy): - - def perform_sort(self, arr): - if arr is None: - return - - for i in range(len(arr))[::-1]: - for j in range(i): - if arr[j] > arr[j + 1]: - arr[j], arr[j + 1] = arr[j + 1], arr[j] - - -class MergeSort(SortStrategy): - - def perform_sort(self, arr): - self.__merge_sort(arr, 0, len(arr) - 1) - - def __merge_sort(self, arr, low, high): - if high - low < 1: - return - - mid = int((low + high) / 2) - self.__merge_sort(arr, low, mid) - self.__merge_sort(arr, mid + 1, high) - self.__merge(arr, low, mid, high) - - def __merge(self, arr, low, mid, high): - temp = [None] * (high - low + 1) - - left_index = low - right_index = mid + 1 - whole_index = 0 - - while left_index <= mid and right_index <= high: - if arr[left_index] <= arr[right_index]: - temp[whole_index] = arr[left_index] - left_index += 1 - else: - temp[whole_index] = arr[right_index] - right_index += 1 - whole_index += 1 - - if left_index <= mid and right_index > high: - while left_index <= mid: - temp[whole_index] = arr[left_index] - whole_index += 1 - left_index += 1 - else: - while right_index <= high: - temp[whole_index] = arr[right_index] - whole_index += 1 - right_index += 1 - - for whole_index in range(len(temp)): - arr[whole_index + low] = temp[whole_index] diff --git a/src/test/cypress/fixtures/exercise/programming/python/all_successful/submission.json b/src/test/cypress/fixtures/exercise/programming/python/all_successful/submission.json deleted file mode 100644 index 258756288bb9..000000000000 --- a/src/test/cypress/fixtures/exercise/programming/python/all_successful/submission.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "deleteFiles": ["context.py", "policy.py", "sort_strategy.py", "sorting_algorithms.py"], - "createFilesInRootFolder": true, - "files": [ - { - "name": "context.py", - "path": "exercise/programming/python/all_successful/context.txt" - }, - { - "name": "policy.py", - "path": "exercise/programming/python/all_successful/policy.txt" - }, - { - "name": "sort_strategy.py", - "path": "exercise/programming/python/all_successful/sort_strategy.txt" - }, - { - "name": "sorting_algorithms.py", - "path": "exercise/programming/python/all_successful/sorting_algorithms.txt" - } - ], - "expectedResult": "100%" -} diff --git a/src/test/cypress/fixtures/exercise/programming/python/template.json b/src/test/cypress/fixtures/exercise/programming/python/template.json deleted file mode 100644 index cb0962ce3c00..000000000000 --- a/src/test/cypress/fixtures/exercise/programming/python/template.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "allowComplaintsForAutomaticAssessments": false, - "allowFeedbackRequests": false, - "allowOfflineIde": false, - "allowOnlineEditor": true, - "assessmentDueDateError": false, - "assessmentType": "AUTOMATIC", - "bonusPoints": 0, - "checkoutSolutionRepository": false, - "dueDateError": false, - "exampleSolutionPublicationDateError": false, - "exampleSolutionPublicationDateWarning": false, - "includedInOverallScore": "INCLUDED_COMPLETELY", - "isAtLeastEditor": false, - "isAtLeastInstructor": false, - "isAtLeastTutor": false, - "maxPoints": 10, - "mode": "INDIVIDUAL", - "noVersionControlAndContinuousIntegrationAvailable": false, - "packageName": "", - "presentationScoreEnabled": false, - "problemStatement": "# Sorting with the Strategy Pattern\n\nIn this exercise, we want to implement sorting algorithms and choose them based on runtime specific variables.\n\n### Part 1: Sorting\n\nFirst, we need to implement two sorting algorithms, in this case `MergeSort` and `BubbleSort`.\n\n**You have the following tasks:**\n\n1. [task][Implement Bubble Sort](test_bubble_sort)\nImplement the method `perform_sort(List)` in the class `BubbleSort`. Make sure to follow the Bubble Sort algorithm exactly.\n\n2. [task][Implement Merge Sort](test_merge_sort)\nImplement the method `perform_sort(List)` in the class `MergeSort`. Make sure to follow the Merge Sort algorithm exactly.\n\n### Part 2: Strategy Pattern\n\nWe want the application to apply different algorithms for sorting a `List` of `Int` objects.\nUse the strategy pattern to select the right sorting algorithm at runtime.\n\n**You have the following tasks:**\n\n1. [task][SortStrategy Interface](test_sort_strategy_class,test_sort_strategy_methods)\nCreate a `SortStrategy` abstract class with an abstract method and adjust the sorting algorithms so that they inherit from this class.\n\n2. [task][Context Class](test_context_attributes,test_context_methods)\nCreate and implement a `Context` class following the below class diagram\n\n3. [task][Context Policy](test_policy_constructor,test_policy_attributes,test_policy_methods)\nCreate and implement a `Policy` class following the below class diagram with a simple configuration mechanism:\n\n 1. [task][Select MergeSort](test_merge_sort_struct,test_merge_sort_for_big_list)\n Select `MergeSort` when the List has more than 10 dates.\n\n 2. [task][Select BubbleSort](test_bubble_sort_struct,test_bubble_sort_for_small_list)\n Select `BubbleSort` when the List has less or equal 10 dates.\n\n4. Complete the `Client` class which demonstrates switching between two strategies at runtime.\n\n@startuml\n\nclass Client {\n}\n\nclass Policy {\n +configure()\n}\n\nclass Context {\n numbers: List\n +sort()\n}\n\nabstract class SortStrategy {\n +perform_sort(List)\n}\n\nclass BubbleSort {\n +performSort(List)\n}\n\nclass MergeSort {\n +perform_sort(List)\n}\n\nMergeSort -up-|> SortStrategy #testsColor(test_merge_sort_class)\nBubbleSort -up-|> SortStrategy #testsColor(test_bubble_sort_class)\nPolicy -right-> Context #testsColor(test_policy_attributes): context\nContext -right-> SortStrategy #testsColor(test_context_attributes): sortAlgorithm\nClient .down.> Policy\nClient .down.> Context\n\nhide empty fields\nhide empty methods\n\n@enduml\n\n\n### Part 3: Optional Challenges\n\n(These are not tested)\n\n1. Create a new class `QuickSort` that inherits from `SortStrategy` and implement the Quick Sort algorithm.\n\n2. Think about a useful decision in `Policy` when to use the new `QuickSort` algorithm.\n", - "programmingLanguage": "PYTHON", - "secondCorrectionEnabled": false, - "shortName": "", - "showTestNamesToStudents": false, - "solutionParticipation": { - "type": "solution" - }, - "startDateError": false, - "staticCodeAnalysisEnabled": false, - "studentAssignedTeamIdComputed": false, - "teamMode": false, - "templateParticipation": { - "type": "template" - }, - "testwiseCoverageEnabled": false, - "title": "", - "type": "programming" -} diff --git a/src/test/cypress/fixtures/exercise/quiz/drag_and_drop/background.jpg b/src/test/cypress/fixtures/exercise/quiz/drag_and_drop/background.jpg deleted file mode 100644 index b7c357de728b47b155cd4835eccf42531d2f39e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9492 zcmeHK2~<;O7QWd?3Ir0_qJS&~3#DvjQ`t%>ATka^in1$VZwiP3iOT>MS~_i15E&_A z8w*8hBH)G?ISPz2P{Bb>Q3+6#0Xikcg{>MjnHNZeIWA4lv2%_y?|N|3H7hU;r@41+pQmRiLl$hCk7R{R98tH@ktQ0kW_ZfVA{17Cqoy)9{E$ zQ@KvL81b1IO8g9o#GSb&j}9QTea8N;sa{J+%#25j?jm;<3rUU?n}A^5ykgD7^tJCJG90;$ zAQR{i0PiCBrLK8CH&y~Hp9a7c&+FpK0UAF6po!*n76$>eKL$9}oxxx+W{bfizu2TC zfQcFaas+_RWdQXkWuf!F^UvZry_zCEMo6C=5)eIDjL#%KE?; z)QLnAQB9phB5A0rYiQ9ZT4b`8v7SDa_PU9sg}I5j*)kh9`(@V7)@J4oK90^S+`YWK zEbZP4^z~Tf=IP}w4}wwG(9j}l8Br)k?pEej?!S4-T7XKzUM2tzV-8p<21munF2G{s z?8=w2e?$`1@B|#PY%*&=jP zOd%=PZa}~uy3;P*Ao+9cqL7L(w&?_;<_l?j1ATfR<3!tEBByfovK!)-#clm|<}<5H z{HEfq`U?35CST{9n1*1NrB^H$H?UdS<_c+X)4^v|6Z0#kXXR=q=I!C7ehL}b5}Us# zyT{}E?eCQ)^$c`)a1?Uyj#h&CIPaM`)cyKGCqu>+#n~$4A8~kH&Z)zrRU(Tj*Sgz2 z!;uPkK#gQ=koNwifRlm#X)*l;9SZr~a!m@|PE@nMD5Yels7XNFqmU&TG*h&VSO01B z^qNe(c|Zn_WH1&YY?W$@A2)ZBJGtK8-X-98;7RH7)y;pTre8*@|C%I+J}YoosuhFs%Kh2D+k z`{{Lj5G&B@EXzCTJ$a8UgIX!BG=*2DO-x7{yqdc^M||N(%v5=1^4KoUGR00j=A!f3 zpic`jDnujp{F(lv*BdTw2pbo~HvVFL&U$QI+FT3;2VUZ+?CN%W)XuCH zpSi^jR-)AQ5*buJ%Fg+kclHPGn%+3^N2}J{VHf>06Mp60$J#Ku&k^DsT!_VLAy zpKoi*s~-l_A61B=s>uuA%glP^3DeoGY^=~Qms!t|l+WzI8y!?33*K2xc)1Uq9Tlj0 z+60{)bav3$d3r8X(fmKn&eHmOy`%6&K$Hxk9v9v5%Px}0AWwX6GJ9l@%jGmrU5#A# z?PyLoVbQ>dxGIz||O<_=?!20YrQJ`*uH{Bm$UP6wR>mkG zl$2%N5PRERl6!tXo9<|9{hzYC+q_%HSU`yU@+W@S#9&GCOf+RIsy8}-nva(Hn? zNnM6y#@DaI$xZJcChI#=1Zqh`g7e~DvVmz=f7tSz?Xy;&|EOJ`;2d4xv?==5^v{Ky z;-qw&172r~udp;PwPk*K{rD0)pYqeMRH(waPuUJLr)e&K*EXRHs@ALwt`Umw0w-FP iS08GFGJrCGGJrCGGJrCGGJrCGGJrDh>N9|m_5K^c1&yNs diff --git a/src/test/cypress/fixtures/exercise/quiz/drag_and_drop/question.txt b/src/test/cypress/fixtures/exercise/quiz/drag_and_drop/question.txt deleted file mode 100644 index 955e816cc5df..000000000000 --- a/src/test/cypress/fixtures/exercise/quiz/drag_and_drop/question.txt +++ /dev/null @@ -1,2 +0,0 @@ -Who is never going to give you up? - [hint] His first name is Rick diff --git a/src/test/cypress/fixtures/exercise/quiz/multiple_choice/question.txt b/src/test/cypress/fixtures/exercise/quiz/multiple_choice/question.txt deleted file mode 100644 index ee4700fa3a9b..000000000000 --- a/src/test/cypress/fixtures/exercise/quiz/multiple_choice/question.txt +++ /dev/null @@ -1,14 +0,0 @@ -A longer more detailed question -[hint] A general hint -[correct] Correct answer 1 -[hint] A hint -[exp] Explanation for why this is correct -[correct] Correct answer 2 -[hint] A hint -[exp] Explanation for why this is correct -[wrong] Wrong Answer 1 -[hint] A hint -[exp] Explanation for why this is wrong -[wrong] Wrong Answer 2 -[hint] A hint -[exp] Explanation for why this is wrong diff --git a/src/test/cypress/fixtures/exercise/quiz/multiple_choice/submission.json b/src/test/cypress/fixtures/exercise/quiz/multiple_choice/submission.json deleted file mode 100644 index 5515e12441a9..000000000000 --- a/src/test/cypress/fixtures/exercise/quiz/multiple_choice/submission.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "submissionExerciseType": "quiz", - "submitted": false, - "submittedAnswers": [ - { - "type": "multiple-choice", - "quizQuestion": null, - "selectedOptions": [] - } - ] -} diff --git a/src/test/cypress/fixtures/exercise/quiz/multiple_choice/template.json b/src/test/cypress/fixtures/exercise/quiz/multiple_choice/template.json deleted file mode 100644 index 288e2447996b..000000000000 --- a/src/test/cypress/fixtures/exercise/quiz/multiple_choice/template.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "type": "multiple-choice", - "randomizeOrder": false, - "invalid": false, - "exportQuiz": false, - "title": "", - "text": "A longer more detailed question", - "hint": "A general hint", - "scoringType": "PROPORTIONAL_WITHOUT_PENALTY", - "points": 10, - "answerOptions": [ - { - "isCorrect": true, - "invalid": false, - "text": "Correct answer 1", - "hint": "A hint", - "explanation": "Explanation for why this is correct" - }, - { - "isCorrect": true, - "invalid": false, - "text": "Correct answer 2", - "hint": "A hint", - "explanation": "Explanation for why this is correct" - }, - { - "isCorrect": false, - "invalid": false, - "text": "Wrong Answer 1", - "hint": "A hint", - "explanation": "Explanation for why this is wrong" - }, - { - "isCorrect": false, - "invalid": false, - "text": "Wrong Answer 2", - "hint": "A hint", - "explanation": "Explanation for why this is wrong" - } - ] -} diff --git a/src/test/cypress/fixtures/exercise/quiz/short_answer/question.txt b/src/test/cypress/fixtures/exercise/quiz/short_answer/question.txt deleted file mode 100644 index 2691efde042f..000000000000 --- a/src/test/cypress/fixtures/exercise/quiz/short_answer/question.txt +++ /dev/null @@ -1,14 +0,0 @@ -Never gonna [-spot 1] you up -Never gonna [-spot 2] you down -Never gonna [-spot 3] around and [-spot 4] you -Never gonna make you [-spot 5] -Never gonna say [-spot 6] -Never gonna tell a lie and hurt you - - -[-option 1] give -[-option 2] let -[-option 3] run -[-option 4] desert -[-option 5] cry -[-option 6] goodbye diff --git a/src/test/cypress/fixtures/exercise/quiz/short_answer/submission.json b/src/test/cypress/fixtures/exercise/quiz/short_answer/submission.json deleted file mode 100644 index dc62a419a4b8..000000000000 --- a/src/test/cypress/fixtures/exercise/quiz/short_answer/submission.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "submissionExerciseType": "quiz", - "submitted": false, - "submittedAnswers": [ - { - "type": "short-answer", - "quizQuestion": null, - "submittedTexts": [] - } - ] -} diff --git a/src/test/cypress/fixtures/exercise/quiz/short_answer/template.json b/src/test/cypress/fixtures/exercise/quiz/short_answer/template.json deleted file mode 100644 index adb85d9280df..000000000000 --- a/src/test/cypress/fixtures/exercise/quiz/short_answer/template.json +++ /dev/null @@ -1,168 +0,0 @@ -{ - "type": "short-answer", - "randomizeOrder": true, - "invalid": false, - "exportQuiz": false, - "matchLetterCase": false, - "similarityValue": 85, - "title": "Short Answer Quiz", - "text": "Never gonna [-spot 1] you up\nNever gonna [-spot 2] you down\nNever gonna [-spot 3] around and [-spot 4] you\nNever gonna make you [-spot 5]\nNever gonna say [-spot 6]\nNever gonna tell a lie and hurt you", - "scoringType": "PROPORTIONAL_WITHOUT_PENALTY", - "points": 1, - "spots": [ - { - "tempID": 8562027009747859, - "invalid": false, - "width": 15, - "spotNr": 1 - }, - { - "tempID": 1693282244205775, - "invalid": false, - "width": 15, - "spotNr": 2 - }, - { - "tempID": 2470277842944981, - "invalid": false, - "width": 15, - "spotNr": 3 - }, - { - "tempID": 1444701769469013, - "invalid": false, - "width": 15, - "spotNr": 4 - }, - { - "tempID": 3791222413897993, - "invalid": false, - "width": 15, - "spotNr": 5 - }, - { - "tempID": 1633040437192643, - "invalid": false, - "width": 15, - "spotNr": 6 - } - ], - "solutions": [ - { - "tempID": 7036040666954049, - "invalid": false, - "text": "give" - }, - { - "tempID": 94143448556475, - "invalid": false, - "text": "let" - }, - { - "tempID": 5696516478778027, - "invalid": false, - "text": "run" - }, - { - "tempID": 3116087876447447, - "invalid": false, - "text": "desert" - }, - { - "tempID": 8350692113124205, - "invalid": false, - "text": "cry" - }, - { - "tempID": 1934608439373183, - "invalid": false, - "text": "goodbye" - } - ], - "correctMappings": [ - { - "spot": { - "tempID": 8562027009747859, - "invalid": false, - "width": 15, - "spotNr": 1 - }, - "solution": { - "tempID": 7036040666954049, - "invalid": false, - "text": "give" - }, - "invalid": false - }, - { - "spot": { - "tempID": 1693282244205775, - "invalid": false, - "width": 15, - "spotNr": 2 - }, - "solution": { - "tempID": 94143448556475, - "invalid": false, - "text": "let" - }, - "invalid": false - }, - { - "spot": { - "tempID": 2470277842944981, - "invalid": false, - "width": 15, - "spotNr": 3 - }, - "solution": { - "tempID": 5696516478778027, - "invalid": false, - "text": "run" - }, - "invalid": false - }, - { - "spot": { - "tempID": 1444701769469013, - "invalid": false, - "width": 15, - "spotNr": 4 - }, - "solution": { - "tempID": 3116087876447447, - "invalid": false, - "text": "desert" - }, - "invalid": false - }, - { - "spot": { - "tempID": 3791222413897993, - "invalid": false, - "width": 15, - "spotNr": 5 - }, - "solution": { - "tempID": 8350692113124205, - "invalid": false, - "text": "cry" - }, - "invalid": false - }, - { - "spot": { - "tempID": 1633040437192643, - "invalid": false, - "width": 15, - "spotNr": 6 - }, - "solution": { - "tempID": 1934608439373183, - "invalid": false, - "text": "goodbye" - }, - "invalid": false - } - ] -} diff --git a/src/test/cypress/fixtures/exercise/quiz/template.json b/src/test/cypress/fixtures/exercise/quiz/template.json deleted file mode 100644 index b487d5d1c09a..000000000000 --- a/src/test/cypress/fixtures/exercise/quiz/template.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "mode": "INDIVIDUAL", - "includedInOverallScore": "INCLUDED_COMPLETELY", - "numberOfAssessmentsOfCorrectionRounds": [{ "inTime": 0, "late": 0, "total": 0 }], - "studentAssignedTeamIdComputed": false, - "secondCorrectionEnabled": false, - "type": "quiz", - "bonusPoints": 0, - "isAtLeastTutor": false, - "isAtLeastEditor": false, - "isAtLeastInstructor": false, - "teamMode": false, - "assessmentDueDateError": false, - "dueDateError": false, - "presentationScoreEnabled": false, - "randomizeQuestionOrder": true, - "releaseDate": null, - "isVisibleBeforeStart": false, - "isOpenForPractice": false, - "isPlannedToStart": false, - "isActiveQuiz": false, - "isPracticeModeAvailable": true, - "title": "", - "duration": 600, - "quizQuestions": [], - "quizMode": "SYNCHRONIZED" -} diff --git a/src/test/cypress/fixtures/exercise/text/submission.json b/src/test/cypress/fixtures/exercise/text/submission.json deleted file mode 100644 index 4e7acc5e5242..000000000000 --- a/src/test/cypress/fixtures/exercise/text/submission.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "text": "On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish." -} diff --git a/src/test/cypress/fixtures/exercise/text/template.json b/src/test/cypress/fixtures/exercise/text/template.json deleted file mode 100644 index 9a185cec3058..000000000000 --- a/src/test/cypress/fixtures/exercise/text/template.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "mode": "INDIVIDUAL", - "includedInOverallScore": "INCLUDED_COMPLETELY", - "numberOfAssessmentsOfCorrectionRounds": [ - { - "inTime": 0, - "late": 0 - } - ], - "studentAssignedTeamIdComputed": false, - "secondCorrectionEnabled": false, - "type": "text", - "bonusPoints": 0, - "isAtLeastTutor": false, - "isAtLeastEditor": false, - "isAtLeastInstructor": false, - "teamMode": false, - "assessmentDueDateError": false, - "dueDateError": false, - "exampleSolutionPublicationDateError": false, - "exampleSolutionPublicationDateWarning": false, - "presentationScoreEnabled": false, - "assessmentType": "MANUAL", - "title": "Text Exercise 1", - "maxPoints": 10, - "problemStatement": "Problem Statement", - "exampleSolution": "Example Solution", - "gradingInstructions": "Assessment Instructions" -} diff --git a/src/test/cypress/fixtures/lecture/template.json b/src/test/cypress/fixtures/lecture/template.json deleted file mode 100644 index 4c540b3d11f2..000000000000 --- a/src/test/cypress/fixtures/lecture/template.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "course": null, - "title": "Test lecture", - "channelName": "lecture-test-lecture", - "description": "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.", - "startDate": null, - "endDate": null -} diff --git a/src/test/cypress/fixtures/loremIpsum-short.txt b/src/test/cypress/fixtures/loremIpsum-short.txt deleted file mode 100644 index b9c7a9bd3d14..000000000000 --- a/src/test/cypress/fixtures/loremIpsum-short.txt +++ /dev/null @@ -1 +0,0 @@ -At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren. \ No newline at end of file diff --git a/src/test/cypress/fixtures/loremIpsum.txt b/src/test/cypress/fixtures/loremIpsum.txt deleted file mode 100644 index b45a9d5eccd8..000000000000 --- a/src/test/cypress/fixtures/loremIpsum.txt +++ /dev/null @@ -1 +0,0 @@ -Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. \ No newline at end of file diff --git a/src/test/cypress/fixtures/pdf-test-file.pdf b/src/test/cypress/fixtures/pdf-test-file.pdf deleted file mode 100644 index e60c959ec0ba7b5b03798ceece2bc508eb9870bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10855 zcmeHNc|4SD_eWAlN>Wrz%D&7#V{F+)jfAX8V`ea!g_*Gvr6l{FlBXz&O2`tjltfuV z3sQCp71>&-e)o*@P~PABKJVxKEq^?>&$zES*E#1p=Un&P*Y}+3k}}mZP=YF>1^A>2 zflGi73W9)Wjz_M*wt!;3&2(OA^tGNH?Vu zorrWI6%UL7N3%LKH3j&HR07);mdYhYv5f)i(mbe45DdJBL}1u~;4CQ+hV|bbv{;(e z@tZW@4=@}c&Ef}}5g9ZOIxsk3t^tk8WZj@3B&!cFS>Ky!XwJkji2&Kq91UXI2eec` zDnB?(=`_4Kk!c48!U?t@dNaXB6d+zY^Eci3n-R+_z<&Y>r$h6$14JPpBnGJrhk;ZO zP-P6v9t5~VWddd~KnRv*upyo1;RcM#o(c9BusPU*j-xW%Smxt>z`EvOJ)$QGPc$>s z0km7-92o%1{G80Y$N)hWM}wt!AsPlGGLuLL8;}9t^oV#Gfe7A9q&hQQKrrB9Nimpo zB90=!=Y781wmUk-VBOJO!{1H?6kPLO;e8i$AU5uxZK3fs%QM-62PAIe`^jNW2#H#Z!Z}6SKjvuzU=7HnBgjG@uKsCYxo}-zYqJW z-4$IN=H%KmX`7s)T3CVNex98Wna)H7+CNQw0I4U5JGK{KEA5=ZA14d8B9u#sIb>3X zN0uK=y@>WMJlud9aQ{X&Ey?||vebiBhPMdzT@USt6}e8=ypnsYu~q!!J`UNUTxQmJ zi*Ui*7q5@i4h73a%JJj+?0ph=G@&;yZ?zVcV z7>8?L4~~&ŸfEJas|8<@7=eyTR+XWi$bV{Idg{vxu?v@i($$#w2>3BLB_&P6@T3}R+Q^qnQ_KR}yiN`85 zaSJ(D^=98Lly1&V`i4HX%Hn(1A&BI7Me3%Sh!%w2e$3S2>sv%eR<_9$ z*X~iRrq?dap<8O+wYh5Ni}K#)%^s0$xeH%qcuX?_pHzwPCJ8@jlzTfg774_gPolxz zv>YvV;FFY6{klHXD@AJt*XIqY205H;_r#V-aQz!0i+r!+TFQv@1yUM37* zQg!TV)^RMnN5HgPJil);+Nu>LRY#9%w|$L?e0~L@ik~U?!)xY#>xrD|N4_CAvQu?j zgoyj$c7alxH9D8yeqAFLC6}v}r6qQRBlMxkRC2+kY>GTTwLF;rTy}qIuIRg_KDe*< zgNj{ZP%8Gr^>y{f@}KTaGhSWDAs(<*Ci>q5Vl-X&t#y8qdhNr1cFv{gDr5Hj$s=5nMylV+e4^ zmAfa$jSed}TkG{t7Z?i(1aUFsw!Hfqv^hqMs5h={d7;B3;hUSw#o1?TB-%R9d=K92 zXvF8(&n@ii62&~!n3v?7-?wK?y)xcflXxJmU(tp9j8c-IU3L=_E3`7f@T9qk=xPBJ zkHctrnvzjM&|{N!I*(3@kNug;D)JwAtd!& zzzfdvN}`m(0xQ|@Sn{gtKKMI>hq_0xp10hx-EHoW{{qgBoK0L{B20>ECjFL9?>iEdS&V-X%E_z_*%y) zFRs9XH`A)UiUPjd(tXc2jJorrW(+fusf_D~#R^q)KcApPrD{Z~ZhK2l9%c^V<}oa7XE6l$YSQgh#OBTR!{VI7PgdS-t^vGEccb!uaZH zSNT0TH@;lvjHYg(ISm@pc66QgHHj5AbhSOPSuRUtmZip5D3`%hZGD60pKBy6$20)4q!|o#S)Nav+J-Ctr8#&VvPlY zK_C#;FiVj*3pg+F@F%hc>tMkqG&%)G2IFxc=wiUi!r1>*NLPEQ5GxH>BE-rV{=Z{> zAa4IT(7z;xY|RVt_{XRpia@}ZqW(e~EUi;zUHO*rz@8S{oe@&|lemRfwqCY-E2*Iv z=O|bs{wCC;Lp4s<=G9R58Qn15fOe9tHD+hJUTk$OdQ4y=-My?|%4d3{@9Q&%HiD0P zb-jR1=)_z#W&8`$hY_GJ{`!`b{k?rj8QX2*cJ6c88XIvE5gjTt*-;r7L)Y|UpfA|Z ziN?jWNbT^tFa&>7zH__Lj?#$DM)4aPCFvh8&X$*9A7(z+jgKS|DWk9a4VrKjiAQ_i zf9p?A8130b|M<~=#xnZ*V}H-%-V;(-8?g9>kh5R=`{2Ay{U==rG2oFPCGq2oqN{wb zV1hH_dy-0hXgNLF<|AdX0bOrq4plmd*&UMGe%x)Cw((h!S!py#+p%^iB~EwKWHN0K zk3T2)ULeg+fjT7hr3-!gYLTaSKuQ1muyg44zTn6WVpl?%D8%#TsF3%8!K;I$DFaeL zq5Qq8C11w9t7Z(H$#8IK%NhHll+7#Z^W4V>(HhTQm=dFNUrgH}E(Y7k ztjTNB_5P-HY8(A^89u7#expUAAv~t z%zg`tsqjDfgj#joc{h~{#`v}FJ9`;}t8E*K{fcN7| zxy{;A2&)Tex;C!ETneGwIz{So_r>z z8TC*)KJ|dm6aTGojbCoK4QQPdJ_ITis!9z`o!(n#Za^)RAZ}|7YF&ZVi?$dViKkEx z?|m36pOHkQet~qJv@_z4j4$NRozX<6u9K3BjMn~m+&@~T>7(o=-r3Zu_WQ?_@M4jP zv-u7ss}F3Kk-us3BK6LxS85`toE2k6apNWTMI6q(u+fM*h}g($X`3}Aa2WS4WF~&~ zdsT%z>cPAEudWu)ns_-~>M*Y3#HTyhn@X2D=5w3mpUC{Y`U&=y$dOBWq9@Y!7@Lb0 z@>+bfa=G_ygkC3->Q~J5_Ho|TSAK7|^;y%;4hihN%x&pOe|_#G+&GWE~cL2(O1kIs2S2eYj$e+xh$X8~JbKzmJ`n3fVL$hkb(I zQ&4s~${sJL>{WQFND-Z!*p>a%#xK2UWxH)zOsfC+Bb9OM_Ilh-&X-SFmHJ|z>=rYO ziPcJX#hNcpXxRf1JP*_5Ze(C|(DwQr6Ug>6LPNKk*Qc!As9K8-z^~9{I0TJ8f1*{C zd0Z}vq#9x*+kgE{o9BuTbI&@fx?<_h9rv>8PuDBM4255wzJF8RyHn+AkK6T}1|H#} znC4mJd6N9z>Wz_thaX{8R=w5vUi!}Rd8n1^7K2Gs>U2$&=1Ypgr~y>pCnRxwOv{y= zT#G$(F_sjQbwThRckI43c>3CnARMZrb4wN;@rMb6-UH74%HRpW2+crs)qu zowxPs+p0sHR&$`+pU)xbeOB)GIaW3GDvYl$7TdKMT;N(*(h@(BH3Q}+(LtDtDqQu= zY6JXn_0)6UErf5o|4}>iFja7NZ_G>G7b9)s1-(=E9-%D*O1It@+!~Z-5ghIN%9ttt z(lWx}!@d)~S0#EpljHWCYV>~NWqLN!Q0Ob%$2C~{d*|S$avuRp->Wq*1nr`}AAc$k z_SU33i^ECbTqLKah5Rk|uYYVt-MwO+e(lZF*?3N&V)gXwfJAYXF|C5UtzP5f?wAS6 zx%61#&}~m{R9*j(((*9+qX+S&s)SQDHdodS``=I@TPyuxzeCiY5xD>BHyvE@m6X@| z<$*hs`RYx-Z{we6)(zpI`%Xrff4Wc=>$W!Fk58Pj)#>k+g*wp1RXlAErVEWOYe1#} zK!yr31PVta22i)t1u8oLUXlIwode53;=pszIcOXV;N!%>fgK1~W9LOttT}+!Sp@i|rA;CbaV+ z_a%;vvZsSqKXTFXC2;PJhEAiQPn=1 zXm;JFPszmCt-H3uC90&N;?5_Y^ojKihD=SffgREkd7pQmjaHn9m6te6t$bAZbu0Je z`qXG)2T7IfXq?x3e~C(eDQYhg{XtfqSGvV0Y^U^TEX+N8XMfYnnoBzm${dXTB$8R` zge3EfwQbkSTYDprNqgCO@WUek3#FU%Gq+Ch7s@q~J%+pcgTHf}H|yS?qp1f@Qhzx! zyAQ9M_PE#n>CsI!GC=?3=v!F4n@Qh;rP!~9mNLB{$qvr?TJpVjxfp77hCByyzaC@Q6vgKzR z7zZfjf{;Kz>#hQa|Lj}ffwO3={slQUbf1@D(SeUW=+88TUAJGrlI)aep``yanX<<2 zT__~OA($nFWc6L%ZaBOvkqL4nI+Lgxl4E6+k{}X6L(&R~g<#!ui7uqwzI39wuZacT z*A?~W6obKlAuuourUY;(F?^^@oVOB{ zv138QLJ9`F+(0aiI7gZXQ$tb`^h2-PBE3|GGTSg^JdFYdI>1n6IGCjfXsa%~*)*{v zJe|g%IWh0$fUIbA0?4WQ4juH93T%xa)mhSiN~nWbBQLV#hj)u8%i2c3|8&{SgHC2U zOu&PQWFm#N%>bAOWt&I9tK#R^15I|+%!%&v4Khh{>B=#02|%82uo=ON#s5u9feHR; z>XImW8X|k3oC5Va=6k-8Is6sKS?Da|& z0#OJ5!pW8dRxpy2&%YwMi1Xi_KfnMi_P>t{g|ZMDELK&IhWB92tdX9khX;wE3Pm7Q zkh*Au5(fPllynHEs|Zv zdC>pD#rMB32I%iW{!*0x4%gq|`b!b`OU!>iU4Mt`FGb)lG5`H^{k3q-FZ%%g2B6|k z0I&IH0sw5xXh?bi@P7I1Yw>1*9*N;b#`yr~#)8BIHaX_c5-rL}e%mClHX}NL%}KsQ z5L^XpWe0)+Cu&#+Z064>0eO}gm~}h}#LmEgww|3j8iCYBsz4DKBnqPf03;SrT8xu4 z|2YRRz(1}XKw-bs4vaiv{~zfz#Pi1zVK@x zUyK$XJh_@HDdsL8ySJF~DBfQa%_k3BS_dP!%9) zUdjiDv9k1EX)3>s0Y@T%+RsuxB!rdJFQq{sQ1~+bB9@^cm!YASp`n+dsVqao{7!=b zC4ygL4}&g4TV{@6%lH9X#t+yse!!OT1GbDG!2JGh-!gu{m+=F>j32;BxZm^v#fjf( z%lH92jlb|AG0@+hArw%J{B_PTa5PX-S^6Ac5YR<@OgfH4Ceqo5BIn;JnE&w?$$Xg+ zM`zCeC^2XR3^=4IrN7SrIF0w?cM1{U`@b*^44l^V1hFgvvtF}60TslG*Dn@BAt { - if (Cypress.env('createUsers')) { - before('Creates all required users', () => { - cy.login(admin); - for (const userKey in USER_ID) { - const user = users.getUserWithId(USER_ID[userKey]); - userManagementAPIRequest.getUser(user.username).then((response) => { - if (!response.isOkStatusCode) { - userManagementAPIRequest.createUser(user.username, user.password, USER_ROLE[userKey]); - } - }); - } - }); - } - - it('Logs in once with all required users', () => { - // If Artemis hasn't imported the required users from Jira we have to force this by logging in with these users once - cy.login(admin); - cy.login(instructor); - cy.login(tutor); - cy.login(studentOne); - cy.login(studentTwo); - cy.login(studentThree); - cy.login(studentFour); - }); -}); diff --git a/src/test/cypress/package-lock.json b/src/test/cypress/package-lock.json deleted file mode 100644 index 1b660ab0208e..000000000000 --- a/src/test/cypress/package-lock.json +++ /dev/null @@ -1,3222 +0,0 @@ -{ - "name": "artemis_cypress", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "artemis_cypress", - "license": "MIT", - "devDependencies": { - "@4tw/cypress-drag-drop": "2.2.5", - "@types/node": "20.9.1", - "cypress": "12.17.4", - "cypress-cloud": "2.0.0-beta.1", - "cypress-file-upload": "5.0.8", - "cypress-pipe": "2.0.0", - "cypress-wait-until": "2.0.1", - "typescript": "5.2.2", - "uuid": "9.0.1", - "wait-on": "7.2.0" - } - }, - "node_modules/@4tw/cypress-drag-drop": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/@4tw/cypress-drag-drop/-/cypress-drag-drop-2.2.5.tgz", - "integrity": "sha512-3ghTmzhOmUqeN6U3QmUnKRUxI7OMLbJA4hHUY/eS/FhWJgxbiGgcaELbolWnBAOpajPXcsNQGYEj9brd59WH6A==", - "dev": true, - "peerDependencies": { - "cypress": "2 - 13" - } - }, - "node_modules/@babel/runtime": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.15.tgz", - "integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==", - "dev": true, - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@cypress/commit-info": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@cypress/commit-info/-/commit-info-2.2.0.tgz", - "integrity": "sha512-A7CYS0Iqp/u52JTnSWlDFjWMKx7rIfd+mk0Fdksrcs4Wdf5HXPsoZO475VJ+xL7LPhJrjKhgyl/TPKO3worZyQ==", - "dev": true, - "dependencies": { - "bluebird": "3.5.5", - "check-more-types": "2.24.0", - "debug": "4.1.1", - "execa": "1.0.0", - "lazy-ass": "1.6.0", - "ramda": "0.26.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@cypress/commit-info/node_modules/bluebird": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", - "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==", - "dev": true - }, - "node_modules/@cypress/commit-info/node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "engines": { - "node": ">=4.8" - } - }, - "node_modules/@cypress/commit-info/node_modules/execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "dependencies": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@cypress/commit-info/node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@cypress/commit-info/node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@cypress/commit-info/node_modules/npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", - "dev": true, - "dependencies": { - "path-key": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@cypress/commit-info/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@cypress/commit-info/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "dev": true, - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@cypress/commit-info/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@cypress/commit-info/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/@cypress/request": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.1.tgz", - "integrity": "sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==", - "dev": true, - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "http-signature": "~1.3.6", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "performance-now": "^2.1.0", - "qs": "6.10.4", - "safe-buffer": "^5.1.2", - "tough-cookie": "^4.1.3", - "tunnel-agent": "^0.6.0", - "uuid": "^8.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@cypress/request/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/@cypress/xvfb": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", - "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==", - "dev": true, - "dependencies": { - "debug": "^3.1.0", - "lodash.once": "^4.1.1" - } - }, - "node_modules/@hapi/hoek": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", - "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", - "dev": true - }, - "node_modules/@hapi/topo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", - "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", - "dev": true, - "dependencies": { - "@hapi/hoek": "^9.0.0" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@sideway/address": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", - "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", - "dev": true, - "dependencies": { - "@hapi/hoek": "^9.0.0" - } - }, - "node_modules/@sideway/formula": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", - "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", - "dev": true - }, - "node_modules/@sideway/pinpoint": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", - "dev": true - }, - "node_modules/@types/node": { - "version": "20.9.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.1.tgz", - "integrity": "sha512-HhmzZh5LSJNS5O8jQKpJ/3ZcrrlG6L70hpGqMIAoM9YVD0YBRNWYsfwcXq8VnSjlNpCpgLzMXdiPo+dxcvSmiA==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/sinonjs__fake-timers": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", - "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==", - "dev": true - }, - "node_modules/@types/sizzle": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", - "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==", - "dev": true - }, - "node_modules/@types/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", - "dev": true, - "optional": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/arch": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/async": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", - "dev": true - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", - "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", - "dev": true - }, - "node_modules/axios": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", - "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", - "dev": true, - "dependencies": { - "follow-redirects": "^1.15.0", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/axios-retry": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-3.7.0.tgz", - "integrity": "sha512-ZTnCkJbRtfScvwiRnoVskFAfvU0UG3xNcsjwTR0mawSbIJoothxn67gKsMaNAFHRXJ1RmuLhmZBzvyXi3+9WyQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.15.4", - "is-retry-allowed": "^2.2.0" - } - }, - "node_modules/axios/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/axios/node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/blob-util": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", - "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==", - "dev": true - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/cachedir": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.4.0.tgz", - "integrity": "sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/check-more-types": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", - "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-table3": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", - "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0" - }, - "engines": { - "node": "10.* || >= 12.*" - }, - "optionalDependencies": { - "@colors/colors": "1.5.0" - } - }, - "node_modules/cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", - "dev": true, - "dependencies": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/common-path-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", - "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", - "dev": true - }, - "node_modules/common-tags": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", - "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cy2": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/cy2/-/cy2-3.4.3.tgz", - "integrity": "sha512-I1yfJWJTRy2ROti1TlLM5Qk86WSeKMrtZbY/G6VD2tjm3VKTu6pDkpcV56C2HhN+txK5p6MMsmzKXJM2W9JlxA==", - "dev": true, - "dependencies": { - "acorn": "^8.8.0", - "debug": "^4.3.2", - "escodegen": "^2.0.0", - "estraverse": "^5.3.0", - "js-yaml": "^4.1.0", - "npm-which": "^3.0.1", - "slash": "3.0.0" - }, - "bin": { - "cy2": "bin/cy2" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/cypress": { - "version": "12.17.4", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-12.17.4.tgz", - "integrity": "sha512-gAN8Pmns9MA5eCDFSDJXWKUpaL3IDd89N9TtIupjYnzLSmlpVr+ZR+vb4U/qaMp+lB6tBvAmt7504c3Z4RU5KQ==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "@cypress/request": "2.88.12", - "@cypress/xvfb": "^1.2.4", - "@types/node": "^16.18.39", - "@types/sinonjs__fake-timers": "8.1.1", - "@types/sizzle": "^2.3.2", - "arch": "^2.2.0", - "blob-util": "^2.0.2", - "bluebird": "^3.7.2", - "buffer": "^5.6.0", - "cachedir": "^2.3.0", - "chalk": "^4.1.0", - "check-more-types": "^2.24.0", - "cli-cursor": "^3.1.0", - "cli-table3": "~0.6.1", - "commander": "^6.2.1", - "common-tags": "^1.8.0", - "dayjs": "^1.10.4", - "debug": "^4.3.4", - "enquirer": "^2.3.6", - "eventemitter2": "6.4.7", - "execa": "4.1.0", - "executable": "^4.1.1", - "extract-zip": "2.0.1", - "figures": "^3.2.0", - "fs-extra": "^9.1.0", - "getos": "^3.2.1", - "is-ci": "^3.0.0", - "is-installed-globally": "~0.4.0", - "lazy-ass": "^1.6.0", - "listr2": "^3.8.3", - "lodash": "^4.17.21", - "log-symbols": "^4.0.0", - "minimist": "^1.2.8", - "ospath": "^1.2.2", - "pretty-bytes": "^5.6.0", - "process": "^0.11.10", - "proxy-from-env": "1.0.0", - "request-progress": "^3.0.0", - "semver": "^7.5.3", - "supports-color": "^8.1.1", - "tmp": "~0.2.1", - "untildify": "^4.0.0", - "yauzl": "^2.10.0" - }, - "bin": { - "cypress": "bin/cypress" - }, - "engines": { - "node": "^14.0.0 || ^16.0.0 || >=18.0.0" - } - }, - "node_modules/cypress-cloud": { - "version": "2.0.0-beta.1", - "resolved": "https://registry.npmjs.org/cypress-cloud/-/cypress-cloud-2.0.0-beta.1.tgz", - "integrity": "sha512-nMKf7077NaOK4AFHUwYGAnL3HtgTWsyQ+dSB4YxSH0GvQbtJo7Ljk0dlkzkUraiPb+0/Rr+XF0ozorSPz7ChJw==", - "dev": true, - "dependencies": { - "@cypress/commit-info": "^2.2.0", - "axios": "^1.2.0", - "axios-retry": "^3.4.0", - "bluebird": "^3.7.2", - "chalk": "^4.1.2", - "commander": "^10.0.0", - "common-path-prefix": "^3.0.0", - "cy2": "^3.4.2", - "date-fns": "^2.30.0", - "debug": "^4.3.4", - "execa": "^5.1.1", - "fast-safe-stringify": "^2.1.1", - "getos": "^3.2.1", - "globby": "^11.1.0", - "is-absolute": "^1.0.0", - "lil-http-terminator": "^1.2.3", - "lodash": "^4.17.21", - "nanoid": "^3.3.4", - "plur": "^4.0.0", - "pretty-ms": "^7.0.1", - "source-map-support": "^0.5.21", - "table": "^6.8.1", - "tmp-promise": "^3.0.3", - "ts-pattern": "^4.3.0", - "ws": "^8.13.0" - }, - "bin": { - "cypress-cloud": "bin/cli.js" - }, - "engines": { - "node": ">=14.7.0" - } - }, - "node_modules/cypress-cloud/node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", - "dev": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/cypress-cloud/node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/cypress-cloud/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cypress-cloud/node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/cypress-file-upload": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/cypress-file-upload/-/cypress-file-upload-5.0.8.tgz", - "integrity": "sha512-+8VzNabRk3zG6x8f8BWArF/xA/W0VK4IZNx3MV0jFWrJS/qKn8eHfa5nU73P9fOQAgwHFJx7zjg4lwOnljMO8g==", - "dev": true, - "engines": { - "node": ">=8.2.1" - }, - "peerDependencies": { - "cypress": ">3.0.0" - } - }, - "node_modules/cypress-pipe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cypress-pipe/-/cypress-pipe-2.0.0.tgz", - "integrity": "sha512-KW9s+bz4tFLucH3rBGfjW+Q12n7S4QpUSSyxiGrgPOfoHlbYWzAGB3H26MO0VTojqf9NVvfd5Kt0MH5XMgbfyg==", - "dev": true - }, - "node_modules/cypress-wait-until": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/cypress-wait-until/-/cypress-wait-until-2.0.1.tgz", - "integrity": "sha512-+IyVnYNiaX1+C+V/LazrJWAi/CqiwfNoRSrFviECQEyolW1gDRy765PZosL2alSSGK8V10Y7BGfOQyZUDgmnjQ==", - "dev": true - }, - "node_modules/cypress/node_modules/@types/node": { - "version": "16.18.54", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.54.tgz", - "integrity": "sha512-oTmGy68gxZZ21FhTJVVvZBYpQHEBZxHKTsGshobMqm9qWpbqdZsA5jvsuPZcHu0KwpmLrOHWPdEfg7XDpNT9UA==", - "dev": true - }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/date-fns": { - "version": "2.30.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", - "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.21.0" - }, - "engines": { - "node": ">=0.11" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/date-fns" - } - }, - "node_modules/dayjs": { - "version": "1.11.9", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.9.tgz", - "integrity": "sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==", - "dev": true - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dev": true, - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enquirer": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", - "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/escodegen": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", - "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", - "dev": true, - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eventemitter2": { - "version": "6.4.7", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz", - "integrity": "sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==", - "dev": true - }, - "node_modules/execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/executable": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", - "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", - "dev": true, - "dependencies": { - "pify": "^2.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "node_modules/extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "dev": true, - "engines": [ - "node >=0.6.0" - ] - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, - "dependencies": { - "pend": "~1.2.0" - } - }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/getos": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", - "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==", - "dev": true, - "dependencies": { - "async": "^3.2.0" - } - }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/global-dirs": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", - "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", - "dev": true, - "dependencies": { - "ini": "2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/http-signature": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", - "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^2.0.2", - "sshpk": "^1.14.1" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "dev": true, - "engines": { - "node": ">=8.12.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/irregular-plurals": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.5.0.tgz", - "integrity": "sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-absolute": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", - "dev": true, - "dependencies": { - "is-relative": "^1.0.0", - "is-windows": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-ci": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", - "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", - "dev": true, - "dependencies": { - "ci-info": "^3.2.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", - "dev": true, - "dependencies": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-relative": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", - "dev": true, - "dependencies": { - "is-unc-path": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-retry-allowed": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz", - "integrity": "sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "node_modules/is-unc-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", - "dev": true, - "dependencies": { - "unc-path-regex": "^0.1.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true - }, - "node_modules/joi": { - "version": "17.11.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.11.0.tgz", - "integrity": "sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==", - "dev": true, - "dependencies": { - "@hapi/hoek": "^9.0.0", - "@hapi/topo": "^5.0.0", - "@sideway/address": "^4.1.3", - "@sideway/formula": "^3.0.1", - "@sideway/pinpoint": "^2.0.0" - } - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true - }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsprim": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", - "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } - }, - "node_modules/lazy-ass": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", - "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==", - "dev": true, - "engines": { - "node": "> 0.8" - } - }, - "node_modules/lil-http-terminator": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/lil-http-terminator/-/lil-http-terminator-1.2.3.tgz", - "integrity": "sha512-vQcHSwAFq/kTR2cG6peOVS7SjgksGgSPeH0G2lkw+buue33thE/FCHdn10wJXXshc5RswFy0Iaz48qA2Busw5Q==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/listr2": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", - "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", - "dev": true, - "dependencies": { - "cli-truncate": "^2.1.0", - "colorette": "^2.0.16", - "log-update": "^4.0.0", - "p-map": "^4.0.0", - "rfdc": "^1.3.0", - "rxjs": "^7.5.1", - "through": "^2.3.8", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "enquirer": ">= 2.3.0 < 3" - }, - "peerDependenciesMeta": { - "enquirer": { - "optional": true - } - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", - "dev": true - }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "dev": true - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", - "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.3.0", - "cli-cursor": "^3.1.0", - "slice-ansi": "^4.0.0", - "wrap-ansi": "^6.2.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/log-update/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "node_modules/npm-path": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/npm-path/-/npm-path-2.0.4.tgz", - "integrity": "sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw==", - "dev": true, - "dependencies": { - "which": "^1.2.10" - }, - "bin": { - "npm-path": "bin/npm-path" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/npm-path/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm-which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-which/-/npm-which-3.0.1.tgz", - "integrity": "sha512-CM8vMpeFQ7MAPin0U3wzDhSGV0hMHNwHU0wjo402IVizPDrs45jSfSuoC+wThevY88LQti8VvaAnqYAeVy3I1A==", - "dev": true, - "dependencies": { - "commander": "^2.9.0", - "npm-path": "^2.0.2", - "which": "^1.2.10" - }, - "bin": { - "npm-which": "bin/npm-which.js" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/npm-which/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/npm-which/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ospath": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", - "integrity": "sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==", - "dev": true - }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse-ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", - "integrity": "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true - }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/plur": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/plur/-/plur-4.0.0.tgz", - "integrity": "sha512-4UGewrYgqDFw9vV6zNV+ADmPAUAfJPKtGvb/VdpQAx25X5f3xXdGdyOEVFwkl8Hl/tl7+xbeHqSEM+D5/TirUg==", - "dev": true, - "dependencies": { - "irregular-plurals": "^3.2.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pretty-ms": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.1.tgz", - "integrity": "sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==", - "dev": true, - "dependencies": { - "parse-ms": "^2.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "dev": true, - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/proxy-from-env": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", - "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==", - "dev": true - }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.10.4", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz", - "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ramda": { - "version": "0.26.1", - "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz", - "integrity": "sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==", - "dev": true - }, - "node_modules/regenerator-runtime": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", - "dev": true - }, - "node_modules/request-progress": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", - "integrity": "sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==", - "dev": true, - "dependencies": { - "throttleit": "^1.0.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true - }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rfdc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", - "dev": true - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", - "dev": true, - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/table": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", - "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", - "dev": true, - "dependencies": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/throttleit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", - "integrity": "sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g==", - "dev": true - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, - "dependencies": { - "rimraf": "^3.0.0" - }, - "engines": { - "node": ">=8.17.0" - } - }, - "node_modules/tmp-promise": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", - "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", - "dev": true, - "dependencies": { - "tmp": "^0.2.0" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tough-cookie": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", - "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", - "dev": true, - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tough-cookie/node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/ts-pattern": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ts-pattern/-/ts-pattern-4.3.0.tgz", - "integrity": "sha512-pefrkcd4lmIVR0LA49Imjf9DYLK8vtWhqBPA3Ya1ir8xCW0O2yjL9dsCVvI7pCodLC5q7smNpEtDR2yVulQxOg==", - "dev": true - }, - "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/unc-path-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", - "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "dev": true, - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/wait-on": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.2.0.tgz", - "integrity": "sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ==", - "dev": true, - "dependencies": { - "axios": "^1.6.1", - "joi": "^17.11.0", - "lodash": "^4.17.21", - "minimist": "^1.2.8", - "rxjs": "^7.8.1" - }, - "bin": { - "wait-on": "bin/wait-on" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/ws": { - "version": "8.14.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.1.tgz", - "integrity": "sha512-4OOseMUq8AzRBI/7SLMUwO+FEDnguetSk7KMb1sHwvF2w2Wv5Hoj0nlifx8vtGsftE/jWHojPy8sMMzYLJ2G/A==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - } - } -} diff --git a/src/test/cypress/package.json b/src/test/cypress/package.json deleted file mode 100644 index 88a277ab0820..000000000000 --- a/src/test/cypress/package.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "artemis_cypress", - "description": "Cypress tests for Artemis", - "private": true, - "license": "MIT", - "cacheDirectories": [ - "node_modules" - ], - "devDependencies": { - "@4tw/cypress-drag-drop": "2.2.5", - "@types/node": "20.9.1", - "cypress": "12.17.4", - "cypress-cloud": "2.0.0-beta.1", - "cypress-file-upload": "5.0.8", - "cypress-wait-until": "2.0.1", - "cypress-pipe": "2.0.0", - "typescript": "5.2.2", - "uuid": "9.0.1", - "wait-on": "7.2.0" - }, - "overrides": { - "semver": "7.5.3", - "word-wrap": "1.2.3", - "debug": "4.3.4", - "tough-cookie": "4.1.3", - "@cypress/request": "3.0.1" - }, - "scripts": { - "cypress:open": "cypress open", - "cypress:run": "cypress run --browser=chrome", - "cypress:setup": "cypress install && cypress run --quiet --spec init/ImportUsers.cy.ts", - "cypress:record:mysql": "npx cypress-cloud run --parallel --record --ci-build-id \"${SORRY_CYPRESS_BRANCH_NAME} #${SORRY_CYPRESS_BUILD_ID} ${SORRY_CYPRESS_RERUN_COUNT} (MySQL)\"", - "cypress:record:postgres": "npx cypress-cloud run --parallel --record --ci-build-id \"${SORRY_CYPRESS_BRANCH_NAME} #${SORRY_CYPRESS_BUILD_ID} ${SORRY_CYPRESS_RERUN_COUNT} (Postgres)\"", - "cypress:record:local": "npx cypress-cloud run --parallel --record --ci-build-id \"${SORRY_CYPRESS_BRANCH_NAME} #${SORRY_CYPRESS_BUILD_ID} ${SORRY_CYPRESS_RERUN_COUNT} (Local)\"", - "update": "ncu -i --format group" - } -} diff --git a/src/test/cypress/support/artemis.ts b/src/test/cypress/support/artemis.ts deleted file mode 100644 index c23be9249317..000000000000 --- a/src/test/cypress/support/artemis.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { ArtemisPageobjects } from './pageobjects/ArtemisPageobjects'; -import { ArtemisRequests } from './requests/ArtemisRequests'; - -/** - * File which contains all shared code related to testing Artemis. - */ - -// Requests -const requests = new ArtemisRequests(); -export const communicationAPIRequest = requests.communication; -export const courseManagementAPIRequest = requests.courseManagement; -export const examAPIRequests = requests.exam; -export const exerciseAPIRequest = requests.exercise; -export const userManagementAPIRequest = requests.userManagement; - -// PageObjects -const pageObjects = new ArtemisPageobjects(); - -export const loginPage = pageObjects.login; - -export const courseCreation = pageObjects.course.creation; -export const courseList = pageObjects.course.list; -export const courseOverview = pageObjects.course.overview; -export const courseManagement = pageObjects.course.management; -export const courseManagementExercises = pageObjects.course.managementExercises; -export const courseMessages = pageObjects.course.messages; -export const courseAssessment = pageObjects.assessment.course; - -export const lectureCreation = pageObjects.lecture.creation; -export const lectureManagement = pageObjects.lecture.management; - -export const navigationBar = pageObjects.navigationBar; - -export const examCreation = pageObjects.exam.creation; -export const examManagement = pageObjects.exam.management; -export const examDetails = pageObjects.exam.details; -export const examAssessment = pageObjects.assessment.exam; -export const examNavigation = pageObjects.exam.navigationBar; -export const examStartEnd = pageObjects.exam.startEnd; -export const examExerciseGroupCreation = pageObjects.exam.exerciseGroupCreation; -export const examExerciseGroups = pageObjects.exam.exerciseGroups; -export const examParticipation = pageObjects.exam.participation; -export const examTestRun = pageObjects.exam.testRun; -export const studentExamManagement = pageObjects.exam.studentExamManagement; - -export const studentAssessment = pageObjects.assessment.student; - -export const exerciseAssessment = pageObjects.assessment.exercise; -export const exerciseResult = pageObjects.exercise.result; - -export const textExerciseCreation = pageObjects.exercise.text.creation; -export const textExerciseEditor = pageObjects.exercise.text.editor; -export const textExerciseAssessment = pageObjects.assessment.text; -export const textExerciseFeedback = pageObjects.exercise.text.feedback; -export const textExerciseExampleSubmissionCreation = pageObjects.exercise.text.exampleSubmissionCreation; -export const textExerciseExampleSubmissions = pageObjects.exercise.text.exampleSubmissions; - -export const modelingExerciseCreation = pageObjects.exercise.modeling.creation; -export const modelingExerciseEditor = pageObjects.exercise.modeling.editor; -export const modelingExerciseAssessment = pageObjects.assessment.modeling; -export const modelingExerciseFeedback = pageObjects.exercise.modeling.feedback; - -export const programmingExerciseCreation = pageObjects.exercise.programming.creation; -export const programmingExerciseEditor = pageObjects.exercise.programming.editor; -export const programmingExerciseAssessment = pageObjects.assessment.programming; -export const programmingExerciseFeedback = pageObjects.exercise.programming.feedback; -export const programmingExercisesScaConfig = pageObjects.exercise.programming.scaConfiguration; -export const programmingExerciseScaFeedback = pageObjects.exercise.programming.scaFeedback; - -export const quizExerciseCreation = pageObjects.exercise.quiz.creation; -export const quizExerciseMultipleChoice = pageObjects.exercise.quiz.multipleChoice; -export const quizExerciseShortAnswerQuiz = pageObjects.exercise.quiz.shortAnswer; -export const quizExerciseDragAndDropQuiz = pageObjects.exercise.quiz.dragAndDrop; - -export const fileUploadExerciseCreation = pageObjects.exercise.fileUpload.creation; -export const fileUploadExerciseEditor = pageObjects.exercise.fileUpload.editor; -export const fileUploadExerciseAssessment = pageObjects.assessment.fileUpload; -export const fileUploadExerciseFeedback = pageObjects.exercise.fileUpload.feedback; diff --git a/src/test/cypress/support/commands.ts b/src/test/cypress/support/commands.ts deleted file mode 100644 index d2bf385fe315..000000000000 --- a/src/test/cypress/support/commands.ts +++ /dev/null @@ -1,156 +0,0 @@ -// *********************************************** -// This example commands.js shows you how to -// create various custom commands and overwrite -// existing commands. -// -// For more comprehensive examples of custom -// commands please read more here: -// https://on.cypress.io/custom-commands -// *********************************************** -// -// -// -- This is a parent command -- -// Cypress.Commands.add('login', (email, password) => { ... }) -// -// -// -- This is a child command -- -// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- -// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) -// -// -// -- This will overwrite an existing command -- -// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) - -import { BASE_API, POST } from './constants'; -import { CypressCredentials } from './users'; - -export {}; - -declare global { - // eslint-disable-next-line @typescript-eslint/no-namespace - namespace Cypress { - interface Chainable { - login(credentials: CypressCredentials, url?: string): any; - loginWithGUI(credentials: CypressCredentials): any; - getSettled(selector: string, options?: any): Chainable; - reloadUntilFound(selector: string, interval?: number, timeout?: number): Chainable; - formRequest(url: string, method: string, formData: FormData): Chainable; - } - } -} - -/** - * Logs in using API - * */ -Cypress.Commands.add('login', (credentials: CypressCredentials, url) => { - const username = credentials.username; - const password = credentials.password; - - cy.session( - username, - () => { - // IMPORTANT: The "log" and "failOnStatusCode" fields need to be set to false to prevent leakage of the credentials via the Cypress Dashboard! - // log = false does not prevent cypress to log the request if it failed, so failOnStatusCode also needs to be set to false, so that the request is never logged. - // We still want to the test to fail if the authentication is unsuccessful, so we expect the status code in the then block. This only logs the status code, so it is safe. - cy.request({ - url: `${BASE_API}/public/authenticate`, - method: POST, - followRedirect: true, - body: { - username, - password, - rememberMe: true, - }, - log: false, - failOnStatusCode: false, - }).then((response) => { - expect(response.status).to.equal(200); - }); - }, - { - validate: () => { - cy.getCookie('jwt', { log: false }).should('exist'); - }, - cacheAcrossSpecs: true, - }, - ); - if (url) { - cy.visit(url); - } -}); - -/** recursively gets an element, returning only after it's determined to be attached to the DOM for good - * this prevents the "Element is detached from DOM" issue in some cases - */ -Cypress.Commands.add('getSettled', (selector: any, opts: { retries?: number; delay?: number } = {}) => { - const retries = opts.retries || 3; - const delay = opts.delay || 100; - - const isAttached = (resolve: any, count = 0) => { - const el = Cypress.$(selector); - - // is element attached to the DOM? - count = Cypress.dom.isAttached(el) ? count + 1 : 0; - - // hit our base case, return the element - if (count >= retries) { - return resolve(el); - } - - // retry after a bit of a delay - setTimeout(() => isAttached(resolve, count), delay); - }; - - // wrap, so we can chain cypress commands off the result - return cy.wrap(null).then(() => { - return new Cypress.Promise((resolve) => { - return isAttached(resolve, 0); - }).then((el) => { - return cy.wrap(el); - }); - }); -}); - -/** - * Periodically refreshes the page until an element with the specified selector is found. The command fails if the time exceeds the timeout. - */ -Cypress.Commands.add('reloadUntilFound', (selector: string, interval = 2000, timeout = 20000) => { - return cy.waitUntil( - () => { - const found = Cypress.$(selector).length > 0; - if (!found) { - cy.reload(); - } - return found; - }, - { - interval, - timeout, - errorMsg: `Timed out finding an element matching the "${selector}" selector`, - }, - ); -}); - -Cypress.Commands.add('formRequest', (url: string, method: string, formData: FormData) => { - return cy - .intercept(method, url) - .as('formRequest') - .window() - .then((win) => { - const xhr = new win.XMLHttpRequest(); - xhr.open(method, url); - const token = localStorage.getItem('authTokenKey')?.replace(/"/g, ''); - if (token) { - const authHeader = 'Bearer ' + token; - xhr.setRequestHeader('Authorization', authHeader); - } - xhr.send(formData); - }) - .wait('@formRequest') - .then((xhr: any) => { - return cy.wrap({ status: xhr.status, body: xhr.response.body }); - }); -}); diff --git a/src/test/cypress/support/constants.ts b/src/test/cypress/support/constants.ts deleted file mode 100644 index 97ee7440e57b..000000000000 --- a/src/test/cypress/support/constants.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { ExerciseGroup } from 'app/entities/exercise-group.model'; - -import { ProgrammingExerciseSubmission } from './pageobjects/exercises/programming/OnlineEditorPage'; - -// Constants which are used in the test specs - -// Requests -export const DELETE = 'DELETE'; -export const POST = 'POST'; -export const GET = 'GET'; -export const PUT = 'PUT'; -export const PATCH = 'PATCH'; -export const BASE_API = 'api'; -export const EXERCISE_BASE = `${BASE_API}/exercises`; - -export const COURSE_BASE = `${BASE_API}/courses`; -export const COURSE_ADMIN_BASE = `${BASE_API}/admin/courses`; - -export const PROGRAMMING_EXERCISE_BASE = `${BASE_API}/programming-exercises`; -export const QUIZ_EXERCISE_BASE = `${BASE_API}/quiz-exercises`; -export const TEXT_EXERCISE_BASE = `${BASE_API}/text-exercises`; -export const MODELING_EXERCISE_BASE = `${BASE_API}/modeling-exercises`; -export const UPLOAD_EXERCISE_BASE = `${BASE_API}/file-upload-exercises`; - -// Constants -export const USER_ID_SELECTOR = 'USERID'; -export const MODELING_EDITOR_CANVAS = '#modeling-editor-canvas'; - -// Timeformat -export const TIME_FORMAT = 'YYYY-MM-DDTHH:mm:ss.SSS'; - -// ExerciseType -// Copied from app/entities/exercise.model -export enum ExerciseType { - PROGRAMMING = 'programming', - MODELING = 'modeling', - QUIZ = 'quiz', - TEXT = 'text', - FILE_UPLOAD = 'file-upload', -} - -// ProgrammingLanguage -// Copied from app/entities/programming-exercise.model -export enum ProgrammingLanguage { - JAVA = 'JAVA', - PYTHON = 'PYTHON', - C = 'C', - HASKELL = 'HASKELL', - KOTLIN = 'KOTLIN', - VHDL = 'VHDL', - ASSEMBLER = 'ASSEMBLER', - SWIFT = 'SWIFT', - OCAML = 'OCAML', - EMPTY = 'EMPTY', -} - -// ProgrammingExerciseAssessmentType -export enum ProgrammingExerciseAssessmentType { - AUTOMATIC, - SEMI_AUTOMATIC, - MANUAL, -} - -// AdditionalData -export class AdditionalData { - quizExerciseID?: number; - submission?: ProgrammingExerciseSubmission; - expectedScore?: number; - textFixture?: string; - practiceMode?: boolean; - progExerciseAssessmentType?: ProgrammingExerciseAssessmentType; -} - -// Exercise -export type Exercise = { - title: string; - type: ExerciseType; - id: number; - additionalData?: AdditionalData; - exerciseGroup?: ExerciseGroup; -}; diff --git a/src/test/cypress/support/index.ts b/src/test/cypress/support/index.ts deleted file mode 100644 index 18be87965603..000000000000 --- a/src/test/cypress/support/index.ts +++ /dev/null @@ -1,73 +0,0 @@ -// *********************************************************** -// This example support/index.js is processed and -// loaded automatically before your test files. -// -// This is a great place to put global configuration and -// behavior that modifies Cypress. -// -// You can change the location of this file or turn off -// automatically serving support files with the -// 'supportFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/configuration -// *********************************************************** - -// Import commands.js using ES2015 syntax: - -// https://github.com/4teamwork/cypress-drag-drop#options adds .drag and .move commands -import '@4tw/cypress-drag-drop'; -// Imports file upload capabilities https://github.com/abramenal/cypress-file-upload -import 'cypress-file-upload'; -// Imports cy.waitUntil https://github.com/NoriSte/cypress-wait-until -import 'cypress-wait-until'; - -import './commands'; -// Imports utility functions -import './utils'; -// Imports cy.pipe https://github.com/NicholasBoll/cypress-pipe -import 'cypress-pipe'; - -/** - * We register hooks on the console.error and console.warn methods and forward their content to the process console to allow better debugging with cypress:run. - */ -/*eslint-disable */ -Cypress.on('window:before:load', (win) => { - cy.stub(win.console, 'error').callsFake((msg) => { - cy.now('task', 'error', msg); - }); - - cy.stub(win.console, 'warn').callsFake((msg) => { - cy.now('task', 'warn', msg); - }); -}); - -/** - * We have to disable all service workers because the test will fail with a security exception and translations will also not be resolved properly otherwise. - * For some reason this does not work when I add it to the hook above. - */ -Cypress.on('window:before:load', (win) => { - delete win.navigator.__proto__.serviceWorker; -}); - -/** - * On development environments (i.e. local environments) sentry is disabled and produces error messages in the console that cause cypress to fail. - * This call tells cypress to ignore errors related to sentry - */ -Cypress.on('uncaught:exception', (err, runnable) => { - return err.name === 'TypeError' && err?.stack?.includes('sentry'); -}); - -/** - * We want to log our test retries to the console to be able to see how often a test is retried. - */ -const config: any = Cypress.config(); -if (!config.isInteractive && config.reporter !== 'spec') { - afterEach(() => { - const test = (cy as any).state('runnable')?.ctx?.currentTest; - if (test?.state === 'failed' && test?._currentRetry < test?._retries) { - cy.task('log', ` RERUN: (Attempt ${test._currentRetry + 1} of ${test._retries + 1}) ${test.title}`, { log: false }); - } - }); -} -/*eslint-enable */ diff --git a/src/test/cypress/support/pageobjects/ArtemisPageobjects.ts b/src/test/cypress/support/pageobjects/ArtemisPageobjects.ts deleted file mode 100644 index 1e2bc2b56b82..000000000000 --- a/src/test/cypress/support/pageobjects/ArtemisPageobjects.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { LoginPage } from './LoginPage'; -import { NavigationBar } from './NavigationBar'; -import { CourseAssessmentDashboardPage } from './assessment/CourseAssessmentDashboardPage'; -import { ExamAssessmentPage } from './assessment/ExamAssessmentPage'; -import { ExerciseAssessmentDashboardPage } from './assessment/ExerciseAssessmentDashboardPage'; -import { FileUploadExerciseAssessmentPage } from './assessment/FileUploadExerciseAssessmentPage'; -import { ModelingExerciseAssessmentEditor } from './assessment/ModelingExerciseAssessmentEditor'; -import { ProgrammingExerciseAssessmentPage } from './assessment/ProgrammingExerciseAssessmentPage'; -import { StudentAssessmentPage } from './assessment/StudentAssessmentPage'; -import { TextExerciseAssessmentPage } from './assessment/TextExerciseAssessmentPage'; -import { CourseCreationPage } from './course/CourseCreationPage'; -import { CourseManagementExercisesPage } from './course/CourseManagementExercisesPage'; -import { CourseManagementPage } from './course/CourseManagementPage'; -import { CourseMessagesPage } from './course/CourseMessages'; -import { CourseOverviewPage } from './course/CourseOverviewPage'; -import { CoursesPage } from './course/CoursesPage'; -import { ExamCreationPage } from './exam/ExamCreationPage'; -import { ExamDetailsPage } from './exam/ExamDetailsPage'; -import { ExamExerciseGroupCreationPage } from './exam/ExamExerciseGroupCreationPage'; -import { ExamExerciseGroupsPage } from './exam/ExamExerciseGroupsPage'; -import { ExamManagementPage } from './exam/ExamManagementPage'; -import { ExamNavigationBar } from './exam/ExamNavigationBar'; -import { ExamParticipation } from './exam/ExamParticipation'; -import { ExamStartEndPage } from './exam/ExamStartEndPage'; -import { ExamTestRunPage } from './exam/ExamTestRunPage'; -import { StudentExamManagementPage } from './exam/StudentExamManagementPage'; -import { ExerciseResultPage } from './exercises/ExerciseResultPage'; -import { FileUploadEditorPage } from './exercises/file-upload/FileUploadEditorPage'; -import { FileUploadExerciseCreationPage } from './exercises/file-upload/FileUploadExerciseCreationPage'; -import { FileUploadExerciseFeedbackPage } from './exercises/file-upload/FileUploadExerciseFeedbackPage'; -import { CreateModelingExercisePage } from './exercises/modeling/CreateModelingExercisePage'; -import { ModelingEditor } from './exercises/modeling/ModelingEditor'; -import { ModelingExerciseFeedbackPage } from './exercises/modeling/ModelingExerciseFeedbackPage'; -import { CodeAnalysisGradingPage } from './exercises/programming/CodeAnalysisGradingPage'; -import { OnlineEditorPage } from './exercises/programming/OnlineEditorPage'; -import { ProgrammingExerciseCreationPage } from './exercises/programming/ProgrammingExerciseCreationPage'; -import { ProgrammingExerciseFeedbackPage } from './exercises/programming/ProgrammingExerciseFeedbackPage'; -import { ScaFeedbackModal } from './exercises/programming/ScaFeedbackModal'; -import { DragAndDropQuiz } from './exercises/quiz/DragAndDropQuiz'; -import { MultipleChoiceQuiz } from './exercises/quiz/MultipleChoiceQuiz'; -import { QuizExerciseCreationPage } from './exercises/quiz/QuizExerciseCreationPage'; -import { ShortAnswerQuiz } from './exercises/quiz/ShortAnswerQuiz'; -import { TextEditorPage } from './exercises/text/TextEditorPage'; -import { TextExerciseCreationPage } from './exercises/text/TextExerciseCreationPage'; -import { TextExerciseExampleSubmissionCreationPage } from './exercises/text/TextExerciseExampleSubmissionCreationPage'; -import { TextExerciseExampleSubmissionsPage } from './exercises/text/TextExerciseExampleSubmissionsPage'; -import { TextExerciseFeedbackPage } from './exercises/text/TextExerciseFeedbackPage'; -import { LectureCreationPage } from './lecture/LectureCreationPage'; -import { LectureManagementPage } from './lecture/LectureManagementPage'; - -/** - * A class which encapsulates all pageobjects, which can be used to automate the Artemis UI. - */ -export class ArtemisPageobjects { - login = new LoginPage(); - navigationBar = new NavigationBar(); - course = { - creation: new CourseCreationPage(), - management: new CourseManagementPage(), - managementExercises: new CourseManagementExercisesPage(), - list: new CoursesPage(), - overview: new CourseOverviewPage(), - messages: new CourseMessagesPage(), - }; - exam = { - details: new ExamDetailsPage(), - creation: new ExamCreationPage(), - management: new ExamManagementPage(), - participation: new ExamParticipation(), - startEnd: new ExamStartEndPage(), - navigationBar: new ExamNavigationBar(), - exerciseGroups: new ExamExerciseGroupsPage(), - exerciseGroupCreation: new ExamExerciseGroupCreationPage(), - studentExamManagement: new StudentExamManagementPage(), - testRun: new ExamTestRunPage(), - }; - exercise = { - result: new ExerciseResultPage(), - programming: { - editor: new OnlineEditorPage(), - creation: new ProgrammingExerciseCreationPage(), - feedback: new ProgrammingExerciseFeedbackPage(), - scaConfiguration: new CodeAnalysisGradingPage(), - scaFeedback: new ScaFeedbackModal(), - }, - text: { - creation: new TextExerciseCreationPage(), - exampleSubmissions: new TextExerciseExampleSubmissionsPage(), - exampleSubmissionCreation: new TextExerciseExampleSubmissionCreationPage(), - editor: new TextEditorPage(), - feedback: new TextExerciseFeedbackPage(), - }, - modeling: { - creation: new CreateModelingExercisePage(), - editor: new ModelingEditor(), - feedback: new ModelingExerciseFeedbackPage(), - }, - quiz: { - creation: new QuizExerciseCreationPage(), - multipleChoice: new MultipleChoiceQuiz(), - shortAnswer: new ShortAnswerQuiz(), - dragAndDrop: new DragAndDropQuiz(), - }, - fileUpload: { - creation: new FileUploadExerciseCreationPage(), - editor: new FileUploadEditorPage(), - feedback: new FileUploadExerciseFeedbackPage(), - }, - }; - assessment = { - exam: new ExamAssessmentPage(), - course: new CourseAssessmentDashboardPage(), - exercise: new ExerciseAssessmentDashboardPage(), - text: new TextExerciseAssessmentPage(), - programming: new ProgrammingExerciseAssessmentPage(), - modeling: new ModelingExerciseAssessmentEditor(), - fileUpload: new FileUploadExerciseAssessmentPage(), - student: new StudentAssessmentPage(), - }; - lecture = { - management: new LectureManagementPage(), - creation: new LectureCreationPage(), - }; -} diff --git a/src/test/cypress/support/pageobjects/LoginPage.ts b/src/test/cypress/support/pageobjects/LoginPage.ts deleted file mode 100644 index d7383b7b2372..000000000000 --- a/src/test/cypress/support/pageobjects/LoginPage.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { CypressCredentials } from '../users'; - -/** - * A class which encapsulates UI selectors and actions for the Login Page. - */ -export class LoginPage { - enterUsername(name: string) { - cy.get('#username').type(name, { log: false }); - } - - enterPassword(password: string) { - cy.get('#password').type(password, { log: false }); - } - - clickLoginButton() { - cy.get('#login-button').click(); - } - - login(credentials: CypressCredentials) { - this.enterUsername(credentials.username); - this.enterPassword(credentials.password); - this.clickLoginButton(); - } - - shouldShowFooter() { - cy.get('#footer').should('be.visible'); - } - - shouldShowAboutUsInFooter() { - cy.get('#about').should('be.visible').and('have.attr', 'href', '/about'); - } - - shouldShowRequestChangeInFooter() { - cy.get('#feedback').should('be.visible').and('have.attr', 'href'); - } - - shouldShowReleaseNotesInFooter() { - cy.get('#releases').should('be.visible').and('have.attr', 'href'); - } - - shouldShowPrivacyStatementInFooter() { - cy.get('#privacy').should('be.visible').and('have.attr', 'href', '/privacy'); - } - - shouldShowImprintInFooter() { - cy.get('#imprint').should('be.visible').and('have.attr', 'href', '/imprint'); - } -} diff --git a/src/test/cypress/support/pageobjects/NavigationBar.ts b/src/test/cypress/support/pageobjects/NavigationBar.ts deleted file mode 100644 index 18fd393a8bd4..000000000000 --- a/src/test/cypress/support/pageobjects/NavigationBar.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { COURSE_BASE, GET } from '../constants'; - -/** - * A class which encapsulates UI selectors and actions for the navigation bar at the top. - */ -export class NavigationBar { - /** - * Opens the course management page via the menu at the top and waits until it is loaded. - */ - openCourseManagement() { - cy.log('Opening course-management page...'); - cy.intercept(GET, `${COURSE_BASE}/course-management-overview*`).as('courseManagementQuery'); - cy.get('#course-admin-menu').click(); - cy.wait('@courseManagementQuery', { timeout: 30000 }); - cy.url().should('include', '/course-management'); - } - - openNotificationPanel() { - cy.get('.navbar .notification-button').click(); - } - - getNotifications() { - return cy.get('.notification-sidebar .notification-item'); - } - - getAccountItem() { - return cy.get('#account-menu'); - } - - logout() { - this.getAccountItem().click().get('#logout').click(); - } -} diff --git a/src/test/cypress/support/pageobjects/assessment/AbstractExerciseAssessmentPage.ts b/src/test/cypress/support/pageobjects/assessment/AbstractExerciseAssessmentPage.ts deleted file mode 100644 index 6082ff502a56..000000000000 --- a/src/test/cypress/support/pageobjects/assessment/AbstractExerciseAssessmentPage.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { BASE_API, ExerciseType, PATCH, PUT } from '../../constants'; - -/** - * Parent class for all exercise assessment pages. - */ -export abstract class AbstractExerciseAssessmentPage { - readonly UNREFERENCED_FEEDBACK_SELECTOR = '.unreferenced-feedback-detail'; - - addNewFeedback(points: number, feedback?: string) { - cy.get('.add-unreferenced-feedback').click(); - cy.get(this.UNREFERENCED_FEEDBACK_SELECTOR).find('#feedback-points').clear().type(points.toString()); - if (feedback) { - cy.get(this.UNREFERENCED_FEEDBACK_SELECTOR).find('#feedback-textarea').clear().type(feedback); - } - } - - submitWithoutInterception() { - cy.get('#submit').click(); - } - - submit() { - cy.intercept(PUT, `${BASE_API}/participations/*/manual-results?submit=true`).as('submitAssessment'); - this.submitWithoutInterception(); - return cy.wait('@submitAssessment'); - } - - rejectComplaint(response: string, examMode: boolean, exerciseType: ExerciseType) { - return this.handleComplaint(response, false, exerciseType, examMode); - } - - acceptComplaint(response: string, examMode: boolean, exerciseType: ExerciseType) { - return this.handleComplaint(response, true, exerciseType, examMode); - } - - private handleComplaint(response: string, accept: boolean, exerciseType: ExerciseType, examMode: boolean) { - if (exerciseType !== ExerciseType.MODELING && !examMode) { - cy.get('#show-complaint').click(); - } - cy.get('#responseTextArea').type(response, { parseSpecialCharSequences: false }); - switch (exerciseType) { - case ExerciseType.PROGRAMMING: - cy.intercept(PUT, `${BASE_API}/programming-submissions/*/assessment-after-complaint`).as('complaintAnswer'); - break; - case ExerciseType.TEXT: - cy.intercept(PUT, `${BASE_API}/participations/*/submissions/*/text-assessment-after-complaint`).as('complaintAnswer'); - break; - case ExerciseType.MODELING: - cy.intercept(PATCH, `${BASE_API}/complaints/*/response`).as('complaintAnswer'); - break; - case ExerciseType.FILE_UPLOAD: - cy.intercept(PUT, `${BASE_API}/file-upload-submissions/*/assessment-after-complaint`).as('complaintAnswer'); - break; - default: - throw new Error(`Exercise type '${exerciseType}' is not supported yet!`); - } - if (accept) { - cy.get('#acceptComplaintButton').click(); - } else { - cy.get('#rejectComplaintButton').click(); - } - return cy.wait('@complaintAnswer'); - } -} diff --git a/src/test/cypress/support/pageobjects/assessment/CourseAssessmentDashboardPage.ts b/src/test/cypress/support/pageobjects/assessment/CourseAssessmentDashboardPage.ts deleted file mode 100644 index da24b01bcfb2..000000000000 --- a/src/test/cypress/support/pageobjects/assessment/CourseAssessmentDashboardPage.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { COURSE_BASE, POST } from '../../constants'; - -/** - * A class which encapsulates UI selectors and actions for the course assessment dashboard page. - */ -export class CourseAssessmentDashboardPage { - openComplaints() { - cy.get('#open-complaints').click(); - } - - showTheComplaint() { - cy.get('#show-complaint').click(); - } - - clickExerciseDashboardButton() { - // Sometimes the page does not load properly, so we reload it if the button is not found - cy.reloadUntilFound('#open-exercise-dashboard'); - cy.get('#open-exercise-dashboard').click(); - } - - clickEvaluateQuizzes() { - cy.intercept(POST, `${COURSE_BASE}/*/exams/*/student-exams/evaluate-quiz-exercises`).as('evaluateQuizzes'); - cy.get('#evaluateQuizExercisesButton').click(); - return cy.wait('@evaluateQuizzes'); - } -} diff --git a/src/test/cypress/support/pageobjects/assessment/ExamAssessmentPage.ts b/src/test/cypress/support/pageobjects/assessment/ExamAssessmentPage.ts deleted file mode 100644 index 444d6fa743c1..000000000000 --- a/src/test/cypress/support/pageobjects/assessment/ExamAssessmentPage.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { BASE_API, POST, PUT } from '../../constants'; -import { AbstractExerciseAssessmentPage } from './AbstractExerciseAssessmentPage'; - -export class ExamAssessmentPage extends AbstractExerciseAssessmentPage { - submitModelingAssessment() { - cy.intercept(PUT, `${BASE_API}/modeling-submissions/*/result/*/assessment*`).as('submitAssessment'); - super.submitWithoutInterception(); - return cy.wait('@submitAssessment'); - } - - submitTextAssessment() { - cy.intercept(POST, `${BASE_API}/participations/*/results/*/submit-text-assessment`).as('submitFeedback'); - super.submitWithoutInterception(); - return cy.wait('@submitFeedback'); - } -} diff --git a/src/test/cypress/support/pageobjects/assessment/ExerciseAssessmentDashboardPage.ts b/src/test/cypress/support/pageobjects/assessment/ExerciseAssessmentDashboardPage.ts deleted file mode 100644 index 97b1cef4b06a..000000000000 --- a/src/test/cypress/support/pageobjects/assessment/ExerciseAssessmentDashboardPage.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * A class which encapsulates UI selectors and actions for the exercise assessment dashboard page. - */ -export class ExerciseAssessmentDashboardPage { - readonly START_ASSESSING_SELECTOR = '#start-new-assessment'; - - clickHaveReadInstructionsButton() { - cy.get('#participate-in-assessment').click(); - } - - clickStartNewAssessment() { - cy.reloadUntilFound(this.START_ASSESSING_SELECTOR); - cy.get(this.START_ASSESSING_SELECTOR).click(); - } - - clickOpenAssessment() { - cy.get('#open-assessment').click(); - } - - clickEvaluateComplaint() { - cy.get('#evaluate-complaint').click(); - } - - getComplaintText() { - return cy.get('#complaintTextArea'); - } - - getLockedMessage() { - return cy.get('#assessmentLockedCurrentUser'); - } -} diff --git a/src/test/cypress/support/pageobjects/assessment/FileUploadExerciseAssessmentPage.ts b/src/test/cypress/support/pageobjects/assessment/FileUploadExerciseAssessmentPage.ts deleted file mode 100644 index d8e1ebae54ba..000000000000 --- a/src/test/cypress/support/pageobjects/assessment/FileUploadExerciseAssessmentPage.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ExerciseType } from '../../constants'; -import { AbstractExerciseAssessmentPage } from './AbstractExerciseAssessmentPage'; - -/** - * A class which encapsulates UI selectors and actions for the file upload exercise assessment page. - */ -export class FileUploadExerciseAssessmentPage extends AbstractExerciseAssessmentPage { - getInstructionsRootElement() { - return cy.get('#instructions-card'); - } - - submitFeedback() { - cy.get('#submit').click(); - } - - rejectComplaint(response: string, examMode: boolean) { - return super.rejectComplaint(response, examMode, ExerciseType.FILE_UPLOAD); - } - - acceptComplaint(response: string, examMode: boolean) { - return super.acceptComplaint(response, examMode, ExerciseType.FILE_UPLOAD); - } -} diff --git a/src/test/cypress/support/pageobjects/assessment/ModelingExerciseAssessmentEditor.ts b/src/test/cypress/support/pageobjects/assessment/ModelingExerciseAssessmentEditor.ts deleted file mode 100644 index 917d80b47b2f..000000000000 --- a/src/test/cypress/support/pageobjects/assessment/ModelingExerciseAssessmentEditor.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { BASE_API, ExerciseType, MODELING_EDITOR_CANVAS, PUT } from '../../constants'; -import { AbstractExerciseAssessmentPage } from './AbstractExerciseAssessmentPage'; - -const ASSESSMENT_CONTAINER = '#modeling-assessment-container'; - -/** - * A class which encapsulates UI selectors and actions for the Modeling Exercise Assessment editor - */ -export class ModelingExerciseAssessmentEditor extends AbstractExerciseAssessmentPage { - openAssessmentForComponent(componentNumber: number) { - cy.get('#apollon-assessment-row').getSettled(`${MODELING_EDITOR_CANVAS} >>> :nth-child(${componentNumber})`).children().eq(0).dblclick('top', { force: true }); - } - - assessComponent(points: number, feedback: string) { - this.getPointAssessmentField().type(`${points}`); - this.getFeedbackAssessmentField().type(`${feedback}`); - } - - clickNextAssessment() { - this.getNextAssessmentField().click(); - } - - rejectComplaint(response: string, examMode: false) { - return super.rejectComplaint(response, examMode, ExerciseType.MODELING); - } - - acceptComplaint(response: string, examMode: false) { - return super.acceptComplaint(response, examMode, ExerciseType.MODELING); - } - - submitExample() { - cy.intercept(PUT, `${BASE_API}/modeling-submissions/*/example-assessment`).as('createExampleSubmission'); - cy.contains('Save Example Assessment').click(); - return cy.wait('@createExampleSubmission').its('response.statusCode').should('eq', 200); - } - - submit() { - cy.intercept(PUT, `${BASE_API}/modeling-submissions/*/result/*/assessment*`).as('submitModelingAssessment'); - super.submitWithoutInterception(); - return cy.wait('@submitModelingAssessment').its('response.statusCode').should('eq', 200); - } - - private getNextAssessmentField() { - return this.getAssessmentContainer().children().last(); - } - - private getPointAssessmentField() { - return this.getAssessmentContainer().children().eq(1).children().children().eq(1); - } - - private getFeedbackAssessmentField() { - return this.getAssessmentContainer().children().eq(3); - } - - private getAssessmentContainer() { - return cy.get(`${ASSESSMENT_CONTAINER}`); - } -} diff --git a/src/test/cypress/support/pageobjects/assessment/ProgrammingExerciseAssessmentPage.ts b/src/test/cypress/support/pageobjects/assessment/ProgrammingExerciseAssessmentPage.ts deleted file mode 100644 index 961934b5ba14..000000000000 --- a/src/test/cypress/support/pageobjects/assessment/ProgrammingExerciseAssessmentPage.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { ExerciseType } from '../../constants'; -import { AbstractExerciseAssessmentPage } from './AbstractExerciseAssessmentPage'; - -/** - * A class which encapsulates UI selectors and actions for the programming exercise assessment page. - */ -export class ProgrammingExerciseAssessmentPage extends AbstractExerciseAssessmentPage { - readonly feedbackEditorSelector = '#test-'; - - provideFeedbackOnCodeLine(lineIndex: number, points: number, feedback: string) { - // We can't change elements from the ace editor, so we can't use custom ids here - cy.get('.ace_gutter-cell').eq(lineIndex).find('svg').click({ force: true }); - this.typeIntoFeedbackEditor(feedback, lineIndex); - this.typePointsIntoFeedbackEditor(points, lineIndex); - this.saveFeedback(lineIndex); - } - - private typeIntoFeedbackEditor(text: string, index: number) { - this.getInlineFeedback(index).find('#feedback-textarea').type(text, { parseSpecialCharSequences: false }); - } - - private typePointsIntoFeedbackEditor(points: number, index: number) { - this.getInlineFeedback(index).find('#feedback-points').clear().type(points.toString()); - } - - private saveFeedback(index: number) { - this.getInlineFeedback(index).find('#feedback-save').click(); - } - - /** - * Every code line in the ace editor has an attached inline feedback - * @param line the code line where the inline feedback is attached - * @returns the root element of the inline feedback component - */ - private getInlineFeedback(line: number) { - return cy.get('#code-editor-inline-feedback-' + line); - } - - rejectComplaint(response: string, examMode: boolean) { - return super.rejectComplaint(response, examMode, ExerciseType.PROGRAMMING); - } - - acceptComplaint(response: string, examMode: boolean) { - return super.acceptComplaint(response, examMode, ExerciseType.PROGRAMMING); - } -} diff --git a/src/test/cypress/support/pageobjects/assessment/StudentAssessmentPage.ts b/src/test/cypress/support/pageobjects/assessment/StudentAssessmentPage.ts deleted file mode 100644 index 43a6bc0e2388..000000000000 --- a/src/test/cypress/support/pageobjects/assessment/StudentAssessmentPage.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * A class which encapsulates UI selectors and actions for the student assessment page. - */ -export class StudentAssessmentPage { - startComplaint() { - cy.get('#complain', { timeout: 30000 }).click(); - } - - enterComplaint(text: string) { - cy.get('#complainTextArea').type(text); - } - - submitComplaint() { - cy.get('#submit-complaint').click(); - } - - getComplaintBadge() { - return cy.get('jhi-complaint-request .badge'); - } - - getComplaintResponse() { - return cy.get('#complainResponseTextArea'); - } -} diff --git a/src/test/cypress/support/pageobjects/assessment/TextExerciseAssessmentPage.ts b/src/test/cypress/support/pageobjects/assessment/TextExerciseAssessmentPage.ts deleted file mode 100644 index 93c8ac8a388b..000000000000 --- a/src/test/cypress/support/pageobjects/assessment/TextExerciseAssessmentPage.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { BASE_API, ExerciseType, POST } from '../../constants'; -import { AbstractExerciseAssessmentPage } from './AbstractExerciseAssessmentPage'; - -/** - * A class which encapsulates UI selectors and actions for the text exercise assessment page. - */ -export class TextExerciseAssessmentPage extends AbstractExerciseAssessmentPage { - getInstructionsRootElement() { - return cy.get('#instructions-card'); - } - - provideFeedbackOnTextSection(sectionIndex: number, points: number, feedback: string) { - this.getFeedbackSection(sectionIndex).click(); - this.typeIntoFeedbackEditor(sectionIndex, feedback); - this.typePointsIntoFeedbackEditor(sectionIndex, points); - } - - private typeIntoFeedbackEditor(sectionIndex: number, feedbackText: string) { - this.getFeedbackSection(sectionIndex).find('#feedback-editor-text-input').type(feedbackText, { parseSpecialCharSequences: false }); - } - - private typePointsIntoFeedbackEditor(sectionIndex: number, feedbackPoints: number) { - this.getFeedbackSection(sectionIndex).find('#feedback-editor-points-input').clear().type(feedbackPoints.toString()); - } - - private getFeedbackSection(sectionIndex: number) { - return cy.get('#text-feedback-block-' + sectionIndex); - } - - submit() { - // Feedback route is special for text exercises, so we override parent here... - cy.intercept(POST, `${BASE_API}/participations/*/results/*/submit-text-assessment`).as('submitFeedback'); - cy.get('#submit').click(); - return cy.wait('@submitFeedback'); - } - - rejectComplaint(response: string, examMode: boolean) { - return super.rejectComplaint(response, examMode, ExerciseType.TEXT); - } - - acceptComplaint(response: string, examMode: boolean) { - return super.acceptComplaint(response, examMode, ExerciseType.TEXT); - } - - getWordCountElement() { - return cy.get('#text-assessment-word-count'); - } - - getCharacterCountElement() { - return cy.get('#text-assessment-character-count'); - } -} diff --git a/src/test/cypress/support/pageobjects/course/CourseCreationPage.ts b/src/test/cypress/support/pageobjects/course/CourseCreationPage.ts deleted file mode 100644 index 24db4af3cb9c..000000000000 --- a/src/test/cypress/support/pageobjects/course/CourseCreationPage.ts +++ /dev/null @@ -1,243 +0,0 @@ -import dayjs from 'dayjs/esm'; - -import { COURSE_ADMIN_BASE, COURSE_BASE, POST, PUT } from '../../constants'; -import { enterDate } from '../../utils'; - -/** - * A class which encapsulates UI selectors and actions for the course creation page. - */ -export class CourseCreationPage { - /** - * Sets the title of the course. - * @param title the exam title - */ - setTitle(title: string) { - cy.get('#field_title').clear().type(title); - } - - /** - * Sets the short name of the course. - * @param shortName the course short name - */ - setShortName(shortName: string) { - cy.get('#field_shortName').clear().type(shortName); - } - - /** - * Sets the description of the course. - * @param description the course description - */ - setDescription(description: string) { - cy.get('#field_description').clear().type(description); - } - - /** - * @param date the date when the exam starts - */ - setStartDate(date: dayjs.Dayjs) { - enterDate('#field_startDate', date); - } - - /** - * @param date the date when the exam will end - */ - setEndDate(date: dayjs.Dayjs) { - enterDate('#field_endDate', date); - } - - /** - * Sets course to be a test course - * @param testCourse if is a test course - */ - setTestCourse(testCourse: boolean) { - if (testCourse) { - cy.get('#field_testCourse').check(); - } else { - cy.get('#field_testCourse').uncheck(); - } - } - - /** - * Sets semester for the course - * @param semester the semester of the course - */ - setSemester(semester: string) { - cy.get('#semester').select(semester); - } - - /** - * Sets the maximum achievable points in the course. - * @param courseMaxPoints the max points - */ - setCourseMaxPoints(courseMaxPoints: number) { - cy.get('#field_maxPoints').clear().type(courseMaxPoints.toString()); - } - - /** - * Sets the default programming language - * @param programmingLanguage the programming language - */ - setProgrammingLanguage(programmingLanguage: string) { - cy.get('#programmingLanguage').select(programmingLanguage); - } - - /** - * Sets if the course group names should be customized - * @param customizeGroupNames customize the group names - */ - setCustomizeGroupNames(customizeGroupNames: boolean) { - if (customizeGroupNames) { - cy.get('#field_customizeGroupNamesEnabled').check(); - } else { - cy.get('#field_customizeGroupNamesEnabled').uncheck(); - } - } - - /** - * Sets the customized group name for students - * @param groupName the group name - */ - setStudentGroup(groupName: string) { - cy.get('#field_studentGroupName').clear().type(groupName); - } - - /** - * Sets the customized group name for tutors - * @param groupName the group name - */ - setTutorGroup(groupName: string) { - cy.get('#field_teachingAssistantGroupName').clear().type(groupName); - } - - /** - * Sets the customized group name for editors - * @param groupName the group name - */ - setEditorGroup(groupName: string) { - cy.get('#field_editorGroupName').clear().type(groupName); - } - - /** - * Sets the customized group name for editors - * @param groupName the group name - */ - setInstructorGroup(groupName: string) { - cy.get('#field_instructorGroupName').clear().type(groupName); - } - - /** - * Sets if complaints are enabled - * @param complaints if complaints should be enabled - */ - setEnableComplaints(complaints: boolean) { - if (complaints) { - cy.get('#field_maxComplaintSettingEnabled').check(); - } else { - cy.get('#field_maxComplaintSettingEnabled').uncheck(); - } - } - - /** - * Sets maximum amount of complaints - * @param maxComplaints the maximum complaints - */ - setMaxComplaints(maxComplaints: number) { - cy.get('#field_maxComplaints').clear().type(maxComplaints.toString()); - } - - /** - * Sets maximum amount of team complaints - * @param maxTeamComplaints the maximum team complaints - */ - setMaxTeamComplaints(maxTeamComplaints: number) { - cy.get('#field_maxTeamComplaints').clear().type(maxTeamComplaints.toString()); - } - - /** - * Sets the maximal complaints time in days - * @param maxComplaintsTimeDays the maximal complaints time in days - */ - setMaxComplaintsTimeDays(maxComplaintsTimeDays: number) { - cy.get('#field_maxComplaintTimeDays').clear().type(maxComplaintsTimeDays.toString()); - } - - /** - * Sets the maximal complaint text limit - * @param maxComplaintTextLimit the maximal complaint text limit - */ - setMaxComplaintTextLimit(maxComplaintTextLimit: number) { - cy.get('#field_maxComplaintTextLimit').clear().type(maxComplaintTextLimit.toString()); - } - - /** - * Sets the maximal complaint response text limit - * @param maxComplaintResponseTextLimit the maximal complaint response text limit - */ - setMaxComplaintResponseTextLimit(maxComplaintResponseTextLimit: number) { - cy.get('#field_maxComplaintResponseTextLimit').clear().type(maxComplaintResponseTextLimit.toString()); - } - - /** - * Sets if more feedback requests are enabled - * @param moreFeedback if more feedback should be enabled - */ - setEnableMoreFeedback(moreFeedback: boolean) { - if (moreFeedback) { - cy.get('#field_maxRequestMoreFeedbackSettingEnabled').check(); - } else { - cy.get('#field_maxRequestMoreFeedbackSettingEnabled').uncheck(); - } - } - - /** - * Sets the maximal request more feedback time in days - * @param maxRequestMoreFeedbackTimeDays maximal request more feedback time in days - */ - setMaxRequestMoreFeedbackTimeDays(maxRequestMoreFeedbackTimeDays: number) { - cy.get('#field_maxRequestMoreFeedbackTimeDays').clear().type(maxRequestMoreFeedbackTimeDays.toString()); - } - - /** - * Sets if course is an online course - * @param onlineCourse if should be online course - */ - setOnlineCourse(onlineCourse: boolean) { - if (onlineCourse) { - cy.get('#field_onlineCourse').check(); - } else { - cy.get('#field_onlineCourse').uncheck(); - } - } - - /** - * Sets if students can register for this course - * @param registration if registration should be possible - */ - setRegistrationEnabled(registration: boolean) { - if (registration) { - cy.get('#field_registrationEnabled').check(); - } else { - cy.get('#field_registrationEnabled').uncheck(); - } - } - - /** - * Submits the created exam. - * @returns the query chainable if a test needs to access the response - */ - submit() { - cy.intercept(POST, COURSE_ADMIN_BASE).as('createCourseQuery'); - cy.get('#save-entity').click(); - return cy.wait('@createCourseQuery'); - } - - /** - * Updates the created exam. - * @returns the query chainable if a test needs to access the response - */ - update() { - cy.intercept(PUT, `${COURSE_BASE}/*`).as('updateCourseQuery'); - cy.get('#save-entity').click(); - return cy.wait('@updateCourseQuery'); - } -} diff --git a/src/test/cypress/support/pageobjects/course/CourseManagementExercisesPage.ts b/src/test/cypress/support/pageobjects/course/CourseManagementExercisesPage.ts deleted file mode 100644 index 9a7372d2030a..000000000000 --- a/src/test/cypress/support/pageobjects/course/CourseManagementExercisesPage.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { Exercise } from 'app/entities/exercise.model'; - -import { DELETE, MODELING_EXERCISE_BASE, PROGRAMMING_EXERCISE_BASE, QUIZ_EXERCISE_BASE, TEXT_EXERCISE_BASE, UPLOAD_EXERCISE_BASE } from '../../constants'; - -/** - * A class which encapsulates UI selectors and actions for the course management exercises page. - */ -export class CourseManagementExercisesPage { - getExercise(exerciseID: number) { - return cy.get(`#exercise-card-${exerciseID}`); - } - - clickDeleteExercise(exerciseID: number) { - this.getExercise(exerciseID).find('#delete-exercise').click(); - } - - clickExampleSubmissionsButton() { - cy.get('#example-submissions-button').click(); - } - - getExerciseTitle() { - return cy.contains('Title').parent().parent().find('dd'); - } - - deleteTextExercise(exercise: Exercise) { - this.getExercise(exercise.id!).find('#delete-exercise').click(); - cy.get('#confirm-entity-name').type(exercise.title!); - cy.intercept(DELETE, `${TEXT_EXERCISE_BASE}/*`).as('deleteTextExercise'); - cy.get('#delete').click(); - cy.wait('@deleteTextExercise'); - } - - deleteModelingExercise(exercise: Exercise) { - this.getExercise(exercise.id!).find('#delete-exercise').click(); - cy.get('#confirm-entity-name').type(exercise.title!); - cy.intercept(DELETE, `${MODELING_EXERCISE_BASE}/*`).as('deleteModelingExercise'); - cy.get('#delete').click(); - cy.wait('@deleteModelingExercise'); - } - - deleteQuizExercise(exercise: Exercise) { - this.getExercise(exercise.id!).find(`#delete-quiz-${exercise.id}`).click(); - cy.get('#confirm-entity-name').type(exercise.title!); - cy.intercept(DELETE, `${QUIZ_EXERCISE_BASE}/*`).as('deleteQuizExercise'); - cy.get('#delete').click(); - cy.wait('@deleteQuizExercise'); - } - - deleteProgrammingExercise(exercise: Exercise) { - this.getExercise(exercise.id!).find('#delete-exercise').click(); - cy.get('#confirm-entity-name').type(exercise.title!); - cy.intercept(DELETE, `${PROGRAMMING_EXERCISE_BASE}/*`).as('deleteProgrammingExercise'); - cy.get('#delete').click(); - cy.wait('@deleteProgrammingExercise'); - } - - deleteFileUploadExercise(exercise: Exercise) { - this.getExercise(exercise.id!).find('#delete-exercise').click(); - cy.get('#confirm-entity-name').type(exercise.title!); - cy.intercept(DELETE, `${UPLOAD_EXERCISE_BASE}/*`).as('deleteFileUploadExercise'); - cy.get('#delete').click(); - cy.wait('@deleteFileUploadExercise'); - } - - createProgrammingExercise() { - cy.get('#create-programming-exercise').click(); - } - - createModelingExercise() { - cy.get('#create-modeling-exercise').click(); - } - - createTextExercise() { - cy.get('#create-text-exercise').click(); - } - - createQuizExercise() { - cy.get('#create-quiz-button').click(); - } - - createFileUploadExercise() { - cy.get('#create-file-upload-exercise').click(); - } - - importProgrammingExercise() { - cy.get('#import-programming-exercise').click(); - } - - importModelingExercise() { - cy.get('#import-modeling-exercise').click(); - } - - importTextExercise() { - cy.get('#import-text-exercise').click(); - } - - importQuizExercise() { - cy.get('#import-quiz-exercise').click(); - } - - clickImportExercise(exerciseID: number) { - return cy.get(`.exercise-${exerciseID}`).find('.import').click(); - } - - startQuiz(quizID: number) { - cy.get(`#instructor-quiz-start-${quizID}`).click(); - } - - shouldContainExerciseWithName(exerciseID: number) { - this.getExercise(exerciseID).scrollIntoView().should('be.visible'); - } - - getModelingExerciseTitle(exerciseID: number) { - return cy.get(`#exercise-card-${exerciseID}`).find(`#modeling-exercise-${exerciseID}-title`); - } - - getModelingExerciseMaxPoints(exerciseID: number) { - return cy.get(`#exercise-card-${exerciseID}`).find(`#modeling-exercise-${exerciseID}-maxPoints`); - } -} diff --git a/src/test/cypress/support/pageobjects/course/CourseManagementPage.ts b/src/test/cypress/support/pageobjects/course/CourseManagementPage.ts deleted file mode 100644 index d18929b71b62..000000000000 --- a/src/test/cypress/support/pageobjects/course/CourseManagementPage.ts +++ /dev/null @@ -1,232 +0,0 @@ -import { Course } from 'app/entities/course.model'; - -import { COURSE_ADMIN_BASE, COURSE_BASE, DELETE, POST, PUT } from '../../constants'; -import { CypressCredentials } from '../../users'; - -/** - * A class which encapsulates UI selectors and actions for the course management page. - */ -export class CourseManagementPage { - openCourseCreation() { - return cy.get('#create-course').click(); - } - - openCourseEdit() { - return cy.get('#edit-course').click(); - } - - /** - * @returns Returns the cypress chainable containing the root element of the course card of our created course. - * This can be used to find specific elements within this course card. - */ - getCourse(courseID: number) { - return cy.get(`#course-${courseID}`); - } - - /** - * Opens the exercises (of the first found course). - */ - openExercisesOfCourse(courseID: number) { - this.getCourse(courseID).find('#course-card-open-exercises').click(); - cy.url().should('include', '/exercises'); - } - - /** - * Opens the students overview page of a course. - * @param courseId the id of the course - */ - openStudentOverviewOfCourse(courseId: number) { - cy.get(`#open-student-management-${courseId}`).click(); - } - - /** - * Opens a course. - * @param courseID - */ - openCourse(courseID: number) { - return this.getCourse(courseID).find('#course-card-header').click(); - } - - deleteCourse(course: Course) { - cy.get('#delete-course').click(); - cy.get('#delete').should('be.disabled'); - cy.get('#confirm-entity-name').type(course.title!); - cy.intercept(DELETE, `${COURSE_ADMIN_BASE}/${course.id}`).as('deleteCourse'); - cy.get('#delete').click(); - cy.wait('@deleteCourse'); - } - - /** - * Adds the user to the student group of the course - * @param credentials the user that gets added to the student group of the course - * */ - addStudentToCourse(credentials: CypressCredentials) { - cy.intercept(POST, `${COURSE_BASE}/*/students/${credentials.username}`).as('addStudentQuery'); - cy.get('#detail-value-artemisApp\\.course\\.studentGroupName').children().first().click({ force: true }); - this.confirmUserIntoGroup(credentials); - cy.wait('@addStudentQuery'); - } - - /** - * Adds the user to the tutor group of the course - * @param credentials the user that gets added to the tutor group of the course - * */ - addTutorToCourse(credentials: CypressCredentials) { - cy.intercept(POST, `${COURSE_BASE}/*/tutors/${credentials.username}`).as('addTutorsQuery'); - cy.get('#add-tutors').click(); - this.confirmUserIntoGroup(credentials); - cy.wait('@addTutorsQuery'); - } - - /** - * Adds the user to the editor group of the course - * @param credentials the user that gets added to the editor group of the course - * */ - addEditorToCourse(credentials: CypressCredentials) { - cy.intercept(POST, `${COURSE_BASE}/*/editors/${credentials.username}`).as('addEditorsQuery'); - cy.get('#add-editors').click(); - this.confirmUserIntoGroup(credentials); - cy.wait('@addEditorsQuery'); - } - - /** - * Adds the user to the instructor group of the course - * @param credentials the user that gets added to the instructor group of the course - * */ - addInstructorToCourse(credentials: CypressCredentials) { - cy.intercept(POST, `${COURSE_BASE}/*/instructors/${credentials.username}`).as('addInstructorQuery'); - cy.get('#add-instructors').click(); - this.confirmUserIntoGroup(credentials); - cy.wait('@addInstructorQuery'); - } - - removeFirstUser() { - cy.get('#registered-students button[jhideletebutton]').click(); - cy.get('.modal #delete').click(); - } - - clickEditCourse() { - cy.get('#edit-course').click(); - } - - updateCourse(course: Course) { - cy.intercept(PUT, `${COURSE_BASE}/${course.id}`).as('updateCourseQuery'); - cy.get('#save-entity').click(); - return cy.wait('@updateCourseQuery'); - } - - checkCourseHasNoIcon() { - cy.get('#delete-course-icon').should('not.exist'); - cy.get('.no-image').should('exist'); - } - - removeIconFromCourse() { - cy.get('#delete-course-icon').click(); - cy.get('#delete-course-icon').should('not.exist'); - cy.get('.no-image').should('exist'); - } - - /** - * helper method to avoid code duplication - * */ - private confirmUserIntoGroup(credentials: CypressCredentials) { - cy.get('#typeahead-basic ').type(credentials.username).type('{enter}'); - cy.get('#ngb-typeahead-0') - .contains(new RegExp('\\(' + credentials.username + '\\)')) - .click(); - cy.get('#bread-crumb-2').click(); - } - - /** - * Opens the exams of a course. - */ - openExamsOfCourse(courseID: number) { - this.getCourse(courseID).find('#course-card-open-exams').click(); - cy.url().should('include', '/exams'); - } - - openAssessmentDashboardOfCourse(courseID: number) { - this.getCourse(courseID).find('#course-card-open-assessment-dashboard').click(); - cy.url().should('include', '/assessment-dashboard'); - } - - /** - * helper methods to get information about the course - * */ - - getRegisteredStudents() { - return cy.get('#registered-students'); - } - - getCourseHeaderTitle() { - return cy.get('#course-header-title'); - } - - getCourseHeaderDescription() { - return cy.get('#course-header-description'); - } - - getCourseTitle() { - return cy.get('#detail-value-artemisApp\\.course\\.title'); - } - - getCourseShortName() { - return cy.get('#detail-value-artemisApp\\.course\\.shortName'); - } - - getCourseStudentGroupName() { - return cy.get('#detail-value-artemisApp\\.course\\.studentGroupName'); - } - - getCourseTutorGroupName() { - return cy.get('#detail-value-artemisApp\\.course\\.teachingAssistantGroupName'); - } - - getCourseEditorGroupName() { - return cy.get('#detail-value-artemisApp\\.course\\.editorGroupName'); - } - - getCourseInstructorGroupName() { - return cy.get('#detail-value-artemisApp\\.course\\.instructorGroupName'); - } - - getCourseStartDate() { - return cy.get('#detail-value-artemisApp\\.course\\.startDate'); - } - - getCourseEndDate() { - return cy.get('#detail-value-artemisApp\\.course\\.endDate'); - } - - getCourseSemester() { - return cy.get('#detail-value-artemisApp\\.course\\.semester'); - } - - getCourseProgrammingLanguage() { - return cy.get('#detail-value-artemisApp\\.course\\.defaultProgrammingLanguage'); - } - - getCourseTestCourse() { - return cy.get('#detail-value-artemisApp\\.course\\.testCourse\\.title'); - } - - getCourseOnlineCourse() { - return cy.get('#detail-value-artemisApp\\.course\\.onlineCourse\\.title'); - } - - getCourseMaxComplaints() { - return cy.get('#detail-value-artemisApp\\.course\\.maxComplaints\\.title'); - } - - getCourseMaxTeamComplaints() { - return cy.get('#detail-value-artemisApp\\.course\\.maxTeamComplaints\\.title'); - } - - getMaxComplaintTimeDays() { - return cy.get('#detail-value-artemisApp\\.course\\.maxComplaintTimeDays\\.title'); - } - - getMaxRequestMoreFeedbackTimeDays() { - return cy.get('#detail-value-artemisApp\\.course\\.maxRequestMoreFeedbackTimeDays\\.title'); - } -} diff --git a/src/test/cypress/support/pageobjects/course/CourseMessages.ts b/src/test/cypress/support/pageobjects/course/CourseMessages.ts deleted file mode 100644 index 721464317634..000000000000 --- a/src/test/cypress/support/pageobjects/course/CourseMessages.ts +++ /dev/null @@ -1,220 +0,0 @@ -import { COURSE_BASE, DELETE, POST, PUT } from '../../constants'; - -/** - * A class which encapsulates UI selectors and actions for the course messages page. - */ -export class CourseMessagesPage { - createChannelButton() { - cy.get('#channelButton').click(); - cy.get('#createChannel').click(); - } - - browseChannelsButton() { - cy.get('#channelButton').click(); - cy.get('#channelOverview').click(); - } - - browseExerciseChannelsButton() { - cy.get('#exerciseChannelButton').click(); - cy.get('#exerciseChannelOverview').click(); - } - - browseLectureChannelsButton() { - cy.get('#lectureChannelButton').click(); - cy.get('#lectureChannelOverview').click(); - } - - browseExamChannelsButton() { - cy.get('#examChannelButton').click(); - cy.get('#examChannelOverview').click(); - } - - checkChannelsExists(name: string) { - cy.get('.channels-overview').find('.list-group-item').contains(name); - } - - getChannelIdByName(name: string) { - return cy - .get('.channels-overview') - .find('.list-group-item') - .filter(`:contains("${name}")`) - .invoke('attr', 'id') - .then((id) => { - return id?.replace('channel-', ''); - }); - } - - joinChannel(channelID: number) { - cy.intercept(POST, `${COURSE_BASE}/*/channels/*/register`).as('joinChannel'); - cy.get(`#channel-${channelID}`).find(`#register${channelID}`).click({ force: true }); - cy.wait('@joinChannel'); - } - - leaveChannel(channelID: number) { - cy.intercept(POST, `${COURSE_BASE}/*/channels/*/deregister`).as('leaveChannel'); - cy.get(`#channel-${channelID}`).find(`#deregister${channelID}`).click({ force: true }); - cy.wait('@leaveChannel'); - } - - checkBadgeJoined(channelID: number) { - return cy.get(`#channel-${channelID}`).find('.badge'); - } - - setName(name: string) { - cy.get('.modal-content').find('#name').clear().type(name); - } - - setDescription(description: string) { - cy.get('.modal-content').find('#description').clear().type(description); - } - - setPrivate() { - cy.get('.modal-content').find('label[for=private]').click(); - } - - setPublic() { - cy.get('.modal-content').find('label[for=public]').click(); - } - - setAnnouncementChannel() { - cy.get('.modal-content').find('label[for=isAnnouncementChannel]').click(); - } - - setUnrestrictedChannel() { - cy.get('.modal-content').find('label[for=isNotAnnouncementChannel]').click(); - } - - createChannel(isAnnouncementChannel: boolean, isPublic: boolean) { - cy.intercept(POST, `${COURSE_BASE}/*/channels`).as('createChannel'); - cy.get('.modal-content').find('#submitButton').click(); - cy.wait('@createChannel').then((interception) => { - const response = interception.response!.body; - cy.url().should('contain', `messages?conversationId=${response.id}`); - expect(response.isAnnouncementChannel).to.eq(isAnnouncementChannel); - expect(response.isPublic).to.eq(isPublic); - }); - } - - getError() { - return cy.get('.modal-body').find('.alert'); - } - - getName() { - return cy.get('h4.d-inline-block'); - } - - getTopic() { - return cy.get('#conversation-topic'); - } - - editName(newName: string) { - cy.get('#name-section').find('.action-button').click(); - cy.get('.channels-overview').find('#name').clear().type(newName); - cy.get('#submitButton').click(); - } - - editTopic(newTopic: string) { - cy.get('#topic-section').find('.action-button').click(); - cy.get('.channels-overview').find('#topic').clear().type(newTopic); - cy.get('#submitButton').click(); - } - - editDescription(newDescription: string) { - cy.get('#description-section').find('.action-button').click(); - cy.get('.channels-overview').find('#description').type(newDescription); - cy.get('#submitButton').click(); - } - - closeEditPanel() { - cy.get('.conversation-detail-dialog').find('.btn-close').click(); - } - - writeMessage(message: string) { - cy.get('.markdown-editor').find('.ace_editor').click().type(message, { delay: 8 }); - } - - checkMessage(messageId: number, message: string) { - this.getSinglePost(messageId).find('.markdown-preview').contains(message); - } - - editMessage(messageId: number, message: string) { - this.getSinglePost(messageId).find('.editIcon').click(); - this.getSinglePost(messageId).find('.markdown-editor').find('.ace_editor').click().type(message, { delay: 8 }); - cy.intercept(PUT, `${COURSE_BASE}/*/messages/*`).as('updateMessage'); - this.getSinglePost(messageId).find('#save').click(); - cy.wait('@updateMessage'); - } - - deleteMessage(messageId: number) { - cy.intercept(DELETE, `${COURSE_BASE}/*/messages/*`).as('deleteMessage'); - this.getSinglePost(messageId).find('.deleteIcon').click(); - this.getSinglePost(messageId).find('.deleteIcon').click(); - cy.wait('@deleteMessage'); - } - - getSinglePost(postID: number) { - return cy.get(`#item-${postID}`); - } - - save(force = false) { - cy.intercept(POST, `${COURSE_BASE}/*/messages`).as('createMessage'); - cy.get('#save').click({ force }); - return cy.wait('@createMessage'); - } - - createGroupChatButton() { - cy.get('#createGroupChat').click(); - } - - createGroupChat() { - cy.intercept(POST, `${COURSE_BASE}/*/group-chats`).as('createGroupChat'); - cy.get('#submitButton').click(); - return cy.wait('@createGroupChat'); - } - - updateGroupChat() { - cy.intercept(POST, `${COURSE_BASE}/*/group-chats/*/register`).as('updateGroupChat'); - cy.get('#submitButton').click(); - cy.wait('@updateGroupChat'); - } - - addUserToGroupChat(user: string) { - cy.get('#users-selector0-user-input').type(user); - cy.get('#ngb-typeahead-0') - .contains(new RegExp('\\(' + user + '\\)')) - .click(); - } - - addUserToGroupChatButton() { - cy.get('.addUsers').click(); - } - - listMembersButton(courseID: number, conversationID: number) { - cy.visit(`/courses/${courseID}/messages?conversationId=${conversationID}`); - cy.get('.members').click(); - } - - checkMemberList(name: string) { - cy.get('jhi-conversation-members').contains(name); - } - - openSettingsTab() { - cy.get('.settings-tab').click(); - } - - leaveGroupChat() { - cy.get('.leave-conversation').click(); - } - - checkGroupChatExists(name: string, exist: boolean) { - if (exist) { - cy.get('.conversation-list').should('contain.text', name); - } else { - cy.get('.conversation-list').should('not.contain.text', name); - } - } - - acceptCodeOfConductButton() { - cy.get('#acceptCodeOfConductButton').click(); - } -} diff --git a/src/test/cypress/support/pageobjects/course/CourseOverviewPage.ts b/src/test/cypress/support/pageobjects/course/CourseOverviewPage.ts deleted file mode 100644 index f8abe30dae09..000000000000 --- a/src/test/cypress/support/pageobjects/course/CourseOverviewPage.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { BASE_API, GET } from '../../constants'; - -/** - * A class which encapsulates UI selectors and actions for the course overview page (/courses/*). - */ -export class CourseOverviewPage { - readonly participationRequestId = 'participateInExerciseQuery'; - - search(term: string): void { - cy.get('input[formcontrolname="searchFilter"]').type(term); - } - - startExercise(exerciseId: number, refreshInterval?: number) { - cy.reloadUntilFound('#start-exercise-' + exerciseId, refreshInterval); - cy.get('#start-exercise-' + exerciseId).click(); - } - - openRunningExercise(exerciseId: number) { - cy.reloadUntilFound('#open-exercise-' + exerciseId); - cy.get('#open-exercise-' + exerciseId).click(); - } - - getExercise(exerciseTitle: string) { - return cy.contains('#test-sidebar-card-medium', exerciseTitle); - } - - openExerciseOverview(exerciseTitle: string) { - this.getExercise(exerciseTitle).click(); - } - - getExercises() { - return cy.get('#test-sidebar-card-medium'); - } - - openRunningProgrammingExercise(exerciseID: number) { - cy.intercept(GET, `${BASE_API}/programming-exercise-participations/*/student-participation-with-latest-result-and-feedbacks`).as('initialQuery'); - this.openRunningExercise(exerciseID); - cy.wait('@initialQuery'); - } - - openExamsTab() { - cy.get('#exam-tab').click(); - } - - openExam(examId: number) { - cy.get('#exam-' + examId).click(); - } -} diff --git a/src/test/cypress/support/pageobjects/course/CoursesPage.ts b/src/test/cypress/support/pageobjects/course/CoursesPage.ts deleted file mode 100644 index ffffee9b859c..000000000000 --- a/src/test/cypress/support/pageobjects/course/CoursesPage.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * A class which encapsulates UI selectors and actions for the courses page (/courses). - */ -export class CoursesPage { - openCourse(courseId: number) { - cy.get(`#course-${courseId}-header`, { timeout: 30000 }).click(); - cy.url().should('include', '/exercises'); - } -} diff --git a/src/test/cypress/support/pageobjects/exam/ExamCreationPage.ts b/src/test/cypress/support/pageobjects/exam/ExamCreationPage.ts deleted file mode 100644 index e8be5a3a7a6c..000000000000 --- a/src/test/cypress/support/pageobjects/exam/ExamCreationPage.ts +++ /dev/null @@ -1,124 +0,0 @@ -import dayjs from 'dayjs/esm'; - -import { COURSE_BASE, POST, PUT } from '../../constants'; -import { enterDate } from '../../utils'; - -/** - * A class which encapsulates UI selectors and actions for the exam creation page. - */ -export class ExamCreationPage { - /** - * Sets the title of the exam. - * @param title the exam title - */ - setTitle(title: string) { - cy.get('#field_title').clear().type(title); - } - - /** - * Sets exam to test mode - */ - setTestMode() { - cy.get('#exam-mode-picker #test-mode').click(); - } - - /** - * @param date the date from when the exam should be visible - */ - setVisibleDate(date: dayjs.Dayjs) { - enterDate('#visibleDate', date); - } - - /** - * @param date the date when the exam starts - */ - setStartDate(date: dayjs.Dayjs) { - enterDate('#startDate', date); - } - - /** - * @param date the date when the exam will end - */ - setEndDate(date: dayjs.Dayjs) { - enterDate('#endDate', date); - } - - /** - * @param time the exam working time - */ - setWorkingTime(time: number) { - cy.get('#workingTimeInMinutes').clear().type(time.toString()); - } - - /** - * Sets the number of exercises in the exam. - * @param amount the amount of exercises - */ - setNumberOfExercises(amount: number) { - cy.get('#numberOfExercisesInExam').clear().type(amount.toString()); - } - - /** - * Sets the maximum achievable points in the exam. - * @param examMaxPoints the max points - */ - setExamMaxPoints(examMaxPoints: number) { - cy.get('#examMaxPoints').clear().type(examMaxPoints.toString()); - } - - /** - * Sets the start text of the exam. - * @param text the start text - */ - setStartText(text: string) { - this.enterText('#startText', text); - } - - /** - * Sets the end text of the exam. - * @param text the end text - */ - setEndText(text: string) { - this.enterText('#endText', text); - } - - /** - * Sets the confirmation start text of the exam. - * @param text the confirmation start text - */ - setConfirmationStartText(text: string) { - this.enterText('#confirmationStartText', text); - } - - /** - * Sets the confirmation end text of the exam. - * @param text the confirmation end text - */ - setConfirmationEndText(text: string) { - this.enterText('#confirmationEndText', text); - } - - /** - * Submits the created exam. - * @returns the query chainable if a test needs to access the response - */ - submit() { - cy.intercept(POST, `${COURSE_BASE}/*/exams`).as('createExamQuery'); - cy.get('#save-exam').click(); - return cy.wait('@createExamQuery'); - } - - /** - * Updates the created exam. - * @returns the query chainable if a test needs to access the response - */ - update() { - cy.intercept(PUT, `${COURSE_BASE}/*/exams`).as('updateExamQuery'); - cy.get('#save-exam').click(); - return cy.wait('@updateExamQuery'); - } - - private enterText(selector: string, text: string) { - cy.get(selector).find('.ace_text-input').focus().clear().type(text); - } -} diff --git a/src/test/cypress/support/pageobjects/exam/ExamDetailsPage.ts b/src/test/cypress/support/pageobjects/exam/ExamDetailsPage.ts deleted file mode 100644 index 79bf50ff997c..000000000000 --- a/src/test/cypress/support/pageobjects/exam/ExamDetailsPage.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * A class which encapsulates UI selectors and actions for the exam details page. - */ -export class ExamDetailsPage { - /** - * Deletes this exam. - * @param examTitle the exam title to confirm the deletion - */ - deleteExam(examTitle: string) { - cy.get('#exam-delete').click(); - cy.get('#delete').should('be.disabled'); - cy.get('#confirm-entity-name').type(examTitle); - cy.get('#delete').should('not.be.disabled').click(); - } -} diff --git a/src/test/cypress/support/pageobjects/exam/ExamExerciseGroupCreationPage.ts b/src/test/cypress/support/pageobjects/exam/ExamExerciseGroupCreationPage.ts deleted file mode 100644 index 8f88dad63292..000000000000 --- a/src/test/cypress/support/pageobjects/exam/ExamExerciseGroupCreationPage.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { Exam } from 'app/entities/exam.model'; - -import multipleChoiceTemplate from '../../../fixtures/exercise/quiz/multiple_choice/template.json'; -import { examAPIRequests, exerciseAPIRequest } from '../../artemis'; -import { AdditionalData, COURSE_BASE, ExerciseType, POST, PUT } from '../../constants'; -import { convertModelAfterMultiPart, generateUUID } from '../../utils'; -import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; -import { Exercise } from 'app/entities/exercise.model'; -import { Visibility } from 'app/entities/programming-exercise-test-case.model'; - -/** - * A class which encapsulates UI selectors and actions for the exam exercise group creation page. - */ -export class ExamExerciseGroupCreationPage { - typeTitle(title: string) { - cy.get('#title').clear().type(title); - } - - isMandatoryBoxShouldBeChecked() { - cy.get('#isMandatory').should('be.checked'); - } - - clickSave() { - cy.intercept({ method: POST, url: `${COURSE_BASE}/*/exams/*/exerciseGroups` }).as('createExerciseGroup'); - cy.get('#save-group').click(); - return cy.wait('@createExerciseGroup'); - } - - update() { - cy.intercept({ method: PUT, url: `${COURSE_BASE}/*/exams/*/exerciseGroups` }).as('updateExerciseGroup'); - cy.get('#save-group').click(); - cy.wait('@updateExerciseGroup'); - } - - addGroupWithExercise(exam: Exam, exerciseType: ExerciseType, additionalData: AdditionalData = {}): Promise { - return new Promise((resolve) => { - this.handleAddGroupWithExercise(exam, 'Exercise ' + generateUUID(), exerciseType, additionalData, (response) => { - let exercise = { ...response.body, additionalData }; - if (exerciseType == ExerciseType.QUIZ) { - const quiz = convertModelAfterMultiPart(response) as QuizExercise; - additionalData!.quizExerciseID = quiz.quizQuestions![0].id; - exercise = { ...quiz, additionalData }; - } - - if (exerciseType === ExerciseType.PROGRAMMING) { - const RETRY_NUMBER = 0; - exerciseAPIRequest.changeProgrammingExerciseTestVisibility(exercise, Visibility.Always, RETRY_NUMBER); - } - - resolve(exercise); - }); - }); - } - - handleAddGroupWithExercise(exam: Exam, title: string, exerciseType: ExerciseType, additionalData: AdditionalData, processResponse: (data: any) => void) { - examAPIRequests.addExerciseGroupForExam(exam).then((groupResponse) => { - switch (exerciseType) { - case ExerciseType.TEXT: - exerciseAPIRequest.createTextExercise({ exerciseGroup: groupResponse.body }, title).then((response) => { - processResponse(response); - }); - break; - case ExerciseType.MODELING: - exerciseAPIRequest.createModelingExercise({ exerciseGroup: groupResponse.body }, title).then((response) => { - processResponse(response); - }); - break; - case ExerciseType.QUIZ: - exerciseAPIRequest.createQuizExercise({ exerciseGroup: groupResponse.body }, [multipleChoiceTemplate], title).then((response) => { - processResponse(response); - }); - break; - case ExerciseType.PROGRAMMING: - exerciseAPIRequest - .createProgrammingExercise({ exerciseGroup: groupResponse.body, title, assessmentType: additionalData.progExerciseAssessmentType }) - .then((response) => { - processResponse(response); - }); - break; - } - }); - } -} diff --git a/src/test/cypress/support/pageobjects/exam/ExamExerciseGroupsPage.ts b/src/test/cypress/support/pageobjects/exam/ExamExerciseGroupsPage.ts deleted file mode 100644 index 1534a7f2f737..000000000000 --- a/src/test/cypress/support/pageobjects/exam/ExamExerciseGroupsPage.ts +++ /dev/null @@ -1,59 +0,0 @@ -/** - * A class which encapsulates UI selectors and actions for the exam exercise groups page. - */ -export class ExamExerciseGroupsPage { - clickCreateNewExerciseGroup() { - cy.get('#create-new-group').click(); - } - - shouldHaveTitle(groupID: number, groupTitle: string) { - cy.get(`#group-${groupID} .group-title`).contains(groupTitle); - } - - shouldNotExist(groupID: number) { - cy.get(`#group-${groupID}`).should('not.exist'); - } - - clickEditGroup(groupID: number) { - cy.get(`#group-${groupID} .edit-group`).click(); - } - - clickDeleteGroup(groupID: number, groupName: string) { - cy.get(`#group-${groupID} .delete-group`).click(); - cy.get('#delete').should('be.disabled'); - cy.get('#confirm-entity-name').type(groupName); - cy.get('#delete').should('not.be.disabled').click(); - } - - shouldShowNumberOfExerciseGroups(numberOfGroups: number) { - cy.get('#number-groups').should('contain.text', numberOfGroups); - } - - clickAddExerciseGroup() { - cy.get('#create-new-group').click(); - } - - clickAddTextExercise(groupID: number) { - cy.get(`#group-${groupID}`).find('.add-text-exercise').click(); - } - - clickAddModelingExercise(groupID: number) { - cy.get(`#group-${groupID}`).find('.add-modeling-exercise').click(); - } - - clickAddQuizExercise(groupID: number) { - cy.get(`#group-${groupID}`).find('.add-quiz-exercise').click(); - } - - clickAddProgrammingExercise(groupID: number) { - cy.get(`#group-${groupID}`).find('.add-programming-exercise').click(); - } - - visitPageViaUrl(courseId: number, examId: number) { - cy.visit(`course-management/${courseId}/exams/${examId}/exercise-groups`); - } - - shouldContainExerciseWithTitle(groupID: number, exerciseTitle: string) { - cy.get(`#group-${groupID}`).find('#exercises').contains(exerciseTitle).scrollIntoView().should('be.visible'); - } -} diff --git a/src/test/cypress/support/pageobjects/exam/ExamManagementPage.ts b/src/test/cypress/support/pageobjects/exam/ExamManagementPage.ts deleted file mode 100644 index a3d819025f8d..000000000000 --- a/src/test/cypress/support/pageobjects/exam/ExamManagementPage.ts +++ /dev/null @@ -1,136 +0,0 @@ -/** - * A class which encapsulates UI selectors and actions for the exam management page. - */ -export class ExamManagementPage { - /** - * Searches for an exam with the provided title. - * @param examTitle the title of the exam. - * @returns the row element of the found exam - */ - getExamRowRoot(examTitle: string) { - return this.getExamSelector(examTitle).parents('tr'); - } - - /** Opens the exam with this exam id. */ - openExam(examId: number) { - cy.get(`#exam-${examId}-title`).click(); - } - - /** - * Clicks the create new exam button. - */ - createNewExam() { - cy.get('#create-exam').click(); - } - - /** - * Returns the title element of the exam row. - * @param examTitle the title to search for - * @returns the element - */ - getExamSelector(examTitle: string) { - return cy.get('#exams-table').contains(examTitle); - } - - /** - * Opens the exercise groups page. - */ - openExerciseGroups(examId: number) { - cy.get(`#exercises-button-${examId}-groups`).click(); - } - - /** - * Opens the student registration page. - */ - openStudentRegistration(examId: number) { - cy.get(`#student-button-${examId}`).click(); - } - - /** - * Opens the student exams page. - */ - openStudentExams(examId: number) { - cy.get(`#student-exams-${examId}`).click(); - } - - /** - * Opens the exam assessment dashboard - * @param courseID the id of the course - * @param examID the id of the exam - * @param timeout how long to wait for the assessment dashboard button - */ - openAssessmentDashboard(courseID: number, examID: number, timeout = 60000) { - cy.visit(`/course-management/${courseID}/exams`); - cy.get(`#exercises-button-${examID}`, { timeout }).click(); - } - - /** - * Opens the test run page. - */ - openTestRun() { - cy.get(`#testrun-button`).click(); - } - - verifySubmitted(courseID: number, examID: number, username: string) { - cy.visit(`/course-management/${courseID}/exams/${examID}/student-exams`); - cy.get('#student-exam').find('.datatable-body-row').filter(`:contains("${username}")`).find('.submitted').contains('Yes'); - } - - checkQuizSubmission(courseID: number, examID: number, username: string, score: string) { - cy.visit(`/course-management/${courseID}/exams/${examID}/student-exams`); - cy.get('#student-exam').find('.datatable-body-row').filter(`:contains("${username}")`).find('.view-submission').click(); - cy.get('.summery').click(); - cy.get('#exercise-result-score').contains(score); - } - - clickEdit() { - cy.get('#editButton').click(); - } - - /** - * helper methods to get information of course - * */ - getExamTitle() { - return cy.get('#detail-value-artemisApp\\.exam\\.title'); - } - - getExamVisibleDate() { - return cy.get('#detail-value-artemisApp\\.examManagement\\.visibleDate'); - } - - getExamStartDate() { - return cy.get('#detail-value-artemisApp\\.exam\\.startDate'); - } - - getExamEndDate() { - return cy.get('#detail-value-artemisApp\\.exam\\.endDate'); - } - - getExamNumberOfExercises() { - return cy.get('#detail-value-artemisApp\\.examManagement\\.numberOfExercisesInExam'); - } - - getExamMaxPoints() { - return cy.get('#detail-value-artemisApp\\.examManagement\\.maxPoints\\.title'); - } - - getExamStartText() { - return cy.get('#detail-value-artemisApp\\.examManagement\\.startText'); - } - - getExamEndText() { - return cy.get('#detail-value-artemisApp\\.examManagement\\.endText'); - } - - getExamConfirmationStartText() { - return cy.get('#detail-value-artemisApp\\.examManagement\\.confirmationStartText'); - } - - getExamConfirmationEndText() { - return cy.get('#detail-value-artemisApp\\.examManagement\\.confirmationEndText'); - } - - getExamWorkingTime() { - return cy.get('#detail-value-artemisApp\\.exam\\.workingTime'); - } -} diff --git a/src/test/cypress/support/pageobjects/exam/ExamNavigationBar.ts b/src/test/cypress/support/pageobjects/exam/ExamNavigationBar.ts deleted file mode 100644 index f939546775d5..000000000000 --- a/src/test/cypress/support/pageobjects/exam/ExamNavigationBar.ts +++ /dev/null @@ -1,27 +0,0 @@ -/** - * A class which encapsulates UI selectors and actions for the navigation bar in an open exam. - */ -export class ExamNavigationBar { - /** - * Opens the exercise at the specified index. - * @param index 0-based index - */ - openExerciseAtIndex(index: number) { - cy.get('#exam-exercise-' + index).click(); - } - - openExerciseOverview() { - cy.get('.exam-navigation .navigation-item.overview').click(); - } - - /** - * Presses the hand in early button in the navigation bar. - */ - handInEarly() { - cy.get('#hand-in-early').click(); - } - - clickSave() { - cy.get('#save'); - } -} diff --git a/src/test/cypress/support/pageobjects/exam/ExamParticipation.ts b/src/test/cypress/support/pageobjects/exam/ExamParticipation.ts deleted file mode 100644 index 014ef3fbec4f..000000000000 --- a/src/test/cypress/support/pageobjects/exam/ExamParticipation.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { Interception } from 'cypress/types/net-stubbing'; - -import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; - -import { - courseList, - courseOverview, - examNavigation, - examStartEnd, - modelingExerciseEditor, - programmingExerciseEditor, - quizExerciseMultipleChoice, - textExerciseEditor, -} from '../../artemis'; -import { AdditionalData, ExerciseType } from '../../constants'; -import { CypressCredentials } from '../../users'; -import { getExercise } from '../../utils'; -import { ProgrammingExerciseSubmission } from '../exercises/programming/OnlineEditorPage'; - -/** - * A class which encapsulates UI selectors and actions for the exam details page. - */ -export class ExamParticipation { - /** - * Makes a submission in a provided exercise - * @param exerciseID the id of the exercise - * @param exerciseType the type of the exercise - * @param additionalData additional data such as the expected score - */ - makeSubmission(exerciseID: number, exerciseType: ExerciseType, additionalData?: AdditionalData) { - switch (exerciseType) { - case ExerciseType.TEXT: - this.makeTextExerciseSubmission(exerciseID, additionalData!.textFixture!); - break; - case ExerciseType.MODELING: - this.makeModelingExerciseSubmission(exerciseID); - break; - case ExerciseType.QUIZ: - this.makeQuizExerciseSubmission(exerciseID, additionalData!.quizExerciseID!); - break; - case ExerciseType.PROGRAMMING: - this.makeProgrammingExerciseSubmission(exerciseID, additionalData!.submission!, additionalData!.practiceMode); - break; - } - } - - makeTextExerciseSubmission(exerciseID: number, textFixture: string) { - cy.fixture(textFixture).then((submissionText) => { - textExerciseEditor.typeSubmission(exerciseID, submissionText); - }); - cy.wait(1000); - } - - private makeProgrammingExerciseSubmission(exerciseID: number, submission: ProgrammingExerciseSubmission, practiceMode = false) { - programmingExerciseEditor.toggleCompressFileTree(exerciseID); - programmingExerciseEditor.deleteFile(exerciseID, 'Client.java'); - programmingExerciseEditor.deleteFile(exerciseID, 'BubbleSort.java'); - programmingExerciseEditor.deleteFile(exerciseID, 'MergeSort.java'); - programmingExerciseEditor.typeSubmission(exerciseID, submission); - if (practiceMode) { - programmingExerciseEditor.submitPractice(exerciseID); - } else { - programmingExerciseEditor.submit(exerciseID); - } - programmingExerciseEditor.getResultScoreFromExercise(exerciseID).contains(submission.expectedResult).and('be.visible'); - } - - makeModelingExerciseSubmission(exerciseID: number) { - modelingExerciseEditor.addComponentToModel(exerciseID, 1, false); - modelingExerciseEditor.addComponentToModel(exerciseID, 2, false); - modelingExerciseEditor.addComponentToModel(exerciseID, 3, false); - } - - makeQuizExerciseSubmission(exerciseID: number, quizExerciseID: number) { - quizExerciseMultipleChoice.tickAnswerOption(exerciseID, 0, quizExerciseID); - quizExerciseMultipleChoice.tickAnswerOption(exerciseID, 2, quizExerciseID); - } - - openExam(student: CypressCredentials, course: Course, exam: Exam) { - cy.login(student, '/'); - cy.visit('/courses'); - courseList.openCourse(course.id!); - courseOverview.openExamsTab(); - courseOverview.openExam(exam.id!); - cy.url().should('contain', `/exams/${exam.id}`); - } - - startParticipation(student: CypressCredentials, course: Course, exam: Exam) { - this.openExam(student, course, exam); - examStartEnd.startExam(true); - } - - selectExerciseOnOverview(index: number) { - cy.get(`.exercise-table tr:nth-child(${index}) a`).click(); - } - - clickSaveAndContinue() { - cy.get('#save').click(); - } - - checkExerciseTitle(exerciseID: number, title: string) { - getExercise(exerciseID).find('.exercise-title').contains(title); - } - - checkExamTitle(title: string) { - cy.get('#exam-title').contains(title); - } - - getResultScore() { - cy.reloadUntilFound('#exercise-result-score'); - return cy.get('#exercise-result-score'); - } - - checkExamFinishedTitle(title: string) { - cy.get('#exam-finished-title').contains(title, { timeout: 40000 }); - } - - checkExamFullnameInputExists() { - cy.get('#fullname', { timeout: 20000 }).should('exist'); - } - - checkYourFullname(name: string) { - cy.get('#your-name', { timeout: 20000 }).contains(name); - } - - handInEarly() { - examNavigation.handInEarly(); - examStartEnd.finishExam().then((request: Interception) => { - expect(request.response!.statusCode).to.eq(200); - }); - } - - verifyExerciseTitleOnFinalPage(exerciseID: number, exerciseTitle: string) { - getExercise(exerciseID).find(`#exercise-group-title-${exerciseID}`).scrollIntoView(); - cy.get(`#exercise-group-title-${exerciseID}`).contains(exerciseTitle).should('be.visible'); - } - - verifyTextExerciseOnFinalPage(textFixture: string) { - cy.fixture(textFixture).then((submissionText) => { - cy.get('textarea').should('have.value', submissionText); - }); - } -} diff --git a/src/test/cypress/support/pageobjects/exam/ExamStartEndPage.ts b/src/test/cypress/support/pageobjects/exam/ExamStartEndPage.ts deleted file mode 100644 index 38c31ca197f1..000000000000 --- a/src/test/cypress/support/pageobjects/exam/ExamStartEndPage.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { COURSE_BASE, GET, POST } from '../../constants'; -import { users } from '../../users'; - -export class ExamStartEndPage { - enterFirstnameLastname() { - users.getAccountInfo((account: any) => cy.get('#fullname').type((account.firstName ?? '') + ' ' + (account.lastName ?? ''))); - } - - setConfirmCheckmark(timeout?: number) { - cy.get('#confirmBox', { timeout }).check(); - } - - pressStartWithWait() { - cy.intercept(GET, `${COURSE_BASE}/*/exams/*/student-exams/*/conduction`).as('startExam'); - cy.get('#start-exam').click(); - return cy.wait('@startExam'); - } - - pressStart() { - cy.get('#start-exam').click(); - } - - clickContinue() { - cy.get('#continue').click(); - } - - pressFinish() { - cy.intercept(POST, `${COURSE_BASE}/*/exams/*/student-exams/submit`).as('finishExam'); - cy.get('#end-exam').click(); - return cy.wait('@finishExam', { timeout: 10000 }); - } - - startExam(withWait = false) { - this.setConfirmCheckmark(); - this.enterFirstnameLastname(); - if (withWait) { - this.pressStartWithWait(); - } else { - this.pressStart(); - } - } - - finishExam(timeout?: number) { - this.setConfirmCheckmark(timeout ? timeout : Cypress.config('defaultCommandTimeout')); - this.enterFirstnameLastname(); - return this.pressFinish(); - } - - pressShowSummary() { - cy.intercept(GET, `${COURSE_BASE}/*/exams/*/student-exams/*/summary`).as('examSummaryDownload'); - cy.get('#showExamSummaryButton').should('be.visible').should('not.have.attr', 'disabled', { timeout: 15000 }).click(); - cy.wait('@examSummaryDownload'); - } -} diff --git a/src/test/cypress/support/pageobjects/exam/ExamTestRunPage.ts b/src/test/cypress/support/pageobjects/exam/ExamTestRunPage.ts deleted file mode 100644 index afb5056cfd4c..000000000000 --- a/src/test/cypress/support/pageobjects/exam/ExamTestRunPage.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; - -import { examStartEnd } from '../../artemis'; -import { COURSE_BASE, DELETE, PATCH, POST } from '../../constants'; -import { CypressCredentials } from '../../users'; - -/** - * A class which encapsulates UI selectors and actions for the exam details page. - */ -export class ExamTestRunPage { - /** - * Creates a test run - * @returns the query chainable if a test needs to access the response - */ - confirmTestRun() { - cy.intercept(POST, `${COURSE_BASE}/*/exams/*/test-run`).as('createTestRunQuery'); - cy.get('.modal-dialog #createTestRunButton').click(); - return cy.wait('@createTestRunQuery'); - } - - startParticipation(user: CypressCredentials, course: Course, exam: Exam, testRunId: number) { - cy.login(user); - this.openTestRunPage(course, exam); - this.startTestRun(testRunId); - cy.url().should('contain', `/course-management/${course.id}/exams/${exam.id}/test-runs/${testRunId}/conduction`); - examStartEnd.startExam(); - } - - createTestRun() { - cy.get('#createTestRunButton').click(); - } - - saveTestRun() { - cy.intercept(PATCH, `${COURSE_BASE}/*/exams/*/student-exams/*/working-time`).as('updateTestRunQuery'); - cy.get('#save').click(); - return cy.wait('@updateTestRunQuery'); - } - - getTestRun(testRunId: number) { - return cy.get(`#testrun-${testRunId}`); - } - - getTestRunRibbon() { - return cy.get('#testRunRibbon'); - } - - openTestRunPage(course: Course, exam: Exam) { - cy.visit('/course-management/' + course.id + '/exams/' + exam.id + '/test-runs'); - } - - setWorkingTimeHours(hours: number) { - cy.get('#workingTimeHours').clear().type(hours.toString()); - } - - setWorkingTimeMinutes(minutes: number) { - cy.get('#workingTimeMinutes').clear().type(minutes.toString()); - } - - setWorkingTimeSeconds(seconds: number) { - cy.get('#workingTimeSeconds').clear().type(seconds.toString()); - } - - getWorkingTime(testRunId: number) { - return this.getTestRun(testRunId).find('.working-time'); - } - - getStarted(testRunId: number) { - return this.getTestRun(testRunId).find('.started'); - } - - getSubmitted(testRunId: number) { - return this.getTestRun(testRunId).find('.submitted'); - } - - getTestRunIdElement(testRunId: number) { - return this.getTestRun(testRunId).find('.testrun-id'); - } - - changeWorkingTime(testRunId: number) { - cy.get(`#testrun-${testRunId}`).find('.manage-worktime').click(); - } - - startTestRun(testRunId: number) { - cy.get(`#testrun-${testRunId}`).find('.start-testrun').click(); - } - - deleteTestRun(testRunId: number) { - cy.get(`#testrun-${testRunId}`).find('.delete-testrun').click(); - cy.get('#confirm-entity-name').type('Test Run'); - cy.intercept(DELETE, `${COURSE_BASE}/*/exams/*/test-run/*`).as('deleteTestRunQuery'); - cy.get('#delete').click(); - return cy.wait('@deleteTestRunQuery'); - } -} diff --git a/src/test/cypress/support/pageobjects/exam/StudentExamManagementPage.ts b/src/test/cypress/support/pageobjects/exam/StudentExamManagementPage.ts deleted file mode 100644 index 58f6cb5d2ed8..000000000000 --- a/src/test/cypress/support/pageobjects/exam/StudentExamManagementPage.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { COURSE_BASE, POST } from '../../constants'; - -/** - * A class which encapsulates UI selectors and actions for the student exam management page. - */ -export class StudentExamManagementPage { - clickGenerateStudentExams() { - cy.intercept(POST, `${COURSE_BASE}/*/exams/*/generate-student-exams`).as('generateStudentExams'); - this.getGenerateStudentExamsButton().click(); - return cy.wait('@generateStudentExams'); - } - - clickRegisterCourseStudents() { - cy.intercept(POST, `${COURSE_BASE}/*/exams/*/register-course-students`).as('registerCourseStudents'); - cy.get('#register-course-students').click(); - return cy.wait('@registerCourseStudents'); - } - - getGenerateStudentExamsButton() { - return cy.get('#generateStudentExamsButton'); - } - - getRegisteredStudents() { - return cy.get('#registered-students'); - } - - checkExamStudent(username: string) { - return cy.get('#student-exam').find(`[href$="user-management/${username}"]`).should('have.length', 1); - } - - getStudentExamRows() { - return cy.get('#student-exam').find('.datatable-body-row'); - } - - getStudentExamRow(username: string) { - return cy.get('#student-exam').find(`a[href$="user-management/${username}"]`).closest('.datatable-body-row'); - } - - getExamProperty(username: string, property: string) { - cy.get('.datatable-header-cell').each(($headerCell, index) => { - if ($headerCell.text().includes(property)) { - this.getStudentExamRow(username).within(() => { - cy.get('.datatable-body-cell-label').eq(index).as('bodyCellLabel'); - }); - } - }); - return cy.get('@bodyCellLabel'); - } - - checkExamProperty(username: string, property: string, value: string) { - this.getExamProperty(username, property).contains(value); - } - - typeSearchText(text: string) { - cy.get('#typeahead-basic').focus().clear().type(text); - } -} diff --git a/src/test/cypress/support/pageobjects/exercises/AbstractExerciseFeedbackPage.ts b/src/test/cypress/support/pageobjects/exercises/AbstractExerciseFeedbackPage.ts deleted file mode 100644 index f98a9e74100e..000000000000 --- a/src/test/cypress/support/pageobjects/exercises/AbstractExerciseFeedbackPage.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Interception } from 'cypress/types/net-stubbing'; - -import { BASE_API, POST } from '../../constants'; - -/** - * Parent class for all exercise feedback pages (/course/./exercise/./participate/.) - */ -export abstract class AbstractExerciseFeedback { - readonly RESULT_SELECTOR = '#result'; - readonly ADDITIONAL_FEEDBACK_SELECTOR = '#additional-feedback'; - readonly COMPLAIN_BUTTON_SELECTOR = '#complain'; - - shouldShowAdditionalFeedback(points: number, feedbackText: string) { - if (Math.abs(points) === 1) { - cy.get(this.ADDITIONAL_FEEDBACK_SELECTOR).contains(`${points} Point: ${feedbackText}`).should('be.visible'); - } else { - cy.get(this.ADDITIONAL_FEEDBACK_SELECTOR).contains(`${points} Points: ${feedbackText}`).should('be.visible'); - } - } - - shouldShowScore(percentage: number) { - cy.get(this.RESULT_SELECTOR).contains(`${percentage}%`); - } - - complain(complaint: string) { - cy.reloadUntilFound(this.COMPLAIN_BUTTON_SELECTOR); - cy.get(this.COMPLAIN_BUTTON_SELECTOR).click(); - cy.get('#complainTextArea').type(complaint, { parseSpecialCharSequences: false }); - cy.intercept(POST, `${BASE_API}/complaints`).as('postComplaint'); - cy.get('#submit-complaint').click(); - return cy.wait('@postComplaint').then((request: Interception) => { - expect(request.response!.statusCode).to.eq(201); - }); - } -} diff --git a/src/test/cypress/support/pageobjects/exercises/ExerciseResultPage.ts b/src/test/cypress/support/pageobjects/exercises/ExerciseResultPage.ts deleted file mode 100644 index dde4299f3265..000000000000 --- a/src/test/cypress/support/pageobjects/exercises/ExerciseResultPage.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { BASE_API, GET } from '../../constants'; - -/** - * A class which encapsulates UI selectors and actions for the exercise result page. - */ -export class ExerciseResultPage { - shouldShowProblemStatement(problemStatement: string) { - cy.get('#problem-statement').contains(problemStatement).should('be.visible'); - } - - shouldShowExerciseTitle(title: string) { - cy.get('#exercise-header').contains(title).should('be.visible'); - } - - shouldShowScore(percentage: number) { - cy.reloadUntilFound('jhi-course-exercise-details #submission-result-graded'); - cy.contains('.tab-bar-exercise-details', `${percentage}%`).should('be.visible'); - } - - clickOpenExercise(exerciseId: number) { - cy.intercept(GET, `${BASE_API}/results/*/rating`).as('getResults'); - cy.get('#open-exercise-' + exerciseId).click(); - return cy.wait('@getResults'); - } - - clickOpenCodeEditor(exerciseId: number) { - cy.get('#open-exercise-' + exerciseId).click(); - } -} diff --git a/src/test/cypress/support/pageobjects/exercises/file-upload/FileUploadEditorPage.ts b/src/test/cypress/support/pageobjects/exercises/file-upload/FileUploadEditorPage.ts deleted file mode 100644 index b5762a614587..000000000000 --- a/src/test/cypress/support/pageobjects/exercises/file-upload/FileUploadEditorPage.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { EXERCISE_BASE, POST, PUT } from '../../../constants'; - -/** - * A class which encapsulates UI selectors and actions for the file upload editor page. - */ -export class FileUploadEditorPage { - attachFile(filePath: string) { - cy.get('#fileUploadInput').attachFile(filePath); - } - - attachFileExam(filePath: string) { - cy.get('#fileUploadInput').attachFile(filePath); - cy.get('#file-upload-submit').click(); - } - - /** - * Saves the file upload submission and continues to the next exercise in the exam. This button is only available in exam mode! - */ - saveAndContinue() { - cy.intercept(PUT, `${EXERCISE_BASE}/*/file-upload-submissions`).as('savedSubmission'); - cy.get('#save').click(); - return cy.wait('@savedSubmission'); - } - - submit() { - cy.intercept(POST, `${EXERCISE_BASE}/*/file-upload-submissions`).as('fileUploadSubmission'); - cy.get('#submit').click(); - return cy.wait('@fileUploadSubmission'); - } - - shouldShowExerciseTitleInHeader(exerciseTitle: string) { - cy.get('#participation-header').contains(exerciseTitle).should('be.visible'); - } - - shouldShowProblemStatement() { - cy.get('#problem-statement').should('be.visible'); - } -} diff --git a/src/test/cypress/support/pageobjects/exercises/file-upload/FileUploadExerciseCreationPage.ts b/src/test/cypress/support/pageobjects/exercises/file-upload/FileUploadExerciseCreationPage.ts deleted file mode 100644 index 21cfaecba175..000000000000 --- a/src/test/cypress/support/pageobjects/exercises/file-upload/FileUploadExerciseCreationPage.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { Dayjs } from 'dayjs/esm'; - -import { UPLOAD_EXERCISE_BASE } from '../../../constants'; -import { POST } from '../../../constants'; -import { enterDate } from '../../../utils'; - -/** - * A class which encapsulates UI selectors and actions for the file upload exercise creation page. - */ -export class FileUploadExerciseCreationPage { - /** - * @param title the title of the text exercise - */ - typeTitle(title: string) { - cy.get('#field_title').clear().type(title); - } - - setReleaseDate(date: Dayjs) { - enterDate('#pick-releaseDate', date); - } - - setDueDate(date: Dayjs) { - enterDate('#pick-dueDate', date); - } - - setAssessmentDueDate(date: Dayjs) { - enterDate('#pick-assessmentDueDate', date); - } - - typeMaxPoints(maxPoints: number) { - cy.get('#field_points').type(maxPoints.toString()); - } - - setFilePattern(pattern: string) { - this.typeText('#field_filePattern', pattern); - } - - typeProblemStatement(statement: string) { - this.typeText('#field_problemStatement', statement); - } - - typeExampleSolution(statement: string) { - this.typeText('#field_exampleSolution', statement); - } - - typeAssessmentInstructions(statement: string) { - this.typeText('#gradingInstructions', statement); - } - - create() { - cy.intercept(POST, UPLOAD_EXERCISE_BASE).as('fileUploadExerciseCreation'); - cy.get('#save-entity').click(); - return cy.wait('@fileUploadExerciseCreation'); - } - - private typeText(selector: string, text: string) { - cy.get(selector).find('.ace_content').type(text); - } -} diff --git a/src/test/cypress/support/pageobjects/exercises/file-upload/FileUploadExerciseFeedbackPage.ts b/src/test/cypress/support/pageobjects/exercises/file-upload/FileUploadExerciseFeedbackPage.ts deleted file mode 100644 index edb314a9f10e..000000000000 --- a/src/test/cypress/support/pageobjects/exercises/file-upload/FileUploadExerciseFeedbackPage.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { AbstractExerciseFeedback } from '../AbstractExerciseFeedbackPage'; - -/** - * A class which encapsulates UI selectors and actions for a file upload exercise feedback page. - */ -export class FileUploadExerciseFeedbackPage extends AbstractExerciseFeedback { - shouldShowTextFeedback(feedbackIndex: number, feedback: string) { - cy.get('#text-feedback-' + feedbackIndex) - .contains(feedback) - .should('be.visible'); - } -} diff --git a/src/test/cypress/support/pageobjects/exercises/modeling/CreateModelingExercisePage.ts b/src/test/cypress/support/pageobjects/exercises/modeling/CreateModelingExercisePage.ts deleted file mode 100644 index ab31ee707a7b..000000000000 --- a/src/test/cypress/support/pageobjects/exercises/modeling/CreateModelingExercisePage.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { Dayjs } from 'dayjs/esm'; - -import { MODELING_EXERCISE_BASE, POST } from '../../../constants'; -import { enterDate } from '../../../utils'; - -/** - * A class which encapsulates UI selectors and actions for the Modeling Exercise Creation Page. - * Path: /course-management/{courseID}/modeling-exercises/{exerciseID} - */ -export class CreateModelingExercisePage { - setTitle(title: string) { - cy.get('#field_title').clear().type(title); - } - - addCategories(categories: string[]) { - categories.forEach((category) => { - cy.get('#field_categories').type(category).type('{enter}'); - }); - } - - setPoints(points: number) { - cy.get('#field_points').clear().type(points.toString()); - } - - save() { - cy.intercept(MODELING_EXERCISE_BASE).as('createModelingExercise'); - cy.get('#save-entity').click(); - return cy.wait('@createModelingExercise'); - } - - import() { - cy.intercept(POST, `${MODELING_EXERCISE_BASE}/import/*`).as('modelingExerciseImport'); - cy.get('#save-entity').click(); - return cy.wait('@modelingExerciseImport'); - } - - /** - * Sets the release Date field - * @param date should be in Format: YYYY-MM-DDTHH:mm:ss.SSS - * */ - setReleaseDate(date: Dayjs) { - enterDate('#pick-releaseDate', date); - } - - /** - * Sets the Due Date field - * @param date should be in Format: YYYY-MM-DDTHH:mm:ss.SSS - * */ - setDueDate(date: Dayjs) { - enterDate('#pick-dueDate', date); - } - - /** - * Sets the Assessment Due Date field - * @param date should be in Format: YYYY-MM-DDTHH:mm:ss.SSS - * */ - setAssessmentDueDate(date: Dayjs) { - enterDate('#pick-assessmentDueDate', date); - } - - includeInOverallScore() { - cy.get('#modeling-includeInScore-picker').children().eq(0).children().eq(2).click({ force: true }); - } - - pickDifficulty(options: { hard?: boolean; medium?: boolean; easy?: boolean }) { - if (options.hard) { - this.getDiffifultyBar().children().eq(3).click(); - } else if (options.medium) { - this.getDiffifultyBar().children().eq(2).click(); - } else if (options.easy) { - this.getDiffifultyBar().children().eq(1).click(); - } else { - this.getDiffifultyBar().children().eq(0).click(); - } - } - - private getDiffifultyBar() { - return cy.get('#modeling-difficulty-picker').children().eq(0); - } -} diff --git a/src/test/cypress/support/pageobjects/exercises/modeling/ModelingEditor.ts b/src/test/cypress/support/pageobjects/exercises/modeling/ModelingEditor.ts deleted file mode 100644 index 1e052f6144aa..000000000000 --- a/src/test/cypress/support/pageobjects/exercises/modeling/ModelingEditor.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { EXERCISE_BASE, MODELING_EDITOR_CANVAS, PUT } from '../../../constants'; -import { getExercise } from '../../../utils'; - -import scrollBehaviorOptions = Cypress.scrollBehaviorOptions; - -/** - * This provides functions for interacting with the modeling editor - * */ -export class ModelingEditor { - /** - * Adds a Modeling Component to the Example Solution - * */ - addComponentToModel(exerciseID: number, componentNumber: number, scrollBehavior: scrollBehaviorOptions = 'center', x?: number, y?: number) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore https://github.com/4teamwork/cypress-drag-drop/issues/103 - getExercise(exerciseID) - .find('#modeling-editor-sidebar') - .children() - .eq(componentNumber) - .drag(`#exercise-${exerciseID} ${MODELING_EDITOR_CANVAS}`, { target: { x, y }, scrollBehavior, timeout: 1000 }); - getExercise(exerciseID).find(MODELING_EDITOR_CANVAS).trigger('pointerup'); - } - - getModelingCanvas() { - return cy.get('#modeling-editor-canvas'); - } - - addComponentToExampleSolutionModel(componentNumber: number, scrollBehavior: scrollBehaviorOptions = 'center') { - cy.get('#modeling-editor-sidebar').children().eq(componentNumber).drag(MODELING_EDITOR_CANVAS, { scrollBehavior, timeout: 1000 }); - cy.get(MODELING_EDITOR_CANVAS).trigger('mouseup').trigger('pointerup'); - } - - submit() { - cy.intercept(PUT, `${EXERCISE_BASE}/*/modeling-submissions`).as('createModelingSubmission'); - cy.get('#submit-modeling-submission').first().click(); - return cy.wait('@createModelingSubmission'); - } - - clickCreateNewExampleSubmission() { - cy.get('#new-modeling-example-submission').click(); - } - - clickCreateExampleSubmission() { - cy.get('#create-example-submission').click(); - } - - showExampleAssessment() { - cy.get('#show-modeling-example-assessment').click(); - } -} diff --git a/src/test/cypress/support/pageobjects/exercises/modeling/ModelingExerciseFeedbackPage.ts b/src/test/cypress/support/pageobjects/exercises/modeling/ModelingExerciseFeedbackPage.ts deleted file mode 100644 index d89dde814633..000000000000 --- a/src/test/cypress/support/pageobjects/exercises/modeling/ModelingExerciseFeedbackPage.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { AbstractExerciseFeedback } from '../AbstractExerciseFeedbackPage'; - -/** - * A class which encapsulates UI selectors and actions for a text exercise feedback page. - */ -export class ModelingExerciseFeedbackPage extends AbstractExerciseFeedback { - shouldShowComponentFeedback(component: number, points: number, feedback: string) { - cy.get('#component-feedback-table').children().eq(1).children().eq(component).should('contain.text', feedback).and('contain.text', `${points}`); - } -} diff --git a/src/test/cypress/support/pageobjects/exercises/programming/CodeAnalysisGradingPage.ts b/src/test/cypress/support/pageobjects/exercises/programming/CodeAnalysisGradingPage.ts deleted file mode 100644 index 06c6c17c6983..000000000000 --- a/src/test/cypress/support/pageobjects/exercises/programming/CodeAnalysisGradingPage.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { PATCH, PROGRAMMING_EXERCISE_BASE } from '../../../constants'; - -/** - * A class which encapsulates UI selectors and actions for static code analysis grading configuration page. - */ -export class CodeAnalysisGradingPage { - visit(courseId: number, exerciseId: number) { - cy.visit(`course-management/${courseId}/programming-exercises/${exerciseId}/grading/code-analysis`); - } - - makeEveryScaCategoryInfluenceGrading() { - // Using ids here would make the test more instable. Its unlikely that this selector will break in the future. - cy.get('select').each((category) => { - cy.wrap(category).select('GRADED'); - }); - } - - saveChanges() { - cy.intercept(PATCH, `${PROGRAMMING_EXERCISE_BASE}/*/static-code-analysis-categories`).as('scaConfigurationRequest'); - cy.get('#save-table-button').click(); - return cy.wait('@scaConfigurationRequest'); - } -} diff --git a/src/test/cypress/support/pageobjects/exercises/programming/OnlineEditorPage.ts b/src/test/cypress/support/pageobjects/exercises/programming/OnlineEditorPage.ts deleted file mode 100644 index 78df0503d47b..000000000000 --- a/src/test/cypress/support/pageobjects/exercises/programming/OnlineEditorPage.ts +++ /dev/null @@ -1,217 +0,0 @@ -import { courseList, courseOverview } from '../../../artemis'; -import { DELETE } from '../../../constants'; -import { BASE_API, POST } from '../../../constants'; -import { CypressCredentials } from '../../../users'; -import { getExercise } from '../../../utils'; - -/** - * A class which encapsulates UI selectors and actions for the Online Editor Page. - */ -export class OnlineEditorPage { - /** - * @param exerciseID the ID of the exercise - * @returns the root element of the file browser. Useful for further querying. - */ - findFileBrowser(exerciseID: number) { - return getExercise(exerciseID).find('#cardFiles'); - } - - /** - * Writes all the content in the corresponding files in the online editor. NOTE: This does not create non-existing files. - * It only opens existing files and writes the content there! - * @param exerciseID the ID of the exercise - * @param submission object which contains the information about which files need to be edited with what content - */ - typeSubmission(exerciseID: number, submission: ProgrammingExerciseSubmission) { - for (const newFile of submission.files) { - if (submission.createFilesInRootFolder) { - this.createFileInRootFolder(exerciseID, newFile.name); - } else { - this.createFileInRootPackage(exerciseID, newFile.name, submission.packageName!); - } - cy.fixture(newFile.path) - .then(($fileContent) => { - const clipboardData = new DataTransfer(); - const format = 'text/plain'; - clipboardData.setData(format, $fileContent); - const pasteEvent = new ClipboardEvent('paste', { clipboardData }); - const editorElement = getExercise(exerciseID).find('.view-lines').first(); - editorElement - .click() - .then((element) => { - element[0].dispatchEvent(pasteEvent); - }) - .wait(500); - }) - .wait(500); - } - cy.wait(500); - } - - /** - * Deletes a file in the filebrowser. - * @param exerciseID the ID of the exercise - * @param name the file name - */ - deleteFile(exerciseID: number, name: string) { - cy.intercept(DELETE, `${BASE_API}/repository/*/**`).as('deleteFile'); - this.findFile(exerciseID, name).find('#file-browser-file-delete').click(); - cy.get('#delete-file').click(); - cy.wait('@deleteFile').its('response.statusCode').should('eq', 200); - this.findFileBrowser(exerciseID).contains(name).should('not.exist'); - } - - /** - * @param exerciseID the ID of the exercise - * @param name the file name - * @returns the root element of a file in the filebrowser - */ - private findFile(exerciseID: number, name: string) { - return this.findFileBrowser(exerciseID).contains(name).parents('#file-browser-file'); - } - - /** - * Opens a file in the file browser by clicking on it. - */ - openFileWithName(exerciseID: number, name: string) { - this.findFile(exerciseID, name).click().wait(2000); - } - - /** - * Submits the currently saved files by clicking on the submit button and expect GRADED result label. - * @param exerciseID the ID of the exercise - */ - submit(exerciseID: number) { - getExercise(exerciseID).find('#submit_button').click(); - getExercise(exerciseID).find('#result-score-badge', { timeout: 200000 }).should('contain.text', 'GRADED').and('be.visible'); - } - - /** - * Submits the currently saved files by clicking on the submit button and expect PRACTICE result label. - * @param exerciseID the ID of the exercise - */ - submitPractice(exerciseID: number) { - getExercise(exerciseID).find('#submit_button').click(); - getExercise(exerciseID).find('#result-score-badge', { timeout: 200000 }).should('contain.text', 'PRACTICE').and('be.visible'); - } - - /** - * Creates a file at root level in the file browser. - * @param exerciseID the ID of the exercise - * @param fileName the name of the new file (e.g. "Policy.java") - */ - createFileInRootFolder(exerciseID: number, fileName: string) { - const postRequestId = 'createFile' + fileName; - const requestPath = `${BASE_API}/repository/*/file?file=${fileName}`; - getExercise(exerciseID).find('[id="create_file_root"]').click().wait(500); - cy.intercept(POST, requestPath).as(postRequestId); - getExercise(exerciseID).find('#file-browser-create-node').type(fileName).wait(500).type('{enter}'); - cy.wait('@' + postRequestId) - .its('response.statusCode') - .should('eq', 200); - this.findFileBrowser(exerciseID).contains(fileName).should('be.visible').wait(500); - } - - /** - * Creates a file at root level (in the main package) in the file browser. - * @param exerciseID the ID of the exercise - * @param fileName the name of the new file (e.g. "Policy.java") - * @param packageName the name of the package (e.g. "de.test") - */ - createFileInRootPackage(exerciseID: number, fileName: string, packageName: string) { - const packagePath = packageName.replace(/\./g, '/'); - const filePath = `src/${packagePath}/${fileName}`; - const postRequestId = 'createFile' + fileName; - const requestPath = `${BASE_API}/repository/*/file?file=${filePath}`; - getExercise(exerciseID).find('[id="file-browser-folder-create-file"]').eq(2).click().wait(500); - cy.intercept(POST, requestPath).as(postRequestId); - getExercise(exerciseID).find('#file-browser-create-node').type(fileName).wait(500).type('{enter}'); - cy.wait('@' + postRequestId) - .its('response.statusCode') - .should('eq', 200); - this.findFileBrowser(exerciseID).contains(fileName).should('be.visible').wait(500); - } - - /** - * @returns the root element of the result panel. This can be used for further querying inside this panel - */ - getResultPanel() { - return cy.get('#result'); - } - - /** - * @returns the element containing the result score percentage. - */ - getResultScore() { - cy.reloadUntilFound('#result-score'); - return cy.get('#result-score'); - } - - /** - * @param exerciseID the ID of the exercise - * @returns the element containing the result score percentage. - */ - getResultScoreFromExercise(exerciseID: number) { - return getExercise(exerciseID).find('#result-score'); - } - - /** - * @returns the root element of the panel, which shows the CI build output. - */ - getBuildOutput() { - return cy.get('#cardBuildOutput'); - } - - toggleCompressFileTree(exerciseID: number) { - return getExercise(exerciseID).find('#compress_tree').click(); - } - - /** - * General method for entering, submitting and verifying something in the online editor. - */ - makeSubmissionAndVerifyResults(exerciseID: number, submission: ProgrammingExerciseSubmission, verifyOutput: () => void) { - // Decompress the file tree to access the parent folder - this.toggleCompressFileTree(exerciseID); - // We delete all existing files, so we can create new files and don't have to delete their already existing content - for (const deleteFile of submission.deleteFiles) { - this.deleteFile(exerciseID, deleteFile); - } - this.typeSubmission(exerciseID, submission); - this.submit(exerciseID); - verifyOutput(); - } - - /** - * Starts the participation in the test programming exercise. - */ - startParticipation(courseId: number, exerciseId: number, credentials: CypressCredentials) { - // For shorter intervals, the reload may come before the app can render the elements. - const reloadInterval = 4000; - cy.login(credentials, '/'); - cy.url().should('include', '/courses'); - cy.log('Participating in the programming exercise as a student...'); - courseList.openCourse(courseId!); - cy.url().should('include', '/exercises'); - courseOverview.startExercise(exerciseId, reloadInterval); - cy.reloadUntilFound('#open-exercise-' + exerciseId, reloadInterval); - courseOverview.openRunningProgrammingExercise(exerciseId); - } -} - -/** - * A class which encapsulates a programming exercise submission taken from the k6 resources. - * - * @param files An array of containers, which contain the file path of the changed file as well as its name. - */ -export class ProgrammingExerciseSubmission { - deleteFiles: string[]; - createFilesInRootFolder: boolean; - files: ProgrammingExerciseFile[]; - expectedResult: string; - packageName?: string; -} - -class ProgrammingExerciseFile { - name: string; - path: string; -} diff --git a/src/test/cypress/support/pageobjects/exercises/programming/ProgrammingExerciseCreationPage.ts b/src/test/cypress/support/pageobjects/exercises/programming/ProgrammingExerciseCreationPage.ts deleted file mode 100644 index aba55301646a..000000000000 --- a/src/test/cypress/support/pageobjects/exercises/programming/ProgrammingExerciseCreationPage.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { POST, PROGRAMMING_EXERCISE_BASE, ProgrammingLanguage } from '../../../constants'; -import { Dayjs } from 'dayjs/esm'; - -const OWL_DATEPICKER_ARIA_LABEL_DATE_FORMAT = 'MMMM D, YYYY'; - -/** - * A class which encapsulates UI selectors and actions for the programming exercise creation page. - */ -export class ProgrammingExerciseCreationPage { - /** - * @param title the title of the programming exercise - */ - setTitle(title: string) { - cy.get('#field_title').clear().type(title); - } - - /** - * @param shortName the short name of the programming exercise - */ - setShortName(shortName: string) { - cy.get('#field_shortName').clear().type(shortName); - } - - /** - * @param programmingLanguage the programming language of the programming exercise - */ - setProgrammingLanguage(programmingLanguage: ProgrammingLanguage) { - cy.get('#field_programmingLanguage').select(programmingLanguage); - } - - /** - * @param packageName the package name of the programming exercise - */ - setPackageName(packageName: string) { - cy.get('#field_packageName').clear().type(packageName); - } - - /** - * @param points Achievable points in the exercise - */ - setPoints(points: number) { - cy.get('#field_points').clear().type(points.toString()); - } - - /** - * Allows the usage of the online editor. - */ - checkAllowOnlineEditor() { - cy.get('#field_allowOnlineEditor').check(); - } - - /** - * Generates the programming exercise. - * @returns the chainable of the request to make further verifications - */ - generate() { - cy.intercept(POST, `${PROGRAMMING_EXERCISE_BASE}/setup`).as('createProgrammingExercise'); - cy.get('#save-entity').click(); - // Creating a programming exercise can take quite a while, so we increase the default timeout here - return cy.wait('@createProgrammingExercise', { timeout: 60000 }); - } - - import() { - cy.intercept(POST, `${PROGRAMMING_EXERCISE_BASE}/import/*`).as('programmingExerciseImport'); - cy.get('#save-entity').click(); - // Creating a programming exercise can take quite a while, so we increase the default timeout here - return cy.wait('@programmingExerciseImport', { timeout: 60000 }); - } - - /** - * Sets the Due Date field by using the owl datepicker - * @param date - * */ - setDueDate(date: Dayjs) { - cy.get('#programming-exercise-due-date-picker').click(); - - // Makes sure that popup is visible before we choose a date - cy.get('.owl-dt-popup').should('be.visible'); - - const ariaLabelDate = date.format(OWL_DATEPICKER_ARIA_LABEL_DATE_FORMAT); - cy.get(`td[aria-label="${ariaLabelDate}"]`).click(); - - // There is a race condition, where an event listener already attaches and is ready to process the actual click on a date element - // but no event listener has been attached yet to close the modal. Thus, we need to keep clicking until the calendar modal is closed. - // Another idea would be to use cy.wait(), however it's not recommended by the developers. - // Cypress-pipe does not retry any Cypress commands so we need to click on the element using jQuery method "$el.trigger('click')" and not "cy.click()" - // See https://www.cypress.io/blog/2019/01/22/when-can-the-test-click for more information - const click = ($el: JQuery) => $el.trigger('click'); - - cy.get('.owl-dt-control-content.owl-dt-control-button-content') - .should('be.visible') - .contains('Set') - .pipe(click) - .should(($el) => { - expect($el).to.not.be.visible; - }); - } -} diff --git a/src/test/cypress/support/pageobjects/exercises/programming/ProgrammingExerciseFeedbackPage.ts b/src/test/cypress/support/pageobjects/exercises/programming/ProgrammingExerciseFeedbackPage.ts deleted file mode 100644 index 966f558dafa9..000000000000 --- a/src/test/cypress/support/pageobjects/exercises/programming/ProgrammingExerciseFeedbackPage.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { AbstractExerciseFeedback } from '../AbstractExerciseFeedbackPage'; -import { OnlineEditorPage } from './OnlineEditorPage'; - -/** - * A class which encapsulates UI selectors and actions for a programming exercise feedback page. - */ -export class ProgrammingExerciseFeedbackPage extends AbstractExerciseFeedback { - shouldShowAdditionalFeedback(points: number, feedbackText: string) { - cy.reloadUntilFound(this.ADDITIONAL_FEEDBACK_SELECTOR); - cy.get(this.ADDITIONAL_FEEDBACK_SELECTOR).contains(`${points} Points: ${feedbackText}`).should('be.visible'); - } - - shouldShowCodeFeedback(exerciseID: number, filename: string, feedback: string, points: string, editorPage: OnlineEditorPage) { - editorPage.openFileWithName(exerciseID, filename); - this.findVisibleInlineFeedback().contains(feedback).should('be.visible'); - this.findVisibleInlineFeedback().contains(`${points}P`).should('be.visible'); - } - - private findVisibleInlineFeedback() { - return cy.get('[id*="code-editor-inline-feedback-"]').should('be.visible'); - } - - shouldShowRepositoryLockedWarning() { - cy.get('#repository-locked-warning').should('be.visible'); - } -} diff --git a/src/test/cypress/support/pageobjects/exercises/programming/ScaFeedbackModal.ts b/src/test/cypress/support/pageobjects/exercises/programming/ScaFeedbackModal.ts deleted file mode 100644 index 14306c2a3fd5..000000000000 --- a/src/test/cypress/support/pageobjects/exercises/programming/ScaFeedbackModal.ts +++ /dev/null @@ -1,26 +0,0 @@ -/** - * A class which encapsulates UI selectors and actions for the static code analysis feedback modal in the online editor. - */ -export class ScaFeedbackModal { - shouldShowPointChart() { - cy.get('#feedback-chart').should('be.visible'); - } - - shouldShowCodeIssue(feedbackText: string, pointReduction: string) { - // This is a workaround to avoid Cypress only returning the first element matching the id - cy.get('.feedback-list') - .contains(feedbackText) - .scrollIntoView() - .should('be.visible') - .parents('.feedback-item') - .find('.feedback-item__credits') - .scrollIntoView() - .should('contain.text', `-${pointReduction}P`) - .and('be.visible'); - } - - closeModal() { - cy.get('.feedback-header__close').click(); - cy.get('.result-detail-container').should('not.exist'); - } -} diff --git a/src/test/cypress/support/pageobjects/exercises/quiz/DragAndDropQuiz.ts b/src/test/cypress/support/pageobjects/exercises/quiz/DragAndDropQuiz.ts deleted file mode 100644 index 07a3ec72439e..000000000000 --- a/src/test/cypress/support/pageobjects/exercises/quiz/DragAndDropQuiz.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { EXERCISE_BASE, MODELING_EDITOR_CANVAS, POST } from '../../../constants'; - -export class DragAndDropQuiz { - createDnDQuiz(title: string) { - cy.get('#quiz-import-apollon-dnd-question').should('be.visible').click(); - cy.get('#create-apollon-diagram').should('be.visible').click(); - cy.get('#field_diagram_title').type(title); - cy.get('#save-dnd-quiz').click(); - } - - dragItemIntoDragArea(itemIndex: number) { - cy.get('#drag-item-' + itemIndex).drag('#drop-location'); - } - - setTitle(title: string) { - cy.get('#field_title').type(title); - } - - /** - * Drags an element to the modeling editor canvas - * - * @param x drop location on X-axis - * @param y drop location on Y-axis - */ - dragUsingCoordinates(x: number, y: number) { - cy.get('#modeling-editor-sidebar').children().eq(2).drag(MODELING_EDITOR_CANVAS, { target: { x, y } }); - cy.wait(200); - cy.get(MODELING_EDITOR_CANVAS).trigger('pointerup'); - } - - /** - * Returns minimum and maximum X value of drop location elements - * - * @param $els selected drop location elements - */ - getXAxis($els: JQuery) { - let minX = Number.MAX_SAFE_INTEGER; - let maxX = Number.MIN_SAFE_INTEGER; - $els.each((index, el) => { - const rect = el.getBoundingClientRect(); - if (rect.x < minX) { - minX = rect.x; - } - if (rect.x + rect.width > maxX) { - maxX = rect.x + rect.width; - } - }); - return { minX, maxX }; - } - - activateInteractiveMode() { - const modelingEditorSidebar = cy.get('#modeling-editor-sidebar'); - const container = modelingEditorSidebar.children().eq(0); - const interactiveButton = container.children().eq(1); - interactiveButton.click(); - } - - markElementAsInteractive(nthElementOnCanvas: number, nthChildOfElement: number) { - cy.get(MODELING_EDITOR_CANVAS).children().children().children().eq(nthElementOnCanvas).children().eq(0).children().eq(nthChildOfElement).click(); - } - - generateQuizExercise() { - cy.get('#generate-quiz-exercise').click(); - cy.get('#quiz-save').should('be.visible'); - cy.wait(100); - cy.get('#quiz-save').click(); - } - - waitForQuizExerciseToBeGenerated() { - cy.get('#jhi-text-exercise-heading-edit').should('be.visible'); - } - - previewQuiz() { - cy.get('#preview-quiz').click(); - } - - waitForQuizPreviewToLoad() { - cy.get('.drag-and-drop-area').should('be.visible'); - cy.wait(200); - } - - submit() { - cy.intercept(POST, `${EXERCISE_BASE}/*/submissions/live`).as('createQuizExercise'); - cy.get('#submit-quiz').contains('Submit').click(); - return cy.wait('@createQuizExercise'); - } -} diff --git a/src/test/cypress/support/pageobjects/exercises/quiz/MultipleChoiceQuiz.ts b/src/test/cypress/support/pageobjects/exercises/quiz/MultipleChoiceQuiz.ts deleted file mode 100644 index d94e033d0306..000000000000 --- a/src/test/cypress/support/pageobjects/exercises/quiz/MultipleChoiceQuiz.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { EXERCISE_BASE, POST } from '../../../constants'; -import { getExercise } from '../../../utils'; - -export class MultipleChoiceQuiz { - tickAnswerOption(exerciseID: number, optionNumber: number, quizQuestionId = 0) { - getExercise(exerciseID) - .find('#question' + quizQuestionId) - .find('#answer-option-' + optionNumber) - .find('#mc-answer-selection-' + optionNumber) - .click(); - } - - submit() { - cy.intercept(POST, `${EXERCISE_BASE}/*/submissions/live`).as('createQuizExercise'); - cy.get('#submit-quiz').scrollIntoView(); - cy.get('#submit-quiz').click(); - return cy.wait('@createQuizExercise'); - } -} diff --git a/src/test/cypress/support/pageobjects/exercises/quiz/QuizExerciseCreationPage.ts b/src/test/cypress/support/pageobjects/exercises/quiz/QuizExerciseCreationPage.ts deleted file mode 100644 index c102704a3e0b..000000000000 --- a/src/test/cypress/support/pageobjects/exercises/quiz/QuizExerciseCreationPage.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { Dayjs } from 'dayjs/esm'; - -import { BASE_API, POST, QUIZ_EXERCISE_BASE } from '../../../constants'; -import { enterDate } from '../../../utils'; - -export class QuizExerciseCreationPage { - setTitle(title: string) { - cy.get('#field_title').type(title); - } - - setVisibleFrom(date: Dayjs) { - enterDate('#pick-releaseDate', date); - } - - addMultipleChoiceQuestion(title: string, points = 1) { - cy.get('#quiz-add-mc-question').click(); - cy.get('#mc-question-title').type(title); - cy.get('#score').clear().type(points.toString()); - cy.fixture('exercise/quiz/multiple_choice/question.txt').then((fileContent) => { - cy.get('.ace_text-input').focus().clear().type(fileContent); - }); - } - - addShortAnswerQuestion(title: string) { - cy.get('#quiz-add-short-answer-question').click(); - cy.get('#short-answer-question-title').type(title); - cy.fixture('exercise/quiz/short_answer/question.txt').then((fileContent) => { - cy.get('.ace_text-input').focus().clear().type(fileContent); - cy.get('#short-answer-show-visual').click(); - }); - } - - addDragAndDropQuestion(title: string) { - cy.get('#quiz-add-dnd-question').click(); - cy.get('#drag-and-drop-question-title').type(title); - this.uploadDragAndDropBackground().then(() => { - cy.wait(2000); - cy.get('.click-layer').trigger('mousedown', { x: 50, y: 50 }).trigger('mousemove', { x: 500, y: 300 }).trigger('mouseup'); - }); - this.createDragAndDropItem('Rick Astley'); - cy.get('#drag-item-0').drag('#drop-location'); - cy.fixture('exercise/quiz/drag_and_drop/question.txt').then((fileContent) => { - cy.get('.ace_text-input').focus().clear().type(fileContent); - }); - } - - createDragAndDropItem(text: string) { - cy.get('#add-text-drag-item').click(); - cy.get('#drag-item-0-text').clear().type(text); - } - - uploadDragAndDropBackground() { - cy.get('#background-image-input-form').children().eq(0).attachFile('exercise/quiz/drag_and_drop/background.jpg'); - cy.intercept(POST, `${BASE_API}/fileUpload*`).as('uploadBackground'); - cy.get('#background-image-input-form').children().eq(1).click(); - return cy.wait('@uploadBackground'); - } - - /** - * @return the response of the request - */ - saveQuiz() { - cy.intercept(POST, QUIZ_EXERCISE_BASE).as('createQuizExercise'); - cy.get('#quiz-save').click(); - return cy.wait('@createQuizExercise'); - } - - import() { - cy.intercept(POST, `${QUIZ_EXERCISE_BASE}/import/*`).as('quizExerciseImport'); - cy.get('#quiz-save').click(); - return cy.wait('@quizExerciseImport'); - } -} diff --git a/src/test/cypress/support/pageobjects/exercises/quiz/ShortAnswerQuiz.ts b/src/test/cypress/support/pageobjects/exercises/quiz/ShortAnswerQuiz.ts deleted file mode 100644 index a4003d260067..000000000000 --- a/src/test/cypress/support/pageobjects/exercises/quiz/ShortAnswerQuiz.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { EXERCISE_BASE, POST } from '../../../constants'; - -export class ShortAnswerQuiz { - getQuizBody() { - return cy.get('#question0').children().first(); - } - - typeAnswer(line: number, column: number, quizQuestionId: number, answer: string) { - this.getQuizBody().find(`#solution-${line}-${column}-${quizQuestionId}`).type(answer); - } - - submit() { - cy.intercept(POST, `${EXERCISE_BASE}/*/submissions/live`).as('createQuizExercise'); - cy.get('#submit-quiz').scrollIntoView(); - cy.get('#submit-quiz').click(); - return cy.wait('@createQuizExercise'); - } -} diff --git a/src/test/cypress/support/pageobjects/exercises/text/TextEditorPage.ts b/src/test/cypress/support/pageobjects/exercises/text/TextEditorPage.ts deleted file mode 100644 index aa53321732c2..000000000000 --- a/src/test/cypress/support/pageobjects/exercises/text/TextEditorPage.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { EXERCISE_BASE, PUT } from '../../../constants'; -import { getExercise } from '../../../utils'; - -/** - * A class which encapsulates UI selectors and actions for the text editor page. - */ -export class TextEditorPage { - typeSubmission(exerciseID: number, submission: string) { - getExercise(exerciseID).find('#text-editor').type(submission, { parseSpecialCharSequences: false }); - } - - clearSubmission(exerciseID: number) { - getExercise(exerciseID).find('#text-editor').clear(); - } - - checkCurrentContent(exerciseID: number, expectedContent: string) { - cy.fixture(expectedContent).then((text) => { - getExercise(exerciseID).find('#text-editor').should('have.value', text); - }); - } - - /** - * Saves the text submission and continues to the next exercise in the exam. This button is only available in exam mode! - */ - saveAndContinue() { - cy.intercept(PUT, `${EXERCISE_BASE}/*/text-submissions`).as('savedSubmission'); - cy.get('#save').click(); - return cy.wait('@savedSubmission'); - } - - submit() { - cy.intercept(PUT, `${EXERCISE_BASE}/*/text-submissions`).as('textSubmission'); - cy.get('#submit button').click(); - return cy.wait('@textSubmission'); - } - - shouldShowExerciseTitleInHeader(exerciseTitle: string) { - cy.get('#participation-header').contains(exerciseTitle).should('be.visible'); - } - - shouldShowProblemStatement() { - cy.get('#problem-statement').should('be.visible'); - } - - shouldShowNumberOfWords(numberOfWords: number) { - cy.get('#word-count').should('contain.text', numberOfWords).and('be.visible'); - } - - shouldShowNumberOfCharacters(numberOfWords: number) { - cy.get('#character-count').should('contain.text', numberOfWords).and('be.visible'); - } -} diff --git a/src/test/cypress/support/pageobjects/exercises/text/TextExerciseCreationPage.ts b/src/test/cypress/support/pageobjects/exercises/text/TextExerciseCreationPage.ts deleted file mode 100644 index 20c01d7f6b52..000000000000 --- a/src/test/cypress/support/pageobjects/exercises/text/TextExerciseCreationPage.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { Dayjs } from 'dayjs/esm'; - -import { TEXT_EXERCISE_BASE } from '../../../constants'; -import { POST } from '../../../constants'; -import { enterDate } from '../../../utils'; - -/** - * A class which encapsulates UI selectors and actions for the text exercise creation page. - */ -export class TextExerciseCreationPage { - /** - * @param title the title of the text exercise - */ - typeTitle(title: string) { - cy.get('#field_title').clear().type(title); - } - - setReleaseDate(date: Dayjs) { - enterDate('#pick-releaseDate', date); - } - - setDueDate(date: Dayjs) { - enterDate('#pick-dueDate', date); - } - - setAssessmentDueDate(date: Dayjs) { - enterDate('#pick-assessmentDueDate', date); - } - - typeMaxPoints(maxPoints: number) { - cy.get('#field_points').type(maxPoints.toString()); - } - - typeProblemStatement(statement: string) { - this.typeText('#problemStatement', statement); - } - - typeExampleSolution(statement: string) { - this.typeText('#exampleSolution', statement); - } - - typeAssessmentInstructions(statement: string) { - this.typeText('#gradingInstructions', statement); - } - - create() { - cy.intercept(POST, TEXT_EXERCISE_BASE).as('textExerciseCreation'); - cy.get('#save-entity').click(); - return cy.wait('@textExerciseCreation'); - } - - import() { - cy.intercept(POST, `${TEXT_EXERCISE_BASE}/import/*`).as('textExerciseImport'); - cy.get('#save-entity').click(); - return cy.wait('@textExerciseImport'); - } - - private typeText(selector: string, text: string) { - cy.get(selector).find('.ace_content').type(text); - } -} diff --git a/src/test/cypress/support/pageobjects/exercises/text/TextExerciseExampleSubmissionCreationPage.ts b/src/test/cypress/support/pageobjects/exercises/text/TextExerciseExampleSubmissionCreationPage.ts deleted file mode 100644 index 812c7d63b998..000000000000 --- a/src/test/cypress/support/pageobjects/exercises/text/TextExerciseExampleSubmissionCreationPage.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { EXERCISE_BASE, POST } from '../../../constants'; - -/** - * A class which encapsulates UI selectors and actions for the text exercise example submission creation page. - */ -export class TextExerciseExampleSubmissionCreationPage { - getInstructionsRootElement() { - return cy.get('#instructions'); - } - - typeExampleSubmission(example: string) { - cy.get('#example-text-submission-input').type(example, { parseSpecialCharSequences: false }); - } - - clickCreateNewExampleSubmission() { - cy.intercept(POST, `${EXERCISE_BASE}/*/example-submissions`).as('createExampleSubmission'); - cy.get('#create-example-submission').click(); - return cy.wait('@createExampleSubmission'); - } - - showsExerciseTitle(exerciseTitle: string) { - this.getInstructionsRootElement().contains(exerciseTitle).should('be.visible'); - } - - showsProblemStatement(problemStatement: string) { - this.getInstructionsRootElement().contains(problemStatement).should('be.visible'); - } - - showsExampleSolution(exampleSolution: string) { - this.getInstructionsRootElement().contains(exampleSolution).should('be.visible'); - } -} diff --git a/src/test/cypress/support/pageobjects/exercises/text/TextExerciseExampleSubmissionsPage.ts b/src/test/cypress/support/pageobjects/exercises/text/TextExerciseExampleSubmissionsPage.ts deleted file mode 100644 index 33be82d683c5..000000000000 --- a/src/test/cypress/support/pageobjects/exercises/text/TextExerciseExampleSubmissionsPage.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * A class which encapsulates UI selectors and actions for the text exercise example submissions page. - */ -export class TextExerciseExampleSubmissionsPage { - clickCreateExampleSubmission() { - cy.get('#create-example-submission').click(); - } -} diff --git a/src/test/cypress/support/pageobjects/exercises/text/TextExerciseFeedbackPage.ts b/src/test/cypress/support/pageobjects/exercises/text/TextExerciseFeedbackPage.ts deleted file mode 100644 index 2ebb6d738ee7..000000000000 --- a/src/test/cypress/support/pageobjects/exercises/text/TextExerciseFeedbackPage.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { AbstractExerciseFeedback } from '../AbstractExerciseFeedbackPage'; - -/** - * A class which encapsulates UI selectors and actions for a text exercise feedback page. - */ -export class TextExerciseFeedbackPage extends AbstractExerciseFeedback { - shouldShowTextFeedback(feedbackIndex: number, feedback: string) { - cy.get('#text-feedback-' + feedbackIndex) - .contains(feedback) - .should('be.visible'); - } -} diff --git a/src/test/cypress/support/pageobjects/lecture/LectureCreationPage.ts b/src/test/cypress/support/pageobjects/lecture/LectureCreationPage.ts deleted file mode 100644 index 7415fef89ade..000000000000 --- a/src/test/cypress/support/pageobjects/lecture/LectureCreationPage.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Dayjs } from 'dayjs/esm'; - -import { BASE_API, POST } from '../../constants'; - -export class LectureCreationPage { - setTitle(title: string) { - cy.get('#field_title').type(title); - } - - save() { - cy.intercept(POST, `${BASE_API}/lectures`).as('createLecture'); - cy.get('#save-entity').click(); - return cy.wait('@createLecture'); - } - - typeDescription(description: string) { - cy.get('.ace_content').type(description, { parseSpecialCharSequences: false }); - } - - setVisibleDate(date: Dayjs) { - cy.get('#visible-date').find('#date-input-field').type(date.toString()); - } - - setStartDate(date: Dayjs) { - cy.get('#start-date').find('#date-input-field').type(date.toString()); - } - - setEndDate(date: Dayjs) { - cy.get('#end-date').find('#date-input-field').type(' ').clear().type(date.toString()); - } -} diff --git a/src/test/cypress/support/pageobjects/lecture/LectureManagementPage.ts b/src/test/cypress/support/pageobjects/lecture/LectureManagementPage.ts deleted file mode 100644 index 215e2122afbc..000000000000 --- a/src/test/cypress/support/pageobjects/lecture/LectureManagementPage.ts +++ /dev/null @@ -1,73 +0,0 @@ -import dayjs from 'dayjs/esm'; - -import { Lecture } from 'app/entities/lecture.model'; - -import { BASE_API, DELETE, POST } from '../../constants'; - -export class LectureManagementPage { - clickCreateLecture() { - cy.get('#jh-create-entity').click(); - } - - deleteLecture(lecture: Lecture) { - this.getLecture(lecture.id!).find('#delete-lecture').click(); - cy.get('#delete').should('be.disabled'); - cy.get('#confirm-entity-name').type(lecture.title!); - cy.intercept(DELETE, `${BASE_API}/lectures/*`).as('deleteLecture'); - cy.get('#delete').click(); - return cy.wait('@deleteLecture'); - } - - getLectures() { - return cy.get('#lectures'); - } - - getLecture(lectureId: number) { - return cy.get(`#lecture-${lectureId}`); - } - - getLectureContainer() { - return cy.get('#lecture-preview'); - } - - openUnitsPage(lectureId: number) { - this.getLecture(lectureId).find('#units').click(); - } - - openCreateUnit(type: UnitType) { - this.getUnitCreationCard().find(type).click(); - } - - getUnitCreationCard() { - return cy.get('#unit-creation'); - } - - addTextUnit(name: string, text: string, releaseDate = dayjs()) { - this.openCreateUnit(UnitType.TEXT); - cy.get('#name').type(name); - cy.get('#pick-releaseDate').find('#date-input-field').type(releaseDate.toString()); - cy.get('.ace_content').type(text, { parseSpecialCharSequences: false }); - return this.submitUnit(); - } - - addExerciseUnit(exerciseId: number) { - this.openCreateUnit(UnitType.EXERCISE); - const exerciseRow = '#exercise-' + exerciseId; - cy.reloadUntilFound(exerciseRow); - cy.get(exerciseRow).click(); - return this.submitUnit('#createButton'); - } - - submitUnit(buttonId = '#submitButton') { - cy.intercept(POST, `${BASE_API}/lectures/*/*`).as('createUnit'); - cy.get(buttonId).click(); - return cy.wait('@createUnit'); - } -} - -enum UnitType { - TEXT = '#createTextUnitButton', - EXERCISE = '#createExerciseUnitButton', - VIDEO = '#createVideoUnitButton', - FILE = '#createFileUploadUnitButton', -} diff --git a/src/test/cypress/support/requests/ArtemisRequests.ts b/src/test/cypress/support/requests/ArtemisRequests.ts deleted file mode 100644 index 6172cd6fc253..000000000000 --- a/src/test/cypress/support/requests/ArtemisRequests.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { CommunicationAPIRequests } from './CommunicationAPIRequests'; -import { CourseManagementAPIRequests } from './CourseManagementAPIRequests'; -import { ExamAPIRequests } from './ExamAPIRequests'; -import { ExerciseAPIRequests } from './ExerciseAPIRequests'; -import { UserManagementAPIRequests } from './UserManagementAPIRequest'; - -/** - * A class which encapsulates all cypress requests, which can be sent to Artemis. - */ -export class ArtemisRequests { - communication = new CommunicationAPIRequests(); - courseManagement = new CourseManagementAPIRequests(); - exam = new ExamAPIRequests(); - exercise = new ExerciseAPIRequests(); - userManagement = new UserManagementAPIRequests(); -} diff --git a/src/test/cypress/support/requests/CommunicationAPIRequests.ts b/src/test/cypress/support/requests/CommunicationAPIRequests.ts deleted file mode 100644 index c405b574d7cf..000000000000 --- a/src/test/cypress/support/requests/CommunicationAPIRequests.ts +++ /dev/null @@ -1,246 +0,0 @@ -import { Course } from 'app/entities/course.model'; -import { Exercise } from 'app/entities/exercise.model'; -import { Lecture } from 'app/entities/lecture.model'; -import { ChannelDTO, getAsChannelDTO } from 'app/entities/metis/conversation/channel.model'; -import { GroupChat } from 'app/entities/metis/conversation/group-chat.model'; -import { Post } from 'app/entities/metis/post.model'; - -import { COURSE_BASE, GET, POST, PUT } from '../constants'; -import { CypressCredentials } from '../users'; -import { ConversationDTO } from 'app/entities/metis/conversation/conversation.model'; -import Chainable = Cypress.Chainable; - -/** - * A class which encapsulates all API requests related to communications. - */ -export class CommunicationAPIRequests { - /** - * Creates a new course post. - * - * @param course - The course to which the post belongs. - * @param content - The content of the post. - * @param channel - The channel the post belongs to - * @returns A Cypress.Chainable> representing the API request response. - */ - createCoursePost(course: Course, content: string, channel: ChannelDTO) { - const body = { - content, - course: { - id: course.id, - title: course.title, - }, - conversation: { - id: channel.id, - type: channel.type, - }, - displayPriority: 'NONE', - visibleForStudents: true, - }; - return cy.request({ method: POST, url: `${COURSE_BASE}/${course.id}/messages`, body }); - } - - /** - * Creates a new course message channel. - * - * @param course - The course to which the message channel belongs. - * @param name - The name of the message channel. - * @param description - The description of the message channel. - * @param isAnnouncementChannel - Set to true if the channel is an announcement channel. - * @param isPublic - Set to true if the channel is public. - * @returns A Cypress.Chainable> representing the API request response. - */ - createCourseMessageChannel(course: Course, name: string, description: string, isAnnouncementChannel: boolean, isPublic: boolean) { - const body = { - description, - isAnnouncementChannel, - isPublic, - name, - type: 'channel', - }; - return cy.request({ method: POST, url: `${COURSE_BASE}/${course.id}/channels`, body }); - } - - /** - * Get course-wide channels of a course - * - * @param courseId - The id of the course - * @returns A Cypress.Chainable with the course-wide channels of the course - */ - getCourseWideChannels(courseId: number): Chainable { - return cy - .request({ method: GET, url: `${COURSE_BASE}/${courseId}/conversations` }) - .then((response) => response.body.filter((conv: ConversationDTO) => getAsChannelDTO(conv)?.isCourseWide === true)); - } - - /** - * Retrieves the exercise channel for a given course and exercise. - * - * @param courseId - The ID of the course. - * @param exerciseId - The ID of the exercise. - * @returns A Cypress.Chainable> representing the API request response. - */ - getExerciseChannel(courseId: number, exerciseId: number) { - return cy.request({ method: GET, url: `${COURSE_BASE}/${courseId}/exercises/${exerciseId}/channel` }); - } - - /** - * Retrieves the lecture channel for a given course and lecture. - * - * @param courseId - The ID of the course. - * @param lectureId - The ID of the lecture. - * @returns A Cypress.Chainable> representing the API request response. - */ - getLectureChannel(courseId: number, exerciseId: number) { - return cy.request({ method: GET, url: `${COURSE_BASE}/${courseId}/lectures/${exerciseId}/channel` }); - } - - /** - * Creates a new course message group chat. - * - * @param course - The course to which the group chat belongs. - * @param users - An array of usernames of users to add to the group chat. - * @returns A Cypress.Chainable> representing the API request response. - */ - createCourseMessageGroupChat(course: Course, users: Array) { - const body = users; - return cy.request({ method: POST, url: `${COURSE_BASE}/${course.id}/group-chats`, body }); - } - - /** - * Creates a new course message. - * - * @param course - The course to which the message belongs. - * @param targetId - The ID of the conversation target (channel or group chat). - * @param type - The type of conversation target (e.g., 'channel' or 'groupChat'). - * @param message - The content of the message. - * @returns A Cypress.Chainable> representing the API request response. - */ - createCourseMessage(course: Course, targetId: number, type: string, message: string) { - const body = { - content: message, - conversation: { - id: targetId, - type, - }, - displayPriority: 'NONE', - visibleForStudents: true, - }; - return cy.request({ method: POST, url: `${COURSE_BASE}/${course.id}/messages`, body }); - } - - /** - * Creates a new course message. - * - * @param course - The course to which the message belongs. - * @param targetId - The ID of the conversation target channel. - * @param message - The content of the message. - * @returns A Cypress.Chainable> representing the API request response. - */ - createCourseWideMessage(course: Course, targetId: number, message: string) { - const body = { - content: message, - conversation: { - id: targetId, - type: 'channel', - }, - displayPriority: 'NONE', - visibleForStudents: true, - }; - return cy.request({ method: POST, url: `${COURSE_BASE}/${course.id}/messages`, body }); - } - - /** - * Updates the name of a course message group chat. - * - * @param course - The course to which the group chat belongs. - * @param groupChat - The group chat to update. - * @param name - The new name of the group chat. - * @returns A Cypress.Chainable> representing the API request response. - */ - updateCourseMessageGroupChatName(course: Course, groupChat: GroupChat, name: string) { - const body = { - name, - type: 'groupChat', - }; - return cy.request({ method: PUT, url: `${COURSE_BASE}/${course.id}/group-chats/${groupChat.id}`, body }); - } - - /** - * Joins a user into a channel. - * - * @param course - The course to which the channel belongs. - * @param channelId - The id of the channel to join. - * @param user - The user's credentials. - * @returns A Cypress.Chainable> representing the API request response. - */ - joinUserIntoChannel(course: Course, channelId: number, user: CypressCredentials) { - const body = [user.username]; - return cy.request({ method: POST, url: `${COURSE_BASE}/${course.id}/channels/${channelId}/register`, body }); - } - - /** - * Creates a new course post reply. - * - * @param course - The course to which the post belongs. - * @param post - The post to which the reply is made. - * @param content - The content of the post reply. - * @returns A Cypress.Chainable> representing the API request response. - */ - createCourseMessageReply(course: Course, post: Post, content: string) { - const body = { - content, - post, - resolvesPost: true, - }; - return cy.request({ method: POST, url: `${COURSE_BASE}/${course.id}/answer-messages`, body }); - } - - /** - * Creates a new course exercise post. - * - * @param course - The course to which the post belongs. - * @param exercise - The exercise to which the post is associated. - * @param title - The title of the post. - * @param content - The content of the post. - * @returns A Cypress.Chainable> representing the API request response. - */ - createCourseExercisePost(course: Course, exercise: Exercise, title: string, content: string) { - const body = { - content, - displayPriority: 'NONE', - exercise: { - id: exercise.id, - title: exercise.title, - type: exercise.type, - }, - tags: [], - title, - visibleForStudents: true, - }; - return cy.request({ method: POST, url: `${COURSE_BASE}/${course.id}/posts`, body }); - } - - /** - * Creates a new course lecture post. - * - * @param course - The course to which the post belongs. - * @param lecture - The lecture to which the post is associated. - * @param title - The title of the post. - * @param content - The content of the post. - * @returns A Cypress.Chainable> representing the API request response. - */ - createCourseLecturePost(course: Course, lecture: Lecture, title: string, content: string) { - const body = { - content, - displayPriority: 'NONE', - lecture: { - id: lecture.id, - title: lecture.title, - }, - tags: [], - title, - visibleForStudents: true, - }; - return cy.request({ method: POST, url: `${COURSE_BASE}${course.id}/posts`, body }); - } -} diff --git a/src/test/cypress/support/requests/CourseManagementAPIRequests.ts b/src/test/cypress/support/requests/CourseManagementAPIRequests.ts deleted file mode 100644 index 60fc4002baed..000000000000 --- a/src/test/cypress/support/requests/CourseManagementAPIRequests.ts +++ /dev/null @@ -1,181 +0,0 @@ -import dayjs from 'dayjs/esm'; - -import { Course, CourseInformationSharingConfiguration } from 'app/entities/course.model'; - -import lectureTemplate from '../../fixtures/lecture/template.json'; -import { BASE_API, COURSE_ADMIN_BASE, COURSE_BASE, DELETE, POST } from '../constants'; -import { CypressCredentials } from '../users'; -import { generateUUID, titleLowercase } from '../utils'; - -/** - * A class which encapsulates all API requests related to course management. - */ -export class CourseManagementAPIRequests { - /** - * Creates a course with the specified title and short name. - * @param options An object containing the options for creating the course - * - customizeGroups: whether the predefined groups should be used (so we don't have to wait more than a minute between course and programming exercise creation) - * - courseName: the title of the course (will generate default name if not provided) - * - courseShortName: the short name (will generate default name if not provided) - * - start: the start date of the course (default: now() - 2 hours) - * - end: the end date of the course (default: now() + 2 hours) - * - iconFileName: the course icon file name (default: undefined) - * - iconFile: the course icon file blob (default: undefined) - * - allowCommunication: if communication should be enabled for the course - * - allowMessaging: if messaging should be enabled for the course - * @returns request response - */ - createCourse( - options: { - customizeGroups?: boolean; - courseName?: string; - courseShortName?: string; - start?: dayjs.Dayjs; - end?: dayjs.Dayjs; - iconFileName?: string; - iconFile?: Blob; - allowCommunication?: boolean; - allowMessaging?: boolean; - } = {}, - ): Cypress.Chainable> { - const { - customizeGroups = false, - courseName = 'Course ' + generateUUID(), - courseShortName = 'cypress' + generateUUID(), - start = dayjs().subtract(2, 'hours'), - end = dayjs().add(2, 'hours'), - iconFileName, - iconFile, - allowCommunication = true, - allowMessaging = true, - } = options; - - const course = new Course(); - course.title = courseName; - course.shortName = courseShortName; - course.testCourse = true; - course.startDate = start; - course.endDate = end; - - if (allowCommunication && allowMessaging) { - course.courseInformationSharingConfiguration = CourseInformationSharingConfiguration.COMMUNICATION_AND_MESSAGING; - course.courseInformationSharingMessagingCodeOfConduct = 'Code of Conduct'; - } else if (allowCommunication) { - course.courseInformationSharingConfiguration = CourseInformationSharingConfiguration.COMMUNICATION_ONLY; - } else { - course.courseInformationSharingConfiguration = CourseInformationSharingConfiguration.DISABLED; - } - - const allowGroupCustomization: boolean = Cypress.env('allowGroupCustomization'); - if (customizeGroups && allowGroupCustomization) { - course.studentGroupName = Cypress.env('studentGroupName'); - course.teachingAssistantGroupName = Cypress.env('tutorGroupName'); - course.editorGroupName = Cypress.env('editorGroupName'); - course.instructorGroupName = Cypress.env('instructorGroupName'); - } - - const formData = new FormData(); - formData.append('course', new File([JSON.stringify(course)], 'course', { type: 'application/json' })); - - if (iconFile) { - formData.append('file', iconFile, iconFileName); - } - - return cy.request({ - url: COURSE_ADMIN_BASE, - method: POST, - body: formData, - }); - } - - /** - * Deletes the course with the specified id. - * - * @param course the course - * @param admin the admin user - * @returns A Cypress.Chainable> representing the API request response. - */ - deleteCourse(course: Course, admin: CypressCredentials) { - if (course) { - cy.login(admin); - // Sometimes the server fails with a ConstraintViolationError if we delete the course immediately after a login - cy.wait(500); - return cy.request({ method: DELETE, url: `${COURSE_ADMIN_BASE}/${course.id}`, retryOnStatusCodeFailure: true }); - } - } - - /** - * Adds the specified student to the course. - * - * @param course - The course to which the student will be added. - * @param user - The user (student) to be added to the course. - * @returns A Cypress.Chainable> representing the API request response. - */ - addStudentToCourse(course: Course, user: CypressCredentials) { - return this.addUserToCourse(course.id!, user.username, 'students'); - } - - /** - * Adds the specified user to the tutor group in the course. - * - * @param course - The course to which the tutor will be added. - * @param user - The user (tutor) to be added to the course. - * @returns A Cypress.Chainable> representing the API request response. - */ - addTutorToCourse(course: Course, user: CypressCredentials) { - return this.addUserToCourse(course.id!, user.username, 'tutors'); - } - - /** - * Adds the specified user to the instructor group in the course. - * - * @param course - The course to which the instructor will be added. - * @param user - The user (instructor) to be added to the course. - * @returns A Cypress.Chainable> representing the API request response. - */ - addInstructorToCourse(course: Course, user: CypressCredentials) { - return this.addUserToCourse(course.id!, user.username, 'instructors'); - } - - private addUserToCourse(courseId: number, username: string, roleIdentifier: string) { - return cy.request({ method: POST, url: `${COURSE_BASE}/${courseId}/${roleIdentifier}/${username}` }); - } - - /** - * Deletes a lecture with the specified lecture ID. - * - * @param lectureId - The ID of the lecture to be deleted. - * @returns A Cypress.Chainable> representing the API request response. - */ - deleteLecture(lectureId: number) { - return cy.request({ - url: `${BASE_API}/lectures/${lectureId}`, - method: DELETE, - }); - } - - /** - * Creates a new lecture for the specified course with various options. - * - * @param course - The course to which the lecture belongs. - * @param title - The title of the lecture (optional, default: auto-generated). - * @param startDate - The start date and time of the lecture (optional, default: current date and time). - * @param endDate - The end date and time of the lecture (optional, default: current date and time + 10 minutes). - * @returns A Cypress.Chainable> representing the API request response. - */ - createLecture(course: Course, title = 'Lecture ' + generateUUID(), startDate = dayjs(), endDate = dayjs().add(10, 'minutes')) { - const body = { - ...lectureTemplate, - course, - title, - startDate, - endDate, - channelName: 'lecture-' + titleLowercase(title), - }; - return cy.request({ - url: `${BASE_API}/lectures`, - method: POST, - body, - }); - } -} diff --git a/src/test/cypress/support/requests/ExamAPIRequests.ts b/src/test/cypress/support/requests/ExamAPIRequests.ts deleted file mode 100644 index 86c92cbbc762..000000000000 --- a/src/test/cypress/support/requests/ExamAPIRequests.ts +++ /dev/null @@ -1,168 +0,0 @@ -import examTemplate from '../../fixtures/exam/template.json'; -import { COURSE_BASE, DELETE, Exercise, POST } from '../constants'; -import { CypressCredentials } from '../users'; -import { dayjsToString, generateUUID, titleLowercase } from '../utils'; -import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; -import { ExerciseGroup } from 'app/entities/exercise-group.model'; -import dayjs from 'dayjs/esm'; - -/** - * A class which encapsulates all API requests related to exams. - */ -export class ExamAPIRequests { - /** - * Creates an exam for the specified course with various options. - * @param options - An object containing the options for creating the exam. - * - course: The course to which the exam belongs (optional, default: undefined). - * - title: The title of the exam (optional, default: auto-generated). - * - testExam: Set to true to create a test exam (optional, default: false). - * - visibleDate: The date when the exam becomes visible (optional, default: current date). - * - startDate: The start date of the exam (optional, default: current date + 1 day). - * - endDate: The end date of the exam (optional, default: current date + 2 days). - * - examMaxPoints: The maximum points achievable in the exam (optional, default: undefined). - * - numberOfExercisesInExam: The number of exercises in the exam (optional, default: undefined). - * - numberOfCorrectionRoundsInExam: The number of correction rounds for the exam (optional, default: undefined). - * - workingTime: The allowed working time for the exam in seconds (optional, default: 86400 seconds or 1 day). - * - examStudentReviewStart: The date when students can start reviewing their exam (optional, default: undefined). - * - examStudentReviewEnd: The date when students can no longer review their exam (optional, default: undefined). - * - publishResultsDate: The date when exam results will be published (optional, default: undefined). - * - gracePeriod: The grace period in seconds for late submissions (optional, default: undefined). - * - channelName: The channel name for the exam (optional, default: auto-generated based on title). - * @returns A Cypress.Chainable> representing the API request response. - */ - createExam(options: { - course?: Course; - title?: string; - testExam?: boolean; - visibleDate?: dayjs.Dayjs; - startDate?: dayjs.Dayjs; - endDate?: dayjs.Dayjs; - examMaxPoints?: number; - numberOfExercisesInExam?: number; - numberOfCorrectionRoundsInExam?: number; - workingTime?: number; - examStudentReviewStart?: dayjs.Dayjs; - examStudentReviewEnd?: dayjs.Dayjs; - publishResultsDate?: dayjs.Dayjs; - gracePeriod?: number; - channelName?: string; - }): Cypress.Chainable> { - const tempTitle = 'exam' + generateUUID(); - - const { - course, - title = tempTitle, - testExam = false, - visibleDate = dayjsToString(dayjs().subtract(1, 'day')), - startDate = dayjsToString(dayjs().add(1, 'day')), - endDate = dayjsToString(dayjs().add(2, 'day')), - examMaxPoints = 10, - numberOfExercisesInExam = 1, - numberOfCorrectionRoundsInExam = 1, - workingTime = 86400, - examStudentReviewStart = null, - examStudentReviewEnd = null, - publishResultsDate = null, - gracePeriod = 30, - } = options; - - const exam = { - ...examTemplate, - course, - title, - testExam, - visibleDate, - startDate, - endDate, - examMaxPoints, - numberOfExercisesInExam, - numberOfCorrectionRoundsInExam, - workingTime, - examStudentReviewStart, - examStudentReviewEnd, - publishResultsDate, - gracePeriod, - channelName: titleLowercase(title), - } as Exam; - - if (testExam) { - exam.numberOfCorrectionRoundsInExam = 0; - } - - return cy.request({ - url: `${COURSE_BASE}/${exam.course!.id}/exams`, - method: POST, - body: exam, - }); - } - - /** - * Deletes the exam with the given parameters - * @param exam the exam object - * @returns A Cypress.Chainable> representing the API request response. - * */ - deleteExam(exam: Exam) { - return cy.request({ method: DELETE, url: `${COURSE_BASE}/${exam.course!.id}/exams/${exam.id}` }); - } - - /** - * Register the student for the exam - * @param exam the exam object - * @returns A Cypress.Chainable> representing the API request response. - */ - registerStudentForExam(exam: Exam, student: CypressCredentials) { - return cy.request({ method: POST, url: `${COURSE_BASE}/${exam.course!.id}/exams/${exam.id}/students/${student.username}` }); - } - - /** - * Creates an exam with the provided settings. - * @param exam the exam object - * @param exerciseArray an array of exercises - * @param workingTime the working time in seconds - * @returns A Cypress.Chainable> representing the API request response. - */ - createExamTestRun(exam: Exam, exerciseArray: Array, workingTime = 1080) { - const courseId = exam.course!.id; - const examId = exam.id!; - const body = { - exam, - exerciseArray, - workingTime, - }; - return cy.request({ url: `${COURSE_BASE}/${courseId}/exams/${examId}/test-run`, method: POST, body }); - } - - /** - * Add exercise group to exam - * @param exam the exam to which the group is added - * @param title the title of the group - * @param mandatory if the exercise group is mandatory - * @returns A Cypress.Chainable> representing the API request response. - * */ - addExerciseGroupForExam(exam: Exam, title = 'Group ' + generateUUID(), mandatory = true) { - const exerciseGroup = new ExerciseGroup(); - exerciseGroup.exam = exam; - exerciseGroup.title = title; - exerciseGroup.isMandatory = mandatory; - return cy.request({ method: POST, url: `${COURSE_BASE}/${exam.course!.id}/exams/${exam.id}/exerciseGroups`, body: exerciseGroup }); - } - - /** - * Generate all missing individual exams - * @param exam the exam for which the missing exams are generated - * @returns A Cypress.Chainable> representing the API request response. - */ - generateMissingIndividualExams(exam: Exam) { - return cy.request({ method: POST, url: `${COURSE_BASE}/${exam.course!.id}/exams/${exam.id}/generate-missing-student-exams` }); - } - - /** - * Prepares individual exercises for exam start - * @param exam the exam for which the exercises are prepared - * @returns A Cypress.Chainable> representing the API request response. - */ - prepareExerciseStartForExam(exam: Exam) { - return cy.request({ method: POST, url: `${COURSE_BASE}/${exam.course!.id}/exams/${exam.id}/student-exams/start-exercises` }); - } -} diff --git a/src/test/cypress/support/requests/ExerciseAPIRequests.ts b/src/test/cypress/support/requests/ExerciseAPIRequests.ts deleted file mode 100644 index eb1fc38eeec9..000000000000 --- a/src/test/cypress/support/requests/ExerciseAPIRequests.ts +++ /dev/null @@ -1,616 +0,0 @@ -import dayjs from 'dayjs/esm'; - -import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; -import { ExerciseGroup } from 'app/entities/exercise-group.model'; -import { Exercise } from 'app/entities/exercise.model'; -import { FileUploadExercise } from 'app/entities/file-upload-exercise.model'; -import { ModelingExercise } from 'app/entities/modeling-exercise.model'; -import { Participation } from 'app/entities/participation/participation.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; -import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; - -import fileUploadExerciseTemplate from '../../fixtures/exercise/file-upload/template.json'; -import modelingExerciseSubmissionTemplate from '../../fixtures/exercise/modeling/submission.json'; -import modelingExerciseTemplate from '../../fixtures/exercise/modeling/template.json'; -import cProgrammingExerciseTemplate from '../../fixtures/exercise/programming/c/template.json'; -import javaAssessmentSubmission from '../../fixtures/exercise/programming/java/assessment/submission.json'; -import javaProgrammingExerciseTemplate from '../../fixtures/exercise/programming/java/template.json'; -import pythonProgrammingExerciseTemplate from '../../fixtures/exercise/programming/python/template.json'; -import multipleChoiceSubmissionTemplate from '../../fixtures/exercise/quiz/multiple_choice/submission.json'; -import shortAnswerSubmissionTemplate from '../../fixtures/exercise/quiz/short_answer/submission.json'; -import quizTemplate from '../../fixtures/exercise/quiz/template.json'; -import textExerciseTemplate from '../../fixtures/exercise/text/template.json'; -import { - BASE_API, - COURSE_BASE, - DELETE, - EXERCISE_BASE, - ExerciseType, - GET, - MODELING_EXERCISE_BASE, - PATCH, - POST, - PROGRAMMING_EXERCISE_BASE, - PUT, - ProgrammingExerciseAssessmentType, - ProgrammingLanguage, - QUIZ_EXERCISE_BASE, - TEXT_EXERCISE_BASE, - UPLOAD_EXERCISE_BASE, -} from '../constants'; -import { dayjsToString, generateUUID, titleLowercase } from '../utils'; -import { ProgrammingExerciseTestCase, Visibility } from 'app/entities/programming-exercise-test-case.model'; - -type PatchProgrammingExerciseTestVisibilityDto = { - id: number; - weight: number; - bonusPoints: number; - bonusMultiplier: number; - visibility: Visibility; -}[]; - -const MAX_RETRIES: number = 10; -const RETRY_DELAY: number = 3000; - -/** - * A class which encapsulates all API requests related to exercises. - */ -export class ExerciseAPIRequests { - /** - * Creates a programming exercise with the specified title and other data - * @param options An object containing the options for creating the programming exercise - * - course: The course the exercise will be added to - * - exerciseGroup: The exercise group the exercise will be added to - * - scaMaxPenalty: The max percentage (0-100) static code analysis can reduce from the points - * If sca should be disabled, pass null or omit this property - * - recordTestwiseCoverage: Enable testwise coverage analysis for this exercise - * - releaseDate: When the programming exercise should be available - * - dueDate: When the programming exercise should be due - * - title: The title of the programming exercise - * - programmingShortName: The short name of the programming exercise - * - programmingLanguage: The programming language for the exercise - * - packageName: The package name of the programming exercise - * - assessmentDate: The due date of the assessment - * - assessmentType: The assessment type of the exercise - * @returns request response - */ - createProgrammingExercise(options: { - course?: Course; - exerciseGroup?: ExerciseGroup; - scaMaxPenalty?: number | null; - recordTestwiseCoverage?: boolean; - releaseDate?: dayjs.Dayjs; - dueDate?: dayjs.Dayjs; - title?: string; - programmingShortName?: string; - programmingLanguage?: ProgrammingLanguage; - packageName?: string; - assessmentDate?: dayjs.Dayjs; - assessmentType?: ProgrammingExerciseAssessmentType; - }): Cypress.Chainable> { - const { - course, - exerciseGroup, - scaMaxPenalty = null, - recordTestwiseCoverage = false, - releaseDate = dayjs(), - dueDate = dayjs().add(1, 'day'), - title = 'Programming ' + generateUUID(), - programmingShortName = 'programming' + generateUUID(), - programmingLanguage = ProgrammingLanguage.JAVA, - packageName = 'de.test', - assessmentDate = dayjs().add(2, 'days'), - assessmentType = ProgrammingExerciseAssessmentType.AUTOMATIC, - } = options; - - let programmingExerciseTemplate = {}; - - if (programmingLanguage == ProgrammingLanguage.PYTHON) { - programmingExerciseTemplate = pythonProgrammingExerciseTemplate; - } else if (programmingLanguage == ProgrammingLanguage.C) { - programmingExerciseTemplate = cProgrammingExerciseTemplate; - } else if (programmingLanguage == ProgrammingLanguage.JAVA) { - programmingExerciseTemplate = javaProgrammingExerciseTemplate; - } - - const exercise = { - ...programmingExerciseTemplate, - title, - shortName: programmingShortName, - packageName, - channelName: 'exercise-' + titleLowercase(title), - assessmentType: ProgrammingExerciseAssessmentType[assessmentType], - ...(course ? { course } : {}), - ...(exerciseGroup ? { exerciseGroup } : {}), - } as ProgrammingExercise; - - if (!exerciseGroup) { - exercise.releaseDate = releaseDate; - exercise.dueDate = dueDate; - exercise.assessmentDueDate = assessmentDate; - } - - if (scaMaxPenalty) { - exercise.staticCodeAnalysisEnabled = true; - exercise.maxStaticCodeAnalysisPenalty = scaMaxPenalty; - } - - exercise.programmingLanguage = programmingLanguage; - exercise.testwiseCoverageEnabled = recordTestwiseCoverage; - - return cy.request({ - url: `${PROGRAMMING_EXERCISE_BASE}/setup`, - method: POST, - body: exercise, - }); - } - - /** - * Retrieves the test cases for passed exercise and adjusts their visibility according. - *
- * Note: test cases are not available before the tests of the solution have completely run through - * -> we need to do retries until the tests have been executed - * - * @param programmingExercise for which the test cases shall be set to {@link newVisibility} - * @param newVisibility that is applied for all found test cases - * @param retryNumber - */ - changeProgrammingExerciseTestVisibility(programmingExercise: ProgrammingExercise, newVisibility: Visibility, retryNumber: number) { - if (retryNumber >= MAX_RETRIES) { - throw new Error('Could not find test cases (tests for solution might not be finished yet)'); - } - - cy.request({ - url: `${PROGRAMMING_EXERCISE_BASE}/${programmingExercise.id}/test-cases`, - method: GET, - }).then((response) => { - const testCases = response.body as ProgrammingExerciseTestCase[]; - - if (retryNumber > 0) { - cy.log(`Could not find test cases yet, retrying... (${retryNumber} / ${MAX_RETRIES})`); - } - - cy.wait(RETRY_DELAY); - - if (testCases.length > 0) { - this.updateProgrammingExerciseTestCaseVisibility(programmingExercise.id!, testCases, newVisibility); - } else { - this.changeProgrammingExerciseTestVisibility(programmingExercise, newVisibility, retryNumber + 1); - } - }); - } - - /** - * Submits the example submission to the specified repository. - * - * @param repositoryId - The repository ID. The repository ID is equal to the participation ID. - * @returns A Cypress.Chainable> representing the API request response. - */ - makeProgrammingExerciseSubmission(repositoryId: number) { - // TODO: For now it is enough to submit the one prepared json file, but in the future this method should support different package names and submissions. - return cy.request({ - url: `${BASE_API}/repository/${repositoryId}/files?commit=yes`, - method: PUT, - body: javaAssessmentSubmission, - }); - } - - /** - * Adds a text exercise to an exercise group in an exam or to a course. - * - * @param body - An object containing either the course or exercise group the exercise will be added to. - * @param title - The title for the text exercise (optional, default: auto-generated). - * @returns A Cypress.Chainable> representing the API request response. - */ - createTextExercise(body: { course: Course } | { exerciseGroup: ExerciseGroup }, title = 'Text ' + generateUUID()): Cypress.Chainable> { - const template = { - ...textExerciseTemplate, - title, - channelName: 'exercise-' + titleLowercase(title), - }; - const textExercise = Object.assign({}, template, body); - return cy.request({ method: POST, url: TEXT_EXERCISE_BASE, body: textExercise }); - } - - /** - * Deletes a text exercise with the specified exercise ID. - * - * @param exerciseId - The ID of the text exercise to be deleted. - * @returns A Cypress.Chainable> representing the API request response. - */ - deleteTextExercise(exerciseId: number) { - return cy.request({ - url: `${TEXT_EXERCISE_BASE}/${exerciseId}`, - method: DELETE, - }); - } - - /** - * Makes a text exercise submission for the specified exercise ID with the given text content. - * - * @param exerciseId - The ID of the text exercise for which the submission is made. - * @param text - The text content of the submission. - * @returns A Cypress.Chainable> representing the API request response. - */ - makeTextExerciseSubmission(exerciseId: number, text: string) { - return cy.request({ - url: `${EXERCISE_BASE}/${exerciseId}/text-submissions`, - method: PUT, - body: { submissionExerciseType: 'text', text }, - }); - } - - /** - * Creates a file upload exercise. - * - * @param body - An object containing either the course or exercise group the exercise will be added to. - * @param title - The title for the exercise (optional, default: auto-generated). - * @returns A Cypress.Chainable> representing the API request response. - */ - createFileUploadExercise( - body: { course: Course } | { exerciseGroup: ExerciseGroup }, - title = 'Upload ' + generateUUID(), - ): Cypress.Chainable> { - const template = { - ...fileUploadExerciseTemplate, - title, - channelName: 'exercise-' + titleLowercase(title), - }; - const uploadExercise = Object.assign({}, template, body); - return cy.request({ method: POST, url: UPLOAD_EXERCISE_BASE, body: uploadExercise }); - } - - /** - * Deletes a file upload exercise with the specified exercise ID. - * - * @param exerciseID - The ID of the file upload exercise to be deleted. - * @returns A Cypress.Chainable> representing the API request response. - */ - deleteFileUploadExercise(exerciseID: number) { - return cy.request({ - url: `${UPLOAD_EXERCISE_BASE}/${exerciseID}`, - method: DELETE, - }); - } - - /** - * Makes a file upload exercise submission for the specified exercise ID with the given file. - * - * @param exerciseId - The ID of the file upload exercise for which the submission is made. - * @param file - The file content of the submission. - * @returns A Cypress.Chainable> representing the API request response. - */ - makeFileUploadExerciseSubmission(exerciseId: number, file: string) { - return cy.request({ - url: `${EXERCISE_BASE}/${exerciseId}/file-upload-submissions`, - method: POST, - body: { submissionExerciseType: 'file-upload', file }, - }); - } - - /** - * Creates a modeling exercise. - * - * @param body - An object containing either the course or exercise group the exercise will be added to. - * @param title - The title for the exercise (optional, default: auto-generated). - * @param releaseDate - The release date of the exercise (optional, default: current date). - * @param dueDate - The due date of the exercise (optional, default: current date + 1 day). - * @param assessmentDueDate - The assessment due date of the exercise (optional, default: current date + 2 days). - * @returns A Cypress.Chainable> representing the API request response. - */ - createModelingExercise( - body: { course: Course } | { exerciseGroup: ExerciseGroup }, - title = 'Modeling ' + generateUUID(), - releaseDate = dayjs(), - dueDate = dayjs().add(1, 'days'), - assessmentDueDate = dayjs().add(2, 'days'), - ): Cypress.Chainable> { - const templateCopy = { - ...modelingExerciseTemplate, - title, - channelName: 'exercise-' + titleLowercase(title), - }; - const dates = { - releaseDate: dayjsToString(releaseDate), - dueDate: dayjsToString(dueDate), - assessmentDueDate: dayjsToString(assessmentDueDate), - }; - let newModelingExercise; - if (body.hasOwnProperty('course')) { - newModelingExercise = Object.assign({}, templateCopy, dates, body); - } else { - newModelingExercise = Object.assign({}, templateCopy, body); - } - return cy.request({ - url: MODELING_EXERCISE_BASE, - method: POST, - body: newModelingExercise, - }); - } - - /** - * Updates the assessment due date of a modeling exercise. - * - * @param exercise - The modeling exercise to update. - * @param due - The new assessment due date (optional, default: current date). - * @returns A Cypress.Chainable> representing the API request response. - */ - updateModelingExerciseAssessmentDueDate(exercise: ModelingExercise, due = dayjs()) { - exercise.assessmentDueDate = due; - return this.updateExercise(exercise, ExerciseType.MODELING); - } - - /** - * Deletes a modeling exercise with the specified exercise ID. - * - * @param exerciseID - The ID of the modeling exercise to be deleted. - * @returns A Cypress.Chainable> representing the API request response. - */ - deleteModelingExercise(exerciseID: number) { - return cy.request({ - url: `${MODELING_EXERCISE_BASE}/${exerciseID}`, - method: DELETE, - }); - } - - /** - * Makes a modeling exercise submission for the specified exercise ID and participation. - * - * @param exerciseID - The ID of the modeling exercise for which the submission is made. - * @param participation - The participation data for the submission. - * @returns A Cypress.Chainable> representing the API request response. - */ - makeModelingExerciseSubmission(exerciseID: number, participation: Participation) { - return cy.request({ - url: `${EXERCISE_BASE}/${exerciseID}/modeling-submissions`, - method: PUT, - body: { - ...modelingExerciseSubmissionTemplate, - id: participation.submissions![0].id, - participation, - }, - }); - } - - /** - * Updates the due date of a modeling exercise. - * - * @param exercise - The modeling exercise to update. - * @param due - The new due date (optional, default: current date). - * @returns A Cypress.Chainable> representing the API request response. - */ - updateModelingExerciseDueDate(exercise: ModelingExercise, due = dayjs()) { - exercise.dueDate = due; - return this.updateExercise(exercise, ExerciseType.MODELING); - } - - /** - * Creates a quiz exercise. - * - * @param body - An object containing either the course or exercise group the exercise will be added to. - * @param quizQuestions - A list of quiz question objects that make up the quiz (e.g., multiple choice, short answer, or drag and drop). - * @param title - The title for the quiz exercise (optional, default: auto-generated). - * @param releaseDate - The release date of the quiz exercise (optional, default: current date + 1 year). - * @param duration - The duration in seconds that students get to complete the quiz (optional, default: 600 seconds). - * @returns A Cypress.Chainable> representing the API request response. - */ - createQuizExercise( - body: { course: Course } | { exerciseGroup: ExerciseGroup }, - quizQuestions: [any], - title = 'Quiz ' + generateUUID(), - releaseDate = dayjs().add(1, 'year'), - duration = 600, - ): Cypress.Chainable> { - const quizExercise: any = { - ...quizTemplate, - title, - quizQuestions, - duration, - channelName: 'exercise-' + titleLowercase(title), - }; - let newQuizExercise; - const dates = { - releaseDate: dayjsToString(releaseDate), - }; - if (body.hasOwnProperty('course')) { - newQuizExercise = Object.assign({}, quizExercise, dates, body); - } else { - newQuizExercise = Object.assign({}, quizExercise, body); - } - - const formData = new FormData(); - formData.append('exercise', new File([JSON.stringify(newQuizExercise)], 'exercise', { type: 'application/json' })); - - return cy.request({ - url: QUIZ_EXERCISE_BASE, - method: POST, - body: formData, - }); - } - - /** - * Deletes a quiz exercise with the specified exercise ID. - * - * @param exerciseId - The ID of the quiz exercise to be deleted. - * @returns A Cypress.Chainable> representing the API request response. - */ - deleteQuizExercise(exerciseId: number) { - return cy.request({ - url: `${QUIZ_EXERCISE_BASE}/${exerciseId}`, - method: DELETE, - }); - } - - /** - * Sets a quiz exercise as visible. - * - * @param quizId - The ID of the quiz exercise to be set as visible. - * @returns A Cypress.Chainable> representing the API request response. - */ - setQuizVisible(quizId: number) { - return cy.request({ - url: `${QUIZ_EXERCISE_BASE}/${quizId}/set-visible`, - method: PUT, - }); - } - - /** - * Starts a quiz exercise immediately. - * - * @param quizId - The ID of the quiz exercise to be started immediately. - * @returns A Cypress.Chainable> representing the API request response. - */ - startQuizNow(quizId: number) { - return cy.request({ - url: `${QUIZ_EXERCISE_BASE}/${quizId}/start-now`, - method: PUT, - }); - } - - /** - * Evaluates the quiz exercises in an exam. - * - * @param exam - The exam for which to evaluate the quiz exercises. - * @returns A Cypress.Chainable> representing the API request response. - */ - evaluateExamQuizzes(exam: Exam) { - return cy.request({ - url: `${COURSE_BASE}/${exam.course!.id}/exams/${exam.id}/student-exams/evaluate-quiz-exercises`, - method: POST, - }); - } - - /** - * Creates a submission for a quiz with only one multiple-choice quiz question. - * - * @param quizExercise - The response body of a quiz exercise. - * @param tickOptions - A list describing which of the 0..n boxes are to be ticked in the submission. - * @returns A Cypress.Chainable> representing the API request response. - */ - createMultipleChoiceSubmission(quizExercise: any, tickOptions: number[]) { - const submittedAnswers = [ - { - ...multipleChoiceSubmissionTemplate.submittedAnswers[0], - quizQuestion: quizExercise.quizQuestions![0], - selectedOptions: tickOptions.map((option) => quizExercise.quizQuestions[0].answerOptions[option]), - }, - ]; - const multipleChoiceSubmission = { - ...multipleChoiceSubmissionTemplate, - submittedAnswers, - }; - return cy.request({ - url: `${EXERCISE_BASE}/${quizExercise.id}/submissions/live`, - method: POST, - body: multipleChoiceSubmission, - }); - } - - /** - * Creates a submission for a quiz with only one short-answer quiz question. - * - * @param quizExercise - The response body of the quiz exercise. - * @param textAnswers - A list containing the answers to be filled into the gaps. In numerical order. - * @returns A Cypress.Chainable> representing the API request response. - */ - createShortAnswerSubmission(quizExercise: any, textAnswers: string[]) { - const submittedTexts = textAnswers.map((answer, index) => { - return { - text: answer, - spot: { - id: quizExercise.quizQuestions[0].spots[index].id, - spotNr: quizExercise.quizQuestions[0].spots[index].spotNr, - width: quizExercise.quizQuestions[0].spots[index].width, - invalid: quizExercise.quizQuestions[0].spots[index].invalid, - }, - }; - }); - const submittedAnswers = [ - { - ...shortAnswerSubmissionTemplate.submittedAnswers[0], - quizQuestion: quizExercise.quizQuestions[0], - submittedTexts, - }, - ]; - const shortAnswerSubmission = { - ...shortAnswerSubmissionTemplate, - submittedAnswers, - }; - return cy.request({ - url: `${EXERCISE_BASE}/${quizExercise.id}/submissions/live`, - method: POST, - body: shortAnswerSubmission, - }); - } - - /** - * Gets the participation data for an exercise with the specified exercise ID. - * - * @param exerciseId - The ID of the exercise for which to retrieve the participation data. - * @returns A Cypress.Chainable> representing the API request response. - */ - getExerciseParticipation(exerciseId: number) { - return cy.request({ - url: `${EXERCISE_BASE}/${exerciseId}/participation`, - method: GET, - }); - } - - /** - * Starts a participation for an exercise with the specified exercise ID. - * - * @param exerciseId - The ID of the exercise for which to start the participation. - * @returns A Cypress.Chainable> representing the API request response. - */ - startExerciseParticipation(exerciseId: number) { - return cy.request({ - url: `${EXERCISE_BASE}/${exerciseId}/participations`, - method: POST, - }); - } - - private updateProgrammingExerciseTestCaseVisibility(programmingExerciseId: number, programmingExerciseTestCases: ProgrammingExerciseTestCase[], newVisibility: Visibility) { - const updatedTestCaseSettings: PatchProgrammingExerciseTestVisibilityDto = []; - - for (const testCase of programmingExerciseTestCases) { - updatedTestCaseSettings.push({ - id: testCase.id!, - weight: testCase.weight!, - bonusPoints: testCase.bonusPoints!, - bonusMultiplier: testCase.bonusMultiplier!, - visibility: newVisibility, - }); - } - - return cy.request({ - url: `${PROGRAMMING_EXERCISE_BASE}/${programmingExerciseId}/update-test-cases`, - method: PATCH, - body: updatedTestCaseSettings, - }); - } - - private updateExercise(exercise: Exercise, type: ExerciseType) { - let url: string; - switch (type) { - case ExerciseType.PROGRAMMING: - url = PROGRAMMING_EXERCISE_BASE; - break; - case ExerciseType.TEXT: - url = TEXT_EXERCISE_BASE; - break; - case ExerciseType.MODELING: - url = MODELING_EXERCISE_BASE; - break; - case ExerciseType.QUIZ: - default: - throw new Error(`Exercise type '${type}' is not supported yet!`); - } - return cy.request({ - url, - method: PUT, - body: exercise, - }); - } -} diff --git a/src/test/cypress/support/requests/UserManagementAPIRequest.ts b/src/test/cypress/support/requests/UserManagementAPIRequest.ts deleted file mode 100644 index a3f224f5d5f0..000000000000 --- a/src/test/cypress/support/requests/UserManagementAPIRequest.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { BASE_API, GET, POST } from '../constants'; -import { UserRole } from '../users'; - -/** - * A class which encapsulates all API requests related to user management. - */ -export class UserManagementAPIRequests { - /** - * Creates a new user - * @param username the username of the new user - * @param password the password of the new user - * @param role the role of the new user - */ - createUser(username: string, password: string, role: UserRole) { - const user = { - login: username, - password, - firstName: username, - lastName: username, - email: username + '@example.com', - authorities: [role], - }; - return cy.request({ - url: `${BASE_API}/admin/users`, - method: POST, - body: user, - }); - } - - getUser(username: string) { - return cy.request({ - url: `${BASE_API}/admin/users/${username}`, - method: GET, - failOnStatusCode: false, - }); - } -} diff --git a/src/test/cypress/support/users.ts b/src/test/cypress/support/users.ts deleted file mode 100644 index 94d89a08140c..000000000000 --- a/src/test/cypress/support/users.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { BASE_API, GET, USER_ID_SELECTOR } from './constants'; - -export enum UserRole { - Instructor = 'ROLE_INSTRUCTOR', - Tutor = 'ROLE_TA', - Student = 'ROLE_USER', -} - -export const USER_ID = { - studentOne: 100, - studentTwo: 102, - studentThree: 104, - studentFour: 106, - instructor: 103, - tutor: 101, -}; - -export const USER_ROLE = { - studentOne: UserRole.Student, - studentTwo: UserRole.Student, - studentThree: UserRole.Student, - studentFour: UserRole.Student, - instructor: UserRole.Instructor, - tutor: UserRole.Tutor, -}; - -/** - * Class to encompass user management logic for cypress tests. - */ -export class CypressUserManagement { - /** - * @returns admin credentials. - */ - public getAdmin(): CypressCredentials { - const adminUsername = Cypress.env('adminUsername') ?? 'admin'; - const adminPassword = Cypress.env('adminPassword') ?? 'admin'; - return { username: adminUsername, password: adminPassword }; - } - - /** - * @returns the first testing account with student rights. - */ - public getStudentOne(): CypressCredentials { - return this.getUserWithId(USER_ID.studentOne); - } - - /** - * @returns the second testing account with student rights. - */ - public getStudentTwo(): CypressCredentials { - return this.getUserWithId(USER_ID.studentTwo); - } - - /** - * @returns the third testing account with student rights. - */ - public getStudentThree(): CypressCredentials { - return this.getUserWithId(USER_ID.studentThree); - } - - /** - * @returns the fourth testing account with student rights. - */ - public getStudentFour(): CypressCredentials { - return this.getUserWithId(USER_ID.studentFour); - } - - /** - * @returns an instructor account. - */ - public getInstructor(): CypressCredentials { - return this.getUserWithId(USER_ID.instructor); - } - - /** - * @returns a tutor account. - */ - public getTutor(): CypressCredentials { - return this.getUserWithId(USER_ID.tutor); - } - - public getUserWithId(userId: number): CypressCredentials { - const username = this.getUsernameTemplate().replace(USER_ID_SELECTOR, userId.toString()); - const password = this.getPasswordTemplate().replace(USER_ID_SELECTOR, userId.toString()); - return { username, password }; - } - - /** - * @returns the username template. - */ - private getUsernameTemplate(): string { - return Cypress.env('username') ?? 'user_' + USER_ID_SELECTOR; - } - - /** - * @returns the password template. - */ - private getPasswordTemplate(): string { - return Cypress.env('password') ?? 'password_' + USER_ID_SELECTOR; - } - - /** - * Provides the entire account info for the user that is currently logged in - * Use like this: artemis.users.getAccountInfo((account) => { someFunction(account); }); - * */ - public getAccountInfo(func: (response: any) => void) { - cy.request({ method: GET, url: `${BASE_API}/public/account`, log: false }).then((response) => { - func(response.body); - }); - } - - public getUserInfo(username: string, func: (response: any) => void) { - cy.request({ method: GET, url: `${BASE_API}/admin/users/${username}`, log: false }).then((response) => { - func(response.body); - }); - } -} - -// Users -export const users = new CypressUserManagement(); -export const admin = users.getAdmin(); -export const instructor = users.getInstructor(); -export const tutor = users.getTutor(); -export const studentOne = users.getStudentOne(); -export const studentTwo = users.getStudentTwo(); -export const studentThree = users.getStudentThree(); -export const studentFour = users.getStudentFour(); - -/** - * Container class for user credentials. - */ -export interface CypressCredentials { - username: string; - password: string; -} diff --git a/src/test/cypress/support/utils.ts b/src/test/cypress/support/utils.ts deleted file mode 100644 index 0f3cbf51c7df..000000000000 --- a/src/test/cypress/support/utils.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { TIME_FORMAT } from './constants'; -import dayjs from 'dayjs/esm'; -import utc from 'dayjs/esm/plugin/utc'; -import { v4 as uuidv4 } from 'uuid'; - -// Add utc plugin to use the utc timezone -dayjs.extend(utc); - -/** - * This file contains all of the global utility functions not directly related to cypress. - */ - -/** - * Generates a unique identifier. - * */ -export function generateUUID() { - const uuid = uuidv4().replace(/-/g, ''); - return uuid.substr(0, 9); -} - -/** - * Allows to enter date into the UI - * */ -export function enterDate(selector: string, date: dayjs.Dayjs) { - const dateInputField = cy.get(selector).find('#date-input-field'); - dateInputField.should('not.be.disabled'); - dateInputField.clear().type(dayjsToString(date), { force: true }); -} - -/** - * Allows to check a specified input field for a value - * */ -export function checkField(field: string, value: any) { - cy.get(field).should('have.value', value); -} - -/** - * Formats the day object with the time format which the server uses. Also makes sure that day uses the utc timezone. - * @param day the day object - * @returns a formatted string representing the date with utc timezone - */ -export function dayjsToString(day: dayjs.Dayjs) { - // We need to add the Z at the end. Otherwise, the server can't parse it. - return day.utc().format(TIME_FORMAT) + 'Z'; -} - -/** - * Converts the response object obtained from a multipart request to an entity object. - * @param response - The Cypress.Response object obtained from a multipart request. - * @returns The entity object parsed from the response. - */ -export function convertModelAfterMultiPart(response: Cypress.Response): T { - // Cypress currently has some issues with our multipart request, parsing this not as an object but as an ArrayBuffer - // Once this is fixed (and hence the expect statements below fail), we can remove the additional parsing - expect(response.body).not.to.be.an('object'); - expect(response.body).to.be.an('ArrayBuffer'); - - return parseArrayBufferAsJsonObject(response.body as ArrayBuffer); -} - -/** - * This function is necessary to make the server and the client date comparable. - * The server sometimes has 3 digit on the milliseconds and sometimes only 1 digit. - * With this function we always cut the date string after the first digit. - * @param date the date as a string - * @returns a date string with only one digit for the milliseconds - */ -export function trimDate(date: string) { - return date.slice(0, 19); -} - -/** - * Converts a snake_case word to Title Case (each word's first letter capitalized and spaces in between). - * @param str - The snake_case word to be converted to Title Case. - * @returns The word in Title Case. - */ -export function titleCaseWord(str: string) { - str = str.replace('_', ' '); - const sentence = str.toLowerCase().split(' '); - for (let i = 0; i < sentence.length; i++) { - sentence[i] = sentence[i][0].toUpperCase() + sentence[i].slice(1); - } - return sentence.join(' '); -} - -/** - * Converts a title to lowercase and replaces spaces with hyphens. - * @param title - The title to be converted to lowercase with hyphens. - * @returns The converted title in lowercase with hyphens. - */ -export function titleLowercase(title: string) { - return title.replace(' ', '-').toLowerCase(); -} - -/** - * Retrieves the DOM element representing the exercise with the specified ID. - * @param exerciseId - The ID of the exercise for which to retrieve the DOM element. - * @returns A Cypress.Chainable that yields the DOM element representing the exercise. - */ -export function getExercise(exerciseId: number) { - return cy.get(`#exercise-${exerciseId}`); -} - -/** - * Converts a boolean value to its related icon class. - * @param boolean - The boolean value to be converted. - * @returns The corresponding ".checked" or ".unchecked" string. - */ -export function convertBooleanToCheckIconClass(boolean: boolean) { - return boolean ? '.checked' : '.unchecked'; -} - -/** - * Parses an ArrayBuffer as a JSON object. - * @param buffer - The ArrayBuffer to be parsed as a JSON object. - * @returns The parsed JSON object. - */ -function parseArrayBufferAsJsonObject(buffer: ArrayBuffer) { - const bodyString = Cypress.Blob.arrayBufferToBinaryString(buffer); - return JSON.parse(bodyString); -} diff --git a/src/test/cypress/tsconfig.json b/src/test/cypress/tsconfig.json deleted file mode 100644 index 65dece962d13..000000000000 --- a/src/test/cypress/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": "../../../tsconfig.json", - "include": ["**/**/**/*.ts"], - "exclude": ["node_modules"], - "compilerOptions": { - "ignoreDeprecations": "5.0", - "target": "es2019", - "sourceMap": false, - "types": ["cypress", "@4tw/cypress-drag-drop", "node", "cypress-wait-until", "cypress-file-upload"] - } -} diff --git a/src/test/cypress/certs/Dockerfile b/src/test/playwright/certs/Dockerfile similarity index 100% rename from src/test/cypress/certs/Dockerfile rename to src/test/playwright/certs/Dockerfile diff --git a/src/test/cypress/certs/README.md b/src/test/playwright/certs/README.md similarity index 74% rename from src/test/cypress/certs/README.md rename to src/test/playwright/certs/README.md index b95146cc4a42..55e8f826bae7 100644 --- a/src/test/cypress/certs/README.md +++ b/src/test/playwright/certs/README.md @@ -1,7 +1,7 @@ -# Cypress: Generate Client Certificates +# Playwright: Generate Client Certificates -[Cypress allows to use self-signed client certificates](https://docs.cypress.io/guides/references/client-certificates -) if you also provide a certificate authority. +Playwright currently lacks support for client certificates. To bypass certificate issues, we are ignoring HTTPS errors. +Once Playwright supports client certificates, follow these steps to generate the necessary client certificates. In order to generate these certificates we use the tool [mkcert](https://github.com/FiloSottile/mkcert), instead of openssl for instance, as it's easy to use. @@ -10,7 +10,7 @@ instead of openssl for instance, as it's easy to use. The following steps show how to generate new client certificates and the CA files: ```bash -cd ./src/test/cypress/certs +cd ./src/test/playwright/certs docker run --rm -v ${PWD}:/certs $(docker build -q . ) /certs/generate-certs.sh artemis-nginx artemis.example localhost 127.0.0.1 ::1 ``` @@ -18,7 +18,7 @@ The CA private key `rootCA-key.pem` doesn't need to be in version control as it' but we can also just recreate the whole CA and client certificates. ## Using the client certificates locally -If you want to access the artemis-nginx locally from your browser instead of the cypress container's browser, +If you want to access the artemis-nginx locally from your browser instead of the playwright container's browser, you can also install the CA locally on your computer [by installing mkcert locally and the following steps](https://github.com/FiloSottile/mkcert#installing-the-ca-on-other-systems): diff --git a/src/test/playwright/certs/artemis-nginx+4-key.pem b/src/test/playwright/certs/artemis-nginx+4-key.pem index eb2d95da1e9c..e2c0bfc8ab63 100644 --- a/src/test/playwright/certs/artemis-nginx+4-key.pem +++ b/src/test/playwright/certs/artemis-nginx+4-key.pem @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQCuCJSHStSQd02f -j+IlQFes7pVUcYv2r0qm5qicGwPcKQf1/nmsy6k4WhE9HQV9VO9LQ4doSNp9NuYX -P/JQqdYLZYYQvxHS+fR7ofIPjirsrbQYAkG5F6imM8H7MkkueG3HGqaKD54PBmC4 -BgBJDFWiF8jSNSYNKOE2L5SaYG/g3LLIkWBlhBQHgrprkio4pv5Y44+nf+hGWkSj -bkRo2+PmIsNmQrpDB2o0O7uoyswa71HE967n9K17SWZ7Hi4kP6BGUWn65P5JB10a -6kz0y8183Uzz99bx8hzxLPg6VNiJZQ+dH4M1Jn6kysKiyV4x24JsM9s6t+Vhln9E -KX5ktosdAgMBAAECggEBAJs3ddkwqWLrtOSR/H2C5G+NHsyAtPdgIfG3mTwZcBjk -03/X5gdyYUusMOHTx3ifzwjOgq9FAvFYjGDCHMlKoGfrtWWsNCZ53k6CApVTE/+h -cRVUte9yJW2Ojf0PPWvf5vEEWPKbuTnnU03ttEVyZdG66tZoprZn9m1QhHYnesEO -PMPvYMd3Oyko8MD/Rr1A/KS/rmc0yfUvgLsqF6PLxq3NKxyVD/8Tp4u9aXbPMnd2 -vugVxjjvt5ubscF1Owi8EjqjVkXlw94JzLcy70XfBzsS2EvUtX/hmHgBEsViXUOQ -KGVyeFTvuReq0RvLQi1LA8vs2q6UC0ZYX75wGDfWWnUCgYEAyP6FY6xdP+N83qEM -TzAf2a33bBCcD5zbrfsvYwHwdzcAz9HBdf3TN1ZcbgfIzIWvuo+hFdjZd32E2+b7 -tSGpcs21iZ3dn1aWxngNs/h94h6cNak/02iCbOsmMX9rHfKZd1ODnQyA8q0s9PQY -uWWWMUfqPse7mSYbgU0aYOVFraMCgYEA3ak3N2mTgTVsUqhNyZCJlmtafp0tsT6b -/7GKSqkl741wokM6un3wx1eo6Q95mngxOlY2xxq9OChnNSEa9ZQnzdUDtQ0YE4QD -09awTIMHNCeSqpV2n3Yv2fT3C5Ya5/WEtYGpVAtqgxwWPij8+VMOa8MVzy+/v6Hg -N1Tpww+Y8D8CgYEAhbEGeK4FuKFQRaVJ0sJn7RrSIIdLxvbHCIqzkl+P2zwyxgj3 -bcxP2dcP1ABJiADESouO0kFTJS/QV5TkiC7DzyEVR1xCNeIamBjyxGrdELLbpLXX -Rn+VgW1IElR2o4zil4RtXuEaRFD8PlK+v1La/ByhqvCfz9aRJQhsK1dVaZECgYEA -jRYR0TFf89P/OLVrnapkCNwX45ND7Bc/0AY/UbpMLSfH02AbV2yl/xvqpT12Vz29 -h7Ysc5qvabk9x/FkaX99vmOhUnIdKv7SONnjqS+VPDsb/XvY3zKozoA/Zp6KTa5W -Y/k9wALsLruH5NTOABw/h5PKo+9uixkLz+w6Ri/9Vp0CgYEAqfkZJe7vCOIwtIwj -Mq5knkJgR+Vq30i4jRoFU0yxIcWA1hODVBnK39+mtA++/3+r5DY5fGRTc9mMyXU/ -y2N2nfSnvPMAUaRmisB7NhmvinEgymlrX+WE+7S9/+nOQADxzWSc6Hxg/ub6mTYV -k2/hv9uG1gbm2+OBP/EBOr48jz0= +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDBExGUKX71DriG +If8pZM7Wb3jA/W65o3tAz2SxM422yWqG/fGOFosDoKST7akQf3kVucFtZGsYAi5r +tm31Ngmj9YIfKFctAPU3TI52idsSbk0vG7NatwyC2YT12FayWeNwp/2S1jMW8cfI +rlGfkLAguzVOwO7XDoPtkn11gdnrMbxdww/QTjlFV3NPX5oz5Po+Amnc9HiYZSO5 +chTwq1nU4lEAj5270Yw32rynIrjEhSrwkhSAF+a4NFaHdD8exkT7EGe/pm0ExZZp +8TdBknIwZEiKWjz5L/9KhwyFKRWTZYWr73Ns9yr1FltkHcXpqfBfDhGjdqihZe9I +s5PqovLDAgMBAAECggEAP3Om2Uxx3tOBrQNLOi1ZFHv58WLYmsWxYfFGpD3PGv1C +ty6Jzip2cTDAJaV7ZGKgRpWPjgXsdC1zWA7SQD4MGQg8RUUasT2ZWR0dzLMtffcm +Ao9V+EAkKnSWD72TcHW+G236FeGzVJ0NDVTMmmYQnBEqScF6PM8WaGM2PAH6viI8 ++IrgL3ZWAXL2YvQmyQavG0P+MTLkctrymrnx4kId0FW7dBDgeBu1JOsLpz3Ft4DB +JoD3gv+aYkYYPzNF6ueLRMp5qVhVu1KZB4QDHZxCAjFUTgn1kCLHmulTVBGrc0v+ +HXhYW6HVrspFqv2em61BZInDu+aruZpADCFj9qxRgQKBgQD8amBMiU8FVBo9c6kD +FP/+NY4Gh9NPy1zk8uQ4InZ9abNpZ+TX1h9vMvMnyXe49XRy3BYPrT4CVXOe3hXd +aMolRfRD89W/KUNBlITUw2DEbr9FxQrYMUmjaWj5pKdxOiUxOndD2DmhGAwpi3AS +iFDLg1j6eAmPfCISXwIGPyT1owKBgQDD0PdB6AuqbJqcvoPRCfUr7x/ciA9VqVuS +gRYFW6ZGrIOPHp43EFEVzw8Va86lUVR2GRIvnRDWH8H+s1W3JSYaYOmqqA/sZ86i +lyDmvaACQqOUHrCBu+QUcsflye9a7e13xlRvVm6NchEPMhfe9mx1NbfMGhFd5AkB +/hi49TSgYQKBgATkMtWI26UoyhFiymWq5IMSmpv5ydiEAlrVciK8WDt57uYeA0tD +dPx8qkWdG9rTttv689p96vO0oDb16sqNm005m9AtS3kW3ZzJugE9gASOeNprRRiH +a/vksQoVbME+9TWNAn6oFAXRJ3suno9dYONwuiqwZM8JAsgEW0+vrZGtAoGBAItV +YOsTm2FsH+QSqCcRZ9QYNdqtMgQpGxC3K50qZrl5Pa+UAM57nMbg7AG5EXSO14Ol +OUyJ/ZXvSRHcN8y28VLpzLrzFUmJX/5PfUjSe03AbzcRU1UtBhEKz3SR6PARxtxo +UmJa5RVeqgbfBR9Qx0HrtFnV3q+peENjs+HAEO9hAoGBALAgM8uPmt/ZUAzGPf0T +kfLV4HolEk7lmSLvEVB0w8yru9q/YcHuD3VtOjiq5h+N38Yn3t2N6PhJ9tt28OWi +jUmDTmf+n95C1jGYG1Y6SgAPJwdCNHh+j6TPJuv9nwX66DCy8ClY0TpezAeXdH3e +YfFCsfkK9CPTQt85EqunOvSa -----END PRIVATE KEY----- diff --git a/src/test/playwright/certs/artemis-nginx+4.pem b/src/test/playwright/certs/artemis-nginx+4.pem index 6492786845eb..0c71f022d760 100644 --- a/src/test/playwright/certs/artemis-nginx+4.pem +++ b/src/test/playwright/certs/artemis-nginx+4.pem @@ -1,25 +1,25 @@ -----BEGIN CERTIFICATE----- -MIIERjCCAq6gAwIBAgIQSQ2vfdquHAQcrzbEKx46mzANBgkqhkiG9w0BAQsFADBf -MR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExGjAYBgNVBAsMEXJvb3RA -MWY0ZmQzNzYzNmMyMSEwHwYDVQQDDBhta2NlcnQgcm9vdEAxZjRmZDM3NjM2YzIw -HhcNMjIxMjA1MDk0NTEzWhcNMjUwMzA1MDk0NTEzWjBFMScwJQYDVQQKEx5ta2Nl -cnQgZGV2ZWxvcG1lbnQgY2VydGlmaWNhdGUxGjAYBgNVBAsMEXJvb3RAMWY0ZmQz -NzYzNmMyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArgiUh0rUkHdN -n4/iJUBXrO6VVHGL9q9KpuaonBsD3CkH9f55rMupOFoRPR0FfVTvS0OHaEjafTbm -Fz/yUKnWC2WGEL8R0vn0e6HyD44q7K20GAJBuReopjPB+zJJLnhtxxqmig+eDwZg -uAYASQxVohfI0jUmDSjhNi+UmmBv4NyyyJFgZYQUB4K6a5IqOKb+WOOPp3/oRlpE -o25EaNvj5iLDZkK6QwdqNDu7qMrMGu9RxPeu5/Ste0lmex4uJD+gRlFp+uT+SQdd -GupM9MvNfN1M8/fW8fIc8Sz4OlTYiWUPnR+DNSZ+pMrCosleMduCbDPbOrflYZZ/ -RCl+ZLaLHQIDAQABo4GXMIGUMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggr -BgEFBQcDATAfBgNVHSMEGDAWgBSpuKALkiwfLnQmm7+JNG2bxGAIgzBMBgNVHREE -RTBDgg1hcnRlbWlzLW5naW54gg9hcnRlbWlzLmV4YW1wbGWCCWxvY2FsaG9zdIcE -fwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAYEApG8ZADQe -SsH/nqH9WpR3ZkYg0rm8pw+YquBNUdDFG2/4IQtaaxrgsvNPrEEMXfCO4vvnC0cH -6Tgay8LzFZxU9D1F06VZ9S1C7KNnYSsjgwhW7wxem1JXgauoutA8D0uHLr/2bVnz -rTShQT7gRp9SRunqDylaSkgpXlfZQRlEANrYT8Jh6LIHRjkxLh/etw7VdFA6Tywh -iQGBE/EbQcGpmqHBoMytblku0D8H+pcFHZ03AZq0FTMbByM9GekQ8HJV88epqvqJ -7pWyQPX9lr7yC6n121dPoA0ylP8D7jIBCmlFeF+QWCiRAgdeb1w+JONHMgI97IR+ -9HBm6gGE+Da/TRq82w02tUN/F7NHdzqwKGx/GKLrEsdNlfP6D9iiVtfBGBoAUm+C -2t3jbQEgqYHA+mzadS75RGJsRnVdY24IHvNjEnESW6KCaSfQyMmp3trRH6JeOttU -2JeqRPjmOzNvzIcB76w1/hB2ljhimyfoxB8Gbrts+GFPRZE+AXg1mvCn +MIIERzCCAq+gAwIBAgIRAMlqfnXCQz3X2CUiF24MFaAwDQYJKoZIhvcNAQELBQAw +XzEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMRowGAYDVQQLDBFyb290 +QGQzNjZiZGIwMGRkODEhMB8GA1UEAwwYbWtjZXJ0IHJvb3RAZDM2NmJkYjAwZGQ4 +MB4XDTI0MDYyMzE2MzE0MloXDTI2MDkyMzE2MzE0MlowRTEnMCUGA1UEChMebWtj +ZXJ0IGRldmVsb3BtZW50IGNlcnRpZmljYXRlMRowGAYDVQQLDBFyb290QGQzNjZi +ZGIwMGRkODCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMETEZQpfvUO +uIYh/ylkztZveMD9brmje0DPZLEzjbbJaob98Y4WiwOgpJPtqRB/eRW5wW1kaxgC +Lmu2bfU2CaP1gh8oVy0A9TdMjnaJ2xJuTS8bs1q3DILZhPXYVrJZ43Cn/ZLWMxbx +x8iuUZ+QsCC7NU7A7tcOg+2SfXWB2esxvF3DD9BOOUVXc09fmjPk+j4Cadz0eJhl +I7lyFPCrWdTiUQCPnbvRjDfavKciuMSFKvCSFIAX5rg0Vod0Px7GRPsQZ7+mbQTF +lmnxN0GScjBkSIpaPPkv/0qHDIUpFZNlhavvc2z3KvUWW2Qdxemp8F8OEaN2qKFl +70izk+qi8sMCAwEAAaOBlzCBlDAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYI +KwYBBQUHAwEwHwYDVR0jBBgwFoAUM5jJgNEPGr9YJJAukqOwnK4E+UwwTAYDVR0R +BEUwQ4INYXJ0ZW1pcy1uZ2lueIIPYXJ0ZW1pcy5leGFtcGxlgglsb2NhbGhvc3SH +BH8AAAGHEAAAAAAAAAAAAAAAAAAAAAEwDQYJKoZIhvcNAQELBQADggGBABnZXfx2 +v7JyVzbWHTpbkgYgxLBy+eoiE2GW7YIaZYDrgGYb43rZT1uAa3KOLVogCbNyiw6F +lZuhOSLZdVBaQDJga11b5CT1lRMGSquU9Nacw4oVP7z1GvO7LEnvO/CK44e+zFST +s/emVdY8iwe3ruTaUoTj+zQe8OLEWiecZB/IVo08OsF8/txHMCSlb1sAO/4elFMP +Sulz/dNe8ELkGNOqUjl0BWhSkE4vlTskch2pAClGVGvoBxmLEwVIbu3tnX/fy8ms +2j1JXreRyDqxPlbQfsrVNz85VxmUdsuTqfrCpVYgpp1DAXX4b6u8/xJugBeXj4qH +mfDytfCfp0+9nTnZuMbX+zpao0S15s3+jLKeAxAJfMFQ/hxWfs67KqG3G4sqDhOf +PfwrDk2wudzr1/PRIb+ZCshRgv16ckaEcjPOulgjzGAlGlN1/33Zr8o+O7L2jOMU +gy8IcXbRERBj5tLBsooXHNitMZHyAYRKy0flCpU+qxPSpJDI4fowbfkp7Q== -----END CERTIFICATE----- diff --git a/src/test/cypress/certs/generate-certs.sh b/src/test/playwright/certs/generate-certs.sh similarity index 100% rename from src/test/cypress/certs/generate-certs.sh rename to src/test/playwright/certs/generate-certs.sh diff --git a/src/test/playwright/certs/rootCA.pem b/src/test/playwright/certs/rootCA.pem index df27e7384ca9..25b5da12b9d1 100644 --- a/src/test/playwright/certs/rootCA.pem +++ b/src/test/playwright/certs/rootCA.pem @@ -1,27 +1,27 @@ -----BEGIN CERTIFICATE----- -MIIEjTCCAvWgAwIBAgIQU1RC58hYfDrlnkOa5hWT9TANBgkqhkiG9w0BAQsFADBf -MR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExGjAYBgNVBAsMEXJvb3RA -MWY0ZmQzNzYzNmMyMSEwHwYDVQQDDBhta2NlcnQgcm9vdEAxZjRmZDM3NjM2YzIw -HhcNMjIxMjA1MDk0NTEzWhcNMzIxMjA1MDk0NTEzWjBfMR4wHAYDVQQKExVta2Nl -cnQgZGV2ZWxvcG1lbnQgQ0ExGjAYBgNVBAsMEXJvb3RAMWY0ZmQzNzYzNmMyMSEw -HwYDVQQDDBhta2NlcnQgcm9vdEAxZjRmZDM3NjM2YzIwggGiMA0GCSqGSIb3DQEB -AQUAA4IBjwAwggGKAoIBgQC6XajL1Rz5RQW0D+TxZ16msa5xAcKt5hEclOUB+oK+ -ychkUiDDSeh4EpkA2txu823n8BLqdNrIZ2A/TW3OVRXcD/hYFTbODI+FZ4DFEHoP -b8QnMlbZfo1AVNOR5ZFAVuneytaauhznnd1+Y49ieeX2v81hmBUKTuwDGVwp69rS -WUqANAKuGim7yOyBX6oRaUPg42xIBVHdDXkWr06zcFC6Z1O5zUYmFYHyn/sP2ZRN -BzMM+lVHCbZlw9Yi5TGLDC4wUAmMS9rColE5E76UNuOvfUERZffdLCzkmbS+VqOI -28fWvO/C8qEB10lcjxxplah4JZSyveH3Q5aFzLK2FbnXfLa/ypr3Mn9rBm06CtaL -Moy6h5gxNFDDB4RTpP7kjz32RRbl5xxqgkTEEAGDr/bk/C3DT6pyvGX5k6cj0zWd -o2bAO42Uk4ehMEHEUhnmvJ1yeOLSabgzfTJ3dM1NkdPI3Ss7dJGfraPx0sGet4SB -KMKw3mqJIizd1vV19TA/oRECAwEAAaNFMEMwDgYDVR0PAQH/BAQDAgIEMBIGA1Ud -EwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFKm4oAuSLB8udCabv4k0bZvEYAiDMA0G -CSqGSIb3DQEBCwUAA4IBgQBSPmSTP6Twe1T5UNqxfLSG/aKtT9yR1gAOW1zmM8KN -IZEwa1k6AH+y+dBT1MdFtSORVRagKNBwNsqqUMgPlXp9INpo+a5GFT4oAv73CrWu -bmXq7oiKkfk9UcdBNp3n8J+h+urXm4jEcUzTdNt8R631+seKOjYZz1SKOzpV5iz5 -20Mjk36RkiaiH3sxYvVo9ayXATz4Yq+0jWOHuQpYmFe2mH6wlle8hT/bRQb6/2z0 -wG/kKZl/CYbgRhc39np06mQ7FmAyXTtQORfjfhAUEu568JzPl/r2jYX1YgtEP4IL -GZXOdSYdtVC1vfpoWIo1YY+xqg3WRA/qgPFW33pZBk/qTaWE4ISMr0ewv613JDdK -ZOttGRDm2EDmh/FoeRoO5niydjb9DP915xObGMrYXKkPBpoIsQCfcmmFNQBAN4e4 -OQwSP9r/hh1cS8Usk6Ch0/iRhq7lv2Z5irLl/nQ4tPUZDVbBOhJ936t0gySVHbCl -GVOog28PQ8wI3fRZ2FZg6IM= +MIIEjjCCAvagAwIBAgIRAI6uW57QOeNpioQa9AKB664wDQYJKoZIhvcNAQELBQAw +XzEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMRowGAYDVQQLDBFyb290 +QGQzNjZiZGIwMGRkODEhMB8GA1UEAwwYbWtjZXJ0IHJvb3RAZDM2NmJkYjAwZGQ4 +MB4XDTI0MDYyMzE2MzE0MVoXDTM0MDYyMzE2MzE0MVowXzEeMBwGA1UEChMVbWtj +ZXJ0IGRldmVsb3BtZW50IENBMRowGAYDVQQLDBFyb290QGQzNjZiZGIwMGRkODEh +MB8GA1UEAwwYbWtjZXJ0IHJvb3RAZDM2NmJkYjAwZGQ4MIIBojANBgkqhkiG9w0B +AQEFAAOCAY8AMIIBigKCAYEAnJfQZabKJd/qNqgxv7G+Wq6wpmNZH42PwziYqKdj +KL+FSFx7959TYxKTfEKXi2SkuA1aLuZUBH8Wle2U2OBPxRpXU/aB6LjDWaRAO4aT +IsYnGYd+n67bF1QYquFcZwRtcExwlFA7y13XP4Rui/9PmFB8BpSiUe9kX0NUqRrL +K69GYwDqKdJSEgQPROFuD6RETSVAZMN71FDgdiUR8ozJ75tl5sJAOkLKTFuxSyD3 +MSCtdpdCnnnu2myozbjbyFYHYFNRh8ZujvbdaF8wPd8sGiMlEF2BpSXQ3nfohNfJ +Arx++hbhHI4kj9vfIbOrCM8403BoPQyLubu9blCmuQAApQk8UKMKGNDSGXX82oVk +clhgHogz48fKzaNK4USiZi5PmvlGzovpPdqrY4C5kyy38pRSCFMHRpDUkHc/oFe4 +L/f1juqLO2FtevDuPDEuEoPd/AiX09OufMpmpVDYGdCVVeBkgURk9D4lITX3+Q64 +x5mYd+ujZVzV6+XIudQj/D6pAgMBAAGjRTBDMA4GA1UdDwEB/wQEAwICBDASBgNV +HRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBQzmMmA0Q8av1gkkC6So7CcrgT5TDAN +BgkqhkiG9w0BAQsFAAOCAYEAY4B7i41qUmPEfXmI0Kp2lwtl/lXno69/a1jGC6ue +dm7V3mhejTzBVAKAP+0C9gmIhlZ/pXX0tNV50yK2KSlt/ukdXVdiLqavm5hQBJgm +nyWH+reIbH9IufDOz1N5vPchvZplHOTk9j2QGh/GVZ54BBMwdeEU2YP8WWibcZWh +LTvficJz67Rf57B/yhisbgaNe8y+8nY37vUdKMtUKlErEN7EaXJlCGhS7JkfEfsp +67EkO1ID+fMvBHBa3ZrPuWgWvkZB+V3hTKdKLca1Sc6eGx6nMRjflidB82rDOTEx +tfTdHvKqiomJIbENtlwSuHbhGCo0EWKqXOi7OeEP9kwUuSSfUgMvBQBLmQLJ1OQq +Y7p2icIuctbzvVIwv2DzKganz2Tz06pb/KMTUlAalfHpqRKB+wg8Sc53g1CtIKNu +Kd7jUSrRD3RBUNiq08GB6iS0cxjOwPpxm4vJp8TbsiDu2DEwhYkvyq2Q3mfBjSXc +zR2vjcpinbbB2wa+ENVB1mbX -----END CERTIFICATE----- diff --git a/src/test/playwright/e2e/exercise/modeling/ModelingExerciseManagement.spec.ts b/src/test/playwright/e2e/exercise/modeling/ModelingExerciseManagement.spec.ts index d1582cdc53b6..cd30ff8cf24b 100644 --- a/src/test/playwright/e2e/exercise/modeling/ModelingExerciseManagement.spec.ts +++ b/src/test/playwright/e2e/exercise/modeling/ModelingExerciseManagement.spec.ts @@ -1,5 +1,5 @@ import dayjs from 'dayjs'; -import { MODELING_EDITOR_CANVAS } from 'src/test/cypress/support/constants'; +import { MODELING_EDITOR_CANVAS } from '../../../support/constants'; import { Course } from 'app/entities/course.model'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; From aac495cfa2d57415bed8b911c47b77b6705880d2 Mon Sep 17 00:00:00 2001 From: Stephan Krusche Date: Mon, 2 Sep 2024 14:38:08 +0200 Subject: [PATCH 07/16] Development: Bump version to 7.5.2 --- README.md | 2 +- build.gradle | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 092d74dcdbb0..bbfc8945e870 100644 --- a/README.md +++ b/README.md @@ -166,7 +166,7 @@ Refer to [Using JHipster in production](http://www.jhipster.tech/production) for The following command can automate the deployment to a server. The example shows the deployment to the main Artemis test server (which runs a virtual machine): ```shell -./artemis-server-cli deploy username@artemistest.ase.in.tum.de -w build/libs/Artemis-7.5.1.war +./artemis-server-cli deploy username@artemistest.ase.in.tum.de -w build/libs/Artemis-7.5.2.war ``` ## Architecture diff --git a/build.gradle b/build.gradle index 9a023c709654..e53437485601 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ plugins { } group = "de.tum.in.www1.artemis" -version = "7.5.1" +version = "7.5.2" description = "Interactive Learning with Individual Feedback" java { diff --git a/package-lock.json b/package-lock.json index e0f6197e7588..0867dc1f015b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "artemis", - "version": "7.5.1", + "version": "7.5.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "artemis", - "version": "7.5.1", + "version": "7.5.2", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 0fba06f2db55..6a576592bbf0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "artemis", - "version": "7.5.1", + "version": "7.5.2", "description": "Interactive Learning with Individual Feedback", "private": true, "license": "MIT", From e1dc4ca974ff84535bdbfcc96ad1b0b9148a5cb3 Mon Sep 17 00:00:00 2001 From: Stephan Krusche Date: Tue, 3 Sep 2024 09:14:47 +0200 Subject: [PATCH 08/16] Development: Group client entities (#9268) --- .../upcoming-exams-and-exercises.component.ts | 2 +- .../assessment-header.component.ts | 2 +- .../assessment-instructions.component.ts | 4 +- .../webapp/app/assessment/athena.service.ts | 6 +- .../complaints-student-view.component.ts | 2 +- .../assessment-dashboard.component.ts | 2 +- .../exam-assessment-buttons.component.ts | 2 +- .../course/manage/course-update.component.ts | 2 +- .../manage/courses-for-dashboard-dto.ts | 2 +- .../detail-overview-list.component.ts | 2 +- .../app/detail-overview-list/detail.model.ts | 8 +- .../consistency-check-result.model.ts | 2 +- src/main/webapp/app/entities/course.model.ts | 4 +- .../{ => exam}/exam-checklist.model.ts | 0 .../exam-exercise-overview-item.model.ts | 0 .../{ => exam}/exam-information.model.ts | 0 .../entities/{ => exam}/exam-page.model.ts | 0 .../entities/{ => exam}/exam-session.model.ts | 2 +- .../{ => exam}/exam-user-dto.model.ts | 0 .../entities/{ => exam}/exam-user.model.ts | 2 +- .../exam-users-attendance-check-dto.model.ts | 0 .../app/entities/{ => exam}/exam.model.ts | 2 +- .../app/entities/exercise-group.model.ts | 2 +- .../webapp/app/entities/feedback.model.ts | 4 +- .../app/entities/grading-scale.model.ts | 2 +- .../entities/hestia/exercise-hint.model.ts | 2 +- ...gramming-exercise-git-diff-report.model.ts | 2 +- ...ogramming-exercise-solution-entry.model.ts | 2 +- .../hestia/programming-exercise-task.model.ts | 2 +- .../testwise-coverage-report-entry.model.ts | 2 +- .../iris/iris-exercise-chat-session.model.ts | 2 +- .../metis/conversation/channel.model.ts | 2 +- ...rogramming-exercise-participation.model.ts | 2 +- ...rogramming-exercise-participation.model.ts | 2 +- .../app/entities/programming/aeolus.result.ts | 7 ++ .../{ => programming}/build-agent.model.ts | 2 +- .../{ => programming}/build-config.model.ts | 0 .../{ => programming}/build-job.model.ts | 4 +- .../build-log-statistics-dto.ts | 0 .../{ => programming}/build-log.model.ts | 2 +- .../build-plan-checkout-directories-dto.ts | 0 .../{ => programming}/build-plan.model.ts | 2 +- .../app/entities/programming/build.action.ts | 19 +++++ .../checkout-directories-dto.ts | 2 +- .../programming/docker.configuration.ts | 6 ++ ...ing-exercise-auxiliary-repository-model.ts | 0 .../programming-exercise-build.config.ts | 19 +++++ ...rogramming-exercise-participation.model.ts | 0 ...ing-exercise-test-case-statistics.model.ts | 0 .../programming-exercise-test-case.model.ts | 2 +- .../programming-exercise.model.ts | 84 +++---------------- .../programming-submission.model.ts | 0 .../repository-info.model.ts | 0 .../static-code-analysis-category.model.ts | 0 .../static-code-analysis-issue.model.ts | 0 .../test-case-result.model.ts | 0 .../app/entities/programming/wind.file.ts | 8 ++ .../app/entities/programming/wind.metadata.ts | 9 ++ .../app/entities/quiz/quiz-pool.model.ts | 2 +- .../webapp/app/entities/student-exam.model.ts | 4 +- .../app/entities/submission-policy.model.ts | 2 +- .../{ => text}/text-assesment-event.model.ts | 2 +- .../{ => text}/text-block-ref.model.ts | 2 +- .../entities/{ => text}/text-block.model.ts | 2 +- .../entities/{ => text}/text-change.model.ts | 0 .../{ => text}/text-exercise.model.ts | 0 .../{ => text}/text-submission.model.ts | 2 +- .../manage/exam-management-resolve.service.ts | 2 +- .../exam/manage/exam-management.component.ts | 4 +- .../exam/manage/exam-management.service.ts | 10 +-- .../app/exam/manage/exam-status.component.ts | 4 +- ...ve-announcement-create-button.component.ts | 2 +- .../exam-checklist.component.ts | 4 +- .../exam-checklist.service.ts | 4 +- ...exam-edit-working-time-dialog.component.ts | 2 +- .../exam-edit-working-time.component.ts | 2 +- .../manage/exams/exam-detail.component.ts | 2 +- .../exam-exercise-import.component.ts | 2 +- .../exam-import/exam-import-paging.service.ts | 2 +- .../exam-import/exam-import.component.ts | 2 +- .../exam-mode-picker.component.ts | 2 +- .../manage/exams/exam-update.component.ts | 2 +- .../exercise-group-update.component.ts | 2 +- .../exercise-groups.component.ts | 4 +- ...ogramming-exercise-group-cell.component.ts | 4 +- ...rogramming-exercise-exam-diff.component.ts | 4 +- .../student-exam-timeline.component.ts | 4 +- .../student-exams/student-exams.component.ts | 2 +- .../students/exam-students.component.ts | 4 +- ...students-upload-images-button.component.ts | 2 +- ...students-upload-images-dialog.component.ts | 2 +- ...xam-students-attendance-check.component.ts | 4 +- .../suspicious-behavior.component.ts | 2 +- .../suspicious-sessions-overview.component.ts | 2 +- .../suspicious-sessions.service.ts | 2 +- .../suspicious-sessions.component.ts | 2 +- .../create-test-run-modal.component.ts | 2 +- .../test-run-management.component.ts | 2 +- .../exam-bar/exam-bar.component.ts | 2 +- .../exam-participation-cover.component.ts | 2 +- .../exam-navigation-bar.component.ts | 6 +- .../exam-navigation-sidebar.component.ts | 6 +- .../exam-participation.component.ts | 10 +-- .../participate/exam-participation.service.ts | 2 +- .../exam-start-information.component.ts | 2 +- .../webapp/app/exam/participate/exam.utils.ts | 2 +- .../exam-exercise-overview-page.component.ts | 2 +- .../programming-exam-submission.component.ts | 2 +- .../text/text-exam-submission.component.ts | 2 +- .../exam-general-information.component.ts | 2 +- .../summary/exam-result-summary.component.ts | 4 +- .../programming-exam-summary.component.ts | 6 +- .../quiz-exam-summary.component.ts | 2 +- .../text-exam-summary.component.ts | 2 +- .../working-time-control.component.ts | 2 +- ...or-tutor-assessment-container.component.ts | 4 +- ...assessment-repo-export-button.component.ts | 2 +- ...assessment-repo-export-dialog.component.ts | 2 +- ...code-hint-generation-overview.component.ts | 2 +- ...solution-entry-creation-modal.component.ts | 2 +- .../code-hint-generation-step.component.ts | 2 +- .../coverage-generation-step.component.ts | 2 +- .../diff-generation-step.component.ts | 2 +- ...olution-entry-generation-step.component.ts | 4 +- .../manage/build-plan-editor.component.ts | 4 +- ...tor-instructor-base-container.component.ts | 2 +- .../charts/category-issues-chart.component.ts | 4 +- ...a-category-distribution-chart.component.ts | 6 +- .../test-case-distribution-chart.component.ts | 6 +- ...test-case-passed-builds-chart.component.ts | 2 +- ...ise-configure-grading-actions.component.ts | 2 +- ...ng-exercise-configure-grading.component.ts | 8 +- ...-policy-configuration-actions.component.ts | 2 +- ...xercise-grading-table-actions.component.ts | 2 +- ...-exercise-grading-tasks-table.component.ts | 6 +- .../programming-exercise-task.service.ts | 6 +- .../tasks/programming-exercise-task.ts | 4 +- .../programming-exercise-task.component.ts | 2 +- ...exercise-editable-instruction.component.ts | 4 +- ...mming-exercise-create-buttons.component.ts | 2 +- .../programming-exercise-detail.component.ts | 5 +- ...amming-exercise-edit-selected.component.ts | 2 +- ...ming-exercise-management-routing.module.ts | 2 +- .../manage/programming-exercise.component.ts | 4 +- ...ramming-exercise-reset-button.directive.ts | 2 +- ...ramming-exercise-reset-dialog.component.ts | 2 +- .../manage/services/build-plan.service.ts | 2 +- .../services/code-analysis-paging.service.ts | 2 +- .../programming-exercise-grading.service.ts | 6 +- .../programming-exercise-paging.service.ts | 2 +- ...gramming-exercise-participation.service.ts | 2 +- .../programming-exercise-websocket.service.ts | 2 +- .../services/programming-exercise.service.ts | 8 +- ...se-instructor-exercise-status.component.ts | 2 +- ...ng-exercise-instructor-status.component.ts | 4 +- ...d-auxiliary-repository-button.component.ts | 4 +- .../programming-exercise-creation-config.ts | 4 +- .../programming-exercise-update.component.ts | 5 +- ...e-auxiliary-repository-button.component.ts | 4 +- ...cise-custom-aeolus-build-plan.component.ts | 3 +- ...ng-exercise-custom-build-plan.component.ts | 2 +- ...ogramming-exercise-difficulty.component.ts | 2 +- .../programming-exercise-grading.component.ts | 2 +- ...gramming-exercise-information.component.ts | 2 +- ...programming-exercise-language.component.ts | 2 +- .../programming-exercise-problem.component.ts | 2 +- .../programming-exercise-theia.component.ts | 2 +- ...code-editor-student-container.component.ts | 2 +- .../programming-submission-policy-status.ts | 2 +- .../programming-submission.service.ts | 2 +- ...e-instructor-submission-state.component.ts | 2 +- ...g-exercise-re-evaluate-button.component.ts | 2 +- ...g-exercise-trigger-all-button.component.ts | 2 +- ...exercise-trigger-build-button.component.ts | 2 +- ...ild-plan-checkout-directories.component.ts | 4 +- ...sitory-and-build-plan-details.component.ts | 4 +- .../code-editor-build-output.component.ts | 8 +- .../code-editor/model/code-editor.model.ts | 2 +- .../commits-info-group.component.ts | 2 +- .../commits-info-row.component.ts | 2 +- .../commits-info/commits-info.component.ts | 2 +- ...rogramming-exercise-plant-uml.extension.ts | 2 +- ...gramming-exercise-instruction.component.ts | 4 +- ...rogramming-exercise-instruction.service.ts | 2 +- ...rogramming-exercise-lifecycle.component.ts | 2 +- .../shared/service/aeolus.service.ts | 4 +- .../shared/service/build-log.service.ts | 2 +- .../programming-language-feature.service.ts | 2 +- .../shared/service/theia.service.ts | 2 +- .../utils/programming-exercise.utils.ts | 4 +- .../manage/quiz-exercise-update.component.ts | 2 +- .../quiz/manage/quiz-pool.component.ts | 2 +- ...z-question-list-edit-existing.component.ts | 2 +- .../course-exercise.service.ts | 4 +- ...exercise-assessment-dashboard.component.ts | 8 +- .../language-table-cell.component.ts | 2 +- .../exam-exercise-row-buttons.component.ts | 2 +- .../example-submission.service.ts | 2 +- ...er-exercise-page-with-details.component.ts | 6 +- .../manage/exercise-hint-update.component.ts | 2 +- .../manage/exercise-hint.component.ts | 2 +- ...exercise-scores-export-button.component.ts | 4 +- .../exercise-scores.component.ts | 4 +- .../shared/exercise/exercise.service.ts | 4 +- .../shared/exercise/exercise.utils.ts | 2 +- .../shared/feedback/feedback.component.ts | 6 +- .../group/programming-feedback-groups.ts | 2 +- .../item/programming-feedback-item.service.ts | 2 +- .../exercise-import-wrapper.component.ts | 2 +- .../import/exercise-import.component.ts | 2 +- .../exercise-import-from-file.component.ts | 3 +- .../shared/manage/exercise-paging.service.ts | 2 +- .../participation-submission.component.ts | 4 +- .../participation/participation.component.ts | 2 +- .../text-submission-viewer.component.ts | 6 +- .../shared/result/result.component.ts | 4 +- .../exercises/shared/result/result.service.ts | 4 +- .../exercises/shared/result/result.utils.ts | 6 +- .../result/updating-result.component.ts | 2 +- .../submission-policy-update.component.ts | 2 +- .../shared/submission/submission.service.ts | 2 +- .../text-assesment-analytics.service.ts | 4 +- .../manual-textblock-selection.component.ts | 6 +- .../text-assessment-area.component.ts | 4 +- .../assess/text-assessment-base.component.ts | 8 +- .../text/assess/text-assessment.service.ts | 6 +- .../text-submission-assessment.component.ts | 8 +- .../text-submission-assessment.route.ts | 2 +- .../textblock-assessment-card.component.ts | 6 +- .../textblock-feedback-editor.component.ts | 4 +- .../example-text-submission.component.ts | 4 +- .../text-exercise-detail.component.ts | 2 +- .../text-exercise-paging.service.ts | 2 +- .../text-exercise-row-buttons.component.ts | 2 +- .../text-exercise-update.component.ts | 2 +- .../text-exercise/text-exercise.component.ts | 2 +- .../text-exercise/text-exercise.route.ts | 2 +- .../text-exercise/text-exercise.service.ts | 2 +- .../text/participate/text-editor.component.ts | 4 +- .../text-result/text-result-block.ts | 2 +- .../text-result/text-result.component.ts | 4 +- .../participate/text-submission.service.ts | 2 +- .../manual-text-selection.component.ts | 6 +- .../base-grading-system.component.ts | 2 +- .../build-agent-details.component.ts | 4 +- .../build-agent-summary.component.ts | 2 +- .../build-agents/build-agents.service.ts | 2 +- .../build-queue/build-queue.component.ts | 4 +- .../build-queue/build-queue.service.ts | 2 +- .../commit-details-view.component.ts | 2 +- .../commit-history.component.ts | 4 +- .../repository-view.component.ts | 2 +- .../assessment/orion-assessment.service.ts | 2 +- .../orion-programming-exercise.component.ts | 2 +- ...rcise-details-student-actions.component.ts | 2 +- .../course-exams/course-exams.component.ts | 2 +- .../app/overview/course-overview.service.ts | 2 +- .../webapp/app/overview/courses.component.ts | 2 +- .../course-exercise-details.component.ts | 2 +- ...rcise-details-student-actions.component.ts | 2 +- .../participation-websocket.service.ts | 2 +- .../code-button/code-button.component.ts | 2 +- .../course-exam-archive-button.component.ts | 2 +- .../reset-repo-button.component.ts | 2 +- .../start-practice-mode-button.component.ts | 2 +- .../consistency-check.component.ts | 2 +- .../tutor-leaderboard.component.ts | 2 +- .../tutor-participation-graph.component.ts | 2 +- .../webapp/app/shared/http/file.service.ts | 2 +- .../orion/orion-build-and-test.service.ts | 6 +- .../shared/orion/orion-connector.service.ts | 2 +- .../users-import-button.component.ts | 2 +- .../users-import-dialog.component.ts | 4 +- .../assessment-dashboard.component.spec.ts | 6 +- .../exam-assessment-buttons.component.spec.ts | 2 +- ...ise-assessment-dashboard.component.spec.ts | 10 +-- .../assessment-header.component.spec.ts | 2 +- .../assessment-instructions.component.spec.ts | 4 +- .../assessment-locks.component.spec.ts | 4 +- .../assessment-warning.component.spec.ts | 4 +- ...code-editor-build-output.component.spec.ts | 8 +- .../complaint-response.service.spec.ts | 2 +- .../complaint-student-view.component.spec.ts | 2 +- .../complaints/complaint.service.spec.ts | 2 +- .../list-of-complaints.component.spec.ts | 4 +- .../consistency-check.component.spec.ts | 2 +- ...course-lti-configuration.component.spec.ts | 2 +- .../course/course-overview.component.spec.ts | 2 +- .../course/course-overview.service.spec.ts | 4 +- .../course/course-update.component.spec.ts | 2 +- .../component/course/course.component.spec.ts | 2 +- .../course/exercise-filter.model.spec.ts | 4 +- ...xam-exercise-row-buttons.component.spec.ts | 6 +- .../exam/exam-update.component.spec.ts | 4 +- .../component/exam/feedback.utils.spec.ts | 2 +- .../exam-exercise-import.component.spec.ts | 6 +- ...xam-exercise-row-buttons.component.spec.ts | 2 +- .../exam/manage/exam-import.component.spec.ts | 2 +- .../manage/exam-management-resolve.spec.ts | 2 +- .../manage/exam-management.component.spec.ts | 4 +- .../manage/exam-management.service.spec.ts | 10 +-- ...tudents-attendance-check.component.spec.ts | 4 +- .../manage/exam-students.component.spec.ts | 6 +- ...nouncement-create-button.component.spec.ts | 2 +- .../exams/exam-checklist.component.spec.ts | 4 +- .../exams/exam-detail.component.spec.ts | 2 +- .../exercise-group-update.component.spec.ts | 2 +- .../exercise-groups.component.spec.ts | 4 +- ...ming-exercise-group-cell.component.spec.ts | 2 +- .../programming-exam-diff.component.spec.ts | 2 +- .../exam-status.component.spec.ts | 4 +- ...nt-exam-detail-table-row.component.spec.ts | 4 +- .../student-exam-detail.component.spec.ts | 2 +- .../student-exam-summary.component.spec.ts | 2 +- .../student-exam-timeline.component.spec.ts | 10 +-- .../student-exams.component.spec.ts | 2 +- ...nts-upload-images-button.component.spec.ts | 2 +- ...nts-upload-images-dialog.component.spec.ts | 2 +- .../user-import-button.component.spec.ts | 2 +- .../user-import-dialog.component.spec.ts | 4 +- .../suspicious-behavior.component.spec.ts | 2 +- ...icious-sessions-overview.component.spec.ts | 2 +- .../suspicious-sessions.component.spec.ts | 2 +- .../suspicious-sessions.service.spec.ts | 2 +- .../participate/exam-bar.component.spec.ts | 2 +- .../exam-navigation-bar.component.spec.ts | 2 +- .../exam-navigation-sidebar.component.spec.ts | 2 +- ...exam-participation-cover.component.spec.ts | 2 +- .../exam-participation.component.spec.ts | 12 +-- .../exam-start-information.component.spec.ts | 2 +- .../exam/participate/exam.utils.spec.ts | 2 +- ...gramming-exam-submission.component.spec.ts | 4 +- .../text-exam-submission.component.spec.ts | 4 +- ...exam-general-information.component.spec.ts | 2 +- .../exam-result-summary.component.spec.ts | 10 +-- ...ary-exercise-card-header.component.spec.ts | 6 +- ...programming-exam-summary.component.spec.ts | 6 +- .../quiz-exam-summary.component.spec.ts | 2 +- .../text-exam-summary.component.spec.ts | 2 +- .../exam-result-overview.component.spec.ts | 6 +- ...tudent-exam-working-time.component.spec.ts | 2 +- .../testexam-working-time.component.spec.ts | 2 +- .../working-time-control.component.spec.ts | 2 +- .../create-test-run-modal.component.spec.ts | 2 +- .../test-run-management.component.spec.ts | 2 +- .../exercise-hint-update.component.spec.ts | 4 +- .../manage/exercise-hint.component.spec.ts | 2 +- ...exercise-hint-expandable.component.spec.ts | 2 +- .../code-hint-container.component.spec.ts | 2 +- .../problem-statement.component.spec.ts | 4 +- .../quiz/manage/quiz-pool.component.spec.ts | 2 +- ...stion-list-edit-existing.component.spec.ts | 2 +- ...xample-submission-import.component.spec.ts | 2 +- .../example-submissions.component.spec.ts | 2 +- ...ise-scores-export-button.component.spec.ts | 2 +- .../exercise-scores.component.spec.ts | 2 +- ...rcise-title-channel-name.component.spec.ts | 2 +- .../difficulty-badge.component.spec.ts | 2 +- ...ercise-page-with-details.component.spec.ts | 6 +- ...eader-participation-page.component.spec.ts | 4 +- .../component/exercises/shared/result.spec.ts | 2 +- .../team-config-form-group.component.spec.ts | 2 +- .../team-submission-sync.component.spec.ts | 2 +- ...e-upload-exercise-update.component.spec.ts | 4 +- .../detailed-grading-system.component.spec.ts | 2 +- .../interval-grading-system.component.spec.ts | 2 +- ...hint-generation-overview.component.spec.ts | 2 +- ...ode-hint-generation-step.component.spec.ts | 2 +- ...coverage-generation-step.component.spec.ts | 2 +- .../diff-generation-step.component.spec.ts | 2 +- ...ion-entry-creation-modal.component.spec.ts | 2 +- ...tion-entry-details-modal.component.spec.ts | 2 +- ...on-entry-generation-step.component.spec.ts | 4 +- .../testwise-coverage-file.component.spec.ts | 2 +- ...testwise-coverage-report.component.spec.ts | 2 +- ...xercise-import-from-file.component.spec.ts | 4 +- .../exercise-import-wrapper.component.spec.ts | 2 +- .../import/exercise-import.component.spec.ts | 4 +- .../component/import/import.component.spec.ts | 2 +- .../settings/iris-enabled.component.spec.ts | 2 +- .../exercise-node-details.component.spec.ts | 2 +- .../learning-path-container.component.spec.ts | 2 +- .../create-exercise-unit.component.spec.ts | 4 +- .../exercise-unit.component.spec.ts | 2 +- .../exercise-unit.service.spec.ts | 2 +- .../lecture-unit/lecture-unit.service.spec.ts | 2 +- ...ture-wizard-competencies.component.spec.ts | 2 +- .../build-agent-details.component.spec.ts | 8 +- .../build-agent-summary.component.spec.ts | 8 +- .../build-agents/build-agents.service.spec.ts | 8 +- .../build-queue/build-queue.component.spec.ts | 4 +- .../build-queue/build-queue.service.spec.ts | 6 +- .../commit-details-view.component.spec.ts | 4 +- .../localvc/commit-history.component.spec.ts | 4 +- .../localvc/repository-view.component.spec.ts | 2 +- ...deling-assessment-editor.component.spec.ts | 4 +- ...modeling-exercise-update.component.spec.ts | 2 +- ...se-detail-common-actions.component.spec.ts | 4 +- ...tor-and-editor-container.component.spec.ts | 2 +- ...ise-assessment-dashboard.component.spec.ts | 2 +- .../overview/course-card.component.spec.ts | 2 +- ...rse-competencies-details.component.spec.ts | 2 +- .../course-exams.component.spec.ts | 2 +- .../course-statistics.component.spec.ts | 2 +- .../course-exercise-details.component.spec.ts | 6 +- ...-details-student-actions.component.spec.ts | 4 +- ...participation-submission.component.spec.ts | 6 +- .../participation.component.spec.ts | 4 +- ...ercise-update-plagiarism.component.spec.ts | 2 +- ...e-instructor-detail-view.component.spec.ts | 2 +- ...case-student-detail-view.component.spec.ts | 2 +- ...sm-cases-instructor-view.component.spec.ts | 2 +- .../plagiarism-inspector.component.spec.ts | 4 +- .../plagiarism-split-view.component.spec.ts | 2 +- .../text-submission-viewer.component.spec.ts | 4 +- ...tor-assessment-container.component.spec.ts | 4 +- ...sment-repo-export-button.component.spec.ts | 2 +- ...sment-repo-export-dialog.component.spec.ts | 2 +- .../build-plan-editor.component.spec.ts | 4 +- .../category-issues-chart.component.spec.ts | 2 +- ...ercise-configure-grading.component.spec.ts | 8 +- ...-exercise-create-buttons.component.spec.ts | 2 +- ...custom-aeolus-build-plan.component.spec.ts | 16 ++-- ...ercise-custom-build-plan.component.spec.ts | 16 ++-- ...gramming-exercise-detail.component.spec.ts | 6 +- ...g-exercise-edit-selected.component.spec.ts | 2 +- ...ise-editable-instruction.component.spec.ts | 2 +- ...ing-exercise-instruction.component.spec.ts | 2 +- ...ercise-instructor-status.component.spec.ts | 4 +- ...tructor-submission-state.component.spec.ts | 2 +- ...tor-trigger-build-button.component.spec.ts | 2 +- ...mming-exercise-lifecycle.component.spec.ts | 2 +- ...rcise-re-evaluate-button.component.spec.ts | 2 +- ...y-and-build-plan-details.component.spec.ts | 6 +- ...ng-exercise-reset-dialog.component.spec.ts | 2 +- ...ase-passed-builds-charts.component.spec.ts | 2 +- ...rcise-trigger-all-button.component.spec.ts | 2 +- ...ise-trigger-build-button.component.spec.ts | 2 +- ...gramming-exercise-update.component.spec.ts | 5 +- .../programming-exercise.component.spec.ts | 2 +- ...egory-distribution-chart.component.spec.ts | 6 +- ...cise-grading-tasks-table.component.spec.ts | 6 +- ...rogramming-exercise-task.component.spec.ts | 2 +- ...-case-distribution-chart.component.spec.ts | 6 +- ...ogramming-exercise-creation-config-mock.ts | 4 +- ...ming-exercise-difficulty.component.spec.ts | 2 +- ...ramming-exercise-grading.component.spec.ts | 2 +- ...ing-exercise-information.component.spec.ts | 2 +- ...amming-exercise-language.component.spec.ts | 2 +- ...ramming-exercise-problem.component.spec.ts | 2 +- ...iliary-repository-button.component.spec.ts | 4 +- ...ogramming-exercise-theia.component.spec.ts | 2 +- .../quiz-exercise-update.component.spec.ts | 2 +- .../commits-info-group.component.spec.ts | 2 +- .../shared/commits-info.component.spec.ts | 2 +- ...urse-exam-archive-button.component.spec.ts | 2 +- .../shared/example-solution.component.spec.ts | 2 +- .../feedback/feedback-modal.component.spec.ts | 4 +- .../standalone-feedback.component.spec.ts | 2 +- .../reset-repo-button.component.spec.ts | 2 +- ...art-practice-mode-button.component.spec.ts | 2 +- ...submission-policy-update.component.spec.ts | 2 +- .../shared/updating-result.component.spec.ts | 2 +- .../team-exercise-search.component.spec.ts | 2 +- .../text-editor/text-editor.component.spec.ts | 4 +- .../example-text-submission.component.spec.ts | 8 +- .../text-exercise-detail.component.spec.ts | 2 +- ...ext-exercise-row-buttons.component.spec.ts | 2 +- .../text-exercise-update.component.spec.ts | 4 +- .../text-exercise.component.spec.ts | 2 +- .../text-result/text-result.component.spec.ts | 4 +- ...nual-textblock-selection.component.spec.ts | 6 +- .../text-assessment-area.component.spec.ts | 2 +- ...xt-submission-assessment.component.spec.ts | 8 +- ...extblock-assessment-card.component.spec.ts | 6 +- ...extblock-feedback-editor.component.spec.ts | 4 +- .../manual-text-selection.component.spec.ts | 8 +- .../tutor-leaderboard.component.spec.ts | 2 +- .../component/utils/exercise.utils.spec.ts | 2 +- .../utils/programming-exercise.utils.spec.ts | 4 +- .../mocks/service/mock-build-plan.service.ts | 2 +- .../mock-code-editor-build-log.service.ts | 2 +- .../service/mock-course-exercise.service.ts | 2 +- .../service/mock-course-management.service.ts | 2 +- .../service/mock-exam-checklist.service.ts | 4 +- .../service/mock-exam-management.service.ts | 2 +- .../mock-ide-build-and-test.service.ts | 2 +- ...ck-programming-exercise-grading.service.ts | 6 +- ...gramming-exercise-participation.service.ts | 2 +- .../mock-programming-exercise.service.ts | 2 +- .../mocks/service/mock-team.service.ts | 2 +- .../service/mock-text-submission.service.ts | 2 +- .../spec/helpers/sample/iris-sample-data.ts | 2 +- .../spec/helpers/sample/metis-sample-data.ts | 2 +- .../code-editor-container.integration.spec.ts | 6 +- ...code-editor-instructor.integration.spec.ts | 2 +- .../code-editor-student.integration.spec.ts | 2 +- .../spec/service/athena.service.spec.ts | 4 +- .../spec/service/build-log.service.spec.ts | 2 +- .../service/chart-category-filter.spec.ts | 2 +- .../service/course-exercise.service.spec.ts | 4 +- .../service/exam-checklist.service.spec.ts | 4 +- .../exam-import-paging.service.spec.ts | 2 +- .../exam-participation.service.spec.ts | 6 +- ...e-submission-import-paging.service.spec.ts | 2 +- .../example-submission.service.spec.ts | 2 +- .../service/exercise-hint.service.spec.ts | 2 +- .../exercise-update-warning.service.spec.ts | 2 +- .../spec/service/exercise.service.spec.ts | 4 +- .../external-submission.service.spec.ts | 2 +- .../programming-feedback-item.service.spec.ts | 2 +- .../orion-build-and-test.service.spec.ts | 4 +- .../orion/orion-connector.service.spec.ts | 2 +- .../service/participation.service.spec.ts | 2 +- .../service/plagiarism-cases.service.spec.ts | 2 +- .../spec/service/profile.service.spec.ts | 2 +- ...ogramming-exercise-grading.service.spec.ts | 2 +- .../programming-exercise-task.service.spec.ts | 6 +- .../programming-exercise.service.spec.ts | 4 +- .../programming-submission.service.spec.ts | 2 +- .../spec/service/result.service.spec.ts | 4 +- .../service/submission-policy.service.spec.ts | 2 +- .../submission-version.service.spec.ts | 2 +- .../spec/service/submission.service.spec.ts | 2 +- .../text-assessment-analytics.service.spec.ts | 4 +- .../service/text-assessment.service.spec.ts | 8 +- .../service/text-exercise.service.spec.ts | 2 +- .../service/text-submission.service.spec.ts | 2 +- .../e2e/exam/ExamAssessment.spec.ts | 2 +- .../e2e/exam/ExamCreationDeletion.spec.ts | 2 +- .../e2e/exam/ExamManagement.spec.ts | 2 +- .../e2e/exam/ExamParticipation.spec.ts | 2 +- .../playwright/e2e/exam/ExamResults.spec.ts | 2 +- .../playwright/e2e/exam/ExamTestRun.spec.ts | 2 +- .../TestExamCreationDeletion.spec.ts | 2 +- .../exam/test-exam/TestExamManagement.spec.ts | 2 +- .../test-exam/TestExamParticipation.spec.ts | 2 +- .../test-exam/TestExamStudentExams.spec.ts | 2 +- .../exam/test-exam/TestExamTestRun.spec.ts | 2 +- .../e2e/exercise/ExerciseImport.spec.ts | 6 +- .../ProgrammingExerciseAssessment.spec.ts | 2 +- .../ProgrammingExerciseManagement.spec.ts | 2 +- .../ProgrammingExerciseParticipation.spec.ts | 2 +- ...grammingExerciseStaticCodeAnalysis.spec.ts | 2 +- .../text/TextExerciseAssessment.spec.ts | 2 +- .../text/TextExerciseManagement.spec.ts | 4 +- .../text/TextExerciseParticipation.spec.ts | 4 +- .../exam/ExamExerciseGroupCreationPage.ts | 4 +- .../pageobjects/exam/ExamParticipationPage.ts | 2 +- .../pageobjects/exam/ExamTestRunPage.ts | 2 +- .../requests/CourseManagementAPIRequests.ts | 2 +- .../support/requests/ExamAPIRequests.ts | 2 +- .../support/requests/ExerciseAPIRequests.ts | 8 +- 553 files changed, 889 insertions(+), 890 deletions(-) rename src/main/webapp/app/entities/{ => exam}/exam-checklist.model.ts (100%) rename src/main/webapp/app/entities/{ => exam}/exam-exercise-overview-item.model.ts (100%) rename src/main/webapp/app/entities/{ => exam}/exam-information.model.ts (100%) rename src/main/webapp/app/entities/{ => exam}/exam-page.model.ts (100%) rename src/main/webapp/app/entities/{ => exam}/exam-session.model.ts (97%) rename src/main/webapp/app/entities/{ => exam}/exam-user-dto.model.ts (100%) rename src/main/webapp/app/entities/{ => exam}/exam-user.model.ts (93%) rename src/main/webapp/app/entities/{ => exam}/exam-users-attendance-check-dto.model.ts (100%) rename src/main/webapp/app/entities/{ => exam}/exam.model.ts (97%) create mode 100644 src/main/webapp/app/entities/programming/aeolus.result.ts rename src/main/webapp/app/entities/{ => programming}/build-agent.model.ts (84%) rename src/main/webapp/app/entities/{ => programming}/build-config.model.ts (100%) rename src/main/webapp/app/entities/{ => programming}/build-job.model.ts (93%) rename src/main/webapp/app/entities/{ => programming}/build-log-statistics-dto.ts (100%) rename src/main/webapp/app/entities/{ => programming}/build-log.model.ts (99%) rename src/main/webapp/app/entities/{ => programming}/build-plan-checkout-directories-dto.ts (100%) rename src/main/webapp/app/entities/{ => programming}/build-plan.model.ts (71%) create mode 100644 src/main/webapp/app/entities/programming/build.action.ts rename src/main/webapp/app/entities/{ => programming}/checkout-directories-dto.ts (63%) create mode 100644 src/main/webapp/app/entities/programming/docker.configuration.ts rename src/main/webapp/app/entities/{ => programming}/programming-exercise-auxiliary-repository-model.ts (100%) create mode 100644 src/main/webapp/app/entities/programming/programming-exercise-build.config.ts rename src/main/webapp/app/entities/{ => programming}/programming-exercise-participation.model.ts (100%) rename src/main/webapp/app/entities/{ => programming}/programming-exercise-test-case-statistics.model.ts (100%) rename src/main/webapp/app/entities/{ => programming}/programming-exercise-test-case.model.ts (92%) rename src/main/webapp/app/entities/{ => programming}/programming-exercise.model.ts (76%) rename src/main/webapp/app/entities/{ => programming}/programming-submission.model.ts (100%) rename src/main/webapp/app/entities/{ => programming}/repository-info.model.ts (100%) rename src/main/webapp/app/entities/{ => programming}/static-code-analysis-category.model.ts (100%) rename src/main/webapp/app/entities/{ => programming}/static-code-analysis-issue.model.ts (100%) rename src/main/webapp/app/entities/{ => programming}/test-case-result.model.ts (100%) create mode 100644 src/main/webapp/app/entities/programming/wind.file.ts create mode 100644 src/main/webapp/app/entities/programming/wind.metadata.ts rename src/main/webapp/app/entities/{ => text}/text-assesment-event.model.ts (95%) rename src/main/webapp/app/entities/{ => text}/text-block-ref.model.ts (91%) rename src/main/webapp/app/entities/{ => text}/text-block.model.ts (96%) rename src/main/webapp/app/entities/{ => text}/text-change.model.ts (100%) rename src/main/webapp/app/entities/{ => text}/text-exercise.model.ts (100%) rename src/main/webapp/app/entities/{ => text}/text-submission.model.ts (84%) diff --git a/src/main/webapp/app/admin/upcoming-exams-and-exercises/upcoming-exams-and-exercises.component.ts b/src/main/webapp/app/admin/upcoming-exams-and-exercises/upcoming-exams-and-exercises.component.ts index bb8614435e1d..8855ae1fb047 100644 --- a/src/main/webapp/app/admin/upcoming-exams-and-exercises/upcoming-exams-and-exercises.component.ts +++ b/src/main/webapp/app/admin/upcoming-exams-and-exercises/upcoming-exams-and-exercises.component.ts @@ -3,7 +3,7 @@ import { HttpResponse } from '@angular/common/http'; import { EntityArrayResponseType as ExerciseEntityArrayResponseType, ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; import { Exercise } from 'app/entities/exercise.model'; import { SortService } from 'app/shared/service/sort.service'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; @Component({ diff --git a/src/main/webapp/app/assessment/assessment-header/assessment-header.component.ts b/src/main/webapp/app/assessment/assessment-header/assessment-header.component.ts index a2418b6b35d4..3245b9f4af72 100644 --- a/src/main/webapp/app/assessment/assessment-header/assessment-header.component.ts +++ b/src/main/webapp/app/assessment/assessment-header/assessment-header.component.ts @@ -2,7 +2,7 @@ import { Component, EventEmitter, HostListener, Input, Output } from '@angular/c import { Result } from 'app/entities/result.model'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; import { TextAssessmentAnalytics } from 'app/exercises/text/assess/analytics/text-assesment-analytics.service'; -import { TextAssessmentEventType } from 'app/entities/text-assesment-event.model'; +import { TextAssessmentEventType } from 'app/entities/text/text-assesment-event.model'; import { ActivatedRoute } from '@angular/router'; import { ComplaintType } from 'app/entities/complaint.model'; import { AssessmentType } from 'app/entities/assessment-type.model'; diff --git a/src/main/webapp/app/assessment/assessment-instructions/assessment-instructions/assessment-instructions.component.ts b/src/main/webapp/app/assessment/assessment-instructions/assessment-instructions/assessment-instructions.component.ts index c7c7aa77c910..d854c6f7ad58 100644 --- a/src/main/webapp/app/assessment/assessment-instructions/assessment-instructions/assessment-instructions.component.ts +++ b/src/main/webapp/app/assessment/assessment-instructions/assessment-instructions/assessment-instructions.component.ts @@ -3,10 +3,10 @@ import { SafeHtml } from '@angular/platform-browser'; import { UMLDiagramType, UMLModel } from '@ls1intum/apollon'; import { ArtemisMarkdownService } from 'app/shared/markdown.service'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; import { FileUploadExercise } from 'app/entities/file-upload-exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { GradingCriterion } from 'app/exercises/shared/structured-grading-criterion/grading-criterion.model'; import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model'; diff --git a/src/main/webapp/app/assessment/athena.service.ts b/src/main/webapp/app/assessment/athena.service.ts index 01e7d4ca0def..962e56b70a39 100644 --- a/src/main/webapp/app/assessment/athena.service.ts +++ b/src/main/webapp/app/assessment/athena.service.ts @@ -5,9 +5,9 @@ import { ProfileService } from 'app/shared/layouts/profiles/profile.service'; import { ModelingFeedbackSuggestion, ProgrammingFeedbackSuggestion, TextFeedbackSuggestion } from 'app/entities/feedback-suggestion.model'; import { Exercise } from 'app/entities/exercise.model'; import { FEEDBACK_SUGGESTION_ACCEPTED_IDENTIFIER, FEEDBACK_SUGGESTION_IDENTIFIER, Feedback, FeedbackType } from 'app/entities/feedback.model'; -import { TextBlock } from 'app/entities/text-block.model'; -import { TextBlockRef } from 'app/entities/text-block-ref.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextBlock } from 'app/entities/text/text-block.model'; +import { TextBlockRef } from 'app/entities/text/text-block-ref.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { PROFILE_ATHENA } from 'app/app.constants'; import { ModelingSubmission } from 'app/entities/modeling-submission.model'; import { UMLModel, findElement } from '@ls1intum/apollon'; diff --git a/src/main/webapp/app/complaints/complaints-for-students/complaints-student-view.component.ts b/src/main/webapp/app/complaints/complaints-for-students/complaints-student-view.component.ts index b37486509496..b469dcab432f 100644 --- a/src/main/webapp/app/complaints/complaints-for-students/complaints-student-view.component.ts +++ b/src/main/webapp/app/complaints/complaints-for-students/complaints-student-view.component.ts @@ -6,7 +6,7 @@ import { StudentParticipation } from 'app/entities/participation/student-partici import { Result } from 'app/entities/result.model'; import { Course } from 'app/entities/course.model'; import { ArtemisServerDateService } from 'app/shared/server-date.service'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { AccountService } from 'app/core/auth/account.service'; import { Submission } from 'app/entities/submission.model'; import { filter } from 'rxjs/operators'; diff --git a/src/main/webapp/app/course/dashboards/assessment-dashboard/assessment-dashboard.component.ts b/src/main/webapp/app/course/dashboards/assessment-dashboard/assessment-dashboard.component.ts index 1f813c75104c..a39b6af80e77 100644 --- a/src/main/webapp/app/course/dashboards/assessment-dashboard/assessment-dashboard.component.ts +++ b/src/main/webapp/app/course/dashboards/assessment-dashboard/assessment-dashboard.component.ts @@ -13,7 +13,7 @@ import { Course } from 'app/entities/course.model'; import { DueDateStat } from 'app/course/dashboards/due-date-stat.model'; import { FilterProp as TeamFilterProp } from 'app/exercises/shared/team/teams.component'; import { SortService } from 'app/shared/service/sort.service'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; diff --git a/src/main/webapp/app/course/dashboards/assessment-dashboard/exam-assessment-buttons/exam-assessment-buttons.component.ts b/src/main/webapp/app/course/dashboards/assessment-dashboard/exam-assessment-buttons/exam-assessment-buttons.component.ts index 704c19d37fdc..7bc20e00e55c 100644 --- a/src/main/webapp/app/course/dashboards/assessment-dashboard/exam-assessment-buttons/exam-assessment-buttons.component.ts +++ b/src/main/webapp/app/course/dashboards/assessment-dashboard/exam-assessment-buttons/exam-assessment-buttons.component.ts @@ -9,7 +9,7 @@ import { Course } from 'app/entities/course.model'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { AlertService } from 'app/core/util/alert.service'; import { HttpErrorResponse } from '@angular/common/http'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import dayjs from 'dayjs/esm'; import { AccountService } from 'app/core/auth/account.service'; import { onError } from 'app/shared/util/global.utils'; diff --git a/src/main/webapp/app/course/manage/course-update.component.ts b/src/main/webapp/app/course/manage/course-update.component.ts index cc260d0a289b..a3406ad5f46b 100644 --- a/src/main/webapp/app/course/manage/course-update.component.ts +++ b/src/main/webapp/app/course/manage/course-update.component.ts @@ -21,7 +21,7 @@ import { OrganizationSelectorComponent } from 'app/shared/organization-selector/ import { faBan, faExclamationTriangle, faPen, faQuestionCircle, faSave, faTimes, faTrash } from '@fortawesome/free-solid-svg-icons'; import { base64StringToBlob } from 'app/utils/blob-util'; import { ImageCroppedEvent } from 'app/shared/image-cropper/interfaces/image-cropped-event.interface'; -import { ProgrammingLanguage } from 'app/entities/programming-exercise.model'; +import { ProgrammingLanguage } from 'app/entities/programming/programming-exercise.model'; import { CourseAdminService } from 'app/course/manage/course-admin.service'; import { FeatureToggle, FeatureToggleService } from 'app/shared/feature-toggle/feature-toggle.service'; import { AccountService } from 'app/core/auth/account.service'; diff --git a/src/main/webapp/app/course/manage/courses-for-dashboard-dto.ts b/src/main/webapp/app/course/manage/courses-for-dashboard-dto.ts index 43d6336168a7..123e334cca33 100644 --- a/src/main/webapp/app/course/manage/courses-for-dashboard-dto.ts +++ b/src/main/webapp/app/course/manage/courses-for-dashboard-dto.ts @@ -1,5 +1,5 @@ import { CourseForDashboardDTO } from 'app/course/manage/course-for-dashboard-dto'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; export class CoursesForDashboardDTO { courses: CourseForDashboardDTO[]; diff --git a/src/main/webapp/app/detail-overview-list/detail-overview-list.component.ts b/src/main/webapp/app/detail-overview-list/detail-overview-list.component.ts index 7f98ff940ef1..4f49ce9fe006 100644 --- a/src/main/webapp/app/detail-overview-list/detail-overview-list.component.ts +++ b/src/main/webapp/app/detail-overview-list/detail-overview-list.component.ts @@ -9,7 +9,7 @@ import { ProgrammingExerciseGitDiffReport } from 'app/entities/hestia/programmin import { IrisSubSettingsType } from 'app/entities/iris/settings/iris-sub-settings.model'; import { ModelingExerciseService } from 'app/exercises/modeling/manage/modeling-exercise.service'; import { AlertService } from 'app/core/util/alert.service'; -import { ProgrammingExerciseParticipationType } from 'app/entities/programming-exercise-participation.model'; +import { ProgrammingExerciseParticipationType } from 'app/entities/programming/programming-exercise-participation.model'; import { Detail } from 'app/detail-overview-list/detail.model'; import { UMLModel } from '@ls1intum/apollon'; import { ProfileService } from 'app/shared/layouts/profiles/profile.service'; diff --git a/src/main/webapp/app/detail-overview-list/detail.model.ts b/src/main/webapp/app/detail-overview-list/detail.model.ts index f8e8a5562044..77085194fb0b 100644 --- a/src/main/webapp/app/detail-overview-list/detail.model.ts +++ b/src/main/webapp/app/detail-overview-list/detail.model.ts @@ -1,12 +1,12 @@ import { GradingCriterion } from 'app/exercises/shared/structured-grading-criterion/grading-criterion.model'; -import type { ProgrammingExercise, ProgrammingLanguage } from 'app/entities/programming-exercise.model'; +import type { ProgrammingExercise, ProgrammingLanguage } from 'app/entities/programming/programming-exercise.model'; import { TemplateProgrammingExerciseParticipation } from 'app/entities/participation/template-programming-exercise-participation.model'; import { SolutionProgrammingExerciseParticipation } from 'app/entities/participation/solution-programming-exercise-participation.model'; import { ProgrammingExerciseInstructorRepositoryType } from 'app/exercises/programming/manage/services/programming-exercise.service'; -import { AuxiliaryRepository } from 'app/entities/programming-exercise-auxiliary-repository-model'; -import { ProgrammingExerciseParticipationType } from 'app/entities/programming-exercise-participation.model'; +import { AuxiliaryRepository } from 'app/entities/programming/programming-exercise-auxiliary-repository-model'; +import { ProgrammingExerciseParticipationType } from 'app/entities/programming/programming-exercise-participation.model'; import { ProgrammingExerciseGitDiffReport } from 'app/entities/hestia/programming-exercise-git-diff-report.model'; -import { BuildLogStatisticsDTO } from 'app/entities/build-log-statistics-dto'; +import { BuildLogStatisticsDTO } from 'app/entities/programming/build-log-statistics-dto'; import { DetailType } from 'app/detail-overview-list/detail-overview-list.component'; import { SafeHtml } from '@angular/platform-browser'; import { UMLDiagramType, UMLModel } from '@ls1intum/apollon'; diff --git a/src/main/webapp/app/entities/consistency-check-result.model.ts b/src/main/webapp/app/entities/consistency-check-result.model.ts index b887135572b7..67b23aeb1193 100644 --- a/src/main/webapp/app/entities/consistency-check-result.model.ts +++ b/src/main/webapp/app/entities/consistency-check-result.model.ts @@ -1,5 +1,5 @@ import { BaseEntity } from 'app/shared/model/base-entity'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; export const enum ErrorType { TEMPLATE_REPO_MISSING = 'TEMPLATE_REPO_MISSING', diff --git a/src/main/webapp/app/entities/course.model.ts b/src/main/webapp/app/entities/course.model.ts index 77abadd7a640..4f179de3a687 100644 --- a/src/main/webapp/app/entities/course.model.ts +++ b/src/main/webapp/app/entities/course.model.ts @@ -3,11 +3,11 @@ import dayjs from 'dayjs/esm'; import { Lecture } from 'app/entities/lecture.model'; import { Exercise } from 'app/entities/exercise.model'; import { DueDateStat } from 'app/course/dashboards/due-date-stat.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { Competency } from 'app/entities/competency.model'; import { Organization } from 'app/entities/organization.model'; import { Post } from 'app/entities/metis/post.model'; -import { ProgrammingLanguage } from 'app/entities/programming-exercise.model'; +import { ProgrammingLanguage } from 'app/entities/programming/programming-exercise.model'; import { OnlineCourseConfiguration } from 'app/entities/online-course-configuration.model'; import { TutorialGroup } from 'app/entities/tutorial-group/tutorial-group.model'; import { TutorialGroupsConfiguration } from 'app/entities/tutorial-group/tutorial-groups-configuration.model'; diff --git a/src/main/webapp/app/entities/exam-checklist.model.ts b/src/main/webapp/app/entities/exam/exam-checklist.model.ts similarity index 100% rename from src/main/webapp/app/entities/exam-checklist.model.ts rename to src/main/webapp/app/entities/exam/exam-checklist.model.ts diff --git a/src/main/webapp/app/entities/exam-exercise-overview-item.model.ts b/src/main/webapp/app/entities/exam/exam-exercise-overview-item.model.ts similarity index 100% rename from src/main/webapp/app/entities/exam-exercise-overview-item.model.ts rename to src/main/webapp/app/entities/exam/exam-exercise-overview-item.model.ts diff --git a/src/main/webapp/app/entities/exam-information.model.ts b/src/main/webapp/app/entities/exam/exam-information.model.ts similarity index 100% rename from src/main/webapp/app/entities/exam-information.model.ts rename to src/main/webapp/app/entities/exam/exam-information.model.ts diff --git a/src/main/webapp/app/entities/exam-page.model.ts b/src/main/webapp/app/entities/exam/exam-page.model.ts similarity index 100% rename from src/main/webapp/app/entities/exam-page.model.ts rename to src/main/webapp/app/entities/exam/exam-page.model.ts diff --git a/src/main/webapp/app/entities/exam-session.model.ts b/src/main/webapp/app/entities/exam/exam-session.model.ts similarity index 97% rename from src/main/webapp/app/entities/exam-session.model.ts rename to src/main/webapp/app/entities/exam/exam-session.model.ts index feb4670ac5c9..96fc05c9b400 100644 --- a/src/main/webapp/app/entities/exam-session.model.ts +++ b/src/main/webapp/app/entities/exam/exam-session.model.ts @@ -1,6 +1,6 @@ import { BaseEntity } from 'app/shared/model/base-entity'; import dayjs from 'dayjs/esm'; -import { StudentExam } from './student-exam.model'; +import { StudentExam } from '../student-exam.model'; export enum SuspiciousSessionReason { DIFFERENT_STUDENT_EXAMS_SAME_IP_ADDRESS = 'DIFFERENT_STUDENT_EXAMS_SAME_IP_ADDRESS', diff --git a/src/main/webapp/app/entities/exam-user-dto.model.ts b/src/main/webapp/app/entities/exam/exam-user-dto.model.ts similarity index 100% rename from src/main/webapp/app/entities/exam-user-dto.model.ts rename to src/main/webapp/app/entities/exam/exam-user-dto.model.ts diff --git a/src/main/webapp/app/entities/exam-user.model.ts b/src/main/webapp/app/entities/exam/exam-user.model.ts similarity index 93% rename from src/main/webapp/app/entities/exam-user.model.ts rename to src/main/webapp/app/entities/exam/exam-user.model.ts index 53a46e26e36d..e1d3edae6fb1 100644 --- a/src/main/webapp/app/entities/exam-user.model.ts +++ b/src/main/webapp/app/entities/exam/exam-user.model.ts @@ -1,5 +1,5 @@ import { User } from 'app/core/user/user.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { BaseEntity } from 'app/shared/model/base-entity'; export class ExamUser implements BaseEntity { diff --git a/src/main/webapp/app/entities/exam-users-attendance-check-dto.model.ts b/src/main/webapp/app/entities/exam/exam-users-attendance-check-dto.model.ts similarity index 100% rename from src/main/webapp/app/entities/exam-users-attendance-check-dto.model.ts rename to src/main/webapp/app/entities/exam/exam-users-attendance-check-dto.model.ts diff --git a/src/main/webapp/app/entities/exam.model.ts b/src/main/webapp/app/entities/exam/exam.model.ts similarity index 97% rename from src/main/webapp/app/entities/exam.model.ts rename to src/main/webapp/app/entities/exam/exam.model.ts index f8c813558467..4ebd6fea578f 100644 --- a/src/main/webapp/app/entities/exam.model.ts +++ b/src/main/webapp/app/entities/exam/exam.model.ts @@ -1,4 +1,4 @@ -import { ExamUser } from 'app/entities/exam-user.model'; +import { ExamUser } from 'app/entities/exam/exam-user.model'; import dayjs from 'dayjs/esm'; import { Course } from 'app/entities/course.model'; import { StudentExam } from 'app/entities/student-exam.model'; diff --git a/src/main/webapp/app/entities/exercise-group.model.ts b/src/main/webapp/app/entities/exercise-group.model.ts index 65c14544f2e4..aeca98ee9109 100644 --- a/src/main/webapp/app/entities/exercise-group.model.ts +++ b/src/main/webapp/app/entities/exercise-group.model.ts @@ -1,5 +1,5 @@ import { Exercise } from 'app/entities/exercise.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { BaseEntity } from 'app/shared/model/base-entity'; export class ExerciseGroup implements BaseEntity { diff --git a/src/main/webapp/app/entities/feedback.model.ts b/src/main/webapp/app/entities/feedback.model.ts index 7666973744e9..7c6809e6e2f3 100644 --- a/src/main/webapp/app/entities/feedback.model.ts +++ b/src/main/webapp/app/entities/feedback.model.ts @@ -1,9 +1,9 @@ import { BaseEntity } from 'app/shared/model/base-entity'; import { Result } from 'app/entities/result.model'; -import { TextBlock } from 'app/entities/text-block.model'; +import { TextBlock } from 'app/entities/text/text-block.model'; import { GradingInstruction } from 'app/exercises/shared/structured-grading-criterion/grading-instruction.model'; import { convertToHtmlLinebreaks, escapeString } from 'app/utils/text.utils'; -import { ProgrammingExerciseTestCase } from 'app/entities/programming-exercise-test-case.model'; +import { ProgrammingExerciseTestCase } from 'app/entities/programming/programming-exercise-test-case.model'; export enum FeedbackHighlightColor { RED = 'rgba(219, 53, 69, 0.6)', diff --git a/src/main/webapp/app/entities/grading-scale.model.ts b/src/main/webapp/app/entities/grading-scale.model.ts index 7652eb6e9248..2042535aab54 100644 --- a/src/main/webapp/app/entities/grading-scale.model.ts +++ b/src/main/webapp/app/entities/grading-scale.model.ts @@ -1,7 +1,7 @@ import { GradeStep } from 'app/entities/grade-step.model'; import { BaseEntity } from 'app/shared/model/base-entity'; import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; export class GradingScale implements BaseEntity { public static readonly DEFAULT_PLAGIARISM_GRADE = 'U'; // This should be the same as the corresponding constant in GradingScale.java diff --git a/src/main/webapp/app/entities/hestia/exercise-hint.model.ts b/src/main/webapp/app/entities/hestia/exercise-hint.model.ts index d48c828adba2..fa61b885b7ec 100644 --- a/src/main/webapp/app/entities/hestia/exercise-hint.model.ts +++ b/src/main/webapp/app/entities/hestia/exercise-hint.model.ts @@ -1,4 +1,4 @@ -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { BaseEntity } from 'app/shared/model/base-entity'; import { ProgrammingExerciseServerSideTask } from 'app/entities/hestia/programming-exercise-task.model'; diff --git a/src/main/webapp/app/entities/hestia/programming-exercise-git-diff-report.model.ts b/src/main/webapp/app/entities/hestia/programming-exercise-git-diff-report.model.ts index 4471eb472fce..5fccf4e2f4aa 100644 --- a/src/main/webapp/app/entities/hestia/programming-exercise-git-diff-report.model.ts +++ b/src/main/webapp/app/entities/hestia/programming-exercise-git-diff-report.model.ts @@ -1,4 +1,4 @@ -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { BaseEntity } from 'app/shared/model/base-entity'; import { ProgrammingExerciseGitDiffEntry } from 'app/entities/hestia/programming-exercise-git-diff-entry.model'; diff --git a/src/main/webapp/app/entities/hestia/programming-exercise-solution-entry.model.ts b/src/main/webapp/app/entities/hestia/programming-exercise-solution-entry.model.ts index eb1ee53e4ec2..9380ec858a4f 100644 --- a/src/main/webapp/app/entities/hestia/programming-exercise-solution-entry.model.ts +++ b/src/main/webapp/app/entities/hestia/programming-exercise-solution-entry.model.ts @@ -1,5 +1,5 @@ import { BaseEntity } from 'app/shared/model/base-entity'; -import { ProgrammingExerciseTestCase } from 'app/entities/programming-exercise-test-case.model'; +import { ProgrammingExerciseTestCase } from 'app/entities/programming/programming-exercise-test-case.model'; import { CodeHint } from 'app/entities/hestia/code-hint-model'; export class ProgrammingExerciseSolutionEntry implements BaseEntity { diff --git a/src/main/webapp/app/entities/hestia/programming-exercise-task.model.ts b/src/main/webapp/app/entities/hestia/programming-exercise-task.model.ts index d83351b2883b..43d4a5b5d144 100644 --- a/src/main/webapp/app/entities/hestia/programming-exercise-task.model.ts +++ b/src/main/webapp/app/entities/hestia/programming-exercise-task.model.ts @@ -1,5 +1,5 @@ import { BaseEntity } from 'app/shared/model/base-entity'; -import { ProgrammingExerciseTestCase } from 'app/entities/programming-exercise-test-case.model'; +import { ProgrammingExerciseTestCase } from 'app/entities/programming/programming-exercise-test-case.model'; export class ProgrammingExerciseServerSideTask implements BaseEntity { public id?: number; diff --git a/src/main/webapp/app/entities/hestia/testwise-coverage-report-entry.model.ts b/src/main/webapp/app/entities/hestia/testwise-coverage-report-entry.model.ts index 47c49d57483d..59234fffbcfe 100644 --- a/src/main/webapp/app/entities/hestia/testwise-coverage-report-entry.model.ts +++ b/src/main/webapp/app/entities/hestia/testwise-coverage-report-entry.model.ts @@ -1,5 +1,5 @@ import { BaseEntity } from 'app/shared/model/base-entity'; -import { ProgrammingExerciseTestCase } from 'app/entities/programming-exercise-test-case.model'; +import { ProgrammingExerciseTestCase } from 'app/entities/programming/programming-exercise-test-case.model'; export class TestwiseCoverageReportEntry implements BaseEntity { public id?: number; diff --git a/src/main/webapp/app/entities/iris/iris-exercise-chat-session.model.ts b/src/main/webapp/app/entities/iris/iris-exercise-chat-session.model.ts index 752551cb58c7..c86342e1d332 100644 --- a/src/main/webapp/app/entities/iris/iris-exercise-chat-session.model.ts +++ b/src/main/webapp/app/entities/iris/iris-exercise-chat-session.model.ts @@ -1,5 +1,5 @@ import { IrisSession } from 'app/entities/iris/iris-session.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; export class IrisExerciseChatSession extends IrisSession { exercise?: ProgrammingExercise; diff --git a/src/main/webapp/app/entities/metis/conversation/channel.model.ts b/src/main/webapp/app/entities/metis/conversation/channel.model.ts index 450cfc266691..dbcc9bb3aac1 100644 --- a/src/main/webapp/app/entities/metis/conversation/channel.model.ts +++ b/src/main/webapp/app/entities/metis/conversation/channel.model.ts @@ -1,7 +1,7 @@ import { Conversation, ConversationDTO, ConversationType } from 'app/entities/metis/conversation/conversation.model'; import { Exercise } from 'app/entities/exercise.model'; import { Lecture } from 'app/entities/lecture.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; // IMPORTANT NOTICE: The following strings have to be consistent with // the types defined in ChannelSubType.java diff --git a/src/main/webapp/app/entities/participation/solution-programming-exercise-participation.model.ts b/src/main/webapp/app/entities/participation/solution-programming-exercise-participation.model.ts index d9db5fc2b9d3..80bad35f24db 100644 --- a/src/main/webapp/app/entities/participation/solution-programming-exercise-participation.model.ts +++ b/src/main/webapp/app/entities/participation/solution-programming-exercise-participation.model.ts @@ -1,5 +1,5 @@ import { Participation, ParticipationType } from 'app/entities/participation/participation.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; export class SolutionProgrammingExerciseParticipation extends Participation { public programmingExercise?: ProgrammingExercise; diff --git a/src/main/webapp/app/entities/participation/template-programming-exercise-participation.model.ts b/src/main/webapp/app/entities/participation/template-programming-exercise-participation.model.ts index 248a30b3e3f4..d6db1617acec 100644 --- a/src/main/webapp/app/entities/participation/template-programming-exercise-participation.model.ts +++ b/src/main/webapp/app/entities/participation/template-programming-exercise-participation.model.ts @@ -1,5 +1,5 @@ import { Participation, ParticipationType } from 'app/entities/participation/participation.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; export class TemplateProgrammingExerciseParticipation extends Participation { public programmingExercise?: ProgrammingExercise; diff --git a/src/main/webapp/app/entities/programming/aeolus.result.ts b/src/main/webapp/app/entities/programming/aeolus.result.ts new file mode 100644 index 000000000000..593a09df693e --- /dev/null +++ b/src/main/webapp/app/entities/programming/aeolus.result.ts @@ -0,0 +1,7 @@ +export class AeolusResult { + name: string; + path: string; + ignore: string; + type?: string; + before?: boolean; +} diff --git a/src/main/webapp/app/entities/build-agent.model.ts b/src/main/webapp/app/entities/programming/build-agent.model.ts similarity index 84% rename from src/main/webapp/app/entities/build-agent.model.ts rename to src/main/webapp/app/entities/programming/build-agent.model.ts index bb33b3a4dd4e..172a8596b299 100644 --- a/src/main/webapp/app/entities/build-agent.model.ts +++ b/src/main/webapp/app/entities/programming/build-agent.model.ts @@ -1,5 +1,5 @@ import { BaseEntity } from 'app/shared/model/base-entity'; -import { BuildJob } from 'app/entities/build-job.model'; +import { BuildJob } from 'app/entities/programming/build-job.model'; export class BuildAgent implements BaseEntity { public id?: number; diff --git a/src/main/webapp/app/entities/build-config.model.ts b/src/main/webapp/app/entities/programming/build-config.model.ts similarity index 100% rename from src/main/webapp/app/entities/build-config.model.ts rename to src/main/webapp/app/entities/programming/build-config.model.ts diff --git a/src/main/webapp/app/entities/build-job.model.ts b/src/main/webapp/app/entities/programming/build-job.model.ts similarity index 93% rename from src/main/webapp/app/entities/build-job.model.ts rename to src/main/webapp/app/entities/programming/build-job.model.ts index 55155414cc8d..a36bb9756091 100644 --- a/src/main/webapp/app/entities/build-job.model.ts +++ b/src/main/webapp/app/entities/programming/build-job.model.ts @@ -1,7 +1,7 @@ import { StringBaseEntity } from 'app/shared/model/base-entity'; -import { RepositoryInfo, TriggeredByPushTo } from 'app/entities/repository-info.model'; +import { RepositoryInfo, TriggeredByPushTo } from 'app/entities/programming/repository-info.model'; import { JobTimingInfo } from 'app/entities/job-timing-info.model'; -import { BuildConfig } from 'app/entities/build-config.model'; +import { BuildConfig } from 'app/entities/programming/build-config.model'; import { Result } from 'app/entities/result.model'; import dayjs from 'dayjs/esm'; diff --git a/src/main/webapp/app/entities/build-log-statistics-dto.ts b/src/main/webapp/app/entities/programming/build-log-statistics-dto.ts similarity index 100% rename from src/main/webapp/app/entities/build-log-statistics-dto.ts rename to src/main/webapp/app/entities/programming/build-log-statistics-dto.ts diff --git a/src/main/webapp/app/entities/build-log.model.ts b/src/main/webapp/app/entities/programming/build-log.model.ts similarity index 99% rename from src/main/webapp/app/entities/build-log.model.ts rename to src/main/webapp/app/entities/programming/build-log.model.ts index db33d9a63412..fd4135a005cd 100644 --- a/src/main/webapp/app/entities/build-log.model.ts +++ b/src/main/webapp/app/entities/programming/build-log.model.ts @@ -1,6 +1,6 @@ import { safeUnescape } from 'app/shared/util/security.util'; import { Annotation } from 'app/exercises/programming/shared/code-editor/monaco/code-editor-monaco.component'; -import { ProgrammingLanguage, ProjectType } from 'app/entities/programming-exercise.model'; +import { ProgrammingLanguage, ProjectType } from 'app/entities/programming/programming-exercise.model'; export enum BuildLogType { ERROR = 'ERROR', diff --git a/src/main/webapp/app/entities/build-plan-checkout-directories-dto.ts b/src/main/webapp/app/entities/programming/build-plan-checkout-directories-dto.ts similarity index 100% rename from src/main/webapp/app/entities/build-plan-checkout-directories-dto.ts rename to src/main/webapp/app/entities/programming/build-plan-checkout-directories-dto.ts diff --git a/src/main/webapp/app/entities/build-plan.model.ts b/src/main/webapp/app/entities/programming/build-plan.model.ts similarity index 71% rename from src/main/webapp/app/entities/build-plan.model.ts rename to src/main/webapp/app/entities/programming/build-plan.model.ts index f1f79e0e1e9f..cb6abecf235d 100644 --- a/src/main/webapp/app/entities/build-plan.model.ts +++ b/src/main/webapp/app/entities/programming/build-plan.model.ts @@ -1,5 +1,5 @@ import { BaseEntity } from 'app/shared/model/base-entity'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; export class BuildPlan implements BaseEntity { public id?: number; diff --git a/src/main/webapp/app/entities/programming/build.action.ts b/src/main/webapp/app/entities/programming/build.action.ts new file mode 100644 index 000000000000..5e9e3e4463a1 --- /dev/null +++ b/src/main/webapp/app/entities/programming/build.action.ts @@ -0,0 +1,19 @@ +import { AeolusResult } from 'app/entities/programming/aeolus.result'; + +export class BuildAction { + name: string; + runAlways: boolean; + workdir: string; + results?: AeolusResult[]; + platform?: string; + parameters: Map = new Map(); +} + +export class ScriptAction extends BuildAction { + script: string; +} + +export class PlatformAction extends BuildAction { + type: string; + kind: string; +} diff --git a/src/main/webapp/app/entities/checkout-directories-dto.ts b/src/main/webapp/app/entities/programming/checkout-directories-dto.ts similarity index 63% rename from src/main/webapp/app/entities/checkout-directories-dto.ts rename to src/main/webapp/app/entities/programming/checkout-directories-dto.ts index 71b05a32d187..657fbce65f6f 100644 --- a/src/main/webapp/app/entities/checkout-directories-dto.ts +++ b/src/main/webapp/app/entities/programming/checkout-directories-dto.ts @@ -1,4 +1,4 @@ -import { BuildPlanCheckoutDirectoriesDTO } from 'app/entities/build-plan-checkout-directories-dto'; +import { BuildPlanCheckoutDirectoriesDTO } from 'app/entities/programming/build-plan-checkout-directories-dto'; export class CheckoutDirectoriesDto { submissionBuildPlanCheckoutDirectories?: BuildPlanCheckoutDirectoriesDTO; diff --git a/src/main/webapp/app/entities/programming/docker.configuration.ts b/src/main/webapp/app/entities/programming/docker.configuration.ts new file mode 100644 index 000000000000..edc08214185c --- /dev/null +++ b/src/main/webapp/app/entities/programming/docker.configuration.ts @@ -0,0 +1,6 @@ +export class DockerConfiguration { + image: string; + tag?: string; + volumes: Map; + parameters: Map; +} diff --git a/src/main/webapp/app/entities/programming-exercise-auxiliary-repository-model.ts b/src/main/webapp/app/entities/programming/programming-exercise-auxiliary-repository-model.ts similarity index 100% rename from src/main/webapp/app/entities/programming-exercise-auxiliary-repository-model.ts rename to src/main/webapp/app/entities/programming/programming-exercise-auxiliary-repository-model.ts diff --git a/src/main/webapp/app/entities/programming/programming-exercise-build.config.ts b/src/main/webapp/app/entities/programming/programming-exercise-build.config.ts new file mode 100644 index 000000000000..eaa526406e08 --- /dev/null +++ b/src/main/webapp/app/entities/programming/programming-exercise-build.config.ts @@ -0,0 +1,19 @@ +import { WindFile } from 'app/entities/programming/wind.file'; + +export class ProgrammingExerciseBuildConfig { + public sequentialTestRuns?: boolean; + public buildPlanConfiguration?: string; + public buildScript?: string; + public checkoutSolutionRepository?: boolean; + public checkoutPath?: string; + public timeoutSeconds?: number; + public dockerFlags?: string; + public windfile?: WindFile; + public testwiseCoverageEnabled?: boolean; + public theiaImage?: string; + + constructor() { + this.checkoutSolutionRepository = false; // default value + this.testwiseCoverageEnabled = false; // default value + } +} diff --git a/src/main/webapp/app/entities/programming-exercise-participation.model.ts b/src/main/webapp/app/entities/programming/programming-exercise-participation.model.ts similarity index 100% rename from src/main/webapp/app/entities/programming-exercise-participation.model.ts rename to src/main/webapp/app/entities/programming/programming-exercise-participation.model.ts diff --git a/src/main/webapp/app/entities/programming-exercise-test-case-statistics.model.ts b/src/main/webapp/app/entities/programming/programming-exercise-test-case-statistics.model.ts similarity index 100% rename from src/main/webapp/app/entities/programming-exercise-test-case-statistics.model.ts rename to src/main/webapp/app/entities/programming/programming-exercise-test-case-statistics.model.ts diff --git a/src/main/webapp/app/entities/programming-exercise-test-case.model.ts b/src/main/webapp/app/entities/programming/programming-exercise-test-case.model.ts similarity index 92% rename from src/main/webapp/app/entities/programming-exercise-test-case.model.ts rename to src/main/webapp/app/entities/programming/programming-exercise-test-case.model.ts index 7b0cdfa37311..2d6822dc7ce4 100644 --- a/src/main/webapp/app/entities/programming-exercise-test-case.model.ts +++ b/src/main/webapp/app/entities/programming/programming-exercise-test-case.model.ts @@ -1,4 +1,4 @@ -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { BaseEntity } from 'app/shared/model/base-entity'; import { ProgrammingExerciseSolutionEntry } from 'app/entities/hestia/programming-exercise-solution-entry.model'; import { TestCaseStats } from './programming-exercise-test-case-statistics.model'; diff --git a/src/main/webapp/app/entities/programming-exercise.model.ts b/src/main/webapp/app/entities/programming/programming-exercise.model.ts similarity index 76% rename from src/main/webapp/app/entities/programming-exercise.model.ts rename to src/main/webapp/app/entities/programming/programming-exercise.model.ts index daf1bf77e907..3d47a8320bd2 100644 --- a/src/main/webapp/app/entities/programming-exercise.model.ts +++ b/src/main/webapp/app/entities/programming/programming-exercise.model.ts @@ -1,80 +1,16 @@ -import dayjs from 'dayjs/esm'; -import { SolutionProgrammingExerciseParticipation } from 'app/entities/participation/solution-programming-exercise-participation.model'; -import { TemplateProgrammingExerciseParticipation } from 'app/entities/participation/template-programming-exercise-participation.model'; -import { Exercise, ExerciseType, resetForImport } from 'app/entities/exercise.model'; +import { AssessmentType } from 'app/entities/assessment-type.model'; import { Course } from 'app/entities/course.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; -import { AuxiliaryRepository } from 'app/entities/programming-exercise-auxiliary-repository-model'; -import { SubmissionPolicy } from 'app/entities/submission-policy.model'; -import { ProgrammingExerciseGitDiffReport } from 'app/entities/hestia/programming-exercise-git-diff-report.model'; +import { Exercise, ExerciseType, resetForImport } from 'app/entities/exercise.model'; import { ExerciseHint } from 'app/entities/hestia/exercise-hint.model'; -import { BuildLogStatisticsDTO } from 'app/entities/build-log-statistics-dto'; -import { AssessmentType } from 'app/entities/assessment-type.model'; - -export class BuildAction { - name: string; - runAlways: boolean; - workdir: string; - results?: AeolusResult[]; - platform?: string; - parameters: Map = new Map(); -} - -export class AeolusResult { - name: string; - path: string; - ignore: string; - type?: string; - before?: boolean; -} - -export class ScriptAction extends BuildAction { - script: string; -} - -export class PlatformAction extends BuildAction { - type: string; - kind: string; -} - -export class WindMetadata { - author: string | any; - description: string; - id: string; - name: string; - docker: DockerConfiguration; -} - -export class DockerConfiguration { - image: string; - tag?: string; - volumes: Map; - parameters: Map; -} - -export class WindFile { - api: string; - metadata: WindMetadata; - actions: BuildAction[]; -} - -export class ProgrammingExerciseBuildConfig { - public sequentialTestRuns?: boolean; - public buildPlanConfiguration?: string; - public buildScript?: string; - public checkoutSolutionRepository?: boolean; - public checkoutPath?: string; - public timeoutSeconds?: number; - public dockerFlags?: string; - public windfile?: WindFile; - public testwiseCoverageEnabled?: boolean; - public theiaImage?: string; - - constructor() { - this.checkoutSolutionRepository = false; // default value - this.testwiseCoverageEnabled = false; // default value - } -} +import { ProgrammingExerciseGitDiffReport } from 'app/entities/hestia/programming-exercise-git-diff-report.model'; +import { SolutionProgrammingExerciseParticipation } from 'app/entities/participation/solution-programming-exercise-participation.model'; +import { TemplateProgrammingExerciseParticipation } from 'app/entities/participation/template-programming-exercise-participation.model'; +import { BuildLogStatisticsDTO } from 'app/entities/programming/build-log-statistics-dto'; +import { AuxiliaryRepository } from 'app/entities/programming/programming-exercise-auxiliary-repository-model'; +import { ProgrammingExerciseBuildConfig } from 'app/entities/programming/programming-exercise-build.config'; +import { SubmissionPolicy } from 'app/entities/submission-policy.model'; +import dayjs from 'dayjs/esm'; export enum ProgrammingLanguage { JAVA = 'JAVA', diff --git a/src/main/webapp/app/entities/programming-submission.model.ts b/src/main/webapp/app/entities/programming/programming-submission.model.ts similarity index 100% rename from src/main/webapp/app/entities/programming-submission.model.ts rename to src/main/webapp/app/entities/programming/programming-submission.model.ts diff --git a/src/main/webapp/app/entities/repository-info.model.ts b/src/main/webapp/app/entities/programming/repository-info.model.ts similarity index 100% rename from src/main/webapp/app/entities/repository-info.model.ts rename to src/main/webapp/app/entities/programming/repository-info.model.ts diff --git a/src/main/webapp/app/entities/static-code-analysis-category.model.ts b/src/main/webapp/app/entities/programming/static-code-analysis-category.model.ts similarity index 100% rename from src/main/webapp/app/entities/static-code-analysis-category.model.ts rename to src/main/webapp/app/entities/programming/static-code-analysis-category.model.ts diff --git a/src/main/webapp/app/entities/static-code-analysis-issue.model.ts b/src/main/webapp/app/entities/programming/static-code-analysis-issue.model.ts similarity index 100% rename from src/main/webapp/app/entities/static-code-analysis-issue.model.ts rename to src/main/webapp/app/entities/programming/static-code-analysis-issue.model.ts diff --git a/src/main/webapp/app/entities/test-case-result.model.ts b/src/main/webapp/app/entities/programming/test-case-result.model.ts similarity index 100% rename from src/main/webapp/app/entities/test-case-result.model.ts rename to src/main/webapp/app/entities/programming/test-case-result.model.ts diff --git a/src/main/webapp/app/entities/programming/wind.file.ts b/src/main/webapp/app/entities/programming/wind.file.ts new file mode 100644 index 000000000000..6e960c30c44c --- /dev/null +++ b/src/main/webapp/app/entities/programming/wind.file.ts @@ -0,0 +1,8 @@ +import { BuildAction } from 'app/entities/programming/build.action'; +import { WindMetadata } from 'app/entities/programming/wind.metadata'; + +export class WindFile { + api: string; + metadata: WindMetadata; + actions: BuildAction[]; +} diff --git a/src/main/webapp/app/entities/programming/wind.metadata.ts b/src/main/webapp/app/entities/programming/wind.metadata.ts new file mode 100644 index 000000000000..6ef6f1abc38e --- /dev/null +++ b/src/main/webapp/app/entities/programming/wind.metadata.ts @@ -0,0 +1,9 @@ +import { DockerConfiguration } from 'app/entities/programming/docker.configuration'; + +export class WindMetadata { + author: string | any; + description: string; + id: string; + name: string; + docker: DockerConfiguration; +} diff --git a/src/main/webapp/app/entities/quiz/quiz-pool.model.ts b/src/main/webapp/app/entities/quiz/quiz-pool.model.ts index b6d7f82b7a83..8b59ba5473c3 100644 --- a/src/main/webapp/app/entities/quiz/quiz-pool.model.ts +++ b/src/main/webapp/app/entities/quiz/quiz-pool.model.ts @@ -1,6 +1,6 @@ import { QuizGroup } from 'app/entities/quiz/quiz-group.model'; import { QuizQuestion } from 'app/entities/quiz/quiz-question.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { BaseEntity } from 'app/shared/model/base-entity'; export class QuizPool implements BaseEntity { diff --git a/src/main/webapp/app/entities/student-exam.model.ts b/src/main/webapp/app/entities/student-exam.model.ts index 1b15503b27cd..b7eb32c151d6 100644 --- a/src/main/webapp/app/entities/student-exam.model.ts +++ b/src/main/webapp/app/entities/student-exam.model.ts @@ -1,9 +1,9 @@ import dayjs from 'dayjs/esm'; import { User } from 'app/core/user/user.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { Exercise } from 'app/entities/exercise.model'; import { BaseEntity } from 'app/shared/model/base-entity'; -import { ExamSession } from 'app/entities/exam-session.model'; +import { ExamSession } from 'app/entities/exam/exam-session.model'; export class StudentExam implements BaseEntity { public id?: number; diff --git a/src/main/webapp/app/entities/submission-policy.model.ts b/src/main/webapp/app/entities/submission-policy.model.ts index 9ae55f0d465e..c6f0d9620f4b 100644 --- a/src/main/webapp/app/entities/submission-policy.model.ts +++ b/src/main/webapp/app/entities/submission-policy.model.ts @@ -1,4 +1,4 @@ -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { BaseEntity } from 'app/shared/model/base-entity'; export enum SubmissionPolicyType { diff --git a/src/main/webapp/app/entities/text-assesment-event.model.ts b/src/main/webapp/app/entities/text/text-assesment-event.model.ts similarity index 95% rename from src/main/webapp/app/entities/text-assesment-event.model.ts rename to src/main/webapp/app/entities/text/text-assesment-event.model.ts index c0b04482f1a2..478f39d62ccf 100644 --- a/src/main/webapp/app/entities/text-assesment-event.model.ts +++ b/src/main/webapp/app/entities/text/text-assesment-event.model.ts @@ -1,7 +1,7 @@ import dayjs from 'dayjs/esm'; import { BaseEntity } from 'app/shared/model/base-entity'; import { FeedbackType } from 'app/entities/feedback.model'; -import { TextBlockType } from 'app/entities/text-block.model'; +import { TextBlockType } from 'app/entities/text/text-block.model'; export enum TextAssessmentEventType { ADD_FEEDBACK_AUTOMATICALLY_SELECTED_BLOCK = 'ADD_FEEDBACK_AUTOMATICALLY_SELECTED_BLOCK', diff --git a/src/main/webapp/app/entities/text-block-ref.model.ts b/src/main/webapp/app/entities/text/text-block-ref.model.ts similarity index 91% rename from src/main/webapp/app/entities/text-block-ref.model.ts rename to src/main/webapp/app/entities/text/text-block-ref.model.ts index b31b08353cf3..b643652a939e 100644 --- a/src/main/webapp/app/entities/text-block-ref.model.ts +++ b/src/main/webapp/app/entities/text/text-block-ref.model.ts @@ -1,4 +1,4 @@ -import { TextBlock, TextBlockType } from 'app/entities/text-block.model'; +import { TextBlock, TextBlockType } from 'app/entities/text/text-block.model'; import { Feedback, FeedbackType } from 'app/entities/feedback.model'; export class TextBlockRef { diff --git a/src/main/webapp/app/entities/text-block.model.ts b/src/main/webapp/app/entities/text/text-block.model.ts similarity index 96% rename from src/main/webapp/app/entities/text-block.model.ts rename to src/main/webapp/app/entities/text/text-block.model.ts index 4267639950e8..034c590439b1 100644 --- a/src/main/webapp/app/entities/text-block.model.ts +++ b/src/main/webapp/app/entities/text/text-block.model.ts @@ -1,5 +1,5 @@ import { sha1Hex } from 'app/shared/util/crypto.utils'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; export enum TextBlockType { AUTOMATIC = 'AUTOMATIC', diff --git a/src/main/webapp/app/entities/text-change.model.ts b/src/main/webapp/app/entities/text/text-change.model.ts similarity index 100% rename from src/main/webapp/app/entities/text-change.model.ts rename to src/main/webapp/app/entities/text/text-change.model.ts diff --git a/src/main/webapp/app/entities/text-exercise.model.ts b/src/main/webapp/app/entities/text/text-exercise.model.ts similarity index 100% rename from src/main/webapp/app/entities/text-exercise.model.ts rename to src/main/webapp/app/entities/text/text-exercise.model.ts diff --git a/src/main/webapp/app/entities/text-submission.model.ts b/src/main/webapp/app/entities/text/text-submission.model.ts similarity index 84% rename from src/main/webapp/app/entities/text-submission.model.ts rename to src/main/webapp/app/entities/text/text-submission.model.ts index 941e239a1a1f..922987ed7a5b 100644 --- a/src/main/webapp/app/entities/text-submission.model.ts +++ b/src/main/webapp/app/entities/text/text-submission.model.ts @@ -1,4 +1,4 @@ -import { TextBlock } from 'app/entities/text-block.model'; +import { TextBlock } from 'app/entities/text/text-block.model'; import { Submission, SubmissionExerciseType } from 'app/entities/submission.model'; import { Language } from 'app/entities/course.model'; diff --git a/src/main/webapp/app/exam/manage/exam-management-resolve.service.ts b/src/main/webapp/app/exam/manage/exam-management-resolve.service.ts index 49a8462bc98d..e33354d96359 100644 --- a/src/main/webapp/app/exam/manage/exam-management-resolve.service.ts +++ b/src/main/webapp/app/exam/manage/exam-management-resolve.service.ts @@ -1,5 +1,5 @@ import { StudentExamService } from 'app/exam/manage/student-exams/student-exam.service'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { ExerciseGroupService } from 'app/exam/manage/exercise-groups/exercise-group.service'; diff --git a/src/main/webapp/app/exam/manage/exam-management.component.ts b/src/main/webapp/app/exam/manage/exam-management.component.ts index 73b0b4c6ed85..bd55ca990c1c 100644 --- a/src/main/webapp/app/exam/manage/exam-management.component.ts +++ b/src/main/webapp/app/exam/manage/exam-management.component.ts @@ -3,14 +3,14 @@ import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; import { ActivatedRoute, Router } from '@angular/router'; import { Subject, Subscription } from 'rxjs'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { onError } from 'app/shared/util/global.utils'; import { AlertService } from 'app/core/util/alert.service'; import { Course } from 'app/entities/course.model'; import { CourseManagementService } from 'app/course/manage/course-management.service'; import { AccountService } from 'app/core/auth/account.service'; import { SortService } from 'app/shared/service/sort.service'; -import { ExamInformationDTO } from 'app/entities/exam-information.model'; +import { ExamInformationDTO } from 'app/entities/exam/exam-information.model'; import dayjs from 'dayjs/esm'; import { EventManager } from 'app/core/util/event-manager.service'; import { faClipboard, faEye, faFileImport, faListAlt, faPlus, faSort, faThList, faTimes, faUser, faWrench } from '@fortawesome/free-solid-svg-icons'; diff --git a/src/main/webapp/app/exam/manage/exam-management.service.ts b/src/main/webapp/app/exam/manage/exam-management.service.ts index 24fa83f28e40..5f2d4c8f8397 100644 --- a/src/main/webapp/app/exam/manage/exam-management.service.ts +++ b/src/main/webapp/app/exam/manage/exam-management.service.ts @@ -1,18 +1,18 @@ import { Injectable } from '@angular/core'; -import { ExamUserDTO } from 'app/entities/exam-user-dto.model'; -import { ExamUserAttendanceCheckDTO } from 'app/entities/exam-users-attendance-check-dto.model'; +import { ExamUserDTO } from 'app/entities/exam/exam-user-dto.model'; +import { ExamUserAttendanceCheckDTO } from 'app/entities/exam/exam-users-attendance-check-dto.model'; import { filter, map, tap } from 'rxjs/operators'; import { HttpClient, HttpResponse } from '@angular/common/http'; import { Observable } from 'rxjs'; import dayjs from 'dayjs/esm'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { createRequestOption } from 'app/shared/util/request.util'; import { StudentDTO } from 'app/entities/student-dto.model'; import { StudentExam } from 'app/entities/student-exam.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { ExamScoreDTO } from 'app/exam/exam-scores/exam-score-dtos.model'; -import { ExamInformationDTO } from 'app/entities/exam-information.model'; -import { ExamChecklist } from 'app/entities/exam-checklist.model'; +import { ExamInformationDTO } from 'app/entities/exam/exam-information.model'; +import { ExamChecklist } from 'app/entities/exam/exam-checklist.model'; import { StatsForDashboard } from 'app/course/dashboards/stats-for-dashboard.model'; import { Submission, reconnectSubmissions } from 'app/entities/submission.model'; import { AccountService } from 'app/core/auth/account.service'; diff --git a/src/main/webapp/app/exam/manage/exam-status.component.ts b/src/main/webapp/app/exam/manage/exam-status.component.ts index 268e12d47d66..fafa2f201137 100644 --- a/src/main/webapp/app/exam/manage/exam-status.component.ts +++ b/src/main/webapp/app/exam/manage/exam-status.component.ts @@ -1,8 +1,8 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { faArrowRight, faCheckCircle, faCircleExclamation, faDotCircle, faTimes, faTimesCircle } from '@fortawesome/free-solid-svg-icons'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExamChecklistService } from 'app/exam/manage/exams/exam-checklist-component/exam-checklist.service'; -import { ExamChecklist } from 'app/entities/exam-checklist.model'; +import { ExamChecklist } from 'app/entities/exam/exam-checklist.model'; import dayjs from 'dayjs/esm'; import { round } from 'app/shared/util/utils'; import { Course } from 'app/entities/course.model'; diff --git a/src/main/webapp/app/exam/manage/exams/exam-checklist-component/exam-announcement-dialog/exam-live-announcement-create-button.component.ts b/src/main/webapp/app/exam/manage/exams/exam-checklist-component/exam-announcement-dialog/exam-live-announcement-create-button.component.ts index 1abff9c1f9ea..826a85b0a83d 100644 --- a/src/main/webapp/app/exam/manage/exams/exam-checklist-component/exam-announcement-dialog/exam-live-announcement-create-button.component.ts +++ b/src/main/webapp/app/exam/manage/exams/exam-checklist-component/exam-announcement-dialog/exam-live-announcement-create-button.component.ts @@ -4,7 +4,7 @@ import { faBullhorn } from '@fortawesome/free-solid-svg-icons'; import dayjs from 'dayjs/esm'; import { Subscription, from } from 'rxjs'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { AlertService } from 'app/core/util/alert.service'; import { ExamLiveAnnouncementCreateModalComponent } from 'app/exam/manage/exams/exam-checklist-component/exam-announcement-dialog/exam-live-announcement-create-modal.component'; diff --git a/src/main/webapp/app/exam/manage/exams/exam-checklist-component/exam-checklist.component.ts b/src/main/webapp/app/exam/manage/exams/exam-checklist-component/exam-checklist.component.ts index 5a2a236c2396..f873b396b058 100644 --- a/src/main/webapp/app/exam/manage/exams/exam-checklist-component/exam-checklist.component.ts +++ b/src/main/webapp/app/exam/manage/exams/exam-checklist-component/exam-checklist.component.ts @@ -1,6 +1,6 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; -import { Exam } from 'app/entities/exam.model'; -import { ExamChecklist } from 'app/entities/exam-checklist.model'; +import { Exam } from 'app/entities/exam/exam.model'; +import { ExamChecklist } from 'app/entities/exam/exam-checklist.model'; import { faChartBar, faEye, faListAlt, faThList, faUser, faWrench } from '@fortawesome/free-solid-svg-icons'; import { ExamChecklistService } from 'app/exam/manage/exams/exam-checklist-component/exam-checklist.service'; import { JhiWebsocketService } from 'app/core/websocket/websocket.service'; diff --git a/src/main/webapp/app/exam/manage/exams/exam-checklist-component/exam-checklist.service.ts b/src/main/webapp/app/exam/manage/exams/exam-checklist-component/exam-checklist.service.ts index fc85375c8e28..ac6133a43d76 100644 --- a/src/main/webapp/app/exam/manage/exams/exam-checklist-component/exam-checklist.service.ts +++ b/src/main/webapp/app/exam/manage/exams/exam-checklist-component/exam-checklist.service.ts @@ -1,7 +1,7 @@ import { HttpResponse } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { ExamChecklist } from 'app/entities/exam-checklist.model'; -import { Exam } from 'app/entities/exam.model'; +import { ExamChecklist } from 'app/entities/exam/exam-checklist.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { Observable } from 'rxjs'; import { filter, map } from 'rxjs/operators'; diff --git a/src/main/webapp/app/exam/manage/exams/exam-checklist-component/exam-edit-workingtime-dialog/exam-edit-working-time-dialog.component.ts b/src/main/webapp/app/exam/manage/exams/exam-checklist-component/exam-edit-workingtime-dialog/exam-edit-working-time-dialog.component.ts index 8eb453d1a091..a1bb4e17c565 100644 --- a/src/main/webapp/app/exam/manage/exams/exam-checklist-component/exam-edit-workingtime-dialog/exam-edit-working-time-dialog.component.ts +++ b/src/main/webapp/app/exam/manage/exams/exam-checklist-component/exam-edit-workingtime-dialog/exam-edit-working-time-dialog.component.ts @@ -3,7 +3,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { faBan, faCheck, faSpinner } from '@fortawesome/free-solid-svg-icons'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { examWorkingTime } from 'app/exam/participate/exam.utils'; diff --git a/src/main/webapp/app/exam/manage/exams/exam-checklist-component/exam-edit-workingtime-dialog/exam-edit-working-time.component.ts b/src/main/webapp/app/exam/manage/exams/exam-checklist-component/exam-edit-workingtime-dialog/exam-edit-working-time.component.ts index 5433a4e48887..4024634666c9 100644 --- a/src/main/webapp/app/exam/manage/exams/exam-checklist-component/exam-edit-workingtime-dialog/exam-edit-working-time.component.ts +++ b/src/main/webapp/app/exam/manage/exams/exam-checklist-component/exam-edit-workingtime-dialog/exam-edit-working-time.component.ts @@ -4,7 +4,7 @@ import { faHourglassHalf } from '@fortawesome/free-solid-svg-icons'; import dayjs from 'dayjs/esm'; import { Subscription, from } from 'rxjs'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { AlertService } from 'app/core/util/alert.service'; import { ExamEditWorkingTimeDialogComponent } from './exam-edit-working-time-dialog.component'; diff --git a/src/main/webapp/app/exam/manage/exams/exam-detail.component.ts b/src/main/webapp/app/exam/manage/exams/exam-detail.component.ts index 582e72ad65d5..21638aa00238 100644 --- a/src/main/webapp/app/exam/manage/exams/exam-detail.component.ts +++ b/src/main/webapp/app/exam/manage/exams/exam-detail.component.ts @@ -3,7 +3,7 @@ import { ActivatedRoute, Router } from '@angular/router'; import { SafeHtml } from '@angular/platform-browser'; import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; import { Subject } from 'rxjs'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ActionType } from 'app/shared/delete-dialog/delete-dialog.model'; import { ButtonSize } from 'app/shared/components/button.component'; import { ArtemisMarkdownService } from 'app/shared/markdown.service'; diff --git a/src/main/webapp/app/exam/manage/exams/exam-exercise-import/exam-exercise-import.component.ts b/src/main/webapp/app/exam/manage/exams/exam-exercise-import/exam-exercise-import.component.ts index 342c7b6fb1c1..9739343cb687 100644 --- a/src/main/webapp/app/exam/manage/exams/exam-exercise-import/exam-exercise-import.component.ts +++ b/src/main/webapp/app/exam/manage/exams/exam-exercise-import/exam-exercise-import.component.ts @@ -1,5 +1,5 @@ import { Component, Input, OnInit } from '@angular/core'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { faCheckDouble, faFont } from '@fortawesome/free-solid-svg-icons'; import { Exercise, ExerciseType, getIcon } from 'app/entities/exercise.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; diff --git a/src/main/webapp/app/exam/manage/exams/exam-import/exam-import-paging.service.ts b/src/main/webapp/app/exam/manage/exams/exam-import/exam-import-paging.service.ts index e9b8976146f3..ca9bcbf3f1fc 100644 --- a/src/main/webapp/app/exam/manage/exams/exam-import/exam-import-paging.service.ts +++ b/src/main/webapp/app/exam/manage/exams/exam-import/exam-import-paging.service.ts @@ -1,6 +1,6 @@ import { HttpClient, HttpResponse } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { PagingService } from 'app/exercises/shared/manage/paging.service'; import { SearchResult, SearchTermPageableSearch } from 'app/shared/table/pageable-table'; import { Observable } from 'rxjs'; diff --git a/src/main/webapp/app/exam/manage/exams/exam-import/exam-import.component.ts b/src/main/webapp/app/exam/manage/exams/exam-import/exam-import.component.ts index 35a04a6c96cc..f97c8c3d537b 100644 --- a/src/main/webapp/app/exam/manage/exams/exam-import/exam-import.component.ts +++ b/src/main/webapp/app/exam/manage/exams/exam-import/exam-import.component.ts @@ -3,7 +3,7 @@ import { Component, Input, ViewChild } from '@angular/core'; import { Router } from '@angular/router'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { AlertService } from 'app/core/util/alert.service'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { ExamExerciseImportComponent } from 'app/exam/manage/exams/exam-exercise-import/exam-exercise-import.component'; diff --git a/src/main/webapp/app/exam/manage/exams/exam-mode-picker/exam-mode-picker.component.ts b/src/main/webapp/app/exam/manage/exams/exam-mode-picker/exam-mode-picker.component.ts index 946654f067f4..c022b55ec428 100644 --- a/src/main/webapp/app/exam/manage/exams/exam-mode-picker/exam-mode-picker.component.ts +++ b/src/main/webapp/app/exam/manage/exams/exam-mode-picker/exam-mode-picker.component.ts @@ -1,5 +1,5 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; @Component({ selector: 'jhi-exam-mode-picker', diff --git a/src/main/webapp/app/exam/manage/exams/exam-update.component.ts b/src/main/webapp/app/exam/manage/exams/exam-update.component.ts index d9068bff7473..ea4d3a510ec4 100644 --- a/src/main/webapp/app/exam/manage/exams/exam-update.component.ts +++ b/src/main/webapp/app/exam/manage/exams/exam-update.component.ts @@ -6,7 +6,7 @@ import { Component, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/c import { ActivatedRoute, Router } from '@angular/router'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { faBan, faExclamationTriangle, faSave } from '@fortawesome/free-solid-svg-icons'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; import { AlertService } from 'app/core/util/alert.service'; diff --git a/src/main/webapp/app/exam/manage/exercise-groups/exercise-group-update.component.ts b/src/main/webapp/app/exam/manage/exercise-groups/exercise-group-update.component.ts index bfee12779e25..7acfb1fac6a6 100644 --- a/src/main/webapp/app/exam/manage/exercise-groups/exercise-group-update.component.ts +++ b/src/main/webapp/app/exam/manage/exercise-groups/exercise-group-update.component.ts @@ -5,7 +5,7 @@ import { AlertService } from 'app/core/util/alert.service'; import { Observable } from 'rxjs'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { ExerciseGroupService } from 'app/exam/manage/exercise-groups/exercise-group.service'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { onError } from 'app/shared/util/global.utils'; import { faBan, faSave } from '@fortawesome/free-solid-svg-icons'; diff --git a/src/main/webapp/app/exam/manage/exercise-groups/exercise-groups.component.ts b/src/main/webapp/app/exam/manage/exercise-groups/exercise-groups.component.ts index b2c563ecbfd1..8fcac15d391b 100644 --- a/src/main/webapp/app/exam/manage/exercise-groups/exercise-groups.component.ts +++ b/src/main/webapp/app/exam/manage/exercise-groups/exercise-groups.component.ts @@ -10,10 +10,10 @@ import { onError } from 'app/shared/util/global.utils'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import dayjs from 'dayjs/esm'; import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; -import { ProgrammingExerciseParticipationType } from 'app/entities/programming-exercise-participation.model'; +import { ProgrammingExerciseParticipationType } from 'app/entities/programming/programming-exercise-participation.model'; import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { AlertService } from 'app/core/util/alert.service'; import { EventManager } from 'app/core/util/event-manager.service'; diff --git a/src/main/webapp/app/exam/manage/exercise-groups/programming-exercise-cell/programming-exercise-group-cell.component.ts b/src/main/webapp/app/exam/manage/exercise-groups/programming-exercise-cell/programming-exercise-group-cell.component.ts index 949ab1482efe..a2b6d64ca6e0 100644 --- a/src/main/webapp/app/exam/manage/exercise-groups/programming-exercise-cell/programming-exercise-group-cell.component.ts +++ b/src/main/webapp/app/exam/manage/exercise-groups/programming-exercise-cell/programming-exercise-group-cell.component.ts @@ -1,7 +1,7 @@ import { Component, Input, OnInit } from '@angular/core'; import { HttpResponse } from '@angular/common/http'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; -import { ProgrammingExerciseParticipationType } from 'app/entities/programming-exercise-participation.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; +import { ProgrammingExerciseParticipationType } from 'app/entities/programming/programming-exercise-participation.model'; import { Exercise } from 'app/entities/exercise.model'; import { ProfileService } from 'app/shared/layouts/profiles/profile.service'; import { createBuildPlanUrl } from 'app/exercises/programming/shared/utils/programming-exercise.utils'; diff --git a/src/main/webapp/app/exam/manage/student-exams/student-exam-timeline/programming-exam-diff/programming-exercise-exam-diff.component.ts b/src/main/webapp/app/exam/manage/student-exams/student-exam-timeline/programming-exam-diff/programming-exercise-exam-diff.component.ts index 7d489674a1e0..7eafe4900d96 100644 --- a/src/main/webapp/app/exam/manage/student-exams/student-exam-timeline/programming-exam-diff/programming-exercise-exam-diff.component.ts +++ b/src/main/webapp/app/exam/manage/student-exams/student-exam-timeline/programming-exam-diff/programming-exercise-exam-diff.component.ts @@ -1,6 +1,6 @@ import { ChangeDetectorRef, Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { FeatureToggle } from 'app/shared/feature-toggle/feature-toggle.service'; import { ButtonSize } from 'app/shared/components/button.component'; import { GitDiffReportModalComponent } from 'app/exercises/programming/hestia/git-diff-report/git-diff-report-modal.component'; diff --git a/src/main/webapp/app/exam/manage/student-exams/student-exam-timeline/student-exam-timeline.component.ts b/src/main/webapp/app/exam/manage/student-exams/student-exam-timeline/student-exam-timeline.component.ts index f351e89940b8..1b54bd14ff8a 100644 --- a/src/main/webapp/app/exam/manage/student-exams/student-exam-timeline/student-exam-timeline.component.ts +++ b/src/main/webapp/app/exam/manage/student-exams/student-exam-timeline/student-exam-timeline.component.ts @@ -2,14 +2,14 @@ import { AfterViewInit, Component, OnDestroy, OnInit, QueryList, ViewChild, View import { ActivatedRoute } from '@angular/router'; import { StudentExam } from 'app/entities/student-exam.model'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; -import { ExamPage } from 'app/entities/exam-page.model'; +import { ExamPage } from 'app/entities/exam/exam-page.model'; import { ExamSubmissionComponent } from 'app/exam/participate/exercises/exam-submission.component'; import { ExamNavigationBarComponent } from 'app/exam/participate/exam-navigation-bar/exam-navigation-bar.component'; import { SubmissionService } from 'app/exercises/shared/submission/submission.service'; import dayjs from 'dayjs/esm'; import { SubmissionVersion } from 'app/entities/submission-version.model'; import { Observable, Subscription, forkJoin, map, mergeMap, toArray } from 'rxjs'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { Submission } from 'app/entities/submission.model'; import { FileUploadSubmission } from 'app/entities/file-upload-submission.model'; import { FileUploadExamSubmissionComponent } from 'app/exam/participate/exercises/file-upload/file-upload-exam-submission.component'; diff --git a/src/main/webapp/app/exam/manage/student-exams/student-exams.component.ts b/src/main/webapp/app/exam/manage/student-exams/student-exams.component.ts index 8ca3aed74f49..f10fc54ecf2a 100644 --- a/src/main/webapp/app/exam/manage/student-exams/student-exams.component.ts +++ b/src/main/webapp/app/exam/manage/student-exams/student-exams.component.ts @@ -10,7 +10,7 @@ import { Course } from 'app/entities/course.model'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { AlertService } from 'app/core/util/alert.service'; import { HttpErrorResponse } from '@angular/common/http'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ConfirmAutofocusModalComponent } from 'app/shared/components/confirm-autofocus-modal.component'; import dayjs from 'dayjs/esm'; import { AccountService } from 'app/core/auth/account.service'; diff --git a/src/main/webapp/app/exam/manage/students/exam-students.component.ts b/src/main/webapp/app/exam/manage/students/exam-students.component.ts index 43e72be1cbe3..ccc0f9e42671 100644 --- a/src/main/webapp/app/exam/manage/students/exam-students.component.ts +++ b/src/main/webapp/app/exam/manage/students/exam-students.component.ts @@ -1,6 +1,6 @@ import { Component, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; -import { ExamUser } from 'app/entities/exam-user.model'; +import { ExamUser } from 'app/entities/exam/exam-user.model'; import { Observable, Subject, Subscription, of } from 'rxjs'; import { ActivatedRoute, Router } from '@angular/router'; import { User } from 'app/core/user/user.model'; @@ -9,7 +9,7 @@ import { catchError, map, switchMap, tap } from 'rxjs/operators'; import { UserService } from 'app/core/user/user.service'; import { DataTableComponent } from 'app/shared/data-table/data-table.component'; import { iconsAsHTML } from 'app/utils/icons.utils'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { ButtonSize, ButtonType } from 'app/shared/components/button.component'; import { AccountService } from 'app/core/auth/account.service'; diff --git a/src/main/webapp/app/exam/manage/students/upload-images/students-upload-images-button.component.ts b/src/main/webapp/app/exam/manage/students/upload-images/students-upload-images-button.component.ts index 5f2cee93c4bf..16b03fe9bbcd 100644 --- a/src/main/webapp/app/exam/manage/students/upload-images/students-upload-images-button.component.ts +++ b/src/main/webapp/app/exam/manage/students/upload-images/students-upload-images-button.component.ts @@ -2,7 +2,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; import { StudentsUploadImagesDialogComponent } from 'app/exam/manage/students/upload-images/students-upload-images-dialog.component'; import { ButtonSize, ButtonType } from 'app/shared/components/button.component'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { faPlus, faUpload } from '@fortawesome/free-solid-svg-icons'; @Component({ diff --git a/src/main/webapp/app/exam/manage/students/upload-images/students-upload-images-dialog.component.ts b/src/main/webapp/app/exam/manage/students/upload-images/students-upload-images-dialog.component.ts index 3208de448eb1..f94e4b9f836c 100644 --- a/src/main/webapp/app/exam/manage/students/upload-images/students-upload-images-dialog.component.ts +++ b/src/main/webapp/app/exam/manage/students/upload-images/students-upload-images-dialog.component.ts @@ -5,7 +5,7 @@ import { AlertService } from 'app/core/util/alert.service'; import { HttpErrorResponse } from '@angular/common/http'; import { Subject } from 'rxjs'; import { ActionType } from 'app/shared/delete-dialog/delete-dialog.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { faArrowRight, faBan, faCheck, faCircleNotch, faSpinner, faUpload } from '@fortawesome/free-solid-svg-icons'; import { onError } from 'app/shared/util/global.utils'; diff --git a/src/main/webapp/app/exam/manage/students/verify-attendance-check/exam-students-attendance-check.component.ts b/src/main/webapp/app/exam/manage/students/verify-attendance-check/exam-students-attendance-check.component.ts index 1d78d6e3806e..e8cfdfa14426 100644 --- a/src/main/webapp/app/exam/manage/students/verify-attendance-check/exam-students-attendance-check.component.ts +++ b/src/main/webapp/app/exam/manage/students/verify-attendance-check/exam-students-attendance-check.component.ts @@ -1,12 +1,12 @@ import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; -import { ExamUserAttendanceCheckDTO } from 'app/entities/exam-users-attendance-check-dto.model'; +import { ExamUserAttendanceCheckDTO } from 'app/entities/exam/exam-users-attendance-check-dto.model'; import { SortService } from 'app/shared/service/sort.service'; import { Subject, Subscription } from 'rxjs'; import { ActivatedRoute, Router } from '@angular/router'; import { ActionType } from 'app/shared/delete-dialog/delete-dialog.model'; import { UserService } from 'app/core/user/user.service'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { ButtonSize, ButtonType } from 'app/shared/components/button.component'; import { AccountService } from 'app/core/auth/account.service'; diff --git a/src/main/webapp/app/exam/manage/suspicious-behavior/suspicious-behavior.component.ts b/src/main/webapp/app/exam/manage/suspicious-behavior/suspicious-behavior.component.ts index 18cf6ea1d227..f29b03f4d428 100644 --- a/src/main/webapp/app/exam/manage/suspicious-behavior/suspicious-behavior.component.ts +++ b/src/main/webapp/app/exam/manage/suspicious-behavior/suspicious-behavior.component.ts @@ -1,6 +1,6 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { Exercise } from 'app/entities/exercise.model'; -import { SuspiciousExamSessions, SuspiciousSessionsAnalysisOptions } from 'app/entities/exam-session.model'; +import { SuspiciousExamSessions, SuspiciousSessionsAnalysisOptions } from 'app/entities/exam/exam-session.model'; import { SuspiciousSessionsService } from 'app/exam/manage/suspicious-behavior/suspicious-sessions.service'; import { ActivatedRoute, Router } from '@angular/router'; import { PlagiarismCasesService } from 'app/course/plagiarism-cases/shared/plagiarism-cases.service'; diff --git a/src/main/webapp/app/exam/manage/suspicious-behavior/suspicious-sessions-overview/suspicious-sessions-overview.component.ts b/src/main/webapp/app/exam/manage/suspicious-behavior/suspicious-sessions-overview/suspicious-sessions-overview.component.ts index d24b473ec63c..01189459c644 100644 --- a/src/main/webapp/app/exam/manage/suspicious-behavior/suspicious-sessions-overview/suspicious-sessions-overview.component.ts +++ b/src/main/webapp/app/exam/manage/suspicious-behavior/suspicious-sessions-overview/suspicious-sessions-overview.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from '@angular/core'; -import { SuspiciousExamSessions, SuspiciousSessionReason } from 'app/entities/exam-session.model'; +import { SuspiciousExamSessions, SuspiciousSessionReason } from 'app/entities/exam/exam-session.model'; import { cloneDeep } from 'lodash-es'; @Component({ diff --git a/src/main/webapp/app/exam/manage/suspicious-behavior/suspicious-sessions.service.ts b/src/main/webapp/app/exam/manage/suspicious-behavior/suspicious-sessions.service.ts index 4f104cb23de8..8c526b0461ba 100644 --- a/src/main/webapp/app/exam/manage/suspicious-behavior/suspicious-sessions.service.ts +++ b/src/main/webapp/app/exam/manage/suspicious-behavior/suspicious-sessions.service.ts @@ -1,6 +1,6 @@ import { HttpClient, HttpParams } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { SuspiciousExamSessions, SuspiciousSessionsAnalysisOptions } from 'app/entities/exam-session.model'; +import { SuspiciousExamSessions, SuspiciousSessionsAnalysisOptions } from 'app/entities/exam/exam-session.model'; import { Observable } from 'rxjs'; @Injectable({ diff --git a/src/main/webapp/app/exam/manage/suspicious-behavior/suspicious-sessions/suspicious-sessions.component.ts b/src/main/webapp/app/exam/manage/suspicious-behavior/suspicious-sessions/suspicious-sessions.component.ts index 05885359d821..860dd819fd01 100644 --- a/src/main/webapp/app/exam/manage/suspicious-behavior/suspicious-sessions/suspicious-sessions.component.ts +++ b/src/main/webapp/app/exam/manage/suspicious-behavior/suspicious-sessions/suspicious-sessions.component.ts @@ -1,5 +1,5 @@ import { Component, Input, OnInit } from '@angular/core'; -import { SuspiciousExamSessions, SuspiciousSessionReason } from 'app/entities/exam-session.model'; +import { SuspiciousExamSessions, SuspiciousSessionReason } from 'app/entities/exam/exam-session.model'; import { StudentExam } from 'app/entities/student-exam.model'; @Component({ diff --git a/src/main/webapp/app/exam/manage/test-runs/create-test-run-modal.component.ts b/src/main/webapp/app/exam/manage/test-runs/create-test-run-modal.component.ts index 829ef039fd9a..a43fa4a9e41c 100644 --- a/src/main/webapp/app/exam/manage/test-runs/create-test-run-modal.component.ts +++ b/src/main/webapp/app/exam/manage/test-runs/create-test-run-modal.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { StudentExam } from 'app/entities/student-exam.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { Exercise } from 'app/entities/exercise.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { FormControl, FormGroup, Validators } from '@angular/forms'; diff --git a/src/main/webapp/app/exam/manage/test-runs/test-run-management.component.ts b/src/main/webapp/app/exam/manage/test-runs/test-run-management.component.ts index b10eb427b1dd..06d0196d6ba9 100644 --- a/src/main/webapp/app/exam/manage/test-runs/test-run-management.component.ts +++ b/src/main/webapp/app/exam/manage/test-runs/test-run-management.component.ts @@ -3,7 +3,7 @@ import { ActivatedRoute } from '@angular/router'; import { Course } from 'app/entities/course.model'; import { StudentExam } from 'app/entities/student-exam.model'; import { SortService } from 'app/shared/service/sort.service'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; import { AlertService } from 'app/core/util/alert.service'; import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; diff --git a/src/main/webapp/app/exam/participate/exam-bar/exam-bar.component.ts b/src/main/webapp/app/exam/participate/exam-bar/exam-bar.component.ts index 1b44965d5241..daf2532e3b15 100644 --- a/src/main/webapp/app/exam/participate/exam-bar/exam-bar.component.ts +++ b/src/main/webapp/app/exam/participate/exam-bar/exam-bar.component.ts @@ -7,7 +7,7 @@ import { ExamParticipationService } from 'app/exam/participate/exam-participatio import { Exercise, ExerciseType } from 'app/entities/exercise.model'; import { faDoorClosed } from '@fortawesome/free-solid-svg-icons'; import dayjs from 'dayjs/esm'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { StudentExam } from 'app/entities/student-exam.model'; @Component({ diff --git a/src/main/webapp/app/exam/participate/exam-cover/exam-participation-cover.component.ts b/src/main/webapp/app/exam/participate/exam-cover/exam-participation-cover.component.ts index eeb5bc50f9d4..090588335574 100644 --- a/src/main/webapp/app/exam/participate/exam-cover/exam-participation-cover.component.ts +++ b/src/main/webapp/app/exam/participate/exam-cover/exam-participation-cover.component.ts @@ -3,7 +3,7 @@ import { SafeHtml } from '@angular/platform-browser'; import { ArtemisMarkdownService } from 'app/shared/markdown.service'; import { CourseManagementService } from 'app/course/manage/course-management.service'; import { TranslateService } from '@ngx-translate/core'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { Course } from 'app/entities/course.model'; import { AccountService } from 'app/core/auth/account.service'; import { ExamParticipationService } from 'app/exam/participate/exam-participation.service'; diff --git a/src/main/webapp/app/exam/participate/exam-navigation-bar/exam-navigation-bar.component.ts b/src/main/webapp/app/exam/participate/exam-navigation-bar/exam-navigation-bar.component.ts index e73b90d55907..800285feeda1 100644 --- a/src/main/webapp/app/exam/participate/exam-navigation-bar/exam-navigation-bar.component.ts +++ b/src/main/webapp/app/exam/participate/exam-navigation-bar/exam-navigation-bar.component.ts @@ -1,6 +1,6 @@ import { AfterViewInit, Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { LayoutService } from 'app/shared/breakpoints/layout.service'; import { CustomBreakpointNames } from 'app/shared/breakpoints/breakpoints.service'; import dayjs from 'dayjs/esm'; @@ -12,9 +12,9 @@ import { CommitState, DomainChange, DomainType } from 'app/exercises/programming import { CodeEditorRepositoryService } from 'app/exercises/programming/shared/code-editor/service/code-editor-repository.service'; import { map } from 'rxjs/operators'; import { CodeEditorConflictStateService } from 'app/exercises/programming/shared/code-editor/service/code-editor-conflict-state.service'; -import { ExamSession } from 'app/entities/exam-session.model'; +import { ExamSession } from 'app/entities/exam/exam-session.model'; import { faBars, faCheck, faEdit } from '@fortawesome/free-solid-svg-icons'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { SubmissionVersion } from 'app/entities/submission-version.model'; import { FileUploadSubmission } from 'app/entities/file-upload-submission.model'; diff --git a/src/main/webapp/app/exam/participate/exam-navigation-sidebar/exam-navigation-sidebar.component.ts b/src/main/webapp/app/exam/participate/exam-navigation-sidebar/exam-navigation-sidebar.component.ts index 61408881fe77..93bcecfa27ae 100644 --- a/src/main/webapp/app/exam/participate/exam-navigation-sidebar/exam-navigation-sidebar.component.ts +++ b/src/main/webapp/app/exam/participate/exam-navigation-sidebar/exam-navigation-sidebar.component.ts @@ -6,9 +6,9 @@ import { Subscription } from 'rxjs'; import { SidebarEventService } from 'app/shared/sidebar/sidebar-event.service'; import { SidebarData } from 'app/types/sidebar'; import { ProfileService } from 'app/shared/layouts/profiles/profile.service'; -import { ExamSession } from 'app/entities/exam-session.model'; +import { ExamSession } from 'app/entities/exam/exam-session.model'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { SubmissionVersion } from 'app/entities/submission-version.model'; import { FileUploadSubmission } from 'app/entities/file-upload-submission.model'; import { CodeEditorRepositoryService } from 'app/exercises/programming/shared/code-editor/service/code-editor-repository.service'; @@ -17,7 +17,7 @@ import { ExamExerciseUpdateService } from 'app/exam/manage/exam-exercise-update. import { ButtonTooltipType, ExamParticipationService } from 'app/exam/participate/exam-participation.service'; import { map } from 'rxjs/operators'; import { CommitState, DomainChange, DomainType } from 'app/exercises/programming/shared/code-editor/model/code-editor.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { faChevronRight, faFileLines, faHourglassHalf } from '@fortawesome/free-solid-svg-icons'; import { facSaveSuccess, facSaveWarning } from '../../../../content/icons/icons'; diff --git a/src/main/webapp/app/exam/participate/exam-participation.component.ts b/src/main/webapp/app/exam/participate/exam-participation.component.ts index 18b5eec1daf5..a26170db25ca 100644 --- a/src/main/webapp/app/exam/participate/exam-participation.component.ts +++ b/src/main/webapp/app/exam/participate/exam-participation.component.ts @@ -5,30 +5,30 @@ import { ExamParticipationService } from 'app/exam/participate/exam-participatio import { StudentExam } from 'app/entities/student-exam.model'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; import { ExamSubmissionComponent } from 'app/exam/participate/exercises/exam-submission.component'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { ModelingSubmission } from 'app/entities/modeling-submission.model'; import { ModelingSubmissionService } from 'app/exercises/modeling/participate/modeling-submission.service'; import { ProgrammingSubmissionService } from 'app/exercises/programming/participate/programming-submission.service'; import { TextSubmissionService } from 'app/exercises/text/participate/text-submission.service'; import { QuizSubmission } from 'app/entities/quiz/quiz-submission.model'; import { Submission } from 'app/entities/submission.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ArtemisServerDateService } from 'app/shared/server-date.service'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; import { BehaviorSubject, Observable, Subject, Subscription, of, throwError } from 'rxjs'; import { catchError, distinctUntilChanged, filter, map, tap, throttleTime, timeout } from 'rxjs/operators'; import { InitializationState } from 'app/entities/participation/participation.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ComponentCanDeactivate } from 'app/shared/guard/can-deactivate.model'; import { TranslateService } from '@ngx-translate/core'; import { AlertService } from 'app/core/util/alert.service'; import dayjs from 'dayjs/esm'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { cloneDeep } from 'lodash-es'; import { Course } from 'app/entities/course.model'; import { captureException } from '@sentry/angular'; import { HttpErrorResponse } from '@angular/common/http'; -import { ExamPage } from 'app/entities/exam-page.model'; +import { ExamPage } from 'app/entities/exam/exam-page.model'; import { ExamPageComponent } from 'app/exam/participate/exercises/exam-page.component'; import { AUTOSAVE_CHECK_INTERVAL, AUTOSAVE_EXERCISE_INTERVAL } from 'app/shared/constants/exercise-exam-constants'; import { CourseExerciseService } from 'app/exercises/shared/course-exercises/course-exercise.service'; diff --git a/src/main/webapp/app/exam/participate/exam-participation.service.ts b/src/main/webapp/app/exam/participate/exam-participation.service.ts index a790afa7a361..5e125f6b1288 100644 --- a/src/main/webapp/app/exam/participate/exam-participation.service.ts +++ b/src/main/webapp/app/exam/participate/exam-participation.service.ts @@ -2,7 +2,7 @@ import { HttpClient, HttpErrorResponse, HttpParams, HttpResponse } from '@angula import { Injectable } from '@angular/core'; import { faLightbulb } from '@fortawesome/free-solid-svg-icons'; import { captureException } from '@sentry/angular'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { Exercise, ExerciseType, getIcon } from 'app/entities/exercise.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; diff --git a/src/main/webapp/app/exam/participate/exam-start-information/exam-start-information.component.ts b/src/main/webapp/app/exam/participate/exam-start-information/exam-start-information.component.ts index eafff2d69467..33237b989106 100644 --- a/src/main/webapp/app/exam/participate/exam-start-information/exam-start-information.component.ts +++ b/src/main/webapp/app/exam/participate/exam-start-information/exam-start-information.component.ts @@ -2,7 +2,7 @@ import { Component, Input, OnInit } from '@angular/core'; import { ArtemisSharedModule } from 'app/shared/shared.module'; import { ArtemisSharedComponentModule } from 'app/shared/components/shared-component.module'; import { InformationBox, InformationBoxComponent } from 'app/shared/information-box/information-box.component'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { StudentExam } from 'app/entities/student-exam.model'; import { ArtemisExamSharedModule } from 'app/exam/shared/exam-shared.module'; import dayjs from 'dayjs/esm'; diff --git a/src/main/webapp/app/exam/participate/exam.utils.ts b/src/main/webapp/app/exam/participate/exam.utils.ts index fecd529e9a80..1070606f377c 100644 --- a/src/main/webapp/app/exam/participate/exam.utils.ts +++ b/src/main/webapp/app/exam/participate/exam.utils.ts @@ -1,4 +1,4 @@ -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { StudentExam } from 'app/entities/student-exam.model'; import dayjs from 'dayjs/esm'; import { round } from 'app/shared/util/utils'; diff --git a/src/main/webapp/app/exam/participate/exercises/exercise-overview-page/exam-exercise-overview-page.component.ts b/src/main/webapp/app/exam/participate/exercises/exercise-overview-page/exam-exercise-overview-page.component.ts index 9e9c12dc8148..483891aba2c1 100644 --- a/src/main/webapp/app/exam/participate/exercises/exercise-overview-page/exam-exercise-overview-page.component.ts +++ b/src/main/webapp/app/exam/participate/exercises/exercise-overview-page/exam-exercise-overview-page.component.ts @@ -2,7 +2,7 @@ import { ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, OnInit, O import { Exercise, ExerciseType, getIcon, getIconTooltip } from 'app/entities/exercise.model'; import { ExamPageComponent } from 'app/exam/participate/exercises/exam-page.component'; import { StudentExam } from 'app/entities/student-exam.model'; -import { ExamExerciseOverviewItem } from 'app/entities/exam-exercise-overview-item.model'; +import { ExamExerciseOverviewItem } from 'app/entities/exam/exam-exercise-overview-item.model'; import { ButtonTooltipType, ExamParticipationService } from 'app/exam/participate/exam-participation.service'; import { faHourglassHalf } from '@fortawesome/free-solid-svg-icons'; import { facSaveSuccess, facSaveWarning } from '../../../../../content/icons/icons'; diff --git a/src/main/webapp/app/exam/participate/exercises/programming/programming-exam-submission.component.ts b/src/main/webapp/app/exam/participate/exercises/programming/programming-exam-submission.component.ts index 2179d1ba37c6..7b18cda9e20a 100644 --- a/src/main/webapp/app/exam/participate/exercises/programming/programming-exam-submission.component.ts +++ b/src/main/webapp/app/exam/participate/exercises/programming/programming-exam-submission.component.ts @@ -3,7 +3,7 @@ import { Submission } from 'app/entities/submission.model'; import { ExamSubmissionComponent } from 'app/exam/participate/exercises/exam-submission.component'; import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model'; import { ButtonSize, ButtonType } from 'app/shared/components/button.component'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { CommitState, DomainType, EditorState } from 'app/exercises/programming/shared/code-editor/model/code-editor.model'; import { Exercise, ExerciseType, IncludedInOverallScore, getCourseFromExercise } from 'app/entities/exercise.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; diff --git a/src/main/webapp/app/exam/participate/exercises/text/text-exam-submission.component.ts b/src/main/webapp/app/exam/participate/exercises/text/text-exam-submission.component.ts index 6b7359bab58b..3a493af08507 100644 --- a/src/main/webapp/app/exam/participate/exercises/text/text-exam-submission.component.ts +++ b/src/main/webapp/app/exam/participate/exercises/text/text-exam-submission.component.ts @@ -1,7 +1,7 @@ import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; import { TextEditorService } from 'app/exercises/text/participate/text-editor.service'; import { Subject } from 'rxjs'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { StringCountService } from 'app/exercises/text/participate/string-count.service'; import { Exercise, ExerciseType, IncludedInOverallScore } from 'app/entities/exercise.model'; import { ExamSubmissionComponent } from 'app/exam/participate/exercises/exam-submission.component'; diff --git a/src/main/webapp/app/exam/participate/general-information/exam-general-information.component.ts b/src/main/webapp/app/exam/participate/general-information/exam-general-information.component.ts index fb79c9e8ffab..89dc3774bf64 100644 --- a/src/main/webapp/app/exam/participate/general-information/exam-general-information.component.ts +++ b/src/main/webapp/app/exam/participate/general-information/exam-general-information.component.ts @@ -1,6 +1,6 @@ import { Component, Input, OnChanges } from '@angular/core'; import { StudentExam } from 'app/entities/student-exam.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { endTime, examWorkingTime, getAdditionalWorkingTime, isExamOverMultipleDays } from 'app/exam/participate/exam.utils'; import dayjs from 'dayjs/esm'; diff --git a/src/main/webapp/app/exam/participate/summary/exam-result-summary.component.ts b/src/main/webapp/app/exam/participate/summary/exam-result-summary.component.ts index ef25fa45c928..dc3af180c411 100644 --- a/src/main/webapp/app/exam/participate/summary/exam-result-summary.component.ts +++ b/src/main/webapp/app/exam/participate/summary/exam-result-summary.component.ts @@ -4,7 +4,7 @@ import { Exercise, ExerciseType, IncludedInOverallScore, getIcon } from 'app/ent import dayjs from 'dayjs/esm'; import { ActivatedRoute } from '@angular/router'; import { ArtemisServerDateService } from 'app/shared/server-date.service'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { AssessmentType } from 'app/entities/assessment-type.model'; import { ThemeService } from 'app/core/theme/theme.service'; import { ExerciseResult, StudentExamWithGradeDTO } from 'app/exam/exam-scores/exam-score-dtos.model'; @@ -22,7 +22,7 @@ import { faArrowUp, faEye, faEyeSlash, faFolderOpen, faInfoCircle, faPrint } fro import { cloneDeep } from 'lodash-es'; import { captureException } from '@sentry/angular'; import { AlertService } from 'app/core/util/alert.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { isExamResultPublished } from 'app/exam/participate/exam.utils'; import { Course } from 'app/entities/course.model'; diff --git a/src/main/webapp/app/exam/participate/summary/exercises/programming-exam-summary/programming-exam-summary.component.ts b/src/main/webapp/app/exam/participate/summary/exercises/programming-exam-summary/programming-exam-summary.component.ts index 6ba27112ac6b..2243c413644a 100644 --- a/src/main/webapp/app/exam/participate/summary/exercises/programming-exam-summary/programming-exam-summary.component.ts +++ b/src/main/webapp/app/exam/participate/summary/exercises/programming-exam-summary/programming-exam-summary.component.ts @@ -1,9 +1,9 @@ import { Component, Input, OnInit, Optional } from '@angular/core'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { AssessmentType } from 'app/entities/assessment-type.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExerciseType } from 'app/entities/exercise.model'; import { MissingResultInformation, evaluateTemplateStatus } from 'app/exercises/shared/result/result.utils'; import { FeedbackComponentPreparedParams, prepareFeedbackComponentParameters } from 'app/exercises/shared/feedback/feedback.utils'; diff --git a/src/main/webapp/app/exam/participate/summary/exercises/quiz-exam-summary/quiz-exam-summary.component.ts b/src/main/webapp/app/exam/participate/summary/exercises/quiz-exam-summary/quiz-exam-summary.component.ts index d1c71b7c9349..217925a8e230 100644 --- a/src/main/webapp/app/exam/participate/summary/exercises/quiz-exam-summary/quiz-exam-summary.component.ts +++ b/src/main/webapp/app/exam/participate/summary/exercises/quiz-exam-summary/quiz-exam-summary.component.ts @@ -9,7 +9,7 @@ import { MultipleChoiceSubmittedAnswer } from 'app/entities/quiz/multiple-choice import { DragAndDropSubmittedAnswer } from 'app/entities/quiz/drag-and-drop-submitted-answer.model'; import { ShortAnswerSubmittedAnswer } from 'app/entities/quiz/short-answer-submitted-answer.model'; import { QuizExerciseService } from 'app/exercises/quiz/manage/quiz-exercise.service'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ArtemisServerDateService } from 'app/shared/server-date.service'; import { Result } from 'app/entities/result.model'; import { roundValueSpecifiedByCourseSettings } from 'app/shared/util/utils'; diff --git a/src/main/webapp/app/exam/participate/summary/exercises/text-exam-summary/text-exam-summary.component.ts b/src/main/webapp/app/exam/participate/summary/exercises/text-exam-summary/text-exam-summary.component.ts index 5ea1bf223f68..a1dcf5c9de34 100644 --- a/src/main/webapp/app/exam/participate/summary/exercises/text-exam-summary/text-exam-summary.component.ts +++ b/src/main/webapp/app/exam/participate/summary/exercises/text-exam-summary/text-exam-summary.component.ts @@ -1,5 +1,5 @@ import { Component, Input } from '@angular/core'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { Exercise } from 'app/entities/exercise.model'; @Component({ diff --git a/src/main/webapp/app/exam/shared/working-time-control/working-time-control.component.ts b/src/main/webapp/app/exam/shared/working-time-control/working-time-control.component.ts index a343ac1c2743..4d90cf31e917 100644 --- a/src/main/webapp/app/exam/shared/working-time-control/working-time-control.component.ts +++ b/src/main/webapp/app/exam/shared/working-time-control/working-time-control.component.ts @@ -1,7 +1,7 @@ import { Component, Input } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { round } from 'app/shared/util/utils'; import { ArtemisDurationFromSecondsPipe } from 'app/shared/pipes/artemis-duration-from-seconds.pipe'; import { getRelativeWorkingTimeExtension } from 'app/exam/participate/exam.utils'; diff --git a/src/main/webapp/app/exercises/programming/assess/code-editor-tutor-assessment-container.component.ts b/src/main/webapp/app/exercises/programming/assess/code-editor-tutor-assessment-container.component.ts index 6ed273f43d6f..ca4b299f55bd 100644 --- a/src/main/webapp/app/exercises/programming/assess/code-editor-tutor-assessment-container.component.ts +++ b/src/main/webapp/app/exercises/programming/assess/code-editor-tutor-assessment-container.component.ts @@ -8,13 +8,13 @@ import { ButtonSize } from 'app/shared/components/button.component'; import { DomainService } from 'app/exercises/programming/shared/code-editor/service/code-editor-domain.service'; import { ExerciseType, IncludedInOverallScore, getCourseFromExercise } from 'app/entities/exercise.model'; import { Result } from 'app/entities/result.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { DomainType } from 'app/exercises/programming/shared/code-editor/model/code-editor.model'; import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model'; import { Complaint } from 'app/entities/complaint.model'; import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; import { ProgrammingAssessmentManualResultService } from 'app/exercises/programming/assess/manual-result/programming-assessment-manual-result.service'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { Location } from '@angular/common'; import { AccountService } from 'app/core/auth/account.service'; import { ProgrammingSubmissionService } from 'app/exercises/programming/participate/programming-submission.service'; diff --git a/src/main/webapp/app/exercises/programming/assess/repo-export/programming-assessment-repo-export-button.component.ts b/src/main/webapp/app/exercises/programming/assess/repo-export/programming-assessment-repo-export-button.component.ts index ab616e7037ca..9a2b5af07fb0 100644 --- a/src/main/webapp/app/exercises/programming/assess/repo-export/programming-assessment-repo-export-button.component.ts +++ b/src/main/webapp/app/exercises/programming/assess/repo-export/programming-assessment-repo-export-button.component.ts @@ -4,7 +4,7 @@ import { ProgrammingAssessmentRepoExportDialogComponent } from 'app/exercises/pr import { FeatureToggle } from 'app/shared/feature-toggle/feature-toggle.service'; import { ButtonSize, ButtonType } from 'app/shared/components/button.component'; import { faDownload } from '@fortawesome/free-solid-svg-icons'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; @Component({ selector: 'jhi-programming-assessment-repo-export', diff --git a/src/main/webapp/app/exercises/programming/assess/repo-export/programming-assessment-repo-export-dialog.component.ts b/src/main/webapp/app/exercises/programming/assess/repo-export/programming-assessment-repo-export-dialog.component.ts index a33b555747b7..e61c909e6893 100644 --- a/src/main/webapp/app/exercises/programming/assess/repo-export/programming-assessment-repo-export-dialog.component.ts +++ b/src/main/webapp/app/exercises/programming/assess/repo-export/programming-assessment-repo-export-dialog.component.ts @@ -4,7 +4,7 @@ import { AlertService } from 'app/core/util/alert.service'; import { ProgrammingAssessmentRepoExportService, RepositoryExportOptions } from 'app/exercises/programming/assess/repo-export/programming-assessment-repo-export.service'; import { HttpResponse } from '@angular/common/http'; import { FeatureToggle } from 'app/shared/feature-toggle/feature-toggle.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; import { downloadZipFileFromResponse } from 'app/shared/util/download.util'; import { faCircleNotch } from '@fortawesome/free-solid-svg-icons'; diff --git a/src/main/webapp/app/exercises/programming/hestia/generation-overview/code-hint-generation-overview/code-hint-generation-overview.component.ts b/src/main/webapp/app/exercises/programming/hestia/generation-overview/code-hint-generation-overview/code-hint-generation-overview.component.ts index 56d9dffe846e..d039db390a19 100644 --- a/src/main/webapp/app/exercises/programming/hestia/generation-overview/code-hint-generation-overview/code-hint-generation-overview.component.ts +++ b/src/main/webapp/app/exercises/programming/hestia/generation-overview/code-hint-generation-overview/code-hint-generation-overview.component.ts @@ -1,6 +1,6 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { CoverageReport } from 'app/entities/hestia/coverage-report.model'; import { ProgrammingExerciseSolutionEntry } from 'app/entities/hestia/programming-exercise-solution-entry.model'; import { CodeHint, CodeHintGenerationStep } from 'app/entities/hestia/code-hint-model'; diff --git a/src/main/webapp/app/exercises/programming/hestia/generation-overview/manual-solution-entry-creation-modal/manual-solution-entry-creation-modal.component.ts b/src/main/webapp/app/exercises/programming/hestia/generation-overview/manual-solution-entry-creation-modal/manual-solution-entry-creation-modal.component.ts index 71bd928ba2ed..0df03f1664b3 100644 --- a/src/main/webapp/app/exercises/programming/hestia/generation-overview/manual-solution-entry-creation-modal/manual-solution-entry-creation-modal.component.ts +++ b/src/main/webapp/app/exercises/programming/hestia/generation-overview/manual-solution-entry-creation-modal/manual-solution-entry-creation-modal.component.ts @@ -1,7 +1,7 @@ import { Component, EventEmitter, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { Subject } from 'rxjs'; -import { ProgrammingExerciseTestCase } from 'app/entities/programming-exercise-test-case.model'; +import { ProgrammingExerciseTestCase } from 'app/entities/programming/programming-exercise-test-case.model'; import { ProgrammingExerciseSolutionEntry } from 'app/entities/hestia/programming-exercise-solution-entry.model'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; import { CodeHint } from 'app/entities/hestia/code-hint-model'; diff --git a/src/main/webapp/app/exercises/programming/hestia/generation-overview/steps/code-hint-generation-step/code-hint-generation-step.component.ts b/src/main/webapp/app/exercises/programming/hestia/generation-overview/steps/code-hint-generation-step/code-hint-generation-step.component.ts index 254537ce8ad6..59e8150e2fe8 100644 --- a/src/main/webapp/app/exercises/programming/hestia/generation-overview/steps/code-hint-generation-step/code-hint-generation-step.component.ts +++ b/src/main/webapp/app/exercises/programming/hestia/generation-overview/steps/code-hint-generation-step/code-hint-generation-step.component.ts @@ -2,7 +2,7 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; import { CodeHint } from 'app/entities/hestia/code-hint-model'; import { faWrench } from '@fortawesome/free-solid-svg-icons'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { CodeHintService } from 'app/exercises/shared/exercise-hint/services/code-hint.service'; import { AlertService } from 'app/core/util/alert.service'; diff --git a/src/main/webapp/app/exercises/programming/hestia/generation-overview/steps/coverage-generation-step/coverage-generation-step.component.ts b/src/main/webapp/app/exercises/programming/hestia/generation-overview/steps/coverage-generation-step/coverage-generation-step.component.ts index 44658811f194..0fdc47306615 100644 --- a/src/main/webapp/app/exercises/programming/hestia/generation-overview/steps/coverage-generation-step/coverage-generation-step.component.ts +++ b/src/main/webapp/app/exercises/programming/hestia/generation-overview/steps/coverage-generation-step/coverage-generation-step.component.ts @@ -1,7 +1,7 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { CoverageReport } from 'app/entities/hestia/coverage-report.model'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { AlertService } from 'app/core/util/alert.service'; @Component({ diff --git a/src/main/webapp/app/exercises/programming/hestia/generation-overview/steps/diff-generation-step/diff-generation-step.component.ts b/src/main/webapp/app/exercises/programming/hestia/generation-overview/steps/diff-generation-step/diff-generation-step.component.ts index 2c2a2929fdfd..3903491a1477 100644 --- a/src/main/webapp/app/exercises/programming/hestia/generation-overview/steps/diff-generation-step/diff-generation-step.component.ts +++ b/src/main/webapp/app/exercises/programming/hestia/generation-overview/steps/diff-generation-step/diff-generation-step.component.ts @@ -1,6 +1,6 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { AlertService } from 'app/core/util/alert.service'; import { ProgrammingExerciseGitDiffReport } from 'app/entities/hestia/programming-exercise-git-diff-report.model'; diff --git a/src/main/webapp/app/exercises/programming/hestia/generation-overview/steps/solution-entry-generation-step/solution-entry-generation-step.component.ts b/src/main/webapp/app/exercises/programming/hestia/generation-overview/steps/solution-entry-generation-step/solution-entry-generation-step.component.ts index 13a0b57ec028..5d4b3c68f675 100644 --- a/src/main/webapp/app/exercises/programming/hestia/generation-overview/steps/solution-entry-generation-step/solution-entry-generation-step.component.ts +++ b/src/main/webapp/app/exercises/programming/hestia/generation-overview/steps/solution-entry-generation-step/solution-entry-generation-step.component.ts @@ -3,8 +3,8 @@ import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; import { ProgrammingExerciseSolutionEntry } from 'app/entities/hestia/programming-exercise-solution-entry.model'; import { SolutionEntryDetailsModalComponent } from 'app/exercises/programming/hestia/generation-overview/solution-entry-details-modal/solution-entry-details-modal.component'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; -import { ProgrammingExerciseTestCaseType } from 'app/entities/programming-exercise-test-case.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExerciseTestCaseType } from 'app/entities/programming/programming-exercise-test-case.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { AlertService } from 'app/core/util/alert.service'; import { Subject } from 'rxjs'; import { faSort, faSortDown, faSortUp, faTimes } from '@fortawesome/free-solid-svg-icons'; diff --git a/src/main/webapp/app/exercises/programming/manage/build-plan-editor.component.ts b/src/main/webapp/app/exercises/programming/manage/build-plan-editor.component.ts index 9aca74dfa4ef..b160bf88b2be 100644 --- a/src/main/webapp/app/exercises/programming/manage/build-plan-editor.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/build-plan-editor.component.ts @@ -3,9 +3,9 @@ import { faCircleNotch, faPlayCircle } from '@fortawesome/free-solid-svg-icons'; import { onError } from 'app/shared/util/global.utils'; import { AlertService } from 'app/core/util/alert.service'; import { BuildPlanService } from 'app/exercises/programming/manage/services/build-plan.service'; -import { BuildPlan } from 'app/entities/build-plan.model'; +import { BuildPlan } from 'app/entities/programming/build-plan.model'; import { ActivatedRoute } from '@angular/router'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; import { MonacoEditorComponent } from 'app/shared/monaco-editor/monaco-editor.component'; diff --git a/src/main/webapp/app/exercises/programming/manage/code-editor/code-editor-instructor-base-container.component.ts b/src/main/webapp/app/exercises/programming/manage/code-editor/code-editor-instructor-base-container.component.ts index 3dad17de0cf1..e53bf800e1a9 100644 --- a/src/main/webapp/app/exercises/programming/manage/code-editor/code-editor-instructor-base-container.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/code-editor/code-editor-instructor-base-container.component.ts @@ -12,7 +12,7 @@ import { TemplateProgrammingExerciseParticipation } from 'app/entities/participa import { ProgrammingExerciseParticipationService } from 'app/exercises/programming/manage/services/programming-exercise-participation.service'; import { ExerciseType } from 'app/entities/exercise.model'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model'; import { SolutionProgrammingExerciseParticipation } from 'app/entities/participation/solution-programming-exercise-participation.model'; import { DomainChange, DomainType } from 'app/exercises/programming/shared/code-editor/model/code-editor.model'; diff --git a/src/main/webapp/app/exercises/programming/manage/grading/charts/category-issues-chart.component.ts b/src/main/webapp/app/exercises/programming/manage/grading/charts/category-issues-chart.component.ts index 27aeb8f9ff8d..236a85bf0cce 100644 --- a/src/main/webapp/app/exercises/programming/manage/grading/charts/category-issues-chart.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/grading/charts/category-issues-chart.component.ts @@ -1,6 +1,6 @@ import { Component, Input, OnChanges } from '@angular/core'; -import { IssuesMap } from 'app/entities/programming-exercise-test-case-statistics.model'; -import { StaticCodeAnalysisCategory, StaticCodeAnalysisCategoryState } from 'app/entities/static-code-analysis-category.model'; +import { IssuesMap } from 'app/entities/programming/programming-exercise-test-case-statistics.model'; +import { StaticCodeAnalysisCategory, StaticCodeAnalysisCategoryState } from 'app/entities/programming/static-code-analysis-category.model'; export class IssueColumn { w: string; diff --git a/src/main/webapp/app/exercises/programming/manage/grading/charts/sca-category-distribution-chart.component.ts b/src/main/webapp/app/exercises/programming/manage/grading/charts/sca-category-distribution-chart.component.ts index 59c58c9fc817..58e2d7aa9dd3 100644 --- a/src/main/webapp/app/exercises/programming/manage/grading/charts/sca-category-distribution-chart.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/grading/charts/sca-category-distribution-chart.component.ts @@ -1,7 +1,7 @@ import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; -import { StaticCodeAnalysisCategory, StaticCodeAnalysisCategoryState } from 'app/entities/static-code-analysis-category.model'; -import { CategoryIssuesMap } from 'app/entities/programming-exercise-test-case-statistics.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; +import { StaticCodeAnalysisCategory, StaticCodeAnalysisCategoryState } from 'app/entities/programming/static-code-analysis-category.model'; +import { CategoryIssuesMap } from 'app/entities/programming/programming-exercise-test-case-statistics.model'; import { TranslateService } from '@ngx-translate/core'; import { getColor } from 'app/exercises/programming/manage/grading/charts/programming-grading-charts.utils'; import { ProgrammingGradingChartsDirective } from 'app/exercises/programming/manage/grading/charts/programming-grading-charts.directive'; diff --git a/src/main/webapp/app/exercises/programming/manage/grading/charts/test-case-distribution-chart.component.ts b/src/main/webapp/app/exercises/programming/manage/grading/charts/test-case-distribution-chart.component.ts index 5aceb9c57804..568402289fca 100644 --- a/src/main/webapp/app/exercises/programming/manage/grading/charts/test-case-distribution-chart.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/grading/charts/test-case-distribution-chart.component.ts @@ -1,7 +1,7 @@ import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core'; -import { ProgrammingExerciseTestCase, Visibility } from 'app/entities/programming-exercise-test-case.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; -import { TestCaseStatsMap } from 'app/entities/programming-exercise-test-case-statistics.model'; +import { ProgrammingExerciseTestCase, Visibility } from 'app/entities/programming/programming-exercise-test-case.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; +import { TestCaseStatsMap } from 'app/entities/programming/programming-exercise-test-case-statistics.model'; import { TranslateService } from '@ngx-translate/core'; import { getColor } from 'app/exercises/programming/manage/grading/charts/programming-grading-charts.utils'; import { ProgrammingGradingChartsDirective } from 'app/exercises/programming/manage/grading/charts/programming-grading-charts.directive'; diff --git a/src/main/webapp/app/exercises/programming/manage/grading/charts/test-case-passed-builds-chart.component.ts b/src/main/webapp/app/exercises/programming/manage/grading/charts/test-case-passed-builds-chart.component.ts index d7c9dadfe0ed..03e4a076bc58 100644 --- a/src/main/webapp/app/exercises/programming/manage/grading/charts/test-case-passed-builds-chart.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/grading/charts/test-case-passed-builds-chart.component.ts @@ -1,5 +1,5 @@ import { Component, Input, OnChanges } from '@angular/core'; -import { TestCaseStats } from 'app/entities/programming-exercise-test-case-statistics.model'; +import { TestCaseStats } from 'app/entities/programming/programming-exercise-test-case-statistics.model'; import { round } from 'app/shared/util/utils'; @Component({ diff --git a/src/main/webapp/app/exercises/programming/manage/grading/programming-exercise-configure-grading-actions.component.ts b/src/main/webapp/app/exercises/programming/manage/grading/programming-exercise-configure-grading-actions.component.ts index fec4e31523f6..6c91acef5676 100644 --- a/src/main/webapp/app/exercises/programming/manage/grading/programming-exercise-configure-grading-actions.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/grading/programming-exercise-configure-grading-actions.component.ts @@ -1,5 +1,5 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; /** * The actions of the grading page: diff --git a/src/main/webapp/app/exercises/programming/manage/grading/programming-exercise-configure-grading.component.ts b/src/main/webapp/app/exercises/programming/manage/grading/programming-exercise-configure-grading.component.ts index c242b861d14e..be99194cbd3c 100644 --- a/src/main/webapp/app/exercises/programming/manage/grading/programming-exercise-configure-grading.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/grading/programming-exercise-configure-grading.component.ts @@ -7,10 +7,10 @@ import { AccountService } from 'app/core/auth/account.service'; import { AlertService } from 'app/core/util/alert.service'; import { CourseManagementService } from 'app/course/manage/course-management.service'; import { Course } from 'app/entities/course.model'; -import { IssuesMap, ProgrammingExerciseGradingStatistics } from 'app/entities/programming-exercise-test-case-statistics.model'; -import { ProgrammingExerciseTestCase, Visibility } from 'app/entities/programming-exercise-test-case.model'; -import { ProgrammingExercise, ProgrammingLanguage } from 'app/entities/programming-exercise.model'; -import { StaticCodeAnalysisCategory, StaticCodeAnalysisCategoryState } from 'app/entities/static-code-analysis-category.model'; +import { IssuesMap, ProgrammingExerciseGradingStatistics } from 'app/entities/programming/programming-exercise-test-case-statistics.model'; +import { ProgrammingExerciseTestCase, Visibility } from 'app/entities/programming/programming-exercise-test-case.model'; +import { ProgrammingExercise, ProgrammingLanguage } from 'app/entities/programming/programming-exercise.model'; +import { StaticCodeAnalysisCategory, StaticCodeAnalysisCategoryState } from 'app/entities/programming/static-code-analysis-category.model'; import { SubmissionPolicy, SubmissionPolicyType } from 'app/entities/submission-policy.model'; import { ProgrammingGradingChartsDirective } from 'app/exercises/programming/manage/grading/charts/programming-grading-charts.directive'; import { ProgrammingExerciseGradingService, StaticCodeAnalysisCategoryUpdate } from 'app/exercises/programming/manage/services/programming-exercise-grading.service'; diff --git a/src/main/webapp/app/exercises/programming/manage/grading/programming-exercise-grading-submission-policy-configuration-actions.component.ts b/src/main/webapp/app/exercises/programming/manage/grading/programming-exercise-grading-submission-policy-configuration-actions.component.ts index 36fcfeb230b6..7e5156faaa52 100644 --- a/src/main/webapp/app/exercises/programming/manage/grading/programming-exercise-grading-submission-policy-configuration-actions.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/grading/programming-exercise-grading-submission-policy-configuration-actions.component.ts @@ -1,6 +1,6 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; import { faSave } from '@fortawesome/free-solid-svg-icons'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { SubmissionPolicyType } from 'app/entities/submission-policy.model'; import { ButtonType } from 'app/shared/components/button.component'; diff --git a/src/main/webapp/app/exercises/programming/manage/grading/programming-exercise-grading-table-actions.component.ts b/src/main/webapp/app/exercises/programming/manage/grading/programming-exercise-grading-table-actions.component.ts index 714ef84c2beb..ae956e5b7a96 100644 --- a/src/main/webapp/app/exercises/programming/manage/grading/programming-exercise-grading-table-actions.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/grading/programming-exercise-grading-table-actions.component.ts @@ -2,7 +2,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; import { faCopy } from '@fortawesome/free-solid-svg-icons'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { ExerciseType } from 'app/entities/exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { GradingTab } from 'app/exercises/programming/manage/grading/programming-exercise-configure-grading.component'; import { ExerciseImportWrapperComponent } from 'app/exercises/shared/import/exercise-import-wrapper/exercise-import-wrapper.component'; diff --git a/src/main/webapp/app/exercises/programming/manage/grading/tasks/programming-exercise-grading-tasks-table.component.ts b/src/main/webapp/app/exercises/programming/manage/grading/tasks/programming-exercise-grading-tasks-table.component.ts index a40d38cade8e..bd491c999df9 100644 --- a/src/main/webapp/app/exercises/programming/manage/grading/tasks/programming-exercise-grading-tasks-table.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/grading/tasks/programming-exercise-grading-tasks-table.component.ts @@ -1,12 +1,12 @@ import { Component, Input, OnInit } from '@angular/core'; import { ProgrammingExerciseTaskService } from 'app/exercises/programming/manage/grading/tasks/programming-exercise-task.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { Course } from 'app/entities/course.model'; import { faAngleDown, faAngleRight, faAsterisk, faMedal, faQuestionCircle, faScaleUnbalanced, faSort, faSortDown, faSortUp } from '@fortawesome/free-solid-svg-icons'; -import { ProgrammingExerciseGradingStatistics } from 'app/entities/programming-exercise-test-case-statistics.model'; +import { ProgrammingExerciseGradingStatistics } from 'app/entities/programming/programming-exercise-test-case-statistics.model'; import { ProgrammingExerciseTask } from './programming-exercise-task'; import { Observable, Subject } from 'rxjs'; -import { ProgrammingExerciseTestCase } from 'app/entities/programming-exercise-test-case.model'; +import { ProgrammingExerciseTestCase } from 'app/entities/programming/programming-exercise-test-case.model'; import { isExamExercise } from 'app/shared/util/utils'; import { ProgrammingExerciseServerSideTask } from 'app/entities/hestia/programming-exercise-task.model'; diff --git a/src/main/webapp/app/exercises/programming/manage/grading/tasks/programming-exercise-task.service.ts b/src/main/webapp/app/exercises/programming/manage/grading/tasks/programming-exercise-task.service.ts index 508c1e4d21bf..5f45d551b476 100644 --- a/src/main/webapp/app/exercises/programming/manage/grading/tasks/programming-exercise-task.service.ts +++ b/src/main/webapp/app/exercises/programming/manage/grading/tasks/programming-exercise-task.service.ts @@ -4,11 +4,11 @@ import { ProgrammingExerciseServerSideTask } from 'app/entities/hestia/programmi import { Observable, catchError, of, tap } from 'rxjs'; import { Exercise } from 'app/entities/exercise.model'; import { ProgrammingExerciseTask } from 'app/exercises/programming/manage/grading/tasks/programming-exercise-task'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { Course } from 'app/entities/course.model'; import { roundValueSpecifiedByCourseSettings } from 'app/shared/util/utils'; -import { ProgrammingExerciseGradingStatistics, TestCaseStats } from 'app/entities/programming-exercise-test-case-statistics.model'; -import { ProgrammingExerciseTestCase } from 'app/entities/programming-exercise-test-case.model'; +import { ProgrammingExerciseGradingStatistics, TestCaseStats } from 'app/entities/programming/programming-exercise-test-case-statistics.model'; +import { ProgrammingExerciseTestCase } from 'app/entities/programming/programming-exercise-test-case.model'; import { ProgrammingExerciseGradingService, ProgrammingExerciseTestCaseUpdate } from '../../services/programming-exercise-grading.service'; import { AlertService } from 'app/core/util/alert.service'; import { map, mergeMap } from 'rxjs/operators'; diff --git a/src/main/webapp/app/exercises/programming/manage/grading/tasks/programming-exercise-task.ts b/src/main/webapp/app/exercises/programming/manage/grading/tasks/programming-exercise-task.ts index cff99aac5cc2..3a5844ddbb9e 100644 --- a/src/main/webapp/app/exercises/programming/manage/grading/tasks/programming-exercise-task.ts +++ b/src/main/webapp/app/exercises/programming/manage/grading/tasks/programming-exercise-task.ts @@ -1,6 +1,6 @@ import { ProgrammingExerciseServerSideTask } from 'app/entities/hestia/programming-exercise-task.model'; -import { TestCaseStats } from 'app/entities/programming-exercise-test-case-statistics.model'; -import { ProgrammingExerciseTestCase, ProgrammingExerciseTestCaseType, Visibility } from 'app/entities/programming-exercise-test-case.model'; +import { TestCaseStats } from 'app/entities/programming/programming-exercise-test-case-statistics.model'; +import { ProgrammingExerciseTestCase, ProgrammingExerciseTestCaseType, Visibility } from 'app/entities/programming/programming-exercise-test-case.model'; export class ProgrammingExerciseTask extends ProgrammingExerciseServerSideTask { declare testCases: ProgrammingExerciseTestCase[]; diff --git a/src/main/webapp/app/exercises/programming/manage/grading/tasks/programming-exercise-task/programming-exercise-task.component.ts b/src/main/webapp/app/exercises/programming/manage/grading/tasks/programming-exercise-task/programming-exercise-task.component.ts index d8c77b50c8df..837c0210f76d 100644 --- a/src/main/webapp/app/exercises/programming/manage/grading/tasks/programming-exercise-task/programming-exercise-task.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/grading/tasks/programming-exercise-task/programming-exercise-task.component.ts @@ -1,7 +1,7 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { faAngleDown, faAngleRight } from '@fortawesome/free-solid-svg-icons'; import { ProgrammingExerciseTask } from 'app/exercises/programming/manage/grading/tasks/programming-exercise-task'; -import { ProgrammingExerciseTestCase, Visibility } from 'app/entities/programming-exercise-test-case.model'; +import { ProgrammingExerciseTestCase, Visibility } from 'app/entities/programming/programming-exercise-test-case.model'; import { ProgrammingExerciseTaskService } from '../programming-exercise-task.service'; import { Subject } from 'rxjs'; diff --git a/src/main/webapp/app/exercises/programming/manage/instructions-editor/programming-exercise-editable-instruction.component.ts b/src/main/webapp/app/exercises/programming/manage/instructions-editor/programming-exercise-editable-instruction.component.ts index b20fb2d6e149..e194057bfd89 100644 --- a/src/main/webapp/app/exercises/programming/manage/instructions-editor/programming-exercise-editable-instruction.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/instructions-editor/programming-exercise-editable-instruction.component.ts @@ -2,11 +2,11 @@ import { AfterViewInit, Component, EventEmitter, HostListener, Input, OnChanges, import { AlertService } from 'app/core/util/alert.service'; import { Observable, Subject, Subscription, of, throwError } from 'rxjs'; import { catchError, map as rxMap, switchMap, tap } from 'rxjs/operators'; -import { ProgrammingExerciseTestCase } from 'app/entities/programming-exercise-test-case.model'; +import { ProgrammingExerciseTestCase } from 'app/entities/programming/programming-exercise-test-case.model'; import { ProblemStatementAnalysis } from 'app/exercises/programming/manage/instructions-editor/analysis/programming-exercise-instruction-analysis.model'; import { Participation } from 'app/entities/participation/participation.model'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { hasExerciseChanged } from 'app/exercises/shared/exercise/exercise.utils'; import { ProgrammingExerciseParticipationService } from 'app/exercises/programming/manage/services/programming-exercise-participation.service'; import { ProgrammingExerciseGradingService } from 'app/exercises/programming/manage/services/programming-exercise-grading.service'; diff --git a/src/main/webapp/app/exercises/programming/manage/programming-exercise-create-buttons.component.ts b/src/main/webapp/app/exercises/programming/manage/programming-exercise-create-buttons.component.ts index 5ec55e54f894..9c842a025b85 100644 --- a/src/main/webapp/app/exercises/programming/manage/programming-exercise-create-buttons.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/programming-exercise-create-buttons.component.ts @@ -4,7 +4,7 @@ import { FeatureToggle } from 'app/shared/feature-toggle/feature-toggle.service' import { faFileImport, faKeyboard, faPlus } from '@fortawesome/free-solid-svg-icons'; import { ExerciseImportWrapperComponent } from 'app/exercises/shared/import/exercise-import-wrapper/exercise-import-wrapper.component'; import { ExerciseType } from 'app/entities/exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { Router } from '@angular/router'; diff --git a/src/main/webapp/app/exercises/programming/manage/programming-exercise-detail.component.ts b/src/main/webapp/app/exercises/programming/manage/programming-exercise-detail.component.ts index 6576932d20e1..1a1a95462530 100644 --- a/src/main/webapp/app/exercises/programming/manage/programming-exercise-detail.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/programming-exercise-detail.component.ts @@ -1,11 +1,12 @@ import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { SafeHtml } from '@angular/platform-browser'; +import { ProgrammingExerciseBuildConfig } from 'app/entities/programming/programming-exercise-build.config'; import { Subject, Subscription } from 'rxjs'; -import { ProgrammingExercise, ProgrammingExerciseBuildConfig, ProgrammingLanguage } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise, ProgrammingLanguage } from 'app/entities/programming/programming-exercise.model'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; import { AlertService, AlertType } from 'app/core/util/alert.service'; -import { ProgrammingExerciseParticipationType } from 'app/entities/programming-exercise-participation.model'; +import { ProgrammingExerciseParticipationType } from 'app/entities/programming/programming-exercise-participation.model'; import { AccountService } from 'app/core/auth/account.service'; import { HttpErrorResponse } from '@angular/common/http'; import { ActionType } from 'app/shared/delete-dialog/delete-dialog.model'; diff --git a/src/main/webapp/app/exercises/programming/manage/programming-exercise-edit-selected.component.ts b/src/main/webapp/app/exercises/programming/manage/programming-exercise-edit-selected.component.ts index 5dd785d95005..287e50b11913 100644 --- a/src/main/webapp/app/exercises/programming/manage/programming-exercise-edit-selected.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/programming-exercise-edit-selected.component.ts @@ -3,7 +3,7 @@ import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { TranslateService } from '@ngx-translate/core'; import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; import { Observable } from 'rxjs'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; import { AlertService, AlertType } from 'app/core/util/alert.service'; import { faSave } from '@fortawesome/free-solid-svg-icons'; diff --git a/src/main/webapp/app/exercises/programming/manage/programming-exercise-management-routing.module.ts b/src/main/webapp/app/exercises/programming/manage/programming-exercise-management-routing.module.ts index 39ed8888464a..54c277c9bd7d 100644 --- a/src/main/webapp/app/exercises/programming/manage/programming-exercise-management-routing.module.ts +++ b/src/main/webapp/app/exercises/programming/manage/programming-exercise-management-routing.module.ts @@ -3,7 +3,7 @@ import { UserRouteAccessService } from 'app/core/auth/user-route-access-service' import { Injectable, NgModule } from '@angular/core'; import { ProgrammingExerciseDetailComponent } from 'app/exercises/programming/manage/programming-exercise-detail.component'; import { ProgrammingExerciseUpdateComponent } from 'app/exercises/programming/manage/update/programming-exercise-update.component'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; import { map } from 'rxjs/operators'; import { HttpResponse } from '@angular/common/http'; diff --git a/src/main/webapp/app/exercises/programming/manage/programming-exercise.component.ts b/src/main/webapp/app/exercises/programming/manage/programming-exercise.component.ts index b28fbed3d6b9..e40533f526cc 100644 --- a/src/main/webapp/app/exercises/programming/manage/programming-exercise.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/programming-exercise.component.ts @@ -1,7 +1,7 @@ import { Component, ContentChild, Input, OnDestroy, OnInit, TemplateRef } from '@angular/core'; import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; import { merge } from 'rxjs'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ProgrammingExerciseInstructorRepositoryType, ProgrammingExerciseService } from './services/programming-exercise.service'; import { ActivatedRoute } from '@angular/router'; import { ExerciseComponent } from 'app/exercises/shared/exercise/exercise.component'; @@ -15,7 +15,7 @@ import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service' import { CourseManagementService } from 'app/course/manage/course-management.service'; import { SortService } from 'app/shared/service/sort.service'; import { ProgrammingExerciseEditSelectedComponent } from 'app/exercises/programming/manage/programming-exercise-edit-selected.component'; -import { ProgrammingExerciseParticipationType } from 'app/entities/programming-exercise-participation.model'; +import { ProgrammingExerciseParticipationType } from 'app/entities/programming/programming-exercise-participation.model'; import { AlertService } from 'app/core/util/alert.service'; import { EventManager } from 'app/core/util/event-manager.service'; import { createBuildPlanUrl } from 'app/exercises/programming/shared/utils/programming-exercise.utils'; diff --git a/src/main/webapp/app/exercises/programming/manage/reset/programming-exercise-reset-button.directive.ts b/src/main/webapp/app/exercises/programming/manage/reset/programming-exercise-reset-button.directive.ts index a16d439806db..f249959c63b5 100644 --- a/src/main/webapp/app/exercises/programming/manage/reset/programming-exercise-reset-button.directive.ts +++ b/src/main/webapp/app/exercises/programming/manage/reset/programming-exercise-reset-button.directive.ts @@ -1,7 +1,7 @@ import { Directive, ElementRef, HostListener, Input, OnInit, Renderer2 } from '@angular/core'; import { ProgrammingExerciseResetDialogComponent } from 'app/exercises/programming/manage/reset/programming-exercise-reset-dialog.component'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; @Directive({ selector: '[jhiProgrammingExerciseResetButton]', diff --git a/src/main/webapp/app/exercises/programming/manage/reset/programming-exercise-reset-dialog.component.ts b/src/main/webapp/app/exercises/programming/manage/reset/programming-exercise-reset-dialog.component.ts index 2ffe3935810a..f064e177d1ff 100644 --- a/src/main/webapp/app/exercises/programming/manage/reset/programming-exercise-reset-dialog.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/reset/programming-exercise-reset-dialog.component.ts @@ -3,7 +3,7 @@ import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { AlertService } from 'app/core/util/alert.service'; import { ProfileService } from 'app/shared/layouts/profiles/profile.service'; import { FeatureToggle } from 'app/shared/feature-toggle/feature-toggle.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ProgrammingExerciseResetOptions, ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; import { faBan, faCircleNotch, faSpinner, faUndo } from '@fortawesome/free-solid-svg-icons'; import { PROFILE_AEOLUS, PROFILE_LOCALCI } from 'app/app.constants'; diff --git a/src/main/webapp/app/exercises/programming/manage/services/build-plan.service.ts b/src/main/webapp/app/exercises/programming/manage/services/build-plan.service.ts index ebafd624ea66..49f0aa9dcbff 100644 --- a/src/main/webapp/app/exercises/programming/manage/services/build-plan.service.ts +++ b/src/main/webapp/app/exercises/programming/manage/services/build-plan.service.ts @@ -1,7 +1,7 @@ import { HttpClient, HttpResponse } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; -import { BuildPlan } from 'app/entities/build-plan.model'; +import { BuildPlan } from 'app/entities/programming/build-plan.model'; export type EntityResponseType = HttpResponse; diff --git a/src/main/webapp/app/exercises/programming/manage/services/code-analysis-paging.service.ts b/src/main/webapp/app/exercises/programming/manage/services/code-analysis-paging.service.ts index a6bbcc6931cf..39fe777826e6 100644 --- a/src/main/webapp/app/exercises/programming/manage/services/code-analysis-paging.service.ts +++ b/src/main/webapp/app/exercises/programming/manage/services/code-analysis-paging.service.ts @@ -1,6 +1,6 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ProgrammingExercisePagingService } from 'app/exercises/programming/manage/services/programming-exercise-paging.service'; import { ExercisePagingService } from 'app/exercises/shared/manage/exercise-paging.service'; diff --git a/src/main/webapp/app/exercises/programming/manage/services/programming-exercise-grading.service.ts b/src/main/webapp/app/exercises/programming/manage/services/programming-exercise-grading.service.ts index 134da4e5abe5..f2ebc62a33f7 100644 --- a/src/main/webapp/app/exercises/programming/manage/services/programming-exercise-grading.service.ts +++ b/src/main/webapp/app/exercises/programming/manage/services/programming-exercise-grading.service.ts @@ -3,9 +3,9 @@ import { HttpClient, HttpParams } from '@angular/common/http'; import { BehaviorSubject, Observable, of } from 'rxjs'; import { catchError, map, switchMap, tap } from 'rxjs/operators'; import { JhiWebsocketService } from 'app/core/websocket/websocket.service'; -import { ProgrammingExerciseTestCase, Visibility } from 'app/entities/programming-exercise-test-case.model'; -import { StaticCodeAnalysisCategory } from 'app/entities/static-code-analysis-category.model'; -import { ProgrammingExerciseGradingStatistics } from 'app/entities/programming-exercise-test-case-statistics.model'; +import { ProgrammingExerciseTestCase, Visibility } from 'app/entities/programming/programming-exercise-test-case.model'; +import { StaticCodeAnalysisCategory } from 'app/entities/programming/static-code-analysis-category.model'; +import { ProgrammingExerciseGradingStatistics } from 'app/entities/programming/programming-exercise-test-case-statistics.model'; export class ProgrammingExerciseTestCaseUpdate { constructor( diff --git a/src/main/webapp/app/exercises/programming/manage/services/programming-exercise-paging.service.ts b/src/main/webapp/app/exercises/programming/manage/services/programming-exercise-paging.service.ts index 29c311cfd44b..08012217fb18 100644 --- a/src/main/webapp/app/exercises/programming/manage/services/programming-exercise-paging.service.ts +++ b/src/main/webapp/app/exercises/programming/manage/services/programming-exercise-paging.service.ts @@ -1,6 +1,6 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ExercisePagingService } from 'app/exercises/shared/manage/exercise-paging.service'; @Injectable({ providedIn: 'root' }) diff --git a/src/main/webapp/app/exercises/programming/manage/services/programming-exercise-participation.service.ts b/src/main/webapp/app/exercises/programming/manage/services/programming-exercise-participation.service.ts index 7af098d1a5a7..5953571a4190 100644 --- a/src/main/webapp/app/exercises/programming/manage/services/programming-exercise-participation.service.ts +++ b/src/main/webapp/app/exercises/programming/manage/services/programming-exercise-participation.service.ts @@ -7,7 +7,7 @@ import { Result } from 'app/entities/result.model'; import { EntityTitleService, EntityType } from 'app/shared/layouts/navbar/entity-title.service'; import { createRequestOption } from 'app/shared/util/request.util'; import { Observable, map, tap } from 'rxjs'; -import { CommitInfo } from 'app/entities/programming-submission.model'; +import { CommitInfo } from 'app/entities/programming/programming-submission.model'; export interface IProgrammingExerciseParticipationService { getLatestResultWithFeedback: (participationId: number, withSubmission: boolean) => Observable; diff --git a/src/main/webapp/app/exercises/programming/manage/services/programming-exercise-websocket.service.ts b/src/main/webapp/app/exercises/programming/manage/services/programming-exercise-websocket.service.ts index a73a3bc5c715..30d8f11507b7 100644 --- a/src/main/webapp/app/exercises/programming/manage/services/programming-exercise-websocket.service.ts +++ b/src/main/webapp/app/exercises/programming/manage/services/programming-exercise-websocket.service.ts @@ -3,7 +3,7 @@ import { HttpResponse } from '@angular/common/http'; import { BehaviorSubject, Observable } from 'rxjs'; import { filter, tap } from 'rxjs/operators'; import { JhiWebsocketService } from 'app/core/websocket/websocket.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; export type EntityResponseType = HttpResponse; export type EntityArrayResponseType = HttpResponse; diff --git a/src/main/webapp/app/exercises/programming/manage/services/programming-exercise.service.ts b/src/main/webapp/app/exercises/programming/manage/services/programming-exercise.service.ts index 39fa4800ecb6..82077ff4ffd6 100644 --- a/src/main/webapp/app/exercises/programming/manage/services/programming-exercise.service.ts +++ b/src/main/webapp/app/exercises/programming/manage/services/programming-exercise.service.ts @@ -7,7 +7,7 @@ import { omit as _omit } from 'lodash-es'; import { createRequestOption } from 'app/shared/util/request.util'; import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; -import { ProgrammingExercise, ProgrammingLanguage } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise, ProgrammingLanguage } from 'app/entities/programming/programming-exercise.model'; import { TemplateProgrammingExerciseParticipation } from 'app/entities/participation/template-programming-exercise-participation.model'; import { SolutionProgrammingExerciseParticipation } from 'app/entities/participation/solution-programming-exercise-participation.model'; import { TextPlagiarismResult } from 'app/exercises/shared/plagiarism/types/text/TextPlagiarismResult'; @@ -19,14 +19,14 @@ import { ProgrammingExerciseSolutionEntry } from 'app/entities/hestia/programmin import { ProgrammingExerciseServerSideTask } from 'app/entities/hestia/programming-exercise-task.model'; import { convertDateFromClient, convertDateFromServer } from 'app/utils/date.utils'; import { ExerciseHint } from 'app/entities/hestia/exercise-hint.model'; -import { ProgrammingExerciseTestCase } from 'app/entities/programming-exercise-test-case.model'; -import { BuildLogStatisticsDTO } from 'app/entities/build-log-statistics-dto'; +import { ProgrammingExerciseTestCase } from 'app/entities/programming/programming-exercise-test-case.model'; +import { BuildLogStatisticsDTO } from 'app/entities/programming/build-log-statistics-dto'; import { SortService } from 'app/shared/service/sort.service'; import { Result } from 'app/entities/result.model'; import { Participation } from 'app/entities/participation/participation.model'; import { PlagiarismResultDTO } from 'app/exercises/shared/plagiarism/types/PlagiarismResultDTO'; import { ImportOptions } from 'app/types/programming-exercises'; -import { CheckoutDirectoriesDto } from 'app/entities/checkout-directories-dto'; +import { CheckoutDirectoriesDto } from 'app/entities/programming/checkout-directories-dto'; export type EntityResponseType = HttpResponse; export type EntityArrayResponseType = HttpResponse; diff --git a/src/main/webapp/app/exercises/programming/manage/status/programming-exercise-instructor-exercise-status.component.ts b/src/main/webapp/app/exercises/programming/manage/status/programming-exercise-instructor-exercise-status.component.ts index 85bf8287074f..f9bd6758fd23 100644 --- a/src/main/webapp/app/exercises/programming/manage/status/programming-exercise-instructor-exercise-status.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/status/programming-exercise-instructor-exercise-status.component.ts @@ -3,7 +3,7 @@ import { Subscription } from 'rxjs'; import { filter, tap } from 'rxjs/operators'; import { ParticipationWebsocketService } from 'app/overview/participation-websocket.service'; import { Participation } from 'app/entities/participation/participation.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { findLatestResult } from 'app/shared/util/utils'; import { faCheckCircle, faExclamationTriangle } from '@fortawesome/free-solid-svg-icons'; import { hasSolutionParticipationChanged, hasTemplateParticipationChanged } from 'app/exercises/shared/participation/participation.utils'; diff --git a/src/main/webapp/app/exercises/programming/manage/status/programming-exercise-instructor-status.component.ts b/src/main/webapp/app/exercises/programming/manage/status/programming-exercise-instructor-status.component.ts index 66638d6d712f..9ad6970303a1 100644 --- a/src/main/webapp/app/exercises/programming/manage/status/programming-exercise-instructor-status.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/status/programming-exercise-instructor-status.component.ts @@ -4,8 +4,8 @@ import { filter } from 'rxjs/operators'; import { ParticipationWebsocketService } from 'app/overview/participation-websocket.service'; import { Result } from 'app/entities/result.model'; import { Participation } from 'app/entities/participation/participation.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; -import { ProgrammingExerciseParticipationType } from 'app/entities/programming-exercise-participation.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; +import { ProgrammingExerciseParticipationType } from 'app/entities/programming/programming-exercise-participation.model'; import { findLatestResult } from 'app/shared/util/utils'; import { SolutionProgrammingExerciseParticipation } from 'app/entities/participation/solution-programming-exercise-participation.model'; import { TemplateProgrammingExerciseParticipation } from 'app/entities/participation/template-programming-exercise-participation.model'; diff --git a/src/main/webapp/app/exercises/programming/manage/update/add-auxiliary-repository-button.component.ts b/src/main/webapp/app/exercises/programming/manage/update/add-auxiliary-repository-button.component.ts index 2b9ece99aff9..06d5d6940c83 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/add-auxiliary-repository-button.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/update/add-auxiliary-repository-button.component.ts @@ -1,7 +1,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; import { ButtonSize, ButtonType } from 'app/shared/components/button.component'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; -import { AuxiliaryRepository } from 'app/entities/programming-exercise-auxiliary-repository-model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; +import { AuxiliaryRepository } from 'app/entities/programming/programming-exercise-auxiliary-repository-model'; import { faPlus } from '@fortawesome/free-solid-svg-icons'; @Component({ diff --git a/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-creation-config.ts b/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-creation-config.ts index 8ab3314ac388..36c9b8df3a8c 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-creation-config.ts +++ b/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-creation-config.ts @@ -1,8 +1,8 @@ -import { AuxiliaryRepository } from 'app/entities/programming-exercise-auxiliary-repository-model'; +import { AuxiliaryRepository } from 'app/entities/programming/programming-exercise-auxiliary-repository-model'; import { ExerciseCategory } from 'app/entities/exercise-category.model'; import { ModePickerOption } from 'app/exercises/shared/mode-picker/mode-picker.component'; import { Observable } from 'rxjs'; -import { ProgrammingLanguage, ProjectType } from 'app/entities/programming-exercise.model'; +import { ProgrammingLanguage, ProjectType } from 'app/entities/programming/programming-exercise.model'; export type ProgrammingExerciseCreationConfig = { titleNamePattern: string; diff --git a/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-update.component.ts b/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-update.component.ts index 5fe22b0b6ff9..e1257c9c467f 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-update.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/update/programming-exercise-update.component.ts @@ -2,9 +2,10 @@ import { ActivatedRoute, Params } from '@angular/router'; import { AfterViewInit, Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; import { AlertService, AlertType } from 'app/core/util/alert.service'; +import { ProgrammingExerciseBuildConfig } from 'app/entities/programming/programming-exercise-build.config'; import { Observable, Subject, Subscription } from 'rxjs'; import { CourseManagementService } from 'app/course/manage/course-management.service'; -import { ProgrammingExercise, ProgrammingExerciseBuildConfig, ProgrammingLanguage, ProjectType, resetProgrammingForImport } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise, ProgrammingLanguage, ProjectType, resetProgrammingForImport } from 'app/entities/programming/programming-exercise.model'; import { ProgrammingExerciseService } from '../services/programming-exercise.service'; import { FileService } from 'app/shared/http/file.service'; import { TranslateService } from '@ngx-translate/core'; @@ -22,7 +23,7 @@ import { ExerciseCategory } from 'app/entities/exercise-category.model'; import { cloneDeep } from 'lodash-es'; import { ExerciseUpdateWarningService } from 'app/exercises/shared/exercise-update-warning/exercise-update-warning.service'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { AuxiliaryRepository } from 'app/entities/programming-exercise-auxiliary-repository-model'; +import { AuxiliaryRepository } from 'app/entities/programming/programming-exercise-auxiliary-repository-model'; import { SubmissionPolicyType } from 'app/entities/submission-policy.model'; import { faExclamationCircle, faQuestionCircle } from '@fortawesome/free-solid-svg-icons'; import { ModePickerOption } from 'app/exercises/shared/mode-picker/mode-picker.component'; diff --git a/src/main/webapp/app/exercises/programming/manage/update/remove-auxiliary-repository-button.component.ts b/src/main/webapp/app/exercises/programming/manage/update/remove-auxiliary-repository-button.component.ts index dcd21a30e18c..2ce643767155 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/remove-auxiliary-repository-button.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/update/remove-auxiliary-repository-button.component.ts @@ -1,7 +1,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; import { ButtonSize, ButtonType } from 'app/shared/components/button.component'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; -import { AuxiliaryRepository } from 'app/entities/programming-exercise-auxiliary-repository-model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; +import { AuxiliaryRepository } from 'app/entities/programming/programming-exercise-auxiliary-repository-model'; import { faTrash } from '@fortawesome/free-solid-svg-icons'; @Component({ diff --git a/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-aeolus-build-plan.component.ts b/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-aeolus-build-plan.component.ts index 4f51ccd37432..e350d8c201b9 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-aeolus-build-plan.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-aeolus-build-plan.component.ts @@ -1,5 +1,6 @@ import { Component, Input, OnChanges, SimpleChanges, ViewChild } from '@angular/core'; -import { BuildAction, ProgrammingExercise, ProgrammingLanguage, ProjectType, ScriptAction } from 'app/entities/programming-exercise.model'; +import { BuildAction, ScriptAction } from 'app/entities/programming/build.action'; +import { ProgrammingExercise, ProgrammingLanguage, ProjectType } from 'app/entities/programming/programming-exercise.model'; import { faQuestionCircle } from '@fortawesome/free-solid-svg-icons'; import { ProgrammingExerciseCreationConfig } from 'app/exercises/programming/manage/update/programming-exercise-creation-config'; import { AeolusService } from 'app/exercises/programming/shared/service/aeolus.service'; diff --git a/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-build-plan.component.ts b/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-build-plan.component.ts index 1a314af06cfd..437c22fc0f40 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-build-plan.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-build-plan.component.ts @@ -1,5 +1,5 @@ import { Component, Input, OnChanges, SimpleChanges, ViewChild } from '@angular/core'; -import { ProgrammingExercise, ProgrammingLanguage, ProjectType } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise, ProgrammingLanguage, ProjectType } from 'app/entities/programming/programming-exercise.model'; import { faQuestionCircle } from '@fortawesome/free-solid-svg-icons'; import { ProgrammingExerciseCreationConfig } from 'app/exercises/programming/manage/update/programming-exercise-creation-config'; import { AeolusService } from 'app/exercises/programming/shared/service/aeolus.service'; diff --git a/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-difficulty.component.ts b/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-difficulty.component.ts index 5c3f1eb64302..9b90e235dcec 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-difficulty.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-difficulty.component.ts @@ -1,5 +1,5 @@ import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; -import { ProgrammingExercise, ProjectType } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise, ProjectType } from 'app/entities/programming/programming-exercise.model'; import { faQuestionCircle } from '@fortawesome/free-solid-svg-icons'; import { ProgrammingExerciseCreationConfig } from 'app/exercises/programming/manage/update/programming-exercise-creation-config'; import { TeamConfigFormGroupComponent } from 'app/exercises/shared/team-config-form-group/team-config-form-group.component'; diff --git a/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-grading.component.ts b/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-grading.component.ts index b82813fa9f06..5a5c6a17c6d3 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-grading.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-grading.component.ts @@ -1,5 +1,5 @@ import { AfterViewInit, Component, Input, OnDestroy, ViewChild } from '@angular/core'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { AssessmentType } from 'app/entities/assessment-type.model'; import { SubmissionPolicyType } from 'app/entities/submission-policy.model'; import { TranslateService } from '@ngx-translate/core'; diff --git a/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-information.component.ts b/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-information.component.ts index b1bd35bca30a..f60b0948a4c6 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-information.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-information.component.ts @@ -1,6 +1,6 @@ import { AfterViewInit, Component, Input, OnDestroy, QueryList, ViewChild, ViewChildren } from '@angular/core'; import { NgModel } from '@angular/forms'; -import { ProgrammingExercise, ProjectType } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise, ProjectType } from 'app/entities/programming/programming-exercise.model'; import { ProgrammingExerciseCreationConfig } from 'app/exercises/programming/manage/update/programming-exercise-creation-config'; import { ExerciseTitleChannelNameComponent } from 'app/exercises/shared/exercise-title-channel-name/exercise-title-channel-name.component'; import { Subject, Subscription } from 'rxjs'; diff --git a/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-language.component.ts b/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-language.component.ts index 5bcf49abc770..696d75ce185f 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-language.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-language.component.ts @@ -1,5 +1,5 @@ import { AfterViewChecked, AfterViewInit, Component, EventEmitter, Input, OnDestroy, ViewChild } from '@angular/core'; -import { ProgrammingExercise, ProgrammingLanguage, ProjectType } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise, ProgrammingLanguage, ProjectType } from 'app/entities/programming/programming-exercise.model'; import { faQuestionCircle } from '@fortawesome/free-solid-svg-icons'; import { ProgrammingExerciseCreationConfig } from 'app/exercises/programming/manage/update/programming-exercise-creation-config'; import { PROFILE_AEOLUS, PROFILE_LOCALCI } from 'app/app.constants'; diff --git a/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-problem.component.ts b/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-problem.component.ts index 74eba35715a5..803b06558f72 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-problem.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/update/update-components/programming-exercise-problem.component.ts @@ -1,5 +1,5 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { ProgrammingExercise, ProgrammingLanguage, ProjectType } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise, ProgrammingLanguage, ProjectType } from 'app/entities/programming/programming-exercise.model'; import { AssessmentType } from 'app/entities/assessment-type.model'; import { faQuestionCircle } from '@fortawesome/free-solid-svg-icons'; import { ProgrammingExerciseCreationConfig } from 'app/exercises/programming/manage/update/programming-exercise-creation-config'; diff --git a/src/main/webapp/app/exercises/programming/manage/update/update-components/theia/programming-exercise-theia.component.ts b/src/main/webapp/app/exercises/programming/manage/update/update-components/theia/programming-exercise-theia.component.ts index 98849723625d..b516009846ed 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/update-components/theia/programming-exercise-theia.component.ts +++ b/src/main/webapp/app/exercises/programming/manage/update/update-components/theia/programming-exercise-theia.component.ts @@ -1,5 +1,5 @@ import { Component, Input, OnChanges, SimpleChanges } from '@angular/core'; -import { ProgrammingExercise, ProgrammingLanguage } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise, ProgrammingLanguage } from 'app/entities/programming/programming-exercise.model'; import { ProgrammingExerciseCreationConfig } from 'app/exercises/programming/manage/update/programming-exercise-creation-config'; import { TheiaService } from 'app/exercises/programming/shared/service/theia.service'; import { ArtemisSharedLibsModule } from 'app/shared/shared-libs.module'; diff --git a/src/main/webapp/app/exercises/programming/participate/code-editor-student-container.component.ts b/src/main/webapp/app/exercises/programming/participate/code-editor-student-container.component.ts index 826902c2058a..34aa3e0b0d5a 100644 --- a/src/main/webapp/app/exercises/programming/participate/code-editor-student-container.component.ts +++ b/src/main/webapp/app/exercises/programming/participate/code-editor-student-container.component.ts @@ -10,7 +10,7 @@ import { DomainService } from 'app/exercises/programming/shared/code-editor/serv import { ExerciseType, IncludedInOverallScore, getCourseFromExercise } from 'app/entities/exercise.model'; import { Result } from 'app/entities/result.model'; import { Feedback, FeedbackType, checkSubsequentFeedbackInAssessment } from 'app/entities/feedback.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { DomainType } from 'app/exercises/programming/shared/code-editor/model/code-editor.model'; import { ActivatedRoute } from '@angular/router'; import { CodeEditorContainerComponent } from 'app/exercises/programming/shared/code-editor/container/code-editor-container.component'; diff --git a/src/main/webapp/app/exercises/programming/participate/programming-submission-policy-status.ts b/src/main/webapp/app/exercises/programming/participate/programming-submission-policy-status.ts index e6162da1afd9..826437a4ce28 100644 --- a/src/main/webapp/app/exercises/programming/participate/programming-submission-policy-status.ts +++ b/src/main/webapp/app/exercises/programming/participate/programming-submission-policy-status.ts @@ -1,5 +1,5 @@ import { Component, Input } from '@angular/core'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { SubmissionPolicyType } from 'app/entities/submission-policy.model'; @Component({ diff --git a/src/main/webapp/app/exercises/programming/participate/programming-submission.service.ts b/src/main/webapp/app/exercises/programming/participate/programming-submission.service.ts index c13539943903..0fd3d43a0535 100644 --- a/src/main/webapp/app/exercises/programming/participate/programming-submission.service.ts +++ b/src/main/webapp/app/exercises/programming/participate/programming-submission.service.ts @@ -7,7 +7,7 @@ import { Result } from 'app/entities/result.model'; import { createRequestOption } from 'app/shared/util/request.util'; import { JhiWebsocketService } from 'app/core/websocket/websocket.service'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { SubmissionType, getLatestSubmissionResult, setLatestSubmissionResult } from 'app/entities/submission.model'; import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model'; import { findLatestResult } from 'app/shared/util/utils'; diff --git a/src/main/webapp/app/exercises/programming/shared/actions/programming-exercise-instructor-submission-state.component.ts b/src/main/webapp/app/exercises/programming/shared/actions/programming-exercise-instructor-submission-state.component.ts index afa3062da5b8..60081cc274f3 100644 --- a/src/main/webapp/app/exercises/programming/shared/actions/programming-exercise-instructor-submission-state.component.ts +++ b/src/main/webapp/app/exercises/programming/shared/actions/programming-exercise-instructor-submission-state.component.ts @@ -3,7 +3,7 @@ import { debounceTime, map, tap } from 'rxjs/operators'; import { ExerciseSubmissionState, ProgrammingSubmissionService, ProgrammingSubmissionState } from 'app/exercises/programming/participate/programming-submission.service'; import { Subscription } from 'rxjs'; import { FeatureToggle } from 'app/shared/feature-toggle/feature-toggle.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { hasExerciseChanged } from 'app/exercises/shared/exercise/exercise.utils'; import { ButtonType } from 'app/shared/components/button.component'; import { faCircleNotch, faClock, faRedo } from '@fortawesome/free-solid-svg-icons'; diff --git a/src/main/webapp/app/exercises/programming/shared/actions/programming-exercise-re-evaluate-button.component.ts b/src/main/webapp/app/exercises/programming/shared/actions/programming-exercise-re-evaluate-button.component.ts index 06c2447d5248..2d1710b1b692 100644 --- a/src/main/webapp/app/exercises/programming/shared/actions/programming-exercise-re-evaluate-button.component.ts +++ b/src/main/webapp/app/exercises/programming/shared/actions/programming-exercise-re-evaluate-button.component.ts @@ -3,7 +3,7 @@ import { HttpErrorResponse } from '@angular/common/http'; import { AlertService } from 'app/core/util/alert.service'; import { ProgrammingExerciseGradingService } from 'app/exercises/programming/manage/services/programming-exercise-grading.service'; import { FeatureToggle } from 'app/shared/feature-toggle/feature-toggle.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ButtonType } from 'app/shared/components/button.component'; import { faRedo } from '@fortawesome/free-solid-svg-icons'; diff --git a/src/main/webapp/app/exercises/programming/shared/actions/programming-exercise-trigger-all-button.component.ts b/src/main/webapp/app/exercises/programming/shared/actions/programming-exercise-trigger-all-button.component.ts index 3dc928117229..28454d8c0e72 100644 --- a/src/main/webapp/app/exercises/programming/shared/actions/programming-exercise-trigger-all-button.component.ts +++ b/src/main/webapp/app/exercises/programming/shared/actions/programming-exercise-trigger-all-button.component.ts @@ -6,7 +6,7 @@ import { NgbActiveModal, NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { hasDueDatePassed } from 'app/exercises/programming/shared/utils/programming-exercise.utils'; import { BuildRunState, ProgrammingBuildRunService } from 'app/exercises/programming/participate/programming-build-run.service'; import { FeatureToggle } from 'app/shared/feature-toggle/feature-toggle.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ButtonType } from 'app/shared/components/button.component'; import { faBan, faRedo, faTimes } from '@fortawesome/free-solid-svg-icons'; diff --git a/src/main/webapp/app/exercises/programming/shared/actions/programming-exercise-trigger-build-button.component.ts b/src/main/webapp/app/exercises/programming/shared/actions/programming-exercise-trigger-build-button.component.ts index 5efd0b6ea087..52089b28c991 100644 --- a/src/main/webapp/app/exercises/programming/shared/actions/programming-exercise-trigger-build-button.component.ts +++ b/src/main/webapp/app/exercises/programming/shared/actions/programming-exercise-trigger-build-button.component.ts @@ -10,7 +10,7 @@ import { hasDueDatePassed } from 'app/exercises/programming/shared/utils/program import { Result } from 'app/entities/result.model'; import { FeatureToggle } from 'app/shared/feature-toggle/feature-toggle.service'; import { SubmissionType } from 'app/entities/submission.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { AlertService } from 'app/core/util/alert.service'; import { hasParticipationChanged } from 'app/exercises/shared/participation/participation.utils'; diff --git a/src/main/webapp/app/exercises/programming/shared/build-details/programming-exercise-build-plan-checkout-directories.component.ts b/src/main/webapp/app/exercises/programming/shared/build-details/programming-exercise-build-plan-checkout-directories.component.ts index 4bcffecaa5af..d1932dc53ff3 100644 --- a/src/main/webapp/app/exercises/programming/shared/build-details/programming-exercise-build-plan-checkout-directories.component.ts +++ b/src/main/webapp/app/exercises/programming/shared/build-details/programming-exercise-build-plan-checkout-directories.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; -import { BuildPlanCheckoutDirectoriesDTO } from 'app/entities/build-plan-checkout-directories-dto'; -import { AuxiliaryRepository } from 'app/entities/programming-exercise-auxiliary-repository-model'; +import { BuildPlanCheckoutDirectoriesDTO } from 'app/entities/programming/build-plan-checkout-directories-dto'; +import { AuxiliaryRepository } from 'app/entities/programming/programming-exercise-auxiliary-repository-model'; @Component({ selector: 'jhi-programming-exercise-build-plan-checkout-directories', diff --git a/src/main/webapp/app/exercises/programming/shared/build-details/programming-exercise-repository-and-build-plan-details.component.ts b/src/main/webapp/app/exercises/programming/shared/build-details/programming-exercise-repository-and-build-plan-details.component.ts index 30021b146f48..f44d22e06ff7 100644 --- a/src/main/webapp/app/exercises/programming/shared/build-details/programming-exercise-repository-and-build-plan-details.component.ts +++ b/src/main/webapp/app/exercises/programming/shared/build-details/programming-exercise-repository-and-build-plan-details.component.ts @@ -1,9 +1,9 @@ import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core'; import { getCourseFromExercise } from 'app/entities/exercise.model'; -import type { ProgrammingExercise, ProgrammingLanguage } from 'app/entities/programming-exercise.model'; +import type { ProgrammingExercise, ProgrammingLanguage } from 'app/entities/programming/programming-exercise.model'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; import { Subscription } from 'rxjs'; -import type { CheckoutDirectoriesDto } from 'app/entities/checkout-directories-dto'; +import type { CheckoutDirectoriesDto } from 'app/entities/programming/checkout-directories-dto'; import { ArtemisSharedComponentModule } from 'app/shared/components/shared-component.module'; import { ArtemisSharedCommonModule } from 'app/shared/shared-common.module'; import { ProgrammingExerciseBuildPlanCheckoutDirectoriesComponent } from 'app/exercises/programming/shared/build-details/programming-exercise-build-plan-checkout-directories.component'; diff --git a/src/main/webapp/app/exercises/programming/shared/code-editor/build-output/code-editor-build-output.component.ts b/src/main/webapp/app/exercises/programming/shared/code-editor/build-output/code-editor-build-output.component.ts index d4506dbc256b..1c7535cbc9d6 100644 --- a/src/main/webapp/app/exercises/programming/shared/code-editor/build-output/code-editor-build-output.component.ts +++ b/src/main/webapp/app/exercises/programming/shared/code-editor/build-output/code-editor-build-output.component.ts @@ -2,7 +2,7 @@ import { ParticipationWebsocketService } from 'app/overview/participation-websoc import { AfterViewInit, Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges } from '@angular/core'; import { Observable, Subscription, of } from 'rxjs'; import { catchError, filter, map, switchMap, tap } from 'rxjs/operators'; -import { BuildLogEntry, BuildLogEntryArray } from 'app/entities/build-log.model'; +import { BuildLogEntry, BuildLogEntryArray } from 'app/entities/programming/build-log.model'; import { Participation, getExercise } from 'app/entities/participation/participation.model'; import { CodeEditorSubmissionService } from 'app/exercises/programming/shared/code-editor/service/code-editor-submission.service'; import { CodeEditorBuildLogService } from 'app/exercises/programming/shared/code-editor/service/code-editor-repository.service'; @@ -11,10 +11,10 @@ import { ResultService } from 'app/exercises/shared/result/result.service'; import { Result } from 'app/entities/result.model'; import { Interactable } from '@interactjs/core/Interactable'; import interact from 'interactjs'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { findLatestResult } from 'app/shared/util/utils'; -import { StaticCodeAnalysisIssue } from 'app/entities/static-code-analysis-issue.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { StaticCodeAnalysisIssue } from 'app/entities/programming/static-code-analysis-issue.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { faChevronDown, faCircleNotch, faTerminal } from '@fortawesome/free-solid-svg-icons'; import { hasParticipationChanged } from 'app/exercises/shared/participation/participation.utils'; import { AssessmentType } from 'app/entities/assessment-type.model'; diff --git a/src/main/webapp/app/exercises/programming/shared/code-editor/model/code-editor.model.ts b/src/main/webapp/app/exercises/programming/shared/code-editor/model/code-editor.model.ts index 15e715b290ef..a3215aa04c48 100644 --- a/src/main/webapp/app/exercises/programming/shared/code-editor/model/code-editor.model.ts +++ b/src/main/webapp/app/exercises/programming/shared/code-editor/model/code-editor.model.ts @@ -1,7 +1,7 @@ import { StudentParticipation } from 'app/entities/participation/student-participation.model'; import { TemplateProgrammingExerciseParticipation } from 'app/entities/participation/template-programming-exercise-participation.model'; import { SolutionProgrammingExerciseParticipation } from 'app/entities/participation/solution-programming-exercise-participation.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; /** * Enumeration defining type of the exported file. diff --git a/src/main/webapp/app/exercises/programming/shared/commits-info/commits-info-group/commits-info-group.component.ts b/src/main/webapp/app/exercises/programming/shared/commits-info/commits-info-group/commits-info-group.component.ts index 4700569d8c97..64ed91bab723 100644 --- a/src/main/webapp/app/exercises/programming/shared/commits-info/commits-info-group/commits-info-group.component.ts +++ b/src/main/webapp/app/exercises/programming/shared/commits-info/commits-info-group/commits-info-group.component.ts @@ -1,5 +1,5 @@ import { Component, Input } from '@angular/core'; -import type { CommitInfo } from 'app/entities/programming-submission.model'; +import type { CommitInfo } from 'app/entities/programming/programming-submission.model'; @Component({ selector: 'jhi-commits-info-group', diff --git a/src/main/webapp/app/exercises/programming/shared/commits-info/commits-info-group/commits-info-row/commits-info-row.component.ts b/src/main/webapp/app/exercises/programming/shared/commits-info/commits-info-group/commits-info-row/commits-info-row.component.ts index 51edbcc7652c..a944e452e1b4 100644 --- a/src/main/webapp/app/exercises/programming/shared/commits-info/commits-info-group/commits-info-row/commits-info-row.component.ts +++ b/src/main/webapp/app/exercises/programming/shared/commits-info/commits-info-group/commits-info-row/commits-info-row.component.ts @@ -1,5 +1,5 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; -import type { CommitInfo } from 'app/entities/programming-submission.model'; +import type { CommitInfo } from 'app/entities/programming/programming-submission.model'; import { faCircle } from '@fortawesome/free-regular-svg-icons'; import { faAngleDown, faAngleLeft } from '@fortawesome/free-solid-svg-icons'; diff --git a/src/main/webapp/app/exercises/programming/shared/commits-info/commits-info.component.ts b/src/main/webapp/app/exercises/programming/shared/commits-info/commits-info.component.ts index d3728a48dc46..28a46506caab 100644 --- a/src/main/webapp/app/exercises/programming/shared/commits-info/commits-info.component.ts +++ b/src/main/webapp/app/exercises/programming/shared/commits-info/commits-info.component.ts @@ -1,5 +1,5 @@ import { Component, Input, OnDestroy, OnInit } from '@angular/core'; -import { CommitInfo, ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { CommitInfo, ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { ProgrammingExerciseParticipationService } from 'app/exercises/programming/manage/services/programming-exercise-participation.service'; import dayjs from 'dayjs/esm'; import { createCommitUrl } from 'app/exercises/programming/shared/utils/programming-exercise.utils'; diff --git a/src/main/webapp/app/exercises/programming/shared/instructions-render/extensions/programming-exercise-plant-uml.extension.ts b/src/main/webapp/app/exercises/programming/shared/instructions-render/extensions/programming-exercise-plant-uml.extension.ts index 6b7a28165b4a..2c0d4036369b 100644 --- a/src/main/webapp/app/exercises/programming/shared/instructions-render/extensions/programming-exercise-plant-uml.extension.ts +++ b/src/main/webapp/app/exercises/programming/shared/instructions-render/extensions/programming-exercise-plant-uml.extension.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { ProgrammingExerciseTestCase } from 'app/entities/programming-exercise-test-case.model'; +import { ProgrammingExerciseTestCase } from 'app/entities/programming/programming-exercise-test-case.model'; import { Subject } from 'rxjs'; import { tap } from 'rxjs/operators'; import { escapeStringForUseInRegex } from 'app/shared/util/global.utils'; diff --git a/src/main/webapp/app/exercises/programming/shared/instructions-render/programming-exercise-instruction.component.ts b/src/main/webapp/app/exercises/programming/shared/instructions-render/programming-exercise-instruction.component.ts index 75e060446c19..f1f669c7fb5c 100644 --- a/src/main/webapp/app/exercises/programming/shared/instructions-render/programming-exercise-instruction.component.ts +++ b/src/main/webapp/app/exercises/programming/shared/instructions-render/programming-exercise-instruction.component.ts @@ -14,12 +14,12 @@ import { } from '@angular/core'; import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; import { ThemeService } from 'app/core/theme/theme.service'; -import { ProgrammingExerciseTestCase } from 'app/entities/programming-exercise-test-case.model'; +import { ProgrammingExerciseTestCase } from 'app/entities/programming/programming-exercise-test-case.model'; import { ProgrammingExerciseGradingService } from 'app/exercises/programming/manage/services/programming-exercise-grading.service'; import { ShowdownExtension } from 'showdown'; import { catchError, filter, map, mergeMap, switchMap, tap } from 'rxjs/operators'; import { Observable, Subscription, merge, of } from 'rxjs'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ParticipationWebsocketService } from 'app/overview/participation-websocket.service'; import { ProgrammingExerciseTaskExtensionWrapper, taskRegex } from './extensions/programming-exercise-task.extension'; import { ProgrammingExercisePlantUmlExtensionWrapper } from 'app/exercises/programming/shared/instructions-render/extensions/programming-exercise-plant-uml.extension'; diff --git a/src/main/webapp/app/exercises/programming/shared/instructions-render/service/programming-exercise-instruction.service.ts b/src/main/webapp/app/exercises/programming/shared/instructions-render/service/programming-exercise-instruction.service.ts index 3234cae415ee..73cd7de06eba 100644 --- a/src/main/webapp/app/exercises/programming/shared/instructions-render/service/programming-exercise-instruction.service.ts +++ b/src/main/webapp/app/exercises/programming/shared/instructions-render/service/programming-exercise-instruction.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { ProgrammingExerciseTestCase } from 'app/entities/programming-exercise-test-case.model'; +import { ProgrammingExerciseTestCase } from 'app/entities/programming/programming-exercise-test-case.model'; import { Result } from 'app/entities/result.model'; /** diff --git a/src/main/webapp/app/exercises/programming/shared/lifecycle/programming-exercise-lifecycle.component.ts b/src/main/webapp/app/exercises/programming/shared/lifecycle/programming-exercise-lifecycle.component.ts index 9185f229d2ff..aa2e0e951699 100644 --- a/src/main/webapp/app/exercises/programming/shared/lifecycle/programming-exercise-lifecycle.component.ts +++ b/src/main/webapp/app/exercises/programming/shared/lifecycle/programming-exercise-lifecycle.component.ts @@ -2,7 +2,7 @@ import { AfterViewInit, Component, Input, OnChanges, OnDestroy, OnInit, QueryLis import dayjs from 'dayjs/esm'; import { TranslateService } from '@ngx-translate/core'; import { AssessmentType } from 'app/entities/assessment-type.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { faCogs, faUserCheck, faUserSlash } from '@fortawesome/free-solid-svg-icons'; import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; import { IncludedInOverallScore } from 'app/entities/exercise.model'; diff --git a/src/main/webapp/app/exercises/programming/shared/service/aeolus.service.ts b/src/main/webapp/app/exercises/programming/shared/service/aeolus.service.ts index e13138c55c04..1b468776d570 100644 --- a/src/main/webapp/app/exercises/programming/shared/service/aeolus.service.ts +++ b/src/main/webapp/app/exercises/programming/shared/service/aeolus.service.ts @@ -1,8 +1,10 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; +import { BuildAction, PlatformAction, ScriptAction } from 'app/entities/programming/build.action'; +import { WindFile } from 'app/entities/programming/wind.file'; import { Observable } from 'rxjs'; -import { BuildAction, PlatformAction, ProgrammingLanguage, ProjectType, ScriptAction, WindFile } from 'app/entities/programming-exercise.model'; +import { ProgrammingLanguage, ProjectType } from 'app/entities/programming/programming-exercise.model'; @Injectable({ providedIn: 'root' }) export class AeolusService { diff --git a/src/main/webapp/app/exercises/programming/shared/service/build-log.service.ts b/src/main/webapp/app/exercises/programming/shared/service/build-log.service.ts index 029e09af8e16..3f749357f188 100644 --- a/src/main/webapp/app/exercises/programming/shared/service/build-log.service.ts +++ b/src/main/webapp/app/exercises/programming/shared/service/build-log.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { HttpClient, HttpParams } from '@angular/common/http'; -import { BuildLogEntry } from 'app/entities/build-log.model'; +import { BuildLogEntry } from 'app/entities/programming/build-log.model'; export interface IBuildLogService { getBuildLogs: (participationId: number, resultId?: number) => Observable; diff --git a/src/main/webapp/app/exercises/programming/shared/service/programming-language-feature/programming-language-feature.service.ts b/src/main/webapp/app/exercises/programming/shared/service/programming-language-feature/programming-language-feature.service.ts index 3c7d1c9eaccd..7f2e95b0f73a 100644 --- a/src/main/webapp/app/exercises/programming/shared/service/programming-language-feature/programming-language-feature.service.ts +++ b/src/main/webapp/app/exercises/programming/shared/service/programming-language-feature/programming-language-feature.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { ProgrammingLanguage, ProjectType } from 'app/entities/programming-exercise.model'; +import { ProgrammingLanguage, ProjectType } from 'app/entities/programming/programming-exercise.model'; import { ProfileService } from 'app/shared/layouts/profiles/profile.service'; /** diff --git a/src/main/webapp/app/exercises/programming/shared/service/theia.service.ts b/src/main/webapp/app/exercises/programming/shared/service/theia.service.ts index d59673d738ac..3165730ddab7 100644 --- a/src/main/webapp/app/exercises/programming/shared/service/theia.service.ts +++ b/src/main/webapp/app/exercises/programming/shared/service/theia.service.ts @@ -2,7 +2,7 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; -import { ProgrammingLanguage } from 'app/entities/programming-exercise.model'; +import { ProgrammingLanguage } from 'app/entities/programming/programming-exercise.model'; @Injectable({ providedIn: 'root' }) export class TheiaService { diff --git a/src/main/webapp/app/exercises/programming/shared/utils/programming-exercise.utils.ts b/src/main/webapp/app/exercises/programming/shared/utils/programming-exercise.utils.ts index 3234ee6a1cf1..5e95bb66dbac 100644 --- a/src/main/webapp/app/exercises/programming/shared/utils/programming-exercise.utils.ts +++ b/src/main/webapp/app/exercises/programming/shared/utils/programming-exercise.utils.ts @@ -1,8 +1,8 @@ import { Result } from 'app/entities/result.model'; import dayjs from 'dayjs/esm'; import { Participation, ParticipationType } from 'app/entities/participation/participation.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { SubmissionType } from 'app/entities/submission.model'; import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model'; import { AssessmentType } from 'app/entities/assessment-type.model'; diff --git a/src/main/webapp/app/exercises/quiz/manage/quiz-exercise-update.component.ts b/src/main/webapp/app/exercises/quiz/manage/quiz-exercise-update.component.ts index a1cc56e466c1..b6fda2b6e1ee 100644 --- a/src/main/webapp/app/exercises/quiz/manage/quiz-exercise-update.component.ts +++ b/src/main/webapp/app/exercises/quiz/manage/quiz-exercise-update.component.ts @@ -19,7 +19,7 @@ import { Course } from 'app/entities/course.model'; import { ExerciseGroupService } from 'app/exam/manage/exercise-groups/exercise-group.service'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { cloneDeep } from 'lodash-es'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { DocumentationType } from 'app/shared/components/documentation-button/documentation-button.component'; import { ExerciseCategory } from 'app/entities/exercise-category.model'; diff --git a/src/main/webapp/app/exercises/quiz/manage/quiz-pool.component.ts b/src/main/webapp/app/exercises/quiz/manage/quiz-pool.component.ts index 7714b90a5841..ea04a7e2fe7f 100644 --- a/src/main/webapp/app/exercises/quiz/manage/quiz-pool.component.ts +++ b/src/main/webapp/app/exercises/quiz/manage/quiz-pool.component.ts @@ -15,7 +15,7 @@ import { QuizQuestionListEditComponent } from 'app/exercises/quiz/manage/quiz-qu import { onError } from 'app/shared/util/global.utils'; import { computeQuizQuestionInvalidReason, isQuizQuestionValid } from 'app/exercises/quiz/shared/quiz-manage-util.service'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import dayjs from 'dayjs/esm'; @Component({ diff --git a/src/main/webapp/app/exercises/quiz/manage/quiz-question-list-edit-existing.component.ts b/src/main/webapp/app/exercises/quiz/manage/quiz-question-list-edit-existing.component.ts index a361064be33f..7dc2df7ed5d3 100644 --- a/src/main/webapp/app/exercises/quiz/manage/quiz-question-list-edit-existing.component.ts +++ b/src/main/webapp/app/exercises/quiz/manage/quiz-question-list-edit-existing.component.ts @@ -9,7 +9,7 @@ import { Course } from 'app/entities/course.model'; import { CourseManagementService } from 'app/course/manage/course-management.service'; import { QuizExerciseService } from 'app/exercises/quiz/manage/quiz-exercise.service'; import { AlertService } from 'app/core/util/alert.service'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; diff --git a/src/main/webapp/app/exercises/shared/course-exercises/course-exercise.service.ts b/src/main/webapp/app/exercises/shared/course-exercises/course-exercise.service.ts index f9eefb8f5d7f..c9ea1e512eb3 100644 --- a/src/main/webapp/app/exercises/shared/course-exercises/course-exercise.service.ts +++ b/src/main/webapp/app/exercises/shared/course-exercises/course-exercise.service.ts @@ -1,9 +1,9 @@ import { ParticipationWebsocketService } from 'app/overview/participation-websocket.service'; import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; import { AccountService } from 'app/core/auth/account.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { FileUploadExercise } from 'app/entities/file-upload-exercise.model'; import { Exercise } from 'app/entities/exercise.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; diff --git a/src/main/webapp/app/exercises/shared/dashboards/tutor/exercise-assessment-dashboard.component.ts b/src/main/webapp/app/exercises/shared/dashboards/tutor/exercise-assessment-dashboard.component.ts index 62f371f95057..a5bffcbe5575 100644 --- a/src/main/webapp/app/exercises/shared/dashboards/tutor/exercise-assessment-dashboard.component.ts +++ b/src/main/webapp/app/exercises/shared/dashboards/tutor/exercise-assessment-dashboard.component.ts @@ -9,7 +9,7 @@ import { TutorParticipationService } from 'app/exercises/shared/dashboards/tutor import { TextSubmissionService } from 'app/exercises/text/participate/text-submission.service'; import { ExampleSubmission } from 'app/entities/example-submission.model'; import { ArtemisMarkdownService } from 'app/shared/markdown.service'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; import { UMLModel } from '@ls1intum/apollon'; import { ComplaintService } from 'app/complaints/complaint.service'; @@ -22,7 +22,7 @@ import { StatsForDashboard } from 'app/course/dashboards/stats-for-dashboard.mod import { TranslateService } from '@ngx-translate/core'; import { FileUploadSubmissionService } from 'app/exercises/file-upload/participate/file-upload-submission.service'; import { FileUploadExercise } from 'app/entities/file-upload-exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ProgrammingSubmissionService } from 'app/exercises/programming/participate/programming-submission.service'; import { AccountService } from 'app/core/auth/account.service'; import { GuidedTourService } from 'app/guided-tour/guided-tour.service'; @@ -31,8 +31,8 @@ import { Exercise, ExerciseType, getCourseFromExercise } from 'app/entities/exer import { TutorParticipation, TutorParticipationStatus } from 'app/entities/participation/tutor-participation.model'; import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; import { DueDateStat } from 'app/course/dashboards/due-date-stat.model'; -import { Exam } from 'app/entities/exam.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { Exam } from 'app/entities/exam/exam.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { SubmissionService, SubmissionWithComplaintDTO } from 'app/exercises/shared/submission/submission.service'; import { ArtemisDatePipe } from 'app/shared/pipes/artemis-date.pipe'; import { SortService } from 'app/shared/service/sort.service'; diff --git a/src/main/webapp/app/exercises/shared/dashboards/tutor/language-table-cell/language-table-cell.component.ts b/src/main/webapp/app/exercises/shared/dashboards/tutor/language-table-cell/language-table-cell.component.ts index 6ad8422696dc..96741ee28f37 100644 --- a/src/main/webapp/app/exercises/shared/dashboards/tutor/language-table-cell/language-table-cell.component.ts +++ b/src/main/webapp/app/exercises/shared/dashboards/tutor/language-table-cell/language-table-cell.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; import { Submission } from 'app/entities/submission.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; @Component({ selector: 'jhi-language-table-cell', diff --git a/src/main/webapp/app/exercises/shared/exam-exercise-row-buttons/exam-exercise-row-buttons.component.ts b/src/main/webapp/app/exercises/shared/exam-exercise-row-buttons/exam-exercise-row-buttons.component.ts index 79f1e755b358..49a62930183d 100644 --- a/src/main/webapp/app/exercises/shared/exam-exercise-row-buttons/exam-exercise-row-buttons.component.ts +++ b/src/main/webapp/app/exercises/shared/exam-exercise-row-buttons/exam-exercise-row-buttons.component.ts @@ -8,7 +8,7 @@ import { QuizExerciseService } from 'app/exercises/quiz/manage/quiz-exercise.ser import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; import { ModelingExerciseService } from 'app/exercises/modeling/manage/modeling-exercise.service'; import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import dayjs from 'dayjs/esm'; import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; import { EventManager } from 'app/core/util/event-manager.service'; diff --git a/src/main/webapp/app/exercises/shared/example-submission/example-submission.service.ts b/src/main/webapp/app/exercises/shared/example-submission/example-submission.service.ts index 08e1b3eccb6e..5fe845bfe309 100644 --- a/src/main/webapp/app/exercises/shared/example-submission/example-submission.service.ts +++ b/src/main/webapp/app/exercises/shared/example-submission/example-submission.service.ts @@ -6,7 +6,7 @@ import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service' import { map } from 'rxjs/operators'; import { Submission } from 'app/entities/submission.model'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { ModelingSubmission } from 'app/entities/modeling-submission.model'; import { StringCountService } from 'app/exercises/text/participate/string-count.service'; diff --git a/src/main/webapp/app/exercises/shared/exercise-headers/header-exercise-page-with-details.component.ts b/src/main/webapp/app/exercises/shared/exercise-headers/header-exercise-page-with-details.component.ts index 3d7af78e4a85..b89694846761 100644 --- a/src/main/webapp/app/exercises/shared/exercise-headers/header-exercise-page-with-details.component.ts +++ b/src/main/webapp/app/exercises/shared/exercise-headers/header-exercise-page-with-details.component.ts @@ -2,19 +2,19 @@ import { Component, Input, OnChanges, OnInit } from '@angular/core'; import { SortService } from 'app/shared/service/sort.service'; import dayjs from 'dayjs/esm'; import { Exercise, ExerciseType, IncludedInOverallScore, getCourseFromExercise, getIcon, getIconTooltip } from 'app/entities/exercise.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { ExerciseCategory } from 'app/entities/exercise-category.model'; import { SubmissionPolicy } from 'app/entities/submission-policy.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; import { getExerciseDueDate } from 'app/exercises/shared/exercise/exercise.utils'; import { faQuestionCircle } from '@fortawesome/free-solid-svg-icons'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { Course } from 'app/entities/course.model'; import { AssessmentType } from 'app/entities/assessment-type.model'; import { ComplaintService } from 'app/complaints/complaint.service'; import { SubmissionType } from 'app/entities/submission.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { roundValueSpecifiedByCourseSettings } from 'app/shared/util/utils'; @Component({ diff --git a/src/main/webapp/app/exercises/shared/exercise-hint/manage/exercise-hint-update.component.ts b/src/main/webapp/app/exercises/shared/exercise-hint/manage/exercise-hint-update.component.ts index b734c1c628df..c9d222f78ee3 100644 --- a/src/main/webapp/app/exercises/shared/exercise-hint/manage/exercise-hint-update.component.ts +++ b/src/main/webapp/app/exercises/shared/exercise-hint/manage/exercise-hint-update.component.ts @@ -9,7 +9,7 @@ import { faBan, faCircleNotch, faSave } from '@fortawesome/free-solid-svg-icons' import { ExerciseHint, HintType } from 'app/entities/hestia/exercise-hint.model'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; import { ProgrammingExerciseSolutionEntry } from 'app/entities/hestia/programming-exercise-solution-entry.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ProgrammingExerciseServerSideTask } from 'app/entities/hestia/programming-exercise-task.model'; import { ManualSolutionEntryCreationModalComponent } from 'app/exercises/programming/hestia/generation-overview/manual-solution-entry-creation-modal/manual-solution-entry-creation-modal.component'; import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; diff --git a/src/main/webapp/app/exercises/shared/exercise-hint/manage/exercise-hint.component.ts b/src/main/webapp/app/exercises/shared/exercise-hint/manage/exercise-hint.component.ts index 49829c3f3fef..3b542f17643b 100644 --- a/src/main/webapp/app/exercises/shared/exercise-hint/manage/exercise-hint.component.ts +++ b/src/main/webapp/app/exercises/shared/exercise-hint/manage/exercise-hint.component.ts @@ -11,7 +11,7 @@ import { EventManager } from 'app/core/util/event-manager.service'; import { faArrowsRotate, faCode, faEye, faFont, faPlus, faTimes, faWrench } from '@fortawesome/free-solid-svg-icons'; import { ExerciseHint, HintType } from 'app/entities/hestia/exercise-hint.model'; import { ExerciseType } from 'app/entities/exercise.model'; -import { ProgrammingExercise, ProgrammingLanguage } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise, ProgrammingLanguage } from 'app/entities/programming/programming-exercise.model'; @Component({ selector: 'jhi-exercise-hint', diff --git a/src/main/webapp/app/exercises/shared/exercise-scores/exercise-scores-export-button.component.ts b/src/main/webapp/app/exercises/shared/exercise-scores/exercise-scores-export-button.component.ts index 62720c9c897f..704737e2b4d0 100644 --- a/src/main/webapp/app/exercises/shared/exercise-scores/exercise-scores-export-button.component.ts +++ b/src/main/webapp/app/exercises/shared/exercise-scores/exercise-scores-export-button.component.ts @@ -6,12 +6,12 @@ import { Exercise, ExerciseType, getCourseFromExercise } from 'app/entities/exer import { Component, Input, OnInit } from '@angular/core'; import { ResultService } from 'app/exercises/shared/result/result.service'; import { getTestCaseNamesFromResults, getTestCaseResults } from 'app/exercises/shared/result/result.utils'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { GradingCriterion } from 'app/exercises/shared/structured-grading-criterion/grading-criterion.model'; import { ResultWithPointsPerGradingCriterion } from 'app/entities/result-with-points-per-grading-criterion.model'; import { faDownload } from '@fortawesome/free-solid-svg-icons'; import { download, generateCsv, mkConfig } from 'export-to-csv'; -import { TestCaseResult } from 'app/entities/test-case-result.model'; +import { TestCaseResult } from 'app/entities/programming/test-case-result.model'; @Component({ selector: 'jhi-exercise-scores-export-button', diff --git a/src/main/webapp/app/exercises/shared/exercise-scores/exercise-scores.component.ts b/src/main/webapp/app/exercises/shared/exercise-scores/exercise-scores.component.ts index 1b578e4ecbd4..b518bd05bb5a 100644 --- a/src/main/webapp/app/exercises/shared/exercise-scores/exercise-scores.component.ts +++ b/src/main/webapp/app/exercises/shared/exercise-scores/exercise-scores.component.ts @@ -14,11 +14,11 @@ import { ResultService } from 'app/exercises/shared/result/result.service'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; import { Result } from 'app/entities/result.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; import { AssessmentType } from 'app/entities/assessment-type.model'; import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { formatTeamAsSearchResult } from 'app/exercises/shared/team/team.utils'; import { faCodeBranch, faComment, faDownload, faFilter, faFolderOpen, faListAlt, faSync } from '@fortawesome/free-solid-svg-icons'; import { faFileCode } from '@fortawesome/free-regular-svg-icons'; diff --git a/src/main/webapp/app/exercises/shared/exercise/exercise.service.ts b/src/main/webapp/app/exercises/shared/exercise/exercise.service.ts index 50c2227751e3..a5c6b2febc1a 100644 --- a/src/main/webapp/app/exercises/shared/exercise/exercise.service.ts +++ b/src/main/webapp/app/exercises/shared/exercise/exercise.service.ts @@ -12,10 +12,10 @@ import { TranslateService } from '@ngx-translate/core'; import { ExerciseCategory } from 'app/entities/exercise-category.model'; import { convertDateFromClient, convertDateFromServer } from 'app/utils/date.utils'; import { EntityTitleService, EntityType } from 'app/shared/layouts/navbar/entity-title.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { InitializationState } from 'app/entities/participation/participation.model'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { FileUploadExercise } from 'app/entities/file-upload-exercise.model'; import { ArtemisMarkdownService } from 'app/shared/markdown.service'; import { SafeHtml } from '@angular/platform-browser'; diff --git a/src/main/webapp/app/exercises/shared/exercise/exercise.utils.ts b/src/main/webapp/app/exercises/shared/exercise/exercise.utils.ts index 655133c142c3..091f4af5364d 100644 --- a/src/main/webapp/app/exercises/shared/exercise/exercise.utils.ts +++ b/src/main/webapp/app/exercises/shared/exercise/exercise.utils.ts @@ -2,7 +2,7 @@ import { SimpleChanges } from '@angular/core'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; import dayjs from 'dayjs/esm'; import { InitializationState, Participation } from 'app/entities/participation/participation.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { AssessmentType } from 'app/entities/assessment-type.model'; import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; import { Observable, from, of } from 'rxjs'; diff --git a/src/main/webapp/app/exercises/shared/feedback/feedback.component.ts b/src/main/webapp/app/exercises/shared/feedback/feedback.component.ts index 8fe19b908551..576445b7831d 100644 --- a/src/main/webapp/app/exercises/shared/feedback/feedback.component.ts +++ b/src/main/webapp/app/exercises/shared/feedback/feedback.component.ts @@ -3,14 +3,14 @@ import { HttpErrorResponse } from '@angular/common/http'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { catchError, map, switchMap, tap } from 'rxjs/operators'; import { of, throwError } from 'rxjs'; -import { BuildLogEntry, BuildLogEntryArray, BuildLogType } from 'app/entities/build-log.model'; +import { BuildLogEntry, BuildLogEntryArray, BuildLogType } from 'app/entities/programming/build-log.model'; import { Feedback, checkSubsequentFeedbackInAssessment } from 'app/entities/feedback.model'; import { Badge, ResultService } from 'app/exercises/shared/result/result.service'; import { Exercise, ExerciseType, getCourseFromExercise } from 'app/entities/exercise.model'; import { Result } from 'app/entities/result.model'; import { BuildLogService } from 'app/exercises/programming/shared/service/build-log.service'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { TranslateService } from '@ngx-translate/core'; import { createCommitUrl, isProgrammingExerciseParticipation } from 'app/exercises/programming/shared/utils/programming-exercise.utils'; import { AssessmentType } from 'app/entities/assessment-type.model'; diff --git a/src/main/webapp/app/exercises/shared/feedback/group/programming-feedback-groups.ts b/src/main/webapp/app/exercises/shared/feedback/group/programming-feedback-groups.ts index 006f24f2fba0..8bdf9ecd30b4 100644 --- a/src/main/webapp/app/exercises/shared/feedback/group/programming-feedback-groups.ts +++ b/src/main/webapp/app/exercises/shared/feedback/group/programming-feedback-groups.ts @@ -1,7 +1,7 @@ import { FeedbackGroup } from 'app/exercises/shared/feedback/group/feedback-group'; import { FeedbackItem } from 'app/exercises/shared/feedback/item/feedback-item'; import { Exercise } from 'app/entities/exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; /** * Returns all FeedbackItemGroups for Programming exercises in the order, in which they will be displayed diff --git a/src/main/webapp/app/exercises/shared/feedback/item/programming-feedback-item.service.ts b/src/main/webapp/app/exercises/shared/feedback/item/programming-feedback-item.service.ts index 03b491da0195..8b231443aa32 100644 --- a/src/main/webapp/app/exercises/shared/feedback/item/programming-feedback-item.service.ts +++ b/src/main/webapp/app/exercises/shared/feedback/item/programming-feedback-item.service.ts @@ -11,7 +11,7 @@ import { SUBMISSION_POLICY_FEEDBACK_IDENTIFIER, } from 'app/entities/feedback.model'; import { TranslateService } from '@ngx-translate/core'; -import { StaticCodeAnalysisIssue } from 'app/entities/static-code-analysis-issue.model'; +import { StaticCodeAnalysisIssue } from 'app/entities/programming/static-code-analysis-issue.model'; import { getAllFeedbackGroups } from 'app/exercises/shared/feedback/group/programming-feedback-groups'; import { FeedbackItem } from 'app/exercises/shared/feedback/item/feedback-item'; import { Exercise } from 'app/entities/exercise.model'; diff --git a/src/main/webapp/app/exercises/shared/import/exercise-import-wrapper/exercise-import-wrapper.component.ts b/src/main/webapp/app/exercises/shared/import/exercise-import-wrapper/exercise-import-wrapper.component.ts index d0389d076607..23673a0cd2da 100644 --- a/src/main/webapp/app/exercises/shared/import/exercise-import-wrapper/exercise-import-wrapper.component.ts +++ b/src/main/webapp/app/exercises/shared/import/exercise-import-wrapper/exercise-import-wrapper.component.ts @@ -1,7 +1,7 @@ import { Component, Input, OnInit } from '@angular/core'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { ExerciseType } from 'app/entities/exercise.model'; -import { ProgrammingLanguage } from 'app/entities/programming-exercise.model'; +import { ProgrammingLanguage } from 'app/entities/programming/programming-exercise.model'; @Component({ selector: 'jhi-exercise-import-wrapper', diff --git a/src/main/webapp/app/exercises/shared/import/exercise-import.component.ts b/src/main/webapp/app/exercises/shared/import/exercise-import.component.ts index 85a408c2fdc1..1fea53eaacbd 100644 --- a/src/main/webapp/app/exercises/shared/import/exercise-import.component.ts +++ b/src/main/webapp/app/exercises/shared/import/exercise-import.component.ts @@ -2,7 +2,7 @@ import { Component, Injector, Input, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; -import { ProgrammingExercise, ProgrammingLanguage } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise, ProgrammingLanguage } from 'app/entities/programming/programming-exercise.model'; import { FileUploadExercisePagingService } from 'app/exercises/file-upload/manage/file-upload-exercise-paging.service'; import { ModelingExercisePagingService } from 'app/exercises/modeling/manage/modeling-exercise-paging.service'; import { CodeAnalysisPagingService } from 'app/exercises/programming/manage/services/code-analysis-paging.service'; diff --git a/src/main/webapp/app/exercises/shared/import/from-file/exercise-import-from-file.component.ts b/src/main/webapp/app/exercises/shared/import/from-file/exercise-import-from-file.component.ts index bc6621cf3e64..688b7cd6fb44 100644 --- a/src/main/webapp/app/exercises/shared/import/from-file/exercise-import-from-file.component.ts +++ b/src/main/webapp/app/exercises/shared/import/from-file/exercise-import-from-file.component.ts @@ -1,10 +1,11 @@ import { Component, Input, OnInit } from '@angular/core'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; +import { ProgrammingExerciseBuildConfig } from 'app/entities/programming/programming-exercise-build.config'; import { MAX_FILE_SIZE } from 'app/shared/constants/input.constants'; import { AlertService } from 'app/core/util/alert.service'; import { faUpload } from '@fortawesome/free-solid-svg-icons'; -import { ProgrammingExercise, ProgrammingExerciseBuildConfig, copyBuildConfigFromExerciseJson } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise, copyBuildConfigFromExerciseJson } from 'app/entities/programming/programming-exercise.model'; import JSZip from 'jszip'; @Component({ diff --git a/src/main/webapp/app/exercises/shared/manage/exercise-paging.service.ts b/src/main/webapp/app/exercises/shared/manage/exercise-paging.service.ts index 5d646d031991..1697967842ad 100644 --- a/src/main/webapp/app/exercises/shared/manage/exercise-paging.service.ts +++ b/src/main/webapp/app/exercises/shared/manage/exercise-paging.service.ts @@ -1,6 +1,6 @@ import { HttpClient, HttpResponse } from '@angular/common/http'; import { Exercise } from 'app/entities/exercise.model'; -import { ProgrammingLanguage } from 'app/entities/programming-exercise.model'; +import { ProgrammingLanguage } from 'app/entities/programming/programming-exercise.model'; import { PagingService } from 'app/exercises/shared/manage/paging.service'; import { SearchResult, SearchTermPageableSearch } from 'app/shared/table/pageable-table'; import { Observable, map } from 'rxjs'; diff --git a/src/main/webapp/app/exercises/shared/participation-submission/participation-submission.component.ts b/src/main/webapp/app/exercises/shared/participation-submission/participation-submission.component.ts index 57f529b33147..733059f76d8d 100644 --- a/src/main/webapp/app/exercises/shared/participation-submission/participation-submission.component.ts +++ b/src/main/webapp/app/exercises/shared/participation-submission/participation-submission.component.ts @@ -11,8 +11,8 @@ import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service' import { Exercise, ExerciseType } from 'app/entities/exercise.model'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; import dayjs from 'dayjs/esm'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { TranslateService } from '@ngx-translate/core'; import { ProfileService } from 'app/shared/layouts/profiles/profile.service'; import { ButtonSize } from 'app/shared/components/button.component'; diff --git a/src/main/webapp/app/exercises/shared/participation/participation.component.ts b/src/main/webapp/app/exercises/shared/participation/participation.component.ts index dfdb90b6d53e..627a33ce8815 100644 --- a/src/main/webapp/app/exercises/shared/participation/participation.component.ts +++ b/src/main/webapp/app/exercises/shared/participation/participation.component.ts @@ -17,7 +17,7 @@ import { ProgrammingExerciseStudentParticipation } from 'app/entities/participat import { AlertService } from 'app/core/util/alert.service'; import { EventManager } from 'app/core/util/event-manager.service'; import { ProfileService } from 'app/shared/layouts/profiles/profile.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { faCircleNotch, faCodeBranch, faEraser, faFilePowerpoint, faTable, faTimes, faTrash } from '@fortawesome/free-solid-svg-icons'; import { GradingSystemService } from 'app/grading-system/grading-system.service'; import { GradeStepsDTO } from 'app/entities/grade-step.model'; diff --git a/src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/text-submission-viewer/text-submission-viewer.component.ts b/src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/text-submission-viewer/text-submission-viewer.component.ts index dc76831f9517..ba3fd8301876 100644 --- a/src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/text-submission-viewer/text-submission-viewer.component.ts +++ b/src/main/webapp/app/exercises/shared/plagiarism/plagiarism-split-view/text-submission-viewer/text-submission-viewer.component.ts @@ -1,10 +1,10 @@ import { Component, Input, OnChanges, SimpleChanges, ViewEncapsulation } from '@angular/core'; import { TextSubmissionService } from 'app/exercises/text/participate/text-submission.service'; import { PlagiarismSubmission } from 'app/exercises/shared/plagiarism/types/PlagiarismSubmission'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { FromToElement, TextSubmissionElement } from 'app/exercises/shared/plagiarism/types/text/TextSubmissionElement'; -import { TextExercise } from 'app/entities/text-exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ExerciseType } from 'app/entities/exercise.model'; import { DomainChange, DomainType, FileType } from 'app/exercises/programming/shared/code-editor/model/code-editor.model'; import { CodeEditorRepositoryFileService } from 'app/exercises/programming/shared/code-editor/service/code-editor-repository.service'; diff --git a/src/main/webapp/app/exercises/shared/result/result.component.ts b/src/main/webapp/app/exercises/shared/result/result.component.ts index 9bad543faa64..b323a640b21e 100644 --- a/src/main/webapp/app/exercises/shared/result/result.component.ts +++ b/src/main/webapp/app/exercises/shared/result/result.component.ts @@ -3,11 +3,11 @@ import { ParticipationService } from 'app/exercises/shared/participation/partici import { MissingResultInformation, ResultTemplateStatus, evaluateTemplateStatus, getResultIconClass, getTextColorClass } from 'app/exercises/shared/result/result.utils'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { TranslateService } from '@ngx-translate/core'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import dayjs from 'dayjs/esm'; import { isProgrammingExerciseStudentParticipation, isResultPreliminary } from 'app/exercises/programming/shared/utils/programming-exercise.utils'; import { Participation, ParticipationType, getExercise } from 'app/entities/participation/participation.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { Submission, SubmissionExerciseType } from 'app/entities/submission.model'; import { Exercise, ExerciseType, getCourseFromExercise } from 'app/entities/exercise.model'; import { FeedbackComponent } from 'app/exercises/shared/feedback/feedback.component'; diff --git a/src/main/webapp/app/exercises/shared/result/result.service.ts b/src/main/webapp/app/exercises/shared/result/result.service.ts index 72390f6979c8..800fe1b4aecd 100644 --- a/src/main/webapp/app/exercises/shared/result/result.service.ts +++ b/src/main/webapp/app/exercises/shared/result/result.service.ts @@ -14,8 +14,8 @@ import { convertDateFromClient, convertDateFromServer } from 'app/utils/date.uti import { TranslateService } from '@ngx-translate/core'; import { roundValueSpecifiedByCourseSettings } from 'app/shared/util/utils'; import { isResultPreliminary } from 'app/exercises/programming/shared/utils/programming-exercise.utils'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { captureException } from '@sentry/angular'; import { Participation, ParticipationType } from 'app/entities/participation/participation.model'; import { SubmissionService } from 'app/exercises/shared/submission/submission.service'; diff --git a/src/main/webapp/app/exercises/shared/result/result.utils.ts b/src/main/webapp/app/exercises/shared/result/result.utils.ts index 9a997cd2be69..b8b43ed63c80 100644 --- a/src/main/webapp/app/exercises/shared/result/result.utils.ts +++ b/src/main/webapp/app/exercises/shared/result/result.utils.ts @@ -4,9 +4,9 @@ import { StudentParticipation } from 'app/entities/participation/student-partici import { Feedback, FeedbackType } from 'app/entities/feedback.model'; import { MIN_SCORE_GREEN, MIN_SCORE_ORANGE } from 'app/app.constants'; import { isProgrammingExerciseStudentParticipation, isResultPreliminary } from 'app/exercises/programming/shared/utils/programming-exercise.utils'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { Submission, SubmissionExerciseType } from 'app/entities/submission.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { AssessmentType } from 'app/entities/assessment-type.model'; import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { faCheckCircle, faQuestionCircle, faTimesCircle } from '@fortawesome/free-regular-svg-icons'; @@ -16,7 +16,7 @@ import { Exercise, ExerciseType } from 'app/entities/exercise.model'; import { Participation, ParticipationType } from 'app/entities/participation/participation.model'; import dayjs from 'dayjs/esm'; import { ResultWithPointsPerGradingCriterion } from 'app/entities/result-with-points-per-grading-criterion.model'; -import { TestCaseResult } from 'app/entities/test-case-result.model'; +import { TestCaseResult } from 'app/entities/programming/test-case-result.model'; /** * Enumeration object representing the possible options that diff --git a/src/main/webapp/app/exercises/shared/result/updating-result.component.ts b/src/main/webapp/app/exercises/shared/result/updating-result.component.ts index 375582cb5132..55cde780b0ec 100644 --- a/src/main/webapp/app/exercises/shared/result/updating-result.component.ts +++ b/src/main/webapp/app/exercises/shared/result/updating-result.component.ts @@ -6,7 +6,7 @@ import { RepositoryService } from 'app/exercises/shared/result/repository.servic import dayjs from 'dayjs/esm'; import { ProgrammingSubmissionService, ProgrammingSubmissionState } from 'app/exercises/programming/participate/programming-submission.service'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ResultService } from 'app/exercises/shared/result/result.service'; import { Submission, SubmissionType } from 'app/entities/submission.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; diff --git a/src/main/webapp/app/exercises/shared/submission-policy/submission-policy-update.component.ts b/src/main/webapp/app/exercises/shared/submission-policy/submission-policy-update.component.ts index 58220c431757..08961c9407d6 100644 --- a/src/main/webapp/app/exercises/shared/submission-policy/submission-policy-update.component.ts +++ b/src/main/webapp/app/exercises/shared/submission-policy/submission-policy-update.component.ts @@ -1,6 +1,6 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { LockRepositoryPolicy, SubmissionPenaltyPolicy, SubmissionPolicyType } from 'app/entities/submission-policy.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { FormControl, FormGroup, Validators } from '@angular/forms'; @Component({ diff --git a/src/main/webapp/app/exercises/shared/submission/submission.service.ts b/src/main/webapp/app/exercises/shared/submission/submission.service.ts index 4ab2d0ccdf10..d2cad659ac83 100644 --- a/src/main/webapp/app/exercises/shared/submission/submission.service.ts +++ b/src/main/webapp/app/exercises/shared/submission/submission.service.ts @@ -5,7 +5,7 @@ import { createRequestOption } from 'app/shared/util/request.util'; import { Result } from 'app/entities/result.model'; import { Submission, getLatestSubmissionResult, setLatestSubmissionResult } from 'app/entities/submission.model'; import { filter, map, tap } from 'rxjs/operators'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { Feedback } from 'app/entities/feedback.model'; import { Complaint } from 'app/entities/complaint.model'; import { ComplaintResponseService } from 'app/complaints/complaint-response.service'; diff --git a/src/main/webapp/app/exercises/text/assess/analytics/text-assesment-analytics.service.ts b/src/main/webapp/app/exercises/text/assess/analytics/text-assesment-analytics.service.ts index d37a8a428dd1..22178ca78f3c 100644 --- a/src/main/webapp/app/exercises/text/assess/analytics/text-assesment-analytics.service.ts +++ b/src/main/webapp/app/exercises/text/assess/analytics/text-assesment-analytics.service.ts @@ -1,10 +1,10 @@ import { Injectable } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TextAssessmentService } from 'app/exercises/text/assess/text-assessment.service'; -import { TextAssessmentEvent, TextAssessmentEventType } from 'app/entities/text-assesment-event.model'; +import { TextAssessmentEvent, TextAssessmentEventType } from 'app/entities/text/text-assesment-event.model'; import { AccountService } from 'app/core/auth/account.service'; import { FeedbackType } from 'app/entities/feedback.model'; -import { TextBlockType } from 'app/entities/text-block.model'; +import { TextBlockType } from 'app/entities/text/text-block.model'; import { ProfileService } from 'app/shared/layouts/profiles/profile.service'; import { Location } from '@angular/common'; diff --git a/src/main/webapp/app/exercises/text/assess/manual-textblock-selection/manual-textblock-selection.component.ts b/src/main/webapp/app/exercises/text/assess/manual-textblock-selection/manual-textblock-selection.component.ts index 094acf5431b8..5c9c22ab595f 100644 --- a/src/main/webapp/app/exercises/text/assess/manual-textblock-selection/manual-textblock-selection.component.ts +++ b/src/main/webapp/app/exercises/text/assess/manual-textblock-selection/manual-textblock-selection.component.ts @@ -1,7 +1,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { TextBlockRef } from 'app/entities/text-block-ref.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; -import { TextBlock } from 'app/entities/text-block.model'; +import { TextBlockRef } from 'app/entities/text/text-block-ref.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; +import { TextBlock } from 'app/entities/text/text-block.model'; import { GradingCriterion } from 'app/exercises/shared/structured-grading-criterion/grading-criterion.model'; import { wordSelection } from 'app/exercises/text/shared/manual-text-selection/manual-text-selection.component'; diff --git a/src/main/webapp/app/exercises/text/assess/text-assessment-area/text-assessment-area.component.ts b/src/main/webapp/app/exercises/text/assess/text-assessment-area/text-assessment-area.component.ts index f834639f59f0..200f7b69d95a 100644 --- a/src/main/webapp/app/exercises/text/assess/text-assessment-area/text-assessment-area.component.ts +++ b/src/main/webapp/app/exercises/text/assess/text-assessment-area/text-assessment-area.component.ts @@ -1,6 +1,6 @@ import { Component, EventEmitter, HostListener, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; -import { TextSubmission } from 'app/entities/text-submission.model'; -import { TextBlockRef } from 'app/entities/text-block-ref.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; +import { TextBlockRef } from 'app/entities/text/text-block-ref.model'; import { StringCountService } from 'app/exercises/text/participate/string-count.service'; import { GradingCriterion } from 'app/exercises/shared/structured-grading-criterion/grading-criterion.model'; diff --git a/src/main/webapp/app/exercises/text/assess/text-assessment-base.component.ts b/src/main/webapp/app/exercises/text/assess/text-assessment-base.component.ts index 69eb2bb1847a..8c1f564182d5 100644 --- a/src/main/webapp/app/exercises/text/assess/text-assessment-base.component.ts +++ b/src/main/webapp/app/exercises/text/assess/text-assessment-base.component.ts @@ -1,9 +1,9 @@ import { Component, OnInit } from '@angular/core'; import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; -import { TextBlockRef } from 'app/entities/text-block-ref.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; -import { TextBlock, TextBlockType } from 'app/entities/text-block.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextBlockRef } from 'app/entities/text/text-block-ref.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; +import { TextBlock, TextBlockType } from 'app/entities/text/text-block.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { Result } from 'app/entities/result.model'; import { AccountService } from 'app/core/auth/account.service'; import { TextAssessmentService } from 'app/exercises/text/assess/text-assessment.service'; diff --git a/src/main/webapp/app/exercises/text/assess/text-assessment.service.ts b/src/main/webapp/app/exercises/text/assess/text-assessment.service.ts index 8e2274337833..d996953e4cf6 100644 --- a/src/main/webapp/app/exercises/text/assess/text-assessment.service.ts +++ b/src/main/webapp/app/exercises/text/assess/text-assessment.service.ts @@ -6,11 +6,11 @@ import { Result } from 'app/entities/result.model'; import { ComplaintResponse } from 'app/entities/complaint-response.model'; import { Feedback } from 'app/entities/feedback.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; -import { TextBlock } from 'app/entities/text-block.model'; -import { TextBlockRef } from 'app/entities/text-block-ref.model'; +import { TextBlock } from 'app/entities/text/text-block.model'; +import { TextBlockRef } from 'app/entities/text/text-block-ref.model'; import { Submission, getLatestSubmissionResult, getSubmissionResultByCorrectionRound, getSubmissionResultById, setLatestSubmissionResult } from 'app/entities/submission.model'; import { Participation } from 'app/entities/participation/participation.model'; -import { TextAssessmentEvent } from 'app/entities/text-assesment-event.model'; +import { TextAssessmentEvent } from 'app/entities/text/text-assesment-event.model'; import { AccountService } from 'app/core/auth/account.service'; import { convertDateFromServer } from 'app/utils/date.utils'; diff --git a/src/main/webapp/app/exercises/text/assess/text-submission-assessment.component.ts b/src/main/webapp/app/exercises/text/assess/text-submission-assessment.component.ts index f35fe3bb044d..875555a1492c 100644 --- a/src/main/webapp/app/exercises/text/assess/text-submission-assessment.component.ts +++ b/src/main/webapp/app/exercises/text/assess/text-submission-assessment.component.ts @@ -6,8 +6,8 @@ import { AlertService } from 'app/core/util/alert.service'; import dayjs from 'dayjs/esm'; import { AccountService } from 'app/core/auth/account.service'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { Result } from 'app/entities/result.model'; import { Complaint } from 'app/entities/complaint.model'; import { ComplaintService } from 'app/complaints/complaint.service'; @@ -34,9 +34,9 @@ import { Course } from 'app/entities/course.model'; import { isAllowedToModifyFeedback } from 'app/assessment/assessment.service'; import { faListAlt } from '@fortawesome/free-regular-svg-icons'; import { AssessmentAfterComplaint } from 'app/complaints/complaints-for-tutor/complaints-for-tutor.component'; -import { TextBlockRef } from 'app/entities/text-block-ref.model'; +import { TextBlockRef } from 'app/entities/text/text-block-ref.model'; import { AthenaService } from 'app/assessment/athena.service'; -import { TextBlock } from 'app/entities/text-block.model'; +import { TextBlock } from 'app/entities/text/text-block.model'; import { Subscription } from 'rxjs'; @Component({ diff --git a/src/main/webapp/app/exercises/text/assess/text-submission-assessment.route.ts b/src/main/webapp/app/exercises/text/assess/text-submission-assessment.route.ts index 517009175196..83e63bcd21b1 100644 --- a/src/main/webapp/app/exercises/text/assess/text-submission-assessment.route.ts +++ b/src/main/webapp/app/exercises/text/assess/text-submission-assessment.route.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, Resolve, Routes } from '@angular/router'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { of } from 'rxjs'; import { UserRouteAccessService } from 'app/core/auth/user-route-access-service'; import { TextSubmissionAssessmentComponent } from './text-submission-assessment.component'; diff --git a/src/main/webapp/app/exercises/text/assess/textblock-assessment-card/textblock-assessment-card.component.ts b/src/main/webapp/app/exercises/text/assess/textblock-assessment-card/textblock-assessment-card.component.ts index 1498affd1415..2a34e2b47136 100644 --- a/src/main/webapp/app/exercises/text/assess/textblock-assessment-card/textblock-assessment-card.component.ts +++ b/src/main/webapp/app/exercises/text/assess/textblock-assessment-card/textblock-assessment-card.component.ts @@ -1,10 +1,10 @@ import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core'; -import { TextBlockRef } from 'app/entities/text-block-ref.model'; +import { TextBlockRef } from 'app/entities/text/text-block-ref.model'; import { TextblockFeedbackEditorComponent } from 'app/exercises/text/assess/textblock-feedback-editor/textblock-feedback-editor.component'; import { StructuredGradingCriterionService } from 'app/exercises/shared/structured-grading-criterion/structured-grading-criterion.service'; -import { TextAssessmentEventType } from 'app/entities/text-assesment-event.model'; +import { TextAssessmentEventType } from 'app/entities/text/text-assesment-event.model'; import { FeedbackType } from 'app/entities/feedback.model'; -import { TextBlockType } from 'app/entities/text-block.model'; +import { TextBlockType } from 'app/entities/text/text-block.model'; import { TextAssessmentAnalytics } from 'app/exercises/text/assess/analytics/text-assesment-analytics.service'; import { ActivatedRoute } from '@angular/router'; import { GradingCriterion } from 'app/exercises/shared/structured-grading-criterion/grading-criterion.model'; diff --git a/src/main/webapp/app/exercises/text/assess/textblock-feedback-editor/textblock-feedback-editor.component.ts b/src/main/webapp/app/exercises/text/assess/textblock-feedback-editor/textblock-feedback-editor.component.ts index f99baf73f449..72d8ef60ad19 100644 --- a/src/main/webapp/app/exercises/text/assess/textblock-feedback-editor/textblock-feedback-editor.component.ts +++ b/src/main/webapp/app/exercises/text/assess/textblock-feedback-editor/textblock-feedback-editor.component.ts @@ -1,11 +1,11 @@ import { AfterViewInit, Component, ElementRef, EventEmitter, HostBinding, Input, Output, ViewChild } from '@angular/core'; -import { TextBlock } from 'app/entities/text-block.model'; +import { TextBlock } from 'app/entities/text/text-block.model'; import { Feedback, FeedbackType } from 'app/entities/feedback.model'; import { ConfirmIconComponent } from 'app/shared/confirm-icon/confirm-icon.component'; import { StructuredGradingCriterionService } from 'app/exercises/shared/structured-grading-criterion/structured-grading-criterion.service'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { ActivatedRoute } from '@angular/router'; -import { TextAssessmentEventType } from 'app/entities/text-assesment-event.model'; +import { TextAssessmentEventType } from 'app/entities/text/text-assesment-event.model'; import { TextAssessmentAnalytics } from 'app/exercises/text/assess/analytics/text-assesment-analytics.service'; import { faAngleRight, faEdit, faExclamation, faExclamationTriangle, faLightbulb, faQuestionCircle, faTimes, faTrash } from '@fortawesome/free-solid-svg-icons'; import { GradingCriterion } from 'app/exercises/shared/structured-grading-criterion/grading-criterion.model'; diff --git a/src/main/webapp/app/exercises/text/manage/example-text-submission/example-text-submission.component.ts b/src/main/webapp/app/exercises/text/manage/example-text-submission/example-text-submission.component.ts index 3db47679dc4a..1640da7b1978 100644 --- a/src/main/webapp/app/exercises/text/manage/example-text-submission/example-text-submission.component.ts +++ b/src/main/webapp/app/exercises/text/manage/example-text-submission/example-text-submission.component.ts @@ -11,8 +11,8 @@ import { tutorAssessmentTour } from 'app/guided-tour/tours/tutor-assessment-tour import { ExampleSubmission, ExampleSubmissionMode } from 'app/entities/example-submission.model'; import { Feedback, FeedbackCorrectionError, FeedbackType } from 'app/entities/feedback.model'; import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; -import { TextExercise } from 'app/entities/text-exercise.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { Result } from 'app/entities/result.model'; import { setLatestSubmissionResult } from 'app/entities/submission.model'; import { TextAssessmentBaseComponent } from 'app/exercises/text/assess/text-assessment-base.component'; diff --git a/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise-detail.component.ts b/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise-detail.component.ts index 72a0414b70fe..4199461314b2 100644 --- a/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise-detail.component.ts +++ b/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise-detail.component.ts @@ -3,7 +3,7 @@ import { SafeHtml } from '@angular/platform-browser'; import { ActivatedRoute } from '@angular/router'; import { HttpResponse } from '@angular/common/http'; import { Subscription } from 'rxjs'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { TextExerciseService } from './text-exercise.service'; import { ArtemisMarkdownService } from 'app/shared/markdown.service'; import { AssessmentType } from 'app/entities/assessment-type.model'; diff --git a/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise-paging.service.ts b/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise-paging.service.ts index df3c7f767a84..ed167d578dd0 100644 --- a/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise-paging.service.ts +++ b/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise-paging.service.ts @@ -1,6 +1,6 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { ExercisePagingService } from 'app/exercises/shared/manage/exercise-paging.service'; @Injectable({ providedIn: 'root' }) diff --git a/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise-row-buttons.component.ts b/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise-row-buttons.component.ts index fff2f2a799f8..00e2973a5cc6 100644 --- a/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise-row-buttons.component.ts +++ b/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise-row-buttons.component.ts @@ -2,7 +2,7 @@ import { Component, Input } from '@angular/core'; import { HttpErrorResponse } from '@angular/common/http'; import { Subject } from 'rxjs'; import { TextExerciseService } from 'app/exercises/text/manage/text-exercise/text-exercise.service'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { EventManager } from 'app/core/util/event-manager.service'; import { faBook, faTable, faTrash, faUsers, faWrench } from '@fortawesome/free-solid-svg-icons'; import { faListAlt } from '@fortawesome/free-regular-svg-icons'; diff --git a/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise-update.component.ts b/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise-update.component.ts index e55e5fb28db2..a9304c422e89 100644 --- a/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise-update.component.ts +++ b/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise-update.component.ts @@ -1,7 +1,7 @@ import { AfterViewInit, ChangeDetectionStrategy, Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { HttpErrorResponse } from '@angular/common/http'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { TextExerciseService } from './text-exercise.service'; import { CourseManagementService } from 'app/course/manage/course-management.service'; import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; diff --git a/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise.component.ts b/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise.component.ts index 7714fe2a28eb..ac46f89650d7 100644 --- a/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise.component.ts +++ b/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise.component.ts @@ -1,7 +1,7 @@ import { Component, Input } from '@angular/core'; import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; import { ExerciseType } from 'app/entities/exercise.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { TextExerciseService } from './text-exercise.service'; import { CourseManagementService } from 'app/course/manage/course-management.service'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; diff --git a/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise.route.ts b/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise.route.ts index 67c3f64a6dd4..2e3198bc4186 100644 --- a/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise.route.ts +++ b/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise.route.ts @@ -2,7 +2,7 @@ import { ActivatedRouteSnapshot, Resolve, Routes } from '@angular/router'; import { UserRouteAccessService } from 'app/core/auth/user-route-access-service'; import { TextExerciseDetailComponent } from './text-exercise-detail.component'; import { TextExerciseUpdateComponent } from './text-exercise-update.component'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { Injectable } from '@angular/core'; import { TextExerciseService } from 'app/exercises/text/manage/text-exercise/text-exercise.service'; import { CourseManagementService } from 'app/course/manage/course-management.service'; diff --git a/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise.service.ts b/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise.service.ts index 6cdfb5c91e95..994f1ac75eeb 100644 --- a/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise.service.ts +++ b/src/main/webapp/app/exercises/text/manage/text-exercise/text-exercise.service.ts @@ -3,7 +3,7 @@ import { HttpClient, HttpResponse } from '@angular/common/http'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { createRequestOption } from 'app/shared/util/request.util'; import { ExerciseServicable, ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; import { TextPlagiarismResult } from 'app/exercises/shared/plagiarism/types/text/TextPlagiarismResult'; diff --git a/src/main/webapp/app/exercises/text/participate/text-editor.component.ts b/src/main/webapp/app/exercises/text/participate/text-editor.component.ts index 08be104f935c..82d8de5b26cf 100644 --- a/src/main/webapp/app/exercises/text/participate/text-editor.component.ts +++ b/src/main/webapp/app/exercises/text/participate/text-editor.component.ts @@ -14,10 +14,10 @@ import { TextSubmissionService } from 'app/exercises/text/participate/text-submi import { ComponentCanDeactivate } from 'app/shared/guard/can-deactivate.model'; import { Feedback } from 'app/entities/feedback.model'; import { hasExerciseDueDatePassed } from 'app/exercises/shared/exercise/exercise.utils'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { ButtonType } from 'app/shared/components/button.component'; import { Result } from 'app/entities/result.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { StringCountService } from 'app/exercises/text/participate/string-count.service'; import { AccountService } from 'app/core/auth/account.service'; import { getFirstResultWithComplaint, getLatestSubmissionResult, setLatestSubmissionResult } from 'app/entities/submission.model'; diff --git a/src/main/webapp/app/exercises/text/participate/text-result/text-result-block.ts b/src/main/webapp/app/exercises/text/participate/text-result/text-result-block.ts index 2ed52a5002fa..33960c213bcc 100644 --- a/src/main/webapp/app/exercises/text/participate/text-result/text-result-block.ts +++ b/src/main/webapp/app/exercises/text/participate/text-result/text-result-block.ts @@ -1,7 +1,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { faCheck, faCheckCircle, faCircle, faDotCircle, faTimes, faTimesCircle } from '@fortawesome/free-solid-svg-icons'; import { Feedback } from 'app/entities/feedback.model'; -import { TextBlock } from 'app/entities/text-block.model'; +import { TextBlock } from 'app/entities/text/text-block.model'; import { convertToHtmlLinebreaks, escapeString } from 'app/utils/text.utils'; enum FeedbackType { diff --git a/src/main/webapp/app/exercises/text/participate/text-result/text-result.component.ts b/src/main/webapp/app/exercises/text/participate/text-result/text-result.component.ts index 681266e5ef85..c63aaece1335 100644 --- a/src/main/webapp/app/exercises/text/participate/text-result/text-result.component.ts +++ b/src/main/webapp/app/exercises/text/participate/text-result/text-result.component.ts @@ -1,10 +1,10 @@ import { Component, Input } from '@angular/core'; import { Feedback, buildFeedbackTextForReview, checkSubsequentFeedbackInAssessment } from 'app/entities/feedback.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { Result } from 'app/entities/result.model'; import { TextResultBlock } from './text-result-block'; import { TranslateService } from '@ngx-translate/core'; -import { TextBlock } from 'app/entities/text-block.model'; +import { TextBlock } from 'app/entities/text/text-block.model'; import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons'; import { LocaleConversionService } from 'app/shared/service/locale-conversion.service'; import { Course } from 'app/entities/course.model'; diff --git a/src/main/webapp/app/exercises/text/participate/text-submission.service.ts b/src/main/webapp/app/exercises/text/participate/text-submission.service.ts index 26d493d36b75..2c90d0c7188c 100644 --- a/src/main/webapp/app/exercises/text/participate/text-submission.service.ts +++ b/src/main/webapp/app/exercises/text/participate/text-submission.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'; import { HttpClient, HttpParams, HttpResponse } from '@angular/common/http'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { createRequestOption } from 'app/shared/util/request.util'; import { stringifyCircular } from 'app/shared/util/utils'; import { getLatestSubmissionResult, setLatestSubmissionResult } from 'app/entities/submission.model'; diff --git a/src/main/webapp/app/exercises/text/shared/manual-text-selection/manual-text-selection.component.ts b/src/main/webapp/app/exercises/text/shared/manual-text-selection/manual-text-selection.component.ts index d4cd37b3b8a6..1a846ba58988 100644 --- a/src/main/webapp/app/exercises/text/shared/manual-text-selection/manual-text-selection.component.ts +++ b/src/main/webapp/app/exercises/text/shared/manual-text-selection/manual-text-selection.component.ts @@ -1,10 +1,10 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { TextAssessmentEventType } from 'app/entities/text-assesment-event.model'; +import { TextAssessmentEventType } from 'app/entities/text/text-assesment-event.model'; import { FeedbackType } from 'app/entities/feedback.model'; -import { TextBlockType } from 'app/entities/text-block.model'; +import { TextBlockType } from 'app/entities/text/text-block.model'; import { TextAssessmentAnalytics } from 'app/exercises/text/assess/analytics/text-assesment-analytics.service'; import { ActivatedRoute } from '@angular/router'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { TextBlockRefGroup } from 'app/exercises/text/assess/manual-textblock-selection/manual-textblock-selection.component'; export type wordSelection = { diff --git a/src/main/webapp/app/grading-system/base-grading-system/base-grading-system.component.ts b/src/main/webapp/app/grading-system/base-grading-system/base-grading-system.component.ts index a53bc9c26f75..21e2a3aef781 100644 --- a/src/main/webapp/app/grading-system/base-grading-system/base-grading-system.component.ts +++ b/src/main/webapp/app/grading-system/base-grading-system/base-grading-system.component.ts @@ -9,7 +9,7 @@ import { HttpResponse } from '@angular/common/http'; import { catchError, finalize } from 'rxjs/operators'; import { TranslateService } from '@ngx-translate/core'; import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { CourseManagementService } from 'app/course/manage/course-management.service'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { download, generateCsv, mkConfig } from 'export-to-csv'; diff --git a/src/main/webapp/app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component.ts b/src/main/webapp/app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component.ts index 05bb0f2689c8..074c1e704695 100644 --- a/src/main/webapp/app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component.ts +++ b/src/main/webapp/app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component.ts @@ -1,10 +1,10 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; -import { BuildAgent } from 'app/entities/build-agent.model'; +import { BuildAgent } from 'app/entities/programming/build-agent.model'; import { BuildAgentsService } from 'app/localci/build-agents/build-agents.service'; import { Subscription } from 'rxjs'; import { faCircleCheck, faExclamationCircle, faExclamationTriangle, faTimes } from '@fortawesome/free-solid-svg-icons'; import dayjs from 'dayjs/esm'; -import { TriggeredByPushTo } from 'app/entities/repository-info.model'; +import { TriggeredByPushTo } from 'app/entities/programming/repository-info.model'; import { ActivatedRoute } from '@angular/router'; import { JhiWebsocketService } from 'app/core/websocket/websocket.service'; import { BuildQueueService } from 'app/localci/build-queue/build-queue.service'; diff --git a/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.ts b/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.ts index cac89931b3be..b7f232bf0fc4 100644 --- a/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.ts +++ b/src/main/webapp/app/localci/build-agents/build-agent-summary/build-agent-summary.component.ts @@ -1,5 +1,5 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; -import { BuildAgent } from 'app/entities/build-agent.model'; +import { BuildAgent } from 'app/entities/programming/build-agent.model'; import { JhiWebsocketService } from 'app/core/websocket/websocket.service'; import { BuildAgentsService } from 'app/localci/build-agents/build-agents.service'; import { Subscription } from 'rxjs'; diff --git a/src/main/webapp/app/localci/build-agents/build-agents.service.ts b/src/main/webapp/app/localci/build-agents/build-agents.service.ts index 1acca8c34375..99905ad80c51 100644 --- a/src/main/webapp/app/localci/build-agents/build-agents.service.ts +++ b/src/main/webapp/app/localci/build-agents/build-agents.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable, throwError } from 'rxjs'; -import { BuildAgent } from 'app/entities/build-agent.model'; +import { BuildAgent } from 'app/entities/programming/build-agent.model'; import { catchError } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) diff --git a/src/main/webapp/app/localci/build-queue/build-queue.component.ts b/src/main/webapp/app/localci/build-queue/build-queue.component.ts index 2ab4ae9bc7f8..79ca4931786c 100644 --- a/src/main/webapp/app/localci/build-queue/build-queue.component.ts +++ b/src/main/webapp/app/localci/build-queue/build-queue.component.ts @@ -1,11 +1,11 @@ import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { BuildJob, BuildJobStatistics, FinishedBuildJob, SpanType } from 'app/entities/build-job.model'; +import { BuildJob, BuildJobStatistics, FinishedBuildJob, SpanType } from 'app/entities/programming/build-job.model'; import { faAngleDown, faAngleRight, faCircleCheck, faExclamationCircle, faExclamationTriangle, faFilter, faSort, faSync, faTimes } from '@fortawesome/free-solid-svg-icons'; import { JhiWebsocketService } from 'app/core/websocket/websocket.service'; import { BuildQueueService } from 'app/localci/build-queue/build-queue.service'; import { debounceTime, distinctUntilChanged, map, switchMap, take, tap } from 'rxjs/operators'; -import { TriggeredByPushTo } from 'app/entities/repository-info.model'; +import { TriggeredByPushTo } from 'app/entities/programming/repository-info.model'; import { ITEMS_PER_PAGE } from 'app/shared/constants/pagination.constants'; import { SortingOrder } from 'app/shared/table/pageable-table'; import { onError } from 'app/shared/util/global.utils'; diff --git a/src/main/webapp/app/localci/build-queue/build-queue.service.ts b/src/main/webapp/app/localci/build-queue/build-queue.service.ts index c0a958f84715..fdc9bec66e2f 100644 --- a/src/main/webapp/app/localci/build-queue/build-queue.service.ts +++ b/src/main/webapp/app/localci/build-queue/build-queue.service.ts @@ -3,7 +3,7 @@ import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { catchError } from 'rxjs/operators'; import { throwError } from 'rxjs'; -import { BuildJob, BuildJobStatistics, FinishedBuildJob, SpanType } from 'app/entities/build-job.model'; +import { BuildJob, BuildJobStatistics, FinishedBuildJob, SpanType } from 'app/entities/programming/build-job.model'; import { createNestedRequestOption } from 'app/shared/util/request.util'; import { HttpResponse } from '@angular/common/http'; import { FinishedBuildJobFilter } from 'app/localci/build-queue/build-queue.component'; diff --git a/src/main/webapp/app/localvc/commit-details-view/commit-details-view.component.ts b/src/main/webapp/app/localvc/commit-details-view/commit-details-view.component.ts index 617797f048c1..98ced261dc32 100644 --- a/src/main/webapp/app/localvc/commit-details-view/commit-details-view.component.ts +++ b/src/main/webapp/app/localvc/commit-details-view/commit-details-view.component.ts @@ -4,7 +4,7 @@ import { ProgrammingExerciseService } from 'app/exercises/programming/manage/ser import { ProgrammingExerciseParticipationService } from 'app/exercises/programming/manage/services/programming-exercise-participation.service'; import { Subscription, throwError } from 'rxjs'; import { ActivatedRoute } from '@angular/router'; -import { CommitInfo } from 'app/entities/programming-submission.model'; +import { CommitInfo } from 'app/entities/programming/programming-submission.model'; import dayjs from 'dayjs/esm'; import { catchError, map, tap } from 'rxjs/operators'; diff --git a/src/main/webapp/app/localvc/commit-history/commit-history.component.ts b/src/main/webapp/app/localvc/commit-history/commit-history.component.ts index 056104710066..fe98dd02cb53 100644 --- a/src/main/webapp/app/localvc/commit-history/commit-history.component.ts +++ b/src/main/webapp/app/localvc/commit-history/commit-history.component.ts @@ -3,11 +3,11 @@ import { ActivatedRoute } from '@angular/router'; import { Subscription } from 'rxjs'; import dayjs from 'dayjs/esm'; import { ExerciseType } from 'app/entities/exercise.model'; -import { CommitInfo, ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { CommitInfo, ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { ProgrammingExerciseParticipationService } from 'app/exercises/programming/manage/services/programming-exercise-participation.service'; import { tap } from 'rxjs/operators'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { SolutionProgrammingExerciseParticipation } from 'app/entities/participation/solution-programming-exercise-participation.model'; import { TemplateProgrammingExerciseParticipation } from 'app/entities/participation/template-programming-exercise-participation.model'; import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model'; diff --git a/src/main/webapp/app/localvc/repository-view/repository-view.component.ts b/src/main/webapp/app/localvc/repository-view/repository-view.component.ts index 8125fbbcb1d6..22ee9747edbb 100644 --- a/src/main/webapp/app/localvc/repository-view/repository-view.component.ts +++ b/src/main/webapp/app/localvc/repository-view/repository-view.component.ts @@ -3,7 +3,7 @@ import { Observable, Subscription } from 'rxjs'; import { ActivatedRoute, Router } from '@angular/router'; import { DomainService } from 'app/exercises/programming/shared/code-editor/service/code-editor-domain.service'; import { ExerciseType, getCourseFromExercise } from 'app/entities/exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { DomainType } from 'app/exercises/programming/shared/code-editor/model/code-editor.model'; import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model'; import { AccountService } from 'app/core/auth/account.service'; diff --git a/src/main/webapp/app/orion/assessment/orion-assessment.service.ts b/src/main/webapp/app/orion/assessment/orion-assessment.service.ts index 27a068b37f2e..9463fc7f3e32 100644 --- a/src/main/webapp/app/orion/assessment/orion-assessment.service.ts +++ b/src/main/webapp/app/orion/assessment/orion-assessment.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { ProgrammingAssessmentRepoExportService, RepositoryExportOptions } from 'app/exercises/programming/assess/repo-export/programming-assessment-repo-export.service'; import { OrionConnectorService } from 'app/shared/orion/orion-connector.service'; import { ProgrammingSubmissionService } from 'app/exercises/programming/participate/programming-submission.service'; diff --git a/src/main/webapp/app/orion/management/orion-programming-exercise.component.ts b/src/main/webapp/app/orion/management/orion-programming-exercise.component.ts index 5728cd2c99be..2854122be21c 100644 --- a/src/main/webapp/app/orion/management/orion-programming-exercise.component.ts +++ b/src/main/webapp/app/orion/management/orion-programming-exercise.component.ts @@ -1,5 +1,5 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { OrionConnectorService } from 'app/shared/orion/orion-connector.service'; import { ExerciseView, OrionState } from 'app/shared/orion/orion'; import { Router } from '@angular/router'; diff --git a/src/main/webapp/app/orion/participation/orion-exercise-details-student-actions.component.ts b/src/main/webapp/app/orion/participation/orion-exercise-details-student-actions.component.ts index aa415ecd9432..30f6b585e32c 100644 --- a/src/main/webapp/app/orion/participation/orion-exercise-details-student-actions.component.ts +++ b/src/main/webapp/app/orion/participation/orion-exercise-details-student-actions.component.ts @@ -1,7 +1,7 @@ import { Component, Input, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { FeatureToggle } from 'app/shared/feature-toggle/feature-toggle.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model'; import { ExerciseView, OrionState } from 'app/shared/orion/orion'; import { OrionConnectorService } from 'app/shared/orion/orion-connector.service'; diff --git a/src/main/webapp/app/overview/course-exams/course-exams.component.ts b/src/main/webapp/app/overview/course-exams/course-exams.component.ts index 916f669790e3..1b78c89b712e 100644 --- a/src/main/webapp/app/overview/course-exams/course-exams.component.ts +++ b/src/main/webapp/app/overview/course-exams/course-exams.component.ts @@ -2,7 +2,7 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { Course } from 'app/entities/course.model'; import { ActivatedRoute, Router } from '@angular/router'; import { Subscription } from 'rxjs'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import dayjs from 'dayjs/esm'; import { ArtemisServerDateService } from 'app/shared/server-date.service'; import { StudentExam } from 'app/entities/student-exam.model'; diff --git a/src/main/webapp/app/overview/course-overview.service.ts b/src/main/webapp/app/overview/course-overview.service.ts index ab2f9f32744d..0432dc2e361b 100644 --- a/src/main/webapp/app/overview/course-overview.service.ts +++ b/src/main/webapp/app/overview/course-overview.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { Exercise, getIcon } from 'app/entities/exercise.model'; import { Lecture } from 'app/entities/lecture.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; import { TutorialGroup } from 'app/entities/tutorial-group/tutorial-group.model'; import { getExerciseDueDate } from 'app/exercises/shared/exercise/exercise.utils'; diff --git a/src/main/webapp/app/overview/courses.component.ts b/src/main/webapp/app/overview/courses.component.ts index 73ce68512b8c..0d5218bb21b0 100644 --- a/src/main/webapp/app/overview/courses.component.ts +++ b/src/main/webapp/app/overview/courses.component.ts @@ -8,7 +8,7 @@ import { courseOverviewTour } from 'app/guided-tour/tours/course-overview-tour'; import { TeamService } from 'app/exercises/shared/team/team.service'; import { JhiWebsocketService } from 'app/core/websocket/websocket.service'; import dayjs from 'dayjs/esm'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { Router } from '@angular/router'; import { faPenAlt } from '@fortawesome/free-solid-svg-icons'; import { CourseAccessStorageService } from 'app/course/course-access-storage.service'; diff --git a/src/main/webapp/app/overview/exercise-details/course-exercise-details.component.ts b/src/main/webapp/app/overview/exercise-details/course-exercise-details.component.ts index 260428c680e3..d0b7264723b6 100644 --- a/src/main/webapp/app/overview/exercise-details/course-exercise-details.component.ts +++ b/src/main/webapp/app/overview/exercise-details/course-exercise-details.component.ts @@ -16,7 +16,7 @@ import { StudentParticipation } from 'app/entities/participation/student-partici import { ExampleSolutionInfo, ExerciseDetailsType, ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; import { AssessmentType } from 'app/entities/assessment-type.model'; import { hasExerciseDueDatePassed } from 'app/exercises/shared/exercise/exercise.utils'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { GradingCriterion } from 'app/exercises/shared/structured-grading-criterion/grading-criterion.model'; import { AlertService } from 'app/core/util/alert.service'; import { TeamAssignmentPayload } from 'app/entities/team.model'; diff --git a/src/main/webapp/app/overview/exercise-details/exercise-details-student-actions.component.ts b/src/main/webapp/app/overview/exercise-details/exercise-details-student-actions.component.ts index 87e74ad54d11..26e3bec0a7b0 100644 --- a/src/main/webapp/app/overview/exercise-details/exercise-details-student-actions.component.ts +++ b/src/main/webapp/app/overview/exercise-details/exercise-details-student-actions.component.ts @@ -7,7 +7,7 @@ import { InitializationState } from 'app/entities/participation/participation.mo import { Exercise, ExerciseType } from 'app/entities/exercise.model'; import { hasExerciseDueDatePassed, isResumeExerciseAvailable, isStartExerciseAvailable, isStartPracticeAvailable } from 'app/exercises/shared/exercise/exercise.utils'; import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; import { ArtemisQuizService } from 'app/shared/quiz/quiz.service'; import { finalize } from 'rxjs/operators'; diff --git a/src/main/webapp/app/overview/participation-websocket.service.ts b/src/main/webapp/app/overview/participation-websocket.service.ts index 97e802f2350c..3836e7a81209 100644 --- a/src/main/webapp/app/overview/participation-websocket.service.ts +++ b/src/main/webapp/app/overview/participation-websocket.service.ts @@ -9,7 +9,7 @@ import { ParticipationService } from 'app/exercises/shared/participation/partici import { JhiWebsocketService } from 'app/core/websocket/websocket.service'; import dayjs from 'dayjs/esm'; import { cloneDeep } from 'lodash-es'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; const PERSONAL_PARTICIPATION_TOPIC = `/user/topic/newResults`; const EXERCISE_PARTICIPATION_TOPIC = (exerciseId: number) => `/topic/exercise/${exerciseId}/newResults`; diff --git a/src/main/webapp/app/shared/components/code-button/code-button.component.ts b/src/main/webapp/app/shared/components/code-button/code-button.component.ts index c9dac5178ab5..0b356bf859e6 100644 --- a/src/main/webapp/app/shared/components/code-button/code-button.component.ts +++ b/src/main/webapp/app/shared/components/code-button/code-button.component.ts @@ -1,5 +1,5 @@ import { Component, Input, OnChanges, OnInit } from '@angular/core'; -import { ProgrammingExercise, ProgrammingLanguage } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise, ProgrammingLanguage } from 'app/entities/programming/programming-exercise.model'; import { FeatureToggle } from 'app/shared/feature-toggle/feature-toggle.service'; import { ExternalCloningService } from 'app/exercises/programming/shared/service/external-cloning.service'; import { TranslateService } from '@ngx-translate/core'; diff --git a/src/main/webapp/app/shared/components/course-exam-archive-button/course-exam-archive-button.component.ts b/src/main/webapp/app/shared/components/course-exam-archive-button/course-exam-archive-button.component.ts index f15e7b2971d7..a26b939ed089 100644 --- a/src/main/webapp/app/shared/components/course-exam-archive-button/course-exam-archive-button.component.ts +++ b/src/main/webapp/app/shared/components/course-exam-archive-button/course-exam-archive-button.component.ts @@ -7,7 +7,7 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { tap } from 'rxjs/operators'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import dayjs from 'dayjs/esm'; import { ButtonSize } from '../button.component'; import { ActionType } from 'app/shared/delete-dialog/delete-dialog.model'; diff --git a/src/main/webapp/app/shared/components/reset-repo-button/reset-repo-button.component.ts b/src/main/webapp/app/shared/components/reset-repo-button/reset-repo-button.component.ts index b196fd1d3df3..07f7b5f7ca94 100644 --- a/src/main/webapp/app/shared/components/reset-repo-button/reset-repo-button.component.ts +++ b/src/main/webapp/app/shared/components/reset-repo-button/reset-repo-button.component.ts @@ -2,7 +2,7 @@ import { Component, Input, OnInit } from '@angular/core'; import { FeatureToggle } from 'app/shared/feature-toggle/feature-toggle.service'; import { faBackward } from '@fortawesome/free-solid-svg-icons'; import { ParticipationService } from 'app/exercises/shared/participation/participation.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; import { ProgrammingExerciseParticipationService } from 'app/exercises/programming/manage/services/programming-exercise-participation.service'; import { InitializationState } from 'app/entities/participation/participation.model'; diff --git a/src/main/webapp/app/shared/components/start-practice-mode-button/start-practice-mode-button.component.ts b/src/main/webapp/app/shared/components/start-practice-mode-button/start-practice-mode-button.component.ts index 3541ca8f141a..2601765baf68 100644 --- a/src/main/webapp/app/shared/components/start-practice-mode-button/start-practice-mode-button.component.ts +++ b/src/main/webapp/app/shared/components/start-practice-mode-button/start-practice-mode-button.component.ts @@ -2,7 +2,7 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { FeatureToggle } from 'app/shared/feature-toggle/feature-toggle.service'; import { finalize } from 'rxjs/operators'; import { faRedo } from '@fortawesome/free-solid-svg-icons'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { CourseExerciseService } from 'app/exercises/shared/course-exercises/course-exercise.service'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; import { AlertService } from 'app/core/util/alert.service'; diff --git a/src/main/webapp/app/shared/consistency-check/consistency-check.component.ts b/src/main/webapp/app/shared/consistency-check/consistency-check.component.ts index 0383adf0244e..cfa9cf0ee405 100644 --- a/src/main/webapp/app/shared/consistency-check/consistency-check.component.ts +++ b/src/main/webapp/app/shared/consistency-check/consistency-check.component.ts @@ -3,7 +3,7 @@ import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { ConsistencyCheckService } from 'app/shared/consistency-check/consistency-check.service'; import { AlertService } from 'app/core/util/alert.service'; import { ConsistencyCheckError } from 'app/entities/consistency-check-result.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { getCourseId } from 'app/entities/exercise.model'; import { faCheck, faTimes } from '@fortawesome/free-solid-svg-icons'; diff --git a/src/main/webapp/app/shared/dashboards/tutor-leaderboard/tutor-leaderboard.component.ts b/src/main/webapp/app/shared/dashboards/tutor-leaderboard/tutor-leaderboard.component.ts index 48c99e458d89..da1cc727af85 100644 --- a/src/main/webapp/app/shared/dashboards/tutor-leaderboard/tutor-leaderboard.component.ts +++ b/src/main/webapp/app/shared/dashboards/tutor-leaderboard/tutor-leaderboard.component.ts @@ -4,7 +4,7 @@ import { Course } from 'app/entities/course.model'; import { Exercise, getCourseFromExercise } from 'app/entities/exercise.model'; import { AccountService } from 'app/core/auth/account.service'; import { SortService } from 'app/shared/service/sort.service'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { faExclamationTriangle, faSort } from '@fortawesome/free-solid-svg-icons'; @Component({ diff --git a/src/main/webapp/app/shared/dashboards/tutor-participation-graph/tutor-participation-graph.component.ts b/src/main/webapp/app/shared/dashboards/tutor-participation-graph/tutor-participation-graph.component.ts index d3b2fb105efa..e1da8a6b0498 100644 --- a/src/main/webapp/app/shared/dashboards/tutor-participation-graph/tutor-participation-graph.component.ts +++ b/src/main/webapp/app/shared/dashboards/tutor-participation-graph/tutor-participation-graph.component.ts @@ -4,7 +4,7 @@ import { get } from 'lodash-es'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; import { TutorParticipation, TutorParticipationStatus } from 'app/entities/participation/tutor-participation.model'; import { DueDateStat } from 'app/course/dashboards/due-date-stat.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { faBook, faChalkboardTeacher } from '@fortawesome/free-solid-svg-icons'; @Component({ diff --git a/src/main/webapp/app/shared/http/file.service.ts b/src/main/webapp/app/shared/http/file.service.ts index 330d449bc4f6..c14136a6688d 100644 --- a/src/main/webapp/app/shared/http/file.service.ts +++ b/src/main/webapp/app/shared/http/file.service.ts @@ -4,7 +4,7 @@ import { lastValueFrom } from 'rxjs'; import { v4 as uuid } from 'uuid'; import { Observable } from 'rxjs'; -import { ProgrammingLanguage, ProjectType } from 'app/entities/programming-exercise.model'; +import { ProgrammingLanguage, ProjectType } from 'app/entities/programming/programming-exercise.model'; @Injectable({ providedIn: 'root' }) export class FileService { diff --git a/src/main/webapp/app/shared/orion/orion-build-and-test.service.ts b/src/main/webapp/app/shared/orion/orion-build-and-test.service.ts index fd3e57b80ddd..d46ee941b24a 100644 --- a/src/main/webapp/app/shared/orion/orion-build-and-test.service.ts +++ b/src/main/webapp/app/shared/orion/orion-build-and-test.service.ts @@ -5,12 +5,12 @@ import { filter, map, tap } from 'rxjs/operators'; import { Observable, Subject, Subscription } from 'rxjs'; import { BuildLogService } from 'app/exercises/programming/shared/service/build-log.service'; import { Participation } from 'app/entities/participation/participation.model'; -import { BuildLogEntryArray } from 'app/entities/build-log.model'; -import { ProgrammingExercise, ProgrammingLanguage, ProjectType } from 'app/entities/programming-exercise.model'; +import { BuildLogEntryArray } from 'app/entities/programming/build-log.model'; +import { ProgrammingExercise, ProgrammingLanguage, ProjectType } from 'app/entities/programming/programming-exercise.model'; import { Result } from 'app/entities/result.model'; import { OrionConnectorService } from 'app/shared/orion/orion-connector.service'; import { Feedback } from 'app/entities/feedback.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; /** * Notifies the IDE about a result, that is currently building and forwards incoming test results. diff --git a/src/main/webapp/app/shared/orion/orion-connector.service.ts b/src/main/webapp/app/shared/orion/orion-connector.service.ts index b49f8745e8db..61c8a0933cec 100644 --- a/src/main/webapp/app/shared/orion/orion-connector.service.ts +++ b/src/main/webapp/app/shared/orion/orion-connector.service.ts @@ -4,7 +4,7 @@ import { ExerciseView, OrionState } from 'app/shared/orion/orion'; import { Router } from '@angular/router'; import { REPOSITORY } from 'app/exercises/programming/manage/code-editor/code-editor-instructor-base-container.component'; import { stringifyCircular } from 'app/shared/util/utils'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { Feedback } from 'app/entities/feedback.model'; import { OrionTutorAssessmentComponent } from 'app/orion/assessment/orion-tutor-assessment.component'; import { AlertService } from 'app/core/util/alert.service'; diff --git a/src/main/webapp/app/shared/user-import/users-import-button.component.ts b/src/main/webapp/app/shared/user-import/users-import-button.component.ts index 8056a4dbf2d1..88cd5df1b505 100644 --- a/src/main/webapp/app/shared/user-import/users-import-button.component.ts +++ b/src/main/webapp/app/shared/user-import/users-import-button.component.ts @@ -3,7 +3,7 @@ import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; import { ButtonSize, ButtonType } from 'app/shared/components/button.component'; import { UsersImportDialogComponent } from 'app/shared/user-import/users-import-dialog.component'; import { CourseGroup } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { faFileImport } from '@fortawesome/free-solid-svg-icons'; import { TutorialGroup } from 'app/entities/tutorial-group/tutorial-group.model'; diff --git a/src/main/webapp/app/shared/user-import/users-import-dialog.component.ts b/src/main/webapp/app/shared/user-import/users-import-dialog.component.ts index cb8287d7b74d..147cf3a2e661 100644 --- a/src/main/webapp/app/shared/user-import/users-import-dialog.component.ts +++ b/src/main/webapp/app/shared/user-import/users-import-dialog.component.ts @@ -3,12 +3,12 @@ import { NgForm } from '@angular/forms'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { AlertService } from 'app/core/util/alert.service'; import { HttpResponse } from '@angular/common/http'; -import { ExamUserDTO } from 'app/entities/exam-user-dto.model'; +import { ExamUserDTO } from 'app/entities/exam/exam-user-dto.model'; import { cleanString } from 'app/shared/util/utils'; import { Subject } from 'rxjs'; import { ActionType } from 'app/shared/delete-dialog/delete-dialog.model'; import { CourseManagementService } from 'app/course/manage/course-management.service'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { StudentDTO } from 'app/entities/student-dto.model'; import { parse } from 'papaparse'; diff --git a/src/test/javascript/spec/component/assessment-dashboard/assessment-dashboard.component.spec.ts b/src/test/javascript/spec/component/assessment-dashboard/assessment-dashboard.component.spec.ts index b9b5192b7e70..bc3cfc327be3 100644 --- a/src/test/javascript/spec/component/assessment-dashboard/assessment-dashboard.component.spec.ts +++ b/src/test/javascript/spec/component/assessment-dashboard/assessment-dashboard.component.spec.ts @@ -12,10 +12,10 @@ import { ExerciseType, IncludedInOverallScore } from 'app/entities/exercise.mode import { TutorParticipationStatus } from 'app/entities/participation/tutor-participation.model'; import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; import { StatsForDashboard } from 'app/course/dashboards/stats-for-dashboard.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { FileUploadExercise } from 'app/entities/file-upload-exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; -import { Exam } from 'app/entities/exam.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { SecondCorrectionEnableButtonComponent } from 'app/exercises/shared/dashboards/tutor/second-correction-button/second-correction-enable-button.component'; import { AssessmentDashboardComponent } from 'app/course/dashboards/assessment-dashboard/assessment-dashboard.component'; diff --git a/src/test/javascript/spec/component/assessment-dashboard/exam-assessment-buttons.component.spec.ts b/src/test/javascript/spec/component/assessment-dashboard/exam-assessment-buttons.component.spec.ts index 8b424f245ce8..e3e18abc527a 100644 --- a/src/test/javascript/spec/component/assessment-dashboard/exam-assessment-buttons.component.spec.ts +++ b/src/test/javascript/spec/component/assessment-dashboard/exam-assessment-buttons.component.spec.ts @@ -8,7 +8,7 @@ import { Course } from 'app/entities/course.model'; import { of, throwError } from 'rxjs'; import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; import { StudentExam } from 'app/entities/student-exam.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { User } from 'app/core/user/user.model'; import dayjs from 'dayjs/esm'; import { By } from '@angular/platform-browser'; diff --git a/src/test/javascript/spec/component/assessment-dashboard/exercise-assessment-dashboard.component.spec.ts b/src/test/javascript/spec/component/assessment-dashboard/exercise-assessment-dashboard.component.spec.ts index f8bdd14321c4..92a1d051230e 100644 --- a/src/test/javascript/spec/component/assessment-dashboard/exercise-assessment-dashboard.component.spec.ts +++ b/src/test/javascript/spec/component/assessment-dashboard/exercise-assessment-dashboard.component.spec.ts @@ -24,19 +24,19 @@ import { StatsForDashboard } from 'app/course/dashboards/stats-for-dashboard.mod import { TextSubmissionService } from 'app/exercises/text/participate/text-submission.service'; import { FileUploadSubmissionService } from 'app/exercises/file-upload/participate/file-upload-submission.service'; import { FileUploadSubmission } from 'app/entities/file-upload-submission.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { FileUploadExercise } from 'app/entities/file-upload-exercise.model'; import { ProgrammingSubmissionService } from 'app/exercises/programming/participate/programming-submission.service'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { Complaint, ComplaintType } from 'app/entities/complaint.model'; import { Language } from 'app/entities/course.model'; import { Submission, SubmissionExerciseType } from 'app/entities/submission.model'; import { TutorParticipationService } from 'app/exercises/shared/dashboards/tutor/tutor-participation.service'; import { Participation } from 'app/entities/participation/participation.model'; import { Result } from 'app/entities/result.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { SecondCorrectionEnableButtonComponent } from 'app/exercises/shared/dashboards/tutor/second-correction-button/second-correction-enable-button.component'; import { LanguageTableCellComponent } from 'app/exercises/shared/dashboards/tutor/language-table-cell/language-table-cell.component'; diff --git a/src/test/javascript/spec/component/assessment-shared/assessment-header.component.spec.ts b/src/test/javascript/spec/component/assessment-shared/assessment-header.component.spec.ts index 83d241b52277..6c151bfbce91 100644 --- a/src/test/javascript/spec/component/assessment-shared/assessment-header.component.spec.ts +++ b/src/test/javascript/spec/component/assessment-shared/assessment-header.component.spec.ts @@ -14,7 +14,7 @@ import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.s import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { MockTranslateService } from '../../helpers/mocks/service/mock-translate.service'; import { TranslateDirective, TranslateService } from '@ngx-translate/core'; -import { TextAssessmentEventType } from 'app/entities/text-assesment-event.model'; +import { TextAssessmentEventType } from 'app/entities/text/text-assesment-event.model'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { GradingSystemService } from 'app/grading-system/grading-system.service'; import { GradingScale } from 'app/entities/grading-scale.model'; diff --git a/src/test/javascript/spec/component/assessment-shared/assessment-instructions.component.spec.ts b/src/test/javascript/spec/component/assessment-shared/assessment-instructions.component.spec.ts index 9f823f82f15f..548e3b7b9c1a 100644 --- a/src/test/javascript/spec/component/assessment-shared/assessment-instructions.component.spec.ts +++ b/src/test/javascript/spec/component/assessment-shared/assessment-instructions.component.spec.ts @@ -6,9 +6,9 @@ import { ExpandableSectionComponent } from 'app/assessment/assessment-instructio import { StructuredGradingInstructionsAssessmentLayoutComponent } from 'app/assessment/structured-grading-instructions-assessment-layout/structured-grading-instructions-assessment-layout.component'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; import { ArtemisMarkdownService } from 'app/shared/markdown.service'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { FileUploadExercise } from 'app/entities/file-upload-exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ExerciseType } from 'app/entities/exercise.model'; import { ModelingEditorComponent } from 'app/exercises/modeling/shared/modeling-editor.component'; import { ExtensionPointDirective } from 'app/shared/extension-point/extension-point.directive'; diff --git a/src/test/javascript/spec/component/assessment-shared/assessment-locks.component.spec.ts b/src/test/javascript/spec/component/assessment-shared/assessment-locks.component.spec.ts index a61789265a44..54ebbc921892 100644 --- a/src/test/javascript/spec/component/assessment-shared/assessment-locks.component.spec.ts +++ b/src/test/javascript/spec/component/assessment-shared/assessment-locks.component.spec.ts @@ -8,8 +8,8 @@ import { MockHasAnyAuthorityDirective } from '../../helpers/mocks/directive/mock import { ArtemisDatePipe } from 'app/shared/pipes/artemis-date.pipe'; import { ModelingSubmission } from 'app/entities/modeling-submission.model'; import { FileUploadSubmission } from 'app/entities/file-upload-submission.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { ModelingAssessmentService } from 'app/exercises/modeling/assess/modeling-assessment.service'; import { TextAssessmentService } from 'app/exercises/text/assess/text-assessment.service'; import { ProgrammingAssessmentManualResultService } from 'app/exercises/programming/assess/manual-result/programming-assessment-manual-result.service'; diff --git a/src/test/javascript/spec/component/assessment-shared/assessment-warning.component.spec.ts b/src/test/javascript/spec/component/assessment-shared/assessment-warning.component.spec.ts index e7ba6af20d1c..eefbd24f2338 100644 --- a/src/test/javascript/spec/component/assessment-shared/assessment-warning.component.spec.ts +++ b/src/test/javascript/spec/component/assessment-shared/assessment-warning.component.spec.ts @@ -2,9 +2,9 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import dayjs from 'dayjs/esm'; import { AssessmentWarningComponent } from 'app/assessment/assessment-warning/assessment-warning.component'; import { ArtemisTestModule } from '../../test.module'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; describe('AssessmentWarningComponent', () => { let component: AssessmentWarningComponent; diff --git a/src/test/javascript/spec/component/code-editor/code-editor-build-output.component.spec.ts b/src/test/javascript/spec/component/code-editor/code-editor-build-output.component.spec.ts index cca5d65fc88d..87206e5b1fff 100644 --- a/src/test/javascript/spec/component/code-editor/code-editor-build-output.component.spec.ts +++ b/src/test/javascript/spec/component/code-editor/code-editor-build-output.component.spec.ts @@ -7,17 +7,17 @@ import { ParticipationWebsocketService } from 'app/overview/participation-websoc import { triggerChanges } from '../../helpers/utils/general.utils'; import { CodeEditorBuildOutputComponent } from 'app/exercises/programming/shared/code-editor/build-output/code-editor-build-output.component'; import { Participation } from 'app/entities/participation/participation.model'; -import { BuildLogEntryArray } from 'app/entities/build-log.model'; +import { BuildLogEntryArray } from 'app/entities/programming/build-log.model'; import { CodeEditorBuildLogService } from 'app/exercises/programming/shared/code-editor/service/code-editor-repository.service'; import { ResultService } from 'app/exercises/shared/result/result.service'; import { MockResultService } from '../../helpers/mocks/service/mock-result.service'; import { MockCodeEditorBuildLogService } from '../../helpers/mocks/service/mock-code-editor-build-log.service'; import { MockParticipationWebsocketService } from '../../helpers/mocks/service/mock-participation-websocket.service'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { Result } from 'app/entities/result.model'; -import { StaticCodeAnalysisIssue } from 'app/entities/static-code-analysis-issue.model'; +import { StaticCodeAnalysisIssue } from 'app/entities/programming/static-code-analysis-issue.model'; import { Feedback, FeedbackType, STATIC_CODE_ANALYSIS_FEEDBACK_IDENTIFIER } from 'app/entities/feedback.model'; -import { ProgrammingLanguage, ProjectType } from 'app/entities/programming-exercise.model'; +import { ProgrammingLanguage, ProjectType } from 'app/entities/programming/programming-exercise.model'; import { ArtemisDatePipe } from 'app/shared/pipes/artemis-date.pipe'; import { MockPipe, MockProvider } from 'ng-mocks'; import { CodeEditorSubmissionService } from 'app/exercises/programming/shared/code-editor/service/code-editor-submission.service'; diff --git a/src/test/javascript/spec/component/complaints/complaint-response.service.spec.ts b/src/test/javascript/spec/component/complaints/complaint-response.service.spec.ts index 149e46dae205..5d93f7870fa0 100644 --- a/src/test/javascript/spec/component/complaints/complaint-response.service.spec.ts +++ b/src/test/javascript/spec/component/complaints/complaint-response.service.spec.ts @@ -9,7 +9,7 @@ import { AccountService } from 'app/core/auth/account.service'; import { MockProvider } from 'ng-mocks'; import dayjs from 'dayjs/esm'; import { User } from 'app/core/user/user.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { ComplaintAction, ComplaintResponseUpdateDTO } from 'app/entities/complaint-response-dto.model'; describe('ComplaintResponseService', () => { diff --git a/src/test/javascript/spec/component/complaints/complaint-student-view.component.spec.ts b/src/test/javascript/spec/component/complaints/complaint-student-view.component.spec.ts index 58ba0cd9a035..528e9d6d5c6a 100644 --- a/src/test/javascript/spec/component/complaints/complaint-student-view.component.spec.ts +++ b/src/test/javascript/spec/component/complaints/complaint-student-view.component.spec.ts @@ -7,7 +7,7 @@ import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { MockComponent, MockDirective, MockPipe } from 'ng-mocks'; import { Participation } from 'app/entities/participation/participation.model'; import { Result } from 'app/entities/result.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { Submission } from 'app/entities/submission.model'; import { Complaint } from 'app/entities/complaint.model'; import { Observable, of } from 'rxjs'; diff --git a/src/test/javascript/spec/component/complaints/complaint.service.spec.ts b/src/test/javascript/spec/component/complaints/complaint.service.spec.ts index 95b704d76e81..959355b8d92a 100644 --- a/src/test/javascript/spec/component/complaints/complaint.service.spec.ts +++ b/src/test/javascript/spec/component/complaints/complaint.service.spec.ts @@ -1,7 +1,7 @@ import { TestBed } from '@angular/core/testing'; import { ComplaintService } from 'app/complaints/complaint.service'; import { Complaint, ComplaintType } from 'app/entities/complaint.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { ComplaintResponse } from 'app/entities/complaint-response.model'; import { User } from 'app/core/user/user.model'; import { AccountService } from 'app/core/auth/account.service'; diff --git a/src/test/javascript/spec/component/complaints/list-of-complaints.component.spec.ts b/src/test/javascript/spec/component/complaints/list-of-complaints.component.spec.ts index aeff086bc8e6..e3abe463b09d 100644 --- a/src/test/javascript/spec/component/complaints/list-of-complaints.component.spec.ts +++ b/src/test/javascript/spec/component/complaints/list-of-complaints.component.spec.ts @@ -13,8 +13,8 @@ import { Complaint, ComplaintType } from 'app/entities/complaint.model'; import { Course } from 'app/entities/course.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; import { Result } from 'app/entities/result.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { ArtemisDatePipe } from 'app/shared/pipes/artemis-date.pipe'; import { SortService } from 'app/shared/service/sort.service'; import dayjs from 'dayjs/esm'; diff --git a/src/test/javascript/spec/component/consistency-check/consistency-check.component.spec.ts b/src/test/javascript/spec/component/consistency-check/consistency-check.component.spec.ts index 78a8c5a7577c..5a845b83473d 100644 --- a/src/test/javascript/spec/component/consistency-check/consistency-check.component.spec.ts +++ b/src/test/javascript/spec/component/consistency-check/consistency-check.component.spec.ts @@ -1,6 +1,6 @@ import { ConsistencyCheckComponent } from 'app/shared/consistency-check/consistency-check.component'; import { ConsistencyCheckService } from 'app/shared/consistency-check/consistency-check.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { Course } from 'app/entities/course.model'; import { ConsistencyCheckError, ErrorType } from 'app/entities/consistency-check-result.model'; import { ArtemisTestModule } from '../../test.module'; diff --git a/src/test/javascript/spec/component/course/course-lti-configuration.component.spec.ts b/src/test/javascript/spec/component/course/course-lti-configuration.component.spec.ts index c8d23f7f5ddc..2912262c8621 100644 --- a/src/test/javascript/spec/component/course/course-lti-configuration.component.spec.ts +++ b/src/test/javascript/spec/component/course/course-lti-configuration.component.spec.ts @@ -11,7 +11,7 @@ import { TranslateDirective } from 'app/shared/language/translate.directive'; import { CourseLtiConfigurationComponent } from 'app/course/manage/course-lti-configuration/course-lti-configuration.component'; import { SortService } from 'app/shared/service/sort.service'; import { Course } from 'app/entities/course.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; import { FileUploadExercise } from 'app/entities/file-upload-exercise.model'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; diff --git a/src/test/javascript/spec/component/course/course-overview.component.spec.ts b/src/test/javascript/spec/component/course/course-overview.component.spec.ts index cb3496dcb9b7..b411f3760596 100644 --- a/src/test/javascript/spec/component/course/course-overview.component.spec.ts +++ b/src/test/javascript/spec/component/course/course-overview.component.spec.ts @@ -31,7 +31,7 @@ import { AlertService } from 'app/core/util/alert.service'; import { AfterViewInit, ChangeDetectorRef, Component, TemplateRef, ViewChild } from '@angular/core'; import { By } from '@angular/platform-browser'; import { TeamAssignmentPayload } from 'app/entities/team.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { CompetencyService } from 'app/course/competencies/competency.service'; import { CourseOverviewComponent } from 'app/overview/course-overview.component'; import { BarControlConfiguration, BarControlConfigurationProvider } from 'app/shared/tab-bar/tab-bar'; diff --git a/src/test/javascript/spec/component/course/course-overview.service.spec.ts b/src/test/javascript/spec/component/course/course-overview.service.spec.ts index d0527dde176a..7dbc94aabaea 100644 --- a/src/test/javascript/spec/component/course/course-overview.service.spec.ts +++ b/src/test/javascript/spec/component/course/course-overview.service.spec.ts @@ -11,8 +11,8 @@ import { TranslateService } from '@ngx-translate/core'; import { MockTranslateService } from '../../helpers/mocks/service/mock-translate.service'; import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.service'; -import { TextExercise } from 'app/entities/text-exercise.model'; -import { Exam } from 'app/entities/exam.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ChannelDTO, ChannelSubType, getAsChannelDTO } from 'app/entities/metis/conversation/channel.model'; describe('CourseOverviewService', () => { diff --git a/src/test/javascript/spec/component/course/course-update.component.spec.ts b/src/test/javascript/spec/component/course/course-update.component.spec.ts index 2239ab6f91d1..289e91dbd948 100644 --- a/src/test/javascript/spec/component/course/course-update.component.spec.ts +++ b/src/test/javascript/spec/component/course/course-update.component.spec.ts @@ -29,7 +29,7 @@ import { OrganizationManagementService } from 'app/admin/organization-management import { Organization } from 'app/entities/organization.model'; import dayjs from 'dayjs/esm'; import { ImageCropperModule } from 'app/shared/image-cropper/image-cropper.module'; -import { ProgrammingLanguage } from 'app/entities/programming-exercise.model'; +import { ProgrammingLanguage } from 'app/entities/programming/programming-exercise.model'; import { CourseAdminService } from 'app/course/manage/course-admin.service'; import { AccountService } from 'app/core/auth/account.service'; import { MockAccountService } from '../../helpers/mocks/service/mock-account.service'; diff --git a/src/test/javascript/spec/component/course/course.component.spec.ts b/src/test/javascript/spec/component/course/course.component.spec.ts index dae7b6996b55..0922550c27e3 100644 --- a/src/test/javascript/spec/component/course/course.component.spec.ts +++ b/src/test/javascript/spec/component/course/course.component.spec.ts @@ -32,7 +32,7 @@ import { AlertService } from 'app/core/util/alert.service'; import { Component } from '@angular/core'; import { of } from 'rxjs'; import dayjs from 'dayjs/esm'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { CourseAccessStorageService } from 'app/course/course-access-storage.service'; const endDate1 = dayjs().add(1, 'days'); diff --git a/src/test/javascript/spec/component/course/exercise-filter.model.spec.ts b/src/test/javascript/spec/component/course/exercise-filter.model.spec.ts index 232aab57fafa..b2720b28a415 100644 --- a/src/test/javascript/spec/component/course/exercise-filter.model.spec.ts +++ b/src/test/javascript/spec/component/course/exercise-filter.model.spec.ts @@ -1,8 +1,8 @@ import { ExerciseFilter } from 'app/entities/exercise-filter.model'; import { Course } from 'app/entities/course.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { ExerciseCategory } from 'app/entities/exercise-category.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { Exercise } from 'app/entities/exercise.model'; describe('Exercise Filter Test', () => { diff --git a/src/test/javascript/spec/component/exam-exercise-row-buttons/exam-exercise-row-buttons.component.spec.ts b/src/test/javascript/spec/component/exam-exercise-row-buttons/exam-exercise-row-buttons.component.spec.ts index 187443be2be4..cc2d7aaf230a 100644 --- a/src/test/javascript/spec/component/exam-exercise-row-buttons/exam-exercise-row-buttons.component.spec.ts +++ b/src/test/javascript/spec/component/exam-exercise-row-buttons/exam-exercise-row-buttons.component.spec.ts @@ -3,9 +3,9 @@ import { ArtemisTestModule } from '../../test.module'; import { TranslatePipeMock } from '../../helpers/mocks/service/mock-translate.service'; import { ExamExerciseRowButtonsComponent } from 'app/exercises/shared/exam-exercise-row-buttons/exam-exercise-row-buttons.component'; import { Course } from 'app/entities/course.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { ExerciseType } from 'app/entities/exercise.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import dayjs from 'dayjs/esm'; import { ModelingExerciseService } from 'app/exercises/modeling/manage/modeling-exercise.service'; import { TextExerciseService } from 'app/exercises/text/manage/text-exercise/text-exercise.service'; @@ -17,7 +17,7 @@ import { FileUploadExercise } from 'app/entities/file-upload-exercise.model'; import { of, throwError } from 'rxjs'; import { HttpErrorResponse } from '@angular/common/http'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { MockDirective, MockProvider } from 'ng-mocks'; import { DeleteButtonDirective } from 'app/shared/delete-dialog/delete-button.directive'; import { MockRouterLinkDirective } from '../../helpers/mocks/directive/mock-router-link.directive'; diff --git a/src/test/javascript/spec/component/exam/exam-update.component.spec.ts b/src/test/javascript/spec/component/exam/exam-update.component.spec.ts index 6de1e1db5c13..7dd87ad9bef8 100644 --- a/src/test/javascript/spec/component/exam/exam-update.component.spec.ts +++ b/src/test/javascript/spec/component/exam/exam-update.component.spec.ts @@ -15,7 +15,7 @@ import { FeatureToggleDirective } from 'app/shared/feature-toggle/feature-toggle import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.service'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { Course, CourseInformationSharingConfiguration } from 'app/entities/course.model'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { FormDateTimePickerComponent } from 'app/shared/date-time-picker/date-time-picker.component'; @@ -41,7 +41,7 @@ import { DifficultyBadgeComponent } from 'app/exercises/shared/exercise-headers/ import { DocumentationButtonComponent } from 'app/shared/components/documentation-button/documentation-button.component'; import { TitleChannelNameComponent } from 'app/shared/form/title-channel-name/title-channel-name.component'; import { UMLDiagramType } from '@ls1intum/apollon'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { MarkdownEditorMonacoComponent } from 'app/shared/markdown-editor/monaco/markdown-editor-monaco.component'; @Component({ diff --git a/src/test/javascript/spec/component/exam/feedback.utils.spec.ts b/src/test/javascript/spec/component/exam/feedback.utils.spec.ts index adf848356db6..5fc2c9311d97 100644 --- a/src/test/javascript/spec/component/exam/feedback.utils.spec.ts +++ b/src/test/javascript/spec/component/exam/feedback.utils.spec.ts @@ -2,7 +2,7 @@ import { prepareFeedbackComponentParameters } from 'app/exercises/shared/feedbac import { ResultTemplateStatus } from 'app/exercises/shared/result/result.utils'; import { AssessmentType } from 'app/entities/assessment-type.model'; import { ExerciseType } from 'app/entities/exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import dayjs from 'dayjs/esm'; import { of } from 'rxjs'; import { MockProvider } from 'ng-mocks'; diff --git a/src/test/javascript/spec/component/exam/manage/exam-exercise-import.component.spec.ts b/src/test/javascript/spec/component/exam/manage/exam-exercise-import.component.spec.ts index 304a86ef1639..38b8d1df5b58 100644 --- a/src/test/javascript/spec/component/exam/manage/exam-exercise-import.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/exam-exercise-import.component.spec.ts @@ -3,12 +3,12 @@ import { ArtemisTestModule } from '../../../test.module'; import { MockModule, MockPipe } from 'ng-mocks'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { FormsModule } from '@angular/forms'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExamExerciseImportComponent } from 'app/exam/manage/exams/exam-exercise-import/exam-exercise-import.component'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; import { FileUploadExercise } from 'app/entities/file-upload-exercise.model'; import { Exercise } from 'app/entities/exercise.model'; diff --git a/src/test/javascript/spec/component/exam/manage/exam-exercise-row-buttons.component.spec.ts b/src/test/javascript/spec/component/exam/manage/exam-exercise-row-buttons.component.spec.ts index fc769df6b8d6..430a59b2f55b 100644 --- a/src/test/javascript/spec/component/exam/manage/exam-exercise-row-buttons.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/exam-exercise-row-buttons.component.spec.ts @@ -2,7 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Router, RouterModule } from '@angular/router'; import { Course } from 'app/entities/course.model'; import { HttpResponse } from '@angular/common/http'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExamExerciseRowButtonsComponent } from 'app/exercises/shared/exam-exercise-row-buttons/exam-exercise-row-buttons.component'; import { DeleteButtonDirective } from 'app/shared/delete-dialog/delete-button.directive'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; diff --git a/src/test/javascript/spec/component/exam/manage/exam-import.component.spec.ts b/src/test/javascript/spec/component/exam/manage/exam-import.component.spec.ts index c743acdb5e98..b0476cd518fe 100644 --- a/src/test/javascript/spec/component/exam/manage/exam-import.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/exam-import.component.spec.ts @@ -3,7 +3,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule } from '@angular/forms'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { AlertService } from 'app/core/util/alert.service'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; diff --git a/src/test/javascript/spec/component/exam/manage/exam-management-resolve.spec.ts b/src/test/javascript/spec/component/exam/manage/exam-management-resolve.spec.ts index c3a2ed6b9848..9c7482c9fe6f 100644 --- a/src/test/javascript/spec/component/exam/manage/exam-management-resolve.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/exam-management-resolve.spec.ts @@ -6,7 +6,7 @@ import { MockProvider } from 'ng-mocks'; import { of } from 'rxjs'; import { HttpResponse } from '@angular/common/http'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { StudentExamService } from 'app/exam/manage/student-exams/student-exam.service'; import { ExerciseGroupService } from 'app/exam/manage/exercise-groups/exercise-group.service'; import { StudentExamWithGradeDTO } from 'app/exam/exam-scores/exam-score-dtos.model'; diff --git a/src/test/javascript/spec/component/exam/manage/exam-management.component.spec.ts b/src/test/javascript/spec/component/exam/manage/exam-management.component.spec.ts index ecd81a41c681..b5601206f621 100644 --- a/src/test/javascript/spec/component/exam/manage/exam-management.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/exam-management.component.spec.ts @@ -10,11 +10,11 @@ import { TranslateService } from '@ngx-translate/core'; import { ActivatedRoute, Router, UrlSegment, convertToParamMap } from '@angular/router'; import { Course } from 'app/entities/course.model'; import { ExamManagementComponent } from 'app/exam/manage/exam-management.component'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { CourseManagementService } from 'app/course/manage/course-management.service'; import { SortService } from 'app/shared/service/sort.service'; -import { ExamInformationDTO } from 'app/entities/exam-information.model'; +import { ExamInformationDTO } from 'app/entities/exam/exam-information.model'; import { EventManager } from 'app/core/util/event-manager.service'; import { HasAnyAuthorityDirective } from 'app/shared/auth/has-any-authority.directive'; import { MockDirective, MockPipe } from 'ng-mocks'; diff --git a/src/test/javascript/spec/component/exam/manage/exam-management.service.spec.ts b/src/test/javascript/spec/component/exam/manage/exam-management.service.spec.ts index a452d76c4a7b..747d87a8a3c5 100644 --- a/src/test/javascript/spec/component/exam/manage/exam-management.service.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/exam-management.service.spec.ts @@ -3,19 +3,19 @@ import { HttpClientTestingModule, HttpTestingController } from '@angular/common/ import { Course } from 'app/entities/course.model'; import { ArtemisTestModule } from '../../../test.module'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import dayjs from 'dayjs/esm'; -import { ExamInformationDTO } from 'app/entities/exam-information.model'; +import { ExamInformationDTO } from 'app/entities/exam/exam-information.model'; import { StudentDTO } from 'app/entities/student-dto.model'; import { StudentExam } from 'app/entities/student-exam.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { ExamScoreDTO } from 'app/exam/exam-scores/exam-score-dtos.model'; import { StatsForDashboard } from 'app/course/dashboards/stats-for-dashboard.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { AccountService } from 'app/core/auth/account.service'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { UMLDiagramType } from '@ls1intum/apollon'; describe('Exam Management Service Tests', () => { diff --git a/src/test/javascript/spec/component/exam/manage/exam-students-attendance-check.component.spec.ts b/src/test/javascript/spec/component/exam/manage/exam-students-attendance-check.component.spec.ts index 1e6b737b7266..dfe43434b530 100644 --- a/src/test/javascript/spec/component/exam/manage/exam-students-attendance-check.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/exam-students-attendance-check.component.spec.ts @@ -4,8 +4,8 @@ import { RouterTestingModule } from '@angular/router/testing'; import { TranslateService } from '@ngx-translate/core'; import { User } from 'app/core/user/user.model'; import { Course } from 'app/entities/course.model'; -import { ExamUserAttendanceCheckDTO } from 'app/entities/exam-users-attendance-check-dto.model'; -import { Exam } from 'app/entities/exam.model'; +import { ExamUserAttendanceCheckDTO } from 'app/entities/exam/exam-users-attendance-check-dto.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { ExamStudentsAttendanceCheckComponent } from 'app/exam/manage/students/verify-attendance-check/exam-students-attendance-check.component'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; diff --git a/src/test/javascript/spec/component/exam/manage/exam-students.component.spec.ts b/src/test/javascript/spec/component/exam/manage/exam-students.component.spec.ts index 048b06c65333..58a448041153 100644 --- a/src/test/javascript/spec/component/exam/manage/exam-students.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/exam-students.component.spec.ts @@ -7,7 +7,7 @@ import { NgxDatatableModule } from '@flaviosantoro92/ngx-datatable'; import { User } from 'app/core/user/user.model'; import { UserService } from 'app/core/user/user.service'; import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { ExamStudentsComponent } from 'app/exam/manage/students/exam-students.component'; import { StudentsUploadImagesButtonComponent } from 'app/exam/manage/students/upload-images/students-upload-images-button.component'; @@ -20,8 +20,8 @@ import { MockTranslateService } from '../../../helpers/mocks/service/mock-transl import { ArtemisTestModule } from '../../../test.module'; import { UsersImportButtonComponent } from 'app/shared/user-import/users-import-button.component'; import { TranslateDirective } from 'app/shared/language/translate.directive'; -import { ExamUserDTO } from 'app/entities/exam-user-dto.model'; -import { ExamUser } from 'app/entities/exam-user.model'; +import { ExamUserDTO } from 'app/entities/exam/exam-user-dto.model'; +import { ExamUser } from 'app/entities/exam/exam-user.model'; describe('ExamStudentsComponent', () => { const course = { id: 1 } as Course; diff --git a/src/test/javascript/spec/component/exam/manage/exams/exam-announcement-dialog/exam-live-announcement-create-button.component.spec.ts b/src/test/javascript/spec/component/exam/manage/exams/exam-announcement-dialog/exam-live-announcement-create-button.component.spec.ts index 1c31b7cd263f..09c6836b7cbb 100644 --- a/src/test/javascript/spec/component/exam/manage/exams/exam-announcement-dialog/exam-live-announcement-create-button.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/exams/exam-announcement-dialog/exam-live-announcement-create-button.component.spec.ts @@ -1,7 +1,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { AlertService } from 'app/core/util/alert.service'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { faBullhorn } from '@fortawesome/free-solid-svg-icons'; import dayjs from 'dayjs/esm'; import { By } from '@angular/platform-browser'; diff --git a/src/test/javascript/spec/component/exam/manage/exams/exam-checklist.component.spec.ts b/src/test/javascript/spec/component/exam/manage/exams/exam-checklist.component.spec.ts index 317ab262a4a9..814df06dd42b 100644 --- a/src/test/javascript/spec/component/exam/manage/exams/exam-checklist.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/exams/exam-checklist.component.spec.ts @@ -1,6 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { ExamChecklist } from 'app/entities/exam-checklist.model'; -import { Exam } from 'app/entities/exam.model'; +import { ExamChecklist } from 'app/entities/exam/exam-checklist.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExamChecklistExerciseGroupTableComponent } from 'app/exam/manage/exams/exam-checklist-component/exam-checklist-exercisegroup-table/exam-checklist-exercisegroup-table.component'; import { ExamChecklistComponent } from 'app/exam/manage/exams/exam-checklist-component/exam-checklist.component'; import { ProgressBarComponent } from 'app/shared/dashboards/tutor-participation-graph/progress-bar/progress-bar.component'; diff --git a/src/test/javascript/spec/component/exam/manage/exams/exam-detail.component.spec.ts b/src/test/javascript/spec/component/exam/manage/exams/exam-detail.component.spec.ts index 211c90093b8b..9d29bcdc9a23 100644 --- a/src/test/javascript/spec/component/exam/manage/exams/exam-detail.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/exams/exam-detail.component.spec.ts @@ -8,7 +8,7 @@ import { RouterTestingModule } from '@angular/router/testing'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { AccountService } from 'app/core/auth/account.service'; import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ChecklistCheckComponent } from 'app/shared/components/checklist-check.component'; import { ExamChecklistExerciseGroupTableComponent } from 'app/exam/manage/exams/exam-checklist-component/exam-checklist-exercisegroup-table/exam-checklist-exercisegroup-table.component'; import { ExamChecklistComponent } from 'app/exam/manage/exams/exam-checklist-component/exam-checklist.component'; diff --git a/src/test/javascript/spec/component/exam/manage/exercise-groups/exercise-group-update.component.spec.ts b/src/test/javascript/spec/component/exam/manage/exercise-groups/exercise-group-update.component.spec.ts index 8ca421927fb9..900f896fa97a 100644 --- a/src/test/javascript/spec/component/exam/manage/exercise-groups/exercise-group-update.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/exercise-groups/exercise-group-update.component.spec.ts @@ -6,7 +6,7 @@ import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { TranslateService } from '@ngx-translate/core'; import { EntityResponseType } from 'app/complaints/complaint.service'; import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { ExerciseGroupUpdateComponent } from 'app/exam/manage/exercise-groups/exercise-group-update.component'; import { ExerciseGroupService } from 'app/exam/manage/exercise-groups/exercise-group.service'; diff --git a/src/test/javascript/spec/component/exam/manage/exercise-groups/exercise-groups.component.spec.ts b/src/test/javascript/spec/component/exam/manage/exercise-groups/exercise-groups.component.spec.ts index cc5dd2cb5225..040752cb4ffb 100644 --- a/src/test/javascript/spec/component/exam/manage/exercise-groups/exercise-groups.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/exercise-groups/exercise-groups.component.spec.ts @@ -7,8 +7,8 @@ import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; import { AlertService } from 'app/core/util/alert.service'; import { EventManager } from 'app/core/util/event-manager.service'; import { Course } from 'app/entities/course.model'; -import { ExamInformationDTO } from 'app/entities/exam-information.model'; -import { Exam } from 'app/entities/exam.model'; +import { ExamInformationDTO } from 'app/entities/exam/exam-information.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; diff --git a/src/test/javascript/spec/component/exam/manage/exercise-groups/programming-exercise-group-cell.component.spec.ts b/src/test/javascript/spec/component/exam/manage/exercise-groups/programming-exercise-group-cell.component.spec.ts index 43d15f8f8634..499338bffb52 100644 --- a/src/test/javascript/spec/component/exam/manage/exercise-groups/programming-exercise-group-cell.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/exercise-groups/programming-exercise-group-cell.component.spec.ts @@ -5,7 +5,7 @@ import { ProgrammingExerciseGroupCellComponent } from 'app/exam/manage/exercise- import { ProfileService } from 'app/shared/layouts/profiles/profile.service'; import { ExerciseType } from 'app/entities/exercise.model'; import { By } from '@angular/platform-browser'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { TranslatePipeMock } from '../../../../helpers/mocks/service/mock-translate.service'; import { of } from 'rxjs'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; diff --git a/src/test/javascript/spec/component/exam/manage/programming-exam-diff.component.spec.ts b/src/test/javascript/spec/component/exam/manage/programming-exam-diff.component.spec.ts index e4ecca13e935..cb10c66e1574 100644 --- a/src/test/javascript/spec/component/exam/manage/programming-exam-diff.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/programming-exam-diff.component.spec.ts @@ -4,7 +4,7 @@ import { ArtemisTestModule } from '../../../test.module'; import { CommitsInfoComponent } from 'app/exercises/programming/shared/commits-info/commits-info.component'; import { MockComponent, MockPipe } from 'ng-mocks'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { of } from 'rxjs'; import { ProgrammingExerciseGitDiffReport } from 'app/entities/hestia/programming-exercise-git-diff-report.model'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; diff --git a/src/test/javascript/spec/component/exam/manage/student-exams/exam-status.component.spec.ts b/src/test/javascript/spec/component/exam/manage/student-exams/exam-status.component.spec.ts index 213d77fac9b6..453df0f6be55 100644 --- a/src/test/javascript/spec/component/exam/manage/student-exams/exam-status.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/student-exams/exam-status.component.spec.ts @@ -5,12 +5,12 @@ import { MockPipe } from 'ng-mocks'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { ArtemisDatePipe } from 'app/shared/pipes/artemis-date.pipe'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import dayjs from 'dayjs/esm'; import { MockTranslateService } from '../../../../helpers/mocks/service/mock-translate.service'; import { TranslateService } from '@ngx-translate/core'; import { MockExamChecklistService } from '../../../../helpers/mocks/service/mock-exam-checklist.service'; -import { ExamChecklist } from 'app/entities/exam-checklist.model'; +import { ExamChecklist } from 'app/entities/exam/exam-checklist.model'; import { of } from 'rxjs'; import { Course } from 'app/entities/course.model'; import { JhiWebsocketService } from 'app/core/websocket/websocket.service'; diff --git a/src/test/javascript/spec/component/exam/manage/student-exams/student-exam-detail-table-row.component.spec.ts b/src/test/javascript/spec/component/exam/manage/student-exams/student-exam-detail-table-row.component.spec.ts index d7cd5e7161e6..22cdaf2eb531 100644 --- a/src/test/javascript/spec/component/exam/manage/student-exams/student-exam-detail-table-row.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/student-exams/student-exam-detail-table-row.component.spec.ts @@ -9,11 +9,11 @@ import { ReactiveFormsModule } from '@angular/forms'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; import { ParticipationType } from 'app/entities/participation/participation.model'; import { Result } from 'app/entities/result.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; import { FileUploadExercise } from 'app/entities/file-upload-exercise.model'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; diff --git a/src/test/javascript/spec/component/exam/manage/student-exams/student-exam-detail.component.spec.ts b/src/test/javascript/spec/component/exam/manage/student-exams/student-exam-detail.component.spec.ts index ae4ca95910a7..531f3d5aef50 100644 --- a/src/test/javascript/spec/component/exam/manage/student-exams/student-exam-detail.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/student-exams/student-exam-detail.component.spec.ts @@ -17,7 +17,7 @@ import { NgForm, NgModel, ReactiveFormsModule } from '@angular/forms'; import { Exercise } from 'app/entities/exercise.model'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import dayjs from 'dayjs/esm'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; import { ParticipationType } from 'app/entities/participation/participation.model'; diff --git a/src/test/javascript/spec/component/exam/manage/student-exams/student-exam-summary.component.spec.ts b/src/test/javascript/spec/component/exam/manage/student-exams/student-exam-summary.component.spec.ts index fe4ee6e5d5eb..07ff99eac312 100644 --- a/src/test/javascript/spec/component/exam/manage/student-exams/student-exam-summary.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/student-exams/student-exam-summary.component.spec.ts @@ -4,7 +4,7 @@ import { MockComponent } from 'ng-mocks'; import { Course } from 'app/entities/course.model'; import { of } from 'rxjs'; import { StudentExam } from 'app/entities/student-exam.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { StudentExamSummaryComponent } from 'app/exam/manage/student-exams/student-exam-summary.component'; import { ExamResultSummaryComponent } from 'app/exam/participate/summary/exam-result-summary.component'; diff --git a/src/test/javascript/spec/component/exam/manage/student-exams/student-exam-timeline.component.spec.ts b/src/test/javascript/spec/component/exam/manage/student-exams/student-exam-timeline.component.spec.ts index 09cc4dee6962..e28f9b6390ca 100644 --- a/src/test/javascript/spec/component/exam/manage/student-exams/student-exam-timeline.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/student-exams/student-exam-timeline.component.spec.ts @@ -4,7 +4,7 @@ import { MockComponent, MockPipe } from 'ng-mocks'; import { Course } from 'app/entities/course.model'; import { Observable, of } from 'rxjs'; import { StudentExam } from 'app/entities/student-exam.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { StudentExamTimelineComponent } from 'app/exam/manage/student-exams/student-exam-timeline/student-exam-timeline.component'; import { ModelingExamSubmissionComponent } from 'app/exam/participate/exercises/modeling/modeling-exam-submission.component'; import { TextExamSubmissionComponent } from 'app/exam/participate/exercises/text/text-exam-submission.component'; @@ -16,14 +16,14 @@ import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { ExamNavigationBarComponent } from 'app/exam/participate/exam-navigation-bar/exam-navigation-bar.component'; import { MockTranslateValuesDirective } from '../../../../helpers/mocks/directive/mock-translate-values.directive'; import { EntityArrayResponseType, SubmissionService } from 'app/exercises/shared/submission/submission.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { FileUploadExercise } from 'app/entities/file-upload-exercise.model'; import dayjs from 'dayjs/esm'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { FileUploadSubmission } from 'app/entities/file-upload-submission.model'; import { SubmissionVersion } from 'app/entities/submission-version.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { Submission } from 'app/entities/submission.model'; import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { MockLocalStorageService } from '../../../../helpers/mocks/service/mock-local-storage.service'; diff --git a/src/test/javascript/spec/component/exam/manage/student-exams/student-exams.component.spec.ts b/src/test/javascript/spec/component/exam/manage/student-exams/student-exams.component.spec.ts index 1534c947d717..c5fbbc5b1a02 100644 --- a/src/test/javascript/spec/component/exam/manage/student-exams/student-exams.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/student-exams/student-exams.component.spec.ts @@ -16,7 +16,7 @@ import { Course } from 'app/entities/course.model'; import { of, throwError } from 'rxjs'; import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; import { StudentExam } from 'app/entities/student-exam.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { User } from 'app/core/user/user.model'; import dayjs from 'dayjs/esm'; import { By } from '@angular/platform-browser'; diff --git a/src/test/javascript/spec/component/exam/manage/student-exams/students-upload-images-button.component.spec.ts b/src/test/javascript/spec/component/exam/manage/student-exams/students-upload-images-button.component.spec.ts index 3a2b4012bc1f..918148de4548 100644 --- a/src/test/javascript/spec/component/exam/manage/student-exams/students-upload-images-button.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/student-exams/students-upload-images-button.component.spec.ts @@ -3,7 +3,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MockComponent, MockModule, MockProvider } from 'ng-mocks'; import { AlertService } from 'app/core/util/alert.service'; import { TranslateModule } from '@ngx-translate/core'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { By } from '@angular/platform-browser'; import { NgbModal, NgbModalRef, NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { ButtonComponent } from 'app/shared/components/button.component'; diff --git a/src/test/javascript/spec/component/exam/manage/student-exams/students-upload-images-dialog.component.spec.ts b/src/test/javascript/spec/component/exam/manage/student-exams/students-upload-images-dialog.component.spec.ts index f0c4be9a98ce..c96fe070e773 100644 --- a/src/test/javascript/spec/component/exam/manage/student-exams/students-upload-images-dialog.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/student-exams/students-upload-images-dialog.component.spec.ts @@ -4,7 +4,7 @@ import { FormsModule } from '@angular/forms'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { StudentsUploadImagesDialogComponent } from 'app/exam/manage/students/upload-images/students-upload-images-dialog.component'; import { HelpIconComponent } from 'app/shared/components/help-icon.component'; diff --git a/src/test/javascript/spec/component/exam/manage/student-exams/user-import-button.component.spec.ts b/src/test/javascript/spec/component/exam/manage/student-exams/user-import-button.component.spec.ts index ca19b1567ba3..e803ff5deb7f 100644 --- a/src/test/javascript/spec/component/exam/manage/student-exams/user-import-button.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/student-exams/user-import-button.component.spec.ts @@ -2,7 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MockComponent, MockModule, MockProvider } from 'ng-mocks'; import { AlertService } from 'app/core/util/alert.service'; import { TranslateModule } from '@ngx-translate/core'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { By } from '@angular/platform-browser'; import { NgbModal, NgbModalRef, NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { ButtonComponent } from 'app/shared/components/button.component'; diff --git a/src/test/javascript/spec/component/exam/manage/student-exams/user-import-dialog.component.spec.ts b/src/test/javascript/spec/component/exam/manage/student-exams/user-import-dialog.component.spec.ts index 0541146c9d95..4f97eab7cc62 100644 --- a/src/test/javascript/spec/component/exam/manage/student-exams/user-import-dialog.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/student-exams/user-import-dialog.component.spec.ts @@ -5,7 +5,7 @@ import { By } from '@angular/platform-browser'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { HelpIconComponent } from 'app/shared/components/help-icon.component'; import { TranslateDirective } from 'app/shared/language/translate.directive'; @@ -19,7 +19,7 @@ import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { Router } from '@angular/router'; import * as fs from 'fs'; import * as path from 'path'; -import { ExamUserDTO } from 'app/entities/exam-user-dto.model'; +import { ExamUserDTO } from 'app/entities/exam/exam-user-dto.model'; describe('UsersImportDialogComponent', () => { let fixture: ComponentFixture; diff --git a/src/test/javascript/spec/component/exam/manage/suspicious-behavior/suspicious-behavior.component.spec.ts b/src/test/javascript/spec/component/exam/manage/suspicious-behavior/suspicious-behavior.component.spec.ts index ae26c8a72e3b..b7586940ad52 100644 --- a/src/test/javascript/spec/component/exam/manage/suspicious-behavior/suspicious-behavior.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/suspicious-behavior/suspicious-behavior.component.spec.ts @@ -14,7 +14,7 @@ import { ButtonComponent } from 'app/shared/components/button.component'; import { MockRouterLinkDirective } from '../../../../helpers/mocks/directive/mock-router-link.directive'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { Exercise } from 'app/entities/exercise.model'; -import { SuspiciousExamSessions, SuspiciousSessionReason } from 'app/entities/exam-session.model'; +import { SuspiciousExamSessions, SuspiciousSessionReason } from 'app/entities/exam/exam-session.model'; import { MockRouter } from '../../../../helpers/mocks/mock-router'; import { FormsModule } from '@angular/forms'; import { DocumentationButtonComponent } from 'app/shared/components/documentation-button/documentation-button.component'; diff --git a/src/test/javascript/spec/component/exam/manage/suspicious-behavior/suspicious-sessions-overview.component.spec.ts b/src/test/javascript/spec/component/exam/manage/suspicious-behavior/suspicious-sessions-overview.component.spec.ts index 3676e637591f..f375ca4fb6cc 100644 --- a/src/test/javascript/spec/component/exam/manage/suspicious-behavior/suspicious-sessions-overview.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/suspicious-behavior/suspicious-sessions-overview.component.spec.ts @@ -1,6 +1,6 @@ import { ComponentFixture, TestBed, fakeAsync } from '@angular/core/testing'; import { SuspiciousSessionsOverviewComponent } from 'app/exam/manage/suspicious-behavior/suspicious-sessions-overview/suspicious-sessions-overview.component'; -import { SuspiciousExamSessions, SuspiciousSessionReason } from 'app/entities/exam-session.model'; +import { SuspiciousExamSessions, SuspiciousSessionReason } from 'app/entities/exam/exam-session.model'; import { ArtemisTestModule } from '../../../../test.module'; import { MockComponent, MockDirective, MockPipe } from 'ng-mocks'; import { SuspiciousSessionsComponent } from 'app/exam/manage/suspicious-behavior/suspicious-sessions/suspicious-sessions.component'; diff --git a/src/test/javascript/spec/component/exam/manage/suspicious-behavior/suspicious-sessions.component.spec.ts b/src/test/javascript/spec/component/exam/manage/suspicious-behavior/suspicious-sessions.component.spec.ts index 68d38513ba77..8024d4a251c2 100644 --- a/src/test/javascript/spec/component/exam/manage/suspicious-behavior/suspicious-sessions.component.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/suspicious-behavior/suspicious-sessions.component.spec.ts @@ -4,7 +4,7 @@ import { SuspiciousSessionsComponent } from 'app/exam/manage/suspicious-behavior import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { MockPipe } from 'ng-mocks'; import { StudentExam } from 'app/entities/student-exam.model'; -import { SuspiciousExamSessions, SuspiciousSessionReason } from 'app/entities/exam-session.model'; +import { SuspiciousExamSessions, SuspiciousSessionReason } from 'app/entities/exam/exam-session.model'; import { ArtemisDatePipe } from 'app/shared/pipes/artemis-date.pipe'; import { ArtemisTestModule } from '../../../../test.module'; diff --git a/src/test/javascript/spec/component/exam/manage/suspicious-behavior/suspicious-sessions.service.spec.ts b/src/test/javascript/spec/component/exam/manage/suspicious-behavior/suspicious-sessions.service.spec.ts index bc1e1522f292..0760f147551b 100644 --- a/src/test/javascript/spec/component/exam/manage/suspicious-behavior/suspicious-sessions.service.spec.ts +++ b/src/test/javascript/spec/component/exam/manage/suspicious-behavior/suspicious-sessions.service.spec.ts @@ -2,7 +2,7 @@ import { HttpClientTestingModule, HttpTestingController } from '@angular/common/ import { TestBed, fakeAsync, tick } from '@angular/core/testing'; import { SuspiciousSessionsService } from 'app/exam/manage/suspicious-behavior/suspicious-sessions.service'; -import { SuspiciousExamSessions, SuspiciousSessionReason, SuspiciousSessionsAnalysisOptions } from 'app/entities/exam-session.model'; +import { SuspiciousExamSessions, SuspiciousSessionReason, SuspiciousSessionsAnalysisOptions } from 'app/entities/exam/exam-session.model'; describe('SuspiciousSessionsService', () => { let service: SuspiciousSessionsService; diff --git a/src/test/javascript/spec/component/exam/participate/exam-bar.component.spec.ts b/src/test/javascript/spec/component/exam/participate/exam-bar.component.spec.ts index 2c187f95b291..03eb5e090d94 100644 --- a/src/test/javascript/spec/component/exam/participate/exam-bar.component.spec.ts +++ b/src/test/javascript/spec/component/exam/participate/exam-bar.component.spec.ts @@ -12,7 +12,7 @@ import { MockSyncStorage } from '../../../helpers/mocks/service/mock-sync-storag import { TranslateService } from '@ngx-translate/core'; import { ExamBarComponent } from 'app/exam/participate/exam-bar/exam-bar.component'; import { MockResizeObserver } from '../../../helpers/mocks/service/mock-resize-observer'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { StudentExam } from 'app/entities/student-exam.model'; describe('ExamBarComponent', () => { diff --git a/src/test/javascript/spec/component/exam/participate/exam-navigation-bar.component.spec.ts b/src/test/javascript/spec/component/exam/participate/exam-navigation-bar.component.spec.ts index fb8f91a5ba57..40c65e3f008d 100644 --- a/src/test/javascript/spec/component/exam/participate/exam-navigation-bar.component.spec.ts +++ b/src/test/javascript/spec/component/exam/participate/exam-navigation-bar.component.spec.ts @@ -2,7 +2,7 @@ import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testin import dayjs from 'dayjs/esm'; import { MockComponent, MockDirective, MockModule } from 'ng-mocks'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; -import { ExamSession } from 'app/entities/exam-session.model'; +import { ExamSession } from 'app/entities/exam/exam-session.model'; import { of } from 'rxjs'; import { ExamNavigationBarComponent } from 'app/exam/participate/exam-navigation-bar/exam-navigation-bar.component'; import { CodeEditorRepositoryService } from 'app/exercises/programming/shared/code-editor/service/code-editor-repository.service'; diff --git a/src/test/javascript/spec/component/exam/participate/exam-navigation-sidebar.component.spec.ts b/src/test/javascript/spec/component/exam/participate/exam-navigation-sidebar.component.spec.ts index 9e2e2cf7b70d..45ce49fc2b4d 100644 --- a/src/test/javascript/spec/component/exam/participate/exam-navigation-sidebar.component.spec.ts +++ b/src/test/javascript/spec/component/exam/participate/exam-navigation-sidebar.component.spec.ts @@ -1,7 +1,7 @@ import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; import { MockComponent, MockModule } from 'ng-mocks'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; -import { ExamSession } from 'app/entities/exam-session.model'; +import { ExamSession } from 'app/entities/exam/exam-session.model'; import { of } from 'rxjs'; import { ExamNavigationSidebarComponent } from 'app/exam/participate/exam-navigation-sidebar/exam-navigation-sidebar.component'; import { CodeEditorRepositoryService } from 'app/exercises/programming/shared/code-editor/service/code-editor-repository.service'; diff --git a/src/test/javascript/spec/component/exam/participate/exam-participation-cover.component.spec.ts b/src/test/javascript/spec/component/exam/participate/exam-participation-cover.component.spec.ts index 9e7b34dedae5..4f5514b08626 100644 --- a/src/test/javascript/spec/component/exam/participate/exam-participation-cover.component.spec.ts +++ b/src/test/javascript/spec/component/exam/participate/exam-participation-cover.component.spec.ts @@ -7,7 +7,7 @@ import { TranslateService } from '@ngx-translate/core'; import { AccountService } from 'app/core/auth/account.service'; import { User } from 'app/core/user/user.model'; import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; import { StudentExam } from 'app/entities/student-exam.model'; import { ExamParticipationCoverComponent } from 'app/exam/participate/exam-cover/exam-participation-cover.component'; diff --git a/src/test/javascript/spec/component/exam/participate/exam-participation.component.spec.ts b/src/test/javascript/spec/component/exam/participate/exam-participation.component.spec.ts index 4742c845c8ad..de433ab78169 100644 --- a/src/test/javascript/spec/component/exam/participate/exam-participation.component.spec.ts +++ b/src/test/javascript/spec/component/exam/participate/exam-participation.component.spec.ts @@ -9,20 +9,20 @@ import { JhiWebsocketService } from 'app/core/websocket/websocket.service'; import { CourseManagementService } from 'app/course/manage/course-management.service'; import { CourseStorageService } from 'app/course/manage/course-storage.service'; import { Course } from 'app/entities/course.model'; -import { ExamPage } from 'app/entities/exam-page.model'; -import { Exam } from 'app/entities/exam.model'; +import { ExamPage } from 'app/entities/exam/exam-page.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; import { ModelingSubmission } from 'app/entities/modeling-submission.model'; import { InitializationState } from 'app/entities/participation/participation.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; import { QuizSubmission } from 'app/entities/quiz/quiz-submission.model'; import { StudentExam } from 'app/entities/student-exam.model'; import { Submission } from 'app/entities/submission.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { ExamExerciseUpdateService } from 'app/exam/manage/exam-exercise-update.service'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { TestRunRibbonComponent } from 'app/exam/manage/test-runs/test-run-ribbon.component'; diff --git a/src/test/javascript/spec/component/exam/participate/exam-start-information/exam-start-information.component.spec.ts b/src/test/javascript/spec/component/exam/participate/exam-start-information/exam-start-information.component.spec.ts index 5f3b9f04df78..6332ee962a6c 100644 --- a/src/test/javascript/spec/component/exam/participate/exam-start-information/exam-start-information.component.spec.ts +++ b/src/test/javascript/spec/component/exam/participate/exam-start-information/exam-start-information.component.spec.ts @@ -1,7 +1,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; import { User } from 'app/core/user/user.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { StudentExam } from 'app/entities/student-exam.model'; import { ExamStartInformationComponent } from 'app/exam/participate/exam-start-information/exam-start-information.component'; import { InformationBoxComponent } from 'app/shared/information-box/information-box.component'; diff --git a/src/test/javascript/spec/component/exam/participate/exam.utils.spec.ts b/src/test/javascript/spec/component/exam/participate/exam.utils.spec.ts index 1254b6abcb98..2f75558e228f 100644 --- a/src/test/javascript/spec/component/exam/participate/exam.utils.spec.ts +++ b/src/test/javascript/spec/component/exam/participate/exam.utils.spec.ts @@ -2,7 +2,7 @@ import { isExamResultPublished } from 'app/exam/participate/exam.utils'; import { ArtemisServerDateService } from 'app/shared/server-date.service'; import { MockArtemisServerDateService } from '../../../helpers/mocks/service/mock-server-date.service'; import { TestBed } from '@angular/core/testing'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import dayjs from 'dayjs/esm'; let artemisServerDateService: ArtemisServerDateService; diff --git a/src/test/javascript/spec/component/exam/participate/exercises/programming-exam-submission.component.spec.ts b/src/test/javascript/spec/component/exam/participate/exercises/programming-exam-submission.component.spec.ts index bcd570d8c8a2..ad5c65c27275 100644 --- a/src/test/javascript/spec/component/exam/participate/exercises/programming-exam-submission.component.spec.ts +++ b/src/test/javascript/spec/component/exam/participate/exercises/programming-exam-submission.component.spec.ts @@ -4,8 +4,8 @@ import { MockComponent, MockPipe, MockProvider } from 'ng-mocks'; import { Course } from 'app/entities/course.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { ProgrammingExamSubmissionComponent } from 'app/exam/participate/exercises/programming/programming-exam-submission.component'; import { ModelingEditorComponent } from 'app/exercises/modeling/shared/modeling-editor.component'; import { CodeEditorContainerComponent } from 'app/exercises/programming/shared/code-editor/container/code-editor-container.component'; diff --git a/src/test/javascript/spec/component/exam/participate/exercises/text-exam-submission.component.spec.ts b/src/test/javascript/spec/component/exam/participate/exercises/text-exam-submission.component.spec.ts index 6671fb12acf4..176692131b10 100644 --- a/src/test/javascript/spec/component/exam/participate/exercises/text-exam-submission.component.spec.ts +++ b/src/test/javascript/spec/component/exam/participate/exercises/text-exam-submission.component.spec.ts @@ -3,8 +3,8 @@ import { NgModel } from '@angular/forms'; import { By } from '@angular/platform-browser'; import { Course } from 'app/entities/course.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { TextExamSubmissionComponent } from 'app/exam/participate/exercises/text/text-exam-submission.component'; import { IncludedInScoreBadgeComponent } from 'app/exercises/shared/exercise-headers/included-in-score-badge.component'; import { TextEditorService } from 'app/exercises/text/participate/text-editor.service'; diff --git a/src/test/javascript/spec/component/exam/participate/general-information/exam-general-information.component.spec.ts b/src/test/javascript/spec/component/exam/participate/general-information/exam-general-information.component.spec.ts index 4be44e0709b1..9ead47365e2e 100644 --- a/src/test/javascript/spec/component/exam/participate/general-information/exam-general-information.component.spec.ts +++ b/src/test/javascript/spec/component/exam/participate/general-information/exam-general-information.component.spec.ts @@ -1,7 +1,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; import { User } from 'app/core/user/user.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { StudentExam } from 'app/entities/student-exam.model'; import { ExamGeneralInformationComponent } from 'app/exam/participate/general-information/exam-general-information.component'; import { StudentExamWorkingTimeComponent } from 'app/exam/shared/student-exam-working-time/student-exam-working-time.component'; diff --git a/src/test/javascript/spec/component/exam/participate/summary/exam-result-summary.component.spec.ts b/src/test/javascript/spec/component/exam/participate/summary/exam-result-summary.component.spec.ts index 815e36582b17..a36b5b62eb0e 100644 --- a/src/test/javascript/spec/component/exam/participate/summary/exam-result-summary.component.spec.ts +++ b/src/test/javascript/spec/component/exam/participate/summary/exam-result-summary.component.spec.ts @@ -9,20 +9,20 @@ import { ThemeService } from 'app/core/theme/theme.service'; import { User } from 'app/core/user/user.model'; import { CourseManagementService } from 'app/course/manage/course-management.service'; import { PlagiarismCasesService } from 'app/course/plagiarism-cases/shared/plagiarism-cases.service'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; import { GradeType } from 'app/entities/grading-scale.model'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; import { ModelingSubmission } from 'app/entities/modeling-submission.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; import { QuizSubmission } from 'app/entities/quiz/quiz-submission.model'; import { StudentExam } from 'app/entities/student-exam.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { ExerciseResult, StudentExamWithGradeDTO, StudentResult } from 'app/exam/exam-scores/exam-score-dtos.model'; import { TestRunRibbonComponent } from 'app/exam/manage/test-runs/test-run-ribbon.component'; import { ExamParticipationService } from 'app/exam/participate/exam-participation.service'; diff --git a/src/test/javascript/spec/component/exam/participate/summary/exercises/header/exam-result-summary-exercise-card-header.component.spec.ts b/src/test/javascript/spec/component/exam/participate/summary/exercises/header/exam-result-summary-exercise-card-header.component.spec.ts index 2fd0a02f46d8..b5a588f2f83f 100644 --- a/src/test/javascript/spec/component/exam/participate/summary/exercises/header/exam-result-summary-exercise-card-header.component.spec.ts +++ b/src/test/javascript/spec/component/exam/participate/summary/exercises/header/exam-result-summary-exercise-card-header.component.spec.ts @@ -2,12 +2,12 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { User } from 'app/core/user/user.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { SubmissionType } from 'app/entities/submission.model'; import { TranslateDirective } from 'app/shared/language/translate.directive'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; diff --git a/src/test/javascript/spec/component/exam/participate/summary/exercises/programming-exam-summary.component.spec.ts b/src/test/javascript/spec/component/exam/participate/summary/exercises/programming-exam-summary.component.spec.ts index deaa197ba1b6..6d8d7327aed3 100644 --- a/src/test/javascript/spec/component/exam/participate/summary/exercises/programming-exam-summary.component.spec.ts +++ b/src/test/javascript/spec/component/exam/participate/summary/exercises/programming-exam-summary.component.spec.ts @@ -9,11 +9,11 @@ import { ComplaintsStudentViewComponent } from 'app/complaints/complaints-for-st import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; import { ExerciseCacheService } from 'app/exercises/shared/exercise/exercise-cache.service'; import { ProfileService } from 'app/shared/layouts/profiles/profile.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { User } from 'app/core/user/user.model'; import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { ProfileInfo } from 'app/shared/layouts/profiles/profile-info.model'; diff --git a/src/test/javascript/spec/component/exam/participate/summary/exercises/quiz-exam-summary.component.spec.ts b/src/test/javascript/spec/component/exam/participate/summary/exercises/quiz-exam-summary.component.spec.ts index a6a54f521bfb..6dc458e8d548 100644 --- a/src/test/javascript/spec/component/exam/participate/summary/exercises/quiz-exam-summary.component.spec.ts +++ b/src/test/javascript/spec/component/exam/participate/summary/exercises/quiz-exam-summary.component.spec.ts @@ -1,7 +1,7 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { TranslateService } from '@ngx-translate/core'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; import { AnswerOption } from 'app/entities/quiz/answer-option.model'; import { DragAndDropMapping } from 'app/entities/quiz/drag-and-drop-mapping.model'; diff --git a/src/test/javascript/spec/component/exam/participate/summary/exercises/text-exam-summary.component.spec.ts b/src/test/javascript/spec/component/exam/participate/summary/exercises/text-exam-summary.component.spec.ts index 7606478c4e1c..cf9a391476c0 100644 --- a/src/test/javascript/spec/component/exam/participate/summary/exercises/text-exam-summary.component.spec.ts +++ b/src/test/javascript/spec/component/exam/participate/summary/exercises/text-exam-summary.component.spec.ts @@ -1,6 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { TextExamSummaryComponent } from 'app/exam/participate/summary/exercises/text-exam-summary/text-exam-summary.component'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { Exercise } from 'app/entities/exercise.model'; import { TextEditorComponent } from 'app/exercises/text/participate/text-editor.component'; import { MockComponent } from 'ng-mocks'; diff --git a/src/test/javascript/spec/component/exam/participate/summary/result-overview/exam-result-overview.component.spec.ts b/src/test/javascript/spec/component/exam/participate/summary/result-overview/exam-result-overview.component.spec.ts index df597333fc63..836d997c7530 100644 --- a/src/test/javascript/spec/component/exam/participate/summary/result-overview/exam-result-overview.component.spec.ts +++ b/src/test/javascript/spec/component/exam/participate/summary/result-overview/exam-result-overview.component.spec.ts @@ -4,14 +4,14 @@ import { RouterTestingModule } from '@angular/router/testing'; import { MockComponent, MockModule, MockPipe, MockProvider } from 'ng-mocks'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { User } from 'app/core/user/user.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExamResultOverviewComponent } from 'app/exam/participate/summary/result-overview/exam-result-overview.component'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; import { ExerciseType, IncludedInOverallScore } from 'app/entities/exercise.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { HttpClientTestingModule } from '@angular/common/http/testing'; import { Result } from 'app/entities/result.model'; diff --git a/src/test/javascript/spec/component/exam/shared/student-exam-working-time.component.spec.ts b/src/test/javascript/spec/component/exam/shared/student-exam-working-time.component.spec.ts index 1c71302e88cc..81da42c6eb6a 100644 --- a/src/test/javascript/spec/component/exam/shared/student-exam-working-time.component.spec.ts +++ b/src/test/javascript/spec/component/exam/shared/student-exam-working-time.component.spec.ts @@ -3,7 +3,7 @@ import { MockPipe } from 'ng-mocks'; import dayjs from 'dayjs/esm'; import { StudentExamWorkingTimeComponent } from 'app/exam/shared/student-exam-working-time/student-exam-working-time.component'; import { ArtemisDurationFromSecondsPipe } from 'app/shared/pipes/artemis-duration-from-seconds.pipe'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { StudentExam } from 'app/entities/student-exam.model'; describe('StudentExamWorkingTimeComponent', () => { diff --git a/src/test/javascript/spec/component/exam/shared/testexam-working-time.component.spec.ts b/src/test/javascript/spec/component/exam/shared/testexam-working-time.component.spec.ts index 7a4817aa9936..b3ca685443bd 100644 --- a/src/test/javascript/spec/component/exam/shared/testexam-working-time.component.spec.ts +++ b/src/test/javascript/spec/component/exam/shared/testexam-working-time.component.spec.ts @@ -2,7 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MockPipe } from 'ng-mocks'; import dayjs from 'dayjs/esm'; import { ArtemisDurationFromSecondsPipe } from 'app/shared/pipes/artemis-duration-from-seconds.pipe'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { StudentExam } from 'app/entities/student-exam.model'; import { TestexamWorkingTimeComponent } from 'app/exam/shared/testExam-workingTime/testexam-working-time.component'; import { round } from 'app/shared/util/utils'; diff --git a/src/test/javascript/spec/component/exam/shared/working-time-control.component.spec.ts b/src/test/javascript/spec/component/exam/shared/working-time-control.component.spec.ts index 75382fcb9e4d..322846cc0bb2 100644 --- a/src/test/javascript/spec/component/exam/shared/working-time-control.component.spec.ts +++ b/src/test/javascript/spec/component/exam/shared/working-time-control.component.spec.ts @@ -2,7 +2,7 @@ import dayjs from 'dayjs/esm'; import { FormsModule } from '@angular/forms'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { WorkingTimeControlComponent } from 'app/exam/shared/working-time-control/working-time-control.component'; const createTestExam = (duration: number) => ({ workingTime: duration, startDate: dayjs.unix(0), endDate: dayjs.unix(duration) }) as Exam; diff --git a/src/test/javascript/spec/component/exam/test-run/create-test-run-modal.component.spec.ts b/src/test/javascript/spec/component/exam/test-run/create-test-run-modal.component.spec.ts index 23f0394ec3f3..4ca659c9076f 100644 --- a/src/test/javascript/spec/component/exam/test-run/create-test-run-modal.component.spec.ts +++ b/src/test/javascript/spec/component/exam/test-run/create-test-run-modal.component.spec.ts @@ -1,5 +1,5 @@ import { ComponentFixture, TestBed, fakeAsync } from '@angular/core/testing'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { Course } from 'app/entities/course.model'; import { CreateTestRunModalComponent } from 'app/exam/manage/test-runs/create-test-run-modal.component'; import dayjs from 'dayjs/esm'; diff --git a/src/test/javascript/spec/component/exam/test-run/test-run-management.component.spec.ts b/src/test/javascript/spec/component/exam/test-run/test-run-management.component.spec.ts index 70e64fbff5d8..40d92651dcfa 100644 --- a/src/test/javascript/spec/component/exam/test-run/test-run-management.component.spec.ts +++ b/src/test/javascript/spec/component/exam/test-run/test-run-management.component.spec.ts @@ -9,7 +9,7 @@ import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { AccountService } from 'app/core/auth/account.service'; import { User } from 'app/core/user/user.model'; import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { Exercise } from 'app/entities/exercise.model'; import { StudentExam } from 'app/entities/student-exam.model'; diff --git a/src/test/javascript/spec/component/exercise-hint/manage/exercise-hint-update.component.spec.ts b/src/test/javascript/spec/component/exercise-hint/manage/exercise-hint-update.component.spec.ts index 2af4e435afaf..4ef9a51082c3 100644 --- a/src/test/javascript/spec/component/exercise-hint/manage/exercise-hint-update.component.spec.ts +++ b/src/test/javascript/spec/component/exercise-hint/manage/exercise-hint-update.component.spec.ts @@ -13,8 +13,8 @@ import { ExerciseHint } from 'app/entities/hestia/exercise-hint.model'; import { ActivatedRoute } from '@angular/router'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; import { ProgrammingExerciseServerSideTask } from 'app/entities/hestia/programming-exercise-task.model'; -import { ProgrammingExerciseTestCase } from 'app/entities/programming-exercise-test-case.model'; -import { ProgrammingExercise, ProgrammingLanguage } from 'app/entities/programming-exercise.model'; +import { ProgrammingExerciseTestCase } from 'app/entities/programming/programming-exercise-test-case.model'; +import { ProgrammingExercise, ProgrammingLanguage } from 'app/entities/programming/programming-exercise.model'; import { CodeHint } from 'app/entities/hestia/code-hint-model'; import { CodeHintService } from 'app/exercises/shared/exercise-hint/services/code-hint.service'; import { ProfileService } from 'app/shared/layouts/profiles/profile.service'; diff --git a/src/test/javascript/spec/component/exercise-hint/manage/exercise-hint.component.spec.ts b/src/test/javascript/spec/component/exercise-hint/manage/exercise-hint.component.spec.ts index 5d9ffdb54ca2..b7b531efa5a8 100644 --- a/src/test/javascript/spec/component/exercise-hint/manage/exercise-hint.component.spec.ts +++ b/src/test/javascript/spec/component/exercise-hint/manage/exercise-hint.component.spec.ts @@ -9,7 +9,7 @@ import { ExerciseHint } from 'app/entities/hestia/exercise-hint.model'; import { ExerciseHintService } from 'app/exercises/shared/exercise-hint/shared/exercise-hint.service'; import { MockActivatedRoute } from '../../../helpers/mocks/activated-route/mock-activated-route'; import { EventManager } from 'app/core/util/event-manager.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; describe('ExerciseHint Management Component', () => { let comp: ExerciseHintComponent; diff --git a/src/test/javascript/spec/component/exercise-hint/participate/exercise-hint-expandable.component.spec.ts b/src/test/javascript/spec/component/exercise-hint/participate/exercise-hint-expandable.component.spec.ts index 9bbadd2c6bb0..0dbdd2699087 100644 --- a/src/test/javascript/spec/component/exercise-hint/participate/exercise-hint-expandable.component.spec.ts +++ b/src/test/javascript/spec/component/exercise-hint/participate/exercise-hint-expandable.component.spec.ts @@ -9,7 +9,7 @@ import { ArtemisTestModule } from '../../../test.module'; import { ExerciseHint } from 'app/entities/hestia/exercise-hint.model'; import { ExerciseHintResponse, ExerciseHintService } from 'app/exercises/shared/exercise-hint/shared/exercise-hint.service'; import { ExerciseHintExpandableComponent } from 'app/exercises/shared/exercise-hint/participate/exercise-hint-expandable.component'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { StarRatingComponent } from 'app/exercises/shared/rating/star-rating/star-rating.component'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { MockTranslateService } from '../../../helpers/mocks/service/mock-translate.service'; diff --git a/src/test/javascript/spec/component/exercise-hint/shared/code-hint-container.component.spec.ts b/src/test/javascript/spec/component/exercise-hint/shared/code-hint-container.component.spec.ts index 745539ab66f3..d7852f272f21 100644 --- a/src/test/javascript/spec/component/exercise-hint/shared/code-hint-container.component.spec.ts +++ b/src/test/javascript/spec/component/exercise-hint/shared/code-hint-container.component.spec.ts @@ -3,7 +3,7 @@ import { ArtemisTestModule } from '../../../test.module'; import { CodeHintContainerComponent } from 'app/exercises/shared/exercise-hint/shared/code-hint-container.component'; import { CodeHint } from 'app/entities/hestia/code-hint-model'; import { ProgrammingExerciseSolutionEntry } from 'app/entities/hestia/programming-exercise-solution-entry.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { CodeHintService } from 'app/exercises/shared/exercise-hint/services/code-hint.service'; describe('ExerciseHint Management Component', () => { diff --git a/src/test/javascript/spec/component/exercises/problem-statement.component.spec.ts b/src/test/javascript/spec/component/exercises/problem-statement.component.spec.ts index dfe3302f9d69..8135e4878ae5 100644 --- a/src/test/javascript/spec/component/exercises/problem-statement.component.spec.ts +++ b/src/test/javascript/spec/component/exercises/problem-statement.component.spec.ts @@ -6,8 +6,8 @@ import { ParticipationService } from 'app/exercises/shared/participation/partici import { HttpResponse } from '@angular/common/http'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; import { Course } from 'app/entities/course.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ProblemStatementComponent } from 'app/overview/exercise-details/problem-statement/problem-statement.component'; import { TranslatePipeMock } from '../../helpers/mocks/service/mock-translate.service'; import { HtmlForMarkdownPipe } from 'app/shared/pipes/html-for-markdown.pipe'; diff --git a/src/test/javascript/spec/component/exercises/quiz/manage/quiz-pool.component.spec.ts b/src/test/javascript/spec/component/exercises/quiz/manage/quiz-pool.component.spec.ts index 598ed280ae94..c3c268ae9481 100644 --- a/src/test/javascript/spec/component/exercises/quiz/manage/quiz-pool.component.spec.ts +++ b/src/test/javascript/spec/component/exercises/quiz/manage/quiz-pool.component.spec.ts @@ -15,7 +15,7 @@ import { MultipleChoiceQuestion } from 'app/entities/quiz/multiple-choice-questi import { QuizGroup } from 'app/entities/quiz/quiz-group.model'; import { NgbModal, NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import dayjs from 'dayjs/esm'; import { QuizPoolMappingComponent } from 'app/exercises/quiz/manage/quiz-pool-mapping.component'; import { QuizQuestionListEditComponent } from 'app/exercises/quiz/manage/quiz-question-list-edit.component'; diff --git a/src/test/javascript/spec/component/exercises/quiz/manage/quiz-question-list-edit-existing.component.spec.ts b/src/test/javascript/spec/component/exercises/quiz/manage/quiz-question-list-edit-existing.component.spec.ts index e0c07d841d71..cac2387f7258 100644 --- a/src/test/javascript/spec/component/exercises/quiz/manage/quiz-question-list-edit-existing.component.spec.ts +++ b/src/test/javascript/spec/component/exercises/quiz/manage/quiz-question-list-edit-existing.component.spec.ts @@ -10,7 +10,7 @@ import { QuizQuestionListEditExistingComponent, State } from 'app/exercises/quiz import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { of } from 'rxjs'; import { HttpResponse } from '@angular/common/http'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { CourseManagementService } from 'app/course/manage/course-management.service'; import { Course } from 'app/entities/course.model'; import { FormsModule } from '@angular/forms'; diff --git a/src/test/javascript/spec/component/exercises/shared/example-submission-import.component.spec.ts b/src/test/javascript/spec/component/exercises/shared/example-submission-import.component.spec.ts index 8a82a0dd3925..4a7188fd906c 100644 --- a/src/test/javascript/spec/component/exercises/shared/example-submission-import.component.spec.ts +++ b/src/test/javascript/spec/component/exercises/shared/example-submission-import.component.spec.ts @@ -4,7 +4,7 @@ import { NgbPagination } from '@ng-bootstrap/ng-bootstrap'; import { TranslateService } from '@ngx-translate/core'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; import { Submission, SubmissionType } from 'app/entities/submission.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { ExampleSubmissionImportPagingService } from 'app/exercises/shared/example-submission/example-submission-import/example-submission-import-paging.service'; import { ExampleSubmissionImportComponent } from 'app/exercises/shared/example-submission/example-submission-import/example-submission-import.component'; import { ExampleSubmissionService } from 'app/exercises/shared/example-submission/example-submission.service'; diff --git a/src/test/javascript/spec/component/exercises/shared/example-submissions.component.spec.ts b/src/test/javascript/spec/component/exercises/shared/example-submissions.component.spec.ts index 0d292309f796..4b40d355f277 100644 --- a/src/test/javascript/spec/component/exercises/shared/example-submissions.component.spec.ts +++ b/src/test/javascript/spec/component/exercises/shared/example-submissions.component.spec.ts @@ -14,7 +14,7 @@ import { TranslateDirective } from 'app/shared/language/translate.directive'; import { ResultComponent } from 'app/exercises/shared/result/result.component'; import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; import { HttpResponse } from '@angular/common/http'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { AlertService } from 'app/core/util/alert.service'; describe('Example Submission Component', () => { diff --git a/src/test/javascript/spec/component/exercises/shared/exercise-scores/exercise-scores-export-button.component.spec.ts b/src/test/javascript/spec/component/exercises/shared/exercise-scores/exercise-scores-export-button.component.spec.ts index 0faee4a0f4c9..4d6e2636cb3d 100644 --- a/src/test/javascript/spec/component/exercises/shared/exercise-scores/exercise-scores-export-button.component.spec.ts +++ b/src/test/javascript/spec/component/exercises/shared/exercise-scores/exercise-scores-export-button.component.spec.ts @@ -7,7 +7,7 @@ import { MockComponent, MockDirective, MockPipe, MockProvider } from 'ng-mocks'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { ResultService } from 'app/exercises/shared/result/result.service'; import { Result } from 'app/entities/result.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap'; import { Course } from 'app/entities/course.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; diff --git a/src/test/javascript/spec/component/exercises/shared/exercise-scores/exercise-scores.component.spec.ts b/src/test/javascript/spec/component/exercises/shared/exercise-scores/exercise-scores.component.spec.ts index c7bd261c1ed2..2bc2d727ee5e 100644 --- a/src/test/javascript/spec/component/exercises/shared/exercise-scores/exercise-scores.component.spec.ts +++ b/src/test/javascript/spec/component/exercises/shared/exercise-scores/exercise-scores.component.spec.ts @@ -11,7 +11,7 @@ import { Exercise, ExerciseType } from 'app/entities/exercise.model'; import { Participation } from 'app/entities/participation/participation.model'; import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { Result } from 'app/entities/result.model'; import { Submission } from 'app/entities/submission.model'; import { Team } from 'app/entities/team.model'; diff --git a/src/test/javascript/spec/component/exercises/shared/exercise-title-channel-name.component.spec.ts b/src/test/javascript/spec/component/exercises/shared/exercise-title-channel-name.component.spec.ts index 23e6a4c7183c..37b91a62f115 100644 --- a/src/test/javascript/spec/component/exercises/shared/exercise-title-channel-name.component.spec.ts +++ b/src/test/javascript/spec/component/exercises/shared/exercise-title-channel-name.component.spec.ts @@ -2,7 +2,7 @@ import { SimpleChange } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { NgForm } from '@angular/forms'; import { Course, CourseInformationSharingConfiguration } from 'app/entities/course.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { ExerciseTitleChannelNameComponent } from 'app/exercises/shared/exercise-title-channel-name/exercise-title-channel-name.component'; import { TitleChannelNameModule } from 'app/shared/form/title-channel-name/title-channel-name.module'; diff --git a/src/test/javascript/spec/component/exercises/shared/headers/difficulty-badge.component.spec.ts b/src/test/javascript/spec/component/exercises/shared/headers/difficulty-badge.component.spec.ts index f1a7ce415e15..0b2b00eff87c 100644 --- a/src/test/javascript/spec/component/exercises/shared/headers/difficulty-badge.component.spec.ts +++ b/src/test/javascript/spec/component/exercises/shared/headers/difficulty-badge.component.spec.ts @@ -2,7 +2,7 @@ import { TestBed } from '@angular/core/testing'; import { TranslateService } from '@ngx-translate/core'; import { MockTranslateService } from '../../../../helpers/mocks/service/mock-translate.service'; import { DifficultyBadgeComponent } from 'app/exercises/shared/exercise-headers/difficulty-badge.component'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { DifficultyLevel } from 'app/entities/exercise.model'; describe('DifficultyBadge', () => { diff --git a/src/test/javascript/spec/component/exercises/shared/headers/header-exercise-page-with-details.component.spec.ts b/src/test/javascript/spec/component/exercises/shared/headers/header-exercise-page-with-details.component.spec.ts index 6682b12aa12c..433069739443 100644 --- a/src/test/javascript/spec/component/exercises/shared/headers/header-exercise-page-with-details.component.spec.ts +++ b/src/test/javascript/spec/component/exercises/shared/headers/header-exercise-page-with-details.component.spec.ts @@ -1,6 +1,6 @@ import { TestBed } from '@angular/core/testing'; import { MockComponent, MockPipe } from 'ng-mocks'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { HeaderExercisePageWithDetailsComponent } from 'app/exercises/shared/exercise-headers/header-exercise-page-with-details.component'; import { NotReleasedTagComponent } from 'app/shared/components/not-released-tag.component'; import { ArtemisTimeAgoPipe } from 'app/shared/pipes/artemis-time-ago.pipe'; @@ -11,10 +11,10 @@ import { IncludedInScoreBadgeComponent } from 'app/exercises/shared/exercise-hea import { ExerciseTypePipe } from 'app/shared/pipes/exercise-type.pipe'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; import { ParticipationType } from 'app/entities/participation/participation.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import dayjs from 'dayjs/esm'; import { ExerciseCategory } from 'app/entities/exercise-category.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { SubmissionType } from 'app/entities/submission.model'; import { Result } from 'app/entities/result.model'; import { LockRepositoryPolicy } from 'app/entities/submission-policy.model'; diff --git a/src/test/javascript/spec/component/exercises/shared/headers/header-participation-page.component.spec.ts b/src/test/javascript/spec/component/exercises/shared/headers/header-participation-page.component.spec.ts index 11e02319eee8..b8e5b4266769 100644 --- a/src/test/javascript/spec/component/exercises/shared/headers/header-participation-page.component.spec.ts +++ b/src/test/javascript/spec/component/exercises/shared/headers/header-participation-page.component.spec.ts @@ -1,6 +1,6 @@ import { TestBed } from '@angular/core/testing'; import { MockComponent, MockPipe } from 'ng-mocks'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ArtemisTimeAgoPipe } from 'app/shared/pipes/artemis-time-ago.pipe'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { DifficultyBadgeComponent } from 'app/exercises/shared/exercise-headers/difficulty-badge.component'; @@ -8,7 +8,7 @@ import { ArtemisTestModule } from '../../../../test.module'; import { IncludedInScoreBadgeComponent } from 'app/exercises/shared/exercise-headers/included-in-score-badge.component'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; import { ParticipationType } from 'app/entities/participation/participation.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { HeaderParticipationPageComponent } from 'app/exercises/shared/exercise-headers/header-participation-page.component'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { ArtemisDatePipe } from 'app/shared/pipes/artemis-date.pipe'; diff --git a/src/test/javascript/spec/component/exercises/shared/result.spec.ts b/src/test/javascript/spec/component/exercises/shared/result.spec.ts index 3314be02465d..782145a2aa63 100644 --- a/src/test/javascript/spec/component/exercises/shared/result.spec.ts +++ b/src/test/javascript/spec/component/exercises/shared/result.spec.ts @@ -13,7 +13,7 @@ import { cloneDeep } from 'lodash-es'; import { Submission } from 'app/entities/submission.model'; import { ExerciseType } from 'app/entities/exercise.model'; import { faQuestionCircle, faTimesCircle } from '@fortawesome/free-regular-svg-icons'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; diff --git a/src/test/javascript/spec/component/exercises/shared/team-config-form-group.component.spec.ts b/src/test/javascript/spec/component/exercises/shared/team-config-form-group.component.spec.ts index 91d124000a49..558987481795 100644 --- a/src/test/javascript/spec/component/exercises/shared/team-config-form-group.component.spec.ts +++ b/src/test/javascript/spec/component/exercises/shared/team-config-form-group.component.spec.ts @@ -1,7 +1,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Exercise, ExerciseMode } from 'app/entities/exercise.model'; import { TeamAssignmentConfig } from 'app/entities/team-assignment-config.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { TeamConfigFormGroupComponent } from 'app/exercises/shared/team-config-form-group/team-config-form-group.component'; import { Subject } from 'rxjs'; diff --git a/src/test/javascript/spec/component/exercises/shared/team-submission-sync.component.spec.ts b/src/test/javascript/spec/component/exercises/shared/team-submission-sync.component.spec.ts index 9fb883b25037..6bab9646a59b 100644 --- a/src/test/javascript/spec/component/exercises/shared/team-submission-sync.component.spec.ts +++ b/src/test/javascript/spec/component/exercises/shared/team-submission-sync.component.spec.ts @@ -14,7 +14,7 @@ import { MockHttpService } from '../../../helpers/mocks/service/mock-http.servic import { HttpClient } from '@angular/common/http'; import { Submission } from 'app/entities/submission.model'; import { Observable, Subject, of } from 'rxjs'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { SubmissionSyncPayload } from 'app/entities/submission-sync-payload.model'; import { User } from 'app/core/user/user.model'; import { AccountService } from 'app/core/auth/account.service'; diff --git a/src/test/javascript/spec/component/file-upload-exercise/file-upload-exercise-update.component.spec.ts b/src/test/javascript/spec/component/file-upload-exercise/file-upload-exercise-update.component.spec.ts index caec2f8dbd54..3579287a3913 100644 --- a/src/test/javascript/spec/component/file-upload-exercise/file-upload-exercise-update.component.spec.ts +++ b/src/test/javascript/spec/component/file-upload-exercise/file-upload-exercise-update.component.spec.ts @@ -17,8 +17,8 @@ import { MockProvider } from 'ng-mocks'; import { MockNgbModalService } from '../../helpers/mocks/service/mock-ngb-modal.service'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import dayjs from 'dayjs/esm'; -import { TextExercise } from 'app/entities/text-exercise.model'; -import { Exam } from 'app/entities/exam.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { fileUploadExercise } from '../../helpers/mocks/service/mock-file-upload-exercise.service'; import { ExerciseTitleChannelNameComponent } from 'app/exercises/shared/exercise-title-channel-name/exercise-title-channel-name.component'; import { TeamConfigFormGroupComponent } from 'app/exercises/shared/team-config-form-group/team-config-form-group.component'; diff --git a/src/test/javascript/spec/component/grading-system/detailed-grading-system.component.spec.ts b/src/test/javascript/spec/component/grading-system/detailed-grading-system.component.spec.ts index 4e3b44045052..7ecabd855b07 100644 --- a/src/test/javascript/spec/component/grading-system/detailed-grading-system.component.spec.ts +++ b/src/test/javascript/spec/component/grading-system/detailed-grading-system.component.spec.ts @@ -14,7 +14,7 @@ import { of } from 'rxjs'; import { HttpResponse } from '@angular/common/http'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { Course } from 'app/entities/course.model'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { CourseManagementService } from 'app/course/manage/course-management.service'; diff --git a/src/test/javascript/spec/component/grading-system/interval-grading-system.component.spec.ts b/src/test/javascript/spec/component/grading-system/interval-grading-system.component.spec.ts index 70f795c2051c..531b3f1f2064 100644 --- a/src/test/javascript/spec/component/grading-system/interval-grading-system.component.spec.ts +++ b/src/test/javascript/spec/component/grading-system/interval-grading-system.component.spec.ts @@ -11,7 +11,7 @@ import { GradeStep } from 'app/entities/grade-step.model'; import { cloneDeep } from 'lodash-es'; import { of } from 'rxjs'; import { ActivatedRoute } from '@angular/router'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { Course } from 'app/entities/course.model'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { CourseManagementService } from 'app/course/manage/course-management.service'; diff --git a/src/test/javascript/spec/component/hestia/generation-overview/code-hint-generation-overview.component.spec.ts b/src/test/javascript/spec/component/hestia/generation-overview/code-hint-generation-overview.component.spec.ts index d34c0758200a..360a08238306 100644 --- a/src/test/javascript/spec/component/hestia/generation-overview/code-hint-generation-overview.component.spec.ts +++ b/src/test/javascript/spec/component/hestia/generation-overview/code-hint-generation-overview.component.spec.ts @@ -1,6 +1,6 @@ import { ArtemisTestModule } from '../../../test.module'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { CodeHint, CodeHintGenerationStep } from 'app/entities/hestia/code-hint-model'; import { CodeHintGenerationOverviewComponent } from 'app/exercises/programming/hestia/generation-overview/code-hint-generation-overview/code-hint-generation-overview.component'; import { MockActivatedRoute } from '../../../helpers/mocks/activated-route/mock-activated-route'; diff --git a/src/test/javascript/spec/component/hestia/generation-overview/code-hint-generation-step.component.spec.ts b/src/test/javascript/spec/component/hestia/generation-overview/code-hint-generation-step.component.spec.ts index 1581002cfad0..f0e9e9999233 100644 --- a/src/test/javascript/spec/component/hestia/generation-overview/code-hint-generation-step.component.spec.ts +++ b/src/test/javascript/spec/component/hestia/generation-overview/code-hint-generation-step.component.spec.ts @@ -3,7 +3,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { of } from 'rxjs'; import { CodeHintGenerationStepComponent } from 'app/exercises/programming/hestia/generation-overview/steps/code-hint-generation-step/code-hint-generation-step.component'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { CodeHintService } from 'app/exercises/shared/exercise-hint/services/code-hint.service'; import { CodeHint } from 'app/entities/hestia/code-hint-model'; diff --git a/src/test/javascript/spec/component/hestia/generation-overview/coverage-generation-step.component.spec.ts b/src/test/javascript/spec/component/hestia/generation-overview/coverage-generation-step.component.spec.ts index 2707ed4960a3..cda7ed0c1f60 100644 --- a/src/test/javascript/spec/component/hestia/generation-overview/coverage-generation-step.component.spec.ts +++ b/src/test/javascript/spec/component/hestia/generation-overview/coverage-generation-step.component.spec.ts @@ -2,7 +2,7 @@ import { ArtemisTestModule } from '../../../test.module'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { of } from 'rxjs'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { CoverageGenerationStepComponent } from 'app/exercises/programming/hestia/generation-overview/steps/coverage-generation-step/coverage-generation-step.component'; import { CoverageReport } from 'app/entities/hestia/coverage-report.model'; diff --git a/src/test/javascript/spec/component/hestia/generation-overview/diff-generation-step.component.spec.ts b/src/test/javascript/spec/component/hestia/generation-overview/diff-generation-step.component.spec.ts index 72b487652668..6d9f4cca6346 100644 --- a/src/test/javascript/spec/component/hestia/generation-overview/diff-generation-step.component.spec.ts +++ b/src/test/javascript/spec/component/hestia/generation-overview/diff-generation-step.component.spec.ts @@ -2,7 +2,7 @@ import { ArtemisTestModule } from '../../../test.module'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { of } from 'rxjs'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { DiffGenerationStepComponent } from 'app/exercises/programming/hestia/generation-overview/steps/diff-generation-step/diff-generation-step.component'; import { ProgrammingExerciseGitDiffReport } from 'app/entities/hestia/programming-exercise-git-diff-report.model'; diff --git a/src/test/javascript/spec/component/hestia/generation-overview/manual-solution-entry-creation-modal.component.spec.ts b/src/test/javascript/spec/component/hestia/generation-overview/manual-solution-entry-creation-modal.component.spec.ts index 34c79f31899d..9720294dde47 100644 --- a/src/test/javascript/spec/component/hestia/generation-overview/manual-solution-entry-creation-modal.component.spec.ts +++ b/src/test/javascript/spec/component/hestia/generation-overview/manual-solution-entry-creation-modal.component.spec.ts @@ -3,7 +3,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ManualSolutionEntryCreationModalComponent } from 'app/exercises/programming/hestia/generation-overview/manual-solution-entry-creation-modal/manual-solution-entry-creation-modal.component'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; import { ProgrammingExerciseSolutionEntryService } from 'app/exercises/shared/exercise-hint/services/programming-exercise-solution-entry.service'; -import { ProgrammingExerciseTestCase } from 'app/entities/programming-exercise-test-case.model'; +import { ProgrammingExerciseTestCase } from 'app/entities/programming/programming-exercise-test-case.model'; import { of } from 'rxjs'; import { ProgrammingExerciseSolutionEntry } from 'app/entities/hestia/programming-exercise-solution-entry.model'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; diff --git a/src/test/javascript/spec/component/hestia/generation-overview/solution-entry-details-modal.component.spec.ts b/src/test/javascript/spec/component/hestia/generation-overview/solution-entry-details-modal.component.spec.ts index 603c7838f5cd..7852a6aa8f5f 100644 --- a/src/test/javascript/spec/component/hestia/generation-overview/solution-entry-details-modal.component.spec.ts +++ b/src/test/javascript/spec/component/hestia/generation-overview/solution-entry-details-modal.component.spec.ts @@ -1,7 +1,7 @@ import { ArtemisTestModule } from '../../../test.module'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ProgrammingExerciseSolutionEntryService } from 'app/exercises/shared/exercise-hint/services/programming-exercise-solution-entry.service'; -import { ProgrammingExerciseTestCase } from 'app/entities/programming-exercise-test-case.model'; +import { ProgrammingExerciseTestCase } from 'app/entities/programming/programming-exercise-test-case.model'; import { of } from 'rxjs'; import { ProgrammingExerciseSolutionEntry } from 'app/entities/hestia/programming-exercise-solution-entry.model'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; diff --git a/src/test/javascript/spec/component/hestia/generation-overview/solution-entry-generation-step.component.spec.ts b/src/test/javascript/spec/component/hestia/generation-overview/solution-entry-generation-step.component.spec.ts index f231e94f008c..9e4ff7118bc9 100644 --- a/src/test/javascript/spec/component/hestia/generation-overview/solution-entry-generation-step.component.spec.ts +++ b/src/test/javascript/spec/component/hestia/generation-overview/solution-entry-generation-step.component.spec.ts @@ -2,7 +2,7 @@ import { ArtemisTestModule } from '../../../test.module'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Observable, of } from 'rxjs'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { SolutionEntryGenerationStepComponent } from 'app/exercises/programming/hestia/generation-overview/steps/solution-entry-generation-step/solution-entry-generation-step.component'; import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; import { AlertService } from 'app/core/util/alert.service'; @@ -11,7 +11,7 @@ import { ProgrammingExerciseSolutionEntry } from 'app/entities/hestia/programmin import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { MockComponent, MockPipe, MockProvider } from 'ng-mocks'; import { EventEmitter } from '@angular/core'; -import { ProgrammingExerciseTestCase, ProgrammingExerciseTestCaseType } from 'app/entities/programming-exercise-test-case.model'; +import { ProgrammingExerciseTestCase, ProgrammingExerciseTestCaseType } from 'app/entities/programming/programming-exercise-test-case.model'; import { SortingOrder } from 'app/shared/table/pageable-table'; import { HelpIconComponent } from 'app/shared/components/help-icon.component'; diff --git a/src/test/javascript/spec/component/hestia/testwise-coverage-report/testwise-coverage-file.component.spec.ts b/src/test/javascript/spec/component/hestia/testwise-coverage-report/testwise-coverage-file.component.spec.ts index d837ef16643a..a35ac8f46b3b 100644 --- a/src/test/javascript/spec/component/hestia/testwise-coverage-report/testwise-coverage-file.component.spec.ts +++ b/src/test/javascript/spec/component/hestia/testwise-coverage-report/testwise-coverage-file.component.spec.ts @@ -2,7 +2,7 @@ import { ArtemisTestModule } from '../../../test.module'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { TestwiseCoverageFileComponent } from 'app/exercises/programming/hestia/testwise-coverage-report/testwise-coverage-file.component'; -import { ProgrammingExerciseTestCase } from 'app/entities/programming-exercise-test-case.model'; +import { ProgrammingExerciseTestCase } from 'app/entities/programming/programming-exercise-test-case.model'; import { TestwiseCoverageReportEntry } from 'app/entities/hestia/testwise-coverage-report-entry.model'; import { CoverageFileReport } from 'app/entities/hestia/coverage-file-report.model'; import { MatExpansionModule } from '@angular/material/expansion'; diff --git a/src/test/javascript/spec/component/hestia/testwise-coverage-report/testwise-coverage-report.component.spec.ts b/src/test/javascript/spec/component/hestia/testwise-coverage-report/testwise-coverage-report.component.spec.ts index 77f8c1db5cbd..1c2e97853b5b 100644 --- a/src/test/javascript/spec/component/hestia/testwise-coverage-report/testwise-coverage-report.component.spec.ts +++ b/src/test/javascript/spec/component/hestia/testwise-coverage-report/testwise-coverage-report.component.spec.ts @@ -3,7 +3,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { TestwiseCoverageReportComponent } from 'app/exercises/programming/hestia/testwise-coverage-report/testwise-coverage-report.component'; import { CoverageReport } from 'app/entities/hestia/coverage-report.model'; import { CoverageFileReport } from 'app/entities/hestia/coverage-file-report.model'; -import { ProgrammingExerciseTestCase } from 'app/entities/programming-exercise-test-case.model'; +import { ProgrammingExerciseTestCase } from 'app/entities/programming/programming-exercise-test-case.model'; import { TestwiseCoverageReportEntry } from 'app/entities/hestia/testwise-coverage-report-entry.model'; describe('TestwiseCoverageReport Component', () => { diff --git a/src/test/javascript/spec/component/import/exercise-import-from-file.component.spec.ts b/src/test/javascript/spec/component/import/exercise-import-from-file.component.spec.ts index 1e6d212a1c9a..d855c5af0aa1 100644 --- a/src/test/javascript/spec/component/import/exercise-import-from-file.component.spec.ts +++ b/src/test/javascript/spec/component/import/exercise-import-from-file.component.spec.ts @@ -6,14 +6,14 @@ import { ArtemisTestModule } from '../../test.module'; import { HelpIconComponent } from 'app/shared/components/help-icon.component'; import { MockComponent, MockDirective } from 'ng-mocks'; import { ButtonComponent } from 'app/shared/components/button.component'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ExerciseType } from 'app/entities/exercise.model'; import { AlertService } from 'app/core/util/alert.service'; import { TranslateDirective } from 'app/shared/language/translate.directive'; import JSZip from 'jszip'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; import { FileUploadExercise } from 'app/entities/file-upload-exercise.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; import { UMLDiagramType } from '@ls1intum/apollon'; diff --git a/src/test/javascript/spec/component/import/exercise-import-wrapper.component.spec.ts b/src/test/javascript/spec/component/import/exercise-import-wrapper.component.spec.ts index fb60d4ab979c..eeb648c6126e 100644 --- a/src/test/javascript/spec/component/import/exercise-import-wrapper.component.spec.ts +++ b/src/test/javascript/spec/component/import/exercise-import-wrapper.component.spec.ts @@ -9,7 +9,7 @@ import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { TranslateDirective } from 'app/shared/language/translate.directive'; import { ArtemisTestModule } from '../../test.module'; import { ExerciseImportTabsComponent } from 'app/exercises/shared/import/exercise-import-tabs.component'; -import { ProgrammingLanguage } from 'app/entities/programming-exercise.model'; +import { ProgrammingLanguage } from 'app/entities/programming/programming-exercise.model'; describe('ExerciseImportWrapperComponent', () => { let component: ExerciseImportWrapperComponent; diff --git a/src/test/javascript/spec/component/import/exercise-import.component.spec.ts b/src/test/javascript/spec/component/import/exercise-import.component.spec.ts index cf1a0da9a91f..ae6201f3dea5 100644 --- a/src/test/javascript/spec/component/import/exercise-import.component.spec.ts +++ b/src/test/javascript/spec/component/import/exercise-import.component.spec.ts @@ -3,9 +3,9 @@ import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testin import { FormsModule } from '@angular/forms'; import { NgbActiveModal, NgbPagination } from '@ng-bootstrap/ng-bootstrap'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; -import { ProgrammingLanguage } from 'app/entities/programming-exercise.model'; +import { ProgrammingLanguage } from 'app/entities/programming/programming-exercise.model'; import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { ModelingExercisePagingService } from 'app/exercises/modeling/manage/modeling-exercise-paging.service'; import { CodeAnalysisPagingService } from 'app/exercises/programming/manage/services/code-analysis-paging.service'; import { ProgrammingExercisePagingService } from 'app/exercises/programming/manage/services/programming-exercise-paging.service'; diff --git a/src/test/javascript/spec/component/import/import.component.spec.ts b/src/test/javascript/spec/component/import/import.component.spec.ts index 637cfb5c95de..88919c3b0a58 100644 --- a/src/test/javascript/spec/component/import/import.component.spec.ts +++ b/src/test/javascript/spec/component/import/import.component.spec.ts @@ -3,7 +3,7 @@ import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testin import { FormsModule } from '@angular/forms'; import { Router } from '@angular/router'; import { NgbActiveModal, NgbPagination } from '@ng-bootstrap/ng-bootstrap'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ButtonComponent } from 'app/shared/components/button.component'; import { ImportComponent } from 'app/shared/import/import.component'; import { BaseEntity } from 'app/shared/model/base-entity'; diff --git a/src/test/javascript/spec/component/iris/settings/iris-enabled.component.spec.ts b/src/test/javascript/spec/component/iris/settings/iris-enabled.component.spec.ts index a79259f2268a..ba02154c4bc5 100644 --- a/src/test/javascript/spec/component/iris/settings/iris-enabled.component.spec.ts +++ b/src/test/javascript/spec/component/iris/settings/iris-enabled.component.spec.ts @@ -9,7 +9,7 @@ import { IrisSettings } from 'app/entities/iris/settings/iris-settings.model'; import { HttpResponse } from '@angular/common/http'; import { IrisEnabledComponent } from 'app/iris/settings/shared/iris-enabled.component'; import { TranslatePipeMock } from '../../../helpers/mocks/service/mock-translate.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { Course } from 'app/entities/course.model'; import { IrisSubSettingsType } from 'app/entities/iris/settings/iris-sub-settings.model'; diff --git a/src/test/javascript/spec/component/learning-paths/graph/node-details/exercise-node-details.component.spec.ts b/src/test/javascript/spec/component/learning-paths/graph/node-details/exercise-node-details.component.spec.ts index 7469f93f790d..bf1140cc06fb 100644 --- a/src/test/javascript/spec/component/learning-paths/graph/node-details/exercise-node-details.component.spec.ts +++ b/src/test/javascript/spec/component/learning-paths/graph/node-details/exercise-node-details.component.spec.ts @@ -8,7 +8,7 @@ import { NgbTooltipMocksModule } from '../../../../helpers/mocks/directive/ngbTo import { ExerciseNodeDetailsComponent } from 'app/course/learning-paths/learning-path-graph/node-details/exercise-node-details.component'; import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; import { Exercise } from 'app/entities/exercise.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; describe('ExerciseNodeDetailsComponent', () => { let fixture: ComponentFixture; diff --git a/src/test/javascript/spec/component/learning-paths/participate/learning-path-container.component.spec.ts b/src/test/javascript/spec/component/learning-paths/participate/learning-path-container.component.spec.ts index 3c0cc20079f0..9ead2c3a9994 100644 --- a/src/test/javascript/spec/component/learning-paths/participate/learning-path-container.component.spec.ts +++ b/src/test/javascript/spec/component/learning-paths/participate/learning-path-container.component.spec.ts @@ -13,7 +13,7 @@ import { LectureUnit } from 'app/entities/lecture-unit/lectureUnit.model'; import { Exercise } from 'app/entities/exercise.model'; import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; import { AttachmentUnit } from 'app/entities/lecture-unit/attachmentUnit.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { LearningPathLectureUnitViewComponent } from 'app/course/learning-paths/participate/lecture-unit/learning-path-lecture-unit-view.component'; import { CourseExerciseDetailsComponent } from 'app/overview/exercise-details/course-exercise-details.component'; import { ExerciseEntry, LearningPathStorageService, LectureUnitEntry, StorageEntry } from 'app/course/learning-paths/participate/learning-path-storage.service'; diff --git a/src/test/javascript/spec/component/lecture-unit/exercise-unit/create-exercise-unit.component.spec.ts b/src/test/javascript/spec/component/lecture-unit/exercise-unit/create-exercise-unit.component.spec.ts index 4841051e7ad9..c01d76662132 100644 --- a/src/test/javascript/spec/component/lecture-unit/exercise-unit/create-exercise-unit.component.spec.ts +++ b/src/test/javascript/spec/component/lecture-unit/exercise-unit/create-exercise-unit.component.spec.ts @@ -10,8 +10,8 @@ import { ExerciseUnitService } from 'app/lecture/lecture-unit/lecture-unit-manag import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { Course } from 'app/entities/course.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; import { FileUploadExercise } from 'app/entities/file-upload-exercise.model'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; diff --git a/src/test/javascript/spec/component/lecture-unit/exercise-unit/exercise-unit.component.spec.ts b/src/test/javascript/spec/component/lecture-unit/exercise-unit/exercise-unit.component.spec.ts index d44b64a65ff0..5d72248e268d 100644 --- a/src/test/javascript/spec/component/lecture-unit/exercise-unit/exercise-unit.component.spec.ts +++ b/src/test/javascript/spec/component/lecture-unit/exercise-unit/exercise-unit.component.spec.ts @@ -4,7 +4,7 @@ import { ExerciseUnit } from 'app/entities/lecture-unit/exerciseUnit.model'; import { Component, Input } from '@angular/core'; import { Exercise } from 'app/entities/exercise.model'; import { Course } from 'app/entities/course.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { By } from '@angular/platform-browser'; @Component({ selector: 'jhi-course-exercise-row', template: '' }) diff --git a/src/test/javascript/spec/component/lecture-unit/exercise-unit/exercise-unit.service.spec.ts b/src/test/javascript/spec/component/lecture-unit/exercise-unit/exercise-unit.service.spec.ts index 486196aa88dd..61d60ac7d907 100644 --- a/src/test/javascript/spec/component/lecture-unit/exercise-unit/exercise-unit.service.spec.ts +++ b/src/test/javascript/spec/component/lecture-unit/exercise-unit/exercise-unit.service.spec.ts @@ -7,7 +7,7 @@ import { take } from 'rxjs/operators'; import { LectureUnit } from 'app/entities/lecture-unit/lectureUnit.model'; import { ExerciseUnitService } from 'app/lecture/lecture-unit/lecture-unit-management/exerciseUnit.service'; import { ExerciseUnit } from 'app/entities/lecture-unit/exerciseUnit.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { Course } from 'app/entities/course.model'; import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; diff --git a/src/test/javascript/spec/component/lecture-unit/lecture-unit.service.spec.ts b/src/test/javascript/spec/component/lecture-unit/lecture-unit.service.spec.ts index c068f467ac38..9195af36b64b 100644 --- a/src/test/javascript/spec/component/lecture-unit/lecture-unit.service.spec.ts +++ b/src/test/javascript/spec/component/lecture-unit/lecture-unit.service.spec.ts @@ -10,7 +10,7 @@ import { TextUnit } from 'app/entities/lecture-unit/textUnit.model'; import { VideoUnit } from 'app/entities/lecture-unit/videoUnit.model'; import { ExerciseUnit } from 'app/entities/lecture-unit/exerciseUnit.model'; import { Course } from 'app/entities/course.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { Attachment, AttachmentType } from 'app/entities/attachment.model'; import { ArtemisTestModule } from '../../test.module'; diff --git a/src/test/javascript/spec/component/lecture/wizard-mode/lecture-wizard-competencies.component.spec.ts b/src/test/javascript/spec/component/lecture/wizard-mode/lecture-wizard-competencies.component.spec.ts index 2882280317c4..914fe55c18ab 100644 --- a/src/test/javascript/spec/component/lecture/wizard-mode/lecture-wizard-competencies.component.spec.ts +++ b/src/test/javascript/spec/component/lecture/wizard-mode/lecture-wizard-competencies.component.spec.ts @@ -16,7 +16,7 @@ import { Course } from 'app/entities/course.model'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { TextUnit } from 'app/entities/lecture-unit/textUnit.model'; import { ExerciseUnit } from 'app/entities/lecture-unit/exerciseUnit.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { CourseCompetencyFormData } from 'app/course/competencies/forms/course-competency-form.component'; diff --git a/src/test/javascript/spec/component/localci/build-agents/build-agent-details.component.spec.ts b/src/test/javascript/spec/component/localci/build-agents/build-agent-details.component.spec.ts index 9b458fcfea34..41ab0dfcea81 100644 --- a/src/test/javascript/spec/component/localci/build-agents/build-agent-details.component.spec.ts +++ b/src/test/javascript/spec/component/localci/build-agents/build-agent-details.component.spec.ts @@ -2,17 +2,17 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { JhiWebsocketService } from 'app/core/websocket/websocket.service'; import { BuildAgentsService } from 'app/localci/build-agents/build-agents.service'; import { of } from 'rxjs'; -import { BuildJob } from 'app/entities/build-job.model'; +import { BuildJob } from 'app/entities/programming/build-job.model'; import dayjs from 'dayjs/esm'; import { ArtemisTestModule } from '../../../test.module'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { DataTableComponent } from 'app/shared/data-table/data-table.component'; import { MockComponent, MockPipe } from 'ng-mocks'; import { NgxDatatableModule } from '@flaviosantoro92/ngx-datatable'; -import { BuildAgent } from 'app/entities/build-agent.model'; -import { RepositoryInfo, TriggeredByPushTo } from 'app/entities/repository-info.model'; +import { BuildAgent } from 'app/entities/programming/build-agent.model'; +import { RepositoryInfo, TriggeredByPushTo } from 'app/entities/programming/repository-info.model'; import { JobTimingInfo } from 'app/entities/job-timing-info.model'; -import { BuildConfig } from 'app/entities/build-config.model'; +import { BuildConfig } from 'app/entities/programming/build-config.model'; import { BuildAgentDetailsComponent } from 'app/localci/build-agents/build-agent-details/build-agent-details/build-agent-details.component'; import { MockActivatedRoute } from '../../../helpers/mocks/activated-route/mock-activated-route'; import { ActivatedRoute } from '@angular/router'; diff --git a/src/test/javascript/spec/component/localci/build-agents/build-agent-summary.component.spec.ts b/src/test/javascript/spec/component/localci/build-agents/build-agent-summary.component.spec.ts index 2ffc69f9b823..76a76f16c094 100644 --- a/src/test/javascript/spec/component/localci/build-agents/build-agent-summary.component.spec.ts +++ b/src/test/javascript/spec/component/localci/build-agents/build-agent-summary.component.spec.ts @@ -3,17 +3,17 @@ import { BuildAgentSummaryComponent } from 'app/localci/build-agents/build-agent import { JhiWebsocketService } from 'app/core/websocket/websocket.service'; import { BuildAgentsService } from 'app/localci/build-agents/build-agents.service'; import { of } from 'rxjs'; -import { BuildJob } from 'app/entities/build-job.model'; +import { BuildJob } from 'app/entities/programming/build-job.model'; import dayjs from 'dayjs/esm'; import { ArtemisTestModule } from '../../../test.module'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { DataTableComponent } from 'app/shared/data-table/data-table.component'; import { MockComponent, MockPipe } from 'ng-mocks'; import { NgxDatatableModule } from '@flaviosantoro92/ngx-datatable'; -import { BuildAgent } from 'app/entities/build-agent.model'; -import { RepositoryInfo, TriggeredByPushTo } from 'app/entities/repository-info.model'; +import { BuildAgent } from 'app/entities/programming/build-agent.model'; +import { RepositoryInfo, TriggeredByPushTo } from 'app/entities/programming/repository-info.model'; import { JobTimingInfo } from 'app/entities/job-timing-info.model'; -import { BuildConfig } from 'app/entities/build-config.model'; +import { BuildConfig } from 'app/entities/programming/build-config.model'; describe('BuildAgentSummaryComponent', () => { let component: BuildAgentSummaryComponent; diff --git a/src/test/javascript/spec/component/localci/build-agents/build-agents.service.spec.ts b/src/test/javascript/spec/component/localci/build-agents/build-agents.service.spec.ts index 20ac1e1e4011..494f211ee2b3 100644 --- a/src/test/javascript/spec/component/localci/build-agents/build-agents.service.spec.ts +++ b/src/test/javascript/spec/component/localci/build-agents/build-agents.service.spec.ts @@ -3,13 +3,13 @@ import { TestBed } from '@angular/core/testing'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { MockTranslateService } from '../../../helpers/mocks/service/mock-translate.service'; import { TranslateService } from '@ngx-translate/core'; -import { BuildJob } from 'app/entities/build-job.model'; +import { BuildJob } from 'app/entities/programming/build-job.model'; import dayjs from 'dayjs/esm'; import { BuildAgentsService } from 'app/localci/build-agents/build-agents.service'; -import { BuildAgent } from 'app/entities/build-agent.model'; -import { RepositoryInfo, TriggeredByPushTo } from 'app/entities/repository-info.model'; +import { BuildAgent } from 'app/entities/programming/build-agent.model'; +import { RepositoryInfo, TriggeredByPushTo } from 'app/entities/programming/repository-info.model'; import { JobTimingInfo } from 'app/entities/job-timing-info.model'; -import { BuildConfig } from 'app/entities/build-config.model'; +import { BuildConfig } from 'app/entities/programming/build-config.model'; describe('BuildAgentsService', () => { let service: BuildAgentsService; diff --git a/src/test/javascript/spec/component/localci/build-queue/build-queue.component.spec.ts b/src/test/javascript/spec/component/localci/build-queue/build-queue.component.spec.ts index 966e1cdeb551..2d8f1c622405 100644 --- a/src/test/javascript/spec/component/localci/build-queue/build-queue.component.spec.ts +++ b/src/test/javascript/spec/component/localci/build-queue/build-queue.component.spec.ts @@ -10,8 +10,8 @@ import { AccountService } from 'app/core/auth/account.service'; import { DataTableComponent } from 'app/shared/data-table/data-table.component'; import { NgxDatatableModule } from '@flaviosantoro92/ngx-datatable'; import { ArtemisTestModule } from '../../../test.module'; -import { BuildJobStatistics, FinishedBuildJob, SpanType } from 'app/entities/build-job.model'; -import { TriggeredByPushTo } from 'app/entities/repository-info.model'; +import { BuildJobStatistics, FinishedBuildJob, SpanType } from 'app/entities/programming/build-job.model'; +import { TriggeredByPushTo } from 'app/entities/programming/repository-info.model'; import { waitForAsync } from '@angular/core/testing'; import { HttpResponse } from '@angular/common/http'; import { SortingOrder } from 'app/shared/table/pageable-table'; diff --git a/src/test/javascript/spec/component/localci/build-queue/build-queue.service.spec.ts b/src/test/javascript/spec/component/localci/build-queue/build-queue.service.spec.ts index aa1b2ad95943..e762ed0d878b 100644 --- a/src/test/javascript/spec/component/localci/build-queue/build-queue.service.spec.ts +++ b/src/test/javascript/spec/component/localci/build-queue/build-queue.service.spec.ts @@ -8,11 +8,11 @@ import { MockSyncStorage } from '../../../helpers/mocks/service/mock-sync-storag import { MockTranslateService } from '../../../helpers/mocks/service/mock-translate.service'; import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { TranslateService } from '@ngx-translate/core'; -import { BuildJob, BuildJobStatistics, SpanType } from 'app/entities/build-job.model'; +import { BuildJob, BuildJobStatistics, SpanType } from 'app/entities/programming/build-job.model'; import dayjs from 'dayjs/esm'; -import { RepositoryInfo, TriggeredByPushTo } from 'app/entities/repository-info.model'; +import { RepositoryInfo, TriggeredByPushTo } from 'app/entities/programming/repository-info.model'; import { JobTimingInfo } from 'app/entities/job-timing-info.model'; -import { BuildConfig } from 'app/entities/build-config.model'; +import { BuildConfig } from 'app/entities/programming/build-config.model'; import { FinishedBuildJobFilter } from 'app/localci/build-queue/build-queue.component'; describe('BuildQueueService', () => { diff --git a/src/test/javascript/spec/component/localvc/commit-details-view.component.spec.ts b/src/test/javascript/spec/component/localvc/commit-details-view.component.spec.ts index 3fb6e53ee8f7..fb964f7ea127 100644 --- a/src/test/javascript/spec/component/localvc/commit-details-view.component.spec.ts +++ b/src/test/javascript/spec/component/localvc/commit-details-view.component.spec.ts @@ -7,7 +7,7 @@ import { DueDateStat } from 'app/course/dashboards/due-date-stat.model'; import dayjs from 'dayjs/esm'; import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model'; import { Observable, of, throwError } from 'rxjs'; -import { CommitInfo } from 'app/entities/programming-submission.model'; +import { CommitInfo } from 'app/entities/programming/programming-submission.model'; import { MockComponent, MockPipe } from 'ng-mocks'; import { CommitDetailsViewComponent } from 'app/localvc/commit-details-view/commit-details-view.component'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; @@ -16,7 +16,7 @@ import { ProgrammingExerciseGitDiffReport } from 'app/entities/hestia/programmin import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { ArtemisDatePipe } from 'app/shared/pipes/artemis-date.pipe'; import { GitDiffReportComponent } from 'app/exercises/programming/hestia/git-diff-report/git-diff-report.component'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { HttpResponse } from '@angular/common/http'; describe('CommitDetailsViewComponent', () => { diff --git a/src/test/javascript/spec/component/localvc/commit-history.component.spec.ts b/src/test/javascript/spec/component/localvc/commit-history.component.spec.ts index 1ab3572e75f4..8c3a628980a6 100644 --- a/src/test/javascript/spec/component/localvc/commit-history.component.spec.ts +++ b/src/test/javascript/spec/component/localvc/commit-history.component.spec.ts @@ -8,12 +8,12 @@ import { DueDateStat } from 'app/course/dashboards/due-date-stat.model'; import dayjs from 'dayjs/esm'; import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model'; import { of } from 'rxjs'; -import { CommitInfo, ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { CommitInfo, ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { CommitsInfoComponent } from 'app/exercises/programming/shared/commits-info/commits-info.component'; import { MockComponent } from 'ng-mocks'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; import { MockProgrammingExerciseService } from '../../helpers/mocks/service/mock-programming-exercise.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { HttpResponse } from '@angular/common/http'; describe('CommitHistoryComponent', () => { diff --git a/src/test/javascript/spec/component/localvc/repository-view.component.spec.ts b/src/test/javascript/spec/component/localvc/repository-view.component.spec.ts index fcc2710140c4..5f4fae4014a9 100644 --- a/src/test/javascript/spec/component/localvc/repository-view.component.spec.ts +++ b/src/test/javascript/spec/component/localvc/repository-view.component.spec.ts @@ -13,7 +13,7 @@ import { AccountService } from 'app/core/auth/account.service'; import { DomainType } from 'app/exercises/programming/shared/code-editor/model/code-editor.model'; import { Observable, of } from 'rxjs'; import { HttpResponse } from '@angular/common/http'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { DueDateStat } from 'app/course/dashboards/due-date-stat.model'; import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model'; diff --git a/src/test/javascript/spec/component/modeling-assessment-editor/modeling-assessment-editor.component.spec.ts b/src/test/javascript/spec/component/modeling-assessment-editor/modeling-assessment-editor.component.spec.ts index 2bdc08914731..7bbd4b2e71a7 100644 --- a/src/test/javascript/spec/component/modeling-assessment-editor/modeling-assessment-editor.component.spec.ts +++ b/src/test/javascript/spec/component/modeling-assessment-editor/modeling-assessment-editor.component.spec.ts @@ -12,7 +12,7 @@ import { AssessmentType } from 'app/entities/assessment-type.model'; import { ComplaintResponse } from 'app/entities/complaint-response.model'; import { Complaint } from 'app/entities/complaint.model'; import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { Exercise } from 'app/entities/exercise.model'; import { Feedback, FeedbackType } from 'app/entities/feedback.model'; @@ -20,7 +20,7 @@ import { ModelingExercise } from 'app/entities/modeling-exercise.model'; import { ModelingSubmission } from 'app/entities/modeling-submission.model'; import { Participation, ParticipationType } from 'app/entities/participation/participation.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { Result } from 'app/entities/result.model'; import { getLatestSubmissionResult } from 'app/entities/submission.model'; import { ModelingAssessmentEditorComponent } from 'app/exercises/modeling/assess/modeling-assessment-editor/modeling-assessment-editor.component'; diff --git a/src/test/javascript/spec/component/modeling-exercise/modeling-exercise-update.component.spec.ts b/src/test/javascript/spec/component/modeling-exercise/modeling-exercise-update.component.spec.ts index f9963b3f1725..ccbc08667bd0 100644 --- a/src/test/javascript/spec/component/modeling-exercise/modeling-exercise-update.component.spec.ts +++ b/src/test/javascript/spec/component/modeling-exercise/modeling-exercise-update.component.spec.ts @@ -12,7 +12,7 @@ import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { MockActivatedRoute } from '../../helpers/mocks/activated-route/mock-activated-route'; import { Course } from 'app/entities/course.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import dayjs from 'dayjs/esm'; import { TranslateService } from '@ngx-translate/core'; import { MockComponent, MockProvider } from 'ng-mocks'; diff --git a/src/test/javascript/spec/component/non-programming-exercise-detail-common-actions.component.spec.ts b/src/test/javascript/spec/component/non-programming-exercise-detail-common-actions.component.spec.ts index a01c3b4bdbd5..e81ad3cbd435 100644 --- a/src/test/javascript/spec/component/non-programming-exercise-detail-common-actions.component.spec.ts +++ b/src/test/javascript/spec/component/non-programming-exercise-detail-common-actions.component.spec.ts @@ -6,11 +6,11 @@ import { MockFileUploadExerciseService } from '../helpers/mocks/service/mock-fil import { SubmissionExportButtonComponent } from 'app/exercises/shared/submission-export/submission-export-button.component'; import { MockComponent, MockDirective, MockProvider } from 'ng-mocks'; import { DeleteButtonDirective } from 'app/shared/delete-dialog/delete-button.directive'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { Course } from 'app/entities/course.model'; import { FileUploadExercise } from 'app/entities/file-upload-exercise.model'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { TextExerciseService } from 'app/exercises/text/manage/text-exercise/text-exercise.service'; import { of } from 'rxjs'; diff --git a/src/test/javascript/spec/component/orion/orion-code-editor-instructor-and-editor-container.component.spec.ts b/src/test/javascript/spec/component/orion/orion-code-editor-instructor-and-editor-container.component.spec.ts index 5350df402a29..fc43be446641 100644 --- a/src/test/javascript/spec/component/orion/orion-code-editor-instructor-and-editor-container.component.spec.ts +++ b/src/test/javascript/spec/component/orion/orion-code-editor-instructor-and-editor-container.component.spec.ts @@ -19,7 +19,7 @@ import { MockRouter } from '../../helpers/mocks/mock-router'; import { Router } from '@angular/router'; import { ParticipationService } from 'app/exercises/shared/participation/participation.service'; import { CourseExerciseService } from 'app/exercises/shared/course-exercises/course-exercise.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; describe('CodeEditorInstructorAndEditorOrionContainerComponent', () => { let comp: CodeEditorInstructorAndEditorOrionContainerComponent; diff --git a/src/test/javascript/spec/component/orion/orion-exercise-assessment-dashboard.component.spec.ts b/src/test/javascript/spec/component/orion/orion-exercise-assessment-dashboard.component.spec.ts index d5688eb628cf..430f28bee09f 100644 --- a/src/test/javascript/spec/component/orion/orion-exercise-assessment-dashboard.component.spec.ts +++ b/src/test/javascript/spec/component/orion/orion-exercise-assessment-dashboard.component.spec.ts @@ -2,7 +2,7 @@ import { TestBed, fakeAsync, tick } from '@angular/core/testing'; import { OrionExerciseAssessmentDashboardComponent } from 'app/orion/assessment/orion-exercise-assessment-dashboard.component'; import { ExerciseType } from 'app/entities/exercise.model'; import { TutorParticipationStatus } from 'app/entities/participation/tutor-participation.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { OrionConnectorService } from 'app/shared/orion/orion-connector.service'; import { BehaviorSubject, of, throwError } from 'rxjs'; import { MockComponent, MockPipe, MockProvider } from 'ng-mocks'; diff --git a/src/test/javascript/spec/component/overview/course-card.component.spec.ts b/src/test/javascript/spec/component/overview/course-card.component.spec.ts index 9c22d764106f..fbe16f160c51 100644 --- a/src/test/javascript/spec/component/overview/course-card.component.spec.ts +++ b/src/test/javascript/spec/component/overview/course-card.component.spec.ts @@ -9,7 +9,7 @@ import { Exercise } from 'app/entities/exercise.model'; import { MockComponent, MockDirective, MockModule, MockPipe } from 'ng-mocks'; import dayjs from 'dayjs/esm'; import { SubmissionExerciseType } from 'app/entities/submission.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { ArtemisTimeAgoPipe } from 'app/shared/pipes/artemis-time-ago.pipe'; import { PieChartModule } from '@swimlane/ngx-charts'; import { TranslateDirective } from 'app/shared/language/translate.directive'; diff --git a/src/test/javascript/spec/component/overview/course-competencies/course-competencies-details.component.spec.ts b/src/test/javascript/spec/component/overview/course-competencies/course-competencies-details.component.spec.ts index 384e0875b8cd..658cc5b4f7ae 100644 --- a/src/test/javascript/spec/component/overview/course-competencies/course-competencies-details.component.spec.ts +++ b/src/test/javascript/spec/component/overview/course-competencies/course-competencies-details.component.spec.ts @@ -20,7 +20,7 @@ import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'; import { MockRouter } from '../../../helpers/mocks/mock-router'; import { HttpClientTestingModule } from '@angular/common/http/testing'; import { Competency, CompetencyProgress } from 'app/entities/competency.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { TextUnit } from 'app/entities/lecture-unit/textUnit.model'; import { HttpResponse } from '@angular/common/http'; import { MockHasAnyAuthorityDirective } from '../../../helpers/mocks/directive/mock-has-any-authority.directive'; diff --git a/src/test/javascript/spec/component/overview/course-exams/course-exams.component.spec.ts b/src/test/javascript/spec/component/overview/course-exams/course-exams.component.spec.ts index 4b6ccb1ca3f1..60590bae4bde 100644 --- a/src/test/javascript/spec/component/overview/course-exams/course-exams.component.spec.ts +++ b/src/test/javascript/spec/component/overview/course-exams/course-exams.component.spec.ts @@ -2,7 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ActivatedRoute, Router } from '@angular/router'; import { Course } from 'app/entities/course.model'; import { CourseExamsComponent } from 'app/overview/course-exams/course-exams.component'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ArtemisTestModule } from '../../../test.module'; import dayjs from 'dayjs/esm'; import { MockDirective, MockModule, MockPipe, MockProvider } from 'ng-mocks'; diff --git a/src/test/javascript/spec/component/overview/course-statistics/course-statistics.component.spec.ts b/src/test/javascript/spec/component/overview/course-statistics/course-statistics.component.spec.ts index 7631c4d81136..b38eefa60f4e 100644 --- a/src/test/javascript/spec/component/overview/course-statistics/course-statistics.component.spec.ts +++ b/src/test/javascript/spec/component/overview/course-statistics/course-statistics.component.spec.ts @@ -14,7 +14,7 @@ import { ExerciseCategory } from 'app/entities/exercise-category.model'; import { Exercise, ExerciseType, IncludedInOverallScore } from 'app/entities/exercise.model'; import { FileUploadExercise } from 'app/entities/file-upload-exercise.model'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; import { TreeviewModule } from 'app/exercises/programming/shared/code-editor/treeview/treeview.module'; import { CourseCompetenciesComponent } from 'app/overview/course-competencies/course-competencies.component'; diff --git a/src/test/javascript/spec/component/overview/exercise-details/course-exercise-details.component.spec.ts b/src/test/javascript/spec/component/overview/exercise-details/course-exercise-details.component.spec.ts index 957b1b6738ce..5fc8684a61cd 100644 --- a/src/test/javascript/spec/component/overview/exercise-details/course-exercise-details.component.spec.ts +++ b/src/test/javascript/spec/component/overview/exercise-details/course-exercise-details.component.spec.ts @@ -9,7 +9,7 @@ import { Participation, ParticipationType } from 'app/entities/participation/par import { StudentParticipation } from 'app/entities/participation/student-participation.model'; import { Result } from 'app/entities/result.model'; import { TeamAssignmentPayload } from 'app/entities/team.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { ProgrammingSubmissionService } from 'app/exercises/programming/participate/programming-submission.service'; import { ProgrammingExerciseInstructionComponent } from 'app/exercises/programming/shared/instructions-render/programming-exercise-instruction.component'; import { QuizExerciseService } from 'app/exercises/quiz/manage/quiz-exercise.service'; @@ -49,11 +49,11 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { MockRouterLinkDirective } from '../../../helpers/mocks/directive/mock-router-link.directive'; import { LtiInitializerComponent } from 'app/overview/exercise-details/lti-initializer.component'; import { ModelingEditorComponent } from 'app/exercises/modeling/shared/modeling-editor.component'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { MockCourseManagementService } from '../../../helpers/mocks/service/mock-course-management.service'; import { ArtemisMarkdownService } from 'app/shared/markdown.service'; import { DiscussionSectionComponent } from 'app/overview/discussion-section/discussion-section.component'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { SubmissionPolicyService } from 'app/exercises/programming/manage/services/submission-policy.service'; import { LockRepositoryPolicy } from 'app/entities/submission-policy.model'; import { PlagiarismCasesService } from 'app/course/plagiarism-cases/shared/plagiarism-cases.service'; diff --git a/src/test/javascript/spec/component/overview/exercise-details/exercise-details-student-actions.component.spec.ts b/src/test/javascript/spec/component/overview/exercise-details/exercise-details-student-actions.component.spec.ts index 1a770b4e5002..99068b63a154 100644 --- a/src/test/javascript/spec/component/overview/exercise-details/exercise-details-student-actions.component.spec.ts +++ b/src/test/javascript/spec/component/overview/exercise-details/exercise-details-student-actions.component.spec.ts @@ -9,10 +9,10 @@ import { Exercise, ExerciseMode, ExerciseType } from 'app/entities/exercise.mode import { InitializationState } from 'app/entities/participation/participation.model'; import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { QuizBatch, QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; import { Team } from 'app/entities/team.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { CourseExerciseService } from 'app/exercises/shared/course-exercises/course-exercise.service'; import { ExerciseDetailsStudentActionsComponent } from 'app/overview/exercise-details/exercise-details-student-actions.component'; import { CodeButtonComponent } from 'app/shared/components/code-button/code-button.component'; diff --git a/src/test/javascript/spec/component/participation-submission/participation-submission.component.spec.ts b/src/test/javascript/spec/component/participation-submission/participation-submission.component.spec.ts index 3e18c92b27c0..43b16fc6e6d0 100644 --- a/src/test/javascript/spec/component/participation-submission/participation-submission.component.spec.ts +++ b/src/test/javascript/spec/component/participation-submission/participation-submission.component.spec.ts @@ -20,15 +20,15 @@ import { ComplaintsForTutorComponent } from 'app/complaints/complaints-for-tutor import { UpdatingResultComponent } from 'app/exercises/shared/result/updating-result.component'; import { Submission, SubmissionExerciseType, SubmissionType } from 'app/entities/submission.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { RouterTestingModule } from '@angular/router/testing'; import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; import { TemplateProgrammingExerciseParticipation } from 'app/entities/participation/template-programming-exercise-participation.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { SolutionProgrammingExerciseParticipation } from 'app/entities/participation/solution-programming-exercise-participation.model'; import { ProfileService } from 'app/shared/layouts/profiles/profile.service'; import { ProfileInfo } from 'app/shared/layouts/profiles/profile-info.model'; diff --git a/src/test/javascript/spec/component/participation/participation.component.spec.ts b/src/test/javascript/spec/component/participation/participation.component.spec.ts index 569fc6ab73bb..7c96169e95ff 100644 --- a/src/test/javascript/spec/component/participation/participation.component.spec.ts +++ b/src/test/javascript/spec/component/participation/participation.component.spec.ts @@ -7,7 +7,7 @@ import { ParticipationService } from 'app/exercises/shared/participation/partici import { ParticipationComponent } from 'app/exercises/shared/participation/participation.component'; import { Course } from 'app/entities/course.model'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { of, throwError } from 'rxjs'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; import dayjs from 'dayjs/esm'; @@ -31,7 +31,7 @@ import { TranslateDirective } from 'app/shared/language/translate.directive'; import { ArtemisTestModule } from '../../test.module'; import { TranslatePipeMock } from '../../helpers/mocks/service/mock-translate.service'; import { FormDateTimePickerComponent } from 'app/shared/date-time-picker/date-time-picker.component'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { GradeStepsDTO } from 'app/entities/grade-step.model'; import { AlertService } from 'app/core/util/alert.service'; diff --git a/src/test/javascript/spec/component/plagiarism/exercise-update-plagiarism.component.spec.ts b/src/test/javascript/spec/component/plagiarism/exercise-update-plagiarism.component.spec.ts index feeb959ee591..9b85c7b332f4 100644 --- a/src/test/javascript/spec/component/plagiarism/exercise-update-plagiarism.component.spec.ts +++ b/src/test/javascript/spec/component/plagiarism/exercise-update-plagiarism.component.spec.ts @@ -1,6 +1,6 @@ import { DEFAULT_PLAGIARISM_DETECTION_CONFIG, Exercise, ExerciseType } from 'app/entities/exercise.model'; import { ExerciseUpdatePlagiarismComponent } from 'app/exercises/shared/plagiarism/exercise-update-plagiarism/exercise-update-plagiarism.component'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { Subject } from 'rxjs'; describe('Exercise Update Plagiarism Component', () => { diff --git a/src/test/javascript/spec/component/plagiarism/plagiarism-case-instructor-detail-view.component.spec.ts b/src/test/javascript/spec/component/plagiarism/plagiarism-case-instructor-detail-view.component.spec.ts index fa2105078290..c66f5a72b3c1 100644 --- a/src/test/javascript/spec/component/plagiarism/plagiarism-case-instructor-detail-view.component.spec.ts +++ b/src/test/javascript/spec/component/plagiarism/plagiarism-case-instructor-detail-view.component.spec.ts @@ -8,7 +8,7 @@ import { TranslateService } from '@ngx-translate/core'; import { PlagiarismCase } from 'app/exercises/shared/plagiarism/types/PlagiarismCase'; import { HttpResponse } from '@angular/common/http'; import { Observable, ReplaySubject, of } from 'rxjs'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { PlagiarismVerdict } from 'app/exercises/shared/plagiarism/types/PlagiarismVerdict'; import { MockLocalStorageService } from '../../helpers/mocks/service/mock-local-storage.service'; import { MetisService } from 'app/shared/metis/metis.service'; diff --git a/src/test/javascript/spec/component/plagiarism/plagiarism-case-student-detail-view.component.spec.ts b/src/test/javascript/spec/component/plagiarism/plagiarism-case-student-detail-view.component.spec.ts index 29248886bc42..5b4ecff30533 100644 --- a/src/test/javascript/spec/component/plagiarism/plagiarism-case-student-detail-view.component.spec.ts +++ b/src/test/javascript/spec/component/plagiarism/plagiarism-case-student-detail-view.component.spec.ts @@ -12,7 +12,7 @@ import { MockLocalStorageService } from '../../helpers/mocks/service/mock-local- import { MetisService } from 'app/shared/metis/metis.service'; import { TranslateService } from '@ngx-translate/core'; import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { PlagiarismVerdict } from 'app/exercises/shared/plagiarism/types/PlagiarismVerdict'; import dayjs from 'dayjs/esm'; import { NotificationService } from 'app/shared/notification/notification.service'; diff --git a/src/test/javascript/spec/component/plagiarism/plagiarism-cases-instructor-view.component.spec.ts b/src/test/javascript/spec/component/plagiarism/plagiarism-cases-instructor-view.component.spec.ts index 6d04c479847c..4a6bda12288c 100644 --- a/src/test/javascript/spec/component/plagiarism/plagiarism-cases-instructor-view.component.spec.ts +++ b/src/test/javascript/spec/component/plagiarism/plagiarism-cases-instructor-view.component.spec.ts @@ -8,7 +8,7 @@ import { Observable, of } from 'rxjs'; import { HttpResponse } from '@angular/common/http'; import { PlagiarismCase } from 'app/exercises/shared/plagiarism/types/PlagiarismCase'; import { TranslateService } from '@ngx-translate/core'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { PlagiarismVerdict } from 'app/exercises/shared/plagiarism/types/PlagiarismVerdict'; import * as DownloadUtil from 'app/shared/util/download.util'; import dayjs from 'dayjs/esm'; diff --git a/src/test/javascript/spec/component/plagiarism/plagiarism-inspector.component.spec.ts b/src/test/javascript/spec/component/plagiarism/plagiarism-inspector.component.spec.ts index ebb90a9f69a2..55b1e0eb0ea4 100644 --- a/src/test/javascript/spec/component/plagiarism/plagiarism-inspector.component.spec.ts +++ b/src/test/javascript/spec/component/plagiarism/plagiarism-inspector.component.spec.ts @@ -11,8 +11,8 @@ import { ModelingPlagiarismResult } from 'app/exercises/shared/plagiarism/types/ import { PlagiarismStatus } from 'app/exercises/shared/plagiarism/types/PlagiarismStatus'; import { TextExerciseService } from 'app/exercises/text/manage/text-exercise/text-exercise.service'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; import { TextPlagiarismResult } from 'app/exercises/shared/plagiarism/types/text/TextPlagiarismResult'; import { JhiWebsocketService } from 'app/core/websocket/websocket.service'; diff --git a/src/test/javascript/spec/component/plagiarism/plagiarism-split-view.component.spec.ts b/src/test/javascript/spec/component/plagiarism/plagiarism-split-view.component.spec.ts index 7c95bd6dacb2..4b06a312d72c 100644 --- a/src/test/javascript/spec/component/plagiarism/plagiarism-split-view.component.spec.ts +++ b/src/test/javascript/spec/component/plagiarism/plagiarism-split-view.component.spec.ts @@ -7,7 +7,7 @@ import { PlagiarismComparison } from 'app/exercises/shared/plagiarism/types/Plag import { PlagiarismSplitViewComponent } from 'app/exercises/shared/plagiarism/plagiarism-split-view/plagiarism-split-view.component'; import { ExerciseType } from 'app/entities/exercise.model'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { PlagiarismSubmission } from 'app/exercises/shared/plagiarism/types/PlagiarismSubmission'; import { FromToElement, TextSubmissionElement } from 'app/exercises/shared/plagiarism/types/text/TextSubmissionElement'; import { PlagiarismMatch, SimpleMatch } from 'app/exercises/shared/plagiarism/types/PlagiarismMatch'; diff --git a/src/test/javascript/spec/component/plagiarism/text-submission-viewer.component.spec.ts b/src/test/javascript/spec/component/plagiarism/text-submission-viewer.component.spec.ts index 225fc1227220..2118d941e1df 100644 --- a/src/test/javascript/spec/component/plagiarism/text-submission-viewer.component.spec.ts +++ b/src/test/javascript/spec/component/plagiarism/text-submission-viewer.component.spec.ts @@ -7,9 +7,9 @@ import { TextSubmissionViewerComponent } from 'app/exercises/shared/plagiarism/p import { CodeEditorRepositoryFileService } from 'app/exercises/programming/shared/code-editor/service/code-editor-repository.service'; import { TextSubmissionService } from 'app/exercises/text/participate/text-submission.service'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { DomainChange, DomainType, FileType } from 'app/exercises/programming/shared/code-editor/model/code-editor.model'; import { PlagiarismSubmission } from 'app/exercises/shared/plagiarism/types/PlagiarismSubmission'; import { TextSubmissionElement } from 'app/exercises/shared/plagiarism/types/text/TextSubmissionElement'; diff --git a/src/test/javascript/spec/component/programming-assessment/code-editor-tutor-assessment-container.component.spec.ts b/src/test/javascript/spec/component/programming-assessment/code-editor-tutor-assessment-container.component.spec.ts index 059cbe0252d6..92350e8377d9 100644 --- a/src/test/javascript/spec/component/programming-assessment/code-editor-tutor-assessment-container.component.spec.ts +++ b/src/test/javascript/spec/component/programming-assessment/code-editor-tutor-assessment-container.component.spec.ts @@ -14,10 +14,10 @@ import { MockComponent, MockPipe, MockProvider } from 'ng-mocks'; import { RepositoryFileService } from 'app/exercises/shared/result/repository.service'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; import { ProgrammingAssessmentRepoExportButtonComponent } from 'app/exercises/programming/assess/repo-export/programming-assessment-repo-export-button.component'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { Feedback, FeedbackType } from 'app/entities/feedback.model'; import { ProgrammingAssessmentManualResultService } from 'app/exercises/programming/assess/manual-result/programming-assessment-manual-result.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { Complaint } from 'app/entities/complaint.model'; import { ComplaintService } from 'app/complaints/complaint.service'; import { MockRepositoryFileService } from '../../helpers/mocks/service/mock-repository-file.service'; diff --git a/src/test/javascript/spec/component/programming-assessment/programming-assessment-repo-export-button.component.spec.ts b/src/test/javascript/spec/component/programming-assessment/programming-assessment-repo-export-button.component.spec.ts index 28d7a4ff4867..5766fd56beda 100644 --- a/src/test/javascript/spec/component/programming-assessment/programming-assessment-repo-export-button.component.spec.ts +++ b/src/test/javascript/spec/component/programming-assessment/programming-assessment-repo-export-button.component.spec.ts @@ -1,7 +1,7 @@ import { MockComponent, MockDirective, MockPipe } from 'ng-mocks'; import dayjs from 'dayjs/esm'; import { ArtemisTestModule } from '../../test.module'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { Course } from 'app/entities/course.model'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { MockTranslateValuesDirective } from '../../helpers/mocks/directive/mock-translate-values.directive'; diff --git a/src/test/javascript/spec/component/programming-assessment/programming-assessment-repo-export-dialog.component.spec.ts b/src/test/javascript/spec/component/programming-assessment/programming-assessment-repo-export-dialog.component.spec.ts index c137b2e2db37..7f9e8d1d6ed4 100644 --- a/src/test/javascript/spec/component/programming-assessment/programming-assessment-repo-export-dialog.component.spec.ts +++ b/src/test/javascript/spec/component/programming-assessment/programming-assessment-repo-export-dialog.component.spec.ts @@ -6,7 +6,7 @@ import { MockComponent, MockDirective, MockPipe } from 'ng-mocks'; import dayjs from 'dayjs/esm'; import { ArtemisTestModule } from '../../test.module'; import { ProgrammingAssessmentRepoExportDialogComponent } from 'app/exercises/programming/assess/repo-export/programming-assessment-repo-export-dialog.component'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { Course } from 'app/entities/course.model'; import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; import { ProgrammingAssessmentRepoExportService } from 'app/exercises/programming/assess/repo-export/programming-assessment-repo-export.service'; diff --git a/src/test/javascript/spec/component/programming-exercise/build-plan-editor.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/build-plan-editor.component.spec.ts index a62e6c9be607..b629be2732b0 100644 --- a/src/test/javascript/spec/component/programming-exercise/build-plan-editor.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/build-plan-editor.component.spec.ts @@ -6,7 +6,7 @@ import { ProgrammingExerciseService } from 'app/exercises/programming/manage/ser import { MockProgrammingExerciseService } from '../../helpers/mocks/service/mock-programming-exercise.service'; import { MockActivatedRoute } from '../../helpers/mocks/activated-route/mock-activated-route'; import { ActivatedRoute, ActivatedRouteSnapshot } from '@angular/router'; -import { BuildPlan } from 'app/entities/build-plan.model'; +import { BuildPlan } from 'app/entities/programming/build-plan.model'; import { of, throwError } from 'rxjs'; import { HttpResponse } from '@angular/common/http'; import { MockBuildPlanService } from '../../helpers/mocks/service/mock-build-plan.service'; @@ -15,7 +15,7 @@ import { MockComponent } from 'ng-mocks'; import { UpdatingResultComponent } from 'app/exercises/shared/result/updating-result.component'; import { NgbTooltipMocksModule } from '../../helpers/mocks/directive/ngbTooltipMocks.module'; import { TranslatePipeMock } from '../../helpers/mocks/service/mock-translate.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { AlertService } from 'app/core/util/alert.service'; import { MockAlertService } from '../../helpers/mocks/service/mock-alert.service'; import { MonacoEditorComponent } from 'app/shared/monaco-editor/monaco-editor.component'; diff --git a/src/test/javascript/spec/component/programming-exercise/category-issues-chart.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/category-issues-chart.component.spec.ts index 3a8cce90d652..17fee925d299 100644 --- a/src/test/javascript/spec/component/programming-exercise/category-issues-chart.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/category-issues-chart.component.spec.ts @@ -1,6 +1,6 @@ import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; import { CategoryIssuesChartComponent } from 'app/exercises/programming/manage/grading/charts/category-issues-chart.component'; -import { StaticCodeAnalysisCategory, StaticCodeAnalysisCategoryState } from 'app/entities/static-code-analysis-category.model'; +import { StaticCodeAnalysisCategory, StaticCodeAnalysisCategoryState } from 'app/entities/programming/static-code-analysis-category.model'; describe('CategoryIssuesChartComponent', () => { let fixture: ComponentFixture; diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-configure-grading.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-configure-grading.component.spec.ts index 603c70222109..714f39e19564 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-configure-grading.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-configure-grading.component.spec.ts @@ -7,10 +7,10 @@ import { NgxDatatableModule } from '@flaviosantoro92/ngx-datatable'; import { NgbModal, NgbModalRef, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'; import { AlertService } from 'app/core/util/alert.service'; import { ExerciseType } from 'app/entities/exercise.model'; -import { ProgrammingExerciseGradingStatistics } from 'app/entities/programming-exercise-test-case-statistics.model'; -import { ProgrammingExerciseTestCase, Visibility } from 'app/entities/programming-exercise-test-case.model'; -import { ProgrammingExercise, ProgrammingLanguage } from 'app/entities/programming-exercise.model'; -import { StaticCodeAnalysisCategory, StaticCodeAnalysisCategoryState } from 'app/entities/static-code-analysis-category.model'; +import { ProgrammingExerciseGradingStatistics } from 'app/entities/programming/programming-exercise-test-case-statistics.model'; +import { ProgrammingExerciseTestCase, Visibility } from 'app/entities/programming/programming-exercise-test-case.model'; +import { ProgrammingExercise, ProgrammingLanguage } from 'app/entities/programming/programming-exercise.model'; +import { StaticCodeAnalysisCategory, StaticCodeAnalysisCategoryState } from 'app/entities/programming/static-code-analysis-category.model'; import { CategoryIssuesChartComponent } from 'app/exercises/programming/manage/grading/charts/category-issues-chart.component'; import { ScaCategoryDistributionChartComponent } from 'app/exercises/programming/manage/grading/charts/sca-category-distribution-chart.component'; import { TestCaseDistributionChartComponent } from 'app/exercises/programming/manage/grading/charts/test-case-distribution-chart.component'; diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-create-buttons.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-create-buttons.component.spec.ts index 17f226cd84d6..630029986a67 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-create-buttons.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-create-buttons.component.spec.ts @@ -2,7 +2,7 @@ import { TestBed } from '@angular/core/testing'; import { ExerciseType } from 'app/entities/exercise.model'; import { ArtemisTestModule } from '../../test.module'; import { ProgrammingExerciseComponent } from 'app/exercises/programming/manage/programming-exercise.component'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { MockTranslateService } from '../../helpers/mocks/service/mock-translate.service'; import { TranslateService } from '@ngx-translate/core'; import { ActivatedRoute, convertToParamMap } from '@angular/router'; diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-custom-aeolus-build-plan.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-custom-aeolus-build-plan.component.spec.ts index fdc1d42c64b1..8b59cc5e8c6b 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-custom-aeolus-build-plan.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-custom-aeolus-build-plan.component.spec.ts @@ -1,16 +1,10 @@ import { TestBed } from '@angular/core/testing'; +import { BuildAction, PlatformAction, ScriptAction } from 'app/entities/programming/build.action'; +import { DockerConfiguration } from 'app/entities/programming/docker.configuration'; +import { WindFile } from 'app/entities/programming/wind.file'; +import { WindMetadata } from 'app/entities/programming/wind.metadata'; import { ArtemisTestModule } from '../../test.module'; -import { - BuildAction, - DockerConfiguration, - PlatformAction, - ProgrammingExercise, - ProgrammingLanguage, - ProjectType, - ScriptAction, - WindFile, - WindMetadata, -} from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise, ProgrammingLanguage, ProjectType } from 'app/entities/programming/programming-exercise.model'; import { ActivatedRoute, convertToParamMap } from '@angular/router'; import { Course } from 'app/entities/course.model'; import { ProgrammingExerciseCustomAeolusBuildPlanComponent } from 'app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-custom-aeolus-build-plan.component'; diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-custom-build-plan.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-custom-build-plan.component.spec.ts index fe342f5eac56..b2ec21d46f82 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-custom-build-plan.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-custom-build-plan.component.spec.ts @@ -1,16 +1,10 @@ import { TestBed } from '@angular/core/testing'; +import { BuildAction, PlatformAction, ScriptAction } from 'app/entities/programming/build.action'; +import { DockerConfiguration } from 'app/entities/programming/docker.configuration'; +import { WindFile } from 'app/entities/programming/wind.file'; +import { WindMetadata } from 'app/entities/programming/wind.metadata'; import { ArtemisTestModule } from '../../test.module'; -import { - BuildAction, - DockerConfiguration, - PlatformAction, - ProgrammingExercise, - ProgrammingLanguage, - ProjectType, - ScriptAction, - WindFile, - WindMetadata, -} from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise, ProgrammingLanguage, ProjectType } from 'app/entities/programming/programming-exercise.model'; import { ActivatedRoute, convertToParamMap } from '@angular/router'; import { Course } from 'app/entities/course.model'; import { ElementRef, Renderer2 } from '@angular/core'; diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-detail.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-detail.component.spec.ts index 47ea2df80cb5..8563723b42b8 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-detail.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-detail.component.spec.ts @@ -3,7 +3,7 @@ import { ActivatedRoute, Router } from '@angular/router'; import { of, throwError } from 'rxjs'; import { ArtemisTestModule } from '../../test.module'; import { ProgrammingExerciseDetailComponent } from 'app/exercises/programming/manage/programming-exercise-detail.component'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { MockActivatedRoute } from '../../helpers/mocks/activated-route/mock-activated-route'; import { Course } from 'app/entities/course.model'; import { TranslateModule } from '@ngx-translate/core'; @@ -11,7 +11,7 @@ import { StatisticsService } from 'app/shared/statistics-graph/statistics.servic import { ExerciseManagementStatisticsDto } from 'app/exercises/shared/statistics/exercise-management-statistics-dto'; import { ProfileService } from 'app/shared/layouts/profiles/profile.service'; import { MockProfileService } from '../../helpers/mocks/service/mock-profile.service'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ProgrammingExerciseGradingService } from 'app/exercises/programming/manage/services/programming-exercise-grading.service'; import { MockProgrammingExerciseService } from '../../helpers/mocks/service/mock-programming-exercise.service'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; @@ -24,7 +24,7 @@ import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { MockProgrammingExerciseGradingService } from '../../helpers/mocks/service/mock-programming-exercise-grading.service'; import { ProgrammingExerciseGitDiffReport } from 'app/entities/hestia/programming-exercise-git-diff-report.model'; import { ProgrammingExerciseSolutionEntry } from 'app/entities/hestia/programming-exercise-solution-entry.model'; -import { BuildLogStatisticsDTO } from 'app/entities/build-log-statistics-dto'; +import { BuildLogStatisticsDTO } from 'app/entities/programming/build-log-statistics-dto'; import { TemplateProgrammingExerciseParticipation } from 'app/entities/participation/template-programming-exercise-participation.model'; import { SolutionProgrammingExerciseParticipation } from 'app/entities/participation/solution-programming-exercise-participation.model'; import { HttpResponse } from '@angular/common/http'; diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-edit-selected.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-edit-selected.component.spec.ts index 550e8a533d0c..802cb0180956 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-edit-selected.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-edit-selected.component.spec.ts @@ -7,7 +7,7 @@ import dayjs from 'dayjs/esm'; import { ArtemisTestModule } from '../../test.module'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.service'; import { MockTranslateService } from '../../helpers/mocks/service/mock-translate.service'; diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-editable-instruction.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-editable-instruction.component.spec.ts index 14ced4c71eea..c00bb591678c 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-editable-instruction.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-editable-instruction.component.spec.ts @@ -17,7 +17,7 @@ import { TemplateProgrammingExerciseParticipation } from 'app/entities/participa import { ProgrammingExerciseParticipationService } from 'app/exercises/programming/manage/services/programming-exercise-participation.service'; import { IProgrammingExerciseGradingService, ProgrammingExerciseGradingService } from 'app/exercises/programming/manage/services/programming-exercise-grading.service'; import { Result } from 'app/entities/result.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ProgrammingExerciseInstructionAnalysisComponent } from 'app/exercises/programming/manage/instructions-editor/analysis/programming-exercise-instruction-analysis.component'; import { ProgrammingExerciseEditableInstructionComponent } from 'app/exercises/programming/manage/instructions-editor/programming-exercise-editable-instruction.component'; import { ProgrammingExerciseInstructionComponent } from 'app/exercises/programming/shared/instructions-render/programming-exercise-instruction.component'; diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-instruction.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-instruction.component.spec.ts index 4a4bee296170..3cfff55d7749 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-instruction.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-instruction.component.spec.ts @@ -31,7 +31,7 @@ import { ProgrammingExerciseParticipationService } from 'app/exercises/programmi import { ProgrammingExerciseInstructionTaskStatusComponent } from 'app/exercises/programming/shared/instructions-render/task/programming-exercise-instruction-task-status.component'; import { Result } from 'app/entities/result.model'; import { ProgrammingExerciseInstructionComponent } from 'app/exercises/programming/shared/instructions-render/programming-exercise-instruction.component'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { FeedbackComponent } from 'app/exercises/shared/feedback/feedback.component'; import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.service'; import { MockParticipationWebsocketService } from '../../helpers/mocks/service/mock-participation-websocket.service'; diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-instructor-status.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-instructor-status.component.spec.ts index 6f8ec78aa596..0d90f4c63d76 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-instructor-status.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-instructor-status.component.spec.ts @@ -8,8 +8,8 @@ import { Result } from 'app/entities/result.model'; import { ParticipationWebsocketService } from 'app/overview/participation-websocket.service'; import { triggerChanges } from '../../helpers/utils/general.utils'; import { ProgrammingExerciseInstructorStatusComponent } from 'app/exercises/programming/manage/status/programming-exercise-instructor-status.component'; -import { ProgrammingExerciseParticipationType } from 'app/entities/programming-exercise-participation.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExerciseParticipationType } from 'app/entities/programming/programming-exercise-participation.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { TemplateProgrammingExerciseParticipation } from 'app/entities/participation/template-programming-exercise-participation.model'; import { SolutionProgrammingExerciseParticipation } from 'app/entities/participation/solution-programming-exercise-participation.model'; import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model'; diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-instructor-submission-state.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-instructor-submission-state.component.spec.ts index e1638e73e8e8..0a0bee0d069b 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-instructor-submission-state.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-instructor-submission-state.component.spec.ts @@ -12,7 +12,7 @@ import { ExerciseSubmissionState, ProgrammingSubmissionService, ProgrammingSubmi import { ProgrammingExerciseInstructorSubmissionStateComponent } from 'app/exercises/programming/shared/actions/programming-exercise-instructor-submission-state.component'; import { triggerChanges } from '../../helpers/utils/general.utils'; import { BuildRunState, ProgrammingBuildRunService } from 'app/exercises/programming/participate/programming-build-run.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { TranslatePipeMock } from '../../helpers/mocks/service/mock-translate.service'; import { MockDirective, MockModule, MockPipe } from 'ng-mocks'; import { ProgrammingExerciseTriggerAllButtonComponent } from 'app/exercises/programming/shared/actions/programming-exercise-trigger-all-button.component'; diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-instructor-trigger-build-button.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-instructor-trigger-build-button.component.spec.ts index f488e31968f6..bf9b03e41e6c 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-instructor-trigger-build-button.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-instructor-trigger-build-button.component.spec.ts @@ -1,6 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ArtemisTestModule } from '../../test.module'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.service'; import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { Course } from 'app/entities/course.model'; diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-lifecycle.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-lifecycle.component.spec.ts index b9bbd8e9ad28..32c41626803d 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-lifecycle.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-lifecycle.component.spec.ts @@ -4,7 +4,7 @@ import { ArtemisTestModule } from '../../test.module'; import { MockComponent, MockDirective } from 'ng-mocks'; import { ProgrammingExerciseLifecycleComponent } from 'app/exercises/programming/shared/lifecycle/programming-exercise-lifecycle.component'; import { HelpIconComponent } from 'app/shared/components/help-icon.component'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ProgrammingExerciseTestScheduleDatePickerComponent } from 'app/exercises/programming/shared/lifecycle/programming-exercise-test-schedule-date-picker.component'; import { NgModel } from '@angular/forms'; import { AssessmentType } from 'app/entities/assessment-type.model'; diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-re-evaluate-button.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-re-evaluate-button.component.spec.ts index 9283221d1266..16bd1cdf33b0 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-re-evaluate-button.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-re-evaluate-button.component.spec.ts @@ -1,6 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ArtemisTestModule } from '../../test.module'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.service'; import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { Course } from 'app/entities/course.model'; diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-repository-and-build-plan-details.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-repository-and-build-plan-details.component.spec.ts index ccc542ea3ec5..aa7f5e3e80bb 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-repository-and-build-plan-details.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-repository-and-build-plan-details.component.spec.ts @@ -1,11 +1,11 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; -import { CheckoutDirectoriesDto } from 'app/entities/checkout-directories-dto'; -import { ProgrammingExercise, ProgrammingLanguage } from 'app/entities/programming-exercise.model'; +import { CheckoutDirectoriesDto } from 'app/entities/programming/checkout-directories-dto'; +import { ProgrammingExercise, ProgrammingLanguage } from 'app/entities/programming/programming-exercise.model'; import { HelpIconComponent } from 'app/shared/components/help-icon.component'; import { MockComponent } from 'ng-mocks'; import { Subscription, of } from 'rxjs'; -import { AuxiliaryRepository } from 'app/entities/programming-exercise-auxiliary-repository-model'; +import { AuxiliaryRepository } from 'app/entities/programming/programming-exercise-auxiliary-repository-model'; import { SimpleChanges } from '@angular/core'; import { ProgrammingExerciseBuildPlanCheckoutDirectoriesComponent } from 'app/exercises/programming/shared/build-details/programming-exercise-build-plan-checkout-directories.component'; import { ProgrammingExerciseRepositoryAndBuildPlanDetailsComponent } from 'app/exercises/programming/shared/build-details/programming-exercise-repository-and-build-plan-details.component'; diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-reset-dialog.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-reset-dialog.component.spec.ts index 6f1c53159b02..596b3dfad522 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-reset-dialog.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-reset-dialog.component.spec.ts @@ -6,7 +6,7 @@ import { MockComponent, MockDirective, MockPipe } from 'ng-mocks'; import dayjs from 'dayjs/esm'; import { ArtemisTestModule } from '../../test.module'; import { ProgrammingExerciseResetDialogComponent } from 'app/exercises/programming/manage/reset/programming-exercise-reset-dialog.component'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { Course } from 'app/entities/course.model'; import { ProgrammingExerciseResetOptions, ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; import { AlertService } from 'app/core/util/alert.service'; diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-test-case-passed-builds-charts.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-test-case-passed-builds-charts.component.spec.ts index 18603184899b..b237c4ad56c7 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-test-case-passed-builds-charts.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-test-case-passed-builds-charts.component.spec.ts @@ -1,7 +1,7 @@ import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; import { TestCasePassedBuildsChartComponent } from 'app/exercises/programming/manage/grading/charts/test-case-passed-builds-chart.component'; -import { TestCaseStats } from 'app/entities/programming-exercise-test-case-statistics.model'; +import { TestCaseStats } from 'app/entities/programming/programming-exercise-test-case-statistics.model'; describe('TestCasePassedBuildsChartComponent', () => { let comp: TestCasePassedBuildsChartComponent; diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-trigger-all-button.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-trigger-all-button.component.spec.ts index 019291c960f3..000cf3dbeb54 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-trigger-all-button.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-trigger-all-button.component.spec.ts @@ -1,6 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ArtemisTestModule } from '../../test.module'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.service'; import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { Course } from 'app/entities/course.model'; diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-trigger-build-button.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-trigger-build-button.component.spec.ts index 5a74d40dec87..c50aa8ffcea1 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-trigger-build-button.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-trigger-build-button.component.spec.ts @@ -19,7 +19,7 @@ import { ArtemisProgrammingExerciseActionsModule } from 'app/exercises/programmi import { triggerChanges } from '../../helpers/utils/general.utils'; import { InitializationState } from 'app/entities/participation/participation.model'; import { ProgrammingExerciseStudentTriggerBuildButtonComponent } from 'app/exercises/programming/shared/actions/programming-exercise-student-trigger-build-button.component'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { AssessmentType } from 'app/entities/assessment-type.model'; describe('TriggerBuildButtonSpec', () => { diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise-update.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise-update.component.spec.ts index 5441500fe1a3..093df3a0508f 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise-update.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise-update.component.spec.ts @@ -2,13 +2,14 @@ import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testin import { DebugElement } from '@angular/core'; import { HttpHeaders, HttpResponse } from '@angular/common/http'; import { ActivatedRoute, UrlSegment } from '@angular/router'; +import { WindFile } from 'app/entities/programming/wind.file'; import { Subject, of, throwError } from 'rxjs'; import dayjs from 'dayjs/esm'; import { MockNgbModalService } from '../../helpers/mocks/service/mock-ngb-modal.service'; import { ArtemisTestModule } from '../../test.module'; import { ProgrammingExerciseUpdateComponent } from 'app/exercises/programming/manage/update/programming-exercise-update.component'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; -import { ProgrammingExercise, ProgrammingLanguage, ProjectType, WindFile } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise, ProgrammingLanguage, ProjectType } from 'app/entities/programming/programming-exercise.model'; import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.service'; import { MockTranslateService } from '../../helpers/mocks/service/mock-translate.service'; @@ -62,7 +63,7 @@ import { ExerciseCategory } from 'app/entities/exercise-category.model'; import { ExerciseUpdateNotificationComponent } from 'app/exercises/shared/exercise-update-notification/exercise-update-notification.component'; import { ExerciseUpdatePlagiarismComponent } from 'app/exercises/shared/plagiarism/exercise-update-plagiarism/exercise-update-plagiarism.component'; import * as Utils from 'app/exercises/shared/course-exercises/course-utils'; -import { AuxiliaryRepository } from 'app/entities/programming-exercise-auxiliary-repository-model'; +import { AuxiliaryRepository } from 'app/entities/programming/programming-exercise-auxiliary-repository-model'; import { AlertService, AlertType } from 'app/core/util/alert.service'; import { FormStatusBarComponent } from 'app/forms/form-status-bar/form-status-bar.component'; import { FormFooterComponent } from 'app/forms/form-footer/form-footer.component'; diff --git a/src/test/javascript/spec/component/programming-exercise/programming-exercise.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/programming-exercise.component.spec.ts index 7915f67f8f84..ec6b28b573ab 100644 --- a/src/test/javascript/spec/component/programming-exercise/programming-exercise.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/programming-exercise.component.spec.ts @@ -3,7 +3,7 @@ import { HttpErrorResponse, HttpHeaders, HttpResponse } from '@angular/common/ht import { of, throwError } from 'rxjs'; import { ArtemisTestModule } from '../../test.module'; import { ProgrammingExerciseComponent } from 'app/exercises/programming/manage/programming-exercise.component'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.service'; import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { MockTranslateService } from '../../helpers/mocks/service/mock-translate.service'; diff --git a/src/test/javascript/spec/component/programming-exercise/sca-category-distribution-chart.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/sca-category-distribution-chart.component.spec.ts index fb52afff1ebc..863bb75ed2ca 100644 --- a/src/test/javascript/spec/component/programming-exercise/sca-category-distribution-chart.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/sca-category-distribution-chart.component.spec.ts @@ -6,9 +6,9 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MockModule, MockPipe, MockProvider } from 'ng-mocks'; import { BarChartModule } from '@swimlane/ngx-charts'; import { TranslateService } from '@ngx-translate/core'; -import { StaticCodeAnalysisCategory, StaticCodeAnalysisCategoryState } from 'app/entities/static-code-analysis-category.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; -import { CategoryIssuesMap } from 'app/entities/programming-exercise-test-case-statistics.model'; +import { StaticCodeAnalysisCategory, StaticCodeAnalysisCategoryState } from 'app/entities/programming/static-code-analysis-category.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; +import { CategoryIssuesMap } from 'app/entities/programming/programming-exercise-test-case-statistics.model'; import { ArtemisNavigationUtilService } from 'app/utils/navigation.utils'; describe('SCA category distribution chart', () => { diff --git a/src/test/javascript/spec/component/programming-exercise/tasks/programming-exercise-grading-tasks-table.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/tasks/programming-exercise-grading-tasks-table.component.spec.ts index 760a02a0c910..dea5aea61f5d 100644 --- a/src/test/javascript/spec/component/programming-exercise/tasks/programming-exercise-grading-tasks-table.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/tasks/programming-exercise-grading-tasks-table.component.spec.ts @@ -3,8 +3,8 @@ import { ArtemisTestModule } from '../../../test.module'; import { ProgrammingExerciseGradingTasksTableComponent } from 'app/exercises/programming/manage/grading/tasks/programming-exercise-grading-tasks-table.component'; import { ProgrammingExerciseTaskService } from 'app/exercises/programming/manage/grading/tasks/programming-exercise-task.service'; import { Observable, Subject, of } from 'rxjs'; -import { ProgrammingExerciseGradingStatistics } from 'app/entities/programming-exercise-test-case-statistics.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExerciseGradingStatistics } from 'app/entities/programming/programming-exercise-test-case-statistics.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { Course } from 'app/entities/course.model'; import { TranslateService } from '@ngx-translate/core'; import { MockTranslateService } from '../../../helpers/mocks/service/mock-translate.service'; @@ -12,7 +12,7 @@ import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { MockComponent, MockPipe } from 'ng-mocks'; import { ProgrammingExerciseTask } from 'app/exercises/programming/manage/grading/tasks/programming-exercise-task'; import { ButtonComponent } from 'app/shared/components/button.component'; -import { ProgrammingExerciseTestCase } from 'app/entities/programming-exercise-test-case.model'; +import { ProgrammingExerciseTestCase } from 'app/entities/programming/programming-exercise-test-case.model'; describe('ProgrammingExerciseGradingTasksTableComponent', () => { let fixture; diff --git a/src/test/javascript/spec/component/programming-exercise/tasks/programming-exercise-task.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/tasks/programming-exercise-task.component.spec.ts index fe23d6eea2d4..2f0c52e95903 100644 --- a/src/test/javascript/spec/component/programming-exercise/tasks/programming-exercise-task.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/tasks/programming-exercise-task.component.spec.ts @@ -7,7 +7,7 @@ import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { MockComponent, MockPipe } from 'ng-mocks'; import { ProgrammingExerciseTask } from 'app/exercises/programming/manage/grading/tasks/programming-exercise-task'; import { ProgrammingExerciseTaskComponent } from 'app/exercises/programming/manage/grading/tasks/programming-exercise-task/programming-exercise-task.component'; -import { Visibility } from 'app/entities/programming-exercise-test-case.model'; +import { Visibility } from 'app/entities/programming/programming-exercise-test-case.model'; import { TestCasePassedBuildsChartComponent } from 'app/exercises/programming/manage/grading/charts/test-case-passed-builds-chart.component'; import { Subject } from 'rxjs'; diff --git a/src/test/javascript/spec/component/programming-exercise/test-case-distribution-chart.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/test-case-distribution-chart.component.spec.ts index 32a4f2bd9ab9..f022af2d9cd1 100644 --- a/src/test/javascript/spec/component/programming-exercise/test-case-distribution-chart.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/test-case-distribution-chart.component.spec.ts @@ -5,10 +5,10 @@ import { TranslateService } from '@ngx-translate/core'; import { TestCaseDistributionChartComponent } from 'app/exercises/programming/manage/grading/charts/test-case-distribution-chart.component'; import { MockModule, MockPipe, MockProvider } from 'ng-mocks'; import { BarChartModule } from '@swimlane/ngx-charts'; -import { ProgrammingExerciseTestCase, Visibility } from 'app/entities/programming-exercise-test-case.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExerciseTestCase, Visibility } from 'app/entities/programming/programming-exercise-test-case.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; -import { TestCaseStatsMap } from 'app/entities/programming-exercise-test-case-statistics.model'; +import { TestCaseStatsMap } from 'app/entities/programming/programming-exercise-test-case-statistics.model'; import { ArtemisNavigationUtilService } from 'app/utils/navigation.utils'; describe('Test case distribution chart', () => { diff --git a/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-creation-config-mock.ts b/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-creation-config-mock.ts index 7879f1f5c0b5..0b99443e2f99 100644 --- a/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-creation-config-mock.ts +++ b/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-creation-config-mock.ts @@ -1,8 +1,8 @@ import { ProgrammingExerciseCreationConfig } from 'app/exercises/programming/manage/update/programming-exercise-creation-config'; import { Observable } from 'rxjs'; -import { ProgrammingLanguage, ProjectType } from 'app/entities/programming-exercise.model'; +import { ProgrammingLanguage, ProjectType } from 'app/entities/programming/programming-exercise.model'; import { ExerciseCategory } from 'app/entities/exercise-category.model'; -import { AuxiliaryRepository } from 'app/entities/programming-exercise-auxiliary-repository-model'; +import { AuxiliaryRepository } from 'app/entities/programming/programming-exercise-auxiliary-repository-model'; /* eslint-disable @typescript-eslint/no-unused-vars */ export const programmingExerciseCreationConfigMock: ProgrammingExerciseCreationConfig = { diff --git a/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-difficulty.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-difficulty.component.spec.ts index ce4ba0bc736f..70c70a17dd5b 100644 --- a/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-difficulty.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-difficulty.component.spec.ts @@ -9,7 +9,7 @@ import { CheckboxControlValueAccessor, DefaultValueAccessor, NgModel, NumberValu import { DifficultyPickerComponent } from 'app/exercises/shared/difficulty-picker/difficulty-picker.component'; import { TeamConfigFormGroupComponent } from 'app/exercises/shared/team-config-form-group/team-config-form-group.component'; import { programmingExerciseCreationConfigMock } from './programming-exercise-creation-config-mock'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ProfileInfo } from 'app/shared/layouts/profiles/profile-info.model'; import { ProfileService } from 'app/shared/layouts/profiles/profile.service'; import { PROFILE_THEIA } from 'app/app.constants'; diff --git a/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-grading.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-grading.component.spec.ts index e59522cf01aa..8087a70b7cea 100644 --- a/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-grading.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-grading.component.spec.ts @@ -4,7 +4,7 @@ import { ActivatedRoute } from '@angular/router'; import { Subject, of } from 'rxjs'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { ProgrammingExerciseGradingComponent } from 'app/exercises/programming/manage/update/update-components/programming-exercise-grading.component'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { IncludedInOverallScore } from 'app/entities/exercise.model'; import { AssessmentType } from 'app/entities/assessment-type.model'; import { SubmissionPolicyType } from 'app/entities/submission-policy.model'; diff --git a/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-information.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-information.component.spec.ts index 30259859d720..963ef4c6ff37 100644 --- a/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-information.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-information.component.spec.ts @@ -6,7 +6,7 @@ import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { ProgrammingExerciseInformationComponent } from 'app/exercises/programming/manage/update/update-components/programming-exercise-information.component'; import { DefaultValueAccessor, NgModel } from '@angular/forms'; import { RemoveKeysPipe } from 'app/shared/pipes/remove-keys.pipe'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { HelpIconComponent } from 'app/shared/components/help-icon.component'; import { CategorySelectorComponent } from 'app/shared/category-selector/category-selector.component'; import { AddAuxiliaryRepositoryButtonComponent } from 'app/exercises/programming/manage/update/add-auxiliary-repository-button.component'; diff --git a/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-language.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-language.component.spec.ts index 4d21b3741ce6..55eefafd0162 100644 --- a/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-language.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-language.component.spec.ts @@ -5,7 +5,7 @@ import { of } from 'rxjs'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { CheckboxControlValueAccessor, DefaultValueAccessor, NgModel, NumberValueAccessor, SelectControlValueAccessor } from '@angular/forms'; import { RemoveKeysPipe } from 'app/shared/pipes/remove-keys.pipe'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ProgrammingExerciseLanguageComponent } from 'app/exercises/programming/manage/update/update-components/programming-exercise-language.component'; import { programmingExerciseCreationConfigMock } from './programming-exercise-creation-config-mock'; import { ProgrammingExerciseTheiaComponent } from 'app/exercises/programming/manage/update/update-components/theia/programming-exercise-theia.component'; diff --git a/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-problem.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-problem.component.spec.ts index b56a555ea0ff..51ded01756bf 100644 --- a/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-problem.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/update-components/programming-exercise-problem.component.spec.ts @@ -4,7 +4,7 @@ import { ActivatedRoute } from '@angular/router'; import { of } from 'rxjs'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { ProgrammingExerciseProblemComponent } from 'app/exercises/programming/manage/update/update-components/programming-exercise-problem.component'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { CompetencySelectionComponent } from 'app/shared/competency-selection/competency-selection.component'; import { NgModel } from '@angular/forms'; diff --git a/src/test/javascript/spec/component/programming-exercise/update-components/remove-auxiliary-repository-button.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/update-components/remove-auxiliary-repository-button.component.spec.ts index 7cec929c092d..cc205e0a226e 100644 --- a/src/test/javascript/spec/component/programming-exercise/update-components/remove-auxiliary-repository-button.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/update-components/remove-auxiliary-repository-button.component.spec.ts @@ -4,9 +4,9 @@ import { RemoveAuxiliaryRepositoryButtonComponent } from 'app/exercises/programm import { ArtemisTestModule } from '../../../test.module'; import { ButtonComponent } from 'app/shared/components/button.component'; import { MockComponent } from 'ng-mocks'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { Course } from 'app/entities/course.model'; -import { AuxiliaryRepository } from 'app/entities/programming-exercise-auxiliary-repository-model'; +import { AuxiliaryRepository } from 'app/entities/programming/programming-exercise-auxiliary-repository-model'; describe('RemoveAuxiliaryRepositoryButton', () => { let comp: RemoveAuxiliaryRepositoryButtonComponent; diff --git a/src/test/javascript/spec/component/programming-exercise/update-components/theia/programming-exercise-theia.component.spec.ts b/src/test/javascript/spec/component/programming-exercise/update-components/theia/programming-exercise-theia.component.spec.ts index 13f4e23cbbcd..ab3018105eaa 100644 --- a/src/test/javascript/spec/component/programming-exercise/update-components/theia/programming-exercise-theia.component.spec.ts +++ b/src/test/javascript/spec/component/programming-exercise/update-components/theia/programming-exercise-theia.component.spec.ts @@ -4,7 +4,7 @@ import { ActivatedRoute } from '@angular/router'; import { of } from 'rxjs'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { RemoveKeysPipe } from 'app/shared/pipes/remove-keys.pipe'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { programmingExerciseCreationConfigMock } from '../programming-exercise-creation-config-mock'; import { ProgrammingExerciseTheiaComponent } from 'app/exercises/programming/manage/update/update-components/theia/programming-exercise-theia.component'; import { TheiaService } from 'app/exercises/programming/shared/service/theia.service'; diff --git a/src/test/javascript/spec/component/quiz-exercise/quiz-exercise-update.component.spec.ts b/src/test/javascript/spec/component/quiz-exercise/quiz-exercise-update.component.spec.ts index a7e1309fcea0..a93c87bdf3f3 100644 --- a/src/test/javascript/spec/component/quiz-exercise/quiz-exercise-update.component.spec.ts +++ b/src/test/javascript/spec/component/quiz-exercise/quiz-exercise-update.component.spec.ts @@ -35,7 +35,7 @@ import { MockRouter } from '../../helpers/mocks/mock-router'; import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.service'; import { MockTranslateService } from '../../helpers/mocks/service/mock-translate.service'; import { ArtemisTestModule } from '../../test.module'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { MockProvider } from 'ng-mocks'; import { Duration } from 'app/exercises/quiz/manage/quiz-exercise-interfaces'; import { QuizQuestionListEditComponent } from 'app/exercises/quiz/manage/quiz-question-list-edit.component'; diff --git a/src/test/javascript/spec/component/shared/commits-info-group.component.spec.ts b/src/test/javascript/spec/component/shared/commits-info-group.component.spec.ts index 5765ddfd3f8b..ddcf06c215a2 100644 --- a/src/test/javascript/spec/component/shared/commits-info-group.component.spec.ts +++ b/src/test/javascript/spec/component/shared/commits-info-group.component.spec.ts @@ -4,7 +4,7 @@ import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { MockPipe } from 'ng-mocks'; import dayjs from 'dayjs/esm'; import { ArtemisTestModule } from '../../test.module'; -import type { CommitInfo } from 'app/entities/programming-submission.model'; +import type { CommitInfo } from 'app/entities/programming/programming-submission.model'; import { CommitsInfoRowComponent } from 'app/exercises/programming/shared/commits-info/commits-info-group/commits-info-row/commits-info-row.component'; import { ArtemisDatePipe } from 'app/shared/pipes/artemis-date.pipe'; import { TruncatePipe } from 'app/shared/pipes/truncate.pipe'; diff --git a/src/test/javascript/spec/component/shared/commits-info.component.spec.ts b/src/test/javascript/spec/component/shared/commits-info.component.spec.ts index 0b5dc3c7fae6..3d7c860143ce 100644 --- a/src/test/javascript/spec/component/shared/commits-info.component.spec.ts +++ b/src/test/javascript/spec/component/shared/commits-info.component.spec.ts @@ -7,7 +7,7 @@ import { ArtemisTestModule } from '../../test.module'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { MockPipe } from 'ng-mocks'; import { of } from 'rxjs'; -import { CommitInfo } from 'app/entities/programming-submission.model'; +import { CommitInfo } from 'app/entities/programming/programming-submission.model'; import { ProfileService } from 'app/shared/layouts/profiles/profile.service'; import { ProfileInfo } from 'app/shared/layouts/profiles/profile-info.model'; import { ParticipationType } from 'app/entities/participation/participation.model'; diff --git a/src/test/javascript/spec/component/shared/course-exam-archive-button.component.spec.ts b/src/test/javascript/spec/component/shared/course-exam-archive-button.component.spec.ts index c667429e667b..7093eb87a5d0 100644 --- a/src/test/javascript/spec/component/shared/course-exam-archive-button.component.spec.ts +++ b/src/test/javascript/spec/component/shared/course-exam-archive-button.component.spec.ts @@ -19,7 +19,7 @@ import { DeleteButtonDirective } from 'app/shared/delete-dialog/delete-button.di import { ArtemisDatePipe } from 'app/shared/pipes/artemis-date.pipe'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { CourseExamArchiveButtonComponent, CourseExamArchiveState } from 'app/shared/components/course-exam-archive-button/course-exam-archive-button.component'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExamManagementService } from 'app/exam/manage/exam-management.service'; import { AccountService } from 'app/core/auth/account.service'; import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'; diff --git a/src/test/javascript/spec/component/shared/example-solution.component.spec.ts b/src/test/javascript/spec/component/shared/example-solution.component.spec.ts index 036b0ee9d044..95cc9ddbe47f 100644 --- a/src/test/javascript/spec/component/shared/example-solution.component.spec.ts +++ b/src/test/javascript/spec/component/shared/example-solution.component.spec.ts @@ -11,7 +11,7 @@ import { ArtemisDatePipe } from 'app/shared/pipes/artemis-date.pipe'; import { ExampleSolutionComponent } from 'app/exercises/shared/example-solution/example-solution.component'; import { ExampleSolutionInfo, ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; import { ArtemisMarkdownService } from 'app/shared/markdown.service'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { Exercise } from 'app/entities/exercise.model'; import { HeaderExercisePageWithDetailsComponent } from 'app/exercises/shared/exercise-headers/header-exercise-page-with-details.component'; import { HtmlForMarkdownPipe } from 'app/shared/pipes/html-for-markdown.pipe'; diff --git a/src/test/javascript/spec/component/shared/feedback/feedback-modal.component.spec.ts b/src/test/javascript/spec/component/shared/feedback/feedback-modal.component.spec.ts index 98f536f9dcea..f2123eb7f2b4 100644 --- a/src/test/javascript/spec/component/shared/feedback/feedback-modal.component.spec.ts +++ b/src/test/javascript/spec/component/shared/feedback/feedback-modal.component.spec.ts @@ -8,8 +8,8 @@ import { ExerciseType } from 'app/entities/exercise.model'; import { Feedback, FeedbackType, STATIC_CODE_ANALYSIS_FEEDBACK_IDENTIFIER } from 'app/entities/feedback.model'; import { ModelingSubmission } from 'app/entities/modeling-submission.model'; import { ParticipationType } from 'app/entities/participation/participation.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { Result } from 'app/entities/result.model'; import { SubmissionType } from 'app/entities/submission.model'; import { BuildLogService } from 'app/exercises/programming/shared/service/build-log.service'; diff --git a/src/test/javascript/spec/component/shared/feedback/standalone-feedback.component.spec.ts b/src/test/javascript/spec/component/shared/feedback/standalone-feedback.component.spec.ts index aa2aa73b8ccb..443d3b40e1a2 100644 --- a/src/test/javascript/spec/component/shared/feedback/standalone-feedback.component.spec.ts +++ b/src/test/javascript/spec/component/shared/feedback/standalone-feedback.component.spec.ts @@ -7,7 +7,7 @@ import { StandaloneFeedbackComponent } from 'app/exercises/shared/feedback/stand import { MockComponent, MockProvider } from 'ng-mocks'; import { FeedbackComponent } from 'app/exercises/shared/feedback/feedback.component'; import { Course } from 'app/entities/course.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; describe('StandaloneFeedbackComponent', () => { diff --git a/src/test/javascript/spec/component/shared/reset-repo-button.component.spec.ts b/src/test/javascript/spec/component/shared/reset-repo-button.component.spec.ts index b1bc40312d47..b910e7893f56 100644 --- a/src/test/javascript/spec/component/shared/reset-repo-button.component.spec.ts +++ b/src/test/javascript/spec/component/shared/reset-repo-button.component.spec.ts @@ -10,7 +10,7 @@ import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { MockTranslateService } from '../../helpers/mocks/service/mock-translate.service'; import { FeatureToggleDirective } from 'app/shared/feature-toggle/feature-toggle.directive'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { Subject } from 'rxjs'; import { ResetRepoButtonComponent } from 'app/shared/components/reset-repo-button/reset-repo-button.component'; import { ParticipationService } from 'app/exercises/shared/participation/participation.service'; diff --git a/src/test/javascript/spec/component/shared/start-practice-mode-button.component.spec.ts b/src/test/javascript/spec/component/shared/start-practice-mode-button.component.spec.ts index d7ac41fb943a..3df720eeefff 100644 --- a/src/test/javascript/spec/component/shared/start-practice-mode-button.component.spec.ts +++ b/src/test/javascript/spec/component/shared/start-practice-mode-button.component.spec.ts @@ -12,7 +12,7 @@ import { FeatureToggleDirective } from 'app/shared/feature-toggle/feature-toggle import { StartPracticeModeButtonComponent } from 'app/shared/components/start-practice-mode-button/start-practice-mode-button.component'; import { ExerciseType } from 'app/entities/exercise.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { InitializationState } from 'app/entities/participation/participation.model'; import { Subject } from 'rxjs'; import dayjs from 'dayjs/esm'; diff --git a/src/test/javascript/spec/component/shared/submission-policy-update.component.spec.ts b/src/test/javascript/spec/component/shared/submission-policy-update.component.spec.ts index f416514a047b..05f3eb734dee 100644 --- a/src/test/javascript/spec/component/shared/submission-policy-update.component.spec.ts +++ b/src/test/javascript/spec/component/shared/submission-policy-update.component.spec.ts @@ -1,6 +1,6 @@ import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { LockRepositoryPolicy, SubmissionPenaltyPolicy, SubmissionPolicyType } from 'app/entities/submission-policy.model'; import { SubmissionPolicyUpdateComponent } from 'app/exercises/shared/submission-policy/submission-policy-update.component'; import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; diff --git a/src/test/javascript/spec/component/shared/updating-result.component.spec.ts b/src/test/javascript/spec/component/shared/updating-result.component.spec.ts index afa519d2640b..9b8c8b9435e9 100644 --- a/src/test/javascript/spec/component/shared/updating-result.component.spec.ts +++ b/src/test/javascript/spec/component/shared/updating-result.component.spec.ts @@ -8,7 +8,7 @@ import { ProgrammingSubmissionService, ProgrammingSubmissionState } from 'app/ex import { MockProgrammingSubmissionService } from '../../helpers/mocks/service/mock-programming-submission.service'; import { triggerChanges } from '../../helpers/utils/general.utils'; import { Exercise, ExerciseType } from 'app/entities/exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { UpdatingResultComponent } from 'app/exercises/shared/result/updating-result.component'; import { ResultComponent } from 'app/exercises/shared/result/result.component'; import { Result } from 'app/entities/result.model'; diff --git a/src/test/javascript/spec/component/team/team-exercise-search.component.spec.ts b/src/test/javascript/spec/component/team/team-exercise-search.component.spec.ts index 156a40652c68..1083ee4d31fc 100644 --- a/src/test/javascript/spec/component/team/team-exercise-search.component.spec.ts +++ b/src/test/javascript/spec/component/team/team-exercise-search.component.spec.ts @@ -4,7 +4,7 @@ import dayjs from 'dayjs/esm'; import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { CourseManagementService } from 'app/course/manage/course-management.service'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { TeamExerciseSearchComponent } from 'app/exercises/shared/team/team-exercise-search/team-exercise-search.component'; import { MockCourseManagementService } from '../../helpers/mocks/service/mock-course-management.service'; import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.service'; diff --git a/src/test/javascript/spec/component/text-editor/text-editor.component.spec.ts b/src/test/javascript/spec/component/text-editor/text-editor.component.spec.ts index 6c60b40ad95e..6bfb8cf13d4f 100644 --- a/src/test/javascript/spec/component/text-editor/text-editor.component.spec.ts +++ b/src/test/javascript/spec/component/text-editor/text-editor.component.spec.ts @@ -16,12 +16,12 @@ import { TextResultComponent } from 'app/exercises/text/participate/text-result/ import { SubmissionResultStatusComponent } from 'app/overview/submission-result-status.component'; import { TextEditorComponent } from 'app/exercises/text/participate/text-editor.component'; import { textEditorRoute } from 'app/exercises/text/participate/text-editor.route'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; import { ButtonComponent } from 'app/shared/components/button.component'; import { Result } from 'app/entities/result.model'; import { ComplaintsFormComponent } from 'app/complaints/form/complaints-form.component'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { TextSubmissionService } from 'app/exercises/text/participate/text-submission.service'; import { MockTextSubmissionService } from '../../helpers/mocks/service/mock-text-submission.service'; import { Language } from 'app/entities/course.model'; diff --git a/src/test/javascript/spec/component/text-exercise/example-text-submission.component.spec.ts b/src/test/javascript/spec/component/text-exercise/example-text-submission.component.spec.ts index 355bed4320fa..28bd19ff7ed4 100644 --- a/src/test/javascript/spec/component/text-exercise/example-text-submission.component.spec.ts +++ b/src/test/javascript/spec/component/text-exercise/example-text-submission.component.spec.ts @@ -8,9 +8,9 @@ import { AssessmentInstructionsComponent } from 'app/assessment/assessment-instr import { ExampleSubmission } from 'app/entities/example-submission.model'; import { Feedback, FeedbackCorrectionErrorType } from 'app/entities/feedback.model'; import { Result } from 'app/entities/result.model'; -import { TextBlock } from 'app/entities/text-block.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextBlock } from 'app/entities/text/text-block.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { TutorParticipationService } from 'app/exercises/shared/dashboards/tutor/tutor-participation.service'; import { ExampleSubmissionService } from 'app/exercises/shared/example-submission/example-submission.service'; import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; @@ -27,7 +27,7 @@ import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { of, throwError } from 'rxjs'; import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.service'; import { ArtemisTestModule } from '../../test.module'; -import { TextBlockRef } from 'app/entities/text-block-ref.model'; +import { TextBlockRef } from 'app/entities/text/text-block-ref.model'; import { UnreferencedFeedbackComponent } from 'app/exercises/shared/unreferenced-feedback/unreferenced-feedback.component'; import { AlertService } from 'app/core/util/alert.service'; import { DebugElement } from '@angular/core'; diff --git a/src/test/javascript/spec/component/text-exercise/text-exercise-detail.component.spec.ts b/src/test/javascript/spec/component/text-exercise/text-exercise-detail.component.spec.ts index 8289a221fc91..b95a4cd7242a 100644 --- a/src/test/javascript/spec/component/text-exercise/text-exercise-detail.component.spec.ts +++ b/src/test/javascript/spec/component/text-exercise/text-exercise-detail.component.spec.ts @@ -6,7 +6,7 @@ import { ArtemisTestModule } from '../../test.module'; import { TextExerciseDetailComponent } from 'app/exercises/text/manage/text-exercise/text-exercise-detail.component'; import { Course } from 'app/entities/course.model'; import { TextExerciseService } from 'app/exercises/text/manage/text-exercise/text-exercise.service'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { MockActivatedRoute } from '../../helpers/mocks/activated-route/mock-activated-route'; import { TranslateService } from '@ngx-translate/core'; diff --git a/src/test/javascript/spec/component/text-exercise/text-exercise-row-buttons.component.spec.ts b/src/test/javascript/spec/component/text-exercise/text-exercise-row-buttons.component.spec.ts index 53a691f7182d..acbd27f05fb4 100644 --- a/src/test/javascript/spec/component/text-exercise/text-exercise-row-buttons.component.spec.ts +++ b/src/test/javascript/spec/component/text-exercise/text-exercise-row-buttons.component.spec.ts @@ -2,7 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { of } from 'rxjs'; import { HttpResponse } from '@angular/common/http'; import { ArtemisTestModule } from '../../test.module'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { TextExerciseRowButtonsComponent } from 'app/exercises/text/manage/text-exercise/text-exercise-row-buttons.component'; import { TextExerciseService } from 'app/exercises/text/manage/text-exercise/text-exercise.service'; import { EventManager } from 'app/core/util/event-manager.service'; diff --git a/src/test/javascript/spec/component/text-exercise/text-exercise-update.component.spec.ts b/src/test/javascript/spec/component/text-exercise/text-exercise-update.component.spec.ts index 88eff4e9d26f..78fea1728c50 100644 --- a/src/test/javascript/spec/component/text-exercise/text-exercise-update.component.spec.ts +++ b/src/test/javascript/spec/component/text-exercise/text-exercise-update.component.spec.ts @@ -5,7 +5,7 @@ import { ActivatedRoute, UrlSegment } from '@angular/router'; import { ArtemisTestModule } from '../../test.module'; import { TextExerciseUpdateComponent } from 'app/exercises/text/manage/text-exercise/text-exercise-update.component'; import { TextExerciseService } from 'app/exercises/text/manage/text-exercise/text-exercise.service'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.service'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; @@ -13,7 +13,7 @@ import { MockActivatedRoute } from '../../helpers/mocks/activated-route/mock-act import { Course } from 'app/entities/course.model'; import dayjs from 'dayjs/esm'; import { Subject, of, throwError } from 'rxjs'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { TranslateService } from '@ngx-translate/core'; import { MockProvider } from 'ng-mocks'; import { MockNgbModalService } from '../../helpers/mocks/service/mock-ngb-modal.service'; diff --git a/src/test/javascript/spec/component/text-exercise/text-exercise.component.spec.ts b/src/test/javascript/spec/component/text-exercise/text-exercise.component.spec.ts index 2f47ef5e53c6..771035e33ff7 100644 --- a/src/test/javascript/spec/component/text-exercise/text-exercise.component.spec.ts +++ b/src/test/javascript/spec/component/text-exercise/text-exercise.component.spec.ts @@ -8,7 +8,7 @@ import { ActivatedRoute, convertToParamMap } from '@angular/router'; import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; import { ArtemisTestModule } from '../../test.module'; import { TextExerciseComponent } from 'app/exercises/text/manage/text-exercise/text-exercise.component'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.service'; import { MockTranslateService } from '../../helpers/mocks/service/mock-translate.service'; import { Course } from 'app/entities/course.model'; diff --git a/src/test/javascript/spec/component/text-result/text-result.component.spec.ts b/src/test/javascript/spec/component/text-result/text-result.component.spec.ts index 579efafdff29..8fd19cfd4d3b 100644 --- a/src/test/javascript/spec/component/text-result/text-result.component.spec.ts +++ b/src/test/javascript/spec/component/text-result/text-result.component.spec.ts @@ -9,9 +9,9 @@ import { TextResultComponent } from 'app/exercises/text/participate/text-result/ import { MockTranslateService } from '../../helpers/mocks/service/mock-translate.service'; import { TranslateService } from '@ngx-translate/core'; import { Result } from 'app/entities/result.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { Feedback } from 'app/entities/feedback.model'; -import { TextBlock } from 'app/entities/text-block.model'; +import { TextBlock } from 'app/entities/text/text-block.model'; import { TextResultBlock } from 'app/exercises/text/participate/text-result/text-result-block'; import { GradingInstruction } from 'app/exercises/shared/structured-grading-criterion/grading-instruction.model'; import { faCheck, faCircle, faTimes } from '@fortawesome/free-solid-svg-icons'; diff --git a/src/test/javascript/spec/component/text-submission-assessment/manual-textblock-selection.component.spec.ts b/src/test/javascript/spec/component/text-submission-assessment/manual-textblock-selection.component.spec.ts index bf1801eb0362..5887bcf83e4e 100644 --- a/src/test/javascript/spec/component/text-submission-assessment/manual-textblock-selection.component.spec.ts +++ b/src/test/javascript/spec/component/text-submission-assessment/manual-textblock-selection.component.spec.ts @@ -4,11 +4,11 @@ import { ManualTextblockSelectionComponent } from 'app/exercises/text/assess/man import { TextblockAssessmentCardComponent } from 'app/exercises/text/assess/textblock-assessment-card/textblock-assessment-card.component'; import { MockComponent, MockProvider } from 'ng-mocks'; import { By } from '@angular/platform-browser'; -import { TextBlockRef } from 'app/entities/text-block-ref.model'; +import { TextBlockRef } from 'app/entities/text/text-block-ref.model'; import { ManualTextSelectionComponent, wordSelection } from 'app/exercises/text/shared/manual-text-selection/manual-text-selection.component'; import { SubmissionExerciseType, SubmissionType } from 'app/entities/submission.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; -import { TextBlock } from 'app/entities/text-block.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; +import { TextBlock } from 'app/entities/text/text-block.model'; import { TextSelectDirective } from 'app/exercises/text/shared/text-select.directive'; describe('ManualTextblockSelectionComponent', () => { diff --git a/src/test/javascript/spec/component/text-submission-assessment/text-assessment-area.component.spec.ts b/src/test/javascript/spec/component/text-submission-assessment/text-assessment-area.component.spec.ts index 1ddc5bf27049..27816633072e 100644 --- a/src/test/javascript/spec/component/text-submission-assessment/text-assessment-area.component.spec.ts +++ b/src/test/javascript/spec/component/text-submission-assessment/text-assessment-area.component.spec.ts @@ -2,7 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { TextAssessmentAreaComponent } from 'app/exercises/text/assess/text-assessment-area/text-assessment-area.component'; import { ArtemisTestModule } from '../../test.module'; import { TextblockAssessmentCardComponent } from 'app/exercises/text/assess/textblock-assessment-card/textblock-assessment-card.component'; -import { TextBlockRef } from 'app/entities/text-block-ref.model'; +import { TextBlockRef } from 'app/entities/text/text-block-ref.model'; import { By } from '@angular/platform-browser'; import { MockComponent, MockDirective } from 'ng-mocks'; import { TranslatePipeMock } from '../../helpers/mocks/service/mock-translate.service'; diff --git a/src/test/javascript/spec/component/text-submission-assessment/text-submission-assessment.component.spec.ts b/src/test/javascript/spec/component/text-submission-assessment/text-submission-assessment.component.spec.ts index e1027d236097..1a550e93428c 100644 --- a/src/test/javascript/spec/component/text-submission-assessment/text-submission-assessment.component.spec.ts +++ b/src/test/javascript/spec/component/text-submission-assessment/text-submission-assessment.component.spec.ts @@ -10,10 +10,10 @@ import { TextblockAssessmentCardComponent } from 'app/exercises/text/assess/text import { TextblockFeedbackEditorComponent } from 'app/exercises/text/assess/textblock-feedback-editor/textblock-feedback-editor.component'; import { ExerciseType } from 'app/entities/exercise.model'; import { AssessmentType } from 'app/entities/assessment-type.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { ParticipationType } from 'app/entities/participation/participation.model'; import { SubmissionExerciseType, SubmissionType, getLatestSubmissionResult } from 'app/entities/submission.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { Result } from 'app/entities/result.model'; import dayjs from 'dayjs/esm'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; @@ -22,7 +22,7 @@ import { ConfirmIconComponent } from 'app/shared/confirm-icon/confirm-icon.compo import { Course } from 'app/entities/course.model'; import { ManualTextblockSelectionComponent } from 'app/exercises/text/assess/manual-textblock-selection/manual-textblock-selection.component'; import { TextAssessmentService } from 'app/exercises/text/assess/text-assessment.service'; -import { TextBlock, TextBlockType } from 'app/entities/text-block.model'; +import { TextBlock, TextBlockType } from 'app/entities/text/text-block.model'; import { Feedback, FeedbackType } from 'app/entities/feedback.model'; import { ComplaintResponse } from 'app/entities/complaint-response.model'; import { AlertService } from 'app/core/util/alert.service'; @@ -45,7 +45,7 @@ import { AssessmentAfterComplaint } from 'app/complaints/complaints-for-tutor/co import { TextAssessmentBaseComponent } from 'app/exercises/text/assess/text-assessment-base.component'; import { AthenaService } from 'app/assessment/athena.service'; import { MockAthenaService } from '../../helpers/mocks/service/mock-athena-service'; -import { TextBlockRef } from 'app/entities/text-block-ref.model'; +import { TextBlockRef } from 'app/entities/text/text-block-ref.model'; import { TranslateDirective } from 'app/shared/language/translate.directive'; describe('TextSubmissionAssessmentComponent', () => { diff --git a/src/test/javascript/spec/component/text-submission-assessment/textblock-assessment-card.component.spec.ts b/src/test/javascript/spec/component/text-submission-assessment/textblock-assessment-card.component.spec.ts index a11f7b7f6692..4cce34baf424 100644 --- a/src/test/javascript/spec/component/text-submission-assessment/textblock-assessment-card.component.spec.ts +++ b/src/test/javascript/spec/component/text-submission-assessment/textblock-assessment-card.component.spec.ts @@ -2,7 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ArtemisTestModule } from '../../test.module'; import { TextblockAssessmentCardComponent } from 'app/exercises/text/assess/textblock-assessment-card/textblock-assessment-card.component'; import { TextblockFeedbackEditorComponent } from 'app/exercises/text/assess/textblock-feedback-editor/textblock-feedback-editor.component'; -import { TextBlockRef } from 'app/entities/text-block-ref.model'; +import { TextBlockRef } from 'app/entities/text/text-block-ref.model'; import { By } from '@angular/platform-browser'; import { MockComponent, MockDirective, MockProvider } from 'ng-mocks'; import { FaLayersComponent } from '@fortawesome/angular-fontawesome'; @@ -10,8 +10,8 @@ import { GradingInstruction } from 'app/exercises/shared/structured-grading-crit import { AssessmentCorrectionRoundBadgeComponent } from 'app/assessment/unreferenced-feedback-detail/assessment-correction-round-badge/assessment-correction-round-badge.component'; import { TranslatePipeMock } from '../../helpers/mocks/service/mock-translate.service'; import { FeedbackType } from 'app/entities/feedback.model'; -import { TextBlockType } from 'app/entities/text-block.model'; -import { TextAssessmentEventType } from 'app/entities/text-assesment-event.model'; +import { TextBlockType } from 'app/entities/text/text-block.model'; +import { TextAssessmentEventType } from 'app/entities/text/text-assesment-event.model'; import { StructuredGradingCriterionService } from 'app/exercises/shared/structured-grading-criterion/structured-grading-criterion.service'; import { TextAssessmentAnalytics } from 'app/exercises/text/assess/analytics/text-assesment-analytics.service'; import { TextAssessmentService } from 'app/exercises/text/assess/text-assessment.service'; diff --git a/src/test/javascript/spec/component/text-submission-assessment/textblock-feedback-editor.component.spec.ts b/src/test/javascript/spec/component/text-submission-assessment/textblock-feedback-editor.component.spec.ts index 6c08b06ec59a..2405cc4cfd97 100644 --- a/src/test/javascript/spec/component/text-submission-assessment/textblock-feedback-editor.component.spec.ts +++ b/src/test/javascript/spec/component/text-submission-assessment/textblock-feedback-editor.component.spec.ts @@ -2,7 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ArtemisTestModule } from '../../test.module'; import { TextblockFeedbackEditorComponent } from 'app/exercises/text/assess/textblock-feedback-editor/textblock-feedback-editor.component'; import { Feedback, FeedbackCorrectionErrorType, FeedbackType } from 'app/entities/feedback.model'; -import { TextBlock, TextBlockType } from 'app/entities/text-block.model'; +import { TextBlock, TextBlockType } from 'app/entities/text/text-block.model'; import { ConfirmIconComponent } from 'app/shared/confirm-icon/confirm-icon.component'; import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { NgbModal, NgbTooltip } from '@ng-bootstrap/ng-bootstrap'; @@ -16,7 +16,7 @@ import { MockNgbModalService } from '../../helpers/mocks/service/mock-ngb-modal. import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.service'; import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { MockTranslateService, TranslateTestingModule } from '../../helpers/mocks/service/mock-translate.service'; -import { TextAssessmentEventType } from 'app/entities/text-assesment-event.model'; +import { TextAssessmentEventType } from 'app/entities/text/text-assesment-event.model'; import { NgModel } from '@angular/forms'; import { TranslateDirective } from 'app/shared/language/translate.directive'; import { TextblockFeedbackDropdownComponent } from 'app/exercises/text/assess/textblock-feedback-editor/dropdown/textblock-feedback-dropdown.component'; diff --git a/src/test/javascript/spec/component/text/manual-text-selection.component.spec.ts b/src/test/javascript/spec/component/text/manual-text-selection.component.spec.ts index db879a19b482..478418b4d8a2 100644 --- a/src/test/javascript/spec/component/text/manual-text-selection.component.spec.ts +++ b/src/test/javascript/spec/component/text/manual-text-selection.component.spec.ts @@ -1,15 +1,15 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ArtemisTestModule } from '../../test.module'; import { ManualTextSelectionComponent } from 'app/exercises/text/shared/manual-text-selection/manual-text-selection.component'; -import { TextAssessmentEventType } from 'app/entities/text-assesment-event.model'; +import { TextAssessmentEventType } from 'app/entities/text/text-assesment-event.model'; import { FeedbackType } from 'app/entities/feedback.model'; -import { TextBlock, TextBlockType } from 'app/entities/text-block.model'; +import { TextBlock, TextBlockType } from 'app/entities/text/text-block.model'; import { MockProvider } from 'ng-mocks'; import { TextAssessmentAnalytics } from 'app/exercises/text/assess/analytics/text-assesment-analytics.service'; import { ActivatedRoute } from '@angular/router'; import { SubmissionExerciseType, SubmissionType } from 'app/entities/submission.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; -import { TextBlockRef } from 'app/entities/text-block-ref.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; +import { TextBlockRef } from 'app/entities/text/text-block-ref.model'; import { TextBlockRefGroup } from 'app/exercises/text/assess/manual-textblock-selection/manual-textblock-selection.component'; describe('ManualTextSelectionComponent', () => { diff --git a/src/test/javascript/spec/component/tutor-leaderboard/tutor-leaderboard.component.spec.ts b/src/test/javascript/spec/component/tutor-leaderboard/tutor-leaderboard.component.spec.ts index 95b4a23b2f3a..d8ca84cd934d 100644 --- a/src/test/javascript/spec/component/tutor-leaderboard/tutor-leaderboard.component.spec.ts +++ b/src/test/javascript/spec/component/tutor-leaderboard/tutor-leaderboard.component.spec.ts @@ -11,7 +11,7 @@ import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { MockRouter } from '../../helpers/mocks/mock-router'; import { Course } from 'app/entities/course.model'; import { Exercise } from 'app/entities/exercise.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; describe('TutorLeaderboardComponent', () => { diff --git a/src/test/javascript/spec/component/utils/exercise.utils.spec.ts b/src/test/javascript/spec/component/utils/exercise.utils.spec.ts index e993f54bce3f..bc08c615408c 100644 --- a/src/test/javascript/spec/component/utils/exercise.utils.spec.ts +++ b/src/test/javascript/spec/component/utils/exercise.utils.spec.ts @@ -1,5 +1,5 @@ import dayjs from 'dayjs/esm'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; import { areManualResultsAllowed, diff --git a/src/test/javascript/spec/component/utils/programming-exercise.utils.spec.ts b/src/test/javascript/spec/component/utils/programming-exercise.utils.spec.ts index b0ec0a41a247..6556bc8c2ac9 100644 --- a/src/test/javascript/spec/component/utils/programming-exercise.utils.spec.ts +++ b/src/test/javascript/spec/component/utils/programming-exercise.utils.spec.ts @@ -1,6 +1,6 @@ import { SubmissionExerciseType, SubmissionType } from 'app/entities/submission.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { Participation, ParticipationType } from 'app/entities/participation/participation.model'; import { createBuildPlanUrl, diff --git a/src/test/javascript/spec/helpers/mocks/service/mock-build-plan.service.ts b/src/test/javascript/spec/helpers/mocks/service/mock-build-plan.service.ts index 6f921f925cc8..eb4e1c7f8a91 100644 --- a/src/test/javascript/spec/helpers/mocks/service/mock-build-plan.service.ts +++ b/src/test/javascript/spec/helpers/mocks/service/mock-build-plan.service.ts @@ -1,5 +1,5 @@ import { of } from 'rxjs'; -import { BuildPlan } from 'app/entities/build-plan.model'; +import { BuildPlan } from 'app/entities/programming/build-plan.model'; export class MockBuildPlanService { getBuildPlan = (exerciseId: number) => of({}); diff --git a/src/test/javascript/spec/helpers/mocks/service/mock-code-editor-build-log.service.ts b/src/test/javascript/spec/helpers/mocks/service/mock-code-editor-build-log.service.ts index 6c4fdb3e1a95..75e162c1440c 100644 --- a/src/test/javascript/spec/helpers/mocks/service/mock-code-editor-build-log.service.ts +++ b/src/test/javascript/spec/helpers/mocks/service/mock-code-editor-build-log.service.ts @@ -1,5 +1,5 @@ import { of } from 'rxjs'; -import { BuildLogEntry } from 'app/entities/build-log.model'; +import { BuildLogEntry } from 'app/entities/programming/build-log.model'; import { IBuildLogService } from 'app/exercises/programming/shared/service/build-log.service'; export class MockCodeEditorBuildLogService implements IBuildLogService { diff --git a/src/test/javascript/spec/helpers/mocks/service/mock-course-exercise.service.ts b/src/test/javascript/spec/helpers/mocks/service/mock-course-exercise.service.ts index a84c3d6f75b5..f35a7271cc77 100644 --- a/src/test/javascript/spec/helpers/mocks/service/mock-course-exercise.service.ts +++ b/src/test/javascript/spec/helpers/mocks/service/mock-course-exercise.service.ts @@ -1,6 +1,6 @@ import { of } from 'rxjs'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; export class MockCourseExerciseService { startExercise = () => of({} as StudentParticipation); diff --git a/src/test/javascript/spec/helpers/mocks/service/mock-course-management.service.ts b/src/test/javascript/spec/helpers/mocks/service/mock-course-management.service.ts index ebcdaacd8f50..888c7b981944 100644 --- a/src/test/javascript/spec/helpers/mocks/service/mock-course-management.service.ts +++ b/src/test/javascript/spec/helpers/mocks/service/mock-course-management.service.ts @@ -2,7 +2,7 @@ import { HttpResponse } from '@angular/common/http'; import { User } from 'app/core/user/user.model'; import { BehaviorSubject, Observable, of } from 'rxjs'; import { Course, CourseGroup } from 'app/entities/course.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { EntityArrayResponseType } from 'app/course/manage/course-management.service'; export class MockCourseManagementService { diff --git a/src/test/javascript/spec/helpers/mocks/service/mock-exam-checklist.service.ts b/src/test/javascript/spec/helpers/mocks/service/mock-exam-checklist.service.ts index ce82ec8995bf..aaca1b66625f 100644 --- a/src/test/javascript/spec/helpers/mocks/service/mock-exam-checklist.service.ts +++ b/src/test/javascript/spec/helpers/mocks/service/mock-exam-checklist.service.ts @@ -1,5 +1,5 @@ -import { Exam } from 'app/entities/exam.model'; -import { ExamChecklist } from 'app/entities/exam-checklist.model'; +import { Exam } from 'app/entities/exam/exam.model'; +import { ExamChecklist } from 'app/entities/exam/exam-checklist.model'; import { of } from 'rxjs'; export class MockExamChecklistService { diff --git a/src/test/javascript/spec/helpers/mocks/service/mock-exam-management.service.ts b/src/test/javascript/spec/helpers/mocks/service/mock-exam-management.service.ts index b63e816d8969..face7704e776 100644 --- a/src/test/javascript/spec/helpers/mocks/service/mock-exam-management.service.ts +++ b/src/test/javascript/spec/helpers/mocks/service/mock-exam-management.service.ts @@ -1,6 +1,6 @@ import { Observable, of } from 'rxjs'; import { HttpResponse } from '@angular/common/http'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; export class MockExamManagementService { findAllCurrentAndUpcomingExams() { diff --git a/src/test/javascript/spec/helpers/mocks/service/mock-ide-build-and-test.service.ts b/src/test/javascript/spec/helpers/mocks/service/mock-ide-build-and-test.service.ts index a50b88c16229..e61332e5c35c 100644 --- a/src/test/javascript/spec/helpers/mocks/service/mock-ide-build-and-test.service.ts +++ b/src/test/javascript/spec/helpers/mocks/service/mock-ide-build-and-test.service.ts @@ -1,5 +1,5 @@ import { of } from 'rxjs'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; export class MockIdeBuildAndTestService { listenOnBuildOutputAndForwardChanges = (exercise: ProgrammingExercise) => of(); diff --git a/src/test/javascript/spec/helpers/mocks/service/mock-programming-exercise-grading.service.ts b/src/test/javascript/spec/helpers/mocks/service/mock-programming-exercise-grading.service.ts index cd93e0dd444c..b48ecc16b192 100644 --- a/src/test/javascript/spec/helpers/mocks/service/mock-programming-exercise-grading.service.ts +++ b/src/test/javascript/spec/helpers/mocks/service/mock-programming-exercise-grading.service.ts @@ -1,12 +1,12 @@ import { BehaviorSubject, Observable, of } from 'rxjs'; -import { ProgrammingExerciseTestCase } from 'app/entities/programming-exercise-test-case.model'; +import { ProgrammingExerciseTestCase } from 'app/entities/programming/programming-exercise-test-case.model'; import { IProgrammingExerciseGradingService, ProgrammingExerciseTestCaseUpdate, StaticCodeAnalysisCategoryUpdate, } from 'app/exercises/programming/manage/services/programming-exercise-grading.service'; -import { StaticCodeAnalysisCategory } from 'app/entities/static-code-analysis-category.model'; -import { ProgrammingExerciseGradingStatistics } from 'app/entities/programming-exercise-test-case-statistics.model'; +import { StaticCodeAnalysisCategory } from 'app/entities/programming/static-code-analysis-category.model'; +import { ProgrammingExerciseGradingStatistics } from 'app/entities/programming/programming-exercise-test-case-statistics.model'; export class MockProgrammingExerciseGradingService implements IProgrammingExerciseGradingService { private testCaseSubject = new BehaviorSubject(undefined); diff --git a/src/test/javascript/spec/helpers/mocks/service/mock-programming-exercise-participation.service.ts b/src/test/javascript/spec/helpers/mocks/service/mock-programming-exercise-participation.service.ts index 6b0fb6ea0d78..8525ad43dc80 100644 --- a/src/test/javascript/spec/helpers/mocks/service/mock-programming-exercise-participation.service.ts +++ b/src/test/javascript/spec/helpers/mocks/service/mock-programming-exercise-participation.service.ts @@ -2,7 +2,7 @@ import { of } from 'rxjs'; import { IProgrammingExerciseParticipationService } from 'app/exercises/programming/manage/services/programming-exercise-participation.service'; import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model'; import { Result } from 'app/entities/result.model'; -import { CommitInfo } from 'app/entities/programming-submission.model'; +import { CommitInfo } from 'app/entities/programming/programming-submission.model'; export class MockProgrammingExerciseParticipationService implements IProgrammingExerciseParticipationService { getLatestResultWithFeedback = (participationId: number, withSubmission: boolean) => of({} as Result); diff --git a/src/test/javascript/spec/helpers/mocks/service/mock-programming-exercise.service.ts b/src/test/javascript/spec/helpers/mocks/service/mock-programming-exercise.service.ts index d897194809fd..b164cc8e700c 100644 --- a/src/test/javascript/spec/helpers/mocks/service/mock-programming-exercise.service.ts +++ b/src/test/javascript/spec/helpers/mocks/service/mock-programming-exercise.service.ts @@ -1,7 +1,7 @@ import { of } from 'rxjs'; import { ProgrammingExerciseInstructorRepositoryType } from 'app/exercises/programming/manage/services/programming-exercise.service'; import { Participation } from 'app/entities/participation/participation.model'; -import { ProgrammingLanguage } from 'app/entities/programming-exercise.model'; +import { ProgrammingLanguage } from 'app/entities/programming/programming-exercise.model'; export class MockProgrammingExerciseService { updateProblemStatement = (exerciseId: number, problemStatement: string) => of(); diff --git a/src/test/javascript/spec/helpers/mocks/service/mock-team.service.ts b/src/test/javascript/spec/helpers/mocks/service/mock-team.service.ts index fa1e00fdfe28..5f830bdf013d 100644 --- a/src/test/javascript/spec/helpers/mocks/service/mock-team.service.ts +++ b/src/test/javascript/spec/helpers/mocks/service/mock-team.service.ts @@ -8,7 +8,7 @@ import { StudentWithTeam } from 'app/entities/team.model'; import { Course } from 'app/entities/course.model'; import { TeamSearchUser } from 'app/entities/team-search-user.model'; import { User } from 'app/core/user/user.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { TeamAssignmentConfig } from 'app/entities/team-assignment-config.model'; import { TeamService } from 'app/exercises/shared/team/team.service'; import dayjs from 'dayjs/esm'; diff --git a/src/test/javascript/spec/helpers/mocks/service/mock-text-submission.service.ts b/src/test/javascript/spec/helpers/mocks/service/mock-text-submission.service.ts index 99dcd86c9c2d..dcea849439c1 100644 --- a/src/test/javascript/spec/helpers/mocks/service/mock-text-submission.service.ts +++ b/src/test/javascript/spec/helpers/mocks/service/mock-text-submission.service.ts @@ -1,5 +1,5 @@ import { Observable, of } from 'rxjs'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { HttpResponse } from '@angular/common/http'; type EntityResponseType = HttpResponse; diff --git a/src/test/javascript/spec/helpers/sample/iris-sample-data.ts b/src/test/javascript/spec/helpers/sample/iris-sample-data.ts index f82327cfaae8..4e348a67d615 100644 --- a/src/test/javascript/spec/helpers/sample/iris-sample-data.ts +++ b/src/test/javascript/spec/helpers/sample/iris-sample-data.ts @@ -1,6 +1,6 @@ import dayjs from 'dayjs/esm'; import { ExerciseType } from 'app/entities/exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { IrisAssistantMessage, IrisSender, IrisUserMessage } from 'app/entities/iris/iris-message.model'; import { IrisMessageContentType, IrisTextMessageContent } from 'app/entities/iris/iris-content-type.model'; import { IrisSession } from 'app/entities/iris/iris-session.model'; diff --git a/src/test/javascript/spec/helpers/sample/metis-sample-data.ts b/src/test/javascript/spec/helpers/sample/metis-sample-data.ts index a6d3e1db5eb0..ce2136c46028 100644 --- a/src/test/javascript/spec/helpers/sample/metis-sample-data.ts +++ b/src/test/javascript/spec/helpers/sample/metis-sample-data.ts @@ -13,7 +13,7 @@ import { Conversation, ConversationType } from 'app/entities/metis/conversation/ import { AttachmentUnit } from 'app/entities/lecture-unit/attachmentUnit.model'; import { Slide } from 'app/entities/lecture-unit/slide.model'; import { Channel, ChannelDTO, ChannelSubType } from 'app/entities/metis/conversation/channel.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { PlagiarismCase } from 'app/exercises/shared/plagiarism/types/PlagiarismCase'; import { LectureUnitType } from 'app/entities/lecture-unit/lectureUnit.model'; diff --git a/src/test/javascript/spec/integration/code-editor/code-editor-container.integration.spec.ts b/src/test/javascript/spec/integration/code-editor/code-editor-container.integration.spec.ts index 637ea5b8baad..d8f9e0bb8126 100644 --- a/src/test/javascript/spec/integration/code-editor/code-editor-container.integration.spec.ts +++ b/src/test/javascript/spec/integration/code-editor/code-editor-container.integration.spec.ts @@ -29,7 +29,7 @@ import { GuidedTourMapping } from 'app/guided-tour/guided-tour-setting.model'; import { JhiWebsocketService } from 'app/core/websocket/websocket.service'; import { MockWebsocketService } from '../../helpers/mocks/service/mock-websocket.service'; import { Participation } from 'app/entities/participation/participation.model'; -import { BuildLogEntryArray } from 'app/entities/build-log.model'; +import { BuildLogEntryArray } from 'app/entities/programming/build-log.model'; import { CodeEditorConflictStateService } from 'app/exercises/programming/shared/code-editor/service/code-editor-conflict-state.service'; import { ResultService } from 'app/exercises/shared/result/result.service'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; @@ -41,7 +41,7 @@ import { } from 'app/exercises/programming/shared/code-editor/service/code-editor-repository.service'; import { Feedback } from 'app/entities/feedback.model'; import { DomainService } from 'app/exercises/programming/shared/code-editor/service/code-editor-domain.service'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { MockActivatedRouteWithSubjects } from '../../helpers/mocks/activated-route/mock-activated-route-with-subjects'; import { MockParticipationWebsocketService } from '../../helpers/mocks/service/mock-participation-websocket.service'; import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.service'; @@ -51,7 +51,7 @@ import { MockCodeEditorRepositoryFileService } from '../../helpers/mocks/service import { MockCodeEditorBuildLogService } from '../../helpers/mocks/service/mock-code-editor-build-log.service'; import { CodeEditorContainerComponent } from 'app/exercises/programming/shared/code-editor/container/code-editor-container.component'; import { omit } from 'lodash-es'; -import { ProgrammingLanguage, ProjectType } from 'app/entities/programming-exercise.model'; +import { ProgrammingLanguage, ProjectType } from 'app/entities/programming/programming-exercise.model'; import { CodeEditorGridComponent } from 'app/exercises/programming/shared/code-editor/layout/code-editor-grid.component'; import { MockComponent, MockDirective, MockModule, MockPipe, MockProvider } from 'ng-mocks'; import { CodeEditorActionsComponent } from 'app/exercises/programming/shared/code-editor/actions/code-editor-actions.component'; diff --git a/src/test/javascript/spec/integration/code-editor/code-editor-instructor.integration.spec.ts b/src/test/javascript/spec/integration/code-editor/code-editor-instructor.integration.spec.ts index a793a859f204..294c3d3a9a4e 100644 --- a/src/test/javascript/spec/integration/code-editor/code-editor-instructor.integration.spec.ts +++ b/src/test/javascript/spec/integration/code-editor/code-editor-instructor.integration.spec.ts @@ -27,7 +27,7 @@ import { DomainService } from 'app/exercises/programming/shared/code-editor/serv import { TemplateProgrammingExerciseParticipation } from 'app/entities/participation/template-programming-exercise-participation.model'; import { Result } from 'app/entities/result.model'; import { ParticipationService } from 'app/exercises/shared/participation/participation.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ProgrammingExerciseStudentParticipation } from 'app/entities/participation/programming-exercise-student-participation.model'; import { SolutionProgrammingExerciseParticipation } from 'app/entities/participation/solution-programming-exercise-participation.model'; import { MockActivatedRouteWithSubjects } from '../../helpers/mocks/activated-route/mock-activated-route-with-subjects'; diff --git a/src/test/javascript/spec/integration/code-editor/code-editor-student.integration.spec.ts b/src/test/javascript/spec/integration/code-editor/code-editor-student.integration.spec.ts index 11036e23a71d..dabf4a7e1d34 100644 --- a/src/test/javascript/spec/integration/code-editor/code-editor-student.integration.spec.ts +++ b/src/test/javascript/spec/integration/code-editor/code-editor-student.integration.spec.ts @@ -28,7 +28,7 @@ import { } from 'app/exercises/programming/shared/code-editor/service/code-editor-repository.service'; import { Feedback } from 'app/entities/feedback.model'; import { CodeEditorStudentContainerComponent } from 'app/exercises/programming/participate/code-editor-student-container.component'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { MockActivatedRouteWithSubjects } from '../../helpers/mocks/activated-route/mock-activated-route-with-subjects'; import { MockParticipationWebsocketService } from '../../helpers/mocks/service/mock-participation-websocket.service'; import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.service'; diff --git a/src/test/javascript/spec/service/athena.service.spec.ts b/src/test/javascript/spec/service/athena.service.spec.ts index 98de7b17fe9c..099b679ee249 100644 --- a/src/test/javascript/spec/service/athena.service.spec.ts +++ b/src/test/javascript/spec/service/athena.service.spec.ts @@ -8,8 +8,8 @@ import { of } from 'rxjs'; import { ProfileInfo } from 'app/shared/layouts/profiles/profile-info.model'; import { Exercise } from 'app/entities/exercise.model'; import { ModelingFeedbackSuggestion, ProgrammingFeedbackSuggestion, TextFeedbackSuggestion } from 'app/entities/feedback-suggestion.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; -import { TextBlockRef } from 'app/entities/text-block-ref.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; +import { TextBlockRef } from 'app/entities/text/text-block-ref.model'; import { Feedback, FeedbackType } from 'app/entities/feedback.model'; import { ModelingSubmission } from 'app/entities/modeling-submission.model'; diff --git a/src/test/javascript/spec/service/build-log.service.spec.ts b/src/test/javascript/spec/service/build-log.service.spec.ts index 9a8639c3159d..0582e9ff369b 100644 --- a/src/test/javascript/spec/service/build-log.service.spec.ts +++ b/src/test/javascript/spec/service/build-log.service.spec.ts @@ -1,6 +1,6 @@ import { TestBed, fakeAsync, tick } from '@angular/core/testing'; import { BuildLogService } from 'app/exercises/programming/shared/service/build-log.service'; -import { BuildLogEntry, BuildLogType } from 'app/entities/build-log.model'; +import { BuildLogEntry, BuildLogType } from 'app/entities/programming/build-log.model'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; describe('Build Log Service', () => { diff --git a/src/test/javascript/spec/service/chart-category-filter.spec.ts b/src/test/javascript/spec/service/chart-category-filter.spec.ts index 533442313bc8..aa4a25ed8bbb 100644 --- a/src/test/javascript/spec/service/chart-category-filter.spec.ts +++ b/src/test/javascript/spec/service/chart-category-filter.spec.ts @@ -5,7 +5,7 @@ import { DueDateStat } from 'app/course/dashboards/due-date-stat.model'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; import { FileUploadExercise } from 'app/entities/file-upload-exercise.model'; import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import dayjs from 'dayjs/esm'; import { ExerciseCategory } from 'app/entities/exercise-category.model'; import { InitializationState } from 'app/entities/participation/participation.model'; diff --git a/src/test/javascript/spec/service/course-exercise.service.spec.ts b/src/test/javascript/spec/service/course-exercise.service.spec.ts index e31154c07dd5..d123760c6d25 100644 --- a/src/test/javascript/spec/service/course-exercise.service.spec.ts +++ b/src/test/javascript/spec/service/course-exercise.service.spec.ts @@ -7,8 +7,8 @@ import { Exercise } from 'app/entities/exercise.model'; import { FileUploadExercise } from 'app/entities/file-upload-exercise.model'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import dayjs from 'dayjs/esm'; import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { take } from 'rxjs/operators'; diff --git a/src/test/javascript/spec/service/exam-checklist.service.spec.ts b/src/test/javascript/spec/service/exam-checklist.service.spec.ts index 89286e0d0d9c..be298e2651d3 100644 --- a/src/test/javascript/spec/service/exam-checklist.service.spec.ts +++ b/src/test/javascript/spec/service/exam-checklist.service.spec.ts @@ -1,8 +1,8 @@ import { HttpResponse } from '@angular/common/http'; import { TestBed } from '@angular/core/testing'; import { Course } from 'app/entities/course.model'; -import { ExamChecklist } from 'app/entities/exam-checklist.model'; -import { Exam } from 'app/entities/exam.model'; +import { ExamChecklist } from 'app/entities/exam/exam-checklist.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { MockProvider } from 'ng-mocks'; import { of, take } from 'rxjs'; import { ArtemisTestModule } from '../test.module'; diff --git a/src/test/javascript/spec/service/exam-import-paging.service.spec.ts b/src/test/javascript/spec/service/exam-import-paging.service.spec.ts index 34299aa2e1ba..091acf0bc0c0 100644 --- a/src/test/javascript/spec/service/exam-import-paging.service.spec.ts +++ b/src/test/javascript/spec/service/exam-import-paging.service.spec.ts @@ -6,7 +6,7 @@ import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { take } from 'rxjs/operators'; import { MockSyncStorage } from '../helpers/mocks/service/mock-sync-storage.service'; import { MockTranslateService } from '../helpers/mocks/service/mock-translate.service'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExamImportPagingService } from 'app/exam/manage/exams/exam-import/exam-import-paging.service'; describe('Exam Import Paging Service', () => { diff --git a/src/test/javascript/spec/service/exam-participation.service.spec.ts b/src/test/javascript/spec/service/exam-participation.service.spec.ts index 8a06fa6654d6..56d0aa53bef8 100644 --- a/src/test/javascript/spec/service/exam-participation.service.spec.ts +++ b/src/test/javascript/spec/service/exam-participation.service.spec.ts @@ -3,7 +3,7 @@ import { HttpClientTestingModule, HttpTestingController } from '@angular/common/ import { take } from 'rxjs/operators'; import dayjs from 'dayjs/esm'; import { ExamParticipationService } from 'app/exam/participate/exam-participation.service'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { QuizSubmission } from 'app/entities/quiz/quiz-submission.model'; import { StudentExam } from 'app/entities/student-exam.model'; import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; @@ -11,10 +11,10 @@ import { MockSyncStorage } from '../helpers/mocks/service/mock-sync-storage.serv import { MockTranslateService } from '../helpers/mocks/service/mock-translate.service'; import { TranslateService } from '@ngx-translate/core'; import { ArtemisTestModule } from '../test.module'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { Course } from 'app/entities/course.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { Result } from 'app/entities/result.model'; import { getLatestSubmissionResult } from 'app/entities/submission.model'; import { StudentExamWithGradeDTO, StudentResult } from 'app/exam/exam-scores/exam-score-dtos.model'; diff --git a/src/test/javascript/spec/service/example-submission-import-paging.service.spec.ts b/src/test/javascript/spec/service/example-submission-import-paging.service.spec.ts index 27bb4130c2ab..d1eee71bc343 100644 --- a/src/test/javascript/spec/service/example-submission-import-paging.service.spec.ts +++ b/src/test/javascript/spec/service/example-submission-import-paging.service.spec.ts @@ -8,7 +8,7 @@ import { MockSyncStorage } from '../helpers/mocks/service/mock-sync-storage.serv import { MockTranslateService } from '../helpers/mocks/service/mock-translate.service'; import { ExampleSubmissionImportPagingService } from 'app/exercises/shared/example-submission/example-submission-import/example-submission-import-paging.service'; import { Exercise } from 'app/entities/exercise.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; describe('Example Submission Import Paging Service', () => { let service: ExampleSubmissionImportPagingService; diff --git a/src/test/javascript/spec/service/example-submission.service.spec.ts b/src/test/javascript/spec/service/example-submission.service.spec.ts index 506871654bf2..60addda81875 100644 --- a/src/test/javascript/spec/service/example-submission.service.spec.ts +++ b/src/test/javascript/spec/service/example-submission.service.spec.ts @@ -6,7 +6,7 @@ import { ArtemisTestModule } from '../test.module'; import { ExampleSubmissionService } from 'app/exercises/shared/example-submission/example-submission.service'; import { ExampleSubmission } from 'app/entities/example-submission.model'; import { Exercise } from 'app/entities/exercise.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { Result } from 'app/entities/result.model'; import { Feedback } from 'app/entities/feedback.model'; import { Submission, getLatestSubmissionResult } from 'app/entities/submission.model'; diff --git a/src/test/javascript/spec/service/exercise-hint.service.spec.ts b/src/test/javascript/spec/service/exercise-hint.service.spec.ts index cdff311a6fcc..74a6c5e84bb9 100644 --- a/src/test/javascript/spec/service/exercise-hint.service.spec.ts +++ b/src/test/javascript/spec/service/exercise-hint.service.spec.ts @@ -3,7 +3,7 @@ import { HttpClientTestingModule, HttpTestingController } from '@angular/common/ import { HttpResponse } from '@angular/common/http'; import { take } from 'rxjs/operators'; import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ExerciseHint } from 'app/entities/hestia/exercise-hint.model'; import { MockExerciseService } from '../helpers/mocks/service/mock-exercise.service'; import { ExerciseHintService } from 'app/exercises/shared/exercise-hint/shared/exercise-hint.service'; diff --git a/src/test/javascript/spec/service/exercise-update-warning.service.spec.ts b/src/test/javascript/spec/service/exercise-update-warning.service.spec.ts index 55ad42c88d49..75be64c26763 100644 --- a/src/test/javascript/spec/service/exercise-update-warning.service.spec.ts +++ b/src/test/javascript/spec/service/exercise-update-warning.service.spec.ts @@ -5,7 +5,7 @@ import { GradingCriterion } from 'app/exercises/shared/structured-grading-criter import { Exercise } from 'app/entities/exercise.model'; import { ExerciseUpdateWarningComponent } from 'app/exercises/shared/exercise-update-warning/exercise-update-warning.component'; import { Component } from '@angular/core'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import dayjs from 'dayjs/esm'; describe('Exercise Update Warning Service', () => { diff --git a/src/test/javascript/spec/service/exercise.service.spec.ts b/src/test/javascript/spec/service/exercise.service.spec.ts index 8e58498bef7a..415078a437e1 100644 --- a/src/test/javascript/spec/service/exercise.service.spec.ts +++ b/src/test/javascript/spec/service/exercise.service.spec.ts @@ -5,7 +5,7 @@ import { TranslateService } from '@ngx-translate/core'; import { Exercise, ExerciseType, IncludedInOverallScore } from 'app/entities/exercise.model'; import { InitializationState } from 'app/entities/participation/participation.model'; import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import type { EntityResponseType, ExerciseDetailsType } from 'app/exercises/shared/exercise/exercise.service'; import { ExerciseService } from 'app/exercises/shared/exercise/exercise.service'; import dayjs from 'dayjs/esm'; @@ -15,7 +15,7 @@ import { MockSyncStorage } from '../helpers/mocks/service/mock-sync-storage.serv import { MockTranslateService } from '../helpers/mocks/service/mock-translate.service'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; import { FileUploadExercise } from 'app/entities/file-upload-exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ArtemisMarkdownService } from 'app/shared/markdown.service'; import { MockProvider } from 'ng-mocks'; import { SafeHtml } from '@angular/platform-browser'; diff --git a/src/test/javascript/spec/service/external-submission.service.spec.ts b/src/test/javascript/spec/service/external-submission.service.spec.ts index b3d34c736e50..b7b7c6701e8b 100644 --- a/src/test/javascript/spec/service/external-submission.service.spec.ts +++ b/src/test/javascript/spec/service/external-submission.service.spec.ts @@ -7,7 +7,7 @@ import { Result } from 'app/entities/result.model'; import { User } from 'app/core/user/user.model'; import { EntityResponseType, ResultService } from 'app/exercises/shared/result/result.service'; import dayjs from 'dayjs/esm'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; describe('External Submission Service', () => { let httpMock: HttpTestingController; diff --git a/src/test/javascript/spec/service/feedback/programming-feedback-item.service.spec.ts b/src/test/javascript/spec/service/feedback/programming-feedback-item.service.spec.ts index 9a1d199c32be..89c6a7755334 100644 --- a/src/test/javascript/spec/service/feedback/programming-feedback-item.service.spec.ts +++ b/src/test/javascript/spec/service/feedback/programming-feedback-item.service.spec.ts @@ -1,4 +1,4 @@ -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { FeedbackGroup } from 'app/exercises/shared/feedback/group/feedback-group'; import { ProgrammingFeedbackItemService } from 'app/exercises/shared/feedback/item/programming-feedback-item.service'; import { Feedback, FeedbackType, STATIC_CODE_ANALYSIS_FEEDBACK_IDENTIFIER, SUBMISSION_POLICY_FEEDBACK_IDENTIFIER } from 'app/entities/feedback.model'; diff --git a/src/test/javascript/spec/service/orion/orion-build-and-test.service.spec.ts b/src/test/javascript/spec/service/orion/orion-build-and-test.service.spec.ts index eb6b7f555eff..53394a7bbd27 100644 --- a/src/test/javascript/spec/service/orion/orion-build-and-test.service.spec.ts +++ b/src/test/javascript/spec/service/orion/orion-build-and-test.service.spec.ts @@ -5,13 +5,13 @@ import { MockProgrammingSubmissionService } from '../../helpers/mocks/service/mo import { Result } from 'app/entities/result.model'; import { BehaviorSubject, of } from 'rxjs'; import { Feedback, FeedbackType, STATIC_CODE_ANALYSIS_FEEDBACK_IDENTIFIER } from 'app/entities/feedback.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { BuildLogService } from 'app/exercises/programming/shared/service/build-log.service'; import { MockParticipationWebsocketService } from '../../helpers/mocks/service/mock-participation-websocket.service'; import { MockCodeEditorBuildLogService } from '../../helpers/mocks/service/mock-code-editor-build-log.service'; import { OrionBuildAndTestService } from 'app/shared/orion/orion-build-and-test.service'; import { OrionConnectorService } from 'app/shared/orion/orion-connector.service'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { ArtemisTestModule } from '../../test.module'; import { SubmissionService } from 'app/exercises/shared/submission/submission.service'; import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.service'; diff --git a/src/test/javascript/spec/service/orion/orion-connector.service.spec.ts b/src/test/javascript/spec/service/orion/orion-connector.service.spec.ts index 6fb2c239ff92..5a5f05943019 100644 --- a/src/test/javascript/spec/service/orion/orion-connector.service.spec.ts +++ b/src/test/javascript/spec/service/orion/orion-connector.service.spec.ts @@ -1,6 +1,6 @@ import { TestBed } from '@angular/core/testing'; import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { OrionConnectorService } from 'app/shared/orion/orion-connector.service'; import { ArtemisTestModule } from '../../test.module'; import { MockSyncStorage } from '../../helpers/mocks/service/mock-sync-storage.service'; diff --git a/src/test/javascript/spec/service/participation.service.spec.ts b/src/test/javascript/spec/service/participation.service.spec.ts index aef90fe10869..0d405cbfb018 100644 --- a/src/test/javascript/spec/service/participation.service.spec.ts +++ b/src/test/javascript/spec/service/participation.service.spec.ts @@ -14,7 +14,7 @@ import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { MockRouter } from '../helpers/mocks/mock-router'; import { Router } from '@angular/router'; import { Course } from 'app/entities/course.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; describe('Participation Service', () => { let service: ParticipationService; diff --git a/src/test/javascript/spec/service/plagiarism-cases.service.spec.ts b/src/test/javascript/spec/service/plagiarism-cases.service.spec.ts index d72b46099546..134bdc518fee 100644 --- a/src/test/javascript/spec/service/plagiarism-cases.service.spec.ts +++ b/src/test/javascript/spec/service/plagiarism-cases.service.spec.ts @@ -3,7 +3,7 @@ import { TestBed, fakeAsync, tick } from '@angular/core/testing'; import { PlagiarismCasesService } from 'app/course/plagiarism-cases/shared/plagiarism-cases.service'; import { take } from 'rxjs/operators'; import { ExerciseType } from 'app/entities/exercise.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { PlagiarismStatus } from 'app/exercises/shared/plagiarism/types/PlagiarismStatus'; import { PlagiarismComparison } from 'app/exercises/shared/plagiarism/types/PlagiarismComparison'; import { TextSubmissionElement } from 'app/exercises/shared/plagiarism/types/text/TextSubmissionElement'; diff --git a/src/test/javascript/spec/service/profile.service.spec.ts b/src/test/javascript/spec/service/profile.service.spec.ts index 00296fdba322..cc833e61a7f6 100644 --- a/src/test/javascript/spec/service/profile.service.spec.ts +++ b/src/test/javascript/spec/service/profile.service.spec.ts @@ -7,7 +7,7 @@ import { MockRouter } from '../helpers/mocks/mock-router'; import { Router } from '@angular/router'; import { ProfileInfo } from 'app/shared/layouts/profiles/profile-info.model'; import { FeatureToggle } from 'app/shared/feature-toggle/feature-toggle.service'; -import { ProgrammingLanguage, ProjectType } from 'app/entities/programming-exercise.model'; +import { ProgrammingLanguage, ProjectType } from 'app/entities/programming/programming-exercise.model'; import { BrowserFingerprintService } from 'app/shared/fingerprint/browser-fingerprint.service'; describe('ProfileService', () => { diff --git a/src/test/javascript/spec/service/programming-exercise-grading.service.spec.ts b/src/test/javascript/spec/service/programming-exercise-grading.service.spec.ts index 5d27d8f339af..6396a81e6dff 100644 --- a/src/test/javascript/spec/service/programming-exercise-grading.service.spec.ts +++ b/src/test/javascript/spec/service/programming-exercise-grading.service.spec.ts @@ -5,7 +5,7 @@ import { MockWebsocketService } from '../helpers/mocks/service/mock-websocket.se import { JhiWebsocketService } from 'app/core/websocket/websocket.service'; import { ProgrammingExerciseGradingService } from 'app/exercises/programming/manage/services/programming-exercise-grading.service'; import { MockHttpService } from '../helpers/mocks/service/mock-http.service'; -import { ProgrammingExerciseTestCase } from 'app/entities/programming-exercise-test-case.model'; +import { ProgrammingExerciseTestCase } from 'app/entities/programming/programming-exercise-test-case.model'; import { Result } from 'app/entities/result.model'; import { HttpClient } from '@angular/common/http'; diff --git a/src/test/javascript/spec/service/programming-exercise-task.service.spec.ts b/src/test/javascript/spec/service/programming-exercise-task.service.spec.ts index 9571cadd5392..b45536f41584 100644 --- a/src/test/javascript/spec/service/programming-exercise-task.service.spec.ts +++ b/src/test/javascript/spec/service/programming-exercise-task.service.spec.ts @@ -4,14 +4,14 @@ import { ArtemisTestModule } from '../test.module'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { AlertService } from 'app/core/util/alert.service'; import { ProgrammingExerciseGradingService } from 'app/exercises/programming/manage/services/programming-exercise-grading.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { Course } from 'app/entities/course.model'; -import { ProgrammingExerciseGradingStatistics, TestCaseStats } from 'app/entities/programming-exercise-test-case-statistics.model'; +import { ProgrammingExerciseGradingStatistics, TestCaseStats } from 'app/entities/programming/programming-exercise-test-case-statistics.model'; import { MockProvider } from 'ng-mocks'; import { MockProgrammingExerciseGradingService } from '../helpers/mocks/service/mock-programming-exercise-grading.service'; import { ProgrammingExerciseTask } from 'app/exercises/programming/manage/grading/tasks/programming-exercise-task'; import { ProgrammingExerciseServerSideTask } from 'app/entities/hestia/programming-exercise-task.model'; -import { ProgrammingExerciseTestCase, ProgrammingExerciseTestCaseType, Visibility } from 'app/entities/programming-exercise-test-case.model'; +import { ProgrammingExerciseTestCase, ProgrammingExerciseTestCaseType, Visibility } from 'app/entities/programming/programming-exercise-test-case.model'; import { firstValueFrom, of } from 'rxjs'; describe('ProgrammingExerciseTask Service', () => { diff --git a/src/test/javascript/spec/service/programming-exercise.service.spec.ts b/src/test/javascript/spec/service/programming-exercise.service.spec.ts index fd2ab5d925e7..70d9a94a1eb7 100644 --- a/src/test/javascript/spec/service/programming-exercise.service.spec.ts +++ b/src/test/javascript/spec/service/programming-exercise.service.spec.ts @@ -2,7 +2,7 @@ import { TestBed, fakeAsync, tick } from '@angular/core/testing'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { take } from 'rxjs/operators'; import { ProgrammingExerciseService } from 'app/exercises/programming/manage/services/programming-exercise.service'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { TranslateService } from '@ngx-translate/core'; import { MockTranslateService } from '../helpers/mocks/service/mock-translate.service'; import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; @@ -10,7 +10,7 @@ import { MockSyncStorage } from '../helpers/mocks/service/mock-sync-storage.serv import { ArtemisTestModule } from '../test.module'; import dayjs from 'dayjs/esm'; import { TemplateProgrammingExerciseParticipation } from 'app/entities/participation/template-programming-exercise-participation.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { Result } from 'app/entities/result.model'; import { AccountService } from 'app/core/auth/account.service'; import { MockAccountService } from '../helpers/mocks/service/mock-account.service'; diff --git a/src/test/javascript/spec/service/programming-submission.service.spec.ts b/src/test/javascript/spec/service/programming-submission.service.spec.ts index 74e4bf5c7326..6259bcaf65d9 100644 --- a/src/test/javascript/spec/service/programming-submission.service.spec.ts +++ b/src/test/javascript/spec/service/programming-submission.service.spec.ts @@ -10,7 +10,7 @@ import { } from 'app/exercises/programming/participate/programming-submission.service'; import { ParticipationWebsocketService } from 'app/overview/participation-websocket.service'; import { Result } from 'app/entities/result.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { Submission } from 'app/entities/submission.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; import { MockParticipationWebsocketService } from '../helpers/mocks/service/mock-participation-websocket.service'; diff --git a/src/test/javascript/spec/service/result.service.spec.ts b/src/test/javascript/spec/service/result.service.spec.ts index 00e6ff3ea277..8afb25f538cd 100644 --- a/src/test/javascript/spec/service/result.service.spec.ts +++ b/src/test/javascript/spec/service/result.service.spec.ts @@ -5,7 +5,7 @@ import { TranslateService } from '@ngx-translate/core'; import { MockProvider } from 'ng-mocks'; import { of } from 'rxjs'; import dayjs from 'dayjs/esm'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { EntityResponseType, ResultService } from 'app/exercises/shared/result/result.service'; import { ResultWithPointsPerGradingCriterion } from 'app/entities/result-with-points-per-grading-criterion.model'; import { Result } from 'app/entities/result.model'; @@ -19,7 +19,7 @@ import { AccountService } from 'app/core/auth/account.service'; import { MockAccountService } from '../helpers/mocks/service/mock-account.service'; import { SubmissionService } from 'app/exercises/shared/submission/submission.service'; import { AssessmentType } from 'app/entities/assessment-type.model'; -import { ProgrammingSubmission } from 'app/entities/programming-submission.model'; +import { ProgrammingSubmission } from 'app/entities/programming/programming-submission.model'; import { FeedbackType, NON_GRADED_FEEDBACK_SUGGESTION_IDENTIFIER, diff --git a/src/test/javascript/spec/service/submission-policy.service.spec.ts b/src/test/javascript/spec/service/submission-policy.service.spec.ts index 01ee9af19dba..60c5f139df52 100644 --- a/src/test/javascript/spec/service/submission-policy.service.spec.ts +++ b/src/test/javascript/spec/service/submission-policy.service.spec.ts @@ -2,7 +2,7 @@ import { TestBed, fakeAsync, tick } from '@angular/core/testing'; import { SubmissionPolicyService } from 'app/exercises/programming/manage/services/submission-policy.service'; import { LockRepositoryPolicy, SubmissionPolicyType } from 'app/entities/submission-policy.model'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { take } from 'rxjs/operators'; describe('Submission Policy Service', () => { diff --git a/src/test/javascript/spec/service/submission-version.service.spec.ts b/src/test/javascript/spec/service/submission-version.service.spec.ts index a9f9570f2207..380659aabf58 100644 --- a/src/test/javascript/spec/service/submission-version.service.spec.ts +++ b/src/test/javascript/spec/service/submission-version.service.spec.ts @@ -1,7 +1,7 @@ import { TestBed, fakeAsync, tick } from '@angular/core/testing'; import { ArtemisTestModule } from '../test.module'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import dayjs from 'dayjs/esm'; import { SubmissionVersionService } from 'app/exercises/shared/submission-version/submission-version.service'; diff --git a/src/test/javascript/spec/service/submission.service.spec.ts b/src/test/javascript/spec/service/submission.service.spec.ts index 3ceaff266c5e..276aa8be2498 100644 --- a/src/test/javascript/spec/service/submission.service.spec.ts +++ b/src/test/javascript/spec/service/submission.service.spec.ts @@ -7,7 +7,7 @@ import { LocalStorageService, SessionStorageService } from 'ngx-webstorage'; import { MockSyncStorage } from '../helpers/mocks/service/mock-sync-storage.service'; import { TranslateService } from '@ngx-translate/core'; import { MockTranslateService } from '../helpers/mocks/service/mock-translate.service'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { Result } from 'app/entities/result.model'; import { Feedback, FeedbackType } from 'app/entities/feedback.model'; import { HttpResponse } from '@angular/common/http'; diff --git a/src/test/javascript/spec/service/text-assessment-analytics.service.spec.ts b/src/test/javascript/spec/service/text-assessment-analytics.service.spec.ts index c7d1a8d53878..111bc06bc06c 100644 --- a/src/test/javascript/spec/service/text-assessment-analytics.service.spec.ts +++ b/src/test/javascript/spec/service/text-assessment-analytics.service.spec.ts @@ -1,9 +1,9 @@ import { TestBed, fakeAsync } from '@angular/core/testing'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; -import { TextAssessmentEventType } from 'app/entities/text-assesment-event.model'; +import { TextAssessmentEventType } from 'app/entities/text/text-assesment-event.model'; import { TextAssessmentAnalytics } from 'app/exercises/text/assess/analytics/text-assesment-analytics.service'; import { FeedbackType } from 'app/entities/feedback.model'; -import { TextBlockType } from 'app/entities/text-block.model'; +import { TextBlockType } from 'app/entities/text/text-block.model'; import { TranslateService } from '@ngx-translate/core'; import { MockTranslateService } from '../helpers/mocks/service/mock-translate.service'; import { MockSyncStorage } from '../helpers/mocks/service/mock-sync-storage.service'; diff --git a/src/test/javascript/spec/service/text-assessment.service.spec.ts b/src/test/javascript/spec/service/text-assessment.service.spec.ts index 4cdfb552a3f9..63ae92c49ffb 100644 --- a/src/test/javascript/spec/service/text-assessment.service.spec.ts +++ b/src/test/javascript/spec/service/text-assessment.service.spec.ts @@ -1,18 +1,18 @@ import { TestBed, fakeAsync, tick } from '@angular/core/testing'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { take } from 'rxjs/operators'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { TextAssessmentService } from 'app/exercises/text/assess/text-assessment.service'; import { Result } from 'app/entities/result.model'; -import { TextAssessmentEvent } from 'app/entities/text-assesment-event.model'; +import { TextAssessmentEvent } from 'app/entities/text/text-assesment-event.model'; import { AccountService } from 'app/core/auth/account.service'; import { MockAccountService } from '../helpers/mocks/service/mock-account.service'; import { ExerciseType } from 'app/entities/exercise.model'; import { AssessmentType } from 'app/entities/assessment-type.model'; import { Course } from 'app/entities/course.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { ComplaintResponse } from 'app/entities/complaint-response.model'; -import { TextBlockRef } from 'app/entities/text-block-ref.model'; +import { TextBlockRef } from 'app/entities/text/text-block-ref.model'; import { NewStudentParticipationResolver, StudentParticipationResolver } from 'app/exercises/text/assess/text-submission-assessment.route'; import { TextSubmissionService } from 'app/exercises/text/participate/text-submission.service'; import { of } from 'rxjs'; diff --git a/src/test/javascript/spec/service/text-exercise.service.spec.ts b/src/test/javascript/spec/service/text-exercise.service.spec.ts index 675dbd3b8aa0..5557d381a1e9 100644 --- a/src/test/javascript/spec/service/text-exercise.service.spec.ts +++ b/src/test/javascript/spec/service/text-exercise.service.spec.ts @@ -2,7 +2,7 @@ import { TestBed } from '@angular/core/testing'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { take } from 'rxjs/operators'; import { TextExerciseService } from 'app/exercises/text/manage/text-exercise/text-exercise.service'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { Course } from 'app/entities/course.model'; import { MockTranslateService } from '../helpers/mocks/service/mock-translate.service'; import { TranslateService } from '@ngx-translate/core'; diff --git a/src/test/javascript/spec/service/text-submission.service.spec.ts b/src/test/javascript/spec/service/text-submission.service.spec.ts index 3fe80d04c135..d21d44eda72c 100644 --- a/src/test/javascript/spec/service/text-submission.service.spec.ts +++ b/src/test/javascript/spec/service/text-submission.service.spec.ts @@ -2,7 +2,7 @@ import { TestBed, fakeAsync, tick } from '@angular/core/testing'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { take } from 'rxjs/operators'; import { TextSubmissionService } from 'app/exercises/text/participate/text-submission.service'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { AccountService } from 'app/core/auth/account.service'; import { MockAccountService } from '../helpers/mocks/service/mock-account.service'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; diff --git a/src/test/playwright/e2e/exam/ExamAssessment.spec.ts b/src/test/playwright/e2e/exam/ExamAssessment.spec.ts index 1e5ce60aa8d5..3bfee439d546 100644 --- a/src/test/playwright/e2e/exam/ExamAssessment.spec.ts +++ b/src/test/playwright/e2e/exam/ExamAssessment.spec.ts @@ -6,7 +6,7 @@ import { Page, expect } from '@playwright/test'; import javaPartiallySuccessful from '../../fixtures/exercise/programming/java/partially_successful/submission.json'; import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { Commands } from '../../support/commands'; import { ExamAPIRequests } from '../../support/requests/ExamAPIRequests'; import { ExamExerciseGroupCreationPage } from '../../support/pageobjects/exam/ExamExerciseGroupCreationPage'; diff --git a/src/test/playwright/e2e/exam/ExamCreationDeletion.spec.ts b/src/test/playwright/e2e/exam/ExamCreationDeletion.spec.ts index 5895880ab49e..757665204a13 100644 --- a/src/test/playwright/e2e/exam/ExamCreationDeletion.spec.ts +++ b/src/test/playwright/e2e/exam/ExamCreationDeletion.spec.ts @@ -4,7 +4,7 @@ import { Course } from 'app/entities/course.model'; import { dayjsToString, generateUUID, trimDate } from '../../support/utils'; import dayjs from 'dayjs'; import { expect } from '@playwright/test'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; /* * Common primitives diff --git a/src/test/playwright/e2e/exam/ExamManagement.spec.ts b/src/test/playwright/e2e/exam/ExamManagement.spec.ts index 743541cd5edb..a91b64b7f764 100644 --- a/src/test/playwright/e2e/exam/ExamManagement.spec.ts +++ b/src/test/playwright/e2e/exam/ExamManagement.spec.ts @@ -3,7 +3,7 @@ import { admin, instructor, studentOne } from '../../support/users'; import { generateUUID, newBrowserPage } from '../../support/utils'; import { test } from '../../support/fixtures'; import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { Commands } from '../../support/commands'; import { CourseManagementAPIRequests } from '../../support/requests/CourseManagementAPIRequests'; diff --git a/src/test/playwright/e2e/exam/ExamParticipation.spec.ts b/src/test/playwright/e2e/exam/ExamParticipation.spec.ts index 8264232513e2..a27ffe2c25ab 100644 --- a/src/test/playwright/e2e/exam/ExamParticipation.spec.ts +++ b/src/test/playwright/e2e/exam/ExamParticipation.spec.ts @@ -5,7 +5,7 @@ import { admin, instructor, studentFour, studentOne, studentThree, studentTwo, t import { generateUUID } from '../../support/utils'; import javaAllSuccessfulSubmission from '../../fixtures/exercise/programming/java/all_successful/submission.json'; import dayjs from 'dayjs'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { expect } from '@playwright/test'; import { ExamStartEndPage } from '../../support/pageobjects/exam/ExamStartEndPage'; import { Commands } from '../../support/commands'; diff --git a/src/test/playwright/e2e/exam/ExamResults.spec.ts b/src/test/playwright/e2e/exam/ExamResults.spec.ts index 676e02c2e686..874a49e23089 100644 --- a/src/test/playwright/e2e/exam/ExamResults.spec.ts +++ b/src/test/playwright/e2e/exam/ExamResults.spec.ts @@ -1,5 +1,5 @@ import { test } from '../../support/fixtures'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { Commands } from '../../support/commands'; import { admin, instructor, studentOne, tutor } from '../../support/users'; import { Course } from 'app/entities/course.model'; diff --git a/src/test/playwright/e2e/exam/ExamTestRun.spec.ts b/src/test/playwright/e2e/exam/ExamTestRun.spec.ts index 732bbc4f1290..42e873ca2427 100644 --- a/src/test/playwright/e2e/exam/ExamTestRun.spec.ts +++ b/src/test/playwright/e2e/exam/ExamTestRun.spec.ts @@ -1,7 +1,7 @@ import dayjs from 'dayjs'; import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import javaBuildErrorSubmission from '../../fixtures/exercise/programming/java/build_error/submission.json'; import { Exercise, ExerciseType } from '../../support/constants'; diff --git a/src/test/playwright/e2e/exam/test-exam/TestExamCreationDeletion.spec.ts b/src/test/playwright/e2e/exam/test-exam/TestExamCreationDeletion.spec.ts index 71ee1df974ec..d3f340fcb917 100644 --- a/src/test/playwright/e2e/exam/test-exam/TestExamCreationDeletion.spec.ts +++ b/src/test/playwright/e2e/exam/test-exam/TestExamCreationDeletion.spec.ts @@ -1,7 +1,7 @@ import dayjs from 'dayjs'; import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { admin } from '../../../support/users'; import { dayjsToString, generateUUID, trimDate } from '../../../support/utils'; diff --git a/src/test/playwright/e2e/exam/test-exam/TestExamManagement.spec.ts b/src/test/playwright/e2e/exam/test-exam/TestExamManagement.spec.ts index 931b80bace33..9fc0bdb9cf5e 100644 --- a/src/test/playwright/e2e/exam/test-exam/TestExamManagement.spec.ts +++ b/src/test/playwright/e2e/exam/test-exam/TestExamManagement.spec.ts @@ -1,5 +1,5 @@ import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { admin, instructor, studentOne } from '../../../support/users'; diff --git a/src/test/playwright/e2e/exam/test-exam/TestExamParticipation.spec.ts b/src/test/playwright/e2e/exam/test-exam/TestExamParticipation.spec.ts index 4231108de78b..c66d2966576f 100644 --- a/src/test/playwright/e2e/exam/test-exam/TestExamParticipation.spec.ts +++ b/src/test/playwright/e2e/exam/test-exam/TestExamParticipation.spec.ts @@ -1,7 +1,7 @@ import dayjs from 'dayjs'; import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import javaAllSuccessfulSubmission from '../../../fixtures/exercise/programming/java/all_successful/submission.json'; import javaBuildErrorSubmission from '../../../fixtures/exercise/programming/java/build_error/submission.json'; diff --git a/src/test/playwright/e2e/exam/test-exam/TestExamStudentExams.spec.ts b/src/test/playwright/e2e/exam/test-exam/TestExamStudentExams.spec.ts index 12ae9b246554..1699d5539c22 100644 --- a/src/test/playwright/e2e/exam/test-exam/TestExamStudentExams.spec.ts +++ b/src/test/playwright/e2e/exam/test-exam/TestExamStudentExams.spec.ts @@ -1,5 +1,5 @@ import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { UserCredentials, admin, studentOne, studentThree, studentTwo, users } from '../../../support/users'; import { generateUUID } from '../../../support/utils'; import { Exercise, ExerciseType } from '../../../support/constants'; diff --git a/src/test/playwright/e2e/exam/test-exam/TestExamTestRun.spec.ts b/src/test/playwright/e2e/exam/test-exam/TestExamTestRun.spec.ts index 90cce7420bee..66b13ff3af12 100644 --- a/src/test/playwright/e2e/exam/test-exam/TestExamTestRun.spec.ts +++ b/src/test/playwright/e2e/exam/test-exam/TestExamTestRun.spec.ts @@ -1,5 +1,5 @@ import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import javaBuildErrorSubmission from '../../../fixtures/exercise/programming/java/build_error/submission.json'; import { Exercise, ExerciseType } from '../../../support/constants'; diff --git a/src/test/playwright/e2e/exercise/ExerciseImport.spec.ts b/src/test/playwright/e2e/exercise/ExerciseImport.spec.ts index d08d08717ca7..8290457c32b9 100644 --- a/src/test/playwright/e2e/exercise/ExerciseImport.spec.ts +++ b/src/test/playwright/e2e/exercise/ExerciseImport.spec.ts @@ -2,9 +2,9 @@ import dayjs from 'dayjs'; import { Course } from 'app/entities/course.model'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import javaPartiallySuccessfulSubmission from '../../fixtures/exercise/programming/java/partially_successful/submission.json'; import multipleChoiceQuizTemplate from '../../fixtures/exercise/quiz/multiple_choice/template.json'; @@ -13,7 +13,7 @@ import { generateUUID } from '../../support/utils'; import { test } from '../../support/fixtures'; import { expect } from '@playwright/test'; import { Fixtures } from '../../fixtures/fixtures'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; import { QuizSubmission } from 'app/entities/quiz/quiz-submission.model'; import { ModelingSubmission } from 'app/entities/modeling-submission.model'; diff --git a/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseAssessment.spec.ts b/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseAssessment.spec.ts index 199c19c87306..ba4e95fbb241 100644 --- a/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseAssessment.spec.ts +++ b/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseAssessment.spec.ts @@ -1,7 +1,7 @@ import dayjs from 'dayjs'; import { Course } from 'app/entities/course.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { ProgrammingExerciseAssessmentType } from '../../../support/constants'; import { admin, instructor, studentOne, tutor } from '../../../support/users'; diff --git a/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseManagement.spec.ts b/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseManagement.spec.ts index 51e6c7bb0bc2..e3a69adabc20 100644 --- a/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseManagement.spec.ts +++ b/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseManagement.spec.ts @@ -1,5 +1,5 @@ import { Course } from 'app/entities/course.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { admin, instructor, studentFour, studentOne, studentThree, studentTwo, tutor } from '../../../support/users'; import { test } from '../../../support/fixtures'; diff --git a/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseParticipation.spec.ts b/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseParticipation.spec.ts index f0540dc21dc3..0a36076081ea 100644 --- a/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseParticipation.spec.ts +++ b/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseParticipation.spec.ts @@ -1,5 +1,5 @@ import { Course } from 'app/entities/course.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import javaAllSuccessfulSubmission from '../../../fixtures/exercise/programming/java/all_successful/submission.json'; import javaBuildErrorSubmission from '../../../fixtures/exercise/programming/java/build_error/submission.json'; diff --git a/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseStaticCodeAnalysis.spec.ts b/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseStaticCodeAnalysis.spec.ts index ffeb96adc4d5..c11dac9b557e 100644 --- a/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseStaticCodeAnalysis.spec.ts +++ b/src/test/playwright/e2e/exercise/programming/ProgrammingExerciseStaticCodeAnalysis.spec.ts @@ -1,5 +1,5 @@ import { Course } from 'app/entities/course.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import javaScaSubmission from '../../../fixtures/exercise/programming/java/static_code_analysis/submission.json'; import { admin, studentOne } from '../../../support/users'; diff --git a/src/test/playwright/e2e/exercise/text/TextExerciseAssessment.spec.ts b/src/test/playwright/e2e/exercise/text/TextExerciseAssessment.spec.ts index 61228fd2ef67..ed4b9a076c42 100644 --- a/src/test/playwright/e2e/exercise/text/TextExerciseAssessment.spec.ts +++ b/src/test/playwright/e2e/exercise/text/TextExerciseAssessment.spec.ts @@ -1,5 +1,5 @@ import { Course } from 'app/entities/course.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { admin, instructor, studentOne, tutor } from '../../../support/users'; import { test } from '../../../support/fixtures'; diff --git a/src/test/playwright/e2e/exercise/text/TextExerciseManagement.spec.ts b/src/test/playwright/e2e/exercise/text/TextExerciseManagement.spec.ts index 56ab3c12e168..5bf800e36484 100644 --- a/src/test/playwright/e2e/exercise/text/TextExerciseManagement.spec.ts +++ b/src/test/playwright/e2e/exercise/text/TextExerciseManagement.spec.ts @@ -1,12 +1,12 @@ import { Course } from 'app/entities/course.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { test } from '../../../support/fixtures'; import { admin } from '../../../support/users'; import { generateUUID } from '../../../support/utils'; import dayjs from 'dayjs'; import { expect } from '@playwright/test'; import { ExampleSubmission } from 'app/entities/example-submission.model'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; test.describe('Text exercise management', () => { let course: Course; diff --git a/src/test/playwright/e2e/exercise/text/TextExerciseParticipation.spec.ts b/src/test/playwright/e2e/exercise/text/TextExerciseParticipation.spec.ts index d476578e779c..b2ac84ef3284 100644 --- a/src/test/playwright/e2e/exercise/text/TextExerciseParticipation.spec.ts +++ b/src/test/playwright/e2e/exercise/text/TextExerciseParticipation.spec.ts @@ -1,11 +1,11 @@ import { Course } from 'app/entities/course.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import { admin, studentOne } from '../../../support/users'; import { test } from '../../../support/fixtures'; import { Fixtures } from '../../../fixtures/fixtures'; import { expect } from '@playwright/test'; -import { TextSubmission } from 'app/entities/text-submission.model'; +import { TextSubmission } from 'app/entities/text/text-submission.model'; test.describe('Text exercise participation', () => { let course: Course; diff --git a/src/test/playwright/support/pageobjects/exam/ExamExerciseGroupCreationPage.ts b/src/test/playwright/support/pageobjects/exam/ExamExerciseGroupCreationPage.ts index 2c060438098e..58d3557d19f3 100644 --- a/src/test/playwright/support/pageobjects/exam/ExamExerciseGroupCreationPage.ts +++ b/src/test/playwright/support/pageobjects/exam/ExamExerciseGroupCreationPage.ts @@ -1,5 +1,5 @@ import { Page } from '@playwright/test'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { ExamAPIRequests } from '../../requests/ExamAPIRequests'; import { ExerciseAPIRequests } from '../../requests/ExerciseAPIRequests'; import multipleChoiceTemplate from '../../../fixtures/exercise/quiz/multiple_choice/template.json'; @@ -8,7 +8,7 @@ import { generateUUID } from '../../utils'; import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { Exercise } from 'app/entities/exercise.model'; -import { Visibility } from 'app/entities/programming-exercise-test-case.model'; +import { Visibility } from 'app/entities/programming/programming-exercise-test-case.model'; export class ExamExerciseGroupCreationPage { private readonly page: Page; diff --git a/src/test/playwright/support/pageobjects/exam/ExamParticipationPage.ts b/src/test/playwright/support/pageobjects/exam/ExamParticipationPage.ts index cdec2ee5d8dc..e07b9e42f486 100644 --- a/src/test/playwright/support/pageobjects/exam/ExamParticipationPage.ts +++ b/src/test/playwright/support/pageobjects/exam/ExamParticipationPage.ts @@ -1,6 +1,6 @@ import { Page, expect } from '@playwright/test'; import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { AdditionalData, ExerciseType } from '../../constants'; import { UserCredentials } from '../../users'; import { OnlineEditorPage, ProgrammingExerciseSubmission } from '../exercises/programming/OnlineEditorPage'; diff --git a/src/test/playwright/support/pageobjects/exam/ExamTestRunPage.ts b/src/test/playwright/support/pageobjects/exam/ExamTestRunPage.ts index a5e3891f5ef7..d741796fe898 100644 --- a/src/test/playwright/support/pageobjects/exam/ExamTestRunPage.ts +++ b/src/test/playwright/support/pageobjects/exam/ExamTestRunPage.ts @@ -1,6 +1,6 @@ import { Page } from '@playwright/test'; import { Course } from 'app/entities/course.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { UserCredentials } from '../../users'; import { Commands } from '../../commands'; import { ExamStartEndPage } from './ExamStartEndPage'; diff --git a/src/test/playwright/support/requests/CourseManagementAPIRequests.ts b/src/test/playwright/support/requests/CourseManagementAPIRequests.ts index 3b04f8571785..3003ec91e760 100644 --- a/src/test/playwright/support/requests/CourseManagementAPIRequests.ts +++ b/src/test/playwright/support/requests/CourseManagementAPIRequests.ts @@ -8,7 +8,7 @@ import lectureTemplate from '../../fixtures/lecture/template.json'; import { BASE_API, COURSE_ADMIN_BASE, COURSE_BASE, Exercise } from '../constants'; import { UserCredentials } from '../users'; import { Commands } from '../commands'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; /** * A class which encapsulates all API requests related to course management. diff --git a/src/test/playwright/support/requests/ExamAPIRequests.ts b/src/test/playwright/support/requests/ExamAPIRequests.ts index be8175b5a711..c250415fb2db 100644 --- a/src/test/playwright/support/requests/ExamAPIRequests.ts +++ b/src/test/playwright/support/requests/ExamAPIRequests.ts @@ -1,6 +1,6 @@ import { Course } from 'app/entities/course.model'; import dayjs from 'dayjs'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { dayjsToString, generateUUID, titleLowercase } from '../utils'; import examTemplate from '../../fixtures/exam/template.json'; import { Page } from '@playwright/test'; diff --git a/src/test/playwright/support/requests/ExerciseAPIRequests.ts b/src/test/playwright/support/requests/ExerciseAPIRequests.ts index 9b7bc73ace71..2fac212a5d73 100644 --- a/src/test/playwright/support/requests/ExerciseAPIRequests.ts +++ b/src/test/playwright/support/requests/ExerciseAPIRequests.ts @@ -4,7 +4,7 @@ import { Page } from 'playwright-core'; import { Course } from 'app/entities/course.model'; import { ExerciseGroup } from 'app/entities/exercise-group.model'; import { QuizExercise } from 'app/entities/quiz/quiz-exercise.model'; -import { TextExercise } from 'app/entities/text-exercise.model'; +import { TextExercise } from 'app/entities/text/text-exercise.model'; import fileUploadExerciseTemplate from '../../fixtures/exercise/file-upload/template.json'; import modelingExerciseSubmissionTemplate from '../../fixtures/exercise/modeling/submission.json'; @@ -34,16 +34,16 @@ import { } from '../constants'; import { dayjsToString, generateUUID, titleLowercase } from '../utils'; import { ModelingExercise } from 'app/entities/modeling-exercise.model'; -import { ProgrammingExercise } from 'app/entities/programming-exercise.model'; +import { ProgrammingExercise } from 'app/entities/programming/programming-exercise.model'; import { FileUploadExercise } from 'app/entities/file-upload-exercise.model'; import { Participation } from 'app/entities/participation/participation.model'; -import { Exam } from 'app/entities/exam.model'; +import { Exam } from 'app/entities/exam/exam.model'; import { StudentParticipation } from 'app/entities/participation/student-participation.model'; import { Team } from 'app/entities/team.model'; import { TeamAssignmentConfig } from 'app/entities/team-assignment-config.model'; import { ProgrammingExerciseSubmission } from '../pageobjects/exercises/programming/OnlineEditorPage'; import { Fixtures } from '../../fixtures/fixtures'; -import { ProgrammingExerciseTestCase, Visibility } from 'app/entities/programming-exercise-test-case.model'; +import { ProgrammingExerciseTestCase, Visibility } from 'app/entities/programming/programming-exercise-test-case.model'; type PatchProgrammingExerciseTestVisibilityDto = { id: number; From f60288bd62c17d70bd186634b8ee0e07571430ae Mon Sep 17 00:00:00 2001 From: Stephan Krusche Date: Tue, 3 Sep 2024 22:17:53 +0200 Subject: [PATCH 09/16] Plagiarism checks: Fix slow performance in large courses (#9269) --- .../StudentParticipationRepository.java | 32 +++++++++++++++---- ...ProgrammingPlagiarismDetectionService.java | 6 ++-- ...ontinuousPlagiarismControlServiceTest.java | 7 +++- .../PlagiarismDetectionConfigHelperTest.java | 3 +- .../PlagiarismDetectionServiceTest.java | 7 +++- 5 files changed, 44 insertions(+), 11 deletions(-) rename src/test/java/de/tum/in/www1/artemis/{service => }/plagiarism/ContinuousPlagiarismControlServiceTest.java (96%) rename src/test/java/de/tum/in/www1/artemis/{service => }/plagiarism/PlagiarismDetectionConfigHelperTest.java (96%) rename src/test/java/de/tum/in/www1/artemis/{service => }/plagiarism/PlagiarismDetectionServiceTest.java (93%) diff --git a/src/main/java/de/tum/in/www1/artemis/repository/StudentParticipationRepository.java b/src/main/java/de/tum/in/www1/artemis/repository/StudentParticipationRepository.java index 8cd15a15b573..f339eb61f51d 100644 --- a/src/main/java/de/tum/in/www1/artemis/repository/StudentParticipationRepository.java +++ b/src/main/java/de/tum/in/www1/artemis/repository/StudentParticipationRepository.java @@ -703,18 +703,38 @@ default Page findAllWithEagerSubmissionsAndResultsByExerci """) List findAllWithEagerLegalSubmissionsAndEagerResultsByExerciseId(@Param("exerciseId") long exerciseId); + /** + * Retrieves all distinct `StudentParticipation` entities for a specific exercise, + * including their latest non-illegal submission and the latest rated result for each submission. + * The method fetches related submissions, results, student, and team data to avoid the N+1 select problem. + * + *

+ * The method ensures that: + *

    + *
  • Only participations belonging to the specified exercise are retrieved.
  • + *
  • Participations marked as a test run are excluded.
  • + *
  • Only the latest non-illegal submission for each participation is considered.
  • + *
  • Only the latest rated result for each submission is considered.
  • + *
+ * + * @param exerciseId the ID of the exercise for which to retrieve participations. + * @return a list of distinct `StudentParticipation` entities matching the criteria. + */ @Query(""" SELECT DISTINCT p FROM StudentParticipation p - LEFT JOIN FETCH p.results r - LEFT JOIN FETCH r.submission rs LEFT JOIN FETCH p.submissions s - LEFT JOIN FETCH s.results sr + LEFT JOIN FETCH s.results r + LEFT JOIN FETCH p.student + LEFT JOIN FETCH p.team WHERE p.exercise.id = :exerciseId AND p.testRun = FALSE - AND p.submissions IS NOT EMPTY - AND (s.type <> de.tum.in.www1.artemis.domain.enumeration.SubmissionType.ILLEGAL OR s.type IS NULL) - AND (rs.type <> de.tum.in.www1.artemis.domain.enumeration.SubmissionType.ILLEGAL OR rs.type IS NULL) + AND s.id = (SELECT MAX(s2.id) + FROM p.submissions s2 + WHERE s2.type <> de.tum.in.www1.artemis.domain.enumeration.SubmissionType.ILLEGAL OR s2.type IS NULL) + AND r.id = (SELECT MAX(r2.id) + FROM s.results r2 + WHERE r2.rated = TRUE) """) List findAllForPlagiarism(@Param("exerciseId") long exerciseId); diff --git a/src/main/java/de/tum/in/www1/artemis/service/plagiarism/ProgrammingPlagiarismDetectionService.java b/src/main/java/de/tum/in/www1/artemis/service/plagiarism/ProgrammingPlagiarismDetectionService.java index 16b674bb748d..68d63b1f49e7 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/plagiarism/ProgrammingPlagiarismDetectionService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/plagiarism/ProgrammingPlagiarismDetectionService.java @@ -185,7 +185,7 @@ public File checkPlagiarismWithJPlagReport(long programmingExerciseId, float sim private JPlagResult computeJPlagResult(ProgrammingExercise programmingExercise, float similarityThreshold, int minimumScore, int minimumSize) { long programmingExerciseId = programmingExercise.getId(); final var targetPath = fileService.getTemporaryUniqueSubfolderPath(repoDownloadClonePath, 60); - List participations = filterStudentParticipationsForComparison(programmingExercise, minimumScore); + List participations = findStudentParticipationsForComparison(programmingExercise, minimumScore); log.info("Download repositories for JPlag for programming exercise {} to compare {} participations", programmingExerciseId, participations.size()); if (participations.size() < 2) { @@ -326,8 +326,10 @@ private Language getJPlagProgrammingLanguage(ProgrammingExercise programmingExer * @param minimumScore consider only submissions whose score is greater or equal to this value * @return an unmodifiable list containing the latest text submission for every participation */ - public List filterStudentParticipationsForComparison(ProgrammingExercise programmingExercise, int minimumScore) { + public List findStudentParticipationsForComparison(ProgrammingExercise programmingExercise, int minimumScore) { + long start = System.nanoTime(); var studentParticipations = studentParticipationRepository.findAllForPlagiarism(programmingExercise.getId()); + log.info("findAllForPlagiarism took {}", TimeLogUtil.formatDurationFrom(start)); return studentParticipations.parallelStream().filter(participation -> !participation.isPracticeMode()) .filter(participation -> participation instanceof ProgrammingExerciseStudentParticipation).filter(plagiarismService.filterForStudents()) diff --git a/src/test/java/de/tum/in/www1/artemis/service/plagiarism/ContinuousPlagiarismControlServiceTest.java b/src/test/java/de/tum/in/www1/artemis/plagiarism/ContinuousPlagiarismControlServiceTest.java similarity index 96% rename from src/test/java/de/tum/in/www1/artemis/service/plagiarism/ContinuousPlagiarismControlServiceTest.java rename to src/test/java/de/tum/in/www1/artemis/plagiarism/ContinuousPlagiarismControlServiceTest.java index 45374611d0ba..957238bac53e 100644 --- a/src/test/java/de/tum/in/www1/artemis/service/plagiarism/ContinuousPlagiarismControlServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/plagiarism/ContinuousPlagiarismControlServiceTest.java @@ -1,4 +1,4 @@ -package de.tum.in.www1.artemis.service.plagiarism; +package de.tum.in.www1.artemis.plagiarism; import static java.util.Collections.emptySet; import static java.util.Collections.singleton; @@ -43,6 +43,11 @@ import de.tum.in.www1.artemis.repository.plagiarism.PlagiarismCaseRepository; import de.tum.in.www1.artemis.repository.plagiarism.PlagiarismComparisonRepository; import de.tum.in.www1.artemis.repository.plagiarism.PlagiarismResultRepository; +import de.tum.in.www1.artemis.service.plagiarism.ContinuousPlagiarismControlService; +import de.tum.in.www1.artemis.service.plagiarism.PlagiarismCaseService; +import de.tum.in.www1.artemis.service.plagiarism.PlagiarismDetectionService; +import de.tum.in.www1.artemis.service.plagiarism.PlagiarismPostService; +import de.tum.in.www1.artemis.service.plagiarism.ProgrammingLanguageNotSupportedForPlagiarismDetectionException; class ContinuousPlagiarismControlServiceTest { diff --git a/src/test/java/de/tum/in/www1/artemis/service/plagiarism/PlagiarismDetectionConfigHelperTest.java b/src/test/java/de/tum/in/www1/artemis/plagiarism/PlagiarismDetectionConfigHelperTest.java similarity index 96% rename from src/test/java/de/tum/in/www1/artemis/service/plagiarism/PlagiarismDetectionConfigHelperTest.java rename to src/test/java/de/tum/in/www1/artemis/plagiarism/PlagiarismDetectionConfigHelperTest.java index 83b6938a5040..1672a44291af 100644 --- a/src/test/java/de/tum/in/www1/artemis/service/plagiarism/PlagiarismDetectionConfigHelperTest.java +++ b/src/test/java/de/tum/in/www1/artemis/plagiarism/PlagiarismDetectionConfigHelperTest.java @@ -1,4 +1,4 @@ -package de.tum.in.www1.artemis.service.plagiarism; +package de.tum.in.www1.artemis.plagiarism; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -12,6 +12,7 @@ import de.tum.in.www1.artemis.domain.modeling.ModelingExercise; import de.tum.in.www1.artemis.domain.plagiarism.PlagiarismDetectionConfig; import de.tum.in.www1.artemis.repository.ModelingExerciseRepository; +import de.tum.in.www1.artemis.service.plagiarism.PlagiarismDetectionConfigHelper; class PlagiarismDetectionConfigHelperTest { diff --git a/src/test/java/de/tum/in/www1/artemis/service/plagiarism/PlagiarismDetectionServiceTest.java b/src/test/java/de/tum/in/www1/artemis/plagiarism/PlagiarismDetectionServiceTest.java similarity index 93% rename from src/test/java/de/tum/in/www1/artemis/service/plagiarism/PlagiarismDetectionServiceTest.java rename to src/test/java/de/tum/in/www1/artemis/plagiarism/PlagiarismDetectionServiceTest.java index d80897af7d4f..39ab8d09aad3 100644 --- a/src/test/java/de/tum/in/www1/artemis/service/plagiarism/PlagiarismDetectionServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/plagiarism/PlagiarismDetectionServiceTest.java @@ -1,4 +1,4 @@ -package de.tum.in.www1.artemis.service.plagiarism; +package de.tum.in.www1.artemis.plagiarism; import static java.util.Collections.emptyList; import static java.util.Collections.emptySet; @@ -22,6 +22,11 @@ import de.tum.in.www1.artemis.domain.plagiarism.modeling.ModelingPlagiarismResult; import de.tum.in.www1.artemis.domain.plagiarism.text.TextPlagiarismResult; import de.tum.in.www1.artemis.repository.plagiarism.PlagiarismResultRepository; +import de.tum.in.www1.artemis.service.plagiarism.ModelingPlagiarismDetectionService; +import de.tum.in.www1.artemis.service.plagiarism.PlagiarismDetectionService; +import de.tum.in.www1.artemis.service.plagiarism.ProgrammingLanguageNotSupportedForPlagiarismDetectionException; +import de.tum.in.www1.artemis.service.plagiarism.ProgrammingPlagiarismDetectionService; +import de.tum.in.www1.artemis.service.plagiarism.TextPlagiarismDetectionService; import de.tum.in.www1.artemis.service.programming.ProgrammingLanguageFeature; import de.tum.in.www1.artemis.service.programming.ProgrammingLanguageFeatureService; From 4c08cc725a64927439015359b53b8f44b6ec55ac Mon Sep 17 00:00:00 2001 From: Aybike Ece Eren Date: Wed, 4 Sep 2024 11:36:04 +0300 Subject: [PATCH 10/16] Lectures: Add PDF preview for instructors (#8987) --- package-lock.json | 453 +++++++++++++++++- package.json | 1 + .../www1/artemis/web/rest/FileResource.java | 63 +++ .../webapp/app/lecture/attachment.service.ts | 11 + .../lecture-attachments.component.html | 11 + .../lecture/lecture-attachments.component.ts | 15 +- .../attachmentUnit.service.ts | 11 + .../lecture-unit-management.component.html | 10 + .../lecture-unit-management.component.ts | 20 +- .../lecture-unit-management.route.ts | 35 +- src/main/webapp/app/lecture/lecture.route.ts | 33 ++ .../pdf-preview/pdf-preview.component.html | 31 ++ .../pdf-preview/pdf-preview.component.scss | 89 ++++ .../pdf-preview/pdf-preview.component.ts | 341 +++++++++++++ .../shared/layouts/navbar/navbar.component.ts | 3 + .../content/scss/themes/_dark-variables.scss | 6 + .../scss/themes/_default-variables.scss | 6 + src/main/webapp/i18n/de/lecture.json | 7 +- src/main/webapp/i18n/en/lecture.json | 7 +- .../in/www1/artemis/FileIntegrationTest.java | 39 +- .../attachment-unit.service.spec.ts | 19 + .../lecture-unit-management.component.spec.ts | 43 +- .../lecture-attachments.component.spec.ts | 22 +- .../lecture/pdf-preview.component.spec.ts | 437 +++++++++++++++++ .../spec/service/attachment.service.spec.ts | 19 + 25 files changed, 1702 insertions(+), 30 deletions(-) create mode 100644 src/main/webapp/app/lecture/pdf-preview/pdf-preview.component.html create mode 100644 src/main/webapp/app/lecture/pdf-preview/pdf-preview.component.scss create mode 100644 src/main/webapp/app/lecture/pdf-preview/pdf-preview.component.ts create mode 100644 src/test/javascript/spec/component/lecture/pdf-preview.component.spec.ts diff --git a/package-lock.json b/package-lock.json index 0867dc1f015b..8b95e957e32e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -59,6 +59,7 @@ "ngx-infinite-scroll": "18.0.0", "ngx-webstorage": "18.0.0", "papaparse": "5.4.1", + "pdfjs-dist": "^4.5.136", "posthog-js": "1.160.0", "rxjs": "7.8.1", "showdown": "2.1.0", @@ -5010,6 +5011,103 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "optional": true + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "optional": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "optional": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "optional": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "optional": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "optional": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz", @@ -7350,6 +7448,40 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "optional": true + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "deprecated": "This package is no longer supported.", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/are-we-there-yet/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "optional": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -7747,7 +7879,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/base64-js": { @@ -8155,6 +8287,21 @@ ], "license": "CC-BY-4.0" }, + "node_modules/canvas": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", + "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.17.0", + "simple-get": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -8214,7 +8361,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true, + "devOptional": true, "license": "ISC", "engines": { "node": ">=10" @@ -8480,6 +8627,15 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "license": "MIT" }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "optional": true, + "bin": { + "color-support": "bin.js" + } + }, "node_modules/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", @@ -8559,7 +8715,7 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/connect-history-api-fallback": { @@ -8572,6 +8728,12 @@ "node": ">=0.8" } }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "optional": true + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -9427,6 +9589,18 @@ "dev": true, "license": "MIT" }, + "node_modules/decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "optional": true, + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/dedent": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", @@ -9556,6 +9730,12 @@ "node": ">=0.4.0" } }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "optional": true + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -9591,7 +9771,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=8" @@ -11331,7 +11511,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/fsevents": { @@ -11358,6 +11538,62 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "deprecated": "This package is no longer supported.", + "optional": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gauge/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "optional": true + }, + "node_modules/gauge/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/gauge/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "optional": true + }, + "node_modules/gauge/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "optional": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -11454,7 +11690,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -11494,7 +11730,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -11505,7 +11741,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -11635,6 +11871,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "optional": true + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -12150,7 +12392,7 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -15820,6 +16062,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "optional": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/mini-css-extract-plugin": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.0.tgz", @@ -16018,7 +16272,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "minipass": "^3.0.0", @@ -16032,7 +16286,7 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -16045,14 +16299,14 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, + "devOptional": true, "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" @@ -16173,6 +16427,12 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/nan": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz", + "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==", + "optional": true + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -16321,6 +16581,48 @@ "dev": true, "license": "MIT" }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "optional": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "optional": true + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "optional": true + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "optional": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -16607,6 +16909,19 @@ "node": ">=8" } }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "deprecated": "This package is no longer supported.", + "optional": true, + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -16683,7 +16998,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -17144,7 +17459,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -17211,6 +17526,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/path2d": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/path2d/-/path2d-0.2.1.tgz", + "integrity": "sha512-Fl2z/BHvkTNvkuBzYTpTuirHZg6wW9z8+4SND/3mDTEcYbbNKWAy21dz9D3ePNNwrrK8pqZO5vLPZ1hLF6T7XA==", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pdfjs-dist": { + "version": "4.5.136", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-4.5.136.tgz", + "integrity": "sha512-V1BALcAN/FmxBEShLxoP73PlQZAZtzlaNfRbRhJrKvXzjLC5VaIlBAQUJuWP8iaYUmIdmdLHmt3E2TBglxOm3w==", + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "canvas": "^2.11.2", + "path2d": "^0.2.1" + } + }, "node_modules/pepjs": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/pepjs/-/pepjs-0.5.3.tgz", @@ -18741,6 +19077,12 @@ "node": ">= 0.8.0" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "optional": true + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -18936,6 +19278,37 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, + "node_modules/simple-get": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "optional": true, + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/simple-statistics": { "version": "7.8.5", "resolved": "https://registry.npmjs.org/simple-statistics/-/simple-statistics-7.8.5.tgz", @@ -19575,7 +19948,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "chownr": "^2.0.0", @@ -19593,7 +19966,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "minipass": "^3.0.0" @@ -19606,7 +19979,7 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -19619,7 +19992,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, + "devOptional": true, "license": "ISC", "engines": { "node": ">=8" @@ -19629,7 +20002,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/terser": { @@ -21537,6 +21910,44 @@ "node": ">= 8" } }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "optional": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wide-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "optional": true + }, + "node_modules/wide-align/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wide-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "optional": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wildcard": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", @@ -21728,7 +22139,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/write-file-atomic": { diff --git a/package.json b/package.json index 6a576592bbf0..951a680f6aa5 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "ngx-infinite-scroll": "18.0.0", "ngx-webstorage": "18.0.0", "papaparse": "5.4.1", + "pdfjs-dist": "^4.5.136", "posthog-js": "1.160.0", "rxjs": "7.8.1", "showdown": "2.1.0", diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/FileResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/FileResource.java index ad959b26096f..8627d8f701ed 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/FileResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/FileResource.java @@ -69,6 +69,7 @@ import de.tum.in.www1.artemis.security.annotations.EnforceAtLeastInstructor; import de.tum.in.www1.artemis.security.annotations.EnforceAtLeastStudent; import de.tum.in.www1.artemis.security.annotations.EnforceAtLeastTutor; +import de.tum.in.www1.artemis.security.annotations.enforceRoleInCourse.EnforceAtLeastEditorInCourse; import de.tum.in.www1.artemis.service.AuthorizationCheckService; import de.tum.in.www1.artemis.service.FilePathService; import de.tum.in.www1.artemis.service.FileService; @@ -372,6 +373,24 @@ public ResponseEntity getLectureAttachment(@PathVariable Long lectureId, return buildFileResponse(getActualPathFromPublicPathString(attachment.getLink()), false); } + /** + * GET /files/courses/{courseId}/attachments/{attachmentId} : Returns the file associated with the + * given attachment ID as a downloadable resource + * + * @param courseId The ID of the course that the Attachment belongs to + * @param attachmentId the ID of the attachment to retrieve + * @return ResponseEntity containing the file as a resource + */ + @GetMapping("files/courses/{courseId}/attachments/{attachmentId}") + @EnforceAtLeastEditorInCourse + public ResponseEntity getAttachmentFile(@PathVariable Long courseId, @PathVariable Long attachmentId) { + Attachment attachment = attachmentRepository.findByIdElseThrow(attachmentId); + Course course = courseRepository.findByIdElseThrow(courseId); + checkAttachmentExistsInCourseOrThrow(course, attachment); + + return buildFileResponse(getActualPathFromPublicPathString(attachment.getLink()), false); + } + /** * GET /files/attachments/lecture/{lectureId}/merge-pdf : Get the lecture units * PDF attachments merged @@ -428,6 +447,26 @@ public ResponseEntity getAttachmentUnitAttachment(@PathVariable Long att return buildFileResponse(getActualPathFromPublicPathString(attachment.getLink()), false); } + /** + * GET files/courses/{courseId}/attachment-units/{attachmenUnitId} : Returns the file associated with the + * given attachmentUnit ID as a downloadable resource + * + * @param courseId The ID of the course that the Attachment belongs to + * @param attachmentUnitId the ID of the attachment to retrieve + * @return ResponseEntity containing the file as a resource + */ + @GetMapping("files/courses/{courseId}/attachment-units/{attachmentUnitId}") + @EnforceAtLeastEditorInCourse + public ResponseEntity getAttachmentUnitFile(@PathVariable Long courseId, @PathVariable Long attachmentUnitId) { + log.debug("REST request to get file for attachment unit : {}", attachmentUnitId); + AttachmentUnit attachmentUnit = attachmentUnitRepository.findByIdElseThrow(attachmentUnitId); + Course course = courseRepository.findByIdElseThrow(courseId); + Attachment attachment = attachmentUnit.getAttachment(); + checkAttachmentUnitExistsInCourseOrThrow(course, attachmentUnit); + + return buildFileResponse(getActualPathFromPublicPathString(attachment.getLink()), false); + } + /** * GET files/attachments/slides/attachment-unit/:attachmentUnitId/slide/:slideNumber : Get the lecture unit attachment slide by slide number * @@ -557,6 +596,30 @@ private void checkAttachmentAuthorizationOrThrow(Course course, Attachment attac } } + /** + * Checks if the attachment exists in the mentioned course + * + * @param course the course to check if the attachment is part of it + * @param attachment the attachment for which the existence should be checked + */ + private void checkAttachmentExistsInCourseOrThrow(Course course, Attachment attachment) { + if (!attachment.getLecture().getCourse().equals(course)) { + throw new EntityNotFoundException("This attachment does not exist in this course."); + } + } + + /** + * Checks if the attachment exists in the mentioned course + * + * @param course the course to check if the attachment is part of it + * @param attachmentUnit the attachment unit for which the existence should be checked + */ + private void checkAttachmentUnitExistsInCourseOrThrow(Course course, AttachmentUnit attachmentUnit) { + if (!attachmentUnit.getLecture().getCourse().equals(course)) { + throw new EntityNotFoundException("This attachment unit does not exist in this course."); + } + } + /** * Reads the file and turns it into a ResponseEntity * diff --git a/src/main/webapp/app/lecture/attachment.service.ts b/src/main/webapp/app/lecture/attachment.service.ts index 57d22c64d550..49f6739bfd8d 100644 --- a/src/main/webapp/app/lecture/attachment.service.ts +++ b/src/main/webapp/app/lecture/attachment.service.ts @@ -135,4 +135,15 @@ export class AttachmentService { } return formData; } + + /** + * Retrieve the file associated with a given attachment ID as a Blob object + * + * @param courseId The ID of the course that the attachment belongs to + * @param attachmentId The ID of the attachment to retrieve + * @returns An Observable that emits the Blob object of the file when the HTTP request completes successfully + */ + getAttachmentFile(courseId: number, attachmentId: number): Observable { + return this.http.get(`api/files/courses/${courseId}/attachments/${attachmentId}`, { responseType: 'blob' }); + } } diff --git a/src/main/webapp/app/lecture/lecture-attachments.component.html b/src/main/webapp/app/lecture/lecture-attachments.component.html index dafff574b446..c20d21a173c5 100644 --- a/src/main/webapp/app/lecture/lecture-attachments.component.html +++ b/src/main/webapp/app/lecture/lecture-attachments.component.html @@ -79,6 +79,17 @@

+ @if (viewButtonAvailable[attachment.id!]) { + + } + @if (currentPage !== 1) { + + } + @if (currentPage !== totalPages) { + + } +
{{ currentPage }}
+
+ } +
+ + + + diff --git a/src/main/webapp/app/lecture/pdf-preview/pdf-preview.component.scss b/src/main/webapp/app/lecture/pdf-preview/pdf-preview.component.scss new file mode 100644 index 000000000000..1ce2019305cb --- /dev/null +++ b/src/main/webapp/app/lecture/pdf-preview/pdf-preview.component.scss @@ -0,0 +1,89 @@ +.pdf-container { + position: relative; + display: grid; + grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); + gap: 30px; + max-height: 60vh; + height: 60vh; + overflow-y: auto; + border: 1px solid var(--border-color); + padding: 10px; + margin: 10px; + width: 95%; + box-shadow: 0 2px 5px var(--pdf-preview-pdf-container-shadow); + align-items: start; + z-index: 0; + + @media (max-width: 800px) { + grid-template-columns: repeat(2, 1fr); + } + + @media (max-width: 500px) { + grid-template-columns: 1fr; + } +} + +.enlarged-container { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + background-color: var(--pdf-preview-enlarged-container-overlay); + z-index: 2; + + .btn-close { + position: absolute; + top: 10px; + right: 10px; + cursor: pointer; + color: var(--bs-body-color); + } +} + +.nav-button { + position: absolute; + transform: translateY(-50%); + cursor: pointer; + border-radius: 50%; + width: 30px; + height: 30px; + display: flex; + justify-content: center; + align-items: center; + font-size: 20px; + z-index: 3; +} + +.nav-button.left { + left: calc(5% + 10px); + + @media (max-width: 1200px) { + left: 10px; + } +} + +.nav-button.right { + right: calc(5% + 10px); + + @media (max-width: 1200px) { + right: 10px; + } +} + +.page-number-display { + position: absolute; + bottom: 10px; + right: calc(5% + 10px); + font-size: 18px; + color: var(--bs-body-color); + z-index: 2; + text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); + + @media (max-width: 1200px) { + right: 10px; + } +} diff --git a/src/main/webapp/app/lecture/pdf-preview/pdf-preview.component.ts b/src/main/webapp/app/lecture/pdf-preview/pdf-preview.component.ts new file mode 100644 index 000000000000..f2075dc57fbb --- /dev/null +++ b/src/main/webapp/app/lecture/pdf-preview/pdf-preview.component.ts @@ -0,0 +1,341 @@ +import { Component, ElementRef, HostListener, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { AttachmentService } from 'app/lecture/attachment.service'; +import * as PDFJS from 'pdfjs-dist'; +import 'pdfjs-dist/build/pdf.worker'; +import { Attachment } from 'app/entities/attachment.model'; +import { AttachmentUnit } from 'app/entities/lecture-unit/attachmentUnit.model'; +import { AttachmentUnitService } from 'app/lecture/lecture-unit/lecture-unit-management/attachmentUnit.service'; +import { onError } from 'app/shared/util/global.utils'; +import { AlertService } from 'app/core/util/alert.service'; +import { Subscription } from 'rxjs'; +import { Course } from 'app/entities/course.model'; +import { HttpErrorResponse } from '@angular/common/http'; +import { ArtemisSharedModule } from 'app/shared/shared.module'; + +type NavigationDirection = 'next' | 'prev'; + +@Component({ + selector: 'jhi-pdf-preview-component', + templateUrl: './pdf-preview.component.html', + styleUrls: ['./pdf-preview.component.scss'], + standalone: true, + imports: [ArtemisSharedModule], +}) +export class PdfPreviewComponent implements OnInit, OnDestroy { + @ViewChild('pdfContainer', { static: true }) pdfContainer: ElementRef; + @ViewChild('enlargedCanvas') enlargedCanvas: ElementRef; + + readonly DEFAULT_SLIDE_WIDTH = 250; + course?: Course; + attachment?: Attachment; + attachmentUnit?: AttachmentUnit; + isEnlargedView = false; + currentPage = 1; + totalPages = 0; + attachmentSub: Subscription; + attachmentUnitSub: Subscription; + + constructor( + public route: ActivatedRoute, + private attachmentService: AttachmentService, + private attachmentUnitService: AttachmentUnitService, + private alertService: AlertService, + ) {} + + ngOnInit() { + this.route.data.subscribe((data) => { + this.course = data.course; + if ('attachment' in data) { + this.attachment = data.attachment; + this.attachmentSub = this.attachmentService.getAttachmentFile(this.course!.id!, this.attachment!.id!).subscribe({ + next: (blob: Blob) => this.loadPdf(URL.createObjectURL(blob)), + error: (error: HttpErrorResponse) => onError(this.alertService, error), + }); + } else if ('attachmentUnit' in data) { + this.attachmentUnit = data.attachmentUnit; + this.attachmentUnitSub = this.attachmentUnitService.getAttachmentFile(this.course!.id!, this.attachmentUnit!.id!).subscribe({ + next: (blob: Blob) => this.loadPdf(URL.createObjectURL(blob)), + error: (error: HttpErrorResponse) => onError(this.alertService, error), + }); + } + }); + } + + ngOnDestroy() { + this.attachmentSub?.unsubscribe(); + this.attachmentUnitSub?.unsubscribe(); + } + + /** + * Handles keyboard events for navigation within the PDF viewer. + * @param event The keyboard event captured. + */ + @HostListener('document:keydown', ['$event']) + handleKeyboardEvents(event: KeyboardEvent) { + if (this.isEnlargedView) { + if (event.key === 'ArrowRight' && this.currentPage < this.totalPages) { + this.navigatePages('next'); + } else if (event.key === 'ArrowLeft' && this.currentPage > 1) { + this.navigatePages('prev'); + } + } + } + + /** + * Adjusts the canvas size based on the window resize event to ensure proper display. + */ + @HostListener('window:resize') + resizeCanvasBasedOnContainer() { + this.adjustCanvasSize(); + } + + /** + * Loads a PDF from a provided URL and initializes viewer setup. + * @param fileUrl The URL of the file to load. + */ + async loadPdf(fileUrl: string) { + try { + const loadingTask = PDFJS.getDocument(fileUrl); + const pdf = await loadingTask.promise; + this.totalPages = pdf.numPages; + + for (let i = 1; i <= pdf.numPages; i++) { + const page = await pdf.getPage(i); + const viewport = page.getViewport({ scale: 2 }); + const canvas = this.createCanvas(viewport); + const context = canvas.getContext('2d'); + if (context) { + await page.render({ canvasContext: context, viewport }).promise; + } + + const container = this.createContainer(canvas, i); + this.pdfContainer.nativeElement.appendChild(container); + } + + URL.revokeObjectURL(fileUrl); + } catch (error) { + onError(this.alertService, error); + } + } + + /** + * Creates a canvas for each page of the PDF to allow for individual page rendering. + * @param viewport The viewport settings used for rendering the page. + * @returns A new HTMLCanvasElement configured for the PDF page. + */ + private createCanvas(viewport: PDFJS.PageViewport): HTMLCanvasElement { + const canvas = document.createElement('canvas'); + /* Canvas styling is predefined because Canvas tags do not support CSS classes + * as they are not HTML elements but rather a bitmap drawing surface. + * See: https://stackoverflow.com/a/29675448 + * */ + canvas.height = viewport.height; + canvas.width = viewport.width; + const fixedWidth = this.DEFAULT_SLIDE_WIDTH; + const scaleFactor = fixedWidth / viewport.width; + canvas.style.width = `${fixedWidth}px`; + canvas.style.height = `${viewport.height * scaleFactor}px`; + return canvas; + } + + /** + * Creates a container div for each canvas, facilitating layering and interaction. + * @param canvas The canvas element that displays a PDF page. + * @param pageIndex The index of the page within the PDF document. + * @returns A configured div element that includes the canvas and interactive overlays. + */ + createContainer(canvas: HTMLCanvasElement, pageIndex: number): HTMLDivElement { + const container = document.createElement('div'); + /* Dynamically created elements are not detected by DOM, that is why we need to set the styles manually. + * See: https://stackoverflow.com/a/70911189 + */ + container.classList.add('pdf-page-container'); + container.style.cssText = `position: relative; display: inline-block; width: ${canvas.style.width}; height: ${canvas.style.height}; margin: 20px; box-shadow: 0 2px 6px var(--pdf-preview-canvas-shadow);`; + + const overlay = this.createOverlay(pageIndex); + container.appendChild(canvas); + container.appendChild(overlay); + + container.addEventListener('mouseenter', () => { + overlay.style.opacity = '1'; + }); + container.addEventListener('mouseleave', () => { + overlay.style.opacity = '0'; + }); + overlay.addEventListener('click', () => this.displayEnlargedCanvas(canvas, pageIndex)); + + return container; + } + + /** + * Generates an interactive overlay for each PDF page to allow for user interactions. + * @param pageIndex The index of the page. + * @returns A div element styled as an overlay. + */ + private createOverlay(pageIndex: number): HTMLDivElement { + const overlay = document.createElement('div'); + overlay.innerHTML = `${pageIndex}`; + /* Dynamically created elements are not detected by DOM, that is why we need to set the styles manually. + * See: https://stackoverflow.com/a/70911189 + */ + overlay.style.cssText = `position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; font-size: 24px; color: white; z-index: 1; transition: opacity 0.3s ease; opacity: 0; cursor: pointer; background-color: var(--pdf-preview-container-overlay)`; + return overlay; + } + + /** + * Dynamically updates the canvas size within an enlarged view based on the viewport. + */ + adjustCanvasSize = () => { + if (this.isEnlargedView) { + const canvasElements = this.pdfContainer.nativeElement.querySelectorAll('.pdf-page-container canvas'); + if (this.currentPage - 1 < canvasElements.length) { + const canvas = canvasElements[this.currentPage - 1] as HTMLCanvasElement; + this.updateEnlargedCanvas(canvas); + } + } + }; + + /** + * Displays a canvas in an enlarged view for detailed examination. + * @param originalCanvas The original canvas element displaying the page. + * @param pageIndex The index of the page being displayed. + */ + displayEnlargedCanvas(originalCanvas: HTMLCanvasElement, pageIndex: number) { + this.isEnlargedView = true; + this.currentPage = pageIndex; + this.updateEnlargedCanvas(originalCanvas); + this.toggleBodyScroll(true); + } + /** + * Updates the enlarged canvas dimensions to optimize PDF page display within the current viewport. + * This method dynamically adjusts the size, position, and scale of the canvas to maintain the aspect ratio, + * ensuring the content is centered and displayed appropriately within the available space. + * It is called within an animation frame to synchronize updates with the browser's render cycle for smooth visuals. + * + * @param {HTMLCanvasElement} originalCanvas - The source canvas element used to extract image data for resizing and redrawing. + */ + updateEnlargedCanvas(originalCanvas: HTMLCanvasElement) { + requestAnimationFrame(() => { + if (!this.isEnlargedView) return; + + const scaleFactor = this.calculateScaleFactor(originalCanvas); + this.resizeCanvas(originalCanvas, scaleFactor); + this.redrawCanvas(originalCanvas); + this.positionCanvas(); + }); + } + + /** + * Calculates the scaling factor to adjust the canvas size based on the dimensions of the container. + * This method ensures that the canvas is scaled to fit within the container without altering the aspect ratio. + * + * @param {HTMLCanvasElement} originalCanvas - The original canvas element representing the PDF page. + * @returns {number} The scaling factor used to resize the original canvas to fit within the container dimensions. + */ + calculateScaleFactor(originalCanvas: HTMLCanvasElement): number { + const containerWidth = this.pdfContainer.nativeElement.clientWidth; + const containerHeight = this.pdfContainer.nativeElement.clientHeight; + const scaleX = containerWidth / originalCanvas.width; + const scaleY = containerHeight / originalCanvas.height; + return Math.min(scaleX, scaleY); + } + + /** + * Resizes the canvas according to the computed scale factor. + * This method updates the dimensions of the enlarged canvas element to ensure that the entire PDF page + * is visible and properly scaled within the viewer. + * + * @param {HTMLCanvasElement} originalCanvas - The canvas element from which the image is scaled. + * @param {number} scaleFactor - The factor by which the canvas is resized. + */ + resizeCanvas(originalCanvas: HTMLCanvasElement, scaleFactor: number): void { + const enlargedCanvas = this.enlargedCanvas.nativeElement; + enlargedCanvas.width = originalCanvas.width * scaleFactor; + enlargedCanvas.height = originalCanvas.height * scaleFactor; + } + + /** + * Redraws the original canvas content onto the enlarged canvas at the updated scale. + * This method ensures that the image is rendered clearly and correctly positioned on the enlarged canvas. + * + * @param {HTMLCanvasElement} originalCanvas - The original canvas containing the image to be redrawn. + */ + redrawCanvas(originalCanvas: HTMLCanvasElement): void { + const enlargedCanvas = this.enlargedCanvas.nativeElement; + const context = enlargedCanvas.getContext('2d'); + if (context) { + context.clearRect(0, 0, enlargedCanvas.width, enlargedCanvas.height); + context.drawImage(originalCanvas, 0, 0, enlargedCanvas.width, enlargedCanvas.height); + } + } + + /** + * Adjusts the position of the enlarged canvas to center it within the viewport of the PDF container. + * This method ensures that the canvas is both vertically and horizontally centered, providing a consistent + * and visually appealing layout. + */ + positionCanvas(): void { + const enlargedCanvas = this.enlargedCanvas.nativeElement; + const containerWidth = this.pdfContainer.nativeElement.clientWidth; + const containerHeight = this.pdfContainer.nativeElement.clientHeight; + + enlargedCanvas.style.position = 'absolute'; + enlargedCanvas.style.left = `${(containerWidth - enlargedCanvas.width) / 2}px`; + enlargedCanvas.style.top = `${(containerHeight - enlargedCanvas.height) / 2}px`; + enlargedCanvas.parentElement!.style.top = `${this.pdfContainer.nativeElement.scrollTop}px`; + } + + /** + * Closes the enlarged view of the PDF and re-enables scrolling in the PDF container. + */ + closeEnlargedView(event: MouseEvent) { + this.isEnlargedView = false; + this.toggleBodyScroll(false); + event.stopPropagation(); + } + + /** + * Toggles the ability to scroll through the PDF container. + * @param disable A boolean flag indicating whether scrolling should be disabled (`true`) or enabled (`false`). + */ + toggleBodyScroll(disable: boolean): void { + this.pdfContainer.nativeElement.style.overflow = disable ? 'hidden' : 'auto'; + } + + /** + * Closes the enlarged view if a click event occurs outside the actual canvas area but within the enlarged container. + * @param event The mouse event captured, used to determine the location of the click. + */ + closeIfOutside(event: MouseEvent): void { + const target = event.target as HTMLElement; + const enlargedCanvas = this.enlargedCanvas.nativeElement; + + if (target.classList.contains('enlarged-container') && target !== enlargedCanvas) { + this.closeEnlargedView(event); + } + } + + /** + * Handles navigation between PDF pages and stops event propagation to prevent unwanted side effects. + * @param direction The direction to navigate. + * @param event The MouseEvent to be stopped. + */ + handleNavigation(direction: NavigationDirection, event: MouseEvent): void { + event.stopPropagation(); + this.navigatePages(direction); + } + + /** + * Navigates to a specific page in the PDF based on the direction relative to the current page. + * @param direction The navigation direction (next or previous). + */ + navigatePages(direction: NavigationDirection) { + const nextPageIndex = direction === 'next' ? this.currentPage + 1 : this.currentPage - 1; + if (nextPageIndex > 0 && nextPageIndex <= this.totalPages) { + this.currentPage = nextPageIndex; + const canvas = this.pdfContainer.nativeElement.querySelectorAll('.pdf-page-container canvas')[this.currentPage - 1] as HTMLCanvasElement; + this.updateEnlargedCanvas(canvas); + } + } +} diff --git a/src/main/webapp/app/shared/layouts/navbar/navbar.component.ts b/src/main/webapp/app/shared/layouts/navbar/navbar.component.ts index b24b25a4b64d..14cc8732f244 100644 --- a/src/main/webapp/app/shared/layouts/navbar/navbar.component.ts +++ b/src/main/webapp/app/shared/layouts/navbar/navbar.component.ts @@ -532,6 +532,9 @@ export class NavbarComponent implements OnInit, OnDestroy { // Special case: Don't display the ID here but the name directly (clicking the ID wouldn't work) this.addTranslationAsCrumb(currentPath, 'example-submission-editor'); break; + case 'attachments': + this.addBreadcrumb(currentPath, segment, false); + break; // No breadcrumbs for those segments case 'competency-management': case 'prerequisite-management': diff --git a/src/main/webapp/content/scss/themes/_dark-variables.scss b/src/main/webapp/content/scss/themes/_dark-variables.scss index fe7182454138..b972c760771a 100644 --- a/src/main/webapp/content/scss/themes/_dark-variables.scss +++ b/src/main/webapp/content/scss/themes/_dark-variables.scss @@ -317,6 +317,12 @@ $stat-av-sc-legend-critical: rgba(204, 0, 0, 1); $stat-av-sc-legend-median: rgba(127, 127, 127, 255); $stat-av-sc-legend-best: rgba(40, 164, 40, 1); +// Component: pdf-preview.component.scss +$pdf-preview-pdf-container-shadow: scale-color($black, $alpha: -90%); +$pdf-preview-canvas-shadow: scale-color($white, $alpha: -40%); +$pdf-preview-container-overlay: scale-color($black, $alpha: -60%); +$pdf-preview-enlarged-container-overlay: scale-color($black, $alpha: -20%); + // Programming Exercise Update $update-programming-exercise-plan-preview-box-background: transparentize(#fff, 0.95); diff --git a/src/main/webapp/content/scss/themes/_default-variables.scss b/src/main/webapp/content/scss/themes/_default-variables.scss index a0c05c0c757f..4490f3ad7ac4 100644 --- a/src/main/webapp/content/scss/themes/_default-variables.scss +++ b/src/main/webapp/content/scss/themes/_default-variables.scss @@ -242,6 +242,12 @@ $stat-av-sc-legend-critical: rgba(204, 0, 0, 1); $stat-av-sc-legend-median: rgba(127, 127, 127, 255); $stat-av-sc-legend-best: rgba(40, 164, 40, 1); +// Component: pdf-preview.component.scss +$pdf-preview-pdf-container-shadow: scale-color($black, $alpha: -90%); +$pdf-preview-canvas-shadow: scale-color($black, $alpha: -90%); +$pdf-preview-container-overlay: scale-color($black, $alpha: -60%); +$pdf-preview-enlarged-container-overlay: scale-color($black, $alpha: -80%); + // Programming Exercise Update $update-programming-exercise-plan-preview-box-background: transparentize(black, 0.95); diff --git a/src/main/webapp/i18n/de/lecture.json b/src/main/webapp/i18n/de/lecture.json index 61e68defd8e9..c5d76e7c292d 100644 --- a/src/main/webapp/i18n/de/lecture.json +++ b/src/main/webapp/i18n/de/lecture.json @@ -96,7 +96,12 @@ "deleteQuestion": "Soll der Anhang wirklich gelöscht werden?", "created": "Anhang erstellt mit ID {{ param }}", "updated": "Anhang aktualisiert mit ID {{ param }}", - "deleted": "Anhang gelöscht mit ID {{ param }}" + "deleted": "Anhang gelöscht mit ID {{ param }}", + "pdfPreview": { + "title": "Anhang", + "attachmentIDError": "Ungültiger Anhang oder ungültige Anhangs-ID.", + "attachmentUnitIDError": "Ungültige Dateieinheit oder ungültige Dateieinheits-ID." + } } } } diff --git a/src/main/webapp/i18n/en/lecture.json b/src/main/webapp/i18n/en/lecture.json index bb8ddb7ad737..b03b840b400f 100644 --- a/src/main/webapp/i18n/en/lecture.json +++ b/src/main/webapp/i18n/en/lecture.json @@ -96,7 +96,12 @@ "deleteQuestion": "Do you really want to delete the attachment?", "created": "Created new attachment with identifier {{ param }}", "updated": "Updated attachment with identifier {{ param }}", - "deleted": "Deleted attachment with identifier {{ param }}" + "deleted": "Deleted attachment with identifier {{ param }}", + "pdfPreview": { + "title": "Attachment", + "attachmentIDError": "Invalid Attachment or Attachment ID.", + "attachmentUnitIDError": "Invalid Attachment Unit or Attachment Unit ID." + } } } } diff --git a/src/test/java/de/tum/in/www1/artemis/FileIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/FileIntegrationTest.java index 13dee755daa6..fb2ad2dec51d 100644 --- a/src/test/java/de/tum/in/www1/artemis/FileIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/FileIntegrationTest.java @@ -68,7 +68,7 @@ class FileIntegrationTest extends AbstractSpringIntegrationIndependentTest { @BeforeEach void initTestCase() { - userUtilService.addUsers(TEST_PREFIX, 1, 1, 0, 1); + userUtilService.addUsers(TEST_PREFIX, 1, 1, 1, 1); } @Test @@ -307,4 +307,41 @@ private AttachmentUnit uploadAttachmentUnit(Lecture lecture, MockMultipartFile f AttachmentUnit.class, expectedStatus); } + @Test + @WithMockUser(username = TEST_PREFIX + "editor1", roles = "EDITOR") + void testGetAttachmentFileAsEditor() throws Exception { + Lecture lecture = lectureUtilService.createCourseWithLecture(true); + + Attachment attachment = LectureFactory.generateAttachmentWithFile(ZonedDateTime.now(), lecture.getId(), false); + attachment.setId(1L); + attachment.setLecture(lecture); + + Long courseId = lecture.getCourse().getId(); + Long attachmentId = attachment.getId(); + + lectureRepo.save(lecture); + attachmentRepo.save(attachment); + + request.get("/api/files/courses/" + courseId + "/attachments/" + attachmentId, HttpStatus.OK, byte[].class); + } + + @Test + @WithMockUser(username = TEST_PREFIX + "editor1", roles = "EDITOR") + void testGetAttachmentUnitFileAsEditor() throws Exception { + Lecture lecture = lectureUtilService.createCourseWithLecture(true); + + AttachmentUnit attachmentUnit = lectureUtilService.createAttachmentUnit(true); + attachmentUnit.setLecture(lecture); + Attachment attachment = attachmentUnit.getAttachment(); + + lectureRepo.save(lecture); + attachmentRepo.save(attachment); + attachmentUnitRepo.save(attachmentUnit); + + Long courseId = lecture.getCourse().getId(); + Long attachmentUnitId = attachmentUnit.getId(); + + request.get("/api/files/courses/" + courseId + "/attachment-units/" + attachmentUnitId, HttpStatus.OK, byte[].class); + } + } diff --git a/src/test/javascript/spec/component/lecture-unit/attachment-unit/attachment-unit.service.spec.ts b/src/test/javascript/spec/component/lecture-unit/attachment-unit/attachment-unit.service.spec.ts index 765d4e646a7e..504f8ffd3903 100644 --- a/src/test/javascript/spec/component/lecture-unit/attachment-unit/attachment-unit.service.spec.ts +++ b/src/test/javascript/spec/component/lecture-unit/attachment-unit/attachment-unit.service.spec.ts @@ -199,4 +199,23 @@ describe('AttachmentUnitService', () => { expect(response.body).toEqual(expected); })); + + describe('getAttachmentFile', () => { + it('should retrieve a file as Blob for a given course and attachment unit ID', () => { + const courseId = 5; + const attachmentUnitId = 10; + const expectedBlob = new Blob(['example data'], { type: 'application/pdf' }); + + service.getAttachmentFile(courseId, attachmentUnitId).subscribe((response) => { + expect(response).toEqual(expectedBlob); + }); + + const req = httpMock.expectOne({ + url: `api/files/courses/${courseId}/attachment-units/${attachmentUnitId}`, + method: 'GET', + }); + expect(req.request.responseType).toBe('blob'); + req.flush(expectedBlob); + }); + }); }); diff --git a/src/test/javascript/spec/component/lecture-unit/lecture-unit-management.component.spec.ts b/src/test/javascript/spec/component/lecture-unit/lecture-unit-management.component.spec.ts index 07fdcc72f02e..bad4cf68f981 100644 --- a/src/test/javascript/spec/component/lecture-unit/lecture-unit-management.component.spec.ts +++ b/src/test/javascript/spec/component/lecture-unit/lecture-unit-management.component.spec.ts @@ -28,7 +28,7 @@ import { Competency } from 'app/entities/competency.model'; import { UnitCreationCardComponent } from 'app/lecture/lecture-unit/lecture-unit-management/unit-creation-card/unit-creation-card.component'; import { ArtemisDatePipe } from 'app/shared/pipes/artemis-date.pipe'; import { MockRouterLinkDirective } from '../../helpers/mocks/directive/mock-router-link.directive'; -import { LectureUnit } from 'app/entities/lecture-unit/lectureUnit.model'; +import { LectureUnit, LectureUnitType } from 'app/entities/lecture-unit/lectureUnit.model'; import { CdkDragDrop } from '@angular/cdk/drag-drop'; import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap'; import { OnlineUnit } from 'app/entities/lecture-unit/onlineUnit.model'; @@ -169,6 +169,14 @@ describe('LectureUnitManagementComponent', () => { expect(lectureUnitManagementComponent.getDeleteQuestionKey(new OnlineUnit())).toBe('artemisApp.onlineUnit.delete.question'); }); + it('should return default question translation key for unhandled types', () => { + const mockUnit = { + type: null, + }; + + expect(lectureUnitManagementComponent.getDeleteQuestionKey(mockUnit as unknown as LectureUnit)).toBe(''); + }); + it('should give the correct confirmation text translation key', () => { expect(lectureUnitManagementComponent.getDeleteConfirmationTextKey(new AttachmentUnit())).toBe('artemisApp.attachmentUnit.delete.typeNameToConfirm'); expect(lectureUnitManagementComponent.getDeleteConfirmationTextKey(new ExerciseUnit())).toBe('artemisApp.exerciseUnit.delete.typeNameToConfirm'); @@ -177,6 +185,14 @@ describe('LectureUnitManagementComponent', () => { expect(lectureUnitManagementComponent.getDeleteConfirmationTextKey(new OnlineUnit())).toBe('artemisApp.onlineUnit.delete.typeNameToConfirm'); }); + it('should return default confirmation text translation key for unhandled types', () => { + const mockUnit = { + type: null, + }; + + expect(lectureUnitManagementComponent.getDeleteConfirmationTextKey(mockUnit as unknown as LectureUnit)).toBe(''); + }); + it('should give the correct action type', () => { expect(lectureUnitManagementComponent.getActionType(new AttachmentUnit())).toEqual(ActionType.Delete); expect(lectureUnitManagementComponent.getActionType(new ExerciseUnit())).toEqual(ActionType.Unlink); @@ -184,4 +200,29 @@ describe('LectureUnitManagementComponent', () => { expect(lectureUnitManagementComponent.getActionType(new VideoUnit())).toEqual(ActionType.Delete); expect(lectureUnitManagementComponent.getActionType(new OnlineUnit())).toEqual(ActionType.Delete); }); + + describe('isViewButtonAvailable', () => { + it('should return true for an attachment unit with a PDF link', () => { + const lectureUnit = { + type: LectureUnitType.ATTACHMENT, + attachment: { link: 'file.pdf' }, + } as LectureUnit; + expect(lectureUnitManagementComponent.isViewButtonAvailable(lectureUnit)).toBeTrue(); + }); + + it('should return false for file extension different than .pdf', () => { + const lectureUnit = { + type: LectureUnitType.ATTACHMENT, + attachment: { link: 'file.txt' }, + }; + expect(lectureUnitManagementComponent.isViewButtonAvailable(lectureUnit)).toBeFalse(); + }); + + it('should return false for a text unit', () => { + const lectureUnit = { + type: LectureUnitType.TEXT, + }; + expect(lectureUnitManagementComponent.isViewButtonAvailable(lectureUnit)).toBeFalse(); + }); + }); }); diff --git a/src/test/javascript/spec/component/lecture/lecture-attachments.component.spec.ts b/src/test/javascript/spec/component/lecture/lecture-attachments.component.spec.ts index 773142efa909..72bab398d1f1 100644 --- a/src/test/javascript/spec/component/lecture/lecture-attachments.component.spec.ts +++ b/src/test/javascript/spec/component/lecture/lecture-attachments.component.spec.ts @@ -20,6 +20,7 @@ import { of, take, throwError } from 'rxjs'; import { HttpResponse } from '@angular/common/http'; import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap'; import { LectureService } from 'app/lecture/lecture.service'; +import { RouterModule } from '@angular/router'; describe('LectureAttachmentsComponent', () => { let comp: LectureAttachmentsComponent; @@ -84,7 +85,7 @@ describe('LectureAttachmentsComponent', () => { beforeEach(() => { return TestBed.configureTestingModule({ - imports: [ArtemisTestModule, MockDirective(NgbTooltip)], + imports: [ArtemisTestModule, MockDirective(NgbTooltip), RouterModule], declarations: [ LectureAttachmentsComponent, MockComponent(FormDateTimePickerComponent), @@ -154,7 +155,7 @@ describe('LectureAttachmentsComponent', () => { fixture.detectChanges(); tick(); expect(comp.attachments).toHaveLength(3); - expect(attachmentServiceFindAllByLectureIdStub).toHaveBeenCalledOnce(); + expect(attachmentServiceFindAllByLectureIdStub).toHaveBeenCalledTimes(2); })); it('should not accept too large file', fakeAsync(() => { @@ -379,4 +380,21 @@ describe('LectureAttachmentsComponent', () => { expect(comp.attachmentToBeCreated.link).toBe(myBlob1.name); expect(attachmentServiceFindAllByLectureIdStub).toHaveBeenCalledOnce(); })); + + describe('isViewButtonAvailable', () => { + it('should return true if the attachment link ends with .pdf', () => { + const attachment = { id: 1, link: 'example.pdf', attachmentType: 'FILE' } as Attachment; + expect(comp.isViewButtonAvailable(attachment.link!)).toBeTrue(); + }); + + it('should return false if the attachment link does not end with .pdf', () => { + const attachment = { id: 2, link: 'example.txt', attachmentType: 'FILE' } as Attachment; + expect(comp.isViewButtonAvailable(attachment.link!)).toBeFalse(); + }); + + it.each([['document.docx'], ['spreadsheet.xlsx'], ['presentation.pptx'], ['image.jpeg']])('should return false for common file extension %s', (link) => { + const attachment = { link }; + expect(comp.isViewButtonAvailable(attachment.link)).toBeFalse(); + }); + }); }); diff --git a/src/test/javascript/spec/component/lecture/pdf-preview.component.spec.ts b/src/test/javascript/spec/component/lecture/pdf-preview.component.spec.ts new file mode 100644 index 000000000000..03e494ccbd41 --- /dev/null +++ b/src/test/javascript/spec/component/lecture/pdf-preview.component.spec.ts @@ -0,0 +1,437 @@ +import { MockTranslateService } from '../../helpers/mocks/service/mock-translate.service'; + +jest.mock('pdfjs-dist', () => { + return { + getDocument: jest.fn(() => ({ + promise: Promise.resolve({ + numPages: 1, + getPage: jest.fn(() => + Promise.resolve({ + getViewport: jest.fn(() => ({ width: 600, height: 800, scale: 1 })), + render: jest.fn(() => ({ + promise: Promise.resolve(), + })), + }), + ), + }), + })), + }; +}); + +jest.mock('pdfjs-dist/build/pdf.worker', () => { + return {}; +}); + +function createMockEvent(target: Element, eventType = 'click'): MouseEvent { + const event = new MouseEvent(eventType, { + view: window, + bubbles: true, + cancelable: true, + }); + Object.defineProperty(event, 'target', { value: target, writable: false }); + return event; +} + +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ActivatedRoute } from '@angular/router'; +import { of, throwError } from 'rxjs'; +import { AttachmentService } from 'app/lecture/attachment.service'; +import { AttachmentUnitService } from 'app/lecture/lecture-unit/lecture-unit-management/attachmentUnit.service'; +import { PdfPreviewComponent } from 'app/lecture/pdf-preview/pdf-preview.component'; +import { ElementRef } from '@angular/core'; +import { AlertService } from 'app/core/util/alert.service'; +import { HttpErrorResponse } from '@angular/common/http'; +import { TranslateService } from '@ngx-translate/core'; + +describe('PdfPreviewComponent', () => { + let component: PdfPreviewComponent; + let fixture: ComponentFixture; + let attachmentServiceMock: any; + let attachmentUnitServiceMock: any; + let alertServiceMock: any; + let routeMock: any; + let mockCanvasElement: HTMLCanvasElement; + let mockEnlargedCanvas: HTMLCanvasElement; + let mockContext: any; + let mockOverlay: HTMLDivElement; + + beforeEach(async () => { + global.URL.createObjectURL = jest.fn().mockReturnValue('mocked_blob_url'); + attachmentServiceMock = { + getAttachmentFile: jest.fn().mockReturnValue(of(new Blob([''], { type: 'application/pdf' }))), + }; + attachmentUnitServiceMock = { + getAttachmentFile: jest.fn().mockReturnValue(of(new Blob([''], { type: 'application/pdf' }))), + }; + routeMock = { + data: of({ + course: { id: 1, name: 'Example Course' }, + attachment: { id: 1, name: 'Example PDF' }, + attachmentUnit: { id: 1, name: 'Chapter 1' }, + }), + }; + alertServiceMock = { + addAlert: jest.fn(), + error: jest.fn(), + }; + + await TestBed.configureTestingModule({ + imports: [PdfPreviewComponent], + providers: [ + { provide: ActivatedRoute, useValue: routeMock }, + { provide: AttachmentService, useValue: attachmentServiceMock }, + { provide: AttachmentUnitService, useValue: attachmentUnitServiceMock }, + { provide: AlertService, useValue: alertServiceMock }, + { provide: TranslateService, useClass: MockTranslateService }, + ], + }).compileComponents(); + + const pdfContainerElement = document.createElement('div'); + Object.defineProperty(pdfContainerElement, 'clientWidth', { value: 800 }); + Object.defineProperty(pdfContainerElement, 'clientHeight', { value: 600 }); + + fixture = TestBed.createComponent(PdfPreviewComponent); + component = fixture.componentInstance; + + mockCanvasElement = document.createElement('canvas'); + mockCanvasElement.width = 800; + mockCanvasElement.height = 600; + + jest.spyOn(component, 'updateEnlargedCanvas').mockImplementation(() => { + component.enlargedCanvas.nativeElement = mockCanvasElement; + }); + + mockEnlargedCanvas = document.createElement('canvas'); + mockEnlargedCanvas.classList.add('enlarged-canvas'); + component.enlargedCanvas = new ElementRef(mockEnlargedCanvas); + + mockContext = { + clearRect: jest.fn(), + drawImage: jest.fn(), + } as unknown as CanvasRenderingContext2D; + jest.spyOn(mockCanvasElement, 'getContext').mockReturnValue(mockContext); + + jest.spyOn(window, 'requestAnimationFrame').mockImplementation((cb: FrameRequestCallback) => { + cb(0); + return 0; + }); + mockOverlay = document.createElement('div'); + mockOverlay.style.opacity = '0'; + mockCanvasElement.appendChild(mockOverlay); + + fixture.detectChanges(); + + component.pdfContainer = new ElementRef(document.createElement('div')); + component.enlargedCanvas = new ElementRef(document.createElement('canvas')); + fixture.detectChanges(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should load attachment file and verify service calls when attachment data is available', () => { + component.ngOnInit(); + expect(attachmentServiceMock.getAttachmentFile).toHaveBeenCalledWith(1, 1); + expect(attachmentUnitServiceMock.getAttachmentFile).not.toHaveBeenCalled(); + }); + + it('should load attachment unit file and verify service calls when attachment unit data is available', () => { + routeMock.data = of({ + course: { id: 1, name: 'Example Course' }, + attachmentUnit: { id: 1, name: 'Chapter 1' }, + }); + component.ngOnInit(); + expect(attachmentUnitServiceMock.getAttachmentFile).toHaveBeenCalledWith(1, 1); + expect(attachmentServiceMock.getAttachmentFile).toHaveBeenCalled(); + }); + + it('should handle errors and trigger alert when loading an attachment file fails', () => { + const errorResponse = new HttpErrorResponse({ + status: 404, + statusText: 'Not Found', + error: 'File not found', + }); + + const attachmentService = TestBed.inject(AttachmentService); + jest.spyOn(attachmentService, 'getAttachmentFile').mockReturnValue(throwError(() => errorResponse)); + const alertServiceSpy = jest.spyOn(alertServiceMock, 'error'); + + component.ngOnInit(); + fixture.detectChanges(); + + expect(alertServiceSpy).toHaveBeenCalledOnce(); + }); + + it('should handle errors and trigger alert when loading an attachment unit file fails', () => { + routeMock.data = of({ + course: { id: 1, name: 'Example Course' }, + attachmentUnit: { id: 1, name: 'Chapter 1' }, + }); + const errorResponse = new HttpErrorResponse({ + status: 404, + statusText: 'Not Found', + error: 'File not found', + }); + + const attachmentUnitService = TestBed.inject(AttachmentUnitService); + jest.spyOn(attachmentUnitService, 'getAttachmentFile').mockReturnValue(throwError(() => errorResponse)); + const alertServiceSpy = jest.spyOn(alertServiceMock, 'error'); + + component.ngOnInit(); + fixture.detectChanges(); + + expect(alertServiceSpy).toHaveBeenCalledOnce(); + }); + + it('should load PDF and verify rendering of pages', () => { + const mockBlob = new Blob(['PDF content'], { type: 'application/pdf' }); + + attachmentServiceMock.getAttachmentFile.mockReturnValue(of(mockBlob)); + component.ngOnInit(); + + expect(URL.createObjectURL).toHaveBeenCalledWith(mockBlob); + expect(attachmentServiceMock.getAttachmentFile).toHaveBeenCalledWith(1, 1); + expect(component.totalPages).toBeGreaterThan(0); + }); + + it('should navigate through pages using keyboard in enlarged view', () => { + component.isEnlargedView = true; + component.totalPages = 5; + component.currentPage = 3; + + const eventRight = new KeyboardEvent('keydown', { key: 'ArrowRight' }); + const eventLeft = new KeyboardEvent('keydown', { key: 'ArrowLeft' }); + + component.handleKeyboardEvents(eventRight); + expect(component.currentPage).toBe(4); + + component.handleKeyboardEvents(eventLeft); + expect(component.currentPage).toBe(3); + }); + + it('should toggle enlarged view state', () => { + const mockCanvas = document.createElement('canvas'); + component.displayEnlargedCanvas(mockCanvas, 1); + expect(component.isEnlargedView).toBeTrue(); + + const clickEvent = new MouseEvent('click', { + button: 0, + }); + + component.closeEnlargedView(clickEvent); + expect(component.isEnlargedView).toBeFalse(); + }); + + it('should prevent scrolling when enlarged view is active', () => { + component.toggleBodyScroll(true); + expect(component.pdfContainer.nativeElement.style.overflow).toBe('hidden'); + + component.toggleBodyScroll(false); + expect(component.pdfContainer.nativeElement.style.overflow).toBe('auto'); + }); + + it('should not update canvas size if not in enlarged view', () => { + component.isEnlargedView = false; + component.currentPage = 3; + + const spy = jest.spyOn(component, 'updateEnlargedCanvas'); + component.adjustCanvasSize(); + + expect(spy).not.toHaveBeenCalled(); + }); + + it('should not update canvas size if the current page canvas does not exist', () => { + component.isEnlargedView = true; + component.currentPage = 10; + + const spy = jest.spyOn(component, 'updateEnlargedCanvas'); + component.adjustCanvasSize(); + + expect(spy).not.toHaveBeenCalled(); + }); + + it('should prevent navigation beyond last page', () => { + component.currentPage = component.totalPages = 5; + component.handleKeyboardEvents(new KeyboardEvent('keydown', { key: 'ArrowRight' })); + + expect(component.currentPage).toBe(5); + }); + + it('should prevent navigation before first page', () => { + component.currentPage = 1; + component.handleKeyboardEvents(new KeyboardEvent('keydown', { key: 'ArrowLeft' })); + + expect(component.currentPage).toBe(1); + }); + + it('should unsubscribe attachment subscription during component destruction', () => { + const spySub = jest.spyOn(component.attachmentSub, 'unsubscribe'); + component.ngOnDestroy(); + expect(spySub).toHaveBeenCalled(); + }); + + it('should unsubscribe attachmentUnit subscription during component destruction', () => { + routeMock.data = of({ + course: { id: 1, name: 'Example Course' }, + attachmentUnit: { id: 1, name: 'Chapter 1' }, + }); + component.ngOnInit(); + fixture.detectChanges(); + expect(component.attachmentUnitSub).toBeDefined(); + const spySub = jest.spyOn(component.attachmentUnitSub, 'unsubscribe'); + component.ngOnDestroy(); + expect(spySub).toHaveBeenCalled(); + }); + + it('should stop event propagation and navigate pages', () => { + const navigateSpy = jest.spyOn(component, 'navigatePages'); + const eventMock = { stopPropagation: jest.fn() } as unknown as MouseEvent; + + component.handleNavigation('next', eventMock); + + expect(eventMock.stopPropagation).toHaveBeenCalled(); + expect(navigateSpy).toHaveBeenCalledWith('next'); + }); + + it('should call updateEnlargedCanvas when window is resized and conditions are met', () => { + component.isEnlargedView = true; + component.currentPage = 1; + + const canvas = document.createElement('canvas'); + const pdfContainer = document.createElement('div'); + pdfContainer.className = 'pdf-page-container'; + pdfContainer.appendChild(canvas); + component.pdfContainer = { + nativeElement: pdfContainer, + } as ElementRef; + + const updateEnlargedCanvasSpy = jest.spyOn(component, 'updateEnlargedCanvas'); + const adjustCanvasSizeSpy = jest.spyOn(component, 'adjustCanvasSize'); + + window.dispatchEvent(new Event('resize')); + expect(adjustCanvasSizeSpy).toHaveBeenCalled(); + expect(updateEnlargedCanvasSpy).toHaveBeenCalledWith(canvas); + }); + + it('should close the enlarged view if click is outside the canvas within the enlarged container', () => { + const target = document.createElement('div'); + target.classList.add('enlarged-container'); + const mockEvent = createMockEvent(target); + + component.isEnlargedView = true; + const closeSpy = jest.spyOn(component, 'closeEnlargedView'); + + component.closeIfOutside(mockEvent); + + expect(closeSpy).toHaveBeenCalled(); + expect(component.isEnlargedView).toBeFalse(); + }); + + it('should not close the enlarged view if the click is on the canvas itself', () => { + const mockEvent = createMockEvent(mockEnlargedCanvas); + Object.defineProperty(mockEvent, 'target', { value: mockEnlargedCanvas, writable: false }); + + component.isEnlargedView = true; + + const closeSpy = jest.spyOn(component, 'closeEnlargedView'); + + component.closeIfOutside(mockEvent as unknown as MouseEvent); + + expect(closeSpy).not.toHaveBeenCalled(); + }); + + it('should calculate the correct scale factor based on container and canvas dimensions', () => { + Object.defineProperty(component.pdfContainer.nativeElement, 'clientWidth', { value: 1000, configurable: true }); + Object.defineProperty(component.pdfContainer.nativeElement, 'clientHeight', { value: 800, configurable: true }); + + mockCanvasElement.width = 500; + mockCanvasElement.height = 400; + + const scaleFactor = component.calculateScaleFactor(mockCanvasElement); + expect(scaleFactor).toBe(2); + }); + + it('should resize the canvas based on the given scale factor', () => { + mockCanvasElement.width = 500; + mockCanvasElement.height = 400; + component.resizeCanvas(mockCanvasElement, 2); + + expect(component.enlargedCanvas.nativeElement.width).toBe(1000); + expect(component.enlargedCanvas.nativeElement.height).toBe(800); + }); + + it('should clear and redraw the canvas with the new dimensions', () => { + mockCanvasElement.width = 500; + mockCanvasElement.height = 400; + + jest.spyOn(mockContext, 'clearRect'); + jest.spyOn(mockContext, 'drawImage'); + + component.resizeCanvas(mockCanvasElement, 2); + component.redrawCanvas(mockCanvasElement); + + expect(component.enlargedCanvas.nativeElement.width).toBe(1000); // 500 * 2 + expect(component.enlargedCanvas.nativeElement.height).toBe(800); // 400 * 2 + + expect(mockContext.clearRect).toHaveBeenCalledWith(0, 0, 1000, 800); + expect(mockContext.drawImage).toHaveBeenCalledWith(mockCanvasElement, 0, 0, 1000, 800); + }); + + it('should correctly position the canvas', () => { + const parent = document.createElement('div'); + component.pdfContainer = { nativeElement: { clientWidth: 1000, clientHeight: 800, scrollTop: 500 } } as ElementRef; + const canvasElem = component.enlargedCanvas.nativeElement; + parent.appendChild(canvasElem); + canvasElem.width = 500; + canvasElem.height = 400; + component.positionCanvas(); + expect(canvasElem.style.left).toBe('250px'); + expect(canvasElem.style.top).toBe('200px'); + expect(parent.style.top).toBe('500px'); + }); + + it('should create a container with correct styles and children', () => { + const mockCanvas = document.createElement('canvas'); + mockCanvas.style.width = '600px'; + mockCanvas.style.height = '400px'; + + const container = component.createContainer(mockCanvas, 1); + expect(container.tagName).toBe('DIV'); + expect(container.classList.contains('pdf-page-container')).toBeTruthy(); + expect(container.style.position).toBe('relative'); + expect(container.style.display).toBe('inline-block'); + expect(container.style.width).toBe('600px'); + expect(container.style.height).toBe('400px'); + expect(container.style.margin).toBe('20px'); + expect(container.children).toHaveLength(2); + + expect(container.firstChild).toBe(mockCanvas); + }); + + it('should handle mouseenter and mouseleave events correctly', () => { + const mockCanvas = document.createElement('canvas'); + const container = component.createContainer(mockCanvas, 1); + const overlay = container.children[1] as HTMLElement; + + // Trigger mouseenter + const mouseEnterEvent = new Event('mouseenter'); + container.dispatchEvent(mouseEnterEvent); + expect(overlay.style.opacity).toBe('1'); + + // Trigger mouseleave + const mouseLeaveEvent = new Event('mouseleave'); + container.dispatchEvent(mouseLeaveEvent); + expect(overlay.style.opacity).toBe('0'); + }); + + it('should handle click event on overlay to trigger displayEnlargedCanvas', () => { + jest.spyOn(component, 'displayEnlargedCanvas'); + const mockCanvas = document.createElement('canvas'); + const container = component.createContainer(mockCanvas, 1); + const overlay = container.children[1]; + + overlay.dispatchEvent(new Event('click')); + expect(component.displayEnlargedCanvas).toHaveBeenCalledWith(mockCanvas, 1); + }); +}); diff --git a/src/test/javascript/spec/service/attachment.service.spec.ts b/src/test/javascript/spec/service/attachment.service.spec.ts index b29db559c4e9..77356f0aa445 100644 --- a/src/test/javascript/spec/service/attachment.service.spec.ts +++ b/src/test/javascript/spec/service/attachment.service.spec.ts @@ -145,4 +145,23 @@ describe('Attachment Service', () => { expect(results).toEqual(elemDefault); }); }); + + describe('getAttachmentFile', () => { + it('should retrieve a file as Blob for a given course and attachment ID', () => { + const courseId = 1; + const attachmentId = 100; + const expectedBlob = new Blob(['dummy content'], { type: 'application/pdf' }); + + service.getAttachmentFile(courseId, attachmentId).subscribe((resp) => { + expect(resp).toEqual(expectedBlob); + }); + + const req = httpMock.expectOne({ + url: `api/files/courses/${courseId}/attachments/${attachmentId}`, + method: 'GET', + }); + expect(req.request.responseType).toBe('blob'); + req.flush(expectedBlob); + }); + }); }); From 903e35b8dc068d6e333aff582585e2e51c47ea0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20S=C3=B6lch?= Date: Thu, 5 Sep 2024 07:55:39 +0200 Subject: [PATCH 11/16] Development: Improve LTI authentication (#9231) --- .../config/lti/CustomLti13Configurer.java | 4 +-- .../service/connectors/lti/LtiService.java | 29 +++++++++++-------- .../artemis/connectors/LtiServiceTest.java | 8 ++--- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/main/java/de/tum/in/www1/artemis/config/lti/CustomLti13Configurer.java b/src/main/java/de/tum/in/www1/artemis/config/lti/CustomLti13Configurer.java index 73d81028276b..41662e7c3be6 100644 --- a/src/main/java/de/tum/in/www1/artemis/config/lti/CustomLti13Configurer.java +++ b/src/main/java/de/tum/in/www1/artemis/config/lti/CustomLti13Configurer.java @@ -5,9 +5,9 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.web.authentication.logout.LogoutFilter; -import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter; import org.springframework.stereotype.Component; +import de.tum.in.www1.artemis.security.jwt.JWTFilter; import de.tum.in.www1.artemis.service.OnlineCourseConfigurationService; import de.tum.in.www1.artemis.service.connectors.lti.Lti13Service; import de.tum.in.www1.artemis.web.filter.Lti13LaunchFilter; @@ -74,7 +74,7 @@ public void configure(HttpSecurity http) { // https://www.imsglobal.org/spec/security/v1p0/#step-3-authentication-response OAuth2LoginAuthenticationFilter defaultLoginFilter = configureLoginFilter(clientRegistrationRepository(http), oidcLaunchFlowAuthenticationProvider, authorizationRequestRepository); - http.addFilterAfter(new Lti13LaunchFilter(defaultLoginFilter, "/" + LTI13_LOGIN_PATH, lti13Service(http)), AbstractPreAuthenticatedProcessingFilter.class); + http.addFilterAfter(new Lti13LaunchFilter(defaultLoginFilter, "/" + LTI13_LOGIN_PATH, lti13Service(http)), JWTFilter.class); } protected Lti13Service lti13Service(HttpSecurity http) { diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/lti/LtiService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/lti/LtiService.java index bd7b778439a9..0dd67f46a739 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/lti/LtiService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/lti/LtiService.java @@ -11,6 +11,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Profile; import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseCookie; @@ -42,6 +43,9 @@ @Profile("lti") public class LtiService { + @Value("${artemis.lti.trustExternalLTISystems:false}") + private boolean trustExternalLTISystems; + public static final String LTI_GROUP_NAME = "lti"; protected static final List SIMPLE_USER_LIST_AUTHORITY = Collections.singletonList(new SimpleGrantedAuthority(Role.STUDENT.getAuthority())); @@ -105,6 +109,14 @@ public void authenticateLtiUser(String email, String username, String firstName, // 2. Case: Lookup user with the LTI email address and make sure it's not in use if (artemisAuthenticationProvider.getUsernameForEmail(email).isPresent() || userRepository.findOneByEmailIgnoreCase(email).isPresent()) { log.info("User with email {} already exists. Email is already in use.", email); + + if (trustExternalLTISystems) { + log.info("Trusting external LTI system. Authenticating user with email: {}", email); + User user = userRepository.findUserWithGroupsAndAuthoritiesByEmail(email).orElseThrow(); + SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(user.getLogin(), user.getPassword(), user.getGrantedAuthorities())); + return; + } + throw new LtiEmailAlreadyInUseException(); } @@ -179,23 +191,16 @@ private void addUserToExerciseGroup(User user, Course course) { * @param response the response to add the JWT cookie to */ public void buildLtiResponse(UriComponentsBuilder uriComponentsBuilder, HttpServletResponse response) { - // TODO SK: why do we logout the user here if it was already activated? - User user = userRepository.getUser(); if (!user.getActivated()) { - log.info("User is not activated. Adding JWT cookie for activation."); - log.info("Add JWT cookie so the user will be logged in"); - ResponseCookie responseCookie = jwtCookieService.buildLoginCookie(true); - response.addHeader(HttpHeaders.SET_COOKIE, responseCookie.toString()); - + log.info("User is not activated. Adding initialize parameter to query."); uriComponentsBuilder.queryParam("initialize", ""); } - else { - log.info("User is activated. Adding JWT cookie for logout."); - prepareLogoutCookie(response); - uriComponentsBuilder.queryParam("ltiSuccessLoginRequired", user.getLogin()); - } + + log.info("Add/Update JWT cookie so the user will be logged in."); + ResponseCookie responseCookie = jwtCookieService.buildLoginCookie(true); + response.addHeader(HttpHeaders.SET_COOKIE, responseCookie.toString()); } /** diff --git a/src/test/java/de/tum/in/www1/artemis/connectors/LtiServiceTest.java b/src/test/java/de/tum/in/www1/artemis/connectors/LtiServiceTest.java index 1097afd3a46b..effc5d69160a 100644 --- a/src/test/java/de/tum/in/www1/artemis/connectors/LtiServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/connectors/LtiServiceTest.java @@ -118,16 +118,14 @@ void addLtiQueryParamsNewUser() { verify(response).addHeader(any(), any()); String initialize = uriComponents.getQueryParams().getFirst("initialize"); - String ltiSuccessLoginRequired = uriComponents.getQueryParams().getFirst("ltiSuccessLoginRequired"); assertThat(initialize).isEmpty(); - assertThat(ltiSuccessLoginRequired).isNull(); } @Test void addLtiQueryParamsExistingUser() { when(userRepository.getUser()).thenReturn(user); user.setActivated(true); - when(jwtCookieService.buildLogoutCookie()).thenReturn(mock(ResponseCookie.class)); + when(jwtCookieService.buildLoginCookie(true)).thenReturn(mock(ResponseCookie.class)); UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.newInstance(); HttpServletResponse response = mock(HttpServletResponse.class); @@ -136,12 +134,10 @@ void addLtiQueryParamsExistingUser() { UriComponents uriComponents = uriComponentsBuilder.build(); - verify(jwtCookieService).buildLogoutCookie(); + verify(jwtCookieService).buildLoginCookie(true); verify(response).addHeader(any(), any()); String initialize = uriComponents.getQueryParams().getFirst("initialize"); - String ltiSuccessLoginRequired = uriComponents.getQueryParams().getFirst("ltiSuccessLoginRequired"); - assertThat(ltiSuccessLoginRequired).isEqualTo(user.getLogin()); assertThat(initialize).isNull(); } From 394c9f91f16a34fd006ff79e84458800398e7e32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konrad=20G=C3=B6=C3=9Fmann?= Date: Thu, 5 Sep 2024 12:31:40 +0200 Subject: [PATCH 12/16] Lectures: Remove redundant competency management from guided creation mode (#8989) --- src/main/webapp/app/lecture/lecture.module.ts | 2 - .../lecture-update-wizard-step.component.ts | 4 +- .../lecture-update-wizard.component.html | 41 +- .../lecture-update-wizard.component.ts | 37 +- ...lecture-wizard-competencies.component.html | 97 ---- ...lecture-wizard-competencies.component.scss | 14 - .../lecture-wizard-competencies.component.ts | 273 --------- .../lecture-wizard-units.component.ts | 14 +- ...ture-wizard-competencies.component.spec.ts | 518 ------------------ .../lecture-wizard-units.component.spec.ts | 109 +++- .../lecture-wizard.component.spec.ts | 46 +- 11 files changed, 154 insertions(+), 1001 deletions(-) delete mode 100644 src/main/webapp/app/lecture/wizard-mode/lecture-wizard-competencies.component.html delete mode 100644 src/main/webapp/app/lecture/wizard-mode/lecture-wizard-competencies.component.scss delete mode 100644 src/main/webapp/app/lecture/wizard-mode/lecture-wizard-competencies.component.ts delete mode 100644 src/test/javascript/spec/component/lecture/wizard-mode/lecture-wizard-competencies.component.spec.ts diff --git a/src/main/webapp/app/lecture/lecture.module.ts b/src/main/webapp/app/lecture/lecture.module.ts index 06b33f93a9ae..5cdad5fc5fa2 100644 --- a/src/main/webapp/app/lecture/lecture.module.ts +++ b/src/main/webapp/app/lecture/lecture.module.ts @@ -19,7 +19,6 @@ import { LectureUpdateWizardTitleComponent } from 'app/lecture/wizard-mode/lectu import { LectureUpdateWizardPeriodComponent } from 'app/lecture/wizard-mode/lecture-wizard-period.component'; import { LectureUpdateWizardAttachmentsComponent } from 'app/lecture/wizard-mode/lecture-wizard-attachments.component'; import { LectureUpdateWizardUnitsComponent } from 'app/lecture/wizard-mode/lecture-wizard-units.component'; -import { LectureUpdateWizardCompetenciesComponent } from 'app/lecture/wizard-mode/lecture-wizard-competencies.component'; import { LectureUpdateWizardStepComponent } from 'app/lecture/wizard-mode/lecture-update-wizard-step.component'; import { TitleChannelNameModule } from 'app/shared/form/title-channel-name/title-channel-name.module'; import { LectureTitleChannelNameComponent } from 'app/lecture/lecture-title-channel-name.component'; @@ -53,7 +52,6 @@ const ENTITY_STATES = [...lectureRoute]; LectureUpdateWizardPeriodComponent, LectureUpdateWizardAttachmentsComponent, LectureUpdateWizardUnitsComponent, - LectureUpdateWizardCompetenciesComponent, LectureUpdateWizardStepComponent, LectureTitleChannelNameComponent, ], diff --git a/src/main/webapp/app/lecture/wizard-mode/lecture-update-wizard-step.component.ts b/src/main/webapp/app/lecture/wizard-mode/lecture-update-wizard-step.component.ts index 3827abac634f..9c8d6973a233 100644 --- a/src/main/webapp/app/lecture/wizard-mode/lecture-update-wizard-step.component.ts +++ b/src/main/webapp/app/lecture/wizard-mode/lecture-update-wizard-step.component.ts @@ -19,6 +19,6 @@ export class LectureUpdateWizardStepComponent { @Input() descriptionTranslationKey: string; - faCheck = faCheck; - faDotCircle = faDotCircle; + protected readonly faCheck = faCheck; + protected readonly faDotCircle = faDotCircle; } diff --git a/src/main/webapp/app/lecture/wizard-mode/lecture-update-wizard.component.html b/src/main/webapp/app/lecture/wizard-mode/lecture-update-wizard.component.html index 71a77421d145..cb704901206e 100644 --- a/src/main/webapp/app/lecture/wizard-mode/lecture-update-wizard.component.html +++ b/src/main/webapp/app/lecture/wizard-mode/lecture-update-wizard.component.html @@ -1,19 +1,16 @@
- @if (currentStep >= 1) { + @if (currentStep >= LECTURE_UPDATE_WIZARD_TITLE_STEP) { } - @if (currentStep >= 2) { + @if (currentStep >= LECTURE_UPDATE_WIZARD_PERIOD_STEP) { } - @if (currentStep >= 3) { + @if (currentStep >= LECTURE_UPDATE_WIZARD_ATTACHMENT_STEP) { } - @if (currentStep >= 4) { + @if (currentStep >= LECTURE_UPDATE_WIZARD_UNIT_STEP) { } - @if (currentStep >= 5) { - - }
@@ -24,38 +21,32 @@
-
+
-
+
-
+
-
-
-
diff --git a/src/main/webapp/app/lecture/wizard-mode/lecture-update-wizard.component.ts b/src/main/webapp/app/lecture/wizard-mode/lecture-update-wizard.component.ts index ea23823ea0dd..d360ffc962ca 100644 --- a/src/main/webapp/app/lecture/wizard-mode/lecture-update-wizard.component.ts +++ b/src/main/webapp/app/lecture/wizard-mode/lecture-update-wizard.component.ts @@ -5,7 +5,6 @@ import { Lecture } from 'app/entities/lecture.model'; import { ArtemisNavigationUtilService } from 'app/utils/navigation.utils'; import { faArrowRight, faCheck, faHandshakeAngle } from '@fortawesome/free-solid-svg-icons'; import { LectureUpdateWizardUnitsComponent } from 'app/lecture/wizard-mode/lecture-wizard-units.component'; -import { LectureUpdateWizardCompetenciesComponent } from 'app/lecture/wizard-mode/lecture-wizard-competencies.component'; import { take } from 'rxjs/operators'; @Component({ @@ -21,7 +20,11 @@ export class LectureUpdateWizardComponent implements OnInit { @Input() isSaving: boolean; @ViewChild(LectureUpdateWizardUnitsComponent, { static: false }) unitsComponent: LectureUpdateWizardUnitsComponent; - @ViewChild(LectureUpdateWizardCompetenciesComponent, { static: false }) competenciesComponent: LectureUpdateWizardCompetenciesComponent; + + readonly LECTURE_UPDATE_WIZARD_TITLE_STEP = 1; + readonly LECTURE_UPDATE_WIZARD_PERIOD_STEP = 2; + readonly LECTURE_UPDATE_WIZARD_ATTACHMENT_STEP = 3; + readonly LECTURE_UPDATE_WIZARD_UNIT_STEP = 4; currentStep: number; @@ -47,7 +50,13 @@ export class LectureUpdateWizardComponent implements OnInit { if (params.step && !isNaN(+params.step)) { this.currentStep = +params.step; } else { - this.currentStep = this.lecture.id ? 5 : this.lecture.startDate !== undefined || this.lecture.endDate !== undefined ? 2 : 1; + if (this.lecture.id) { + this.currentStep = this.LECTURE_UPDATE_WIZARD_UNIT_STEP; + } else if (this.lecture.startDate === undefined && this.lecture.endDate === undefined) { + this.currentStep = this.LECTURE_UPDATE_WIZARD_TITLE_STEP; + } else if (!this.lecture.id) { + this.currentStep = this.LECTURE_UPDATE_WIZARD_PERIOD_STEP; + } } this.router.navigate([], { @@ -62,7 +71,7 @@ export class LectureUpdateWizardComponent implements OnInit { * Progress to the next step of the wizard mode */ next() { - if (this.currentStep === 2 || this.currentStep === 5) { + if (this.currentStep === this.LECTURE_UPDATE_WIZARD_PERIOD_STEP || this.currentStep === this.LECTURE_UPDATE_WIZARD_UNIT_STEP) { this.saveLectureFunction(); return; } @@ -77,30 +86,16 @@ export class LectureUpdateWizardComponent implements OnInit { this.currentStep++; } - /** - * Checks if the given step has already been completed - */ - isCompleted(step: number) { - return this.currentStep > step; - } - - /** - * Checks if the given step is the current one - */ - isCurrent(step: number) { - return this.currentStep === step; - } - getNextIcon() { - return this.currentStep < 5 ? faArrowRight : faCheck; + return this.currentStep < this.LECTURE_UPDATE_WIZARD_UNIT_STEP ? faArrowRight : faCheck; } getNextText() { - return this.currentStep < 5 ? 'artemisApp.lecture.home.nextStepLabel' : 'entity.action.finish'; + return this.currentStep < this.LECTURE_UPDATE_WIZARD_UNIT_STEP ? 'artemisApp.lecture.home.nextStepLabel' : 'entity.action.finish'; } toggleWizardMode() { - if (this.currentStep <= 2) { + if (this.currentStep <= this.LECTURE_UPDATE_WIZARD_PERIOD_STEP) { this.toggleModeFunction(); } else { this.router.navigate(['course-management', this.lecture.course!.id, 'lectures', this.lecture.id]); diff --git a/src/main/webapp/app/lecture/wizard-mode/lecture-wizard-competencies.component.html b/src/main/webapp/app/lecture/wizard-mode/lecture-wizard-competencies.component.html deleted file mode 100644 index e7e90982591c..000000000000 --- a/src/main/webapp/app/lecture/wizard-mode/lecture-wizard-competencies.component.html +++ /dev/null @@ -1,97 +0,0 @@ -
-

-

- -

-
-
- @if (competencies && competencies.length > 0) { - - - - - - - - - - - - @for (competency of competencies; track trackCompetencyId($index, competency)) { - - - - - - - } - -
ID - - - -
- {{ competency.id }} - @if (currentlyProcessedCompetency?.id === competency?.id) { -
- } -
{{ competency.title }}{{ getConnectedUnitsForCompetency(competency) }} -
- - - @if (lecture.isAtLeastInstructor) { - - } -
-
- - } -
-
- @if (isLoadingCompetencies) { -
-
- -
-
- } - @if (!isEditingCompetency) { -
- -
- } - @if (isLoadingCompetencyForm) { -
-
- -
-
- } - @if ((isAddingCompetency || isEditingCompetency || isConnectingCompetency) && !isLoadingCompetencyForm) { - - } -
diff --git a/src/main/webapp/app/lecture/wizard-mode/lecture-wizard-competencies.component.scss b/src/main/webapp/app/lecture/wizard-mode/lecture-wizard-competencies.component.scss deleted file mode 100644 index b23d804a9fd8..000000000000 --- a/src/main/webapp/app/lecture/wizard-mode/lecture-wizard-competencies.component.scss +++ /dev/null @@ -1,14 +0,0 @@ -.edit-overlay { - position: absolute; - left: 0; - right: 0; - top: -1px; - display: flex; - justify-content: center; - align-items: center; - background-color: var(--lecture-attachment-edit-overlay-color); - z-index: 9; - font-size: 18px; - height: calc(100% + 1px); - border: none; -} diff --git a/src/main/webapp/app/lecture/wizard-mode/lecture-wizard-competencies.component.ts b/src/main/webapp/app/lecture/wizard-mode/lecture-wizard-competencies.component.ts deleted file mode 100644 index 8b6253399a31..000000000000 --- a/src/main/webapp/app/lecture/wizard-mode/lecture-wizard-competencies.component.ts +++ /dev/null @@ -1,273 +0,0 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { Observable, Subject } from 'rxjs'; -import { Lecture } from 'app/entities/lecture.model'; -import { Competency } from 'app/entities/competency.model'; -import { onError } from 'app/shared/util/global.utils'; -import { LectureUnit } from 'app/entities/lecture-unit/lectureUnit.model'; -import { faLink, faPencilAlt } from '@fortawesome/free-solid-svg-icons'; -import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; -import { AlertService } from 'app/core/util/alert.service'; -import { LectureService } from 'app/lecture/lecture.service'; -import { CompetencyService } from 'app/course/competencies/competency.service'; -import { finalize } from 'rxjs/operators'; -import { TranslateService } from '@ngx-translate/core'; -import { ExerciseUnit } from 'app/entities/lecture-unit/exerciseUnit.model'; -import { CourseCompetencyFormData } from 'app/course/competencies/forms/course-competency-form.component'; - -@Component({ - selector: 'jhi-lecture-update-wizard-competencies', - templateUrl: './lecture-wizard-competencies.component.html', - styleUrls: ['./lecture-wizard-competencies.component.scss'], -}) -export class LectureUpdateWizardCompetenciesComponent implements OnInit { - @Input() currentStep: number; - @Input() lecture: Lecture; - @Input() isSaving: boolean; - - isAddingCompetency: boolean; - isLoadingCompetencyForm: boolean; - isLoadingCompetencies: boolean; - isEditingCompetency: boolean; - isConnectingCompetency: boolean; - - currentlyProcessedCompetency: Competency; - competencies: Competency[] = []; - competencyFormData: CourseCompetencyFormData; - - private dialogErrorSource = new Subject(); - dialogError$ = this.dialogErrorSource.asObservable(); - - faPencilAlt = faPencilAlt; - faLink = faLink; - - constructor( - protected alertService: AlertService, - protected lectureService: LectureService, - protected competencyService: CompetencyService, - protected courseCompetencyService: CompetencyService, - protected translateService: TranslateService, - ) {} - - ngOnInit() { - this.loadCompetencies(); - } - - showCreateCompetency() { - this.isLoadingCompetencyForm = true; - this.isConnectingCompetency = false; - this.isAddingCompetency = !this.isAddingCompetency; - this.competencyFormData = { - id: undefined, - title: undefined, - description: undefined, - taxonomy: undefined, - connectedLectureUnits: undefined, - }; - - this.subscribeToLoadUnitResponse(this.lectureService.findWithDetails(this.lecture.id!)); - } - - protected subscribeToLoadUnitResponse(result: Observable>) { - result.subscribe({ - next: (response: HttpResponse) => this.onLoadUnitSuccess(response.body!), - error: (error: HttpErrorResponse) => this.onLoadError(error), - }); - } - - protected subscribeToLoadCompetenciesResponse(result: Observable>) { - result.subscribe({ - next: (response: HttpResponse) => this.onLoadCompetenciesSuccess(response.body!), - error: (error: HttpErrorResponse) => this.onLoadError(error), - }); - } - - /** - * Action on successful lecture unit fetch - */ - protected onLoadUnitSuccess(lecture: Lecture) { - this.lecture = lecture; - - this.isLoadingCompetencyForm = false; - } - - /** - * Action on successful competencies fetch - */ - protected onLoadCompetenciesSuccess(competencies: Competency[]) { - this.isLoadingCompetencies = false; - - this.competencies = competencies; - } - - /** - * Action on unsuccessful fetch - * @param error the error handed to the alert service - */ - protected onLoadError(error: HttpErrorResponse) { - this.isSaving = false; - this.isLoadingCompetencyForm = false; - this.isLoadingCompetencies = false; - - onError(this.alertService, error); - } - - onCompetencyFormSubmitted(formData: CourseCompetencyFormData) { - if (this.isEditingCompetency) { - this.editCompetency(formData); - } else { - this.createCompetency(formData); - } - } - - createCompetency(formData: CourseCompetencyFormData) { - if (!formData?.title) { - return; - } - - const { title, description, taxonomy, connectedLectureUnits } = formData; - this.currentlyProcessedCompetency = {}; - - this.currentlyProcessedCompetency.title = title; - this.currentlyProcessedCompetency.description = description; - this.currentlyProcessedCompetency.taxonomy = taxonomy; - this.currentlyProcessedCompetency.lectureUnits = connectedLectureUnits; - - this.isLoadingCompetencyForm = true; - - this.competencyService - .create(this.currentlyProcessedCompetency!, this.lecture.course!.id!) - .pipe( - finalize(() => { - this.isLoadingCompetencyForm = false; - }), - ) - .subscribe({ - next: (response: HttpResponse) => { - this.isAddingCompetency = false; - - // The rest api is returning lecture units and exercises separately after creating/editing but we - // need the unit to show it in the table as connected. Since it's only for showing it, as a - // workaround we take the unit from the lecture which is the same one. - const newCompetency = response.body!; - const exerciseUnits = this.lecture.lectureUnits?.filter((unit: ExerciseUnit) => newCompetency.exercises?.find((exercise) => exercise.id === unit.exercise?.id)); - newCompetency.lectureUnits = newCompetency.lectureUnits?.concat(exerciseUnits ?? []); - - this.competencies = this.competencies.concat(newCompetency); - - this.alertService.success(`Competency ${this.currentlyProcessedCompetency.title} was successfully created.`); - }, - error: (res: HttpErrorResponse) => onError(this.alertService, res), - }); - } - - editCompetency(formData: CourseCompetencyFormData) { - const { title, description, taxonomy, connectedLectureUnits } = formData; - - this.currentlyProcessedCompetency.title = title; - this.currentlyProcessedCompetency.description = description; - this.currentlyProcessedCompetency.taxonomy = taxonomy; - this.currentlyProcessedCompetency.lectureUnits = connectedLectureUnits; - - this.isLoadingCompetencyForm = true; - - this.competencyService - .update(this.currentlyProcessedCompetency, this.lecture.course!.id!) - .pipe( - finalize(() => { - this.isLoadingCompetencyForm = false; - }), - ) - .subscribe({ - next: (response: HttpResponse) => { - this.isEditingCompetency = false; - this.isConnectingCompetency = false; - - // The rest api is returning lecture units and exercises separately after creating/editing but we - // need the unit to show it in the table as connected. Since it's only for showing it, as a - // workaround we take the unit from the lecture which is the same one. - const editedCompetency = response.body!; - const exerciseUnits = this.lecture.lectureUnits?.filter((unit: ExerciseUnit) => - editedCompetency.exercises?.find((exercise) => exercise.id === unit.exercise?.id), - ); - editedCompetency.lectureUnits = editedCompetency.lectureUnits?.concat(exerciseUnits ?? []); - - const index = this.competencies.findIndex((competency) => competency.id === this.currentlyProcessedCompetency.id); - if (index === -1) { - this.competencies = this.competencies.concat(editedCompetency); - } else { - this.competencies[index] = editedCompetency; - } - - this.alertService.success(`Competency ${this.currentlyProcessedCompetency.title} was successfully edited.`); - this.currentlyProcessedCompetency = {}; - }, - error: (res: HttpErrorResponse) => onError(this.alertService, res), - }); - } - - trackCompetencyId(index: number, item: Competency) { - return item.id; - } - - loadCompetencies() { - this.isLoadingCompetencies = true; - this.isLoadingCompetencyForm = true; - - this.subscribeToLoadCompetenciesResponse(this.courseCompetencyService.getAllForCourse(this.lecture.course!.id!)); - this.subscribeToLoadUnitResponse(this.lectureService.findWithDetails(this.lecture.id!)); - } - - getConnectedUnitsForCompetency(competency: Competency) { - const units = competency.lectureUnits?.filter((unit) => this.lecture.lectureUnits?.find((u) => u.id === unit.id)); - - if (units === undefined || units.length === 0) { - return this.translateService.instant('artemisApp.lecture.wizardMode.competencyNoConnectedUnits'); - } - - return units.map((unit) => unit.name).join(', '); - } - - startEditCompetency(competency: Competency) { - const connectedUnits: LectureUnit[] = []; - competency.lectureUnits?.forEach((unit) => connectedUnits.push(Object.assign({}, unit))); - - this.isLoadingCompetencyForm = true; - this.isEditingCompetency = true; - this.currentlyProcessedCompetency = competency; - - this.competencyFormData = { - id: competency.id, - title: competency.title, - description: competency.description, - taxonomy: competency.taxonomy, - connectedLectureUnits: connectedUnits, - }; - - this.subscribeToLoadUnitResponse(this.lectureService.findWithDetails(this.lecture.id!)); - } - - startConnectingCompetency(competency: Competency) { - this.isConnectingCompetency = true; - - this.startEditCompetency(competency); - } - - deleteCompetency(competency: Competency) { - this.competencyService.delete(competency.id!, this.lecture.course!.id!).subscribe({ - next: () => { - this.competencies = this.competencies.filter((existingCompetency) => existingCompetency.id !== competency.id); - this.dialogErrorSource.next(''); - }, - error: (error: HttpErrorResponse) => this.dialogErrorSource.next(error.message), - }); - } - - onCompetencyFormCanceled() { - this.isAddingCompetency = false; - this.isEditingCompetency = false; - this.isConnectingCompetency = false; - this.isLoadingCompetencyForm = false; - - this.currentlyProcessedCompetency = {}; - } -} diff --git a/src/main/webapp/app/lecture/wizard-mode/lecture-wizard-units.component.ts b/src/main/webapp/app/lecture/wizard-mode/lecture-wizard-units.component.ts index 71d2484fbba4..9d08f4063e84 100644 --- a/src/main/webapp/app/lecture/wizard-mode/lecture-wizard-units.component.ts +++ b/src/main/webapp/app/lecture/wizard-mode/lecture-wizard-units.component.ts @@ -105,12 +105,13 @@ export class LectureUpdateWizardUnitsComponent implements OnInit { return; } - const { name, releaseDate, content } = formData; + const { name, releaseDate, content, competencies } = formData; this.currentlyProcessedTextUnit = this.isEditingLectureUnit ? this.currentlyProcessedTextUnit : new TextUnit(); this.currentlyProcessedTextUnit.name = name; this.currentlyProcessedTextUnit.releaseDate = releaseDate; this.currentlyProcessedTextUnit.content = content; + this.currentlyProcessedTextUnit.competencies = competencies; (this.isEditingLectureUnit ? this.textUnitService.update(this.currentlyProcessedTextUnit, this.lecture.id!) @@ -129,13 +130,14 @@ export class LectureUpdateWizardUnitsComponent implements OnInit { return; } - const { name, description, releaseDate, source } = formData; + const { name, description, releaseDate, source, competencies } = formData; this.currentlyProcessedVideoUnit = this.isEditingLectureUnit ? this.currentlyProcessedVideoUnit : new VideoUnit(); this.currentlyProcessedVideoUnit.name = name || undefined; this.currentlyProcessedVideoUnit.releaseDate = releaseDate || undefined; this.currentlyProcessedVideoUnit.description = description || undefined; this.currentlyProcessedVideoUnit.source = source || undefined; + this.currentlyProcessedVideoUnit.competencies = competencies; (this.isEditingLectureUnit ? this.videoUnitService.update(this.currentlyProcessedVideoUnit, this.lecture.id!) @@ -154,13 +156,14 @@ export class LectureUpdateWizardUnitsComponent implements OnInit { return; } - const { name, description, releaseDate, source } = formData; + const { name, description, releaseDate, source, competencies } = formData; this.currentlyProcessedOnlineUnit = this.isEditingLectureUnit ? this.currentlyProcessedOnlineUnit : new OnlineUnit(); this.currentlyProcessedOnlineUnit.name = name || undefined; this.currentlyProcessedOnlineUnit.releaseDate = releaseDate || undefined; this.currentlyProcessedOnlineUnit.description = description || undefined; this.currentlyProcessedOnlineUnit.source = source || undefined; + this.currentlyProcessedOnlineUnit.competencies = competencies || undefined; (this.isEditingLectureUnit ? this.onlineUnitService.update(this.currentlyProcessedOnlineUnit, this.lecture.id!) @@ -179,7 +182,7 @@ export class LectureUpdateWizardUnitsComponent implements OnInit { return; } - const { description, name, releaseDate, updateNotificationText } = attachmentUnitFormData.formProperties; + const { description, name, releaseDate, updateNotificationText, competencies } = attachmentUnitFormData.formProperties; const { file, fileName } = attachmentUnitFormData.fileProperties; this.currentlyProcessedAttachmentUnit = this.isEditingLectureUnit ? this.currentlyProcessedAttachmentUnit : new AttachmentUnit(); @@ -210,6 +213,9 @@ export class LectureUpdateWizardUnitsComponent implements OnInit { if (description) { this.currentlyProcessedAttachmentUnit.description = description; } + if (competencies) { + this.currentlyProcessedAttachmentUnit.competencies = competencies; + } const formData = new FormData(); formData.append('file', file, fileName); diff --git a/src/test/javascript/spec/component/lecture/wizard-mode/lecture-wizard-competencies.component.spec.ts b/src/test/javascript/spec/component/lecture/wizard-mode/lecture-wizard-competencies.component.spec.ts deleted file mode 100644 index 914fe55c18ab..000000000000 --- a/src/test/javascript/spec/component/lecture/wizard-mode/lecture-wizard-competencies.component.spec.ts +++ /dev/null @@ -1,518 +0,0 @@ -import { ComponentFixture, TestBed, fakeAsync } from '@angular/core/testing'; -import { MockComponent, MockPipe, MockProvider } from 'ng-mocks'; -import { AlertService } from 'app/core/util/alert.service'; -import { ActivatedRoute, Router } from '@angular/router'; -import { MockRouter } from '../../../helpers/mocks/mock-router'; -import { of, throwError } from 'rxjs'; -import { HttpResponse } from '@angular/common/http'; -import { Lecture } from 'app/entities/lecture.model'; -import { LectureUpdateWizardCompetenciesComponent } from 'app/lecture/wizard-mode/lecture-wizard-competencies.component'; -import { LectureService } from 'app/lecture/lecture.service'; -import { MockTranslateService } from '../../../helpers/mocks/service/mock-translate.service'; -import { TranslateService } from '@ngx-translate/core'; -import { CompetencyService } from 'app/course/competencies/competency.service'; -import { Competency } from 'app/entities/competency.model'; -import { Course } from 'app/entities/course.model'; -import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; -import { TextUnit } from 'app/entities/lecture-unit/textUnit.model'; -import { ExerciseUnit } from 'app/entities/lecture-unit/exerciseUnit.model'; -import { TextExercise } from 'app/entities/text/text-exercise.model'; -import { FaIconComponent } from '@fortawesome/angular-fontawesome'; -import { CourseCompetencyFormData } from 'app/course/competencies/forms/course-competency-form.component'; - -describe('LectureWizardCompetenciesComponent', () => { - let wizardCompetenciesComponentFixture: ComponentFixture; - let wizardCompetenciesComponent: LectureUpdateWizardCompetenciesComponent; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [], - declarations: [LectureUpdateWizardCompetenciesComponent, MockPipe(ArtemisTranslatePipe), MockComponent(FaIconComponent)], - providers: [ - MockProvider(AlertService), - MockProvider(LectureService), - MockProvider(CompetencyService), - { provide: TranslateService, useClass: MockTranslateService }, - { provide: Router, useClass: MockRouter }, - { - provide: ActivatedRoute, - useValue: { queryParams: of({}) }, - }, - ], - schemas: [], - }) - .compileComponents() - .then(() => { - wizardCompetenciesComponentFixture = TestBed.createComponent(LectureUpdateWizardCompetenciesComponent); - wizardCompetenciesComponent = wizardCompetenciesComponentFixture.componentInstance; - - const course = new Course(); - course.id = 2; - - wizardCompetenciesComponent.lecture = new Lecture(); - wizardCompetenciesComponent.lecture.id = 1; - wizardCompetenciesComponent.lecture.course = course; - }); - }); - - afterEach(() => { - jest.restoreAllMocks(); - }); - - it('should initialize and load data', fakeAsync(() => { - const lectureService = TestBed.inject(LectureService); - const competencyService = TestBed.inject(CompetencyService); - - const lecture = new Lecture(); - lecture.id = 1; - const lectureResponse: HttpResponse = new HttpResponse({ - body: lecture, - status: 201, - }); - const lectureStub = jest.spyOn(lectureService, 'findWithDetails').mockReturnValue(of(lectureResponse)); - - const competencies: Competency[] = [{}]; - const competenciesResponse: HttpResponse = new HttpResponse({ - body: competencies, - status: 201, - }); - const competenciesStub = jest.spyOn(competencyService, 'getAllForCourse').mockReturnValue(of(competenciesResponse)); - - wizardCompetenciesComponentFixture.detectChanges(); - expect(wizardCompetenciesComponent).not.toBeNull(); - - wizardCompetenciesComponentFixture.whenStable().then(() => { - expect(lectureStub).toHaveBeenCalledOnce(); - expect(competenciesStub).toHaveBeenCalledOnce(); - - expect(wizardCompetenciesComponent.lecture).toBe(lecture); - expect(wizardCompetenciesComponent.competencies).toBe(competencies); - }); - })); - - it('should show create form and load lecture when clicked', fakeAsync(() => { - const lectureService = TestBed.inject(LectureService); - const competencyService = TestBed.inject(CompetencyService); - - const lecture = new Lecture(); - lecture.id = 1; - const lectureResponse: HttpResponse = new HttpResponse({ - body: lecture, - status: 201, - }); - const lectureStub = jest.spyOn(lectureService, 'findWithDetails').mockReturnValue(of(lectureResponse)); - - const competencies: Competency[] = [{}]; - const competenciesResponse: HttpResponse = new HttpResponse({ - body: competencies, - status: 201, - }); - jest.spyOn(competencyService, 'getAllForCourse').mockReturnValue(of(competenciesResponse)); - - wizardCompetenciesComponentFixture.detectChanges(); - - wizardCompetenciesComponent.showCreateCompetency(); - - wizardCompetenciesComponentFixture.whenStable().then(() => { - expect(lectureStub).toHaveBeenCalledTimes(2); - - expect(wizardCompetenciesComponent.lecture).toBe(lecture); - expect(wizardCompetenciesComponent.isAddingCompetency).toBeTrue(); - }); - })); - - it('should show an alert when loading fails', fakeAsync(() => { - const lectureService = TestBed.inject(LectureService); - const competencyService = TestBed.inject(CompetencyService); - const alertService = TestBed.inject(AlertService); - - const lectureStub = jest.spyOn(lectureService, 'findWithDetails').mockReturnValue(throwError(() => ({ status: 404 }))); - - const competencies: Competency[] = [{}]; - const competenciesResponse: HttpResponse = new HttpResponse({ - body: competencies, - status: 201, - }); - jest.spyOn(competencyService, 'getAllForCourse').mockReturnValue(of(competenciesResponse)); - - const alertStub = jest.spyOn(alertService, 'error'); - - wizardCompetenciesComponentFixture.detectChanges(); - - wizardCompetenciesComponentFixture.whenStable().then(() => { - expect(lectureStub).toHaveBeenCalledOnce(); - expect(alertStub).toHaveBeenCalledOnce(); - }); - })); - - it('should show an alert when creating fails', fakeAsync(() => { - const lectureService = TestBed.inject(LectureService); - const competencyService = TestBed.inject(CompetencyService); - const alertService = TestBed.inject(AlertService); - - jest.spyOn(lectureService, 'findWithDetails').mockReturnValue(throwError(() => ({ status: 404 }))); - const createStub = jest.spyOn(competencyService, 'create').mockReturnValue(throwError(() => ({ status: 404 }))); - - const competencies: Competency[] = [{}]; - const competenciesResponse: HttpResponse = new HttpResponse({ - body: competencies, - status: 201, - }); - jest.spyOn(competencyService, 'getAllForCourse').mockReturnValue(of(competenciesResponse)); - - const alertStub = jest.spyOn(alertService, 'error'); - - wizardCompetenciesComponentFixture.detectChanges(); - - wizardCompetenciesComponent.createCompetency({ - id: 1, - title: 'Competency', - }); - - wizardCompetenciesComponentFixture.whenStable().then(() => { - expect(createStub).toHaveBeenCalledOnce(); - expect(alertStub).toHaveBeenCalledTimes(2); - }); - })); - - it('should show an alert when deleting fails', fakeAsync(() => { - const lectureService = TestBed.inject(LectureService); - const competencyService = TestBed.inject(CompetencyService); - const alertService = TestBed.inject(AlertService); - - jest.spyOn(lectureService, 'findWithDetails').mockReturnValue(throwError(() => ({ status: 404 }))); - - const competencies: Competency[] = [{}]; - const competenciesResponse: HttpResponse = new HttpResponse({ - body: competencies, - status: 201, - }); - jest.spyOn(competencyService, 'getAllForCourse').mockReturnValue(of(competenciesResponse)); - - const alertStub = jest.spyOn(alertService, 'error'); - const deleteStub = jest.spyOn(competencyService, 'delete').mockReturnValue(throwError(() => ({ status: 404 }))); - - wizardCompetenciesComponentFixture.detectChanges(); - - wizardCompetenciesComponent.deleteCompetency(competencies[0]); - - wizardCompetenciesComponentFixture.whenStable().then(() => { - expect(deleteStub).toHaveBeenCalledOnce(); - expect(alertStub).toHaveBeenCalledOnce(); - }); - })); - - it('should show an alert when editing fails', fakeAsync(() => { - const lectureService = TestBed.inject(LectureService); - const competencyService = TestBed.inject(CompetencyService); - const alertService = TestBed.inject(AlertService); - - jest.spyOn(lectureService, 'findWithDetails').mockReturnValue(throwError(() => ({ status: 404 }))); - const editStub = jest.spyOn(competencyService, 'update').mockReturnValue(throwError(() => ({ status: 404 }))); - - const competencies: Competency[] = [{}]; - const competenciesResponse: HttpResponse = new HttpResponse({ - body: competencies, - status: 201, - }); - jest.spyOn(competencyService, 'getAllForCourse').mockReturnValue(of(competenciesResponse)); - - const alertStub = jest.spyOn(alertService, 'error'); - - wizardCompetenciesComponentFixture.detectChanges(); - - wizardCompetenciesComponentFixture.whenStable().then(() => { - wizardCompetenciesComponent.currentlyProcessedCompetency = {}; - wizardCompetenciesComponent.editCompetency({ - id: 1, - title: 'Competency', - }); - wizardCompetenciesComponentFixture.whenStable().then(() => { - expect(editStub).toHaveBeenCalledOnce(); - expect(alertStub).toHaveBeenCalledTimes(2); - }); - }); - })); - - it('should close all forms when canceling', fakeAsync(() => { - const lectureService = TestBed.inject(LectureService); - const competencyService = TestBed.inject(CompetencyService); - - jest.spyOn(lectureService, 'findWithDetails').mockReturnValue(throwError(() => ({ status: 404 }))); - - const competencies: Competency[] = [{}]; - const competenciesResponse: HttpResponse = new HttpResponse({ - body: competencies, - status: 201, - }); - jest.spyOn(competencyService, 'getAllForCourse').mockReturnValue(of(competenciesResponse)); - - wizardCompetenciesComponentFixture.detectChanges(); - - wizardCompetenciesComponent.onCompetencyFormCanceled(); - - wizardCompetenciesComponentFixture.whenStable().then(() => { - expect(wizardCompetenciesComponent.isAddingCompetency).toBeFalse(); - expect(wizardCompetenciesComponent.isEditingCompetency).toBeFalse(); - expect(wizardCompetenciesComponent.isLoadingCompetencyForm).toBeFalse(); - }); - })); - - it('should delete the competency when clicked', fakeAsync(() => { - const lectureService = TestBed.inject(LectureService); - const competencyService = TestBed.inject(CompetencyService); - - jest.spyOn(lectureService, 'findWithDetails').mockReturnValue(throwError(() => ({ status: 404 }))); - - const competencies: Competency[] = [{}]; - const competenciesResponse: HttpResponse = new HttpResponse({ - body: competencies, - status: 201, - }); - jest.spyOn(competencyService, 'getAllForCourse').mockReturnValue(of(competenciesResponse)); - const deleteStub = jest.spyOn(competencyService, 'delete').mockReturnValue(of(new HttpResponse({ status: 201 }))); - - wizardCompetenciesComponentFixture.detectChanges(); - - wizardCompetenciesComponent.deleteCompetency(competencies[0]); - - wizardCompetenciesComponentFixture.whenStable().then(() => { - expect(deleteStub).toHaveBeenCalledOnce(); - }); - })); - - it('should open the form when editing', fakeAsync(() => { - const lectureService = TestBed.inject(LectureService); - const competencyService = TestBed.inject(CompetencyService); - - jest.spyOn(lectureService, 'findWithDetails').mockReturnValue(throwError(() => ({ status: 404 }))); - jest.spyOn(competencyService, 'getAllForCourse').mockReturnValue(throwError(() => ({ status: 404 }))); - - wizardCompetenciesComponentFixture.detectChanges(); - - const competency: Competency = {}; - competency.id = 12; - wizardCompetenciesComponent.startEditCompetency(competency); - - wizardCompetenciesComponentFixture.whenStable().then(() => { - expect(wizardCompetenciesComponent.isEditingCompetency).toBeTrue(); - expect(wizardCompetenciesComponent.currentlyProcessedCompetency.id).toBe(12); - }); - })); - - it('should return the connected units for a competency and lecture', fakeAsync(() => { - const lectureService = TestBed.inject(LectureService); - const competencyService = TestBed.inject(CompetencyService); - - jest.spyOn(lectureService, 'findWithDetails').mockReturnValue(throwError(() => ({ status: 404 }))); - jest.spyOn(competencyService, 'getAllForCourse').mockReturnValue(throwError(() => ({ status: 404 }))); - - wizardCompetenciesComponentFixture.detectChanges(); - - const lectureUnit = new TextUnit(); - lectureUnit.name = 'Test'; - lectureUnit.id = 5; - - wizardCompetenciesComponent.lecture.lectureUnits = [lectureUnit]; - - const competency: Competency = {}; - competency.id = 12; - competency.lectureUnits = [lectureUnit]; - const result = wizardCompetenciesComponent.getConnectedUnitsForCompetency(competency); - - expect(result).toBe('Test'); - })); - - it('should return no connected units for empty competency', fakeAsync(() => { - const lectureService = TestBed.inject(LectureService); - const competencyService = TestBed.inject(CompetencyService); - - jest.spyOn(lectureService, 'findWithDetails').mockReturnValue(throwError(() => ({ status: 404 }))); - jest.spyOn(competencyService, 'getAllForCourse').mockReturnValue(throwError(() => ({ status: 404 }))); - - wizardCompetenciesComponentFixture.detectChanges(); - - const competency: Competency = {}; - competency.id = 12; - const result = wizardCompetenciesComponent.getConnectedUnitsForCompetency(competency); - - expect(result).toBe('artemisApp.lecture.wizardMode.competencyNoConnectedUnits'); - })); - - it('should call the service and show an alert when creating a competency', fakeAsync(() => { - const lectureService = TestBed.inject(LectureService); - const competencyService = TestBed.inject(CompetencyService); - const alertService = TestBed.inject(AlertService); - - jest.spyOn(lectureService, 'findWithDetails').mockReturnValue(throwError(() => ({ status: 404 }))); - jest.spyOn(competencyService, 'getAllForCourse').mockReturnValue(throwError(() => ({ status: 404 }))); - - const createStub = jest.spyOn(competencyService, 'create').mockReturnValue(of(new HttpResponse({ status: 201, body: {} }))); - const alertStub = jest.spyOn(alertService, 'success'); - - wizardCompetenciesComponentFixture.detectChanges(); - - const formData: CourseCompetencyFormData = { - id: 1, - title: 'Competency', - }; - - wizardCompetenciesComponentFixture.whenStable().then(() => { - wizardCompetenciesComponent.isEditingCompetency = false; - wizardCompetenciesComponent.onCompetencyFormSubmitted(formData); - - wizardCompetenciesComponentFixture.whenStable().then(() => { - expect(wizardCompetenciesComponent.isAddingCompetency).toBeFalse(); - expect(createStub).toHaveBeenCalledOnce(); - expect(alertStub).toHaveBeenCalledOnce(); - }); - }); - })); - - it('should append exercises as units when creating a competency', fakeAsync(() => { - const lectureService = TestBed.inject(LectureService); - const competencyService = TestBed.inject(CompetencyService); - const alertService = TestBed.inject(AlertService); - - jest.spyOn(lectureService, 'findWithDetails').mockReturnValue(throwError(() => ({ status: 404 }))); - jest.spyOn(competencyService, 'getAllForCourse').mockReturnValue(throwError(() => ({ status: 404 }))); - - const competency: Competency = {}; - const exercise = new TextExercise(undefined, undefined); - exercise.id = 2; - competency.exercises = [exercise]; - competency.lectureUnits = []; - const createStub = jest.spyOn(competencyService, 'create').mockReturnValue(of(new HttpResponse({ status: 201, body: competency }))); - const alertStub = jest.spyOn(alertService, 'success'); - - const unit = new ExerciseUnit(); - unit.id = 2; - unit.exercise = exercise; - - wizardCompetenciesComponent.lecture.lectureUnits = [unit]; - - wizardCompetenciesComponentFixture.detectChanges(); - - const formData: CourseCompetencyFormData = { - id: 1, - title: 'Competency', - }; - - wizardCompetenciesComponentFixture.whenStable().then(() => { - wizardCompetenciesComponent.lecture.lectureUnits = [unit]; - wizardCompetenciesComponent.isEditingCompetency = false; - wizardCompetenciesComponent.onCompetencyFormSubmitted(formData); - - wizardCompetenciesComponentFixture.whenStable().then(() => { - expect(wizardCompetenciesComponent.isAddingCompetency).toBeFalse(); - expect(createStub).toHaveBeenCalledOnce(); - expect(alertStub).toHaveBeenCalledOnce(); - - expect(wizardCompetenciesComponent.competencies).toHaveLength(1); - expect(wizardCompetenciesComponent.competencies[0]!.lectureUnits![0]!.id).toBe(2); - }); - }); - })); - - it('should not call the service when creating a competency with an empty form', fakeAsync(() => { - const lectureService = TestBed.inject(LectureService); - const competencyService = TestBed.inject(CompetencyService); - const alertService = TestBed.inject(AlertService); - - jest.spyOn(lectureService, 'findWithDetails').mockReturnValue(throwError(() => ({ status: 404 }))); - jest.spyOn(competencyService, 'getAllForCourse').mockReturnValue(throwError(() => ({ status: 404 }))); - - const createStub = jest.spyOn(competencyService, 'create').mockReturnValue(of(new HttpResponse({ status: 201, body: {} }))); - const alertStub = jest.spyOn(alertService, 'success'); - - wizardCompetenciesComponentFixture.detectChanges(); - - const formData: CourseCompetencyFormData = {}; - - wizardCompetenciesComponentFixture.whenStable().then(() => { - wizardCompetenciesComponent.createCompetency(formData); - - wizardCompetenciesComponentFixture.whenStable().then(() => { - expect(createStub).not.toHaveBeenCalled(); - expect(alertStub).not.toHaveBeenCalled(); - }); - }); - })); - - it('should call the service and show an alert when editing a competency', fakeAsync(() => { - const lectureService = TestBed.inject(LectureService); - const competencyService = TestBed.inject(CompetencyService); - const alertService = TestBed.inject(AlertService); - - jest.spyOn(lectureService, 'findWithDetails').mockReturnValue(throwError(() => ({ status: 404 }))); - jest.spyOn(competencyService, 'getAllForCourse').mockReturnValue(throwError(() => ({ status: 404 }))); - - const editStub = jest.spyOn(competencyService, 'update').mockReturnValue(of(new HttpResponse({ status: 201, body: {} }))); - const alertStub = jest.spyOn(alertService, 'success'); - - wizardCompetenciesComponentFixture.detectChanges(); - - const formData: CourseCompetencyFormData = { - id: 1, - title: 'Competency', - }; - - wizardCompetenciesComponentFixture.whenStable().then(() => { - wizardCompetenciesComponent.currentlyProcessedCompetency = {}; - wizardCompetenciesComponent.isEditingCompetency = true; - wizardCompetenciesComponent.onCompetencyFormSubmitted(formData); - - wizardCompetenciesComponentFixture.whenStable().then(() => { - expect(wizardCompetenciesComponent.isEditingCompetency).toBeFalse(); - expect(editStub).toHaveBeenCalledOnce(); - expect(alertStub).toHaveBeenCalledOnce(); - }); - }); - })); - - it('should append exercises as units when editing a competency', fakeAsync(() => { - const lectureService = TestBed.inject(LectureService); - const competencyService = TestBed.inject(CompetencyService); - const alertService = TestBed.inject(AlertService); - - jest.spyOn(lectureService, 'findWithDetails').mockReturnValue(throwError(() => ({ status: 404 }))); - jest.spyOn(competencyService, 'getAllForCourse').mockReturnValue(throwError(() => ({ status: 404 }))); - - const competency: Competency = {}; - const exercise = new TextExercise(undefined, undefined); - exercise.id = 2; - competency.exercises = [exercise]; - competency.lectureUnits = []; - const editStub = jest.spyOn(competencyService, 'update').mockReturnValue(of(new HttpResponse({ status: 201, body: competency }))); - const alertStub = jest.spyOn(alertService, 'success'); - - const unit = new ExerciseUnit(); - unit.id = 2; - unit.exercise = exercise; - - wizardCompetenciesComponent.lecture.lectureUnits = [unit]; - - wizardCompetenciesComponentFixture.detectChanges(); - - const formData: CourseCompetencyFormData = { - id: 1, - title: 'Competency', - }; - - wizardCompetenciesComponentFixture.whenStable().then(() => { - wizardCompetenciesComponent.currentlyProcessedCompetency = {}; - wizardCompetenciesComponent.lecture.lectureUnits = [unit]; - wizardCompetenciesComponent.isEditingCompetency = true; - wizardCompetenciesComponent.onCompetencyFormSubmitted(formData); - - wizardCompetenciesComponentFixture.whenStable().then(() => { - expect(wizardCompetenciesComponent.isEditingCompetency).toBeFalse(); - expect(editStub).toHaveBeenCalledOnce(); - expect(alertStub).toHaveBeenCalledOnce(); - - expect(wizardCompetenciesComponent.competencies).toHaveLength(1); - expect(wizardCompetenciesComponent.competencies[0]!.lectureUnits![0]!.id).toBe(2); - }); - }); - })); -}); diff --git a/src/test/javascript/spec/component/lecture/wizard-mode/lecture-wizard-units.component.spec.ts b/src/test/javascript/spec/component/lecture/wizard-mode/lecture-wizard-units.component.spec.ts index cb597fb41f64..58113a1c5b16 100644 --- a/src/test/javascript/spec/component/lecture/wizard-mode/lecture-wizard-units.component.spec.ts +++ b/src/test/javascript/spec/component/lecture/wizard-mode/lecture-wizard-units.component.spec.ts @@ -163,7 +163,16 @@ describe('LectureWizardUnitComponent', () => { name: 'Test', releaseDate: dayjs().year(2010).month(3).date(5), description: 'Lorem Ipsum', - source: 'https://www.youtube.com/embed/8iU8LPEa4o0', + source: 'https://youtu.be/dQw4w9WgXcQ', + competencies: [ + { + id: 1, + masteryThreshold: 0, + optional: false, + taxonomy: undefined, + title: 'Test', + }, + ], }; const response: HttpResponse = new HttpResponse({ @@ -192,6 +201,7 @@ describe('LectureWizardUnitComponent', () => { expect(videoUnitCallArgument.description).toEqual(formData.description); expect(videoUnitCallArgument.releaseDate).toEqual(formData.releaseDate); expect(videoUnitCallArgument.source).toEqual(formData.source); + expect(videoUnitCallArgument.competencies).toEqual(formData.competencies); expect(lectureIdCallArgument).toBe(1); expect(createStub).toHaveBeenCalledOnce(); @@ -227,6 +237,15 @@ describe('LectureWizardUnitComponent', () => { name: 'Test', releaseDate: dayjs().year(2010).month(3).date(5), content: 'Lorem Ipsum', + competencies: [ + { + id: 1, + masteryThreshold: 0, + optional: false, + taxonomy: undefined, + title: 'Test', + }, + ], }; const persistedTextUnit: TextUnit = new TextUnit(); @@ -254,6 +273,15 @@ describe('LectureWizardUnitComponent', () => { wizardUnitComponent.createEditTextUnit(formData); wizardUnitComponentFixture.whenStable().then(() => { + const textUnitCallArgument: TextUnit = createStub.mock.calls[0][0]; + const lectureIdCallArgument: number = createStub.mock.calls[0][1]; + + expect(textUnitCallArgument.name).toEqual(formData.name); + expect(textUnitCallArgument.content).toEqual(formData.content); + expect(textUnitCallArgument.releaseDate).toEqual(formData.releaseDate); + expect(textUnitCallArgument.competencies).toEqual(formData.competencies); + expect(lectureIdCallArgument).toBe(1); + expect(createStub).toHaveBeenCalledOnce(); expect(updateSpy).toHaveBeenCalledOnce(); @@ -368,6 +396,15 @@ describe('LectureWizardUnitComponent', () => { releaseDate: dayjs().year(2010).month(3).date(5), description: 'Lorem Ipsum', source: 'https://www.example.com', + competencies: [ + { + id: 1, + masteryThreshold: 0, + optional: false, + taxonomy: undefined, + title: 'Test', + }, + ], }; const response: HttpResponse = new HttpResponse({ @@ -396,6 +433,7 @@ describe('LectureWizardUnitComponent', () => { expect(onlineUnitCallArgument.description).toEqual(formDate.description); expect(onlineUnitCallArgument.releaseDate).toEqual(formDate.releaseDate); expect(onlineUnitCallArgument.source).toEqual(formDate.source); + expect(onlineUnitCallArgument.competencies).toEqual(formDate.competencies); expect(lectureIdCallArgument).toBe(1); expect(createStub).toHaveBeenCalledOnce(); @@ -436,6 +474,15 @@ describe('LectureWizardUnitComponent', () => { releaseDate: dayjs().year(2010).month(3).date(5), version: 2, updateNotificationText: 'lorem ipsum', + competencies: [ + { + id: 1, + masteryThreshold: 0, + optional: false, + taxonomy: undefined, + title: 'Test', + }, + ], }, fileProperties: { file: fakeFile, @@ -479,7 +526,11 @@ describe('LectureWizardUnitComponent', () => { wizardUnitComponent.createEditAttachmentUnit(attachmentUnitFormData); wizardUnitComponentFixture.whenStable().then(() => { + const lectureIdCallArgument: number = createAttachmentUnitStub.mock.calls[0][1]; + + expect(lectureIdCallArgument).toBe(1); expect(createAttachmentUnitStub).toHaveBeenCalledWith(formData, 1); + expect(updateSpy).toHaveBeenCalledOnce(); updateSpy.mockRestore(); @@ -605,6 +656,62 @@ describe('LectureWizardUnitComponent', () => { }); })); + it('should show alert upon unsuccessful attachment form submission with error information', fakeAsync(() => { + const attachmentUnitService = TestBed.inject(AttachmentUnitService); + const alertService = TestBed.inject(AlertService); + + const fakeFile = new File([''], 'Test-File.pdf', { type: 'application/pdf' }); + + const attachmentUnitFormData: AttachmentUnitFormData = { + formProperties: { + name: 'test', + description: 'lorem ipsum', + releaseDate: dayjs().year(2010).month(3).date(5), + version: 2, + updateNotificationText: 'lorem ipsum', + }, + fileProperties: { + file: fakeFile, + fileName: 'lorem ipsum', + }, + }; + + const examplePath = '/path/to/file'; + + const attachment = new Attachment(); + attachment.version = 1; + attachment.attachmentType = AttachmentType.FILE; + attachment.releaseDate = attachmentUnitFormData.formProperties.releaseDate; + attachment.name = attachmentUnitFormData.formProperties.name; + attachment.link = examplePath; + + const attachmentUnit = new AttachmentUnit(); + attachmentUnit.description = attachmentUnitFormData.formProperties.description; + attachmentUnit.attachment = attachment; + + const formData = new FormData(); + formData.append('file', fakeFile, attachmentUnitFormData.fileProperties.fileName); + formData.append('attachment', objectToJsonBlob(attachment)); + formData.append('attachmentUnit', objectToJsonBlob(attachmentUnit)); + + const createAttachmentUnitStub = jest + .spyOn(attachmentUnitService, 'create') + .mockReturnValue(throwError(() => ({ status: 404, error: { params: 'file', title: 'Test Title' } }))); + const alertStub = jest.spyOn(alertService, 'error'); + + wizardUnitComponentFixture.detectChanges(); + tick(); + + wizardUnitComponent.isAttachmentUnitFormOpen = true; + + wizardUnitComponent.createEditAttachmentUnit(attachmentUnitFormData); + + wizardUnitComponentFixture.whenStable().then(() => { + expect(createAttachmentUnitStub).toHaveBeenCalledOnce(); + expect(alertStub).toHaveBeenCalledOnce(); + }); + })); + it('should not send POST request upon empty attachment form submission', fakeAsync(() => { const attachmentUnitService = TestBed.inject(AttachmentUnitService); diff --git a/src/test/javascript/spec/component/lecture/wizard-mode/lecture-wizard.component.spec.ts b/src/test/javascript/spec/component/lecture/wizard-mode/lecture-wizard.component.spec.ts index 39f6b3b80998..716de13900a0 100644 --- a/src/test/javascript/spec/component/lecture/wizard-mode/lecture-wizard.component.spec.ts +++ b/src/test/javascript/spec/component/lecture/wizard-mode/lecture-wizard.component.spec.ts @@ -12,7 +12,6 @@ import { LectureUpdateWizardComponent } from 'app/lecture/wizard-mode/lecture-up import { ArtemisNavigationUtilService } from 'app/utils/navigation.utils'; import { CourseManagementService } from 'app/course/manage/course-management.service'; import { LectureUpdateWizardStepComponent } from 'app/lecture/wizard-mode/lecture-update-wizard-step.component'; -import { LectureUpdateWizardCompetenciesComponent } from 'app/lecture/wizard-mode/lecture-wizard-competencies.component'; import { LectureUpdateWizardUnitsComponent } from 'app/lecture/wizard-mode/lecture-wizard-units.component'; import { LectureUpdateWizardAttachmentsComponent } from 'app/lecture/wizard-mode/lecture-wizard-attachments.component'; import { LectureUpdateWizardPeriodComponent } from 'app/lecture/wizard-mode/lecture-wizard-period.component'; @@ -32,7 +31,6 @@ describe('LectureWizardComponent', () => { LectureUpdateWizardComponent, MockPipe(ArtemisTranslatePipe), MockComponent(LectureUpdateWizardStepComponent), - MockComponent(LectureUpdateWizardCompetenciesComponent), MockComponent(LectureUpdateWizardUnitsComponent), MockComponent(LectureUpdateWizardAttachmentsComponent), MockComponent(LectureUpdateWizardPeriodComponent), @@ -75,7 +73,7 @@ describe('LectureWizardComponent', () => { expect(wizardComponent).not.toBeNull(); wizardComponentFixture.whenStable().then(() => { - expect(wizardComponent.currentStep).toBe(5); + expect(wizardComponent.currentStep).toBe(4); }); })); @@ -134,7 +132,7 @@ describe('LectureWizardComponent', () => { wizardComponentFixture.detectChanges(); wizardComponentFixture.whenStable().then(() => { - expect(wizardComponent.currentStep).toBe(5); + expect(wizardComponent.currentStep).toBe(4); wizardComponent.next(); expect(saveStub).toHaveBeenCalledOnce(); }); @@ -150,46 +148,6 @@ describe('LectureWizardComponent', () => { }); })); - it('should return is completed for smaller step', fakeAsync(() => { - wizardComponentFixture.detectChanges(); - - wizardComponentFixture.whenStable().then(() => { - wizardComponent.currentStep = 2; - const result = wizardComponent.isCompleted(1); - expect(result).toBeTrue(); - }); - })); - - it('should not return is completed for bigger step', fakeAsync(() => { - wizardComponentFixture.detectChanges(); - - wizardComponentFixture.whenStable().then(() => { - wizardComponent.currentStep = 2; - const result = wizardComponent.isCompleted(3); - expect(result).toBeFalse(); - }); - })); - - it('should return is current for same step', fakeAsync(() => { - wizardComponentFixture.detectChanges(); - - wizardComponentFixture.whenStable().then(() => { - wizardComponent.currentStep = 2; - const result = wizardComponent.isCurrent(2); - expect(result).toBeTrue(); - }); - })); - - it('should not return is current for different step', fakeAsync(() => { - wizardComponentFixture.detectChanges(); - - wizardComponentFixture.whenStable().then(() => { - wizardComponent.currentStep = 2; - const result = wizardComponent.isCurrent(1); - expect(result).toBeFalse(); - }); - })); - it('should return correct icon for last step', fakeAsync(() => { wizardComponentFixture.detectChanges(); From 796e488cc369554ddbcbc55d55cbc8323673bc05 Mon Sep 17 00:00:00 2001 From: Stephan Krusche Date: Thu, 5 Sep 2024 12:59:52 +0200 Subject: [PATCH 13/16] General: Improve login dialog (#9270) --- .../app/core/language/language.helper.ts | 2 +- src/main/webapp/app/home/home.component.html | 36 +++++++++++-------- src/main/webapp/app/home/home.component.ts | 27 ++++++++++---- src/main/webapp/i18n/de/dataExport.json | 2 +- src/main/webapp/i18n/de/global.json | 5 +-- src/main/webapp/i18n/de/home.json | 9 ++--- src/main/webapp/i18n/de/login.json | 2 +- src/main/webapp/i18n/de/metis.json | 2 +- .../i18n/de/organizationManagement.json | 4 +-- src/main/webapp/i18n/de/reset.json | 4 +-- src/main/webapp/i18n/de/userSettings.json | 2 +- src/main/webapp/i18n/en/global.json | 9 ++--- src/main/webapp/i18n/en/home.json | 13 +++---- src/main/webapp/i18n/en/login.json | 4 +-- src/main/webapp/i18n/en/reset.json | 4 +-- .../core/language/language.helper.spec.ts | 4 +-- src/test/playwright/e2e/Login.spec.ts | 2 +- 17 files changed, 78 insertions(+), 53 deletions(-) diff --git a/src/main/webapp/app/core/language/language.helper.ts b/src/main/webapp/app/core/language/language.helper.ts index 036c2f63699c..60cfe80b69c2 100644 --- a/src/main/webapp/app/core/language/language.helper.ts +++ b/src/main/webapp/app/core/language/language.helper.ts @@ -98,7 +98,7 @@ export class JhiLanguageHelper { return 'en'; } - public getNavigatorReference(): any { + public getNavigatorReference(): Navigator { return navigator; } } diff --git a/src/main/webapp/app/home/home.component.html b/src/main/webapp/app/home/home.component.html index 09685f917014..2ac14640fc07 100644 --- a/src/main/webapp/app/home/home.component.html +++ b/src/main/webapp/app/home/home.component.html @@ -13,8 +13,8 @@

Please sign in with your account.
} @if (accountName) { -
- Please sign in with your account. +
+ Sign in with your account.
} +
+

+
+
+
{{ operatorName }}
+
+ @if (operatorAdminName) { +
+
+
{{ operatorAdminName }}
+
+ } + @if (operatorContactEmail) { + + }
diff --git a/src/main/webapp/app/core/about-us/about-us.component.scss b/src/main/webapp/app/core/about-us/about-us.component.scss index 18f8bfcd0a33..6a8714e970e6 100644 --- a/src/main/webapp/app/core/about-us/about-us.component.scss +++ b/src/main/webapp/app/core/about-us/about-us.component.scss @@ -37,3 +37,13 @@ flex: 0 0 50%; max-width: 50%; } + +.inline-block { + display: inline-block; + vertical-align: middle; + margin-right: 20px; +} + +.fixed-width { + width: 200px; +} diff --git a/src/main/webapp/app/core/about-us/about-us.component.ts b/src/main/webapp/app/core/about-us/about-us.component.ts index aa8f35742728..42ba47b5093a 100644 --- a/src/main/webapp/app/core/about-us/about-us.component.ts +++ b/src/main/webapp/app/core/about-us/about-us.component.ts @@ -19,8 +19,11 @@ export class AboutUsComponent implements OnInit { email: string; data: AboutUsModel; - gitCommitId: string; - gitBranchName: string; + gitCommitId?: string; + gitBranchName?: string; + operatorName?: string; + operatorAdminName?: string; + operatorContactEmail?: string; // Array of tuple containing translation keys and translation values readonly SECTIONS: [string, { [key: string]: string }][] = [ @@ -61,7 +64,10 @@ export class AboutUsComponent implements OnInit { ngOnInit(): void { this.staticContentService.getStaticJsonFromArtemisServer('about-us.json').subscribe((data) => { // Map contributors into the model, as the returned data are just plain objects - this.data = { ...data, contributors: data.contributors.map((con: any) => new ContributorModel(con.fullName, con.photoDirectory, con.sortBy, con.role, con.website)) }; + this.data = { + ...data, + contributors: data.contributors.map((con: any) => new ContributorModel(con.fullName, con.photoDirectory, con.sortBy, con.role, con.website)), + }; // Sort by last name // Either the last "word" in the name, or the dedicated sortBy field, if present @@ -74,9 +80,11 @@ export class AboutUsComponent implements OnInit { this.gitCommitId = profileInfo.git.commit.id.abbrev; this.gitBranchName = profileInfo.git.branch; } + this.operatorName = profileInfo.operatorName; + this.operatorAdminName = profileInfo.operatorAdminName; + this.operatorContactEmail = profileInfo.contact; }); } - /** * Create the mail reference for the contact */ diff --git a/src/main/webapp/app/shared/layouts/profiles/profile-info.model.ts b/src/main/webapp/app/shared/layouts/profiles/profile-info.model.ts index 18c335e0079f..9d7bafb69cde 100644 --- a/src/main/webapp/app/shared/layouts/profiles/profile-info.model.ts +++ b/src/main/webapp/app/shared/layouts/profiles/profile-info.model.ts @@ -56,6 +56,8 @@ export class ProfileInfo { }; }; public theiaPortalURL: string; + public operatorName: string; + public operatorAdminName?: string; } export const hasEditableBuildPlan = (profileInfo: ProfileInfo): boolean => { diff --git a/src/main/webapp/app/shared/layouts/profiles/profile.service.ts b/src/main/webapp/app/shared/layouts/profiles/profile.service.ts index ce197b034a47..ac828dc310ea 100644 --- a/src/main/webapp/app/shared/layouts/profiles/profile.service.ts +++ b/src/main/webapp/app/shared/layouts/profiles/profile.service.ts @@ -61,6 +61,8 @@ export class ProfileService { profileInfo.externalUserManagementURL = data.externalUserManagementURL ?? ''; profileInfo.contact = data.contact; + profileInfo.operatorName = data.operatorName; + profileInfo.operatorAdminName = data.operatorAdminName; profileInfo.registrationEnabled = data.registrationEnabled; profileInfo.needsToAcceptTerms = data.needsToAcceptTerms; profileInfo.allowedEmailPattern = data.allowedEmailPattern; diff --git a/src/main/webapp/i18n/de/operatorInfo.json b/src/main/webapp/i18n/de/operatorInfo.json new file mode 100644 index 000000000000..769631e8a7b4 --- /dev/null +++ b/src/main/webapp/i18n/de/operatorInfo.json @@ -0,0 +1,10 @@ +{ + "artemisApp": { + "operatorInfo": { + "title": "Betreiber", + "name": "Name", + "admin": "Administrator:in", + "adminEmail": "Kontakt-E-Mail" + } + } +} diff --git a/src/main/webapp/i18n/en/operatorInfo.json b/src/main/webapp/i18n/en/operatorInfo.json new file mode 100644 index 000000000000..a6e174a9b9fd --- /dev/null +++ b/src/main/webapp/i18n/en/operatorInfo.json @@ -0,0 +1,10 @@ +{ + "artemisApp": { + "operatorInfo": { + "title": "Operator", + "name": "Name", + "admin": "Administrator", + "adminEmail": "Contact Email" + } + } +} diff --git a/src/test/java/de/tum/in/www1/artemis/telemetry/TelemetryServiceTest.java b/src/test/java/de/tum/in/www1/artemis/telemetry/TelemetryServiceTest.java new file mode 100644 index 000000000000..9ff3a4db9874 --- /dev/null +++ b/src/test/java/de/tum/in/www1/artemis/telemetry/TelemetryServiceTest.java @@ -0,0 +1,78 @@ +package de.tum.in.www1.artemis.telemetry; + +import static org.mockito.Mockito.spy; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withServerError; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus; + +import java.net.URI; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.test.web.client.ExpectedCount; +import org.springframework.test.web.client.MockRestServiceServer; +import org.springframework.web.client.RestTemplate; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import de.tum.in.www1.artemis.AbstractSpringIntegrationIndependentTest; +import de.tum.in.www1.artemis.service.telemetry.TelemetryService; + +@ExtendWith(MockitoExtension.class) +class TelemetryServiceTest extends AbstractSpringIntegrationIndependentTest { + + @Value("${artemis.telemetry.destination}") + private String destination; + + @Autowired + private RestTemplate restTemplate; + + private MockRestServiceServer mockServer; + + private final ObjectMapper mapper = new ObjectMapper(); + + @Autowired + private TelemetryService telemetryService; + + private TelemetryService telemetryServiceSpy; + + @BeforeEach + void init() { + telemetryServiceSpy = spy(telemetryService); + mockServer = MockRestServiceServer.createServer(restTemplate); + telemetryServiceSpy.useTelemetry = true; + } + + @Test + void testSendTelemetry_TelemetryEnabled() throws Exception { + mockServer.expect(ExpectedCount.once(), requestTo(new URI(destination + "/api/telemetry"))).andExpect(method(HttpMethod.POST)) + .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(mapper.writeValueAsString("Success!"))); + telemetryServiceSpy.sendTelemetry(); + mockServer.verify(); + } + + @Test + void testSendTelemetry_TelemetryDisabled() throws Exception { + mockServer.expect(ExpectedCount.never(), requestTo(new URI(destination + "/api/telemetry"))).andExpect(method(HttpMethod.POST)) + .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(mapper.writeValueAsString("Success!"))); + telemetryServiceSpy.useTelemetry = false; + telemetryServiceSpy.sendTelemetry(); + mockServer.verify(); + } + + @Test + void testSendTelemetry_ExceptionHandling() throws Exception { + mockServer.expect(ExpectedCount.once(), requestTo(new URI(destination + "/api/telemetry"))).andExpect(method(HttpMethod.POST)) + .andRespond(withServerError().body(mapper.writeValueAsString("Failure!"))); + telemetryServiceSpy.sendTelemetry(); + mockServer.verify(); + } +} diff --git a/src/test/javascript/spec/component/shared/code-button.component.spec.ts b/src/test/javascript/spec/component/shared/code-button.component.spec.ts index 967f51a4e333..6423338cddbf 100644 --- a/src/test/javascript/spec/component/shared/code-button.component.spec.ts +++ b/src/test/javascript/spec/component/shared/code-button.component.spec.ts @@ -83,6 +83,7 @@ describe('CodeButtonComponent', () => { }, }, theiaPortalURL: 'https://theia-test.k8s.ase.cit.tum.de', + operatorName: 'TUM', }; let participation: ProgrammingExerciseStudentParticipation = new ProgrammingExerciseStudentParticipation(); diff --git a/src/test/javascript/spec/service/profile.service.spec.ts b/src/test/javascript/spec/service/profile.service.spec.ts index cc833e61a7f6..45d63d7f9482 100644 --- a/src/test/javascript/spec/service/profile.service.spec.ts +++ b/src/test/javascript/spec/service/profile.service.spec.ts @@ -145,6 +145,7 @@ describe('ProfileService', () => { }, }, }, + operatorName: 'TUM', theiaPortalURL: 'http://theia-test.k8s.ase.cit.tum.de', }; @@ -261,6 +262,7 @@ describe('ProfileService', () => { }, }, theiaPortalURL: 'http://theia-test.k8s.ase.cit.tum.de', + operatorName: 'TUM', }; beforeEach(() => { diff --git a/src/test/resources/config/application-artemis.yml b/src/test/resources/config/application-artemis.yml index 1bc086c96a92..9cac2ec6dc93 100644 --- a/src/test/resources/config/application-artemis.yml +++ b/src/test/resources/config/application-artemis.yml @@ -62,5 +62,15 @@ artemis: restricted-modules: module_text_test_restricted,module_programming_test_restricted apollon: conversion-service-url: http://localhost:8080 + telemetry: + enabled: true + sendAdminDetails: true + destination: http://localhost:8081 plagiarism-checks: plagiarism-results-limit: 100 + +info: + operatorName: Some Artemis Operator # Must be set before starting the application in production. Shown in the about us page, and sent to the telemetry service + operatorAdminName: Some Universities Admin # Can be set to be shown in the about us page, and to be sent to the telemetry service + contact: admin@uni.de # The admins contact email address, shown in the about us page, and sent to the telemetry service + diff --git a/src/test/resources/config/application.yml b/src/test/resources/config/application.yml index ba0acb609f26..f699af193497 100644 --- a/src/test/resources/config/application.yml +++ b/src/test/resources/config/application.yml @@ -251,6 +251,7 @@ info: # default value set to true for tests text-assessment-analytics-enabled: true student-exam-store-session-data: true + contact: contactEmail@contact.de jhipster: clientApp: From 12fc9827085fe001946557fa8833e944661309e9 Mon Sep 17 00:00:00 2001 From: Stephan Krusche Date: Thu, 5 Sep 2024 17:02:29 +0200 Subject: [PATCH 15/16] Development: Make sure the telemetry service only sends data in non development environments --- .../www1/artemis/service/telemetry/TelemetryService.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/tum/in/www1/artemis/service/telemetry/TelemetryService.java b/src/main/java/de/tum/in/www1/artemis/service/telemetry/TelemetryService.java index af5d464a93f1..7e49653d99d9 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/telemetry/TelemetryService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/telemetry/TelemetryService.java @@ -23,6 +23,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; +import de.tum.in.www1.artemis.service.ProfileService; + @Service @Profile(PROFILE_SCHEDULING) public class TelemetryService { @@ -37,6 +39,8 @@ public record TelemetryData(String version, String serverUrl, String operator, S private final RestTemplate restTemplate; + private final ProfileService profileService; + @Value("${artemis.telemetry.enabled}") public boolean useTelemetry; @@ -61,9 +65,10 @@ public record TelemetryData(String version, String serverUrl, String operator, S @Value("${info.contact}") private String contact; - public TelemetryService(Environment env, RestTemplate restTemplate) { + public TelemetryService(Environment env, RestTemplate restTemplate, ProfileService profileService) { this.env = env; this.restTemplate = restTemplate; + this.profileService = profileService; } /** @@ -73,7 +78,7 @@ public TelemetryService(Environment env, RestTemplate restTemplate) { */ @EventListener(ApplicationReadyEvent.class) public void sendTelemetry() { - if (!useTelemetry) { + if (!useTelemetry || profileService.isDevActive()) { return; } From fd263486eff48958f419be8bcaf403652ef051aa Mon Sep 17 00:00:00 2001 From: Patrik Zander <38403547+pzdr7@users.noreply.github.com> Date: Thu, 5 Sep 2024 23:13:32 +0200 Subject: [PATCH 16/16] Development: Configure telemetry variables for e2e tests (#9288) --- docker/artemis/config/playwright.env | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docker/artemis/config/playwright.env b/docker/artemis/config/playwright.env index c57d79d581c7..a3ee64a57442 100644 --- a/docker/artemis/config/playwright.env +++ b/docker/artemis/config/playwright.env @@ -27,6 +27,8 @@ ARTEMIS_CONTINUOUSINTEGRATION_EMPTYCOMMITNECESSARY="true" ARTEMIS_APOLLON_CONVERSIONSERVICEURL="https://apollon.ase.in.tum.de/api/converter" +ARTEMIS_TELEMETRY_ENABLED="false" + # Token is valid 3 days JHIPSTER_SECURITY_AUTHENTICATION_JWT_TOKENVALIDITYINSECONDS="259200" # Token is valid 30 days @@ -38,6 +40,7 @@ INFO_IMPRINT="https://ase.in.tum.de/lehrstuhl_1/component/content/article/179-im INFO_TESTSERVER="true" INFO_TEXTASSESSMENTANALYTICSENABLED="true" INFO_STUDENTEXAMSTORESESSIONDATA="true" +INFO_OPERATORNAME="TUM" LOGGING_FILE_NAME="/opt/artemis/data/artemis.log"