87: Add initial support of parent-child project

This commit is contained in:
Tom Zhao 2025-03-26 12:57:18 +01:00
parent 02dc062962
commit 6526dc1fd9
4 changed files with 60 additions and 9 deletions
core/src/main
view/src/main/java/se/su/dsv/scipro/admin/pages

@ -113,6 +113,14 @@ public class Project extends DomainObject {
@Column(name = "daisy_identifier", unique = true) @Column(name = "daisy_identifier", unique = true)
private Integer identifier; private Integer identifier;
@Basic
@Column(name = "parent_project_id")
private Long parentProjectId;
@Basic
@Column(name = "root_project_id")
private Long rootProjectId;
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
// Embedded JPA-mapping // Embedded JPA-mapping
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
@ -365,6 +373,22 @@ public class Project extends DomainObject {
this.userNotes = userNotes; this.userNotes = userNotes;
} }
public Long getParentProjectId() {
return parentProjectId;
}
public void setParentProjectId(Long parentProjectId) {
this.parentProjectId = parentProjectId;
}
public Long getRootProjectId() {
return rootProjectId;
}
public void setRootProjectId(Long rootProjectId) {
this.rootProjectId = rootProjectId;
}
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
// Methods Common To All Objects // Methods Common To All Objects
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------

@ -1,6 +1,7 @@
package se.su.dsv.scipro.project.split; package se.su.dsv.scipro.project.split;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import se.su.dsv.scipro.finalseminar.FinalSeminarService; import se.su.dsv.scipro.finalseminar.FinalSeminarService;
import se.su.dsv.scipro.project.Project; import se.su.dsv.scipro.project.Project;
import se.su.dsv.scipro.project.ProjectService; import se.su.dsv.scipro.project.ProjectService;
@ -22,6 +23,7 @@ public class SplitOrRestartProjectServiceImpl implements SplitOrRestartProjectSe
} }
@Override @Override
@Transactional
public Pair<SplittableStatus, Project> getSplittableStatus(long projectId) { public Pair<SplittableStatus, Project> getSplittableStatus(long projectId) {
Project project = projectService.findOne(projectId); Project project = projectService.findOne(projectId);
if (project == null) if (project == null)
@ -43,6 +45,7 @@ public class SplitOrRestartProjectServiceImpl implements SplitOrRestartProjectSe
} }
@Override @Override
@Transactional
public void splitProject(long projectId) { public void splitProject(long projectId) {
Pair<SplittableStatus, Project> result = getSplittableStatus(projectId); Pair<SplittableStatus, Project> result = getSplittableStatus(projectId);
if (result.getHead() != SplittableStatus.OK) { if (result.getHead() != SplittableStatus.OK) {
@ -52,35 +55,38 @@ public class SplitOrRestartProjectServiceImpl implements SplitOrRestartProjectSe
Project project = result.getTail(); Project project = result.getTail();
// Todo: Get ev. Phase Two Approval
for (User author : project.getProjectParticipants()) { for (User author : project.getProjectParticipants()) {
Project childProject = new Project(); Project childProject = new Project();
childProject.setTitle(project.getTitle()); childProject.setTitle(project.getTitle());
childProject.setProjectType(project.getProjectType()); childProject.setProjectType(project.getProjectType());
childProject.setProjectStatus(ProjectStatus.ACTIVE);
childProject.setResearchArea(project.getResearchArea());
childProject.setStartDate(project.getStartDate()); childProject.setStartDate(project.getStartDate());
childProject.setExpectedEndDate(project.getExpectedEndDate()); childProject.setExpectedEndDate(project.getExpectedEndDate());
// Copy supervisor childProject.setHeadSupervisor(project.getHeadSupervisor());
childProject.setProjectParticipants(List.of(author)); childProject.setProjectParticipants(List.of(author));
// Copy reviewer childProject.setCoSupervisors(project.getCoSupervisors());
// Copy cosupervisor
// Copy research area
childProject.setProjectStatus(ProjectStatus.ACTIVE); childProject.setReviewers(project.getReviewers());
// childProject.setParentProjectId childProject.setParentProjectId(project.getId());
// childProject.setRootProjectId childProject.setRootProjectId(project.getRootProjectId() != null ? project.getRootProjectId() :
project.getId());
childProject = projectService.save(childProject); childProject = projectService.save(childProject);
// Send event to eventBus to synchronize eventual Phase Two Approval // Todo: Send event to eventBus to synchronize eventual Phase Two Approval
} }
// Parent project will set as inactive // Parent project will set as inactive
project.setProjectStatus(ProjectStatus.INACTIVE); project.setProjectStatus(ProjectStatus.INACTIVE);
projectService.save(project); projectService.save(project);
System.out.println("Hello, split project -> " + projectId); System.out.println("Hello, split project -> " + projectId);
} }
} }

@ -0,0 +1,16 @@
alter table `project`
add column `parent_project_id` bigint(20) null default null;
alter table `project`
add column `root_project_id` bigint(20) null default null;
alter table `project`
add constraint fk_project_parent_project_id_project_id
foreign key (parent_project_id) references project(id)
on delete cascade on update cascade;
alter table `project`
add constraint fk_project_root_project_id_project_id
foreign key (root_project_id) references project(id)
on delete cascade on update cascade;

@ -14,6 +14,7 @@ import se.su.dsv.scipro.components.menuhighlighting.MenuHighlightAdminProjectMan
import se.su.dsv.scipro.data.DetachableServiceModel; import se.su.dsv.scipro.data.DetachableServiceModel;
import se.su.dsv.scipro.project.Project; import se.su.dsv.scipro.project.Project;
import se.su.dsv.scipro.project.ProjectService; import se.su.dsv.scipro.project.ProjectService;
import se.su.dsv.scipro.project.split.SplitOrRestartProjectService;
import se.su.dsv.scipro.security.auth.Authorization; import se.su.dsv.scipro.security.auth.Authorization;
import se.su.dsv.scipro.security.auth.roles.Roles; import se.su.dsv.scipro.security.auth.roles.Roles;
import se.su.dsv.scipro.system.User; import se.su.dsv.scipro.system.User;
@ -27,6 +28,9 @@ public class AdminSplitProjectPage extends AbstractAdminProjectPage implements M
@Inject @Inject
private ProjectService projectService; private ProjectService projectService;
@Inject
private SplitOrRestartProjectService splitOrRestartProjectService;
public AdminSplitProjectPage(PageParameters pp) { public AdminSplitProjectPage(PageParameters pp) {
final long id = pp.get(PageParameterKeys.MAP.get(Project.class)).toLong(0); final long id = pp.get(PageParameterKeys.MAP.get(Project.class)).toLong(0);
final Project project = projectService.findOne(id); final Project project = projectService.findOne(id);
@ -69,6 +73,7 @@ public class AdminSplitProjectPage extends AbstractAdminProjectPage implements M
System.out.println("Project ID: " + projectId); System.out.println("Project ID: " + projectId);
splitOrRestartProjectService.splitProject(projectId);
final PageParameters pp = new PageParameters(); final PageParameters pp = new PageParameters();
pp.set(PageParameterKeys.MAP.get(Project.class), projectId); pp.set(PageParameterKeys.MAP.get(Project.class), projectId);