Coverage Summary for Class: ProjectService (org.kitodo.production.services.data)
Class |
Class, %
|
Method, %
|
Line, %
|
ProjectService |
100%
(1/1)
|
50%
(12/24)
|
41,4%
(58/140)
|
/*
* (c) Kitodo. Key to digital objects e. V. <contact@kitodo.org>
*
* This file is part of the Kitodo project.
*
* It is licensed under GNU General Public License version 3 or later.
*
* For the full copyright and license information, please read the
* GPL3-License.txt file that was distributed with this source code.
*/
package org.kitodo.production.services.data;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.IdsQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.kitodo.config.enums.KitodoConfigFile;
import org.kitodo.data.database.beans.Client;
import org.kitodo.data.database.beans.Folder;
import org.kitodo.data.database.beans.Process;
import org.kitodo.data.database.beans.Project;
import org.kitodo.data.database.beans.Template;
import org.kitodo.data.database.beans.User;
import org.kitodo.data.database.enums.IndexAction;
import org.kitodo.data.database.exceptions.DAOException;
import org.kitodo.data.database.persistence.ProjectDAO;
import org.kitodo.data.elasticsearch.exceptions.CustomResponseException;
import org.kitodo.data.elasticsearch.index.Indexer;
import org.kitodo.data.elasticsearch.index.type.ProjectType;
import org.kitodo.data.elasticsearch.index.type.enums.ProjectTypeField;
import org.kitodo.data.elasticsearch.index.type.enums.TemplateTypeField;
import org.kitodo.data.elasticsearch.search.Searcher;
import org.kitodo.data.exceptions.DataException;
import org.kitodo.exceptions.ProjectDeletionException;
import org.kitodo.production.dto.ClientDTO;
import org.kitodo.production.dto.ProjectDTO;
import org.kitodo.production.dto.TemplateDTO;
import org.kitodo.production.helper.Helper;
import org.kitodo.production.services.ServiceManager;
import org.kitodo.production.services.data.base.ClientSearchService;
import org.primefaces.model.SortOrder;
public class ProjectService extends ClientSearchService<Project, ProjectDTO, ProjectDAO> {
private static volatile ProjectService instance = null;
/**
* Constructor with Searcher and Indexer assigning.
*/
private ProjectService() {
super(new ProjectDAO(), new ProjectType(), new Indexer<>(Project.class), new Searcher(Project.class),
ProjectTypeField.CLIENT_ID.getKey());
}
/**
* Return singleton variable of type ProjectService.
*
* @return unique instance of ProcessService
*/
public static ProjectService getInstance() {
ProjectService localReference = instance;
if (Objects.isNull(localReference)) {
synchronized (ProjectService.class) {
localReference = instance;
if (Objects.isNull(localReference)) {
localReference = new ProjectService();
instance = localReference;
}
}
}
return localReference;
}
/**
* Method saves processes and templates related to modified project.
*
* @param project
* object
*/
@Override
protected void manageDependenciesForIndex(Project project)
throws CustomResponseException, DataException, IOException {
manageProcessesDependenciesForIndex(project);
manageTemplatesDependenciesForIndex(project);
}
/**
* Management of processes for project object.
*
* @param project
* object
*/
private void manageProcessesDependenciesForIndex(Project project)
throws CustomResponseException, DataException, IOException {
if (project.getIndexAction() == IndexAction.DELETE) {
for (Process process : project.getProcesses()) {
ServiceManager.getProcessService().removeFromIndex(process, false);
}
}
}
/**
* Management of templates for project object.
*
* @param project
* object
*/
private void manageTemplatesDependenciesForIndex(Project project)
throws CustomResponseException, DataException, IOException {
if (project.getIndexAction() == IndexAction.DELETE) {
for (Template template : project.getTemplates()) {
template.getProjects().remove(project);
}
}
for (Template template : project.getTemplates()) {
ServiceManager.getTemplateService().saveToIndex(template, false);
}
}
@Override
public Long countDatabaseRows() throws DAOException {
return countDatabaseRows("SELECT COUNT(*) FROM Project");
}
@Override
public Long countNotIndexedDatabaseRows() throws DAOException {
return countDatabaseRows("SELECT COUNT(*) FROM Project WHERE indexAction = 'INDEX' OR indexAction IS NULL");
}
@Override
public Long countResults(Map filters) throws DataException {
return countDocuments(getProjectsForCurrentUserQuery());
}
@Override
public List<Project> getAllNotIndexed() {
return getByQuery("FROM Project WHERE indexAction = 'INDEX' OR indexAction IS NULL");
}
@Override
public List<Project> getAllForSelectedClient() {
return dao.getByQuery("SELECT p FROM Project AS p INNER JOIN p.client AS c WITH c.id = :clientId",
Collections.singletonMap("clientId", ServiceManager.getUserService().getSessionClientId()));
}
@Override
public List<ProjectDTO> loadData(int first, int pageSize, String sortField, SortOrder sortOrder, Map filters)
throws DataException {
return findByQuery(getProjectsForCurrentUserQuery(), getSortBuilder(sortField, sortOrder), first, pageSize,
false);
}
/**
* Find all projects available to assign to the edited user. It will be
* displayed in the addProjectsPopup.
*
* @param user
* user which is going to be edited
* @return list of all matching projects
*/
public List<ProjectDTO> findAllAvailableForAssignToUser(User user) throws DataException {
return findAvailableForAssignToUser(user);
}
private List<ProjectDTO> findAvailableForAssignToUser(User user) throws DataException {
BoolQueryBuilder query = new BoolQueryBuilder();
for (Client client : user.getClients()) {
query.should(createSimpleQuery(ProjectTypeField.CLIENT_ID.getKey(), client.getId(), true));
}
List<ProjectDTO> projectDTOS = findByQuery(query, true);
List<ProjectDTO> alreadyAssigned = new ArrayList<>();
for (Project project : user.getProjects()) {
alreadyAssigned.addAll(projectDTOS.stream().filter(projectDTO -> projectDTO.getId().equals(project.getId()))
.collect(Collectors.toList()));
}
projectDTOS.removeAll(alreadyAssigned);
return projectDTOS;
}
@Override
public ProjectDTO convertJSONObjectToDTO(Map<String, Object> jsonObject, boolean related) throws DataException {
ProjectDTO projectDTO = new ProjectDTO();
projectDTO.setId(getIdFromJSONObject(jsonObject));
projectDTO.setTitle(ProjectTypeField.TITLE.getStringValue(jsonObject));
projectDTO.setStartDate(ProjectTypeField.START_DATE.getStringValue(jsonObject));
projectDTO.setEndDate(ProjectTypeField.END_DATE.getStringValue(jsonObject));
projectDTO.setMetsRightsOwner(ProjectTypeField.METS_RIGTS_OWNER.getStringValue(jsonObject));
projectDTO.setNumberOfPages(ProjectTypeField.NUMBER_OF_PAGES.getIntValue(jsonObject));
projectDTO.setNumberOfVolumes(ProjectTypeField.NUMBER_OF_VOLUMES.getIntValue(jsonObject));
projectDTO.setActive(ProjectTypeField.ACTIVE.getBooleanValue(jsonObject));
ClientDTO clientDTO = new ClientDTO();
clientDTO.setId(ProjectTypeField.CLIENT_ID.getIntValue(jsonObject));
clientDTO.setName(ProjectTypeField.CLIENT_NAME.getStringValue(jsonObject));
projectDTO.setClient(clientDTO);
projectDTO.setHasProcesses(ProjectTypeField.HAS_PROCESSES.getBooleanValue(jsonObject));
if (!related) {
convertRelatedJSONObjects(jsonObject, projectDTO);
} else {
projectDTO.setTemplates(getTemplatesForProjectDTO(jsonObject));
}
return projectDTO;
}
private List<TemplateDTO> getTemplatesForProjectDTO(Map<String, Object> jsonObject) throws DataException {
List<TemplateDTO> templateDTOS = new ArrayList<>();
List<Map<String, Object>> jsonArray = ProjectTypeField.TEMPLATES.getJsonArray(jsonObject);
for (Map<String, Object> singleObject : jsonArray) {
TemplateDTO templateDTO = new TemplateDTO();
templateDTO.setId(TemplateTypeField.ID.getIntValue(singleObject));
templateDTO.setTitle(TemplateTypeField.TITLE.getStringValue(singleObject));
templateDTOS.add(templateDTO);
}
return templateDTOS.stream().filter(TemplateDTO::isActive).collect(Collectors.toList());
}
private void convertRelatedJSONObjects(Map<String, Object> jsonObject, ProjectDTO projectDTO) throws DataException {
// TODO: not clear if project lists will need it
projectDTO.setUsers(new ArrayList<>());
projectDTO.setTemplates(convertRelatedJSONObjectToDTO(jsonObject, ProjectTypeField.TEMPLATES.getKey(),
ServiceManager.getTemplateService()).stream().filter(TemplateDTO::isActive).collect(Collectors.toList()));
}
/**
* Checks if a project can be actually used.
*
* @param project
* The project to check
* @return true, if project is complete and can be used, false, if project is
* incomplete
*/
public boolean isProjectComplete(Project project) {
boolean projectsXmlExists = KitodoConfigFile.PROJECT_CONFIGURATION.exists();
return Objects.nonNull(project.getTitle()) && projectsXmlExists;
}
/**
* Creates a deep copy of a project, but without the title.
*
* @param baseProject
* project to duplicate
*
* @return the duplicated project
*/
public Project duplicateProject(Project baseProject) {
Project duplicatedProject = new Project();
duplicatedProject.setTitle(baseProject.getTitle() + "_" + Helper.generateRandomString(3));
duplicatedProject.setClient(baseProject.getClient());
duplicatedProject.setStartDate(baseProject.getStartDate());
duplicatedProject.setEndDate(baseProject.getEndDate());
duplicatedProject.setNumberOfPages(baseProject.getNumberOfPages());
duplicatedProject.setNumberOfVolumes(baseProject.getNumberOfVolumes());
duplicatedProject.setDmsImportRootPath(baseProject.getDmsImportRootPath());
duplicatedProject.setMetsRightsOwner(baseProject.getMetsRightsOwner());
duplicatedProject.setMetsRightsOwnerLogo(baseProject.getMetsRightsOwnerLogo());
duplicatedProject.setMetsRightsOwnerSite(baseProject.getMetsRightsOwnerSite());
duplicatedProject.setMetsRightsOwnerMail(baseProject.getMetsRightsOwnerMail());
duplicatedProject.setMetsDigiprovPresentation(baseProject.getMetsDigiprovPresentation());
duplicatedProject.setMetsDigiprovReference(baseProject.getMetsDigiprovReference());
duplicatedProject.setMetsPointerPath(baseProject.getMetsPointerPath());
duplicatedProject.setMetsPurl(baseProject.getMetsPurl());
duplicatedProject.setMetsContentIDs(baseProject.getMetsContentIDs());
FolderService folderService = ServiceManager.getFolderService();
List<Folder> duplicatedFolders = new ArrayList<>();
Folder generatorSource = null;
Folder mediaView = null;
Folder preview = null;
for (Folder folder : baseProject.getFolders()) {
Folder duplicatedFolder = folderService.cloneFolder(folder);
duplicatedFolder.setProject(duplicatedProject);
duplicatedFolders.add(duplicatedFolder);
if (folder.equals(baseProject.getGeneratorSource())) {
generatorSource = duplicatedFolder;
}
if (folder.equals(baseProject.getMediaView())) {
mediaView = duplicatedFolder;
}
if (folder.equals(baseProject.getPreview())) {
preview = duplicatedFolder;
}
}
duplicatedProject.setFolders(duplicatedFolders);
duplicatedProject.setGeneratorSource(generatorSource);
duplicatedProject.setMediaView(mediaView);
duplicatedProject.setPreview(preview);
return duplicatedProject;
}
/**
* Get query for finding projects for current user.
*
* @return query for finding projects for current user
*/
public QueryBuilder getProjectsForCurrentUserQuery() {
List<Project> projects = ServiceManager.getUserService().getAuthenticatedUser().getProjects();
IdsQueryBuilder idsQueryBuilder = QueryBuilders.idsQuery();
for (Project project : projects) {
idsQueryBuilder.addIds(project.getId().toString());
}
return idsQueryBuilder;
}
/**
* Find all Projects for Current User.
* @return A list of all Projects assigned tot he current user
* @throws DataException when elasticsearch query is failing
*/
public List<ProjectDTO> findAllProjectsForCurrentUser() throws DataException {
return findByQuery(getProjectsForCurrentUserQuery(), false);
}
/**
* Get all projects templates for given title and client id.
*
* @param title
* of Project
* @param clientId
* id of client
* @return list of all projects templates as Project objects
*/
public List<Project> getProjectsWithTitleAndClient(String title, Integer clientId) {
String query = "SELECT p FROM Project AS p INNER JOIN p.client AS c WITH c.id = :clientId WHERE p.title = :title";
Map<String, Object> parameters = new HashMap<>();
parameters.put("clientId", clientId);
parameters.put("title", title);
return getByQuery(query, parameters);
}
/**
* Create and return String containing the titles of all given projects joined by a ", ".
* @param projects list of roles
* @return String containing project titles
*/
public static String getProjectTitles(List<Project> projects) {
return projects.stream().map(Project::getTitle).collect(Collectors.joining(", "));
}
/**
* Delete project with ID 'projectID'.
*
* @param projectID ID of project to be deleted
*/
public static void delete(int projectID) throws DAOException, DataException, ProjectDeletionException {
Project project = ServiceManager.getProjectService().getById(projectID);
if (project.getProcesses().size() > 0) {
throw new ProjectDeletionException("cannotDeleteProject");
}
for (User user : project.getUsers()) {
user.getProjects().remove(project);
ServiceManager.getUserService().saveToDatabase(user);
}
for (Template template : project.getTemplates()) {
template.getProjects().remove(project);
ServiceManager.getTemplateService().saveToDatabase(template);
}
ServiceManager.getProjectService().remove(project);
}
}