Merge branch 'dmp-refactoring' of https://code-repo.d4science.org/MaDgiK-CITE/argos into dmp-refactoring

This commit is contained in:
Sofia Papacharalampous 2024-03-15 15:49:44 +02:00
commit 765440b509
37 changed files with 394 additions and 120 deletions

View File

@ -102,6 +102,7 @@ public final class Permission {
//Description //Description
public static String BrowseDescription = "BrowseDescription"; public static String BrowseDescription = "BrowseDescription";
public static String EditDescription = "EditDescription"; public static String EditDescription = "EditDescription";
public static String FinalizeDescription = "FinalizeDescription";
public static String DeleteDescription = "DeleteDescription"; public static String DeleteDescription = "DeleteDescription";
public static String CloneDescription = "CloneDescription"; public static String CloneDescription = "CloneDescription";

View File

@ -12,4 +12,8 @@ public interface AuthorizationContentResolver {
AffiliatedResource dmpAffiliation(UUID id); AffiliatedResource dmpAffiliation(UUID id);
Map<UUID, AffiliatedResource> dmpsAffiliation(List<UUID> ids); Map<UUID, AffiliatedResource> dmpsAffiliation(List<UUID> ids);
AffiliatedResource descriptionAffiliation(UUID id);
Map<UUID, AffiliatedResource> descriptionsAffiliation(List<UUID> ids);
} }

View File

@ -4,9 +4,12 @@ import eu.eudat.authorization.AffiliatedResource;
import eu.eudat.authorization.PermissionNameProvider; import eu.eudat.authorization.PermissionNameProvider;
import eu.eudat.commons.enums.IsActive; import eu.eudat.commons.enums.IsActive;
import eu.eudat.commons.scope.user.UserScope; import eu.eudat.commons.scope.user.UserScope;
import eu.eudat.data.DescriptionEntity;
import eu.eudat.data.DmpEntity; import eu.eudat.data.DmpEntity;
import eu.eudat.data.DmpUserEntity; import eu.eudat.data.DmpUserEntity;
import eu.eudat.model.Description;
import eu.eudat.model.DmpUser; import eu.eudat.model.DmpUser;
import eu.eudat.query.DescriptionQuery;
import eu.eudat.query.DmpUserQuery; import eu.eudat.query.DmpUserQuery;
import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.data.query.QueryFactory;
import gr.cite.tools.fieldset.BaseFieldSet; import gr.cite.tools.fieldset.BaseFieldSet;
@ -14,6 +17,7 @@ import org.springframework.stereotype.Service;
import org.springframework.web.context.annotation.RequestScope; import org.springframework.web.context.annotation.RequestScope;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
@Service @Service
@RequestScope @RequestScope
@ -60,6 +64,37 @@ public class AuthorizationContentResolverImpl implements AuthorizationContentRes
return affiliatedResources; 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){ private List<UUID> getAffiliatedFromCache(List<UUID> ids, UUID userId, Map<UUID, AffiliatedResource> affiliatedResources, String entityType){
List<UUID> idsToResolve = new ArrayList<>(); List<UUID> idsToResolve = new ArrayList<>();
for (UUID id : ids){ for (UUID id : ids){

View File

@ -71,6 +71,9 @@ public class Description {
public static final String _descriptionTemplate = "descriptionTemplate"; public static final String _descriptionTemplate = "descriptionTemplate";
private List<String> authorizationFlags;
public static final String _authorizationFlags = "authorizationFlags";
private Dmp dmp; private Dmp dmp;
public static final String _dmp = "dmp"; public static final String _dmp = "dmp";
@ -203,4 +206,12 @@ public class Description {
public void setDescriptionTemplate(DescriptionTemplate descriptionTemplate) { public void setDescriptionTemplate(DescriptionTemplate descriptionTemplate) {
this.descriptionTemplate = descriptionTemplate; this.descriptionTemplate = descriptionTemplate;
} }
public List<String> getAuthorizationFlags() {
return authorizationFlags;
}
public void setAuthorizationFlags(List<String> authorizationFlags) {
this.authorizationFlags = authorizationFlags;
}
} }

View File

@ -1,6 +1,8 @@
package eu.eudat.model.builder; package eu.eudat.model.builder;
import eu.eudat.authorization.AffiliatedResource;
import eu.eudat.authorization.AuthorizationFlags; import eu.eudat.authorization.AuthorizationFlags;
import eu.eudat.authorization.authorizationcontentresolver.AuthorizationContentResolver;
import eu.eudat.commons.JsonHandlingService; import eu.eudat.commons.JsonHandlingService;
import eu.eudat.commons.XmlHandlingService; import eu.eudat.commons.XmlHandlingService;
import eu.eudat.commons.types.description.PropertyDefinitionEntity; 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.convention.ConventionService;
import eu.eudat.data.DescriptionEntity; import eu.eudat.data.DescriptionEntity;
import eu.eudat.data.DescriptionTemplateEntity; import eu.eudat.data.DescriptionTemplateEntity;
import eu.eudat.data.DmpEntity;
import eu.eudat.data.UserRoleEntity; import eu.eudat.data.UserRoleEntity;
import eu.eudat.model.*; import eu.eudat.model.*;
import eu.eudat.model.builder.descriptionpropertiesdefinition.PropertyDefinitionBuilder; import eu.eudat.model.builder.descriptionpropertiesdefinition.PropertyDefinitionBuilder;
import eu.eudat.query.*; import eu.eudat.query.*;
import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.tools.data.builder.BuilderFactory; import gr.cite.tools.data.builder.BuilderFactory;
import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.data.query.QueryFactory;
import gr.cite.tools.exception.MyApplicationException; import gr.cite.tools.exception.MyApplicationException;
@ -37,6 +41,8 @@ public class DescriptionBuilder extends BaseBuilder<Description, DescriptionEnti
private final BuilderFactory builderFactory; private final BuilderFactory builderFactory;
private final JsonHandlingService jsonHandlingService; private final JsonHandlingService jsonHandlingService;
private final XmlHandlingService xmlHandlingService; private final XmlHandlingService xmlHandlingService;
private final AuthorizationService authorizationService;
private final AuthorizationContentResolver authorizationContentResolver;
private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None); private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None);
@ -44,12 +50,14 @@ public class DescriptionBuilder extends BaseBuilder<Description, DescriptionEnti
public DescriptionBuilder( public DescriptionBuilder(
ConventionService conventionService, ConventionService conventionService,
QueryFactory queryFactory, 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))); super(conventionService, new LoggerService(LoggerFactory.getLogger(DescriptionBuilder.class)));
this.queryFactory = queryFactory; this.queryFactory = queryFactory;
this.builderFactory = builderFactory; this.builderFactory = builderFactory;
this.jsonHandlingService = jsonHandlingService; this.jsonHandlingService = jsonHandlingService;
this.xmlHandlingService = xmlHandlingService; this.xmlHandlingService = xmlHandlingService;
this.authorizationService = authorizationService;
this.authorizationContentResolver = authorizationContentResolver;
} }
public DescriptionBuilder authorize(EnumSet<AuthorizationFlags> values) { 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)); FieldSet definitionPropertiesFields = fields.extractPrefixed(this.asPrefix(Description._properties));
Map<UUID, DefinitionEntity> definitionEntityMap = !definitionPropertiesFields.isEmpty() ? this.collectDescriptionTemplateDefinitions(data) : null; 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<>(); List<Description> models = new ArrayList<>();
for (DescriptionEntity d : data) { for (DescriptionEntity d : data) {
Description m = new Description(); Description m = new Description();
@ -108,6 +119,7 @@ public class DescriptionBuilder extends BaseBuilder<Description, DescriptionEnti
PropertyDefinitionEntity propertyDefinition = this.jsonHandlingService.fromJsonSafe(PropertyDefinitionEntity.class, d.getProperties()); 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)); 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); models.add(m);
} }

View File

@ -89,7 +89,6 @@ public class DmpBuilder extends BaseBuilder<Dmp, DmpEntity> {
Map<UUID, List<DmpDescriptionTemplate>> dmpDescriptionTemplatesMap = this.collectDmpDescriptionTemplates(dmpDescriptionTemplatesFields, data); Map<UUID, List<DmpDescriptionTemplate>> dmpDescriptionTemplatesMap = this.collectDmpDescriptionTemplates(dmpDescriptionTemplatesFields, data);
Set<String> authorizationFlags = this.extractAuthorizationFlags(fields, Dmp._authorizationFlags, this.authorizationContentResolver.getPermissionNames()); 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())); 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)); 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()); DmpPropertiesEntity propertyDefinition = this.jsonHandlingService.fromJsonSafe(DmpPropertiesEntity.class, d.getProperties());
m.setProperties(this.builderFactory.builder(DmpPropertiesBuilder.class).authorize(this.authorize).build(propertiesFields, propertyDefinition)); 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); models.add(m);
} }
this.logger.debug("build {} items", Optional.of(models).map(List::size).orElse(0)); this.logger.debug("build {} items", Optional.of(models).map(List::size).orElse(0));

View File

@ -41,7 +41,7 @@ public class DescriptionReferenceCensor extends BaseCensor {
if (fields == null || fields.isEmpty()) if (fields == null || fields.isEmpty())
return; return;
this.authService.authorizeForce(Permission.BrowseDescriptionReference); this.authService.authorizeForce(Permission.BrowseDescriptionReference, Permission.DeferredAffiliation);
FieldSet descriptionFields = fields.extractPrefixed(this.asIndexerPrefix(DescriptionReference._description)); FieldSet descriptionFields = fields.extractPrefixed(this.asIndexerPrefix(DescriptionReference._description));
this.censorFactory.censor(DescriptionCensor.class).censor(descriptionFields, userId); this.censorFactory.censor(DescriptionCensor.class).censor(descriptionFields, userId);
FieldSet referenceFields = fields.extractPrefixed(this.asIndexerPrefix(DescriptionReference._reference)); FieldSet referenceFields = fields.extractPrefixed(this.asIndexerPrefix(DescriptionReference._reference));

View File

@ -41,7 +41,7 @@ public class DescriptionTagCensor extends BaseCensor {
if (fields == null || fields.isEmpty()) if (fields == null || fields.isEmpty())
return; return;
this.authService.authorizeForce(Permission.BrowseDescriptionTag); this.authService.authorizeForce(Permission.BrowseDescriptionTag, Permission.DeferredAffiliation);
FieldSet descriptionFields = fields.extractPrefixed(this.asIndexerPrefix(DescriptionTag._description)); FieldSet descriptionFields = fields.extractPrefixed(this.asIndexerPrefix(DescriptionTag._description));
this.censorFactory.censor(DescriptionCensor.class).censor(descriptionFields, userId); this.censorFactory.censor(DescriptionCensor.class).censor(descriptionFields, userId);
FieldSet tagFields = fields.extractPrefixed(this.asIndexerPrefix(DescriptionTag._tag)); FieldSet tagFields = fields.extractPrefixed(this.asIndexerPrefix(DescriptionTag._tag));

View File

@ -39,7 +39,7 @@ public class TagCensor extends BaseCensor {
if (fields == null || fields.isEmpty()) if (fields == null || fields.isEmpty())
return; return;
this.authService.authorizeForce(Permission.BrowseTag); this.authService.authorizeForce(Permission.BrowseTag, Permission.DeferredAffiliation);
FieldSet createdByFields = fields.extractPrefixed(this.asIndexerPrefix(Tag._createdBy)); FieldSet createdByFields = fields.extractPrefixed(this.asIndexerPrefix(Tag._createdBy));
this.censorFactory.censor(UserCensor.class).censor(createdByFields, userId); this.censorFactory.censor(UserCensor.class).censor(createdByFields, userId);
} }

View File

@ -33,7 +33,7 @@ public class FieldCensor extends BaseCensor {
if (fields == null || fields.isEmpty()) if (fields == null || fields.isEmpty())
return; return;
this.authService.authorizeForce(Permission.BrowseDescription); this.authService.authorizeForce(Permission.BrowseDescription, Permission.DeferredAffiliation);
} }
} }

View File

@ -41,7 +41,7 @@ public class PropertyDefinitionCensor extends BaseCensor {
if (fields == null || fields.isEmpty()) if (fields == null || fields.isEmpty())
return; return;
this.authService.authorizeForce(Permission.BrowseDescription); this.authService.authorizeForce(Permission.BrowseDescription, Permission.DeferredAffiliation);
FieldSet fieldSetFields = fields.extractPrefixed(this.asIndexerPrefix(PropertyDefinition._fieldSets)); FieldSet fieldSetFields = fields.extractPrefixed(this.asIndexerPrefix(PropertyDefinition._fieldSets));
this.censorFactory.censor(PropertyDefinitionFieldSetCensor.class).censor(fieldSetFields, userId); this.censorFactory.censor(PropertyDefinitionFieldSetCensor.class).censor(fieldSetFields, userId);
} }

View File

@ -39,7 +39,7 @@ public class PropertyDefinitionFieldSetCensor extends BaseCensor {
if (fields == null || fields.isEmpty()) if (fields == null || fields.isEmpty())
return; return;
this.authService.authorizeForce(Permission.BrowseDescription); this.authService.authorizeForce(Permission.BrowseDescription, Permission.DeferredAffiliation);
FieldSet itemsFields = fields.extractPrefixed(this.asIndexerPrefix(PropertyDefinitionFieldSet._items)); FieldSet itemsFields = fields.extractPrefixed(this.asIndexerPrefix(PropertyDefinitionFieldSet._items));
this.censorFactory.censor(PropertyDefinitionFieldSetItemCensor.class).censor(itemsFields, userId); this.censorFactory.censor(PropertyDefinitionFieldSetItemCensor.class).censor(itemsFields, userId);
} }

View File

@ -39,7 +39,7 @@ public class PropertyDefinitionFieldSetItemCensor extends BaseCensor {
if (fields == null || fields.isEmpty()) if (fields == null || fields.isEmpty())
return; return;
this.authService.authorizeForce(Permission.BrowseDescription); this.authService.authorizeForce(Permission.BrowseDescription, Permission.DeferredAffiliation);
FieldSet fieldFields = fields.extractPrefixed(this.asIndexerPrefix(PropertyDefinitionFieldSetItem._fields)); FieldSet fieldFields = fields.extractPrefixed(this.asIndexerPrefix(PropertyDefinitionFieldSetItem._fields));
this.censorFactory.censor(FieldCensor.class).censor(fieldFields, userId); this.censorFactory.censor(FieldCensor.class).censor(fieldFields, userId);
} }

View File

@ -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.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.match(Description._descriptionTemplate) || item.match(PublicDescription._descriptionTemplate)) return DescriptionEntity._descriptionTemplateId;
else if (item.prefix(Description._dmp)) return DescriptionEntity._dmpId; else if (item.prefix(Description._dmp)) return DescriptionEntity._dmpId;
else if (item.match(Description._dmp)) return DescriptionEntity._dmpId;
else return null; else return null;
} }

View File

@ -154,14 +154,16 @@ public class DescriptionReferenceQuery extends QueryBase<DescriptionReferenceEnt
boolean usePublic = this.authorize.contains(AuthorizationFlags.Public); boolean usePublic = this.authorize.contains(AuthorizationFlags.Public);
if (this.authorize.contains(AuthorizationFlags.DmpAssociated)) userId = this.userScope.getUserIdSafe(); if (this.authorize.contains(AuthorizationFlags.DmpAssociated)) userId = this.userScope.getUserIdSafe();
else userId = null; else userId = null;
if (this.authorize.contains(AuthorizationFlags.Owner)) userId = this.userScope.getUserIdSafe();
List<Predicate> predicates = new ArrayList<>(); List<Predicate> predicates = new ArrayList<>();
if (userId != null || usePublic ) { if (userId != null || usePublic ) {
UUID finalUserId = userId;
Subquery<UUID> descriptionSubquery = queryUtilsService.buildSubQuery(new BuildSubQueryInput<>( Subquery<UUID> descriptionSubquery = queryUtilsService.buildSubQuery(new BuildSubQueryInput<>(
new BuildSubQueryInput.Builder<>(DescriptionEntity.class, UUID.class, queryContext) new BuildSubQueryInput.Builder<>(DescriptionEntity.class, UUID.class, queryContext)
.keyPathFunc((subQueryRoot) -> subQueryRoot.get(DescriptionEntity._id)) .keyPathFunc((subQueryRoot) -> subQueryRoot.get(DescriptionEntity._id))
.filterFunc((subQueryRoot, cb) -> .filterFunc((subQueryRoot, cb) ->
cb.in(subQueryRoot.get(DescriptionEntity._dmpDescriptionTemplateId)).value(queryUtilsService.buildDmpAuthZSubQuery(queryContext.Query, queryContext.CriteriaBuilder, userId, usePublic)) cb.in(subQueryRoot.get(DescriptionEntity._dmpDescriptionTemplateId)).value(queryUtilsService.buildDmpAuthZSubQuery(queryContext.Query, queryContext.CriteriaBuilder, finalUserId, usePublic))
) )
)); ));
predicates.add(queryContext.CriteriaBuilder.in(queryContext.Root.get(DescriptionReferenceEntity._descriptionId)).value(descriptionSubquery)); predicates.add(queryContext.CriteriaBuilder.in(queryContext.Root.get(DescriptionReferenceEntity._descriptionId)).value(descriptionSubquery));

View File

@ -152,14 +152,16 @@ public class DescriptionTagQuery extends QueryBase<DescriptionTagEntity> {
boolean usePublic = this.authorize.contains(AuthorizationFlags.Public); boolean usePublic = this.authorize.contains(AuthorizationFlags.Public);
if (this.authorize.contains(AuthorizationFlags.DmpAssociated)) userId = this.userScope.getUserIdSafe(); if (this.authorize.contains(AuthorizationFlags.DmpAssociated)) userId = this.userScope.getUserIdSafe();
else userId = null; else userId = null;
if (this.authorize.contains(AuthorizationFlags.Owner)) userId = this.userScope.getUserIdSafe();
List<Predicate> predicates = new ArrayList<>(); List<Predicate> predicates = new ArrayList<>();
if (userId != null || usePublic ) { if (userId != null || usePublic ) {
UUID finalUserId = userId;
Subquery<UUID> descriptionSubquery = queryUtilsService.buildSubQuery(new BuildSubQueryInput<>( Subquery<UUID> descriptionSubquery = queryUtilsService.buildSubQuery(new BuildSubQueryInput<>(
new BuildSubQueryInput.Builder<>(DescriptionEntity.class, UUID.class, queryContext) new BuildSubQueryInput.Builder<>(DescriptionEntity.class, UUID.class, queryContext)
.keyPathFunc((subQueryRoot) -> subQueryRoot.get(DescriptionEntity._id)) .keyPathFunc((subQueryRoot) -> subQueryRoot.get(DescriptionEntity._id))
.filterFunc((subQueryRoot, cb) -> .filterFunc((subQueryRoot, cb) ->
cb.in(subQueryRoot.get(DescriptionEntity._dmpDescriptionTemplateId)).value(queryUtilsService.buildDmpAuthZSubQuery(queryContext.Query, queryContext.CriteriaBuilder, userId, usePublic)) cb.in(subQueryRoot.get(DescriptionEntity._dmpDescriptionTemplateId)).value(queryUtilsService.buildDmpAuthZSubQuery(queryContext.Query, queryContext.CriteriaBuilder, finalUserId, usePublic))
) )
)); ));
predicates.add(queryContext.CriteriaBuilder.in(queryContext.Root.get(DescriptionTagEntity._descriptionId)).value(descriptionSubquery)); predicates.add(queryContext.CriteriaBuilder.in(queryContext.Root.get(DescriptionTagEntity._descriptionId)).value(descriptionSubquery));

View File

@ -5,9 +5,7 @@ import eu.eudat.authorization.Permission;
import eu.eudat.commons.enums.DmpUserRole; import eu.eudat.commons.enums.DmpUserRole;
import eu.eudat.commons.enums.IsActive; import eu.eudat.commons.enums.IsActive;
import eu.eudat.commons.scope.user.UserScope; import eu.eudat.commons.scope.user.UserScope;
import eu.eudat.data.DmpReferenceEntity; import eu.eudat.data.*;
import eu.eudat.data.DmpUserEntity;
import eu.eudat.data.ReferenceEntity;
import eu.eudat.model.DmpUser; import eu.eudat.model.DmpUser;
import eu.eudat.model.PublicDmpUser; import eu.eudat.model.PublicDmpUser;
import eu.eudat.query.utils.BuildSubQueryInput; import eu.eudat.query.utils.BuildSubQueryInput;
@ -19,6 +17,7 @@ import gr.cite.tools.data.query.QueryContext;
import jakarta.persistence.Tuple; import jakarta.persistence.Tuple;
import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.Predicate; import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Subquery;
import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -36,6 +35,8 @@ public class DmpUserQuery extends QueryBase<DmpUserEntity> {
private Collection<UUID> dmpIds; private Collection<UUID> dmpIds;
private Collection<UUID> descriptionIds;
private Collection<UUID> userIds; private Collection<UUID> userIds;
private Collection<DmpUserRole> userRoles; private Collection<DmpUserRole> userRoles;
@ -89,6 +90,21 @@ public class DmpUserQuery extends QueryBase<DmpUserEntity> {
return this; 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) { public DmpUserQuery userRoles(DmpUserRole value) {
this.userRoles = List.of(value); this.userRoles = List.of(value);
return this; return this;
@ -161,7 +177,7 @@ public class DmpUserQuery extends QueryBase<DmpUserEntity> {
@Override @Override
protected Boolean isFalseQuery() { 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 @Override
@ -208,6 +224,19 @@ public class DmpUserQuery extends QueryBase<DmpUserEntity> {
inClause.value(item); inClause.value(item);
predicates.add(inClause); 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) { if (this.userIds != null) {
CriteriaBuilder.In<UUID> inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(DmpUserEntity._userId)); CriteriaBuilder.In<UUID> inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(DmpUserEntity._userId));
for (UUID item : this.userIds) for (UUID item : this.userIds)

View File

@ -1,9 +1,17 @@
package eu.eudat.query; package eu.eudat.query;
import eu.eudat.authorization.AuthorizationFlags; import eu.eudat.authorization.AuthorizationFlags;
import eu.eudat.authorization.Permission;
import eu.eudat.commons.enums.IsActive; 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.data.TagEntity;
import eu.eudat.model.Tag; 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.FieldResolver;
import gr.cite.tools.data.query.QueryBase; import gr.cite.tools.data.query.QueryBase;
import gr.cite.tools.data.query.QueryContext; import gr.cite.tools.data.query.QueryContext;
@ -34,8 +42,15 @@ public class TagQuery extends QueryBase<TagEntity> {
private Collection<UUID> createdByIds; private Collection<UUID> createdByIds;
private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None); 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) { public TagQuery like(String value) {
@ -153,6 +168,37 @@ public class TagQuery extends QueryBase<TagEntity> {
protected Class<TagEntity> entityClass() { protected Class<TagEntity> entityClass() {
return TagEntity.class; 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 @Override
protected <X, Y> Predicate applyFilters(QueryContext<X, Y> queryContext) { protected <X, Y> Predicate applyFilters(QueryContext<X, Y> queryContext) {

View File

@ -2,6 +2,7 @@ package eu.eudat.service.description;
import eu.eudat.authorization.AuthorizationFlags; import eu.eudat.authorization.AuthorizationFlags;
import eu.eudat.authorization.Permission; import eu.eudat.authorization.Permission;
import eu.eudat.authorization.authorizationcontentresolver.AuthorizationContentResolver;
import eu.eudat.commons.JsonHandlingService; import eu.eudat.commons.JsonHandlingService;
import eu.eudat.commons.XmlHandlingService; import eu.eudat.commons.XmlHandlingService;
import eu.eudat.commons.enums.*; import eu.eudat.commons.enums.*;
@ -97,21 +98,22 @@ public class DescriptionServiceImpl implements DescriptionService {
private final StorageFileProperties storageFileConfig; private final StorageFileProperties storageFileConfig;
private final StorageFileService storageFileService; private final StorageFileService storageFileService;
private final DescriptionTouchedIntegrationEventHandler descriptionTouchedIntegrationEventHandler; private final DescriptionTouchedIntegrationEventHandler descriptionTouchedIntegrationEventHandler;
private final AuthorizationContentResolver authorizationContentResolver;
@Autowired @Autowired
public DescriptionServiceImpl( public DescriptionServiceImpl(
EntityManager entityManager, EntityManager entityManager,
AuthorizationService authorizationService, AuthorizationService authorizationService,
DeleterFactory deleterFactory, DeleterFactory deleterFactory,
BuilderFactory builderFactory, BuilderFactory builderFactory,
ConventionService conventionService, ConventionService conventionService,
ErrorThesaurusProperties errors, ErrorThesaurusProperties errors,
MessageSource messageSource, MessageSource messageSource,
EventBroker eventBroker, EventBroker eventBroker,
QueryFactory queryFactory, QueryFactory queryFactory,
JsonHandlingService jsonHandlingService, JsonHandlingService jsonHandlingService,
UserScope userScope, UserScope userScope,
XmlHandlingService xmlHandlingService, NotifyIntegrationEventHandler eventHandler, NotificationProperties notificationProperties, FileTransformerService fileTransformerService, ElasticService elasticService, ValidatorFactory validatorFactory, StorageFileProperties storageFileConfig, StorageFileService storageFileService, DescriptionTouchedIntegrationEventHandler descriptionTouchedIntegrationEventHandler) { XmlHandlingService xmlHandlingService, NotifyIntegrationEventHandler eventHandler, NotificationProperties notificationProperties, FileTransformerService fileTransformerService, ElasticService elasticService, ValidatorFactory validatorFactory, StorageFileProperties storageFileConfig, StorageFileService storageFileService, DescriptionTouchedIntegrationEventHandler descriptionTouchedIntegrationEventHandler, AuthorizationContentResolver authorizationContentResolver) {
this.entityManager = entityManager; this.entityManager = entityManager;
this.authorizationService = authorizationService; this.authorizationService = authorizationService;
this.deleterFactory = deleterFactory; this.deleterFactory = deleterFactory;
@ -132,6 +134,7 @@ public class DescriptionServiceImpl implements DescriptionService {
this.storageFileConfig = storageFileConfig; this.storageFileConfig = storageFileConfig;
this.storageFileService = storageFileService; this.storageFileService = storageFileService;
this.descriptionTouchedIntegrationEventHandler = descriptionTouchedIntegrationEventHandler; this.descriptionTouchedIntegrationEventHandler = descriptionTouchedIntegrationEventHandler;
this.authorizationContentResolver = authorizationContentResolver;
} }
//region Persist //region Persist
@ -140,9 +143,10 @@ public class DescriptionServiceImpl implements DescriptionService {
public Description persist(DescriptionPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, IOException { 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)); 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()); 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; DescriptionEntity data;
if (isUpdate) { if (isUpdate) {
@ -337,13 +341,14 @@ public class DescriptionServiceImpl implements DescriptionService {
public Description persistStatus(DescriptionStatusPersist model, FieldSet fields) throws IOException { public Description persistStatus(DescriptionStatusPersist model, FieldSet fields) throws IOException {
logger.debug(new MapLogEntry("persisting data dmp").And("model", model).And("fields", fields)); 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()); 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 (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 (!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(model.getStatus())){
if (data.getStatus().equals(DescriptionStatus.Finalized)){ 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()); 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 == 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()); if(!dmpEntity.getStatus().equals(DmpStatus.Draft)) throw new MyValidationException(this.errors.getDmpIsFinalized().getCode(), this.errors.getDmpIsFinalized().getMessage());
@ -672,7 +677,7 @@ public class DescriptionServiceImpl implements DescriptionService {
public void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException, IOException { public void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException, IOException {
logger.debug("deleting description: {}", id); 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); this.deleterFactory.deleter(DescriptionDeleter.class).deleteAndSaveByIds(List.of(id), false);
} }
@ -685,7 +690,7 @@ public class DescriptionServiceImpl implements DescriptionService {
public void clone(UUID dmpId, UUID descriptionId) throws InvalidApplicationException, IOException { public void clone(UUID dmpId, UUID descriptionId) throws InvalidApplicationException, IOException {
logger.debug("cloning description: {} with description: {}", descriptionId, dmpId); 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(); DescriptionEntity existing = this.queryFactory.query(DescriptionQuery.class).ids(descriptionId).isActive(IsActive.Active).first();
@ -765,7 +770,8 @@ public class DescriptionServiceImpl implements DescriptionService {
@Override @Override
public StorageFile uploadFieldFile(DescriptionFieldFilePersist model, MultipartFile file, FieldSet fields) throws IOException { 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(); 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())); if (descriptionTemplate == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getDescriptionTemplateId(), DescriptionTemplate.class.getSimpleName()}, LocaleContextHolder.getLocale()));
@ -805,7 +811,8 @@ public class DescriptionServiceImpl implements DescriptionService {
@Override @Override
public StorageFileEntity getFieldFile(UUID descriptionId, UUID storageFileId) { 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(); 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())); if (descriptionEntity == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{descriptionId, Description.class.getSimpleName()}, LocaleContextHolder.getLocale()));

View File

@ -132,18 +132,48 @@ permissions:
BrowseDescription: BrowseDescription:
roles: roles:
- Admin - Admin
dmp:
roles:
- Owner
- User
- DescriptionContributor
- Reviewer
clients: [ ] clients: [ ]
allowAnonymous: false allowAnonymous: false
allowAuthenticated: false allowAuthenticated: false
EditDescription: EditDescription:
roles: roles:
- Admin - Admin
dmp:
roles:
- Owner
- User
- DescriptionContributor
- Reviewer
clients: [ ]
allowAnonymous: false
allowAuthenticated: false
FinalizeDescription:
roles:
- Admin
dmp:
roles:
- Owner
- User
- DescriptionContributor
- Reviewer
clients: [ ] clients: [ ]
allowAnonymous: false allowAnonymous: false
allowAuthenticated: false allowAuthenticated: false
DeleteDescription: DeleteDescription:
roles: roles:
- Admin - Admin
dmp:
roles:
- Owner
- User
- DescriptionContributor
- Reviewer
claims: [ ] claims: [ ]
clients: [ ] clients: [ ]
allowAnonymous: false allowAnonymous: false
@ -151,11 +181,16 @@ permissions:
CloneDescription: CloneDescription:
roles: roles:
- Admin - Admin
dmp:
roles:
- Owner
- User
- DescriptionContributor
- Reviewer
claims: [ ] claims: [ ]
clients: [ ] clients: [ ]
allowAnonymous: false allowAnonymous: false
allowAuthenticated: false allowAuthenticated: false
# Tag # Tag
BrowseTag: BrowseTag:
roles: roles:

View File

@ -10,8 +10,10 @@ export enum AppPermission {
DeleteDmpBlueprint = "DeleteDmpBlueprint", DeleteDmpBlueprint = "DeleteDmpBlueprint",
//Description //Description
NewDescription = "NewDescription",
BrowseDescription = "BrowseDescription", BrowseDescription = "BrowseDescription",
EditDescription = "EditDescription", EditDescription = "EditDescription",
FinalizeDescription = "FinalizeDescription",
DeleteDescription= "DeleteDescription", DeleteDescription= "DeleteDescription",
//Dmp //Dmp

View File

@ -6,6 +6,7 @@ import { Dmp, DmpDescriptionTemplate, PublicDmp } from "../dmp/dmp";
import { Reference, ReferencePersist } from "../reference/reference"; import { Reference, ReferencePersist } from "../reference/reference";
import { Tag } from "../tag/tag"; import { Tag } from "../tag/tag";
import { User } from "../user/user"; import { User } from "../user/user";
import { AppPermission } from "@app/core/common/enum/permission.enum";
export interface Description extends BaseEntity { export interface Description extends BaseEntity {
label?: string; label?: string;
@ -19,6 +20,7 @@ export interface Description extends BaseEntity {
descriptionTemplate?: DescriptionTemplate; descriptionTemplate?: DescriptionTemplate;
dmpDescriptionTemplate?: DmpDescriptionTemplate; dmpDescriptionTemplate?: DmpDescriptionTemplate;
dmp?: Dmp; dmp?: Dmp;
authorizationFlags?: AppPermission[];
} }
@ -64,9 +66,9 @@ export interface DescriptionTag extends BaseEntity {
tag?: Tag; tag?: Tag;
} }
// //
// Persist // Persist
// //
export interface DescriptionPersist extends BaseEntityPersist { export interface DescriptionPersist extends BaseEntityPersist {
label: string; label: string;
dmpId: Guid; dmpId: Guid;
@ -141,4 +143,4 @@ export interface PublicDescriptionTemplate {
id: Guid; id: Guid;
label: string; label: string;
description: string; description: string;
} }

View File

@ -148,10 +148,10 @@
<div class="personal-usage">{{'DASHBOARD.PUBLIC-USAGE' | translate}}</div> <div class="personal-usage">{{'DASHBOARD.PUBLIC-USAGE' | translate}}</div>
<div [ngClass]="{'counter': dashboardStatistics?.dmpCount != 0, 'counter-zero': dashboardStatistics?.dmpCount == 0}"> <div [ngClass]="{'counter': dashboardStatistics?.dmpCount != 0, 'counter-zero': dashboardStatistics?.dmpCount == 0}">
{{dashboardStatistics?.dmpCount}}</div> {{dashboardStatistics?.dmpCount}}</div>
<a [routerLink]="['/plans']" class="link">{{'DASHBOARD.PUBLIC-DMPS' | translate}}</a> <a [routerLink]="['/explore-plans']" class="link">{{'DASHBOARD.PUBLIC-DMPS' | translate}}</a>
<div [ngClass]="{'counter': dashboardStatistics?.descriptionCount != 0, 'counter-zero': dashboardStatistics?.descriptionCount == 0}"> <div [ngClass]="{'counter': dashboardStatistics?.descriptionCount != 0, 'counter-zero': dashboardStatistics?.descriptionCount == 0}">
{{dashboardStatistics?.descriptionCount}}</div> {{dashboardStatistics?.descriptionCount}}</div>
<a [routerLink]="['/descriptions']" class="link">{{'DASHBOARD.PUBLIC-DESCRIPTIONS' | translate}}</a> <a [routerLink]="['/explore-descriptions']" class="link">{{'DASHBOARD.PUBLIC-DESCRIPTIONS' | translate}}</a>
<div [ngClass]="{'counter': grantCount != 0, 'counter-zero': grantCount == 0}"> <div [ngClass]="{'counter': grantCount != 0, 'counter-zero': grantCount == 0}">
{{grantCount}}</div> {{grantCount}}</div>
<a href="#" class="link-disabled">{{'DASHBOARD.GRANTS' | translate}}</a> <a href="#" class="link-disabled">{{'DASHBOARD.GRANTS' | translate}}</a>

View File

@ -20,6 +20,9 @@ import { debounceTime, takeUntil } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof'; import { nameof } from 'ts-simple-nameof';
import { AuthService } from '../../../core/services/auth/auth.service'; import { AuthService } from '../../../core/services/auth/auth.service';
import { ReferenceType } from '@app/core/model/reference-type/reference-type'; import { ReferenceType } from '@app/core/model/reference-type/reference-type';
import { DmpStatus } from '@app/core/common/enum/dmp-status';
import { DescriptionStatus } from '@app/core/common/enum/description-status';
import { IsActive } from '@app/core/common/enum/is-active.enum';
@Component({ @Component({
selector: 'app-drafts', selector: 'app-drafts',
@ -30,7 +33,7 @@ export class DraftsComponent extends BaseComponent implements OnInit {
lookup: RecentActivityItemLookup = new RecentActivityItemLookup(); lookup: RecentActivityItemLookup = new RecentActivityItemLookup();
pageSize: number = 5; pageSize: number = 5;
listingItems: RecentActivityItem[]; listingItems: RecentActivityItem[] = [];
public formGroup = new UntypedFormBuilder().group({ public formGroup = new UntypedFormBuilder().group({
like: new UntypedFormControl(), like: new UntypedFormControl(),
@ -131,8 +134,11 @@ export class DraftsComponent extends BaseComponent implements OnInit {
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.version)].join('.'), [nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.version)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.groupId)].join('.'), [nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.groupId)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.updatedAt)].join('.'), [nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.updatedAt)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.isActive)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.id)].join('.'), [nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.id)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.label)].join('.'), [nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.label)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.status)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.isActive)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.id)].join('.'), [nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.id)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.user.id)].join('.'), [nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.user.id)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.role)].join('.'), [nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.role)].join('.'),
@ -147,6 +153,7 @@ export class DraftsComponent extends BaseComponent implements OnInit {
[nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.label)].join('.'), [nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.label)].join('.'),
[nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.status)].join('.'), [nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.status)].join('.'),
[nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.updatedAt)].join('.'), [nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.updatedAt)].join('.'),
[nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.isActive)].join('.'),
[nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.id)].join('.'), [nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.id)].join('.'),
[nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.label)].join('.'), [nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.label)].join('.'),
[nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.groupId)].join('.'), [nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.groupId)].join('.'),
@ -170,7 +177,22 @@ export class DraftsComponent extends BaseComponent implements OnInit {
.getMyRecentActivityItems(this.lookup) .getMyRecentActivityItems(this.lookup)
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
this.listingItems = response; response.forEach(item => {
if (item.dmp){
if (item.dmp.descriptions) {
if (item.dmp.status == DmpStatus.Finalized) {
item.dmp.descriptions = item.dmp.descriptions.filter(x => x.isActive === IsActive.Active && x.status === DescriptionStatus.Finalized);
} else {
item.dmp.descriptions = item.dmp.descriptions.filter(x => x.isActive === IsActive.Active && x.status != DescriptionStatus.Canceled);
}
}
item.dmp.dmpUsers = item.dmp.dmpUsers.filter(x=> x.isActive === IsActive.Active);
this.listingItems.push(item);
}
if (item.description){
if (item.description.status != DescriptionStatus.Canceled) this.listingItems.push(item);
}
})
//this.totalCount = response.totalCount; //this.totalCount = response.totalCount;

View File

@ -2,6 +2,9 @@ import { Location } from '@angular/common';
import { Component, Input, OnInit } from '@angular/core'; import { Component, Input, OnInit } from '@angular/core';
import { UntypedFormBuilder, UntypedFormControl } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormControl } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { DescriptionStatus } from '@app/core/common/enum/description-status';
import { DmpStatus } from '@app/core/common/enum/dmp-status';
import { IsActive } from '@app/core/common/enum/is-active.enum';
import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order'; import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order';
import { RecentActivityItem } from '@app/core/model/dashboard/recent-activity-item'; import { RecentActivityItem } from '@app/core/model/dashboard/recent-activity-item';
import { DescriptionTemplate } from '@app/core/model/description-template/description-template'; import { DescriptionTemplate } from '@app/core/model/description-template/description-template';
@ -30,7 +33,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
lookup: RecentActivityItemLookup = new RecentActivityItemLookup(); lookup: RecentActivityItemLookup = new RecentActivityItemLookup();
pageSize: number = 5; pageSize: number = 5;
listingItems: RecentActivityItem[]; listingItems: RecentActivityItem[]= [];
public formGroup = new UntypedFormBuilder().group({ public formGroup = new UntypedFormBuilder().group({
like: new UntypedFormControl(), like: new UntypedFormControl(),
@ -130,8 +133,11 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.version)].join('.'), [nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.version)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.groupId)].join('.'), [nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.groupId)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.updatedAt)].join('.'), [nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.updatedAt)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.isActive)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.id)].join('.'), [nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.id)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.label)].join('.'), [nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.label)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.status)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.isActive)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.id)].join('.'), [nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.id)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.user.id)].join('.'), [nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.user.id)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.role)].join('.'), [nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.role)].join('.'),
@ -146,6 +152,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
[nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.label)].join('.'), [nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.label)].join('.'),
[nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.status)].join('.'), [nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.status)].join('.'),
[nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.updatedAt)].join('.'), [nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.updatedAt)].join('.'),
[nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.isActive)].join('.'),
[nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.id)].join('.'), [nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.id)].join('.'),
[nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.label)].join('.'), [nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.label)].join('.'),
[nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.groupId)].join('.'), [nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.groupId)].join('.'),
@ -168,7 +175,22 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
.getMyRecentActivityItems(this.lookup) .getMyRecentActivityItems(this.lookup)
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
this.listingItems = response; response.forEach(item => {
if (item.dmp){
if (item.dmp.descriptions) {
if (item.dmp.status == DmpStatus.Finalized) {
item.dmp.descriptions = item.dmp.descriptions.filter(x => x.isActive === IsActive.Active && x.status === DescriptionStatus.Finalized);
} else {
item.dmp.descriptions = item.dmp.descriptions.filter(x => x.isActive === IsActive.Active && x.status != DescriptionStatus.Canceled);
}
}
item.dmp.dmpUsers = item.dmp.dmpUsers.filter(x=> x.isActive === IsActive.Active);
this.listingItems.push(item);
}
if (item.description){
if (item.description.status != DescriptionStatus.Canceled) this.listingItems.push(item);
}
})
//this.totalCount = response.totalCount; //this.totalCount = response.totalCount;

View File

@ -18,6 +18,7 @@ import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { BaseComponent } from '@common/base/base.component'; import { BaseComponent } from '@common/base/base.component';
import { debounceTime, takeUntil } from 'rxjs/operators'; import { debounceTime, takeUntil } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof'; import { nameof } from 'ts-simple-nameof';
import { DescriptionStatus } from '@app/core/common/enum/description-status';
@Component({ @Component({
selector: 'app-recent-edited-description-activity', selector: 'app-recent-edited-description-activity',
@ -28,7 +29,7 @@ export class RecentEditedDescriptionActivityComponent extends BaseComponent impl
lookup: RecentActivityItemLookup = new RecentActivityItemLookup(); lookup: RecentActivityItemLookup = new RecentActivityItemLookup();
pageSize: number = 5; pageSize: number = 5;
listingItems: Description[]; listingItems: Description[] = [];
public formGroup = new UntypedFormBuilder().group({ public formGroup = new UntypedFormBuilder().group({
@ -148,7 +149,11 @@ export class RecentEditedDescriptionActivityComponent extends BaseComponent impl
.getMyRecentActivityItems(this.lookup) .getMyRecentActivityItems(this.lookup)
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
this.listingItems = response.map(x => x.description); response.forEach(item => {
if (item.description){
if (item.description.status != DescriptionStatus.Canceled) this.listingItems.push(item.description);
}
})
// this.totalCount = response.count; // this.totalCount = response.count;

View File

@ -2,6 +2,9 @@ import { Location } from '@angular/common';
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { DescriptionStatus } from '@app/core/common/enum/description-status';
import { DmpStatus } from '@app/core/common/enum/dmp-status';
import { IsActive } from '@app/core/common/enum/is-active.enum';
import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order'; import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order';
import { RecentActivityItem } from '@app/core/model/dashboard/recent-activity-item'; import { RecentActivityItem } from '@app/core/model/dashboard/recent-activity-item';
import { Description } from '@app/core/model/description/description'; import { Description } from '@app/core/model/description/description';
@ -33,13 +36,12 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
@ViewChild("dmps") resultsContainer; @ViewChild("dmps") resultsContainer;
listingItems: Dmp[]; listingItems: Dmp[]= [];
isDraft: boolean; isDraft: boolean;
totalCount: number; totalCount: number;
startIndex: number = 0; startIndex: number = 0;
offsetLess: number = 0; offsetLess: number = 0;
hasMoreResults: boolean = true;
dmpFormGroup: UntypedFormGroup; dmpFormGroup: UntypedFormGroup;
public formGroup = new UntypedFormBuilder().group({ public formGroup = new UntypedFormBuilder().group({
like: new UntypedFormControl(), like: new UntypedFormControl(),
@ -137,6 +139,8 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.updatedAt)].join('.'), [nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.updatedAt)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.id)].join('.'), [nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.id)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.label)].join('.'), [nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.label)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.status)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.isActive)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.id)].join('.'), [nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.id)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.user.id)].join('.'), [nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.user.id)].join('.'),
[nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.role)].join('.'), [nameof<RecentActivityItem>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.role)].join('.'),
@ -153,7 +157,20 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
.getMyRecentActivityItems(this.lookup) .getMyRecentActivityItems(this.lookup)
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
this.listingItems = response.map(x => x.dmp); response.forEach(item => {
if (item.dmp){
item.dmp.dmpUsers = item.dmp.dmpUsers.filter(x => x.isActive === IsActive.Active);
if (item.dmp.descriptions) {
if (item.dmp.status == DmpStatus.Finalized) {
item.dmp.descriptions = item.dmp.descriptions.filter(x => x.isActive === IsActive.Active && x.status === DescriptionStatus.Finalized);
} else {
item.dmp.descriptions = item.dmp.descriptions.filter(x => x.isActive === IsActive.Active && x.status != DescriptionStatus.Canceled);
}
}
this.listingItems.push(item.dmp);
}
})
//this.totalCount = response.totalCount; //this.totalCount = response.totalCount;

View File

@ -78,24 +78,6 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
step: number = 0; 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( constructor(
// BaseFormEditor injected dependencies // BaseFormEditor injected dependencies
protected dialog: MatDialog, protected dialog: MatDialog,
@ -606,7 +588,9 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
} }
buildForm() { 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.visibilityRulesService.buildVisibilityRules(this.visibilityRulesService.getVisibilityRulesFromDescriptionTempalte(this.item.descriptionTemplate), this.formGroup);
// this.selectedSystemFields = this.selectedSystemFieldDisabled(); // this.selectedSystemFields = this.selectedSystemFieldDisabled();

View File

@ -1,5 +1,6 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; 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 { 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 { 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'; 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.description),
nameof<Description>(x => x.status), 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.id)].join('.'),
[nameof<Description>(x => x.dmpDescriptionTemplate), nameof<DmpDescriptionTemplate>(x => x.sectionId)].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.status)].join('.'),
(prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.isActive)].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.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.isActive)].join('.'),
(prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.blueprint), nameof<DmpBlueprint>(x => x.definition)].join('.'), (prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.blueprint), nameof<DmpBlueprint>(x => x.definition)].join('.'),

View File

@ -21,10 +21,11 @@ const routes: Routes = [
data: { data: {
...BreadcrumbService.generateRouteDataConfiguration({ ...BreadcrumbService.generateRouteDataConfiguration({
title: 'BREADCRUMBS.EDIT-DESCRIPTION' title: 'BREADCRUMBS.EDIT-DESCRIPTION'
}), })
authContext: { // ,
permissions: [AppPermission.EditDescription] // authContext: {
} // permissions: [AppPermission.EditDescription]
// }
} }
}, },
{ {
@ -55,10 +56,11 @@ const routes: Routes = [
data: { data: {
...BreadcrumbService.generateRouteDataConfiguration({ ...BreadcrumbService.generateRouteDataConfiguration({
title: 'BREADCRUMBS.EDIT-DESCRIPTION' title: 'BREADCRUMBS.EDIT-DESCRIPTION'
}), })
authContext: { // ,
permissions: [AppPermission.EditDescription] // authContext: {
} // permissions: [AppPermission.EditDescription]
// }
} }
}, },
{ {
@ -72,10 +74,11 @@ const routes: Routes = [
data: { data: {
...BreadcrumbService.generateRouteDataConfiguration({ ...BreadcrumbService.generateRouteDataConfiguration({
title: 'BREADCRUMBS.EDIT-DESCRIPTION' title: 'BREADCRUMBS.EDIT-DESCRIPTION'
}), })
authContext: { // ,
permissions: [AppPermission.EditDescription] // authContext: {
} // permissions: [AppPermission.EditDescription]
// }
} }
}, },

View File

@ -8,6 +8,7 @@ import { MatSort } from '@angular/material/sort';
import { ActivatedRoute, Params, Router } from '@angular/router'; import { ActivatedRoute, Params, Router } from '@angular/router';
import { DescriptionStatus } from '@app/core/common/enum/description-status'; import { DescriptionStatus } from '@app/core/common/enum/description-status';
import { IsActive } from '@app/core/common/enum/is-active.enum'; 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 { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order';
import { DescriptionTemplate } from '@app/core/model/description-template/description-template'; import { DescriptionTemplate } from '@app/core/model/description-template/description-template';
import { Description } from '@app/core/model/description/description'; 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.label),
nameof<Description>(x => x.status), nameof<Description>(x => x.status),
nameof<Description>(x => x.updatedAt), 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.id)].join('.'),
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.label)].join('.'), [nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.label)].join('.'),
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.groupId)].join('.'), [nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.groupId)].join('.'),
@ -239,7 +245,7 @@ export class DescriptionListingComponent extends BaseComponent implements OnInit
this.hasListingItems = true; this.hasListingItems = true;
}); });
} }
} }
openFiltersDialog(): void { openFiltersDialog(): void {

View File

@ -8,8 +8,8 @@
<div *ngIf="description.status === descriptionStatusEnum.Finalized" class="col-auto description-title">{{description.label}}</div> <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 *ngIf="description.status === descriptionStatusEnum.Draft" class="col-auto description-title-draft">{{description.label}}</div>
<div class="description-subtitle"> <div class="description-subtitle">
<span *ngIf="isUserDescriptionRelated()" class="col-auto">{{ enumUtils.toDmpUserRolesString(dmpService.getCurrentUserRolesInDmp(description?.dmp?.dmpUsers)) }}</span> <span *ngIf="canEdit" class="col-auto">{{ enumUtils.toDmpUserRolesString(dmpService.getCurrentUserRolesInDmp(description?.dmp?.dmpUsers)) }}</span>
<span *ngIf="isUserDescriptionRelated()">.</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 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.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> <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="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="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()" (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> </div>
<mat-menu #actionsMenu="matMenu"> <mat-menu #actionsMenu="matMenu">
<button *ngIf="isAuthenticated()" mat-menu-item (click)="copyToDmp(description)" class="menu-item"> <button *ngIf="isAuthenticated()" mat-menu-item (click)="copyToDmp(description)" class="menu-item">
<mat-icon>file_copy</mat-icon>{{'DESCRIPTION-LISTING.ACTIONS.COPY-DESCRIPTION' | translate}} <mat-icon>file_copy</mat-icon>{{'DESCRIPTION-LISTING.ACTIONS.COPY-DESCRIPTION' | translate}}
</button> </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 }} <mat-icon>delete</mat-icon>{{ 'DESCRIPTION-LISTING.ACTIONS.DELETE' | translate }}
</button> </button>
</mat-menu> </mat-menu>

View File

@ -26,6 +26,7 @@ import * as FileSaver from 'file-saver';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { DescriptionStatus } from '../../../../core/common/enum/description-status'; import { DescriptionStatus } from '../../../../core/common/enum/description-status';
import { DescriptionCopyDialogComponent } from '../../description-copy-dialog/description-copy-dialog.component'; import { DescriptionCopyDialogComponent } from '../../description-copy-dialog/description-copy-dialog.component';
import { AppPermission } from '@app/core/common/enum/permission.enum';
@Component({ @Component({
selector: 'app-description-listing-item-component', selector: 'app-description-listing-item-component',
@ -44,6 +45,8 @@ export class DescriptionListingItemComponent extends BaseComponent implements On
isUserOwner: boolean; isUserOwner: boolean;
descriptionStatusEnum = DescriptionStatus; descriptionStatusEnum = DescriptionStatus;
dmpAccessTypeEnum = DmpAccessType; dmpAccessTypeEnum = DmpAccessType;
canDelete: boolean = false;
canEdit: boolean = false;
constructor( constructor(
@ -80,6 +83,13 @@ export class DescriptionListingItemComponent extends BaseComponent implements On
this.isDeleted = false; this.isDeleted = false;
this.setIsUserOwner(); 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() { setIsUserOwner() {
@ -240,11 +250,4 @@ export class DescriptionListingItemComponent extends BaseComponent implements On
onDeleteCallbackError(error) { onDeleteCallbackError(error) {
this.uiNotificationService.snackBarNotification(error.error.message ? error.error.message : this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-DELETE'), SnackBarNotificationLevel.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));
}
} }

View File

@ -12,12 +12,12 @@
<p class="col description-label p-0 ml-3 mb-0">{{ description.label }}</p> <p class="col description-label p-0 ml-3 mb-0">{{ description.label }}</p>
</div> </div>
<div class="row d-flex align-items-center mt-3 mb-4 label-txt"> <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"> <p class="ml-0 mb-0 label2-txt">
{{ enumUtils.toDmpUserRolesString(dmpService.getCurrentUserRolesInDmp(description?.dmp?.dmpUsers)) }} {{ enumUtils.toDmpUserRolesString(dmpService.getCurrentUserRolesInDmp(description?.dmp?.dmpUsers)) }}
</p> </p>
</div> </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"> <div *ngIf="description.status === descriptionStatusEnum.Finalized && description.dmp.accessType === dmpAccessTypeEnum.Public" class="d-flex flex-row">
<mat-icon class="status-icon">public</mat-icon> <mat-icon class="status-icon">public</mat-icon>
{{'DESCRIPTION-OVERVIEW.PUBLIC' | translate}} {{'DESCRIPTION-OVERVIEW.PUBLIC' | translate}}
@ -39,13 +39,13 @@
</div> </div>
</div> </div>
<div class="row mb-4 pb-3"> <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> <mat-icon class="mat-mini-fab-icon">create</mat-icon>
</button> </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> <mat-icon class="mat-mini-fab-icon">content_copy</mat-icon>
</button> </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> <mat-icon class="mat-mini-fab-icon">delete</mat-icon>
</button> </button>
</div> </div>
@ -92,7 +92,7 @@
</div> </div>
<div class="col-md-4 col-lg-4 p-0"> <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 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)"> <div class="row ml-0 mr-0 pl-4 d-flex align-items-center" (click)="finalize(description)">
<button mat-mini-fab class="finalize-btn"> <button mat-mini-fab class="finalize-btn">
<mat-icon class="mat-mini-fab-icon check-icon">check</mat-icon> <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> <p class="authors-role">{{ enumUtils.toDmpUserRoleString(dmpUser.role) }}</p>
</div> </div>
</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> </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)"> <button mat-raised-button class="invite-btn" (click)="openShareDialog(description.dmp.id, description.dmp.label)">
<mat-icon>group_add</mat-icon> <mat-icon>group_add</mat-icon>
{{'DESCRIPTION-OVERVIEW.ACTIONS.INVITE-SHORT' | translate}} {{'DESCRIPTION-OVERVIEW.ACTIONS.INVITE-SHORT' | translate}}

View File

@ -33,6 +33,7 @@ import { filter, takeUntil } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof'; import { nameof } from 'ts-simple-nameof';
import { DescriptionCopyDialogComponent } from '../description-copy-dialog/description-copy-dialog.component'; import { DescriptionCopyDialogComponent } from '../description-copy-dialog/description-copy-dialog.component';
import { ReferenceType } from '@app/core/model/reference-type/reference-type'; import { ReferenceType } from '@app/core/model/reference-type/reference-type';
import { AppPermission } from '@app/core/common/enum/permission.enum';
@Component({ @Component({
@ -49,7 +50,6 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
isPublicView = true; isPublicView = true;
hasPublishButton: boolean = true; hasPublishButton: boolean = true;
// breadCrumbs: Observable<BreadcrumbItem[]> = observableOf(); // breadCrumbs: Observable<BreadcrumbItem[]> = observableOf();
isUserOwner: boolean;
expand = false; expand = false;
lockStatus: Boolean; lockStatus: Boolean;
descriptionStatusEnum = DescriptionStatus; descriptionStatusEnum = DescriptionStatus;
@ -57,6 +57,11 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
dmpStatusEnum = DmpStatus; dmpStatusEnum = DmpStatus;
dmpUserRoleEnum = DmpUserRole; dmpUserRoleEnum = DmpUserRole;
canEdit = false;
canDelete = false;
canFinalize = false;
canInviteDmpUsers = false;
constructor( constructor(
private route: ActivatedRoute, private route: ActivatedRoute,
private router: Router, private router: Router,
@ -72,6 +77,7 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
public enumUtils: EnumUtils, public enumUtils: EnumUtils,
private matomoService: MatomoService, private matomoService: MatomoService,
private fileUtils: FileUtils, private fileUtils: FileUtils,
private authService: AuthService,
public fileTransformerService: FileTransformerService, public fileTransformerService: FileTransformerService,
private referenceTypeService: ReferenceTypeService, private referenceTypeService: ReferenceTypeService,
private fb: UntypedFormBuilder, private fb: UntypedFormBuilder,
@ -81,6 +87,10 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
ngOnInit() { ngOnInit() {
this.matomoService.trackPageView('Description Overview'); this.matomoService.trackPageView('Description Overview');
this.canDelete = false;
this.canEdit = false;
this.canFinalize = false;
this.canInviteDmpUsers = false;
// Gets description data using parameter id // Gets description data using parameter id
this.route.params this.route.params
.pipe(takeUntil(this._destroyed)) .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.researchers = this.referenceService.getReferencesForTypes(this.description?.dmp?.dmpReferences, [this.referenceTypeService.getResearcherReferenceType()]);
// this.users = this.description.dmp.users; // this.users = this.description.dmp.users;
this.checkLockStatus(this.description.id); 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 = []; // const breadCrumbs = [];
// breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.MY-DESCRIPTION-DESCRIPTIONS'), url: "/descriptions" }); // 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 }); // breadCrumbs.push({ parentComponentName: 'DescriptionListingComponent', label: this.description.label, url: '/descriptions/overview/' + this.description.id });
// this.breadCrumbs = observableOf(breadCrumbs); // this.breadCrumbs = observableOf(breadCrumbs);
}, (error: any) => { }, (error: any) => {
if (error.status === 404) { if (error.status === 404) {
return this.onFetchingDeletedCallbackError('/descriptions/'); 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])); 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 { isUserAuthor(userId: Guid): boolean {
if (this.isAuthenticated()) { if (this.isAuthenticated()) {
@ -186,11 +201,6 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
} else return false; } 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) { openShareDialog(rowId: any, rowName: any) {
// TODO: add dialog // TODO: add dialog
@ -439,6 +449,11 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
nameof<Description>(x => x.status), nameof<Description>(x => x.status),
nameof<Description>(x => x.updatedAt), nameof<Description>(x => x.updatedAt),
nameof<Description>(x => x.hash), 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.id)].join('.'),
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.label)].join('.'), [nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.label)].join('.'),
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.groupId)].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.label)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.accessType)].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.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.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.id)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.user.name)].join('.'), [nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.user.name)].join('.'),

View File

@ -82,20 +82,20 @@ export class DmpEditorComponent extends BaseEditor<DmpEditorModel, Dmp> implemen
}; };
protected get canDelete(): boolean { 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 { 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 { 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 { 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( constructor(

View File

@ -41,6 +41,7 @@ export class DmpEditorResolver extends BaseEditorResolver {
nameof<Dmp>(x => x.hash), nameof<Dmp>(x => x.hash),
[nameof<Dmp>(x => x.authorizationFlags), AppPermission.EditDmp].join('.'), [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.fieldId)].join('.'),
[nameof<Dmp>(x => x.properties), nameof<DmpProperties>(x => x.dmpBlueprintValues), nameof<DmpBlueprintValue>(x => x.fieldValue)].join('.'), [nameof<Dmp>(x => x.properties), nameof<DmpProperties>(x => x.dmpBlueprintValues), nameof<DmpBlueprintValue>(x => x.fieldValue)].join('.'),