description authz
This commit is contained in:
parent
c62a945a6a
commit
266c05ee80
|
@ -101,6 +101,7 @@ public final class Permission {
|
|||
//Description
|
||||
public static String BrowseDescription = "BrowseDescription";
|
||||
public static String EditDescription = "EditDescription";
|
||||
public static String FinalizeDescription = "FinalizeDescription";
|
||||
public static String DeleteDescription = "DeleteDescription";
|
||||
public static String CloneDescription = "CloneDescription";
|
||||
|
||||
|
|
|
@ -12,4 +12,8 @@ public interface AuthorizationContentResolver {
|
|||
AffiliatedResource dmpAffiliation(UUID id);
|
||||
|
||||
Map<UUID, AffiliatedResource> dmpsAffiliation(List<UUID> ids);
|
||||
|
||||
AffiliatedResource descriptionAffiliation(UUID id);
|
||||
|
||||
Map<UUID, AffiliatedResource> descriptionsAffiliation(List<UUID> ids);
|
||||
}
|
||||
|
|
|
@ -4,9 +4,12 @@ import eu.eudat.authorization.AffiliatedResource;
|
|||
import eu.eudat.authorization.PermissionNameProvider;
|
||||
import eu.eudat.commons.enums.IsActive;
|
||||
import eu.eudat.commons.scope.user.UserScope;
|
||||
import eu.eudat.data.DescriptionEntity;
|
||||
import eu.eudat.data.DmpEntity;
|
||||
import eu.eudat.data.DmpUserEntity;
|
||||
import eu.eudat.model.Description;
|
||||
import eu.eudat.model.DmpUser;
|
||||
import eu.eudat.query.DescriptionQuery;
|
||||
import eu.eudat.query.DmpUserQuery;
|
||||
import gr.cite.tools.data.query.QueryFactory;
|
||||
import gr.cite.tools.fieldset.BaseFieldSet;
|
||||
|
@ -14,6 +17,7 @@ import org.springframework.stereotype.Service;
|
|||
import org.springframework.web.context.annotation.RequestScope;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@RequestScope
|
||||
|
@ -60,6 +64,37 @@ public class AuthorizationContentResolverImpl implements AuthorizationContentRes
|
|||
return affiliatedResources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AffiliatedResource descriptionAffiliation(UUID id) {
|
||||
return this.descriptionsAffiliation(List.of(id)).getOrDefault(id, new AffiliatedResource());
|
||||
}
|
||||
@Override
|
||||
public Map<UUID, AffiliatedResource> descriptionsAffiliation(List<UUID> ids){
|
||||
UUID userId = this.userScope.getUserIdSafe();
|
||||
Map<UUID, AffiliatedResource> affiliatedResources = new HashMap<>();
|
||||
for (UUID id : ids){
|
||||
affiliatedResources.put(id, new AffiliatedResource());
|
||||
}
|
||||
if (userId == null || !userScope.isSet()) return affiliatedResources;
|
||||
|
||||
List<UUID> idsToResolve = this.getAffiliatedFromCache(ids, userId, affiliatedResources, DescriptionEntity.class.getSimpleName());
|
||||
if (idsToResolve.isEmpty()) return affiliatedResources;
|
||||
|
||||
List<DescriptionEntity> descriptionEntities = this.queryFactory.query(DescriptionQuery.class).ids(ids).collectAs(new BaseFieldSet().ensure(Description._id).ensure(Description._dmp));
|
||||
List<DmpUserEntity> dmpUsers = this.queryFactory.query(DmpUserQuery.class).descriptionIds(ids).userIds(userId).isActives(IsActive.Active).collectAs(new BaseFieldSet().ensure(DmpUser._role).ensure(DmpUser._dmp));
|
||||
Map<UUID, List<DmpUserEntity>> dmpUsersMap = dmpUsers.stream().collect(Collectors.groupingBy(DmpUserEntity::getDmpId));
|
||||
|
||||
for (DescriptionEntity description : descriptionEntities){
|
||||
List<DmpUserEntity> dmpDescriptionUsers = dmpUsersMap.getOrDefault(description.getDmpId(), new ArrayList<>());
|
||||
for (DmpUserEntity dmpUser : dmpDescriptionUsers) {
|
||||
affiliatedResources.get(description.getId()).getDmpUserRoles().add(dmpUser.getRole());
|
||||
}
|
||||
}
|
||||
|
||||
this.ensureAffiliatedInCache(idsToResolve, userId, affiliatedResources, DescriptionEntity.class.getSimpleName());
|
||||
return affiliatedResources;
|
||||
}
|
||||
|
||||
private List<UUID> getAffiliatedFromCache(List<UUID> ids, UUID userId, Map<UUID, AffiliatedResource> affiliatedResources, String entityType){
|
||||
List<UUID> idsToResolve = new ArrayList<>();
|
||||
for (UUID id : ids){
|
||||
|
|
|
@ -71,6 +71,9 @@ public class Description {
|
|||
|
||||
public static final String _descriptionTemplate = "descriptionTemplate";
|
||||
|
||||
private List<String> authorizationFlags;
|
||||
public static final String _authorizationFlags = "authorizationFlags";
|
||||
|
||||
private Dmp dmp;
|
||||
|
||||
public static final String _dmp = "dmp";
|
||||
|
@ -203,4 +206,12 @@ public class Description {
|
|||
public void setDescriptionTemplate(DescriptionTemplate descriptionTemplate) {
|
||||
this.descriptionTemplate = descriptionTemplate;
|
||||
}
|
||||
|
||||
public List<String> getAuthorizationFlags() {
|
||||
return authorizationFlags;
|
||||
}
|
||||
|
||||
public void setAuthorizationFlags(List<String> authorizationFlags) {
|
||||
this.authorizationFlags = authorizationFlags;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package eu.eudat.model.builder;
|
||||
|
||||
import eu.eudat.authorization.AffiliatedResource;
|
||||
import eu.eudat.authorization.AuthorizationFlags;
|
||||
import eu.eudat.authorization.authorizationcontentresolver.AuthorizationContentResolver;
|
||||
import eu.eudat.commons.JsonHandlingService;
|
||||
import eu.eudat.commons.XmlHandlingService;
|
||||
import eu.eudat.commons.types.description.PropertyDefinitionEntity;
|
||||
|
@ -8,10 +10,12 @@ import eu.eudat.commons.types.descriptiontemplate.DefinitionEntity;
|
|||
import eu.eudat.convention.ConventionService;
|
||||
import eu.eudat.data.DescriptionEntity;
|
||||
import eu.eudat.data.DescriptionTemplateEntity;
|
||||
import eu.eudat.data.DmpEntity;
|
||||
import eu.eudat.data.UserRoleEntity;
|
||||
import eu.eudat.model.*;
|
||||
import eu.eudat.model.builder.descriptionpropertiesdefinition.PropertyDefinitionBuilder;
|
||||
import eu.eudat.query.*;
|
||||
import gr.cite.commons.web.authz.service.AuthorizationService;
|
||||
import gr.cite.tools.data.builder.BuilderFactory;
|
||||
import gr.cite.tools.data.query.QueryFactory;
|
||||
import gr.cite.tools.exception.MyApplicationException;
|
||||
|
@ -37,6 +41,8 @@ public class DescriptionBuilder extends BaseBuilder<Description, DescriptionEnti
|
|||
private final BuilderFactory builderFactory;
|
||||
private final JsonHandlingService jsonHandlingService;
|
||||
private final XmlHandlingService xmlHandlingService;
|
||||
private final AuthorizationService authorizationService;
|
||||
private final AuthorizationContentResolver authorizationContentResolver;
|
||||
|
||||
private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None);
|
||||
|
||||
|
@ -44,12 +50,14 @@ public class DescriptionBuilder extends BaseBuilder<Description, DescriptionEnti
|
|||
public DescriptionBuilder(
|
||||
ConventionService conventionService,
|
||||
QueryFactory queryFactory,
|
||||
BuilderFactory builderFactory, JsonHandlingService jsonHandlingService, XmlHandlingService xmlHandlingService) {
|
||||
BuilderFactory builderFactory, JsonHandlingService jsonHandlingService, XmlHandlingService xmlHandlingService, AuthorizationService authorizationService, AuthorizationContentResolver authorizationContentResolver) {
|
||||
super(conventionService, new LoggerService(LoggerFactory.getLogger(DescriptionBuilder.class)));
|
||||
this.queryFactory = queryFactory;
|
||||
this.builderFactory = builderFactory;
|
||||
this.jsonHandlingService = jsonHandlingService;
|
||||
this.xmlHandlingService = xmlHandlingService;
|
||||
this.authorizationService = authorizationService;
|
||||
this.authorizationContentResolver = authorizationContentResolver;
|
||||
}
|
||||
|
||||
public DescriptionBuilder authorize(EnumSet<AuthorizationFlags> values) {
|
||||
|
@ -85,7 +93,10 @@ public class DescriptionBuilder extends BaseBuilder<Description, DescriptionEnti
|
|||
FieldSet definitionPropertiesFields = fields.extractPrefixed(this.asPrefix(Description._properties));
|
||||
|
||||
Map<UUID, DefinitionEntity> definitionEntityMap = !definitionPropertiesFields.isEmpty() ? this.collectDescriptionTemplateDefinitions(data) : null;
|
||||
|
||||
|
||||
Set<String> authorizationFlags = this.extractAuthorizationFlags(fields, Description._authorizationFlags, this.authorizationContentResolver.getPermissionNames());
|
||||
Map<UUID, AffiliatedResource> affiliatedResourceMap = authorizationFlags == null || authorizationFlags.isEmpty() ? null : this.authorizationContentResolver.descriptionsAffiliation(data.stream().map(DescriptionEntity::getId).collect(Collectors.toList()));
|
||||
|
||||
List<Description> models = new ArrayList<>();
|
||||
for (DescriptionEntity d : data) {
|
||||
Description m = new Description();
|
||||
|
@ -108,6 +119,7 @@ public class DescriptionBuilder extends BaseBuilder<Description, DescriptionEnti
|
|||
PropertyDefinitionEntity propertyDefinition = this.jsonHandlingService.fromJsonSafe(PropertyDefinitionEntity.class, d.getProperties());
|
||||
m.setProperties(this.builderFactory.builder(PropertyDefinitionBuilder.class).withDefinition(definitionEntityMap != null ? definitionEntityMap.getOrDefault(d.getDescriptionTemplateId(), null) : null).authorize(this.authorize).build(definitionPropertiesFields, propertyDefinition));
|
||||
}
|
||||
if (affiliatedResourceMap != null && !authorizationFlags.isEmpty()) m.setAuthorizationFlags(this.evaluateAuthorizationFlags(this.authorizationService, authorizationFlags, affiliatedResourceMap.getOrDefault(d.getId(), null)));
|
||||
models.add(m);
|
||||
}
|
||||
|
||||
|
|
|
@ -89,7 +89,6 @@ public class DmpBuilder extends BaseBuilder<Dmp, DmpEntity> {
|
|||
Map<UUID, List<DmpDescriptionTemplate>> dmpDescriptionTemplatesMap = this.collectDmpDescriptionTemplates(dmpDescriptionTemplatesFields, data);
|
||||
|
||||
Set<String> authorizationFlags = this.extractAuthorizationFlags(fields, Dmp._authorizationFlags, this.authorizationContentResolver.getPermissionNames());
|
||||
|
||||
Map<UUID, AffiliatedResource> affiliatedResourceMap = authorizationFlags == null || authorizationFlags.isEmpty() ? null : this.authorizationContentResolver.dmpsAffiliation(data.stream().map(DmpEntity::getId).collect(Collectors.toList()));
|
||||
|
||||
FieldSet propertiesFields = fields.extractPrefixed(this.asPrefix(Dmp._properties));
|
||||
|
@ -121,7 +120,7 @@ public class DmpBuilder extends BaseBuilder<Dmp, DmpEntity> {
|
|||
DmpPropertiesEntity propertyDefinition = this.jsonHandlingService.fromJsonSafe(DmpPropertiesEntity.class, d.getProperties());
|
||||
m.setProperties(this.builderFactory.builder(DmpPropertiesBuilder.class).authorize(this.authorize).build(propertiesFields, propertyDefinition));
|
||||
}
|
||||
if (authorizationFlags != null && !authorizationFlags.isEmpty()) m.setAuthorizationFlags(this.evaluateAuthorizationFlags(this.authorizationService, authorizationFlags, affiliatedResourceMap.getOrDefault(d.getId(), null)));
|
||||
if (affiliatedResourceMap != null && !authorizationFlags.isEmpty()) m.setAuthorizationFlags(this.evaluateAuthorizationFlags(this.authorizationService, authorizationFlags, affiliatedResourceMap.getOrDefault(d.getId(), null)));
|
||||
models.add(m);
|
||||
}
|
||||
this.logger.debug("build {} items", Optional.of(models).map(List::size).orElse(0));
|
||||
|
|
|
@ -39,7 +39,7 @@ public class TagCensor extends BaseCensor {
|
|||
if (fields == null || fields.isEmpty())
|
||||
return;
|
||||
|
||||
this.authService.authorizeForce(Permission.BrowseTag);
|
||||
this.authService.authorizeForce(Permission.BrowseTag, Permission.DeferredAffiliation);
|
||||
FieldSet createdByFields = fields.extractPrefixed(this.asIndexerPrefix(Tag._createdBy));
|
||||
this.censorFactory.censor(UserCensor.class).censor(createdByFields, userId);
|
||||
}
|
||||
|
|
|
@ -314,6 +314,7 @@ public class DescriptionQuery extends QueryBase<DescriptionEntity> {
|
|||
else if (item.prefix(Description._descriptionTemplate) || item.prefix(PublicDescription._descriptionTemplate)) return DescriptionEntity._descriptionTemplateId;
|
||||
else if (item.match(Description._descriptionTemplate) || item.match(PublicDescription._descriptionTemplate)) return DescriptionEntity._descriptionTemplateId;
|
||||
else if (item.prefix(Description._dmp)) return DescriptionEntity._dmpId;
|
||||
else if (item.match(Description._dmp)) return DescriptionEntity._dmpId;
|
||||
else return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,9 +5,7 @@ import eu.eudat.authorization.Permission;
|
|||
import eu.eudat.commons.enums.DmpUserRole;
|
||||
import eu.eudat.commons.enums.IsActive;
|
||||
import eu.eudat.commons.scope.user.UserScope;
|
||||
import eu.eudat.data.DmpReferenceEntity;
|
||||
import eu.eudat.data.DmpUserEntity;
|
||||
import eu.eudat.data.ReferenceEntity;
|
||||
import eu.eudat.data.*;
|
||||
import eu.eudat.model.DmpUser;
|
||||
import eu.eudat.model.PublicDmpUser;
|
||||
import eu.eudat.query.utils.BuildSubQueryInput;
|
||||
|
@ -19,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;
|
||||
|
@ -36,6 +35,8 @@ public class DmpUserQuery extends QueryBase<DmpUserEntity> {
|
|||
|
||||
private Collection<UUID> dmpIds;
|
||||
|
||||
private Collection<UUID> descriptionIds;
|
||||
|
||||
private Collection<UUID> userIds;
|
||||
|
||||
private Collection<DmpUserRole> userRoles;
|
||||
|
@ -89,6 +90,21 @@ public class DmpUserQuery extends QueryBase<DmpUserEntity> {
|
|||
return this;
|
||||
}
|
||||
|
||||
public DmpUserQuery descriptionIds(UUID value) {
|
||||
this.descriptionIds = List.of(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public DmpUserQuery descriptionIds(UUID... value) {
|
||||
this.descriptionIds = Arrays.asList(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public DmpUserQuery descriptionIds(Collection<UUID> values) {
|
||||
this.descriptionIds = values;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DmpUserQuery userRoles(DmpUserRole value) {
|
||||
this.userRoles = List.of(value);
|
||||
return this;
|
||||
|
@ -161,7 +177,7 @@ public class DmpUserQuery extends QueryBase<DmpUserEntity> {
|
|||
|
||||
@Override
|
||||
protected Boolean isFalseQuery() {
|
||||
return this.isEmpty(this.ids) || this.isEmpty(this.dmpIds) || this.isEmpty(this.userIds);
|
||||
return this.isEmpty(this.ids) || this.isEmpty(this.dmpIds) || this.isEmpty(this.descriptionIds) || this.isEmpty(this.userIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -208,6 +224,19 @@ public class DmpUserQuery extends QueryBase<DmpUserEntity> {
|
|||
inClause.value(item);
|
||||
predicates.add(inClause);
|
||||
}
|
||||
if (this.descriptionIds != null) {
|
||||
Subquery<UUID> descriptionSubquery = queryUtilsService.buildSubQuery(new BuildSubQueryInput<>(
|
||||
new BuildSubQueryInput.Builder<>(DescriptionEntity.class, UUID.class, queryContext)
|
||||
.keyPathFunc((subQueryRoot) -> subQueryRoot.get(DescriptionEntity._dmpId))
|
||||
.filterFunc((subQueryRoot, cb) -> {
|
||||
CriteriaBuilder.In<UUID> inClause = cb.in(subQueryRoot.get(DmpUserEntity._id));
|
||||
for (UUID item : this.descriptionIds)
|
||||
inClause.value(item);
|
||||
return inClause;
|
||||
})
|
||||
));
|
||||
predicates.add(queryContext.CriteriaBuilder.in(queryContext.Root.get(DmpUserEntity._dmpId)).value(descriptionSubquery));
|
||||
}
|
||||
if (this.userIds != null) {
|
||||
CriteriaBuilder.In<UUID> inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(DmpUserEntity._userId));
|
||||
for (UUID item : this.userIds)
|
||||
|
|
|
@ -1,9 +1,17 @@
|
|||
package eu.eudat.query;
|
||||
|
||||
import eu.eudat.authorization.AuthorizationFlags;
|
||||
import eu.eudat.authorization.Permission;
|
||||
import eu.eudat.commons.enums.IsActive;
|
||||
import eu.eudat.commons.scope.user.UserScope;
|
||||
import eu.eudat.data.DescriptionTagEntity;
|
||||
import eu.eudat.data.DmpReferenceEntity;
|
||||
import eu.eudat.data.ReferenceEntity;
|
||||
import eu.eudat.data.TagEntity;
|
||||
import eu.eudat.model.Tag;
|
||||
import eu.eudat.query.utils.BuildSubQueryInput;
|
||||
import eu.eudat.query.utils.QueryUtilsService;
|
||||
import gr.cite.commons.web.authz.service.AuthorizationService;
|
||||
import gr.cite.tools.data.query.FieldResolver;
|
||||
import gr.cite.tools.data.query.QueryBase;
|
||||
import gr.cite.tools.data.query.QueryContext;
|
||||
|
@ -34,8 +42,15 @@ public class TagQuery extends QueryBase<TagEntity> {
|
|||
private Collection<UUID> createdByIds;
|
||||
|
||||
private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None);
|
||||
|
||||
private final UserScope userScope;
|
||||
private final AuthorizationService authService;
|
||||
private final QueryUtilsService queryUtilsService;
|
||||
|
||||
public TagQuery() {
|
||||
public TagQuery(UserScope userScope, AuthorizationService authService, QueryUtilsService queryUtilsService) {
|
||||
this.userScope = userScope;
|
||||
this.authService = authService;
|
||||
this.queryUtilsService = queryUtilsService;
|
||||
}
|
||||
|
||||
public TagQuery like(String value) {
|
||||
|
@ -153,6 +168,37 @@ public class TagQuery extends QueryBase<TagEntity> {
|
|||
protected Class<TagEntity> entityClass() {
|
||||
return TagEntity.class;
|
||||
}
|
||||
@Override
|
||||
protected <X, Y> Predicate applyAuthZ(QueryContext<X, Y> queryContext) {
|
||||
if (this.authorize.contains(AuthorizationFlags.None)) return null;
|
||||
if (this.authorize.contains(AuthorizationFlags.Permission) && this.authService.authorize(Permission.BrowseTag)) return null;
|
||||
UUID userId;
|
||||
boolean usePublic = this.authorize.contains(AuthorizationFlags.Public);
|
||||
if (this.authorize.contains(AuthorizationFlags.DmpAssociated)) userId = this.userScope.getUserIdSafe();
|
||||
else userId = null;
|
||||
|
||||
List<Predicate> predicates = new ArrayList<>();
|
||||
if (userId != null || usePublic ) {
|
||||
predicates.add(queryContext.CriteriaBuilder.or(
|
||||
queryContext.CriteriaBuilder.isNull(queryContext.Root.get(TagEntity._createdById)),
|
||||
userId != null ? queryContext.CriteriaBuilder.equal(queryContext.Root.get(TagEntity._createdById), userId) : queryContext.CriteriaBuilder.or(), //Creates a false query
|
||||
queryContext.CriteriaBuilder.in(queryContext.Root.get(TagEntity._id)).value(queryUtilsService.buildSubQuery(new BuildSubQueryInput<>(new BuildSubQueryInput.Builder<>(DescriptionTagEntity.class, UUID.class)
|
||||
.query(queryContext.Query)
|
||||
.criteriaBuilder(queryContext.CriteriaBuilder)
|
||||
.keyPathFunc((subQueryRoot) -> subQueryRoot.get(DescriptionTagEntity._tagId))
|
||||
.filterFunc((subQueryRoot, cb) ->
|
||||
cb.in(subQueryRoot.get(DescriptionTagEntity._descriptionId)).value(queryUtilsService.buildDescriptionAuthZSubQuery(queryContext.Query, queryContext.CriteriaBuilder, userId, usePublic))
|
||||
)
|
||||
))) //Creates a false query
|
||||
));
|
||||
}
|
||||
if (!predicates.isEmpty()) {
|
||||
Predicate[] predicatesArray = predicates.toArray(new Predicate[0]);
|
||||
return queryContext.CriteriaBuilder.and(predicatesArray);
|
||||
} else {
|
||||
return queryContext.CriteriaBuilder.or(); //Creates a false query
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <X, Y> Predicate applyFilters(QueryContext<X, Y> queryContext) {
|
||||
|
|
|
@ -2,6 +2,7 @@ package eu.eudat.service.description;
|
|||
|
||||
import eu.eudat.authorization.AuthorizationFlags;
|
||||
import eu.eudat.authorization.Permission;
|
||||
import eu.eudat.authorization.authorizationcontentresolver.AuthorizationContentResolver;
|
||||
import eu.eudat.commons.JsonHandlingService;
|
||||
import eu.eudat.commons.XmlHandlingService;
|
||||
import eu.eudat.commons.enums.*;
|
||||
|
@ -96,21 +97,22 @@ public class DescriptionServiceImpl implements DescriptionService {
|
|||
private final StorageFileProperties storageFileConfig;
|
||||
private final StorageFileService storageFileService;
|
||||
private final DescriptionTouchedIntegrationEventHandler descriptionTouchedIntegrationEventHandler;
|
||||
private final AuthorizationContentResolver authorizationContentResolver;
|
||||
|
||||
@Autowired
|
||||
public DescriptionServiceImpl(
|
||||
EntityManager entityManager,
|
||||
AuthorizationService authorizationService,
|
||||
DeleterFactory deleterFactory,
|
||||
BuilderFactory builderFactory,
|
||||
ConventionService conventionService,
|
||||
ErrorThesaurusProperties errors,
|
||||
MessageSource messageSource,
|
||||
EventBroker eventBroker,
|
||||
QueryFactory queryFactory,
|
||||
JsonHandlingService jsonHandlingService,
|
||||
UserScope userScope,
|
||||
XmlHandlingService xmlHandlingService, NotifyIntegrationEventHandler eventHandler, NotificationProperties notificationProperties, FileTransformerService fileTransformerService, ElasticService elasticService, ValidatorFactory validatorFactory, StorageFileProperties storageFileConfig, StorageFileService storageFileService, DescriptionTouchedIntegrationEventHandler descriptionTouchedIntegrationEventHandler) {
|
||||
EntityManager entityManager,
|
||||
AuthorizationService authorizationService,
|
||||
DeleterFactory deleterFactory,
|
||||
BuilderFactory builderFactory,
|
||||
ConventionService conventionService,
|
||||
ErrorThesaurusProperties errors,
|
||||
MessageSource messageSource,
|
||||
EventBroker eventBroker,
|
||||
QueryFactory queryFactory,
|
||||
JsonHandlingService jsonHandlingService,
|
||||
UserScope userScope,
|
||||
XmlHandlingService xmlHandlingService, NotifyIntegrationEventHandler eventHandler, NotificationProperties notificationProperties, FileTransformerService fileTransformerService, ElasticService elasticService, ValidatorFactory validatorFactory, StorageFileProperties storageFileConfig, StorageFileService storageFileService, DescriptionTouchedIntegrationEventHandler descriptionTouchedIntegrationEventHandler, AuthorizationContentResolver authorizationContentResolver) {
|
||||
this.entityManager = entityManager;
|
||||
this.authorizationService = authorizationService;
|
||||
this.deleterFactory = deleterFactory;
|
||||
|
@ -131,6 +133,7 @@ public class DescriptionServiceImpl implements DescriptionService {
|
|||
this.storageFileConfig = storageFileConfig;
|
||||
this.storageFileService = storageFileService;
|
||||
this.descriptionTouchedIntegrationEventHandler = descriptionTouchedIntegrationEventHandler;
|
||||
this.authorizationContentResolver = authorizationContentResolver;
|
||||
}
|
||||
|
||||
//region Persist
|
||||
|
@ -139,9 +142,10 @@ public class DescriptionServiceImpl implements DescriptionService {
|
|||
public Description persist(DescriptionPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, IOException {
|
||||
logger.debug(new MapLogEntry("persisting data description").And("model", model).And("fields", fields));
|
||||
|
||||
this.authorizationService.authorizeForce(Permission.EditDescription);
|
||||
|
||||
Boolean isUpdate = this.conventionService.isValidGuid(model.getId());
|
||||
if (isUpdate) this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.descriptionAffiliation(model.getId())), Permission.EditDescription);
|
||||
else this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.dmpAffiliation(model.getDmpId())), Permission.EditDescription);
|
||||
|
||||
|
||||
DescriptionEntity data;
|
||||
if (isUpdate) {
|
||||
|
@ -336,13 +340,14 @@ public class DescriptionServiceImpl implements DescriptionService {
|
|||
public Description persistStatus(DescriptionStatusPersist model, FieldSet fields) throws IOException {
|
||||
logger.debug(new MapLogEntry("persisting data dmp").And("model", model).And("fields", fields));
|
||||
|
||||
this.authorizationService.authorizeForce(Permission.EditDescription);
|
||||
this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.descriptionAffiliation(model.getId())), Permission.EditDescription);
|
||||
|
||||
DescriptionEntity data = this.entityManager.find(DescriptionEntity.class, model.getId());
|
||||
if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), Description.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 (!data.getStatus().equals(model.getStatus())){
|
||||
if (data.getStatus().equals(DescriptionStatus.Finalized)){
|
||||
this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.descriptionAffiliation(model.getId())), Permission.FinalizeDescription);
|
||||
DmpEntity dmpEntity = this.entityManager.find(DmpEntity.class, data.getDmpId());
|
||||
if (dmpEntity == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{data.getDmpId(), DmpEntity.class.getSimpleName()}, LocaleContextHolder.getLocale()));
|
||||
if(!dmpEntity.getStatus().equals(DmpStatus.Draft)) throw new MyValidationException(this.errors.getDmpIsFinalized().getCode(), this.errors.getDmpIsFinalized().getMessage());
|
||||
|
@ -650,7 +655,7 @@ public class DescriptionServiceImpl implements DescriptionService {
|
|||
public void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException, IOException {
|
||||
logger.debug("deleting description: {}", id);
|
||||
|
||||
this.authorizationService.authorizeForce(Permission.DeleteDescription);
|
||||
this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.descriptionAffiliation(id)), Permission.DeleteDescription);
|
||||
|
||||
this.deleterFactory.deleter(DescriptionDeleter.class).deleteAndSaveByIds(List.of(id), false);
|
||||
}
|
||||
|
@ -663,7 +668,7 @@ public class DescriptionServiceImpl implements DescriptionService {
|
|||
public void clone(UUID dmpId, UUID descriptionId) throws InvalidApplicationException, IOException {
|
||||
logger.debug("cloning description: {} with description: {}", descriptionId, dmpId);
|
||||
|
||||
this.authorizationService.authorizeForce(Permission.CloneDescription);
|
||||
this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.descriptionAffiliation(descriptionId)), Permission.CloneDescription);
|
||||
|
||||
DescriptionEntity existing = this.queryFactory.query(DescriptionQuery.class).ids(descriptionId).isActive(IsActive.Active).first();
|
||||
|
||||
|
@ -743,7 +748,8 @@ public class DescriptionServiceImpl implements DescriptionService {
|
|||
|
||||
@Override
|
||||
public StorageFile uploadFieldFile(DescriptionFieldFilePersist model, MultipartFile file, FieldSet fields) throws IOException {
|
||||
this.authorizationService.authorizeForce(Permission.EditDescription);
|
||||
//this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.descriptionAffiliation(descriptionId)), Permission.CloneDescription);
|
||||
this.authorizationService.authorizeForce(Permission.EditDescription);//TODO: Missing Description or dmp for authz
|
||||
|
||||
DescriptionTemplateEntity descriptionTemplate = this.queryFactory.query(DescriptionTemplateQuery.class).ids(model.getDescriptionTemplateId()).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).first();
|
||||
if (descriptionTemplate == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getDescriptionTemplateId(), DescriptionTemplate.class.getSimpleName()}, LocaleContextHolder.getLocale()));
|
||||
|
@ -783,7 +789,8 @@ public class DescriptionServiceImpl implements DescriptionService {
|
|||
|
||||
@Override
|
||||
public StorageFileEntity getFieldFile(UUID descriptionId, UUID storageFileId) {
|
||||
this.authorizationService.authorizeForce(Permission.BrowseDescription);
|
||||
this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.descriptionAffiliation(descriptionId)), Permission.BrowseDescription);
|
||||
|
||||
DescriptionEntity descriptionEntity = this.queryFactory.query(DescriptionQuery.class).isActive(IsActive.Active).ids(descriptionId).first();
|
||||
if (descriptionEntity == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{descriptionId, Description.class.getSimpleName()}, LocaleContextHolder.getLocale()));
|
||||
|
||||
|
|
|
@ -132,18 +132,48 @@ permissions:
|
|||
BrowseDescription:
|
||||
roles:
|
||||
- Admin
|
||||
dmp:
|
||||
roles:
|
||||
- Owner
|
||||
- User
|
||||
- DescriptionContributor
|
||||
- Reviewer
|
||||
clients: [ ]
|
||||
allowAnonymous: false
|
||||
allowAuthenticated: false
|
||||
EditDescription:
|
||||
roles:
|
||||
- Admin
|
||||
dmp:
|
||||
roles:
|
||||
- Owner
|
||||
- User
|
||||
- DescriptionContributor
|
||||
- Reviewer
|
||||
clients: [ ]
|
||||
allowAnonymous: false
|
||||
allowAuthenticated: false
|
||||
FinalizeDescription:
|
||||
roles:
|
||||
- Admin
|
||||
dmp:
|
||||
roles:
|
||||
- Owner
|
||||
- User
|
||||
- DescriptionContributor
|
||||
- Reviewer
|
||||
clients: [ ]
|
||||
allowAnonymous: false
|
||||
allowAuthenticated: false
|
||||
DeleteDescription:
|
||||
roles:
|
||||
- Admin
|
||||
dmp:
|
||||
roles:
|
||||
- Owner
|
||||
- User
|
||||
- DescriptionContributor
|
||||
- Reviewer
|
||||
claims: [ ]
|
||||
clients: [ ]
|
||||
allowAnonymous: false
|
||||
|
@ -151,11 +181,16 @@ permissions:
|
|||
CloneDescription:
|
||||
roles:
|
||||
- Admin
|
||||
dmp:
|
||||
roles:
|
||||
- Owner
|
||||
- User
|
||||
- DescriptionContributor
|
||||
- Reviewer
|
||||
claims: [ ]
|
||||
clients: [ ]
|
||||
allowAnonymous: false
|
||||
allowAuthenticated: false
|
||||
|
||||
# Tag
|
||||
BrowseTag:
|
||||
roles:
|
||||
|
|
|
@ -10,8 +10,10 @@ export enum AppPermission {
|
|||
DeleteDmpBlueprint = "DeleteDmpBlueprint",
|
||||
|
||||
//Description
|
||||
NewDescription = "NewDescription",
|
||||
BrowseDescription = "BrowseDescription",
|
||||
EditDescription = "EditDescription",
|
||||
FinalizeDescription = "FinalizeDescription",
|
||||
DeleteDescription= "DeleteDescription",
|
||||
|
||||
//Dmp
|
||||
|
|
|
@ -6,6 +6,7 @@ import { Dmp, DmpDescriptionTemplate, PublicDmp } from "../dmp/dmp";
|
|||
import { Reference, ReferencePersist } from "../reference/reference";
|
||||
import { Tag } from "../tag/tag";
|
||||
import { User } from "../user/user";
|
||||
import { AppPermission } from "@app/core/common/enum/permission.enum";
|
||||
|
||||
export interface Description extends BaseEntity {
|
||||
label?: string;
|
||||
|
@ -19,6 +20,7 @@ export interface Description extends BaseEntity {
|
|||
descriptionTemplate?: DescriptionTemplate;
|
||||
dmpDescriptionTemplate?: DmpDescriptionTemplate;
|
||||
dmp?: Dmp;
|
||||
authorizationFlags?: AppPermission[];
|
||||
}
|
||||
|
||||
|
||||
|
@ -64,9 +66,9 @@ export interface DescriptionTag extends BaseEntity {
|
|||
tag?: Tag;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// Persist
|
||||
//
|
||||
//
|
||||
export interface DescriptionPersist extends BaseEntityPersist {
|
||||
label: string;
|
||||
dmpId: Guid;
|
||||
|
@ -141,4 +143,4 @@ export interface PublicDescriptionTemplate {
|
|||
id: Guid;
|
||||
label: string;
|
||||
description: string;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,24 +78,6 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
step: number = 0;
|
||||
|
||||
|
||||
|
||||
protected get canDelete(): boolean {
|
||||
return !this.isDeleted && !this.isNew && this.hasPermission(this.authService.permissionEnum.DeleteDescription);
|
||||
}
|
||||
|
||||
protected get canSave(): boolean {
|
||||
return !this.isDeleted && this.hasPermission(this.authService.permissionEnum.EditDescription);
|
||||
}
|
||||
|
||||
protected get canFinalize(): boolean {
|
||||
return !this.isDeleted && this.hasPermission(this.authService.permissionEnum.EditDescription);
|
||||
}
|
||||
|
||||
|
||||
private hasPermission(permission: AppPermission): boolean {
|
||||
return this.authService.hasPermission(permission) || this.editorModel?.permissions?.includes(permission);
|
||||
}
|
||||
|
||||
constructor(
|
||||
// BaseFormEditor injected dependencies
|
||||
protected dialog: MatDialog,
|
||||
|
@ -606,7 +588,9 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
}
|
||||
|
||||
buildForm() {
|
||||
this.formGroup = this.editorModel.buildForm(null, this.isDeleted || !this.authService.hasPermission(AppPermission.EditDescription));
|
||||
const canedit = this.isNew ? this.authService.hasPermission(AppPermission.NewDescription) :
|
||||
this.item.authorizationFlags?.some(x => x === AppPermission.EditDescription) || this.item.dmp.authorizationFlags?.some(x => x === AppPermission.EditDmp) ||this.authService.hasPermission(AppPermission.EditDescription);
|
||||
this.formGroup = this.editorModel.buildForm(null, this.isDeleted || !canedit);
|
||||
//this.visibilityRulesService.buildVisibilityRules(this.visibilityRulesService.getVisibilityRulesFromDescriptionTempalte(this.item.descriptionTemplate), this.formGroup);
|
||||
|
||||
// this.selectedSystemFields = this.selectedSystemFieldDisabled();
|
||||
|
|
|
@ -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 { DescriptionTemplate, DescriptionTemplateBaseFieldData, DescriptionTemplateDefinition, DescriptionTemplateExternalDatasetData, DescriptionTemplateField, DescriptionTemplateFieldSet, DescriptionTemplateMultiplicity, DescriptionTemplatePage, DescriptionTemplateReferenceTypeData, DescriptionTemplateRule, DescriptionTemplateSection, DescriptionTemplateSelectData, DescriptionTemplateSelectOption, DescriptionTemplateUploadData, DescriptionTemplateUploadOption } from '@app/core/model/description-template/description-template';
|
||||
import { Description, DescriptionExternalIdentifier, DescriptionField, DescriptionPropertyDefinition, DescriptionPropertyDefinitionFieldSet, DescriptionPropertyDefinitionFieldSetItem, DescriptionReference, DescriptionTag } from '@app/core/model/description/description';
|
||||
import { DescriptionTemplatesInSection, DmpBlueprint, DmpBlueprintDefinition, DmpBlueprintDefinitionSection } from '@app/core/model/dmp-blueprint/dmp-blueprint';
|
||||
|
@ -50,6 +51,10 @@ export class DescriptionEditorResolver extends BaseEditorResolver {
|
|||
nameof<Description>(x => x.description),
|
||||
nameof<Description>(x => x.status),
|
||||
|
||||
[nameof<Description>(x => x.authorizationFlags), AppPermission.EditDescription].join('.'),
|
||||
[nameof<Description>(x => x.authorizationFlags), AppPermission.DeleteDescription].join('.'),
|
||||
[nameof<Description>(x => x.authorizationFlags), AppPermission.FinalizeDescription].join('.'),
|
||||
|
||||
[nameof<Description>(x => x.dmpDescriptionTemplate), nameof<DmpDescriptionTemplate>(x => x.id)].join('.'),
|
||||
[nameof<Description>(x => x.dmpDescriptionTemplate), nameof<DmpDescriptionTemplate>(x => x.sectionId)].join('.'),
|
||||
|
||||
|
@ -124,6 +129,8 @@ export class DescriptionEditorResolver extends BaseEditorResolver {
|
|||
(prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.status)].join('.'),
|
||||
(prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.isActive)].join('.'),
|
||||
|
||||
(prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.authorizationFlags), AppPermission.EditDmp].join('.'),
|
||||
|
||||
(prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.blueprint), nameof<DmpBlueprint>(x => x.id)].join('.'),
|
||||
(prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.blueprint), nameof<DmpBlueprint>(x => x.isActive)].join('.'),
|
||||
(prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.blueprint), nameof<DmpBlueprint>(x => x.definition)].join('.'),
|
||||
|
|
|
@ -21,10 +21,11 @@ const routes: Routes = [
|
|||
data: {
|
||||
...BreadcrumbService.generateRouteDataConfiguration({
|
||||
title: 'BREADCRUMBS.EDIT-DESCRIPTION'
|
||||
}),
|
||||
authContext: {
|
||||
permissions: [AppPermission.EditDescription]
|
||||
}
|
||||
})
|
||||
// ,
|
||||
// authContext: {
|
||||
// permissions: [AppPermission.EditDescription]
|
||||
// }
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -55,10 +56,11 @@ const routes: Routes = [
|
|||
data: {
|
||||
...BreadcrumbService.generateRouteDataConfiguration({
|
||||
title: 'BREADCRUMBS.EDIT-DESCRIPTION'
|
||||
}),
|
||||
authContext: {
|
||||
permissions: [AppPermission.EditDescription]
|
||||
}
|
||||
})
|
||||
// ,
|
||||
// authContext: {
|
||||
// permissions: [AppPermission.EditDescription]
|
||||
// }
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -72,10 +74,11 @@ const routes: Routes = [
|
|||
data: {
|
||||
...BreadcrumbService.generateRouteDataConfiguration({
|
||||
title: 'BREADCRUMBS.EDIT-DESCRIPTION'
|
||||
}),
|
||||
authContext: {
|
||||
permissions: [AppPermission.EditDescription]
|
||||
}
|
||||
})
|
||||
// ,
|
||||
// authContext: {
|
||||
// permissions: [AppPermission.EditDescription]
|
||||
// }
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import { MatSort } from '@angular/material/sort';
|
|||
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||
import { DescriptionStatus } from '@app/core/common/enum/description-status';
|
||||
import { IsActive } from '@app/core/common/enum/is-active.enum';
|
||||
import { AppPermission } from '@app/core/common/enum/permission.enum';
|
||||
import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order';
|
||||
import { DescriptionTemplate } from '@app/core/model/description-template/description-template';
|
||||
import { Description } from '@app/core/model/description/description';
|
||||
|
@ -196,6 +197,11 @@ export class DescriptionListingComponent extends BaseComponent implements OnInit
|
|||
nameof<Description>(x => x.label),
|
||||
nameof<Description>(x => x.status),
|
||||
nameof<Description>(x => x.updatedAt),
|
||||
|
||||
|
||||
[nameof<Description>(x => x.authorizationFlags), AppPermission.EditDescription].join('.'),
|
||||
[nameof<Description>(x => x.authorizationFlags), AppPermission.DeleteDescription].join('.'),
|
||||
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.id)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.label)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.groupId)].join('.'),
|
||||
|
@ -236,7 +242,7 @@ export class DescriptionListingComponent extends BaseComponent implements OnInit
|
|||
this.hasListingItems = true;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
openFiltersDialog(): void {
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
<div *ngIf="description.status === descriptionStatusEnum.Finalized" class="col-auto description-title">{{description.label}}</div>
|
||||
<div *ngIf="description.status === descriptionStatusEnum.Draft" class="col-auto description-title-draft">{{description.label}}</div>
|
||||
<div class="description-subtitle">
|
||||
<span *ngIf="isUserDescriptionRelated()" class="col-auto">{{ enumUtils.toDmpUserRolesString(dmpService.getCurrentUserRolesInDmp(description?.dmp?.dmpUsers)) }}</span>
|
||||
<span *ngIf="isUserDescriptionRelated()">.</span>
|
||||
<span *ngIf="canEdit" class="col-auto">{{ enumUtils.toDmpUserRolesString(dmpService.getCurrentUserRolesInDmp(description?.dmp?.dmpUsers)) }}</span>
|
||||
<span *ngIf="canEdit">.</span>
|
||||
<span class="col-auto" *ngIf="description.status === descriptionStatusEnum.Finalized && description.dmp.accessType === dmpAccessTypeEnum.Public"><span class="material-icons icon-align">public</span>{{'DESCRIPTION-LISTING.STATES.PUBLIC' | translate}}</span>
|
||||
<span *ngIf="description.status === descriptionStatusEnum.Finalized && description.dmp.accessType != dmpAccessTypeEnum.Public" class="col-auto"><span class="material-icons icon-align">done</span>{{ enumUtils.toDescriptionStatusString(description.status) }}</span>
|
||||
<span *ngIf="description.status === descriptionStatusEnum.Draft" class=" col-auto draft"><span class="material-icons icon-align">create</span>{{ enumUtils.toDescriptionStatusString(description.status) }}</span>
|
||||
|
@ -27,13 +27,13 @@
|
|||
<a class="col-auto border-right pointer" *ngIf="fileTransformerService.availableFormats && fileTransformerService.availableFormats.length > 0" [matMenuTriggerFor]="exportMenu"><span class="material-icons icon-align pr-2">open_in_new</span>{{'DESCRIPTION-LISTING.ACTIONS.EXPORT' | translate}}</a>
|
||||
<a class="col-auto border-right pointer" *ngIf="isUserOwner" (click)="openShareDialog(description.dmp.id, description.dmp.label)"><span class="material-icons icon-align pr-2">group_add</span>{{'DESCRIPTION-LISTING.ACTIONS.INVITE-SHORT' | translate}}</a>
|
||||
<a class="col-auto border-right pointer" *ngIf="isAuthenticated()" (click)="copyToDmp(description)"><span class="material-icons icon-align pr-2">file_copy</span>{{'DESCRIPTION-LISTING.ACTIONS.COPY-DESCRIPTION' | translate}}</a>
|
||||
<a class="col-auto border-right pointer" *ngIf="isAuthenticated() && isUserDescriptionRelated()" (click)="deleteClicked(description.id)"><span class="material-icons icon-align pr-2">delete</span>{{ 'DESCRIPTION-LISTING.ACTIONS.DELETE' | translate }}</a>
|
||||
<a class="col-auto border-right pointer" *ngIf="canDelete" (click)="deleteClicked(description.id)"><span class="material-icons icon-align pr-2">delete</span>{{ 'DESCRIPTION-LISTING.ACTIONS.DELETE' | translate }}</a>
|
||||
</div>
|
||||
<mat-menu #actionsMenu="matMenu">
|
||||
<button *ngIf="isAuthenticated()" mat-menu-item (click)="copyToDmp(description)" class="menu-item">
|
||||
<mat-icon>file_copy</mat-icon>{{'DESCRIPTION-LISTING.ACTIONS.COPY-DESCRIPTION' | translate}}
|
||||
</button>
|
||||
<button *ngIf="isUserDescriptionRelated()" mat-menu-item (click)="deleteClicked(description.id)" class="menu-item">
|
||||
<button *ngIf="canDelete" mat-menu-item (click)="deleteClicked(description.id)" class="menu-item">
|
||||
<mat-icon>delete</mat-icon>{{ 'DESCRIPTION-LISTING.ACTIONS.DELETE' | translate }}
|
||||
</button>
|
||||
</mat-menu>
|
||||
|
|
|
@ -26,6 +26,7 @@ import * as FileSaver from 'file-saver';
|
|||
import { takeUntil } from 'rxjs/operators';
|
||||
import { DescriptionStatus } from '../../../../core/common/enum/description-status';
|
||||
import { DescriptionCopyDialogComponent } from '../../description-copy-dialog/description-copy-dialog.component';
|
||||
import { AppPermission } from '@app/core/common/enum/permission.enum';
|
||||
|
||||
@Component({
|
||||
selector: 'app-description-listing-item-component',
|
||||
|
@ -44,6 +45,8 @@ export class DescriptionListingItemComponent extends BaseComponent implements On
|
|||
isUserOwner: boolean;
|
||||
descriptionStatusEnum = DescriptionStatus;
|
||||
dmpAccessTypeEnum = DmpAccessType;
|
||||
canDelete: boolean = false;
|
||||
canEdit: boolean = false;
|
||||
|
||||
|
||||
constructor(
|
||||
|
@ -80,6 +83,13 @@ export class DescriptionListingItemComponent extends BaseComponent implements On
|
|||
this.isDeleted = false;
|
||||
this.setIsUserOwner();
|
||||
}
|
||||
|
||||
this.canDelete = this.authService.hasPermission(AppPermission.DeleteDescription) ||
|
||||
this.description.authorizationFlags?.some(x => x === AppPermission.DeleteDescription);
|
||||
|
||||
this.canEdit = this.authService.hasPermission(AppPermission.EditDescription) ||
|
||||
this.description.authorizationFlags?.some(x => x === AppPermission.EditDescription);
|
||||
|
||||
}
|
||||
|
||||
setIsUserOwner() {
|
||||
|
@ -240,11 +250,4 @@ export class DescriptionListingItemComponent extends BaseComponent implements On
|
|||
onDeleteCallbackError(error) {
|
||||
this.uiNotificationService.snackBarNotification(error.error.message ? error.error.message : this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-DELETE'), SnackBarNotificationLevel.Error);
|
||||
}
|
||||
|
||||
|
||||
|
||||
isUserDescriptionRelated(): boolean {
|
||||
const principalId: Guid = this.authService.userId();
|
||||
return this.description.dmp.dmpUsers.some(x => (x.user.id === principalId));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,12 +12,12 @@
|
|||
<p class="col description-label p-0 ml-3 mb-0">{{ description.label }}</p>
|
||||
</div>
|
||||
<div class="row d-flex align-items-center mt-3 mb-4 label-txt">
|
||||
<div *ngIf="isUserDescriptionRelated()" class="d-flex">
|
||||
<div *ngIf="canEdit" class="d-flex">
|
||||
<p class="ml-0 mb-0 label2-txt">
|
||||
{{ enumUtils.toDmpUserRolesString(dmpService.getCurrentUserRolesInDmp(description?.dmp?.dmpUsers)) }}
|
||||
</p>
|
||||
</div>
|
||||
<span *ngIf="isUserDescriptionRelated()" class="ml-2 mr-2">.</span>
|
||||
<span *ngIf="canEdit" class="ml-2 mr-2">.</span>
|
||||
<div *ngIf="description.status === descriptionStatusEnum.Finalized && description.dmp.accessType === dmpAccessTypeEnum.Public" class="d-flex flex-row">
|
||||
<mat-icon class="status-icon">public</mat-icon>
|
||||
{{'DESCRIPTION-OVERVIEW.PUBLIC' | translate}}
|
||||
|
@ -39,13 +39,13 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="row mb-4 pb-3">
|
||||
<button *ngIf="isDraftDescription(description) && !lockStatus" (click)="editClicked(description)" mat-mini-fab class="mr-3 actions-btn" matTooltip="{{'DESCRIPTION-OVERVIEW.ACTIONS.EDIT' | translate}}" matTooltipPosition="above">
|
||||
<button *ngIf="canEdit && isDraftDescription(description) && !lockStatus" (click)="editClicked(description)" mat-mini-fab class="mr-3 actions-btn" matTooltip="{{'DESCRIPTION-OVERVIEW.ACTIONS.EDIT' | translate}}" matTooltipPosition="above">
|
||||
<mat-icon class="mat-mini-fab-icon">create</mat-icon>
|
||||
</button>
|
||||
<button *ngIf="isAuthenticated()" (click)="openCopyToDmpDialog()" mat-mini-fab class="mr-3 actions-btn" matTooltip="{{'DESCRIPTION-OVERVIEW.ACTIONS.CLONE' | translate}}" matTooltipPosition="above">
|
||||
<button *ngIf="canEdit" (click)="openCopyToDmpDialog()" mat-mini-fab class="mr-3 actions-btn" matTooltip="{{'DESCRIPTION-OVERVIEW.ACTIONS.CLONE' | translate}}" matTooltipPosition="above">
|
||||
<mat-icon class="mat-mini-fab-icon">content_copy</mat-icon>
|
||||
</button>
|
||||
<button *ngIf="isUserDescriptionRelated() && !lockStatus" (click)="deleteClicked()" mat-mini-fab class="mr-3 actions-btn" matTooltip="{{'DESCRIPTION-OVERVIEW.ACTIONS.DELETE' | translate}}" matTooltipPosition="above">
|
||||
<button *ngIf="canDelete && !lockStatus" (click)="deleteClicked()" mat-mini-fab class="mr-3 actions-btn" matTooltip="{{'DESCRIPTION-OVERVIEW.ACTIONS.DELETE' | translate}}" matTooltipPosition="above">
|
||||
<mat-icon class="mat-mini-fab-icon">delete</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -92,7 +92,7 @@
|
|||
</div>
|
||||
<div class="col-md-4 col-lg-4 p-0">
|
||||
<div class="frame mb-3 pt-4 pl-3 pr-5 pb-1" *ngIf="isAuthenticated()">
|
||||
<div *ngIf="isDraftDescription(description) && !lockStatus">
|
||||
<div *ngIf="canFinalize && isDraftDescription(description) && !lockStatus">
|
||||
<div class="row ml-0 mr-0 pl-4 d-flex align-items-center" (click)="finalize(description)">
|
||||
<button mat-mini-fab class="finalize-btn">
|
||||
<mat-icon class="mat-mini-fab-icon check-icon">check</mat-icon>
|
||||
|
@ -141,10 +141,10 @@
|
|||
<p class="authors-role">{{ enumUtils.toDmpUserRoleString(dmpUser.role) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<button *ngIf="isUserOwner && description.dmp?.status === dmpStatusEnum.Draft && dmpUser.role === dmpUserRoleEnum.Owner" (click)="removeUserFromDmp(dmpUser)" class="remove-btn">{{ 'DESCRIPTION-OVERVIEW.ACTIONS.REMOVE-AUTHOR' | translate}}</button>
|
||||
<button *ngIf="canInviteDmpUsers && description.dmp?.status === dmpStatusEnum.Draft && dmpUser.role === dmpUserRoleEnum.Owner" (click)="removeUserFromDmp(dmpUser)" class="remove-btn">{{ 'DESCRIPTION-OVERVIEW.ACTIONS.REMOVE-AUTHOR' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="isUserOwner" class="row mt-3 mb-3 d-flex align-items-center justify-content-center">
|
||||
<div *ngIf="canInviteDmpUsers" class="row mt-3 mb-3 d-flex align-items-center justify-content-center">
|
||||
<button mat-raised-button class="invite-btn" (click)="openShareDialog(description.dmp.id, description.dmp.label)">
|
||||
<mat-icon>group_add</mat-icon>
|
||||
{{'DESCRIPTION-OVERVIEW.ACTIONS.INVITE-SHORT' | translate}}
|
||||
|
|
|
@ -33,6 +33,7 @@ import { filter, takeUntil } from 'rxjs/operators';
|
|||
import { nameof } from 'ts-simple-nameof';
|
||||
import { DescriptionCopyDialogComponent } from '../description-copy-dialog/description-copy-dialog.component';
|
||||
import { ReferenceType } from '@app/core/model/reference-type/reference-type';
|
||||
import { AppPermission } from '@app/core/common/enum/permission.enum';
|
||||
|
||||
|
||||
@Component({
|
||||
|
@ -49,7 +50,6 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
|
|||
isPublicView = true;
|
||||
hasPublishButton: boolean = true;
|
||||
// breadCrumbs: Observable<BreadcrumbItem[]> = observableOf();
|
||||
isUserOwner: boolean;
|
||||
expand = false;
|
||||
lockStatus: Boolean;
|
||||
descriptionStatusEnum = DescriptionStatus;
|
||||
|
@ -57,6 +57,11 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
|
|||
dmpStatusEnum = DmpStatus;
|
||||
dmpUserRoleEnum = DmpUserRole;
|
||||
|
||||
canEdit = false;
|
||||
canDelete = false;
|
||||
canFinalize = false;
|
||||
canInviteDmpUsers = false;
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
|
@ -72,6 +77,7 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
|
|||
public enumUtils: EnumUtils,
|
||||
private matomoService: MatomoService,
|
||||
private fileUtils: FileUtils,
|
||||
private authService: AuthService,
|
||||
public fileTransformerService: FileTransformerService,
|
||||
private referenceTypeService: ReferenceTypeService,
|
||||
private fb: UntypedFormBuilder,
|
||||
|
@ -81,6 +87,10 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
|
|||
|
||||
ngOnInit() {
|
||||
this.matomoService.trackPageView('Description Overview');
|
||||
this.canDelete = false;
|
||||
this.canEdit = false;
|
||||
this.canFinalize = false;
|
||||
this.canInviteDmpUsers = false;
|
||||
// Gets description data using parameter id
|
||||
this.route.params
|
||||
.pipe(takeUntil(this._destroyed))
|
||||
|
@ -97,11 +107,22 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
|
|||
this.researchers = this.referenceService.getReferencesForTypes(this.description?.dmp?.dmpReferences, [this.referenceTypeService.getResearcherReferenceType()]);
|
||||
// this.users = this.description.dmp.users;
|
||||
this.checkLockStatus(this.description.id);
|
||||
this.setIsUserOwner();
|
||||
this.canDelete = this.authService.hasPermission(AppPermission.DeleteDescription) ||
|
||||
this.description.authorizationFlags?.some(x => x === AppPermission.DeleteDescription);
|
||||
|
||||
this.canEdit = this.authService.hasPermission(AppPermission.EditDescription) ||
|
||||
this.description.authorizationFlags?.some(x => x === AppPermission.EditDescription);
|
||||
|
||||
this.canFinalize = this.authService.hasPermission(AppPermission.FinalizeDescription) ||
|
||||
this.description.authorizationFlags?.some(x => x === AppPermission.FinalizeDescription);
|
||||
|
||||
this.canInviteDmpUsers = this.authService.hasPermission(AppPermission.InviteDmpUsers) ||
|
||||
this.description.dmp?.authorizationFlags?.some(x => x === AppPermission.InviteDmpUsers);
|
||||
// const breadCrumbs = [];
|
||||
// breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.MY-DESCRIPTION-DESCRIPTIONS'), url: "/descriptions" });
|
||||
// breadCrumbs.push({ parentComponentName: 'DescriptionListingComponent', label: this.description.label, url: '/descriptions/overview/' + this.description.id });
|
||||
// this.breadCrumbs = observableOf(breadCrumbs);
|
||||
|
||||
}, (error: any) => {
|
||||
if (error.status === 404) {
|
||||
return this.onFetchingDeletedCallbackError('/descriptions/');
|
||||
|
@ -172,12 +193,6 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
|
|||
this.router.navigateByUrl('/reload', { skipLocationChange: true }).then(() => this.router.navigate([path]));
|
||||
}
|
||||
|
||||
setIsUserOwner() {
|
||||
if (this.description) {
|
||||
const principalId: Guid = this.authentication.userId();
|
||||
if (principalId) this.isUserOwner = !!this.description.dmp.dmpUsers.find(x => (x.role === DmpUserRole.Owner) && (principalId === x.id));
|
||||
}
|
||||
}
|
||||
|
||||
isUserAuthor(userId: Guid): boolean {
|
||||
if (this.isAuthenticated()) {
|
||||
|
@ -186,11 +201,6 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
|
|||
} else return false;
|
||||
}
|
||||
|
||||
isUserDescriptionRelated(): boolean {
|
||||
const principalId: Guid = this.authentication.userId();
|
||||
return this.description.dmp.dmpUsers.some(x => (x.user.id === principalId));
|
||||
}
|
||||
|
||||
|
||||
openShareDialog(rowId: any, rowName: any) {
|
||||
// TODO: add dialog
|
||||
|
@ -439,6 +449,11 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
|
|||
nameof<Description>(x => x.status),
|
||||
nameof<Description>(x => x.updatedAt),
|
||||
nameof<Description>(x => x.hash),
|
||||
|
||||
[nameof<Description>(x => x.authorizationFlags), AppPermission.EditDescription].join('.'),
|
||||
[nameof<Description>(x => x.authorizationFlags), AppPermission.DeleteDescription].join('.'),
|
||||
[nameof<Description>(x => x.authorizationFlags), AppPermission.FinalizeDescription].join('.'),
|
||||
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.id)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.label)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.groupId)].join('.'),
|
||||
|
@ -449,6 +464,7 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
|
|||
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.label)].join('.'),
|
||||
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.accessType)].join('.'),
|
||||
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.status)].join('.'),
|
||||
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.authorizationFlags),AppPermission.InviteDmpUsers].join('.'),
|
||||
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.id)].join('.'),
|
||||
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.user.id)].join('.'),
|
||||
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.user.name)].join('.'),
|
||||
|
|
|
@ -82,20 +82,20 @@ export class DmpEditorComponent extends BaseEditor<DmpEditorModel, Dmp> implemen
|
|||
};
|
||||
|
||||
protected get canDelete(): boolean {
|
||||
return !this.isDeleted && !this.isNew && this.hasPermission(this.authService.permissionEnum.DeleteDmp);
|
||||
return !this.isDeleted && !this.isNew && (this.hasPermission(this.authService.permissionEnum.DeleteDmp) || this.item?.authorizationFlags?.some(x => x === AppPermission.DeleteDmp));
|
||||
}
|
||||
|
||||
protected get canSave(): boolean {
|
||||
return !this.isDeleted && this.hasPermission(this.authService.permissionEnum.EditDmp);
|
||||
return !this.isDeleted && (this.hasPermission(this.authService.permissionEnum.EditDmp) || this.item?.authorizationFlags?.some(x => x === AppPermission.EditDmp));
|
||||
}
|
||||
|
||||
protected get canFinalize(): boolean {
|
||||
return !this.isDeleted && this.hasPermission(this.authService.permissionEnum.EditDmp);
|
||||
return !this.isDeleted && (this.hasPermission(this.authService.permissionEnum.EditDmp) || this.item?.authorizationFlags?.some(x => x === AppPermission.EditDmp));
|
||||
}
|
||||
|
||||
|
||||
private hasPermission(permission: AppPermission): boolean {
|
||||
return this.authService.hasPermission(permission) || this.editorModel?.permissions?.includes(permission);
|
||||
return this.authService.hasPermission(permission) || this.item?.authorizationFlags?.some(x => x === permission) || this.editorModel?.permissions?.includes(permission);
|
||||
}
|
||||
|
||||
constructor(
|
||||
|
|
|
@ -40,6 +40,7 @@ export class DmpEditorResolver extends BaseEditorResolver {
|
|||
nameof<Dmp>(x => x.hash),
|
||||
|
||||
[nameof<Dmp>(x => x.authorizationFlags), AppPermission.EditDmp].join('.'),
|
||||
[nameof<Dmp>(x => x.authorizationFlags), AppPermission.DeleteDmp].join('.'),
|
||||
|
||||
[nameof<Dmp>(x => x.properties), nameof<DmpProperties>(x => x.dmpBlueprintValues), nameof<DmpBlueprintValue>(x => x.fieldId)].join('.'),
|
||||
[nameof<Dmp>(x => x.properties), nameof<DmpProperties>(x => x.dmpBlueprintValues), nameof<DmpBlueprintValue>(x => x.fieldValue)].join('.'),
|
||||
|
|
Loading…
Reference in New Issue