Assign supervisor to student ideas no matter if target (goal) is reached #96

Merged
ansv7779 merged 12 commits from 67-supervisor-target-non-blocking into develop 2025-02-18 09:59:24 +01:00
4 changed files with 92 additions and 18 deletions
core/src/main/java/se/su/dsv/scipro
view/src/main
java/se/su/dsv/scipro/match
webapp/css
war/src/main/resources

@ -13,6 +13,7 @@ import java.util.*;
import java.util.function.Function; import java.util.function.Function;
import se.su.dsv.scipro.checklist.ChecklistCategory; import se.su.dsv.scipro.checklist.ChecklistCategory;
import se.su.dsv.scipro.file.FileUpload; import se.su.dsv.scipro.file.FileUpload;
import se.su.dsv.scipro.match.*;
import se.su.dsv.scipro.match.ApplicationPeriod; import se.su.dsv.scipro.match.ApplicationPeriod;
import se.su.dsv.scipro.match.Idea; import se.su.dsv.scipro.match.Idea;
import se.su.dsv.scipro.match.IdeaService; import se.su.dsv.scipro.match.IdeaService;
@ -85,16 +86,19 @@ public class DataInitializer implements Lifecycle {
private User stina_student; private User stina_student;
private User sid_student; private User sid_student;
private User simon_student; private User simon_student;
private ProjectType bachelorClass; private User sofia_student;
private Set<ResearchArea> researchAreas; private Set<ResearchArea> researchAreas;
private Long researchAreaId = RESEARCH_AREA_ID; private Long researchAreaId = RESEARCH_AREA_ID;
private Set<Language> languages; private Set<Language> languages = Set.of(Language.SWEDISH, Language.ENGLISH);
private ApplicationPeriod applicationPeriod; private Program program;
private Keyword keyword1;
private ResearchArea researchArea1; private ResearchArea researchArea1;
private ResearchArea researchArea2; private ResearchArea researchArea2;
private Keyword keyword1;
private Keyword keyword2;
private ProjectType bachelorClass;
private ProjectType masterClass; private ProjectType masterClass;
private ProjectType magisterClass; private ProjectType magisterClass;
private ApplicationPeriod applicationPeriod;
private Project project2; private Project project2;
@Transactional @Transactional
@ -103,6 +107,7 @@ public class DataInitializer implements Lifecycle {
if (profile.getCurrentProfile() == Profiles.DEV && noUsers()) { if (profile.getCurrentProfile() == Profiles.DEV && noUsers()) {
createDefaultProjectTypesIfNotDone(); createDefaultProjectTypesIfNotDone();
createDefaultChecklistCategoriesIfNotDone(); createDefaultChecklistCategoriesIfNotDone();
createProgram();
createApplicationPeriodIfNotDone(); createApplicationPeriodIfNotDone();
createGradingCriterionTemplateIfNotDone(); createGradingCriterionTemplateIfNotDone();
createResearchAreasForDemo(); createResearchAreasForDemo();
@ -111,6 +116,8 @@ public class DataInitializer implements Lifecycle {
createUsers(); createUsers();
createMatchedIdea(); createMatchedIdea();
createProjects(); createProjects();
createTarget();
createStudentIdea();
createRoughDraftApproval(); createRoughDraftApproval();
} }
if (profile.getCurrentProfile() == Profiles.DEV && noAdminUser()) { if (profile.getCurrentProfile() == Profiles.DEV && noAdminUser()) {
@ -135,6 +142,15 @@ public class DataInitializer implements Lifecycle {
return userService.findByUsername(ADMIN + MAIL) == null; return userService.findByUsername(ADMIN + MAIL) == null;
} }
private void createProgram() {
program = new Program();
program.setCode("AppCompSci");
program.setName("Tillämpad Datavetenskap");
program.setExternalId(123);
program.setNameEn("Applied Computer Science");
program = save(program);
}
private void createApplicationPeriodIfNotDone() { private void createApplicationPeriodIfNotDone() {
applicationPeriod = new ApplicationPeriod("HT 2014"); applicationPeriod = new ApplicationPeriod("HT 2014");
applicationPeriod.setStartDate(LocalDate.now().minusDays(APPLICATION_PERIOD_START_MINUS_DAYS)); applicationPeriod.setStartDate(LocalDate.now().minusDays(APPLICATION_PERIOD_START_MINUS_DAYS));
@ -150,12 +166,12 @@ public class DataInitializer implements Lifecycle {
keyword1 = new Keyword("IT"); keyword1 = new Keyword("IT");
keyword1.addResearchArea(researchArea1); keyword1.addResearchArea(researchArea1);
keyword1.addResearchArea(researchArea2); keyword1.addResearchArea(researchArea2);
save(keyword1); keyword1 = save(keyword1);
Keyword keyword2 = new Keyword("Computers"); keyword2 = new Keyword("Computers");
keyword2.addResearchArea(researchArea1); keyword2.addResearchArea(researchArea1);
keyword2.addResearchArea(researchArea2); keyword2.addResearchArea(researchArea2);
save(keyword2); keyword2 = save(keyword2);
} }
private void createResearchAreasForDemo() { private void createResearchAreasForDemo() {
@ -211,6 +227,11 @@ public class DataInitializer implements Lifecycle {
// can not be used as author on any idea // can not be used as author on any idea
// can not be used as author on any project // can not be used as author on any project
createStudent("Stig"); createStudent("Stig");
// Used to test assign supervisor to student idea
// this student has a submitted idea, which has not assigned supervisor
// don't use this student for anything else
sofia_student = createStudent("Sofia");
} }
private User createStudent(String firstName) { private User createStudent(String firstName) {
@ -229,8 +250,11 @@ public class DataInitializer implements Lifecycle {
user.setUnit(u); user.setUnit(u);
user.setResearchAreas(researchAreas); user.setResearchAreas(researchAreas);
user.setLanguages(languages); user.setLanguages(languages);
user.setActiveAsSupervisor(true);
createBeta(user); createBeta(user);
return user;
return save(user);
} }
private User createUser(String firstName, String lastName) { private User createUser(String firstName, String lastName) {
@ -304,6 +328,32 @@ public class DataInitializer implements Lifecycle {
save(getMagisterTemplate()); save(getMagisterTemplate());
} }
private void createTarget() {
Target target = new Target(eric_employee, applicationPeriod, bachelorClass);
target.setTarget(10);
save(target);
}
private void createStudentIdea() {
Idea idea = new Idea();
idea.setTitle("Fundamental Math Concepts of AI");
idea.setType(Idea.Type.STUDENT);
TholanderBox box = new TholanderBox();
box.setLiterature("Math AI Literature");
box.setBackground("Math AI Background");
box.setProblem("Math AI Problem");
box.setMethod("Math AI Method");
box.setInterests("Math AI Interests");
idea.setTholanderBox(box);
idea.setProjectType(bachelorClass);
idea.setApplicationPeriod(applicationPeriod);
List<Keyword> keywords = List.of(keyword1, keyword2);
ideaService.saveStudentIdea(idea, sofia_student, program, new HashSet<User>(), keywords, true);
}
private GradingReportTemplate getBachelorTemplate() { private GradingReportTemplate getBachelorTemplate() {
GradingReportTemplate gradingReportTemplate = new GradingReportTemplate( GradingReportTemplate gradingReportTemplate = new GradingReportTemplate(
bachelorClass, bachelorClass,

@ -205,17 +205,34 @@ public abstract class AbstractAdminIdeaPanel extends Panel {
ideaService.adminUnmatchIdea(idea, SciProSession.get().getUser()); ideaService.adminUnmatchIdea(idea, SciProSession.get().getUser());
info("Unmatched idea: " + idea.getTitle()); info("Unmatched idea: " + idea.getTitle());
} else { } else {
if ( ideaService.changeSupervisor(idea, newSelection, SciProSession.get().getUser());
targetService.hasTargetsLeft(
idea.getApplicationPeriod(), Target currentTarget = targetService.findOne(
newSelection, idea.getApplicationPeriod(),
idea.getProjectType() newSelection,
) idea.getProjectType()
) { );
ideaService.changeSupervisor(idea, newSelection, SciProSession.get().getUser()); Long countMatched = ideaService.countMatched(
info("Supervisor changed"); idea.getApplicationPeriod(),
newSelection,
idea.getProjectType()
);
int targetCounter = (currentTarget == null) ? 0 : currentTarget.getTarget();
ansv7779 marked this conversation as resolved
Review

This seems weird, a count method should return 0 not null.

This seems weird, a count method should return 0 not `null`.
Review

Fine point, the unnecessary null check has been removed.

The rationale for null check is that ideaService.countMatched returning Long. It would be better that a @NotNull annotation is applied to such method which is guaranteed to return non null object.

Fine point, the unnecessary null check has been removed. The rationale for null check is that ideaService.countMatched returning Long. It would be better that a @NotNull annotation is applied to such method which is guaranteed to return non null object.
String msg =
"Supervisor changed: matched/target -> " +
countMatched +
" / " +
targetCounter +
" (" +
idea.getProjectType().getName() +
")";
if (countMatched > targetCounter) {
warn(msg);
} else { } else {
error("The supervisor have reached current target numbers"); info(msg);
} }
} }
target.addListener(new AjaxFeedbackPanelUpdater()); target.addListener(new AjaxFeedbackPanelUpdater());

@ -129,6 +129,12 @@ footer a:hover { color: #d95e00;}
border-color: #EBCCD1; border-color: #EBCCD1;
} }
.feedbackPanelWARNING {
color: #000000;
background-color: #FFD105;
border-color: #EBCCD1;
}
.feedbackPanelINFO { .feedbackPanelINFO {
color: #3C763D; color: #3C763D;
background-color: #DFF0D8; background-color: #DFF0D8;

@ -9,6 +9,7 @@ spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.Ph
# We also need to set the implicit strategy to be JPA compliant, as we rely on this naming strategy for certain # We also need to set the implicit strategy to be JPA compliant, as we rely on this naming strategy for certain
# join tables (idea_Keyword vs idea_keyword) # join tables (idea_Keyword vs idea_keyword)
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl
spring.jpa.show-sql=false
spring.mvc.servlet.path=/api spring.mvc.servlet.path=/api