package eu.dnetlib.uoamonitorservice.service; import eu.dnetlib.uoaadmintoolslibrary.handlers.ForbiddenException; import eu.dnetlib.uoamonitorservice.dao.CategoryDAO; import eu.dnetlib.uoamonitorservice.dao.StakeholderDAO; import eu.dnetlib.uoamonitorservice.dao.TopicDAO; import eu.dnetlib.uoamonitorservice.dto.CategoryFull; import eu.dnetlib.uoamonitorservice.entities.Category; import eu.dnetlib.uoamonitorservice.entities.Stakeholder; import eu.dnetlib.uoamonitorservice.entities.Topic; import eu.dnetlib.uoamonitorservice.generics.Common; import eu.dnetlib.uoamonitorservice.handlers.EntityNotFoundException; import eu.dnetlib.uoamonitorservice.handlers.PathNotValidException; import eu.dnetlib.uoamonitorservice.primitives.Visibility; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.stream.Collectors; @Service public class CategoryService { private final StakeholderDAO stakeholderDAO; private final TopicDAO topicDAO; private final CategoryDAO dao; private final SubCategoryService subCategoryService; private final CommonService commonService; @Autowired public CategoryService(StakeholderDAO stakeholderDAO, TopicDAO topicDAO, CategoryDAO dao, SubCategoryService subCategoryService, CommonService commonService) { this.stakeholderDAO = stakeholderDAO; this.topicDAO = topicDAO; this.dao = dao; this.subCategoryService = subCategoryService; this.commonService = commonService; } public Category find(String id) { return dao.findById(id).orElseThrow(() -> new EntityNotFoundException("Category with id: " + id + " not found")); } public Category findByPath(Topic topic, String categoryId) { if (!topic.getCategories().contains(categoryId)) { throw new PathNotValidException("Category with id: " + categoryId + " not found in Topic: " + topic.getId()); } return this.dao.findById(categoryId).orElseThrow(() -> new EntityNotFoundException("Category with id: " + categoryId + " not found")); } public CategoryFull getFullCategory(String type, String alias, Category category) { if (commonService.hasVisibilityAuthority(type, alias, category)) { return new CategoryFull(category, category.getSubCategories().stream() .map(subCategoryId -> this.subCategoryService.getFullSubCategory(type, alias, subCategoryId)) .collect(Collectors.toList())); } else { return null; } } public CategoryFull getFullCategory(String type, String alias, String categoryId) { Category category = this.find(categoryId); return this.getFullCategory(type, alias, category); } public CategoryFull buildCategory(CategoryFull categoryFull) { categoryFull.setSubCategories(categoryFull.getSubCategories().stream().map(this.subCategoryService::buildSubcategory).collect(Collectors.toList())); categoryFull.update(this.save(new Category(categoryFull))); return categoryFull; } public Category save(Category category) { if(category.getId() != null) { category.setSubCategories(this.find(category.getId()).getSubCategories()); } else { category.setCreationDate(new Date()); } category.setUpdateDate(new Date()); category.getSubCategories().forEach(this.subCategoryService::find); return this.dao.save(category); } public CategoryFull save(Stakeholder stakeholder, Topic topic, Category category) { return this.save(stakeholder, topic, category, true); } public CategoryFull save(Stakeholder stakeholder, Topic topic, Category category, boolean createOverview) { if (category.getId() != null) { if (this.commonService.hasEditAuthority(stakeholder.getType(), stakeholder.getAlias())) { category.setSubCategories(this.find(category.getId()).getSubCategories()); this.updateChildren(category); category = this.save(category); } else { throw new ForbiddenException("You are not authorized to update stakeholder with id: " + stakeholder.getId()); } } else { if (this.commonService.hasCreateAuthority(stakeholder.getType())) { category = this.save(category); this.createChildren(topic, category); if(createOverview) { this.subCategoryService.save(stakeholder, category, category.createOverview()); } this.addCategory(topic, category.getId()); } else { throw new ForbiddenException("You are not authorized to create a category in stakeholder with id: " + stakeholder.getId()); } } return this.getFullCategory(stakeholder.getType(), stakeholder.getAlias(), category); } public void createChildren(Topic defaultTopic, Category category) { this.topicDAO.findByDefaultId(defaultTopic.getId()).forEach(topic -> { this.stakeholderDAO.findByTopicsContaining(topic.getId()).forEach(stakeholder -> { this.save(stakeholder, topic, category.copy(), false); }); }); } public void updateChildren(Category category) { this.dao.findByDefaultId(category.getId()).forEach(child -> { this.save(category.override(child, this.find(category.getId()))); }); } public CategoryFull reorderSubCategories(Stakeholder stakeholder, Category category, List subcategories) { if(this.commonService.hasEditAuthority(stakeholder.getType(), stakeholder.getAlias())) { subcategories.forEach(this.subCategoryService::find); if (category.getSubCategories().size() == subcategories.size() && new HashSet<>(category.getSubCategories()).containsAll(subcategories)) { category.setSubCategories(subcategories); category.setUpdateDate(new Date()); this.reorderChildren(stakeholder, category, subcategories); return this.getFullCategory(stakeholder.getType(), stakeholder.getAlias(), this.dao.save(category)); } else { throw new EntityNotFoundException("Some subCategories dont exist in the category with id " + category.getId()); } } else { throw new ForbiddenException("You are not authorized to reorder subCategories in category with id: " + category.getId()); } } public void reorderChildren(Stakeholder defaultStakeholder, Category defaultCategory, List defaultSubCategories) { this.stakeholderDAO.findByDefaultId(defaultStakeholder.getId()).forEach(stakeholder -> { this.dao.findByDefaultId(defaultCategory.getId()).stream().map(category -> this.getFullCategory(stakeholder.getType(), stakeholder.getAlias(), category)).forEach(category -> { this.reorderSubCategories(stakeholder, new Category(category), this.commonService.reorder(defaultSubCategories, category.getSubCategories().stream().map(subCategory -> (Common) subCategory).collect(Collectors.toList()))); }); }); } public void delete(String type, Category category, boolean remove) { if (this.commonService.hasDeleteAuthority(type)) { this.dao.findByDefaultId(category.getId()).forEach(child -> { this.delete(type, child.getId(), remove); }); category.getSubCategories().forEach(subcategoryId -> { this.subCategoryService.delete(type, subcategoryId, false); }); if (remove) { this.removeCategory(category.getId()); } this.dao.delete(category); } else { throw new ForbiddenException("Delete category: You are not authorized to delete category with id: " + category.getId()); } } public void delete(String type, String id, boolean remove) { Category category = this.find(id); this.delete(type, category, remove); } public void addCategory(Topic topic, String id) { topic.addCategory(id); topic.setUpdateDate(new Date()); this.topicDAO.save(topic); } public void removeCategory(String id) { this.topicDAO.findByCategoriesContaining(id).forEach(topic -> { topic.removeCategory(id); topic.setUpdateDate(new Date()); this.topicDAO.save(topic); }); } public CategoryFull changeVisibility(String type, String alias, CategoryFull category, Visibility visibility, Boolean propagate) { if (this.commonService.hasEditAuthority(type, alias)) { category.setVisibility(visibility); if (propagate) { category.setSubCategories(category.getSubCategories().stream() .map(subCategory -> this.subCategoryService.changeVisibility(type, alias, subCategory, visibility, true)) .collect(Collectors.toList())); } category.update(this.save(new Category(category))); return category; } else { throw new ForbiddenException("Change category visibility: You are not authorized to update category with id: " + category.getId()); } } public CategoryFull changeVisibility(String type, String alias, Category category, Visibility visibility, Boolean propagate) { CategoryFull categoryFull = this.getFullCategory(type, alias, category); return this.changeVisibility(type, alias, categoryFull, visibility, propagate); } }