From cef1e295f7b8c12937510d130c829ab3a5216038 Mon Sep 17 00:00:00 2001 From: sgiannopoulos Date: Thu, 14 Mar 2024 11:23:46 +0200 Subject: [PATCH] dmp authz changes --- .../DmpBlueprintValueCensor.java | 2 +- .../dmpproperties/DmpContactCensor.java | 4 +- .../dmpproperties/DmpPropertiesCensor.java | 2 +- .../dmpreference/DmpReferenceDataCensor.java | 2 +- .../java/eu/eudat/query/EntityDoiQuery.java | 3 +- .../main/java/eu/eudat/query/UserQuery.java | 2 +- .../java/eu/eudat/service/dmp/DmpService.java | 5 +- .../eu/eudat/service/dmp/DmpServiceImpl.java | 35 +++++++----- .../eudat/service/lock/LockServiceImpl.java | 25 +++++---- .../eu/eudat/controllers/DmpController.java | 2 +- .../eu/eudat/controllers/LockController.java | 10 ++-- .../src/main/resources/config/permissions.yml | 54 +++++++++++++++++++ dmp-frontend/src/app/core/model/dmp/dmp.ts | 6 ++- .../dmp-editor.component.ts | 2 +- .../dmp-editor.resolver.ts | 3 ++ .../dmp-editor.routing.ts | 9 ++-- .../ui/dmp/overview/dmp-overview.component.ts | 31 +++++++---- 17 files changed, 138 insertions(+), 59 deletions(-) diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/censorship/dmpproperties/DmpBlueprintValueCensor.java b/dmp-backend/core/src/main/java/eu/eudat/model/censorship/dmpproperties/DmpBlueprintValueCensor.java index bb73313a4..f1228f49c 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/model/censorship/dmpproperties/DmpBlueprintValueCensor.java +++ b/dmp-backend/core/src/main/java/eu/eudat/model/censorship/dmpproperties/DmpBlueprintValueCensor.java @@ -33,7 +33,7 @@ public class DmpBlueprintValueCensor extends BaseCensor { if (fields == null || fields.isEmpty()) return; - this.authService.authorizeForce(Permission.BrowseDmp); + this.authService.authorizeForce(Permission.BrowseDmp, Permission.DeferredAffiliation); } } diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/censorship/dmpproperties/DmpContactCensor.java b/dmp-backend/core/src/main/java/eu/eudat/model/censorship/dmpproperties/DmpContactCensor.java index c02ccee9c..25fa7d3e5 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/model/censorship/dmpproperties/DmpContactCensor.java +++ b/dmp-backend/core/src/main/java/eu/eudat/model/censorship/dmpproperties/DmpContactCensor.java @@ -3,10 +3,8 @@ package eu.eudat.model.censorship.dmpproperties; import eu.eudat.authorization.Permission; import eu.eudat.convention.ConventionService; import eu.eudat.model.censorship.BaseCensor; -import eu.eudat.model.censorship.DmpCensor; import eu.eudat.model.censorship.UserCensor; import eu.eudat.model.dmpproperties.DmpContact; -import eu.eudat.model.dmpproperties.DmpProperties; import gr.cite.commons.web.authz.service.AuthorizationService; import gr.cite.tools.data.censor.CensorFactory; import gr.cite.tools.fieldset.FieldSet; @@ -40,7 +38,7 @@ public class DmpContactCensor extends BaseCensor { if (fields == null || fields.isEmpty()) return; - this.authService.authorizeForce(Permission.BrowseDmp); + this.authService.authorizeForce(Permission.BrowseDmp, Permission.DeferredAffiliation); FieldSet userFields = fields.extractPrefixed(this.asIndexerPrefix(DmpContact._user)); this.censorFactory.censor(UserCensor.class).censor(userFields, userId); } diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/censorship/dmpproperties/DmpPropertiesCensor.java b/dmp-backend/core/src/main/java/eu/eudat/model/censorship/dmpproperties/DmpPropertiesCensor.java index 96ef0656d..2f57498b5 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/model/censorship/dmpproperties/DmpPropertiesCensor.java +++ b/dmp-backend/core/src/main/java/eu/eudat/model/censorship/dmpproperties/DmpPropertiesCensor.java @@ -38,7 +38,7 @@ public class DmpPropertiesCensor extends BaseCensor { if (fields == null || fields.isEmpty()) return; - this.authService.authorizeForce(Permission.BrowseDmp); + this.authService.authorizeForce(Permission.BrowseDmp, Permission.DeferredAffiliation); FieldSet dmpBlueprintValuesFields = fields.extractPrefixed(this.asIndexerPrefix(DmpProperties._dmpBlueprintValues)); this.censorFactory.censor(DmpBlueprintValueCensor.class).censor(dmpBlueprintValuesFields, userId); FieldSet contactsFields = fields.extractPrefixed(this.asIndexerPrefix(DmpProperties._contacts)); diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/censorship/dmpreference/DmpReferenceDataCensor.java b/dmp-backend/core/src/main/java/eu/eudat/model/censorship/dmpreference/DmpReferenceDataCensor.java index 6c90f9992..acda2c753 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/model/censorship/dmpreference/DmpReferenceDataCensor.java +++ b/dmp-backend/core/src/main/java/eu/eudat/model/censorship/dmpreference/DmpReferenceDataCensor.java @@ -36,7 +36,7 @@ public class DmpReferenceDataCensor extends BaseCensor { if (fields == null || fields.isEmpty()) return; - this.authService.authorizeForce(Permission.BrowseDmpDescriptionTemplate); + this.authService.authorizeForce(Permission.BrowseDmpDescriptionTemplate, Permission.DeferredAffiliation); } } diff --git a/dmp-backend/core/src/main/java/eu/eudat/query/EntityDoiQuery.java b/dmp-backend/core/src/main/java/eu/eudat/query/EntityDoiQuery.java index 79517b349..c4bb9408e 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/query/EntityDoiQuery.java +++ b/dmp-backend/core/src/main/java/eu/eudat/query/EntityDoiQuery.java @@ -17,6 +17,7 @@ import gr.cite.tools.data.query.QueryContext; import jakarta.persistence.Tuple; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.Predicate; +import jakarta.persistence.criteria.Subquery; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @@ -189,7 +190,7 @@ public class EntityDoiQuery extends QueryBase { List predicates = new ArrayList<>(); boolean usePublic = this.authorize.contains(AuthorizationFlags.Public); if (userId != null || usePublic) { - predicates.add(queryContext.CriteriaBuilder.in(queryContext.Root.get(EntityDoiEntity._entityId)).value( queryContext.CriteriaBuilder.in(queryContext.Root.get(DmpUserEntity._dmpId)).value(queryUtilsService.buildDmpAuthZSubQuery(queryContext.Query, queryContext.CriteriaBuilder, userId, usePublic)))); + predicates.add(queryContext.CriteriaBuilder.in(queryContext.Root.get(EntityDoiEntity._entityId)).value(queryUtilsService.buildDmpAuthZSubQuery(queryContext.Query, queryContext.CriteriaBuilder, userId, usePublic))); } if (!predicates.isEmpty()) { Predicate[] predicatesArray = predicates.toArray(new Predicate[0]); diff --git a/dmp-backend/core/src/main/java/eu/eudat/query/UserQuery.java b/dmp-backend/core/src/main/java/eu/eudat/query/UserQuery.java index 6fb6d78b6..6f73c6b15 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/query/UserQuery.java +++ b/dmp-backend/core/src/main/java/eu/eudat/query/UserQuery.java @@ -150,7 +150,7 @@ public class UserQuery extends QueryBase { if (this.authorize.contains(AuthorizationFlags.Permission) && this.authService.authorize(Permission.BrowseUser)) return null; UUID userId; if (this.authorize.contains(AuthorizationFlags.Owner)) userId = this.userScope.getUserIdSafe(); - if (this.authorize.contains(AuthorizationFlags.Public)) userId = this.userScope.getUserIdSafe(); + if (this.authorize.contains(AuthorizationFlags.DmpAssociated)) userId = this.userScope.getUserIdSafe(); else userId = null; List predicates = new ArrayList<>(); 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 76e92b64b..3e405ea24 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,8 +1,5 @@ package eu.eudat.service.dmp; -import com.fasterxml.jackson.core.JsonProcessingException; -import eu.eudat.data.DmpEntity; -import eu.eudat.data.DmpUserEntity; import eu.eudat.model.Dmp; import eu.eudat.model.DmpUser; import eu.eudat.model.persist.*; @@ -36,7 +33,7 @@ public interface DmpService { ResponseEntity export(UUID id, String transformerId, String exportType) throws InvalidApplicationException, IOException; - void inviteUsers(UUID id, List users) throws InvalidApplicationException, JAXBException, IOException; + void inviteUserOrAssignUsers(UUID id, List users) throws InvalidApplicationException, JAXBException, IOException; void dmpInvitationAccept(String token) throws InvalidApplicationException, IOException; 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 05463eedb..530f61038 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 @@ -191,6 +191,12 @@ public class DmpServiceImpl implements DmpService { this.patchAndSaveTemplates(data.getId(), model.getDescriptionTemplates()); + if (!isUpdate || userScope.isSet()) { + this.addOwner(data); + if (model.getUsers() == null) model.setUsers(new ArrayList<>()); + if (model.getUsers().stream().noneMatch(x-> x.getUser() != null && x.getUser().equals(this.userScope.getUserIdSafe()) && DmpUserRole.Owner.equals(x.getRole()))) model.getUsers().add(this.createOwnerPersist()); + } + this.eventBroker.emit(new DmpTouchedEvent(data.getId())); this.dmpTouchedIntegrationEventHandler.handle(DmpTouchedIntegrationEventHandler.buildEventFromPersistModel(model)); @@ -198,12 +204,9 @@ public class DmpServiceImpl implements DmpService { this.annotationEntityTouchedIntegrationEventHandler.handle(AnnotationEntityTouchedIntegrationEventHandler.buildEventFromPersistModel(model)); this.sendNotification(data); - + if (!this.conventionService.isListNullOrEmpty(model.getUsers())){ - this.inviteUsers(data.getId(), model.getUsers()); - }else{ - this.addOwner(data); - this.assignUsers(data.getId(), new ArrayList<>(), null); + this.inviteUserOrAssignUsers(data.getId(), model.getUsers()); } this.elasticService.persistDmp(data); @@ -211,6 +214,13 @@ public class DmpServiceImpl implements DmpService { return this.builderFactory.builder(DmpBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(BaseFieldSet.build(fields, Dmp._id, Dmp._hash), data); } + private DmpUserPersist createOwnerPersist() { + DmpUserPersist persist = new DmpUserPersist(); + persist.setRole(DmpUserRole.Owner); + persist.setUser(userScope.getUserIdSafe()); + return persist; + } + private void addOwner(DmpEntity dmpEntity) throws InvalidApplicationException { DmpUserEntity data = new DmpUserEntity(); data.setId(UUID.randomUUID()); @@ -286,14 +296,14 @@ public class DmpServiceImpl implements DmpService { public void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException, IOException { logger.debug("deleting dmp: {}", id); - this.authorizationService.authorizeForce(Permission.DeleteDmp); + this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.dmpAffiliation(id)), Permission.DeleteDmp); this.deleterFactory.deleter(DmpDeleter.class).deleteAndSaveByIds(List.of(id), false); } @Override public Dmp createNewVersion(NewVersionDmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JAXBException, ParserConfigurationException, IOException, TransformerException { - this.authorizationService.authorizeForce(Permission.CreateNewVersionDmp); + this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.dmpAffiliation( model.getId())), Permission.CreateNewVersionDmp); DmpEntity oldDmpEntity = this.entityManager.find(DmpEntity.class, model.getId()); if (oldDmpEntity == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), Dmp.class.getSimpleName()}, LocaleContextHolder.getLocale())); @@ -395,7 +405,7 @@ public class DmpServiceImpl implements DmpService { @Override public Dmp buildClone(CloneDmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, IOException, InvalidApplicationException { - this.authorizationService.authorizeForce(Permission.CloneDmp); + this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.dmpAffiliation( model.getId())), Permission.CloneDmp); DmpEntity existingDmpEntity = this.queryFactory.query(DmpQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).ids(model.getId()).firstAs(fields); if (!this.conventionService.isValidGuid(model.getId()) || existingDmpEntity == null) @@ -527,7 +537,7 @@ public class DmpServiceImpl implements DmpService { @Override public Dmp removeUser(DmpUserRemovePersist model, FieldSet fields) throws InvalidApplicationException, IOException { - this.authorizationService.authorizeForce(Permission.AssignDmpUsers); + this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.dmpAffiliation(model.getDmpId())), Permission.AssignDmpUsers); DmpEntity data = this.entityManager.find(DmpEntity.class, model.getDmpId()); if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), Dmp.class.getSimpleName()}, LocaleContextHolder.getLocale())); @@ -566,7 +576,7 @@ public class DmpServiceImpl implements DmpService { 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()); if (model.getStatus() != null && model.getStatus() == DmpStatus.Finalized && data.getStatus() != DmpStatus.Finalized) { - this.authorizationService.authorizeForce(Permission.FinalizeDmp); + this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.dmpAffiliation(model.getId())), Permission.FinalizeDmp); data.setStatus(model.getStatus()); data.setFinalizedAt(Instant.now()); } @@ -807,9 +817,8 @@ public class DmpServiceImpl implements DmpService { } // invites - public void inviteUsers(UUID id, List users) throws InvalidApplicationException, JAXBException, IOException { - - this.authorizationService.authorizeForce(Permission.InviteDmpUsers); + public void inviteUserOrAssignUsers(UUID id, List users) throws InvalidApplicationException, JAXBException, IOException { + this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.dmpAffiliation(id)), Permission.InviteDmpUsers); DmpEntity dmp = this.queryFactory.query(DmpQuery.class).ids(id).first(); if (dmp == null){ diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/lock/LockServiceImpl.java b/dmp-backend/core/src/main/java/eu/eudat/service/lock/LockServiceImpl.java index 779bf5316..334b0a83b 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/lock/LockServiceImpl.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/lock/LockServiceImpl.java @@ -2,6 +2,7 @@ package eu.eudat.service.lock; import eu.eudat.authorization.AuthorizationFlags; import eu.eudat.authorization.Permission; +import eu.eudat.authorization.authorizationcontentresolver.AuthorizationContentResolver; import eu.eudat.commons.scope.user.UserScope; import eu.eudat.convention.ConventionService; import eu.eudat.data.LockEntity; @@ -51,18 +52,19 @@ public class LockServiceImpl implements LockService { private final ConventionService conventionService; private final MessageSource messageSource; private final ErrorThesaurusProperties errors; + private final AuthorizationContentResolver authorizationContentResolver; @Autowired public LockServiceImpl( - EntityManager entityManager, - UserScope userScope, - AuthorizationService authorizationService, - DeleterFactory deleterFactory, - BuilderFactory builderFactory, - QueryFactory queryFactory, - ConventionService conventionService, - MessageSource messageSource, - ErrorThesaurusProperties errors) { + EntityManager entityManager, + UserScope userScope, + AuthorizationService authorizationService, + DeleterFactory deleterFactory, + BuilderFactory builderFactory, + QueryFactory queryFactory, + ConventionService conventionService, + MessageSource messageSource, + ErrorThesaurusProperties errors, AuthorizationContentResolver authorizationContentResolver) { this.entityManager = entityManager; this.userScope = userScope; this.authorizationService = authorizationService; @@ -72,12 +74,13 @@ public class LockServiceImpl implements LockService { this.conventionService = conventionService; this.messageSource = messageSource; this.errors = errors; + this.authorizationContentResolver = authorizationContentResolver; } public Lock persist(LockPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException { logger.debug(new MapLogEntry("persisting data").And("model", model).And("fields", fields)); - this.authorizationService.authorizeForce(Permission.EditLock); + this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.dmpAffiliation(model.getTarget())), Permission.EditLock); Boolean isUpdate = this.conventionService.isValidGuid(model.getId()); @@ -176,7 +179,7 @@ public class LockServiceImpl implements LockService { public void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException { logger.debug("deleting : {}", id); - this.authorizationService.authorizeForce(Permission.DeleteLock); + this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.dmpAffiliation(id)), Permission.DeleteLock); this.deleterFactory.deleter(LockDeleter.class).deleteAndSaveByIds(List.of(id)); } diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/DmpController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/DmpController.java index e31b0b3ef..b1d068870 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/DmpController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/DmpController.java @@ -256,7 +256,7 @@ public class DmpController { public boolean inviteUsers(@PathVariable("id") UUID id, @RequestBody DmpUserInvitePersist model) throws InvalidApplicationException, JAXBException, IOException { logger.debug(new MapLogEntry("inviting users to dmp").And("model", model)); - this.dmpService.inviteUsers(id, model.getUsers()); + this.dmpService.inviteUserOrAssignUsers(id, model.getUsers()); this.auditService.track(AuditableAction.Dmp_Invite_Users, Map.ofEntries( new AbstractMap.SimpleEntry("model", model) diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/LockController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/LockController.java index 1478f3cb2..8e8d98ba3 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/LockController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/LockController.java @@ -3,6 +3,7 @@ package eu.eudat.controllers; import eu.eudat.audit.AuditableAction; import eu.eudat.authorization.AuthorizationFlags; import eu.eudat.authorization.Permission; +import eu.eudat.authorization.authorizationcontentresolver.AuthorizationContentResolver; import gr.cite.tools.validation.ValidationFilterAnnotation; import eu.eudat.data.LockEntity; import eu.eudat.model.Lock; @@ -62,14 +63,14 @@ public class LockController { private final MessageSource messageSource; private final AuthorizationService authService; - + private final AuthorizationContentResolver authorizationContentResolver; @Autowired public LockController(BuilderFactory builderFactory, AuditService auditService, LockService lockService, CensorFactory censorFactory, QueryFactory queryFactory, - MessageSource messageSource, AuthorizationService authService) { + MessageSource messageSource, AuthorizationService authService, AuthorizationContentResolver authorizationContentResolver) { this.builderFactory = builderFactory; this.auditService = auditService; this.lockService = lockService; @@ -77,6 +78,7 @@ public class LockController { this.queryFactory = queryFactory; this.messageSource = messageSource; this.authService = authService; + this.authorizationContentResolver = authorizationContentResolver; } @PostMapping("query") @@ -154,7 +156,7 @@ public class LockController { @GetMapping("target/status/{id}") public Boolean getLocked(@PathVariable("id") UUID targetId) throws Exception { logger.debug(new MapLogEntry("is locked" + Lock.class.getSimpleName()).And("targetId", targetId)); - this.authService.authorizeForce(Permission.BrowseLock); + this.authService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.dmpAffiliation(targetId)), Permission.BrowseLock); Boolean isLocked = this.lockService.isLocked(targetId); this.auditService.track(AuditableAction.Lock_IsLocked, Map.ofEntries( @@ -167,7 +169,7 @@ public class LockController { @DeleteMapping("target/unlock/{id}") public boolean unlock(@PathVariable("id") UUID targetId) throws Exception { logger.debug(new MapLogEntry("unlock" + Lock.class.getSimpleName()).And("targetId", targetId)); - this.authService.authorizeForce(Permission.BrowseLock); + this.authService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.dmpAffiliation(targetId)), Permission.BrowseLock); this.lockService.unlock(targetId); this.auditService.track(AuditableAction.Lock_UnLocked, Map.ofEntries( diff --git a/dmp-backend/web/src/main/resources/config/permissions.yml b/dmp-backend/web/src/main/resources/config/permissions.yml index 8a491b84f..d721300ba 100644 --- a/dmp-backend/web/src/main/resources/config/permissions.yml +++ b/dmp-backend/web/src/main/resources/config/permissions.yml @@ -342,6 +342,12 @@ permissions: DeleteDmp: roles: - Admin + dmp: + roles: + - Owner + - User + - DescriptionContributor + - Reviewer claims: [ ] clients: [ ] allowAnonymous: false @@ -349,6 +355,12 @@ permissions: CloneDmp: roles: - Admin + dmp: + roles: + - Owner + - User + - DescriptionContributor + - Reviewer claims: [ ] clients: [ ] allowAnonymous: false @@ -356,6 +368,12 @@ permissions: CreateNewVersionDmp: roles: - Admin + dmp: + roles: + - Owner + - User + - DescriptionContributor + - Reviewer claims: [ ] clients: [ ] allowAnonymous: false @@ -363,6 +381,12 @@ permissions: ExportDmp: roles: - Admin + dmp: + roles: + - Owner + - User + - DescriptionContributor + - Reviewer claims: [ ] clients: [ ] allowAnonymous: false @@ -370,6 +394,12 @@ permissions: FinalizeDmp: roles: - Admin + dmp: + roles: + - Owner + - User + - DescriptionContributor + - Reviewer claims: [ ] clients: [ ] allowAnonymous: false @@ -390,6 +420,12 @@ permissions: InviteDmpUsers: roles: - Admin + dmp: + roles: + - Owner + - User + - DescriptionContributor + - Reviewer claims: [ ] clients: [ ] allowAnonymous: false @@ -709,18 +745,36 @@ permissions: BrowseLock: roles: - Admin + dmp: + roles: + - Owner + - User + - DescriptionContributor + - Reviewer clients: [ ] allowAnonymous: false allowAuthenticated: false EditLock: roles: - Admin + dmp: + roles: + - Owner + - User + - DescriptionContributor + - Reviewer clients: [ ] allowAnonymous: false allowAuthenticated: false DeleteLock: roles: - Admin + dmp: + roles: + - Owner + - User + - DescriptionContributor + - Reviewer claims: [ ] clients: [ ] allowAnonymous: false diff --git a/dmp-frontend/src/app/core/model/dmp/dmp.ts b/dmp-frontend/src/app/core/model/dmp/dmp.ts index e1ec8da29..bb39635fc 100644 --- a/dmp-frontend/src/app/core/model/dmp/dmp.ts +++ b/dmp-frontend/src/app/core/model/dmp/dmp.ts @@ -12,6 +12,7 @@ import { ReferencePersist } from '../reference/reference'; import { DmpAssociatedUser, User } from "../user/user"; import { DmpReference } from './dmp-reference'; import { IsActive } from '@app/core/common/enum/is-active.enum'; +import { AppPermission } from '@app/core/common/enum/permission.enum'; export interface Dmp extends BaseEntity { label?: string; @@ -33,6 +34,7 @@ export interface Dmp extends BaseEntity { descriptions?: Description[]; dmpDescriptionTemplates?: DmpDescriptionTemplate[]; entityDois?: EntityDoi[]; + authorizationFlags?: AppPermission[]; } export interface DmpProperties { @@ -68,9 +70,9 @@ export interface DmpDescriptionTemplate extends BaseEntity { sectionId?: Guid; } -// +// // Persist -// +// export interface DmpPersist extends BaseEntityPersist { label: string; status: DmpStatus; diff --git a/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.component.ts b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.component.ts index 7fd742b87..b106ed4b4 100644 --- a/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.component.ts +++ b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.component.ts @@ -196,7 +196,7 @@ export class DmpEditorComponent extends BaseEditor implemen } buildForm() { - const canedit = this.isNew ? this.authService.hasPermission(AppPermission.NewDmp) : this.authService.hasPermission(AppPermission.EditDmp); + const canedit = this.isNew ? this.authService.hasPermission(AppPermission.NewDmp) : this.item.authorizationFlags?.some(x => x === AppPermission.EditDmp) || this.authService.hasPermission(AppPermission.EditDmp); this.formGroup = this.editorModel.buildForm(null, this.isDeleted || !canedit); if (this.editorModel.status == DmpStatus.Finalized || this.isDeleted) { diff --git a/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.resolver.ts b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.resolver.ts index dfa905242..a015d5cd2 100644 --- a/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.resolver.ts +++ b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.resolver.ts @@ -1,5 +1,6 @@ import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; +import { AppPermission } from '@app/core/common/enum/permission.enum'; import { Description } from '@app/core/model/description/description'; import { DescriptionTemplatesInSection, DmpBlueprint, DmpBlueprintDefinition, DmpBlueprintDefinitionSection, ExtraFieldInSection, FieldInSection, ReferenceTypeFieldInSection, SystemFieldInSection } from '@app/core/model/dmp-blueprint/dmp-blueprint'; import { Dmp, DmpBlueprintValue, DmpContact, DmpDescriptionTemplate, DmpProperties, DmpUser } from '@app/core/model/dmp/dmp'; @@ -38,6 +39,8 @@ export class DmpEditorResolver extends BaseEditorResolver { nameof(x => x.publicAfter), nameof(x => x.hash), + [nameof(x => x.authorizationFlags), AppPermission.EditDmp].join('.'), + [nameof(x => x.properties), nameof(x => x.dmpBlueprintValues), nameof(x => x.fieldId)].join('.'), [nameof(x => x.properties), nameof(x => x.dmpBlueprintValues), nameof(x => x.fieldValue)].join('.'), [nameof(x => x.properties), nameof(x => x.contacts), nameof(x => x.user), nameof(x => x.id)].join('.'), diff --git a/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.routing.ts b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.routing.ts index 10dc021f4..1e2c38c97 100644 --- a/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.routing.ts +++ b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.routing.ts @@ -35,10 +35,11 @@ const routes: Routes = [ data: { ...BreadcrumbService.generateRouteDataConfiguration({ title: 'BREADCRUMBS.EDIT-DMP' - }), - authContext: { - permissions: [AppPermission.EditDmp] - } + }) + // , + // authContext: { + // permissions: [AppPermission.EditDmp] + // } } }, diff --git a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts index 811c45bb3..7f37bdead 100644 --- a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts +++ b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts @@ -117,7 +117,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { this.dmp = data; this.dmp.dmpUsers = data.dmpUsers.filter(x=> x.isActive === IsActive.Active); if(this.dmp.descriptions) this.dmp.descriptions = data.descriptions.filter(x=> x.isActive === IsActive.Active); - this.selectedBlueprint= data.blueprint; + this.selectedBlueprint= data.blueprint; this.researchers = this.referenceService.getReferencesForTypes(this.dmp?.dmpReferences, [this.referenceTypeService.getResearcherReferenceType()]); if (!this.hasDoi()) { this.selectedModel = this.dmp.entityDois[0]; @@ -196,39 +196,39 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { isDmpOwner(): boolean { const principalId: Guid = this.authentication.userId(); - if (principalId) return !!this.dmp.dmpUsers?.find(x => (x.role === DmpUserRole.Owner) && (principalId === x.id)); + if (principalId) return !!this.dmp.dmpUsers?.find(x => (x.role === DmpUserRole.Owner) && (principalId === x.user?.id)); } canEditDmp(): boolean{ - return (this.isDraftDmp()) && (this.isDmpOwner() || this.authentication.hasPermission(AppPermission.EditDmp)) && this.isPublicView == false; + return (this.isDraftDmp()) && (this.dmp.authorizationFlags?.some(x => x === AppPermission.EditDmp) || this.authentication.hasPermission(AppPermission.EditDmp)) && this.isPublicView == false; } canCreateNewVersion(): boolean { - return this.isDmpOwner() || this.authentication.hasPermission(AppPermission.CreateNewVersionDmp) && this.isPublicView == false; + return this.dmp.authorizationFlags?.some(x => x === AppPermission.CreateNewVersionDmp) || this.authentication.hasPermission(AppPermission.CreateNewVersionDmp) && this.isPublicView == false; } canDeleteDmp(): boolean { - return this.isDmpOwner() || this.authentication.hasPermission(AppPermission.DeleteDmp) && this.isPublicView == false; + return this.dmp.authorizationFlags?.some(x => x === AppPermission.DeleteDmp) || this.authentication.hasPermission(AppPermission.DeleteDmp) && this.isPublicView == false; } canCloneDmp(): boolean { - return this.isDmpOwner() || this.authentication.hasPermission(AppPermission.CloneDmp); + return this.dmp.authorizationFlags?.some(x => x === AppPermission.CloneDmp) || this.authentication.hasPermission(AppPermission.CloneDmp); } canFinalizeDmp(): boolean { - return this.isDmpOwner() || this.authentication.hasPermission(AppPermission.FinalizeDmp) && this.isPublicView == false; + return this.dmp.authorizationFlags?.some(x => x === AppPermission.FinalizeDmp) || this.authentication.hasPermission(AppPermission.FinalizeDmp) && this.isPublicView == false; } canExportDmp(): boolean { - return this.isDmpOwner() || this.authentication.hasPermission(AppPermission.ExportDmp); + return this.dmp.authorizationFlags?.some(x => x === AppPermission.ExportDmp) || this.authentication.hasPermission(AppPermission.ExportDmp); } canInviteDmpUsers(): boolean { - return this.isDmpOwner() || this.authentication.hasPermission(AppPermission.InviteDmpUsers) && this.isPublicView == false; + return this.dmp.authorizationFlags?.some(x => x === AppPermission.InviteDmpUsers) || this.authentication.hasPermission(AppPermission.InviteDmpUsers) && this.isPublicView == false; } canAssignDmpUsers(): boolean { - return this.isDmpOwner() || this.authentication.hasPermission(AppPermission.AssignDmpUsers) && this.isPublicView == false; + return this.dmp.authorizationFlags?.some(x => x === AppPermission.AssignDmpUsers) || this.authentication.hasPermission(AppPermission.AssignDmpUsers) && this.isPublicView == false; } editClicked() { @@ -768,6 +768,15 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { nameof(x => x.groupId), nameof(x => x.version), nameof(x => x.updatedAt), + nameof(x => x.updatedAt), + [nameof(x => x.authorizationFlags), AppPermission.CreateNewVersionDmp].join('.'), + [nameof(x => x.authorizationFlags), AppPermission.DeleteDmp].join('.'), + [nameof(x => x.authorizationFlags), AppPermission.CloneDmp].join('.'), + [nameof(x => x.authorizationFlags), AppPermission.FinalizeDmp].join('.'), + [nameof(x => x.authorizationFlags), AppPermission.ExportDmp].join('.'), + [nameof(x => x.authorizationFlags), AppPermission.InviteDmpUsers].join('.'), + [nameof(x => x.authorizationFlags), AppPermission.AssignDmpUsers].join('.'), + [nameof(x => x.authorizationFlags), AppPermission.EditDmp].join('.'), [nameof(x => x.entityDois), nameof(x => x.id)].join('.'), [nameof(x => x.entityDois), nameof(x => x.repositoryId)].join('.'), [nameof(x => x.entityDois), nameof(x => x.doi)].join('.'), @@ -793,7 +802,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { [nameof(x => x.blueprint), nameof(x => x.definition)].join('.'), [nameof(x => x.blueprint), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.id)].join('.'), [nameof(x => x.blueprint), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.label)].join('.'), - + nameof(x => x.hash), ] }