Allow supervisors to request improvements from final seminar opponents #78
@ -20,7 +20,11 @@ import se.su.dsv.scipro.file.FileUpload;
|
|||||||
import se.su.dsv.scipro.finalseminar.FinalSeminar;
|
import se.su.dsv.scipro.finalseminar.FinalSeminar;
|
||||||
import se.su.dsv.scipro.finalseminar.FinalSeminarOpposition;
|
import se.su.dsv.scipro.finalseminar.FinalSeminarOpposition;
|
||||||
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.IdeaService;
|
||||||
import se.su.dsv.scipro.match.Keyword;
|
import se.su.dsv.scipro.match.Keyword;
|
||||||
|
import se.su.dsv.scipro.match.Target;
|
||||||
|
import se.su.dsv.scipro.match.TholanderBox;
|
||||||
import se.su.dsv.scipro.milestones.dataobjects.MilestoneActivityTemplate;
|
import se.su.dsv.scipro.milestones.dataobjects.MilestoneActivityTemplate;
|
||||||
import se.su.dsv.scipro.milestones.dataobjects.MilestonePhaseTemplate;
|
import se.su.dsv.scipro.milestones.dataobjects.MilestonePhaseTemplate;
|
||||||
import se.su.dsv.scipro.milestones.service.MilestoneActivityTemplateService;
|
import se.su.dsv.scipro.milestones.service.MilestoneActivityTemplateService;
|
||||||
@ -37,6 +41,7 @@ import se.su.dsv.scipro.reviewing.ReviewerAssignmentService;
|
|||||||
import se.su.dsv.scipro.reviewing.RoughDraftApprovalService;
|
import se.su.dsv.scipro.reviewing.RoughDraftApprovalService;
|
||||||
import se.su.dsv.scipro.security.auth.roles.Roles;
|
import se.su.dsv.scipro.security.auth.roles.Roles;
|
||||||
import se.su.dsv.scipro.system.*;
|
import se.su.dsv.scipro.system.*;
|
||||||
|
import se.su.dsv.scipro.util.Pair;
|
||||||
|
|
||||||
public class DataInitializer implements Lifecycle {
|
public class DataInitializer implements Lifecycle {
|
||||||
|
|
||||||
@ -51,6 +56,9 @@ public class DataInitializer implements Lifecycle {
|
|||||||
@Inject
|
@Inject
|
||||||
private PasswordService passwordService;
|
private PasswordService passwordService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private IdeaService ideaService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private MilestoneActivityTemplateService milestoneActivityTemplateService;
|
private MilestoneActivityTemplateService milestoneActivityTemplateService;
|
||||||
|
|
||||||
@ -94,14 +102,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 Program program;
|
||||||
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 project1;
|
private Project project1;
|
||||||
private Project project2;
|
private Project project2;
|
||||||
|
|
||||||
@ -111,13 +124,17 @@ 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();
|
||||||
createKeywordsIfNotDone();
|
createKeywordsIfNotDone();
|
||||||
createMilestonesIfNotDone();
|
createMilestonesIfNotDone();
|
||||||
createUsers();
|
createUsers();
|
||||||
|
createMatchedIdea();
|
||||||
createProjects();
|
createProjects();
|
||||||
|
createTarget();
|
||||||
|
createStudentIdea();
|
||||||
createRoughDraftApproval();
|
createRoughDraftApproval();
|
||||||
createPastFinalSeminar();
|
createPastFinalSeminar();
|
||||||
setUpNotifications();
|
setUpNotifications();
|
||||||
@ -175,27 +192,36 @@ 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 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));
|
||||||
applicationPeriod.setEndDate(LocalDate.now().plusDays(APPLICATION_PERIOD_END_PLUS_DAYS));
|
applicationPeriod.setEndDate(LocalDate.now().plusDays(APPLICATION_PERIOD_END_PLUS_DAYS));
|
||||||
applicationPeriod.setCourseStartDate(LocalDate.now().plusDays(APPLICATION_PERIOD_COURSE_START_PLUS_DAYS));
|
applicationPeriod.setCourseStartDate(LocalDate.now().plusDays(APPLICATION_PERIOD_COURSE_START_PLUS_DAYS));
|
||||||
applicationPeriod.setCourseStartTime(LocalTime.of(8, 0));
|
applicationPeriod.setCourseStartTime(LocalTime.of(8, 0));
|
||||||
applicationPeriod = save(applicationPeriod);
|
applicationPeriod = save(applicationPeriod);
|
||||||
applicationPeriod.setProjectTypes(new HashSet<>(Collections.singletonList(bachelorClass)));
|
applicationPeriod.setProjectTypes(new HashSet<>(Set.of(bachelorClass, masterClass)));
|
||||||
save(applicationPeriod);
|
save(applicationPeriod);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createKeywordsIfNotDone() {
|
private void createKeywordsIfNotDone() {
|
||||||
Keyword 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() {
|
||||||
@ -251,6 +277,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) {
|
||||||
@ -269,8 +300,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) {
|
||||||
@ -322,12 +356,54 @@ public class DataInitializer implements Lifecycle {
|
|||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createMatchedIdea() {
|
||||||
|
Idea idea = new Idea();
|
||||||
|
idea.setApplicationPeriod(applicationPeriod);
|
||||||
|
idea.setType(Idea.Type.SUPERVISOR);
|
||||||
|
idea.setProjectType(masterClass);
|
||||||
|
idea.setTitle("Idea without first meeting");
|
||||||
|
idea.setDescription("Explore the deep sea");
|
||||||
|
idea.setPrerequisites("Diving experience");
|
||||||
|
idea.setResearchArea(researchArea1);
|
||||||
|
idea.setPublished(true);
|
||||||
|
Idea saved = ideaService.saveSupervisorIdea(idea, eve_employee, new ArrayList<>(Set.of(keyword1)), true);
|
||||||
|
Pair<Boolean, String> validated = ideaService.validateAdminAddAuthors(saved, Set.of(sid_student));
|
||||||
|
assert validated.getHead();
|
||||||
|
ideaService.setAuthors(saved, Set.of(sid_student), eve_employee);
|
||||||
|
}
|
||||||
|
|
||||||
private void createGradingCriterionTemplateIfNotDone() {
|
private void createGradingCriterionTemplateIfNotDone() {
|
||||||
save(getBachelorTemplate());
|
save(getBachelorTemplate());
|
||||||
save(getMasterTemplate());
|
save(getMasterTemplate());
|
||||||
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,
|
||||||
|
@ -169,7 +169,11 @@ public class FirstMeetingPanel extends GenericPanel<Idea> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void saveAndNotify() {
|
private void saveAndNotify() {
|
||||||
firstMeetingRepository.save(getModelObject());
|
FirstMeeting saved = firstMeetingRepository.save(getModelObject());
|
||||||
|
// After saving the first meeting we have to populate it on the already loaded idea to
|
||||||
|
// make sure that other places that want to render the first meeting get the correct data.
|
||||||
|
// An alternative would be to detach the idea model to force a database refresh.
|
||||||
|
FirstMeetingPanel.this.getModelObject().setFirstMeeting(saved);
|
||||||
NotificationSource source = new NotificationSource();
|
NotificationSource source = new NotificationSource();
|
||||||
String date = dateService.format(getModelObject().getFirstMeetingDate(), DateStyle.DATETIME);
|
String date = dateService.format(getModelObject().getFirstMeetingDate(), DateStyle.DATETIME);
|
||||||
String room = getModelObject().getRoom();
|
String room = getModelObject().getRoom();
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
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());
|
||||||
|
@ -337,29 +337,26 @@ public class SupervisorMyIdeasPanel extends Panel {
|
|||||||
if (idea.getMatch() == null) {
|
if (idea.getMatch() == null) {
|
||||||
return "-";
|
return "-";
|
||||||
}
|
}
|
||||||
switch (idea.getMatchStatus()) {
|
return switch (idea.getMatchStatus()) {
|
||||||
case UNMATCHED:
|
case UNMATCHED -> getString("status.unmatched");
|
||||||
return getString("status.unmatched");
|
case COMPLETED -> getString("status.completed");
|
||||||
case COMPLETED:
|
case INACTIVE -> getString("status.inactive");
|
||||||
return getString("status.completed");
|
case MATCHED -> {
|
||||||
case INACTIVE:
|
|
||||||
return getString("status.inactive");
|
|
||||||
case MATCHED:
|
|
||||||
if (applicationPeriodService.courseStartHasPassed(idea.getApplicationPeriod())) {
|
if (applicationPeriodService.courseStartHasPassed(idea.getApplicationPeriod())) {
|
||||||
if (idea.isExported()) {
|
if (idea.isExported()) {
|
||||||
if (idea.wasExportSuccessful()) {
|
if (idea.wasExportSuccessful()) {
|
||||||
return getString("status.project.created");
|
yield getString("status.project.created");
|
||||||
} else {
|
} else {
|
||||||
return getString("status.export.failed");
|
yield getString("status.export.failed");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return getString("status.awaiting.project.creation");
|
yield getString("status.awaiting.project.creation");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return getString("status.awaiting.course.start", Model.of(idea.getApplicationPeriod()));
|
yield getString("status.awaiting.course.start", Model.of(idea.getApplicationPeriod()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "-"; // can't happen
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user