Merge branch '38-attach-file-grants' into 117-filter-users
This commit is contained in:
commit
8b333ab3a6
@ -1,5 +1,7 @@
|
||||
package ru.ulstu.grant.model;
|
||||
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.annotations.FetchMode;
|
||||
import org.hibernate.validator.constraints.NotBlank;
|
||||
import ru.ulstu.core.model.BaseEntity;
|
||||
import ru.ulstu.core.model.UserContainer;
|
||||
@ -66,10 +68,11 @@ public class Grant extends BaseEntity implements UserContainer {
|
||||
|
||||
private String comment;
|
||||
|
||||
//Заявка на грант
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "file_id")
|
||||
private FileData application;
|
||||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "grant_id", unique = true)
|
||||
@Fetch(FetchMode.SUBSELECT)
|
||||
private List<FileData> files = new ArrayList<>();
|
||||
|
||||
|
||||
@ManyToOne(cascade = CascadeType.ALL)
|
||||
@JoinColumn(name = "project_id")
|
||||
@ -113,12 +116,12 @@ public class Grant extends BaseEntity implements UserContainer {
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
public FileData getApplication() {
|
||||
return application;
|
||||
public List<FileData> getFiles() {
|
||||
return files;
|
||||
}
|
||||
|
||||
public void setApplication(FileData application) {
|
||||
this.application = application;
|
||||
public void setFiles(List<FileData> files) {
|
||||
this.files = files;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
|
@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hibernate.validator.constraints.NotEmpty;
|
||||
import ru.ulstu.deadline.model.Deadline;
|
||||
import ru.ulstu.file.model.FileDataDto;
|
||||
import ru.ulstu.paper.model.Paper;
|
||||
import ru.ulstu.project.model.ProjectDto;
|
||||
import ru.ulstu.user.model.UserDto;
|
||||
@ -25,7 +26,7 @@ public class GrantDto {
|
||||
private Grant.GrantStatus status;
|
||||
private List<Deadline> deadlines = new ArrayList<>();
|
||||
private String comment;
|
||||
private String applicationFileName;
|
||||
private List<FileDataDto> files = new ArrayList<>();
|
||||
private ProjectDto project;
|
||||
private Set<Integer> authorIds;
|
||||
private Set<UserDto> authors;
|
||||
@ -49,6 +50,7 @@ public class GrantDto {
|
||||
@JsonProperty("status") Grant.GrantStatus status,
|
||||
@JsonProperty("deadlines") List<Deadline> deadlines,
|
||||
@JsonProperty("comment") String comment,
|
||||
@JsonProperty("files") List<FileDataDto> files,
|
||||
@JsonProperty("project") ProjectDto project,
|
||||
@JsonProperty("authorIds") Set<Integer> authorIds,
|
||||
@JsonProperty("authors") Set<UserDto> authors,
|
||||
@ -63,8 +65,9 @@ public class GrantDto {
|
||||
this.status = status;
|
||||
this.deadlines = deadlines;
|
||||
this.comment = comment;
|
||||
this.applicationFileName = null;
|
||||
this.files = files;
|
||||
this.project = project;
|
||||
this.authorIds = authorIds;
|
||||
this.authors = authors;
|
||||
this.leaderId = leaderId;
|
||||
this.wasLeader = wasLeader;
|
||||
@ -80,8 +83,8 @@ public class GrantDto {
|
||||
this.status = grant.getStatus();
|
||||
this.deadlines = grant.getDeadlines();
|
||||
this.comment = grant.getComment();
|
||||
this.files = convert(grant.getFiles(), FileDataDto::new);
|
||||
this.project = grant.getProject() == null ? null : new ProjectDto(grant.getProject());
|
||||
this.applicationFileName = grant.getApplication() == null ? null : grant.getApplication().getName();
|
||||
this.authorIds = convert(grant.getAuthors(), user -> user.getId());
|
||||
this.authors = convert(grant.getAuthors(), UserDto::new);
|
||||
this.leaderId = grant.getLeader().getId();
|
||||
@ -132,6 +135,14 @@ public class GrantDto {
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
public List<FileDataDto> getFiles() {
|
||||
return files;
|
||||
}
|
||||
|
||||
public void setFiles(List<FileDataDto> files) {
|
||||
this.files = files;
|
||||
}
|
||||
|
||||
public ProjectDto getProject() {
|
||||
return project;
|
||||
}
|
||||
@ -140,14 +151,6 @@ public class GrantDto {
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
public String getApplicationFileName() {
|
||||
return applicationFileName;
|
||||
}
|
||||
|
||||
public void setApplicationFileName(String applicationFileName) {
|
||||
this.applicationFileName = applicationFileName;
|
||||
}
|
||||
|
||||
public Set<Integer> getAuthorIds() {
|
||||
return authorIds;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import ru.ulstu.deadline.model.Deadline;
|
||||
import ru.ulstu.deadline.service.DeadlineService;
|
||||
import ru.ulstu.file.model.FileDataDto;
|
||||
import ru.ulstu.file.service.FileService;
|
||||
import ru.ulstu.grant.model.Grant;
|
||||
import ru.ulstu.grant.model.GrantDto;
|
||||
@ -18,11 +19,11 @@ import ru.ulstu.user.model.User;
|
||||
import ru.ulstu.user.service.UserService;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static org.springframework.util.ObjectUtils.isEmpty;
|
||||
@ -83,9 +84,10 @@ public class GrantService {
|
||||
grant.setProject(projectService.findById(grantDto.getProject().getId()));
|
||||
}
|
||||
grant.setDeadlines(deadlineService.saveOrCreate(grantDto.getDeadlines()));
|
||||
if (grantDto.getApplicationFileName() != null) {
|
||||
grant.setApplication(fileService.createFileFromTmp(grantDto.getApplicationFileName()));
|
||||
}
|
||||
|
||||
grant.setFiles(fileService.saveOrCreate(grantDto.getFiles().stream()
|
||||
.filter(f -> !f.isDeleted())
|
||||
.collect(toList())));
|
||||
grant.getAuthors().clear();
|
||||
if (grantDto.getAuthorIds() != null && !grantDto.getAuthorIds().isEmpty()) {
|
||||
grantDto.getAuthorIds().forEach(authorIds -> grant.getAuthors().add(userService.findById(authorIds)));
|
||||
@ -108,8 +110,11 @@ public class GrantService {
|
||||
@Transactional
|
||||
public Integer update(GrantDto grantDto) throws IOException {
|
||||
Grant grant = grantRepository.findOne(grantDto.getId());
|
||||
if (grantDto.getApplicationFileName() != null && grant.getApplication() != null) {
|
||||
fileService.deleteFile(grant.getApplication());
|
||||
|
||||
for (FileDataDto file : grantDto.getFiles().stream()
|
||||
.filter(f -> f.isDeleted() && f.getId() != null)
|
||||
.collect(toList())) {
|
||||
fileService.delete(file.getId());
|
||||
}
|
||||
grantDto.getRemovedDeadlineIds().forEach(deadlineService::remove);
|
||||
grantRepository.save(copyFromDto(grant, grantDto));
|
||||
@ -119,9 +124,6 @@ public class GrantService {
|
||||
@Transactional
|
||||
public void delete(Integer grantId) throws IOException {
|
||||
Grant grant = grantRepository.findOne(grantId);
|
||||
if (grant.getApplication() != null) {
|
||||
fileService.deleteFile(grant.getApplication());
|
||||
}
|
||||
grantRepository.delete(grant);
|
||||
}
|
||||
|
||||
@ -179,7 +181,7 @@ public class GrantService {
|
||||
return grantRepository.findByStatus(Grant.GrantStatus.COMPLETED)
|
||||
.stream()
|
||||
.map(Grant::getLeader)
|
||||
.collect(toList());
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<Paper> getGrantPapers(List<Integer> paperIds) {
|
||||
@ -209,16 +211,10 @@ public class GrantService {
|
||||
|
||||
private List<User> getCompletedPapersAuthors(Paper.PaperType type) {
|
||||
List<Paper> papers = paperService.findAllCompletedByType(type);
|
||||
papers.stream()
|
||||
return papers.stream()
|
||||
.filter(paper -> paper.getAuthors() != null)
|
||||
.flatMap(paper-> paper.getAuthors().stream())
|
||||
.collect(toList());
|
||||
List<User> users = new ArrayList<>();
|
||||
for (Paper p : papers) {
|
||||
p.getAuthors()
|
||||
.stream()
|
||||
.forEach(users::add);
|
||||
}
|
||||
return users;
|
||||
}
|
||||
|
||||
private List<User> getBAKAuthors() {
|
||||
@ -229,14 +225,10 @@ public class GrantService {
|
||||
}
|
||||
|
||||
private List<User> getScopusAuthors() {
|
||||
List<User> oldAuthors = getCompletedPapersAuthors(Paper.PaperType.SCOPUS);
|
||||
List<User> newAuthors = new ArrayList<>();
|
||||
oldAuthors.forEach(author -> {
|
||||
int count = Collections.frequency(oldAuthors, author);
|
||||
if (count > 3) {
|
||||
newAuthors.add(author);
|
||||
}
|
||||
});
|
||||
return newAuthors;
|
||||
List<User> authors = getCompletedPapersAuthors(Paper.PaperType.SCOPUS);
|
||||
return authors
|
||||
.stream()
|
||||
.filter(author -> Collections.frequency(authors, author) > 3)
|
||||
.collect(toList());
|
||||
}
|
||||
}
|
||||
|
@ -17,5 +17,5 @@ public interface PaperRepository extends JpaRepository<Paper, Integer> {
|
||||
|
||||
List<Paper> findAllByIdIn(List<Integer> paperIds);
|
||||
|
||||
List<Paper> findByType(Paper.PaperType type);
|
||||
List<Paper> findByTypeAndStatus(Paper.PaperType type, Paper.PaperStatus status);
|
||||
}
|
||||
|
@ -305,9 +305,6 @@ public class PaperService {
|
||||
}
|
||||
|
||||
public List<Paper> findAllCompletedByType(Paper.PaperType type) {
|
||||
return paperRepository.findByType(type)
|
||||
.stream()
|
||||
.filter(findAllCompleted()::contains)
|
||||
.collect(toList());
|
||||
return paperRepository.findByTypeAndStatus(type, Paper.PaperStatus.COMPLETED);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
# Server Settings
|
||||
spring.main.banner-mode=off
|
||||
server.port=8443
|
||||
server.http.port=8080
|
||||
server.http.port=8888
|
||||
spring.http.multipart.maxFileSize=20MB
|
||||
spring.http.multipart.maxRequestSize=20MB
|
||||
# Thymeleaf Settings
|
||||
@ -24,7 +24,7 @@ spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFact
|
||||
# JPA Settings
|
||||
spring.datasource.url=jdbc:postgresql://localhost:5432/ng-tracker
|
||||
spring.datasource.username=postgres
|
||||
spring.datasource.password=postgres
|
||||
spring.datasource.password=superuser
|
||||
spring.datasource.driverclassName=org.postgresql.Driver
|
||||
spring.jpa.hibernate.ddl-auto=validate
|
||||
# Liquibase Settings
|
||||
|
10
src/main/resources/db/changelog-20190428_000000-schema.xml
Normal file
10
src/main/resources/db/changelog-20190428_000000-schema.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<?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="20190428_000000-1">
|
||||
<update tableName="project">
|
||||
<column name="status" value="APPLICATION"/>
|
||||
</update>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
11
src/main/resources/db/changelog-20190430_000000-schema.xml
Normal file
11
src/main/resources/db/changelog-20190430_000000-schema.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?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="tanya" id="20190430_000000-1">
|
||||
<dropColumn columnName="file_id" tableName="grants"/>
|
||||
<addColumn tableName="file">
|
||||
<column name="grant_id" type="integer"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
@ -34,4 +34,6 @@
|
||||
<include file="db/changelog-20190421_000000-schema.xml"/>
|
||||
<include file="db/changelog-20190422_000000-schema.xml"/>
|
||||
<include file="db/changelog-20190424_000000-schema.xml"/>
|
||||
<include file="db/changelog-20190428_000000-schema.xml"/>
|
||||
<include file="db/changelog-20190430_000000-schema.xml"/>
|
||||
</databaseChangeLog>
|
@ -29,3 +29,15 @@
|
||||
.btn-delete-deadline {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.div-file-name{
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
.div-loader {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.div-row-file {
|
||||
margin-bottom: 2px;
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
</head>
|
||||
<body>
|
||||
<div th:fragment="filesList (isLatexAttach)" th:remove="tag">
|
||||
<th:block th:each="file, rowStat : *{files}">
|
||||
<span th:if="${(!isLatexAttach and file.isLatexAttach == null) or file.isLatexAttach == isLatexAttach}"
|
||||
th:remove="tag">
|
||||
<div class="row div-row-file" th:id="|files${rowStat.index}|"
|
||||
th:style="${file.deleted} ? 'display: none;' :''">
|
||||
<input type="hidden" th:field="*{files[__${rowStat.index}__].id}"/>
|
||||
<input type="hidden" th:field="*{files[__${rowStat.index}__].deleted}"/>
|
||||
<input type="hidden" th:field="*{files[__${rowStat.index}__].name}"/>
|
||||
<input type="hidden" th:field="*{files[__${rowStat.index}__].tmpFileName}"/>
|
||||
<div class="col-10 div-file-name">
|
||||
<a th:onclick="${file.id==null} ?
|
||||
'downloadFile('+${file.tmpFileName}+',null,\''+${file.name}+'\')':
|
||||
'downloadFile(null,'+${file.id}+',\''+${file.name}+'\')' "
|
||||
href="javascript:void(0)"
|
||||
th:text="*{files[__${rowStat.index}__].name}">
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<a class="btn btn-danger float-right"
|
||||
th:onclick="|$('#files${rowStat.index}\\.deleted').val('true');
|
||||
$('#files${rowStat.index}').hide(); |">
|
||||
<span aria-hidden="true"><i class="fa fa-times"/></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</th:block>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -61,7 +61,7 @@
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<button type="submit"
|
||||
class="btn btn-danger float-right btn-delete-deadline "
|
||||
class="btn btn-danger float-right btn-delete-deadline"
|
||||
id="removeDeadline" name="removeDeadline"
|
||||
th:value="${rowStat.index}">
|
||||
<span aria-hidden="true">
|
||||
@ -77,12 +77,14 @@
|
||||
<input type="submit" id="addDeadline" name="addDeadline" class="btn btn-primary"
|
||||
value="Добавить дедлайн"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="loader">Загрузить заявку:</label>
|
||||
<div class="form-group div-loader">
|
||||
<label for="loader">Загрузить файлы:</label>
|
||||
<div id="loader">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" id="files-list">
|
||||
<div th:replace="grants/fragments/grantFilesListFragment :: filesList(isLatexAttach = ${false})"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-sm-12">
|
||||
<label data-toggle="collapse"
|
||||
@ -236,20 +238,100 @@
|
||||
new FileLoader({
|
||||
div: "loader",
|
||||
url: urlFileUpload,
|
||||
maxSize: 1.5,
|
||||
extensions: ["doc", "docx", "xls", "jpg", "pdf", "txt", "png"],
|
||||
maxSize: -1,
|
||||
extensions: [],
|
||||
callback: function (response) {
|
||||
showFeedbackMessage("Файл успешно загружен");
|
||||
console.debug(response);
|
||||
addNewFile(response);
|
||||
}
|
||||
});
|
||||
$('.selectpicker').selectpicker();
|
||||
});
|
||||
/*]]>*/
|
||||
function addNewFile(fileDto) {
|
||||
var fileNumber = $("#files-list div.row").length;
|
||||
|
||||
var newFileRow = $("<div/>")
|
||||
.attr("id", 'files' + fileNumber)
|
||||
.addClass("row div-row-file");
|
||||
|
||||
var idInput = $("<input/>")
|
||||
.attr("type", "hidden")
|
||||
.attr("id", "files" + fileNumber + ".id")
|
||||
.attr("value", '')
|
||||
.attr("name", "files[" + fileNumber + "].id");
|
||||
newFileRow.append(idInput);
|
||||
|
||||
var flagInput = $("<input/>")
|
||||
.attr("type", "hidden")
|
||||
.attr("id", "files" + fileNumber + ".deleted")
|
||||
.attr("value", "false")
|
||||
.attr("name", "files[" + fileNumber + "].deleted");
|
||||
newFileRow.append(flagInput);
|
||||
|
||||
var nameInput = $("<input/>")
|
||||
.attr("type", "hidden")
|
||||
.attr("id", "files" + fileNumber + ".name")
|
||||
.attr("value", fileDto.fileName)
|
||||
.attr("name", "files[" + fileNumber + "].name");
|
||||
newFileRow.append(nameInput);
|
||||
|
||||
var tmpFileNameInput = $("<input/>")
|
||||
.attr("type", "hidden")
|
||||
.attr("id", "files" + fileNumber + ".tmpFileName")
|
||||
.attr("value", fileDto.tmpFileName)
|
||||
.attr("name", "files[" + fileNumber + "].tmpFileName");
|
||||
newFileRow.append(tmpFileNameInput);
|
||||
|
||||
var nameDiv = $("<div/>")
|
||||
.addClass("col-10 div-file-name")
|
||||
.append($("<a/>").text(fileDto.fileName)
|
||||
.attr("href", 'javascript:void(0)')
|
||||
.attr("onclick", "downloadFile('" + fileDto.tmpFileName + "',null,'" + fileDto.fileName + "')"));
|
||||
newFileRow.append(nameDiv);
|
||||
|
||||
var nextDiv = $("<div/>")
|
||||
.addClass("col-2");
|
||||
|
||||
var nextA = $("<a/>")
|
||||
.addClass("btn btn-danger float-right")
|
||||
.attr("onclick", "$('#files" + fileNumber + "\\\\.deleted').val('true'); $('#files" + fileNumber + "').hide();")
|
||||
.append(($("<span/>").attr("aria-hidden", "true")).append($("<i/>").addClass("fa fa-times")))
|
||||
;
|
||||
nextDiv.append(nextA)
|
||||
newFileRow.append(nextDiv);
|
||||
$("#files-list").append(newFileRow);
|
||||
}
|
||||
|
||||
function downloadFile(tmpName, fileId, downloadName) {
|
||||
let xhr = new XMLHttpRequest();
|
||||
if (fileId != null) xhr.open('GET', urlFileDownload + fileId);
|
||||
if (tmpName != null) xhr.open('GET', urlFileDownloadTmp + tmpName);
|
||||
xhr.responseType = 'blob';
|
||||
|
||||
var formData = new FormData();
|
||||
if (fileId != null) formData.append("file-id", fileId);
|
||||
if (tmpName != null) formData.append("tmp-file-name", tmpName);
|
||||
|
||||
xhr.send(formData);
|
||||
|
||||
xhr.onload = function () {
|
||||
if (this.status == 200) {
|
||||
console.debug(this.response);
|
||||
var blob = new Blob([this.response], {type: '*'});
|
||||
let a = document.createElement("a");
|
||||
a.style = "display: none";
|
||||
document.body.appendChild(a);
|
||||
let url = window.URL.createObjectURL(blob);
|
||||
a.href = url;
|
||||
a.download = downloadName;
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
} else {
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
function updateAuthors() {
|
||||
@ -259,23 +341,6 @@
|
||||
var lid = $("#leaderId option:selected").val();
|
||||
$("#authors [value='" + lid + "']").attr("disabled", "disabled");
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<script>
|
||||
function viewdiv(id) {
|
||||
var el = document.getElementById(id);
|
||||
var link = document.getElementById('toggleLink');
|
||||
if (el.style.display == "block") {
|
||||
el.style.display = "none";
|
||||
link.innerText = link.getAttribute('data-text-hide');
|
||||
} else {
|
||||
el.style.display = "block";
|
||||
link.innerText = link.getAttribute('data-text-show');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
</div>
|
||||
</body>
|
||||
|
Loading…
Reference in New Issue
Block a user