From 2842b64302975301bb27e3a08984ad44809f808d Mon Sep 17 00:00:00 2001
From: Andreas Svanberg <andreass@dsv.su.se>
Date: Wed, 5 Mar 2025 14:11:03 +0100
Subject: [PATCH 1/5] Test verifying project type validation on author idea
 selection

---
 .../se/su/dsv/scipro/match/IdeaServiceImplTest.java   | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/core/src/test/java/se/su/dsv/scipro/match/IdeaServiceImplTest.java b/core/src/test/java/se/su/dsv/scipro/match/IdeaServiceImplTest.java
index 6365ba546a..ecc908e50a 100755
--- a/core/src/test/java/se/su/dsv/scipro/match/IdeaServiceImplTest.java
+++ b/core/src/test/java/se/su/dsv/scipro/match/IdeaServiceImplTest.java
@@ -401,6 +401,17 @@ public class IdeaServiceImplTest {
         assertEquals(expected, ideaService.countAuthorsByApplicationPeriod(applicationPeriod, params));
     }
 
+    @Test
+    public void wrong_type_for_author() {
+        when(applicationPeriodService.getTypesForStudent(applicationPeriod, student)).thenReturn(List.of(master));
+
+        assertPair(
+            false,
+            "The idea is the wrong level for you, please pick another one.",
+            ideaService.validateStudentAcceptance(createBachelorIdea(Idea.Status.UNMATCHED), student, coAuthor, applicationPeriod)
+        );
+    }
+
     private Idea mockInactiveIdea() {
         Idea idea = new Idea();
         Match match = new Match();
-- 
2.39.5


From 50c16b49118a6cb01684771cd6f2705a929d75a3 Mon Sep 17 00:00:00 2001
From: Andreas Svanberg <andreass@dsv.su.se>
Date: Wed, 5 Mar 2025 14:21:45 +0100
Subject: [PATCH 2/5] Make project type exemption apply to partner as well when
 selecting supervisor ideas

---
 .../se/su/dsv/scipro/match/IdeaServiceImpl.java     |  6 ++----
 .../se/su/dsv/scipro/match/IdeaServiceImplTest.java | 13 +++++++++++++
 2 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/core/src/main/java/se/su/dsv/scipro/match/IdeaServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/match/IdeaServiceImpl.java
index 08845a8a3f..2e97a2b07a 100755
--- a/core/src/main/java/se/su/dsv/scipro/match/IdeaServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/match/IdeaServiceImpl.java
@@ -235,10 +235,8 @@ public class IdeaServiceImpl extends AbstractServiceImpl<Idea, Long> implements
             if (authorParticipatingOnActiveIdea(coAuthor, ap)) {
                 return new Pair<>(Boolean.FALSE, PARTNER_ALREADY_PARTICIPATING_ERROR);
             }
-            if (
-                coAuthor.getDegreeType() != ProjectType.UNKNOWN &&
-                coAuthor.getDegreeType() != idea.getProjectType().getDegreeType()
-            ) {
+            List<ProjectType> typesForCoAuthor = applicationPeriodService.getTypesForStudent(ap, coAuthor);
+            if (!typesForCoAuthor.contains(idea.getProjectType())) {
                 return new Pair<>(Boolean.FALSE, WRONG_LEVEL_FOR_YOUR_PARTNER);
             }
             if (!projectService.getActiveProjectsByUserAndProjectType(coAuthor, idea.getProjectType()).isEmpty()) {
diff --git a/core/src/test/java/se/su/dsv/scipro/match/IdeaServiceImplTest.java b/core/src/test/java/se/su/dsv/scipro/match/IdeaServiceImplTest.java
index ecc908e50a..301e041a03 100755
--- a/core/src/test/java/se/su/dsv/scipro/match/IdeaServiceImplTest.java
+++ b/core/src/test/java/se/su/dsv/scipro/match/IdeaServiceImplTest.java
@@ -241,6 +241,7 @@ public class IdeaServiceImplTest {
         when(generalSystemSettingsService.getGeneralSystemSettingsInstance()).thenReturn(new GeneralSystemSettings());
         Idea idea = createBachelorIdea(Idea.Status.UNMATCHED);
         when(applicationPeriodService.getTypesForStudent(applicationPeriod, student)).thenReturn(List.of(bachelor));
+        when(applicationPeriodService.getTypesForStudent(applicationPeriod, coAuthor)).thenReturn(List.of(bachelor));
 
         Pair<Boolean, String> acceptance = ideaService.validateStudentAcceptance(
             idea,
@@ -404,6 +405,7 @@ public class IdeaServiceImplTest {
     @Test
     public void wrong_type_for_author() {
         when(applicationPeriodService.getTypesForStudent(applicationPeriod, student)).thenReturn(List.of(master));
+        when(applicationPeriodService.getTypesForStudent(applicationPeriod, coAuthor)).thenReturn(List.of(bachelor));
 
         assertPair(
             false,
@@ -412,6 +414,17 @@ public class IdeaServiceImplTest {
         );
     }
 
+    @Test
+    public void wrong_type_for_partner() {
+        when(applicationPeriodService.getTypesForStudent(applicationPeriod, coAuthor)).thenReturn(List.of(master));
+
+        assertPair(
+            false,
+            "The idea is the wrong level for your partner, please pick another one.",
+            ideaService.validateStudentAcceptance(createBachelorIdea(Idea.Status.UNMATCHED), student, coAuthor, applicationPeriod)
+        );
+    }
+
     private Idea mockInactiveIdea() {
         Idea idea = new Idea();
         Match match = new Match();
-- 
2.39.5


From 21390b5f8aab16e149d43269fde5d60aac93af4f Mon Sep 17 00:00:00 2001
From: Andreas Svanberg <andreass@dsv.su.se>
Date: Wed, 5 Mar 2025 14:33:24 +0100
Subject: [PATCH 3/5] Formatting

---
 .../su/dsv/scipro/match/IdeaServiceImplTest.java   | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/core/src/test/java/se/su/dsv/scipro/match/IdeaServiceImplTest.java b/core/src/test/java/se/su/dsv/scipro/match/IdeaServiceImplTest.java
index 301e041a03..871ea15351 100755
--- a/core/src/test/java/se/su/dsv/scipro/match/IdeaServiceImplTest.java
+++ b/core/src/test/java/se/su/dsv/scipro/match/IdeaServiceImplTest.java
@@ -410,7 +410,12 @@ public class IdeaServiceImplTest {
         assertPair(
             false,
             "The idea is the wrong level for you, please pick another one.",
-            ideaService.validateStudentAcceptance(createBachelorIdea(Idea.Status.UNMATCHED), student, coAuthor, applicationPeriod)
+            ideaService.validateStudentAcceptance(
+                createBachelorIdea(Idea.Status.UNMATCHED),
+                student,
+                coAuthor,
+                applicationPeriod
+            )
         );
     }
 
@@ -421,7 +426,12 @@ public class IdeaServiceImplTest {
         assertPair(
             false,
             "The idea is the wrong level for your partner, please pick another one.",
-            ideaService.validateStudentAcceptance(createBachelorIdea(Idea.Status.UNMATCHED), student, coAuthor, applicationPeriod)
+            ideaService.validateStudentAcceptance(
+                createBachelorIdea(Idea.Status.UNMATCHED),
+                student,
+                coAuthor,
+                applicationPeriod
+            )
         );
     }
 
-- 
2.39.5


From bce2e27f5db07a54ad19c93df38f01dcde988d14 Mon Sep 17 00:00:00 2001
From: Andreas Svanberg <andreass@dsv.su.se>
Date: Thu, 6 Mar 2025 12:51:49 +0100
Subject: [PATCH 4/5] Add test data

---
 .../se/su/dsv/scipro/testdata/BaseData.java   | 10 +++
 .../dsv/scipro/testdata/DataInitializer.java  |  5 ++
 .../populators/PartnerTypeException.java      | 68 +++++++++++++++++++
 3 files changed, 83 insertions(+)
 create mode 100644 test-data/src/main/java/se/su/dsv/scipro/testdata/populators/PartnerTypeException.java

diff --git a/test-data/src/main/java/se/su/dsv/scipro/testdata/BaseData.java b/test-data/src/main/java/se/su/dsv/scipro/testdata/BaseData.java
index 1dd6b18132..56bb1313a4 100644
--- a/test-data/src/main/java/se/su/dsv/scipro/testdata/BaseData.java
+++ b/test-data/src/main/java/se/su/dsv/scipro/testdata/BaseData.java
@@ -1,6 +1,9 @@
 package se.su.dsv.scipro.testdata;
 
+import java.util.List;
+import se.su.dsv.scipro.match.Keyword;
 import se.su.dsv.scipro.system.ProjectType;
+import se.su.dsv.scipro.system.ResearchArea;
 
 /// All the base test data that can be re-used in different test cases.
 ///
@@ -16,4 +19,11 @@ public interface BaseData {
     ProjectType bachelor();
     ProjectType magister();
     ProjectType master();
+
+    /**
+     * @return generic research area with some keywords attached to it
+     */
+    ResearchAreaAndKeywords researchArea();
+
+    record ResearchAreaAndKeywords(ResearchArea researchArea, List<Keyword> keywords) {}
 }
diff --git a/test-data/src/main/java/se/su/dsv/scipro/testdata/DataInitializer.java b/test-data/src/main/java/se/su/dsv/scipro/testdata/DataInitializer.java
index cf01ab2315..c12cb602b2 100644
--- a/test-data/src/main/java/se/su/dsv/scipro/testdata/DataInitializer.java
+++ b/test-data/src/main/java/se/su/dsv/scipro/testdata/DataInitializer.java
@@ -2193,6 +2193,11 @@ public class DataInitializer implements Lifecycle, BaseData, Factory {
         return createEmployee(firstName);
     }
 
+    @Override
+    public ResearchAreaAndKeywords researchArea() {
+        return new ResearchAreaAndKeywords(researchArea1, List.of(keyword1, keyword2));
+    }
+
     private static final class SimpleTextFile implements FileUpload {
 
         private final User uploader;
diff --git a/test-data/src/main/java/se/su/dsv/scipro/testdata/populators/PartnerTypeException.java b/test-data/src/main/java/se/su/dsv/scipro/testdata/populators/PartnerTypeException.java
new file mode 100644
index 0000000000..1cdc6de604
--- /dev/null
+++ b/test-data/src/main/java/se/su/dsv/scipro/testdata/populators/PartnerTypeException.java
@@ -0,0 +1,68 @@
+package se.su.dsv.scipro.testdata.populators;
+
+import jakarta.inject.Inject;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.Set;
+import org.springframework.stereotype.Service;
+import se.su.dsv.scipro.match.ApplicationPeriod;
+import se.su.dsv.scipro.match.ApplicationPeriodService;
+import se.su.dsv.scipro.match.Idea;
+import se.su.dsv.scipro.match.IdeaService;
+import se.su.dsv.scipro.match.Target;
+import se.su.dsv.scipro.match.TargetService;
+import se.su.dsv.scipro.system.User;
+import se.su.dsv.scipro.testdata.BaseData;
+import se.su.dsv.scipro.testdata.Factory;
+import se.su.dsv.scipro.testdata.TestDataPopulator;
+
+@Service
+public class PartnerTypeException implements TestDataPopulator {
+
+    private final ApplicationPeriodService applicationPeriodService;
+    private final IdeaService ideaService;
+    private final TargetService targetService;
+
+    @Inject
+    public PartnerTypeException(
+        ApplicationPeriodService applicationPeriodService,
+        IdeaService ideaService,
+        TargetService targetService
+    ) {
+        this.applicationPeriodService = applicationPeriodService;
+        this.ideaService = ideaService;
+        this.targetService = targetService;
+    }
+
+    @Override
+    public void populate(BaseData baseData, Factory factory) {
+        factory.createAuthor("Oskar");
+
+        User johan = factory.createAuthor("Johan");
+        johan.setDegreeType(baseData.master().getDegreeType());
+
+        User supervisor = factory.createSupervisor("Elsa");
+
+        ApplicationPeriod applicationPeriod = new ApplicationPeriod("Supervisor ideas");
+        applicationPeriod.setStartDate(LocalDate.now());
+        applicationPeriod.setEndDate(LocalDate.now().plusDays(14));
+        applicationPeriod.setCourseStartDateTime(LocalDateTime.now().plusDays(15));
+        applicationPeriod.setProjectTypes(Set.of(baseData.bachelor()));
+        applicationPeriodService.save(applicationPeriod);
+
+        Target target = targetService.findOne(applicationPeriod, supervisor, baseData.bachelor());
+        target.setTarget(10);
+        targetService.save(target);
+
+        Idea idea = new Idea();
+        idea.setPublished(true);
+        idea.setTitle("The next gen AI 2.0 turbo edition");
+        idea.setPrerequisites("Hacker experience");
+        idea.setDescription("Better than all the rest");
+        idea.setProjectType(baseData.bachelor());
+        idea.setApplicationPeriod(applicationPeriod);
+        idea.setResearchArea(baseData.researchArea().researchArea());
+
+        ideaService.saveSupervisorIdea(idea, supervisor, baseData.researchArea().keywords(), true);
+    }
+}
-- 
2.39.5


From d3d83269e2e0f2eb1fdc90e059b15c3fbb1ff5b7 Mon Sep 17 00:00:00 2001
From: Andreas Svanberg <andreass@dsv.su.se>
Date: Fri, 7 Mar 2025 18:48:15 +0100
Subject: [PATCH 5/5] Exception should be Exemption

---
 .../{PartnerTypeException.java => PartnerTypeExemption.java}  | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
 rename test-data/src/main/java/se/su/dsv/scipro/testdata/populators/{PartnerTypeException.java => PartnerTypeExemption.java} (96%)

diff --git a/test-data/src/main/java/se/su/dsv/scipro/testdata/populators/PartnerTypeException.java b/test-data/src/main/java/se/su/dsv/scipro/testdata/populators/PartnerTypeExemption.java
similarity index 96%
rename from test-data/src/main/java/se/su/dsv/scipro/testdata/populators/PartnerTypeException.java
rename to test-data/src/main/java/se/su/dsv/scipro/testdata/populators/PartnerTypeExemption.java
index 1cdc6de604..c490d0b069 100644
--- a/test-data/src/main/java/se/su/dsv/scipro/testdata/populators/PartnerTypeException.java
+++ b/test-data/src/main/java/se/su/dsv/scipro/testdata/populators/PartnerTypeExemption.java
@@ -17,14 +17,14 @@ import se.su.dsv.scipro.testdata.Factory;
 import se.su.dsv.scipro.testdata.TestDataPopulator;
 
 @Service
-public class PartnerTypeException implements TestDataPopulator {
+public class PartnerTypeExemption implements TestDataPopulator {
 
     private final ApplicationPeriodService applicationPeriodService;
     private final IdeaService ideaService;
     private final TargetService targetService;
 
     @Inject
-    public PartnerTypeException(
+    public PartnerTypeExemption(
         ApplicationPeriodService applicationPeriodService,
         IdeaService ideaService,
         TargetService targetService
-- 
2.39.5