diff --git a/dmp-backend/core/src/main/java/eu/eudat/audit/AuditableAction.java b/dmp-backend/core/src/main/java/eu/eudat/audit/AuditableAction.java index c7e729331..9f11c37ce 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/audit/AuditableAction.java +++ b/dmp-backend/core/src/main/java/eu/eudat/audit/AuditableAction.java @@ -33,6 +33,7 @@ public class AuditableAction { public static final EventId Dmp_Delete = new EventId(5003, "Dmp_Delete"); public static final EventId Dmp_Clone = new EventId(5004, "Dmp_Clone"); public static final EventId Dmp_PersistNewVersion = new EventId(5005, "Dmp_PersistNewVersion"); + public static final EventId Dmp_Assign_Users = new EventId(5006, "Dmp_Assign_Users"); public static final EventId Description_Query = new EventId(6000, "Description_Query"); public static final EventId Description_Lookup = new EventId(6001, "Description_Lookup"); diff --git a/dmp-backend/core/src/main/java/eu/eudat/authorization/Permission.java b/dmp-backend/core/src/main/java/eu/eudat/authorization/Permission.java index 4912b4ade..fec9a1da9 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/authorization/Permission.java +++ b/dmp-backend/core/src/main/java/eu/eudat/authorization/Permission.java @@ -52,6 +52,9 @@ public final class Permission { public static String DeleteDmp = "DeleteDmp"; public static String CloneDmp = "CloneDmp"; public static String CreateNewVersionDmp = "CreateNewVersionDmp"; + public static String ExportDmp = "ExportDmp"; + public static String FinalizeDmp = "FinalizeDmp"; + public static String AssignDmpUsers = "AssignDmpUsers"; //DmpBlueprint public static String BrowseDmpBlueprint = "BrowseDmpBlueprint"; diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/persist/DmpUserPersist.java b/dmp-backend/core/src/main/java/eu/eudat/model/persist/DmpUserPersist.java new file mode 100644 index 000000000..821a136e6 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/model/persist/DmpUserPersist.java @@ -0,0 +1,28 @@ +package eu.eudat.model.persist; + +import eu.eudat.commons.enums.DmpUserRole; + +import java.util.UUID; + +public class DmpUserPersist { + + private UUID user; + + private DmpUserRole role; + + public UUID getUser() { + return user; + } + + public void setUser(UUID user) { + this.user = user; + } + + public DmpUserRole getRole() { + return role; + } + + public void setRole(DmpUserRole role) { + this.role = role; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/result/QueryResult.java b/dmp-backend/core/src/main/java/eu/eudat/model/result/QueryResult.java index 84cfa612a..52cce8e8b 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/model/result/QueryResult.java +++ b/dmp-backend/core/src/main/java/eu/eudat/model/result/QueryResult.java @@ -8,22 +8,14 @@ public class QueryResult { public QueryResult() { } - public QueryResult(List items, long count, long countOverride) { - this.items = items; - this.count = count; - this.countOverride = countOverride; - } - public QueryResult(List items, long count) { this.items = items; this.count = count; - this.countOverride = 0; } public QueryResult(M item) { this.items = List.of(item); this.count = 1; - this.countOverride = 0; } public QueryResult(List items) { @@ -38,8 +30,6 @@ public class QueryResult { private long count; - private long countOverride; - public List getItems() { return items; } @@ -56,14 +46,6 @@ public class QueryResult { this.count = count; } - public long getCountOverride() { - return countOverride; - } - - public void setCountOverride(long countOverride) { - this.countOverride = countOverride; - } - public static QueryResult empty() { return new QueryResult<>(new ArrayList<>(), 0L); } diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpService.java b/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpService.java index 4e7b05642..afa5079c6 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpService.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpService.java @@ -1,9 +1,11 @@ package eu.eudat.service.dmp; import com.fasterxml.jackson.core.JsonProcessingException; +import eu.eudat.data.DmpUserEntity; import eu.eudat.model.Dmp; import eu.eudat.model.persist.CloneDmpPersist; import eu.eudat.model.persist.DmpPersist; +import eu.eudat.model.persist.DmpUserPersist; import eu.eudat.model.persist.NewVersionDmpPersist; import gr.cite.tools.exception.MyApplicationException; import gr.cite.tools.exception.MyForbiddenException; @@ -15,6 +17,7 @@ import jakarta.xml.bind.JAXBException; import javax.management.InvalidApplicationException; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; +import java.util.List; import java.util.UUID; public interface DmpService { @@ -27,4 +30,6 @@ public interface DmpService { Dmp buildClone(CloneDmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException; + List assignUsers(UUID dmp, List model, FieldSet fields) throws InvalidApplicationException; + } diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpServiceImpl.java b/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpServiceImpl.java index c52ed7124..494053f27 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpServiceImpl.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpServiceImpl.java @@ -17,13 +17,12 @@ import eu.eudat.errorcode.ErrorThesaurusProperties; import eu.eudat.event.DmpTouchedEvent; import eu.eudat.event.EventBroker; import eu.eudat.model.Dmp; -import eu.eudat.model.DmpReference; -import eu.eudat.model.DmpUser; import eu.eudat.model.Reference; import eu.eudat.model.builder.DmpBuilder; import eu.eudat.model.deleter.DmpDeleter; import eu.eudat.model.deleter.DmpDescriptionTemplateDeleter; import eu.eudat.model.deleter.DmpReferenceDeleter; +import eu.eudat.model.deleter.DmpUserDeleter; import eu.eudat.model.persist.*; import eu.eudat.model.persist.referencedefinition.DefinitionPersist; import eu.eudat.model.persist.referencedefinition.FieldPersist; @@ -121,8 +120,6 @@ public class DmpServiceImpl implements DmpService { } public Dmp persist(DmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JsonProcessingException { - logger.debug(new MapLogEntry("persisting data dmp").And("model", model).And("fields", fields)); - this.authorizationService.authorizeForce(Permission.EditDmp); DmpEntity data = this.patchAndSave(model); @@ -146,8 +143,6 @@ public class DmpServiceImpl implements DmpService { @Override public Dmp createNewVersion(NewVersionDmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JAXBException, ParserConfigurationException, JsonProcessingException, TransformerException { - logger.debug(new MapLogEntry("persisting data dmp (new version)").And("model", model).And("fields", fields)); - this.authorizationService.authorizeForce(Permission.CreateNewVersionDmp); DmpEntity oldDmpEntity = this.entityManager.find(DmpEntity.class, model.getId()); @@ -239,8 +234,6 @@ public class DmpServiceImpl implements DmpService { @Override public Dmp buildClone(CloneDmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException { - logger.debug(new MapLogEntry("cloning dmp").And("model", model).And("fields", fields)); - this.authorizationService.authorizeForce(Permission.CloneDmp); DmpEntity existingDmpEntity = this.queryFactory.query(DmpQuery.class).authorize(AuthorizationFlags.OwnerOrPermissionOrMemberOrPublic).ids(model.getId()).firstAs(fields); @@ -319,6 +312,37 @@ public class DmpServiceImpl implements DmpService { return this.builderFactory.builder(DmpBuilder.class).build(fields, resultingDmpEntity); } + @Override + public List assignUsers(UUID dmp, List model, FieldSet fieldSet) throws InvalidApplicationException { + this.authorizationService.authorizeForce(Permission.AssignDmpUsers); + + List existingUsers = this.queryFactory.query(DmpUserQuery.class).dmpIds(dmp).collect(); + + for (DmpUserPersist dmpUser : model) { + if (checkUserRoleIfExists(existingUsers, dmp, dmpUser.getUser(), dmpUser.getRole())) + continue; + + DmpUserEntity newUser = new DmpUserEntity(); + newUser.setId(UUID.randomUUID()); + newUser.setDmp(dmp); + newUser.setUser(dmpUser.getUser()); + newUser.setRole(dmpUser.getRole()); + newUser.setCreatedAt(Instant.now()); + newUser.setUpdatedAt(Instant.now()); + newUser.setIsActive(IsActive.Active); + + this.entityManager.persist(newUser); + } + + //If there are still dmp user associations here this means that they were not included in the persist model, so they have to be deleted + if (!existingUsers.isEmpty()) + this.deleterFactory.deleter(DmpUserDeleter.class).delete(existingUsers); + + this.entityManager.flush(); + + return this.queryFactory.query(DmpUserQuery.class).dmpIds().collect(); + } + private DmpEntity patchAndSave(DmpPersist model) throws JsonProcessingException, InvalidApplicationException { Boolean isUpdate = this.conventionService.isValidGuid(model.getId()); @@ -328,7 +352,11 @@ public class DmpServiceImpl implements DmpService { data = this.entityManager.find(DmpEntity.class, model.getId()); if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), Dmp.class.getSimpleName()}, LocaleContextHolder.getLocale())); if (!this.conventionService.hashValue(data.getUpdatedAt()).equals(model.getHash())) throw new MyValidationException(this.errors.getHashConflict().getCode(), this.errors.getHashConflict().getMessage()); - data.setStatus(model.getStatus()); + if (model.getStatus() != null && model.getStatus() == DmpStatus.Finalized && data.getStatus() != DmpStatus.Finalized) { + this.authorizationService.authorizeForce(Permission.FinalizeDmp); + data.setStatus(model.getStatus()); + data.setFinalizedAt(Instant.now()); + } } else { data = new DmpEntity(); data.setId(UUID.randomUUID()); @@ -492,4 +520,14 @@ public class DmpServiceImpl implements DmpService { return data; } + private boolean checkUserRoleIfExists(List dmpUserEntities, UUID dmp, UUID user, DmpUserRole role) { + for (DmpUserEntity dmpUser : dmpUserEntities) { + if (dmpUser.getDmp().equals(dmp) && dmpUser.getUser().equals(user) && dmpUser.getRole() == role) { + dmpUserEntities.remove(dmpUser); + return true; + }; + } + return false; + } + } diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/v2/DmpController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/v2/DmpController.java index 5e2603ada..416e49c82 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/v2/DmpController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/v2/DmpController.java @@ -4,11 +4,15 @@ import com.fasterxml.jackson.core.JsonProcessingException; import eu.eudat.audit.AuditableAction; import eu.eudat.authorization.AuthorizationFlags; import eu.eudat.data.DmpEntity; +import eu.eudat.data.DmpUserEntity; import eu.eudat.model.Dmp; +import eu.eudat.model.DmpUser; import eu.eudat.model.builder.DmpBuilder; +import eu.eudat.model.builder.DmpUserBuilder; import eu.eudat.model.censorship.DmpCensor; import eu.eudat.model.persist.CloneDmpPersist; import eu.eudat.model.persist.DmpPersist; +import eu.eudat.model.persist.DmpUserPersist; import eu.eudat.model.persist.NewVersionDmpPersist; import eu.eudat.model.result.QueryResult; import eu.eudat.query.DmpQuery; @@ -110,6 +114,7 @@ public class DmpController { @Transactional public Dmp Persist(@MyValidate @RequestBody DmpPersist model, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, JsonProcessingException { logger.debug(new MapLogEntry("persisting" + Dmp.class.getSimpleName()).And("model", model).And("fieldSet", fieldSet)); + Dmp persisted = this.dmpService.persist(model, fieldSet); this.auditService.track(AuditableAction.Dmp_Persist, Map.ofEntries( @@ -150,6 +155,7 @@ public class DmpController { @Transactional public Dmp createNewVersion(@MyValidate @RequestBody NewVersionDmpPersist model, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException, JAXBException, JsonProcessingException, TransformerException, InvalidApplicationException, ParserConfigurationException { logger.debug(new MapLogEntry("persisting" + NewVersionDmpPersist.class.getSimpleName()).And("model", model).And("fieldSet", fieldSet)); + Dmp persisted = this.dmpService.createNewVersion(model, fieldSet); this.auditService.track(AuditableAction.Dmp_PersistNewVersion, Map.ofEntries( @@ -160,4 +166,21 @@ public class DmpController { return persisted; } + @PostMapping("{id}/assign-users") + @Transactional + public QueryResult assignUsers(@PathVariable("id") UUID id, @MyValidate @RequestBody List model, FieldSet fieldSet) throws InvalidApplicationException { + logger.debug(new MapLogEntry("assigning users to dmp").And("model", model).And("fieldSet", fieldSet)); + + List persisted = this.dmpService.assignUsers(id, model, fieldSet); + + this.auditService.track(AuditableAction.Dmp_Assign_Users, Map.ofEntries( + new AbstractMap.SimpleEntry("model", model), + new AbstractMap.SimpleEntry("fields", fieldSet) + )); + + List models = this.builderFactory.builder(DmpUserBuilder.class).build(fieldSet, persisted); + + return new QueryResult<>(models); + } + } diff --git a/dmp-backend/web/src/main/resources/config/permissions.yml b/dmp-backend/web/src/main/resources/config/permissions.yml index b8d0c1ebd..87b7bf40c 100644 --- a/dmp-backend/web/src/main/resources/config/permissions.yml +++ b/dmp-backend/web/src/main/resources/config/permissions.yml @@ -249,13 +249,13 @@ permissions: clients: [ ] allowAnonymous: false allowAuthenticated: false - CloneDmp: - roles: - - Admin - claims: [ ] - clients: [ ] - allowAnonymous: false - allowAuthenticated: false + CloneDmp: + roles: + - Admin + claims: [ ] + clients: [ ] + allowAnonymous: false + allowAuthenticated: false CreateNewVersionDmp: roles: - Admin @@ -263,6 +263,27 @@ permissions: clients: [ ] allowAnonymous: false allowAuthenticated: false + ExportDmp: + roles: + - Admin + claims: [ ] + clients: [ ] + allowAnonymous: false + allowAuthenticated: false + FinalizeDmp: + roles: + - Admin + claims: [ ] + clients: [ ] + allowAnonymous: false + allowAuthenticated: false + AssignDmpUsers: + roles: + - Admin + claims: [ ] + clients: [ ] + allowAnonymous: false + allowAuthenticated: false # DmpBlueprint BrowseDmpBlueprint: roles: