Merge branch '97-edit-project' into 'dev'

Resolve "Редактирование проекта"

Closes #97

See merge request romanov73/ng-tracker!59
This commit is contained in:
Anton Romanov 2019-04-23 07:34:13 +00:00
commit 5e86952cb6
11 changed files with 141 additions and 18 deletions

View File

@ -89,7 +89,7 @@ public class GrantController {
} }
@PostMapping(value = "/grant", params = "createProject") @PostMapping(value = "/grant", params = "createProject")
public String createProject(@Valid GrantDto grantDto, Errors errors) { public String createProject(@Valid GrantDto grantDto, Errors errors) throws IOException {
if (errors.hasErrors()) { if (errors.hasErrors()) {
return GRANT_PAGE; return GRANT_PAGE;
} }

View File

@ -89,7 +89,7 @@ public class GrantService {
return grant; return grant;
} }
public void createProject(GrantDto grantDto) { public void createProject(GrantDto grantDto) throws IOException {
grantDto.setProject( grantDto.setProject(
new ProjectDto(projectService.save(new ProjectDto(grantDto.getTitle())))); new ProjectDto(projectService.save(new ProjectDto(grantDto.getTitle()))));
} }

View File

@ -2,16 +2,26 @@ package ru.ulstu.project.controller;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap; import org.springframework.ui.ModelMap;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import ru.ulstu.deadline.model.Deadline;
import ru.ulstu.grant.model.GrantDto;
import ru.ulstu.project.model.Project; import ru.ulstu.project.model.Project;
import ru.ulstu.project.model.ProjectDto; import ru.ulstu.project.model.ProjectDto;
import ru.ulstu.project.service.ProjectService; import ru.ulstu.project.service.ProjectService;
import springfox.documentation.annotations.ApiIgnore; import springfox.documentation.annotations.ApiIgnore;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import static org.springframework.util.StringUtils.isEmpty;
import static ru.ulstu.core.controller.Navigation.hasErrors;
@Controller() @Controller()
@RequestMapping(value = "/projects") @RequestMapping(value = "/projects")
@ -46,4 +56,33 @@ public class ProjectController {
public List<Project.ProjectStatus> getProjectStatuses() { public List<Project.ProjectStatus> getProjectStatuses() {
return projectService.getProjectStatuses(); return projectService.getProjectStatuses();
} }
@PostMapping(value = "/project", params = "save")
public String save(@Valid ProjectDto projectDto, Errors errors) throws IOException {
filterEmptyDeadlines(projectDto);
if (projectDto.getDeadlines().isEmpty()) {
errors.rejectValue("deadlines", "errorCode", "Не может быть пустым");
}
if (errors.hasErrors()) {
return "/projects/project";
}
projectService.save(projectDto);
return String.format("redirect:%s", "/projects/projects");
}
@PostMapping(value = "/project", params = "addDeadline")
public String addDeadline(@Valid ProjectDto projectDto, Errors errors) {
filterEmptyDeadlines(projectDto);
if (errors.hasErrors()) {
return "/projects/project";
}
projectDto.getDeadlines().add(new Deadline());
return "/projects/project";
}
private void filterEmptyDeadlines(ProjectDto projectDto) {
projectDto.setDeadlines(projectDto.getDeadlines().stream()
.filter(dto -> dto.getDate() != null || !isEmpty(dto.getDescription()))
.collect(Collectors.toList()));
}
} }

View File

@ -3,6 +3,7 @@ package ru.ulstu.project.model;
import org.hibernate.validator.constraints.NotBlank; import org.hibernate.validator.constraints.NotBlank;
import ru.ulstu.core.model.BaseEntity; import ru.ulstu.core.model.BaseEntity;
import ru.ulstu.deadline.model.Deadline; import ru.ulstu.deadline.model.Deadline;
import ru.ulstu.file.model.FileData;
import ru.ulstu.grant.model.Grant; import ru.ulstu.grant.model.Grant;
import javax.persistence.CascadeType; import javax.persistence.CascadeType;
@ -57,6 +58,10 @@ public class Project extends BaseEntity {
@NotNull @NotNull
private String repository; private String repository;
@ManyToOne
@JoinColumn(name = "file_id")
private FileData application;
public String getTitle() { public String getTitle() {
return title; return title;
} }
@ -104,4 +109,12 @@ public class Project extends BaseEntity {
public void setDeadlines(List<Deadline> deadlines) { public void setDeadlines(List<Deadline> deadlines) {
this.deadlines = deadlines; this.deadlines = deadlines;
} }
public FileData getApplication() {
return application;
}
public void setApplication(FileData application) {
this.application = application;
}
} }

View File

@ -19,6 +19,7 @@ public class ProjectDto {
private List<Deadline> deadlines = new ArrayList<>(); private List<Deadline> deadlines = new ArrayList<>();
private GrantDto grant; private GrantDto grant;
private String repository; private String repository;
private String applicationFileName;
public ProjectDto() { public ProjectDto() {
} }
@ -42,6 +43,7 @@ public class ProjectDto {
this.grant = grant; this.grant = grant;
this.repository = repository; this.repository = repository;
this.deadlines = deadlines; this.deadlines = deadlines;
this.applicationFileName = null;
} }
@ -50,6 +52,7 @@ public class ProjectDto {
this.title = project.getTitle(); this.title = project.getTitle();
this.status = project.getStatus(); this.status = project.getStatus();
this.description = project.getDescription(); this.description = project.getDescription();
this.applicationFileName = project.getApplication() == null ? null : project.getApplication().getName();
this.grant = project.getGrant() == null ? null : new GrantDto(project.getGrant()); this.grant = project.getGrant() == null ? null : new GrantDto(project.getGrant());
this.repository = project.getRepository(); this.repository = project.getRepository();
this.deadlines = project.getDeadlines(); this.deadlines = project.getDeadlines();
@ -110,4 +113,12 @@ public class ProjectDto {
public void setDeadlines(List<Deadline> deadlines) { public void setDeadlines(List<Deadline> deadlines) {
this.deadlines = deadlines; this.deadlines = deadlines;
} }
public String getApplicationFileName() {
return applicationFileName;
}
public void setApplicationFileName(String applicationFileName) {
this.applicationFileName = applicationFileName;
}
} }

View File

@ -4,15 +4,19 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.thymeleaf.util.StringUtils; import org.thymeleaf.util.StringUtils;
import ru.ulstu.deadline.service.DeadlineService; import ru.ulstu.deadline.service.DeadlineService;
import ru.ulstu.file.service.FileService;
import ru.ulstu.grant.repository.GrantRepository;
import ru.ulstu.project.model.Project; import ru.ulstu.project.model.Project;
import ru.ulstu.project.model.ProjectDto; import ru.ulstu.project.model.ProjectDto;
import ru.ulstu.project.repository.ProjectRepository; import ru.ulstu.project.repository.ProjectRepository;
import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import static org.springframework.util.ObjectUtils.isEmpty; import static org.springframework.util.ObjectUtils.isEmpty;
import static ru.ulstu.core.util.StreamApiUtils.convert; import static ru.ulstu.core.util.StreamApiUtils.convert;
import static ru.ulstu.project.model.Project.ProjectStatus.APPLICATION;
@Service @Service
public class ProjectService { public class ProjectService {
@ -20,11 +24,17 @@ public class ProjectService {
private final ProjectRepository projectRepository; private final ProjectRepository projectRepository;
private final DeadlineService deadlineService; private final DeadlineService deadlineService;
private final GrantRepository grantRepository;
private final FileService fileService;
public ProjectService(ProjectRepository projectRepository, public ProjectService(ProjectRepository projectRepository,
DeadlineService deadlineService) { DeadlineService deadlineService,
GrantRepository grantRepository,
FileService fileService) {
this.projectRepository = projectRepository; this.projectRepository = projectRepository;
this.deadlineService = deadlineService; this.deadlineService = deadlineService;
this.grantRepository = grantRepository;
this.fileService = fileService;
} }
public List<Project> findAll() { public List<Project> findAll() {
@ -46,19 +56,28 @@ public class ProjectService {
} }
@Transactional @Transactional
public Project create(ProjectDto projectDto) { public Project create(ProjectDto projectDto) throws IOException {
Project newProject = copyFromDto(new Project(), projectDto); Project newProject = copyFromDto(new Project(), projectDto);
newProject = projectRepository.save(newProject); newProject = projectRepository.save(newProject);
return newProject; return newProject;
} }
private Project copyFromDto(Project project, ProjectDto projectDto) { private Project copyFromDto(Project project, ProjectDto projectDto) throws IOException {
project.setDescription(projectDto.getDescription());
project.setStatus(projectDto.getStatus() == null ? APPLICATION : projectDto.getStatus());
project.setTitle(projectDto.getTitle()); project.setTitle(projectDto.getTitle());
if (projectDto.getGrant() != null && projectDto.getGrant().getId() != null) {
project.setGrant(grantRepository.findOne(projectDto.getGrant().getId()));
}
project.setRepository(projectDto.getRepository());
project.setDeadlines(deadlineService.saveOrCreate(projectDto.getDeadlines())); project.setDeadlines(deadlineService.saveOrCreate(projectDto.getDeadlines()));
if (projectDto.getApplicationFileName() != null) {
project.setApplication(fileService.createFileFromTmp(projectDto.getApplicationFileName()));
}
return project; return project;
} }
public Project save(ProjectDto projectDto) { public Project save(ProjectDto projectDto) throws IOException {
if (isEmpty(projectDto.getId())) { if (isEmpty(projectDto.getId())) {
return create(projectDto); return create(projectDto);
} else { } else {

View File

@ -0,0 +1,16 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<changeSet author="anton" id="20190418_000000-1">
<addColumn tableName="project">
<column name="file_id" type="integer"/>
</addColumn>
<addForeignKeyConstraint baseTableName="project" baseColumnNames="file_id"
constraintName="fk_project_file_id" referencedTableName="file"
referencedColumnNames="id"/>
<addColumn tableName="project">
<column name="applicationFileName" type="varchar(255)"/>
</addColumn>
</changeSet>
</databaseChangeLog>

View File

@ -31,4 +31,5 @@
<include file="db/changelog-20190402_000000-schema.xml"/> <include file="db/changelog-20190402_000000-schema.xml"/>
<include file="db/changelog-20190404_000000-schema.xml"/> <include file="db/changelog-20190404_000000-schema.xml"/>
<include file="db/changelog-20190421_000000-schema.xml"/> <include file="db/changelog-20190421_000000-schema.xml"/>
<include file="db/changelog-20190422_000000-schema.xml"/>
</databaseChangeLog> </databaseChangeLog>

View File

@ -13,8 +13,8 @@
<div th:replace="projects/fragments/projectNavigationFragment"/> <div th:replace="projects/fragments/projectNavigationFragment"/>
</div> </div>
<div class="row justify-content-center" id="dashboard"> <div class="row justify-content-center" id="dashboard">
<th:block> <th:block th:each="project : ${projects}">
<div/> <div th:replace="projects/fragments/projectDashboardFragment :: projectDashboard(project=${project})"/>
</th:block> </th:block>
</div> </div>
</div> </div>

View File

@ -0,0 +1,19 @@
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head th:fragment="headerfiles">
<meta charset="UTF-8"/>
</head>
<body>
<div th:fragment="projectDashboard (project)" class="col-12 col-sm-12 col-md-12 col-lg-4 col-xl-3 dashboard-card">
<div class="row">
<div class="col-2">
<span th:replace="projects/fragments/projectStatusFragment :: projectStatus(projectStatus=${project.status})"/>
</div>
<div class="col col-10 text-right">
<h7 class="service-heading" th:text="${project.title}"> title</h7>
<p class="text-muted" th:text="${project.status.statusName}"> status</p>
</div>
</div>
</div>
</body>
</html>

View File

@ -71,16 +71,21 @@
<div class="form-group"> <div class="form-group">
<label>Дедлайны показателей:</label> <label>Дедлайны показателей:</label>
<div class="row"> <div class="row" th:each="deadline, rowStat : *{deadlines}">
<input type="hidden"/> <input type="hidden" th:field="*{deadlines[__${rowStat.index}__].id}"/>
<div class="col-6"> <div class="col-6 div-deadline-date">
<input type="date" class="form-control" name="deadline"/> <input type="date" class="form-control form-deadline-date" name="deadline"
th:field="*{deadlines[__${rowStat.index}__].date}"/>
</div> </div>
<div class="col-4"> <div class="col-4 div-deadline-description">
<input class="form-control" type="text" placeholder="Описание"/> <input class="form-control" type="text" placeholder="Описание"
th:field="*{deadlines[__${rowStat.index}__].description}"/>
</div> </div>
<div class="col-2"> <div class="col-2">
<a class="btn btn-danger float-right"><span <a class="btn btn-danger float-right"
th:onclick="|$('#deadlines${rowStat.index}\\.description').val('');
$('#deadlines${rowStat.index}\\.date').val('');
$('#addDeadline').click();|"><span
aria-hidden="true"><i class="fa fa-times"/></span> aria-hidden="true"><i class="fa fa-times"/></span>
</a> </a>
</div> </div>
@ -90,8 +95,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<input type="submit" id="addDeadline" name="addDeadline" class="btn btn-primary" <input type="submit" id="addDeadline" name="addDeadline" class="btn btn-primary"
value="Добавить value="Добавить дедлайн"/>
дедлайн"/>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -110,7 +114,8 @@
Сохранить Сохранить
</button> </button>
<button id="cancelButton" class="btn btn-default text-uppercase" <button id="cancelButton" class="btn btn-default text-uppercase"
href="/projects/projects"> onclick="location.href='/projects/projects'" href="/projects/projects"
type="button">
Отмена Отмена
</button> </button>
</div> </div>