status authz changes
This commit is contained in:
parent
fcacf93024
commit
6ebe3228ae
|
@ -7,12 +7,16 @@ public class DescriptionStatusTouchedEvent {
|
|||
public DescriptionStatusTouchedEvent() {
|
||||
}
|
||||
|
||||
public DescriptionStatusTouchedEvent(UUID id) {
|
||||
public DescriptionStatusTouchedEvent(UUID id, String tenantCode) {
|
||||
this.id = id;
|
||||
this.tenantCode = tenantCode;
|
||||
}
|
||||
|
||||
private UUID id;
|
||||
|
||||
private String tenantCode;
|
||||
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
@ -21,4 +25,11 @@ public class DescriptionStatusTouchedEvent {
|
|||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTenantCode() {
|
||||
return tenantCode;
|
||||
}
|
||||
|
||||
public void setTenantCode(String tenantCode) {
|
||||
this.tenantCode = tenantCode;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,12 +7,15 @@ public class PlanStatusTouchedEvent {
|
|||
public PlanStatusTouchedEvent() {
|
||||
}
|
||||
|
||||
public PlanStatusTouchedEvent(UUID id) {
|
||||
public PlanStatusTouchedEvent(UUID id, String tenantCode) {
|
||||
this.id = id;
|
||||
this.tenantCode = tenantCode;
|
||||
}
|
||||
|
||||
private UUID id;
|
||||
|
||||
private String tenantCode;
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
@ -21,4 +24,11 @@ public class PlanStatusTouchedEvent {
|
|||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTenantCode() {
|
||||
return tenantCode;
|
||||
}
|
||||
|
||||
public void setTenantCode(String tenantCode) {
|
||||
this.tenantCode = tenantCode;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,11 +13,13 @@ import org.opencdmp.authorization.AuthorizationFlags;
|
|||
import org.opencdmp.authorization.authorizationcontentresolver.AuthorizationContentResolver;
|
||||
import org.opencdmp.commons.JsonHandlingService;
|
||||
import org.opencdmp.commons.XmlHandlingService;
|
||||
import org.opencdmp.commons.enums.IsActive;
|
||||
import org.opencdmp.commons.scope.tenant.TenantScope;
|
||||
import org.opencdmp.commons.types.description.PropertyDefinitionEntity;
|
||||
import org.opencdmp.commons.types.descriptiontemplate.DefinitionEntity;
|
||||
import org.opencdmp.convention.ConventionService;
|
||||
import org.opencdmp.data.DescriptionEntity;
|
||||
import org.opencdmp.data.DescriptionStatusEntity;
|
||||
import org.opencdmp.data.DescriptionTemplateEntity;
|
||||
import org.opencdmp.model.DescriptionTag;
|
||||
import org.opencdmp.model.PlanDescriptionTemplate;
|
||||
|
@ -34,8 +36,10 @@ import org.opencdmp.model.descriptionreference.DescriptionReference;
|
|||
import org.opencdmp.model.descriptionstatus.DescriptionStatus;
|
||||
import org.opencdmp.model.descriptiontemplate.DescriptionTemplate;
|
||||
import org.opencdmp.model.plan.Plan;
|
||||
import org.opencdmp.model.planstatus.PlanStatusDefinitionAuthorization;
|
||||
import org.opencdmp.model.user.User;
|
||||
import org.opencdmp.query.*;
|
||||
import org.opencdmp.service.custompolicy.CustomPolicyService;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
|
@ -57,6 +61,7 @@ public class DescriptionBuilder extends BaseBuilder<Description, DescriptionEnti
|
|||
private final AuthorizationService authorizationService;
|
||||
private final AuthorizationContentResolver authorizationContentResolver;
|
||||
private final TenantScope tenantScope;
|
||||
private final CustomPolicyService customPolicyService;
|
||||
|
||||
private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None);
|
||||
|
||||
|
@ -64,7 +69,7 @@ public class DescriptionBuilder extends BaseBuilder<Description, DescriptionEnti
|
|||
public DescriptionBuilder(
|
||||
ConventionService conventionService,
|
||||
QueryFactory queryFactory,
|
||||
BuilderFactory builderFactory, JsonHandlingService jsonHandlingService, XmlHandlingService xmlHandlingService, AuthorizationService authorizationService, AuthorizationContentResolver authorizationContentResolver, TenantScope tenantScope) {
|
||||
BuilderFactory builderFactory, JsonHandlingService jsonHandlingService, XmlHandlingService xmlHandlingService, AuthorizationService authorizationService, AuthorizationContentResolver authorizationContentResolver, TenantScope tenantScope, CustomPolicyService customPolicyService) {
|
||||
super(conventionService, new LoggerService(LoggerFactory.getLogger(DescriptionBuilder.class)));
|
||||
this.queryFactory = queryFactory;
|
||||
this.builderFactory = builderFactory;
|
||||
|
@ -73,6 +78,7 @@ public class DescriptionBuilder extends BaseBuilder<Description, DescriptionEnti
|
|||
this.authorizationService = authorizationService;
|
||||
this.authorizationContentResolver = authorizationContentResolver;
|
||||
this.tenantScope = tenantScope;
|
||||
this.customPolicyService = customPolicyService;
|
||||
}
|
||||
|
||||
public DescriptionBuilder authorize(EnumSet<AuthorizationFlags> values) {
|
||||
|
@ -90,6 +96,9 @@ public class DescriptionBuilder extends BaseBuilder<Description, DescriptionEnti
|
|||
FieldSet statusFields = fields.extractPrefixed(this.asPrefix(Description._status));
|
||||
Map<UUID, DescriptionStatus> statusItemsMap = this.collectDescriptionStatuses(statusFields, data);
|
||||
|
||||
FieldSet availableStatusesFields = fields.extractPrefixed(this.asPrefix(Description._availableStatuses));
|
||||
Map<UUID, List<DescriptionStatus>> avaialbleStatusesItemsMap = this.collectAvailableDescriptionStatuses(availableStatusesFields, data);
|
||||
|
||||
FieldSet planDescriptionTemplateFields = fields.extractPrefixed(this.asPrefix(Description._planDescriptionTemplate));
|
||||
Map<UUID, PlanDescriptionTemplate> planDescriptionTemplateItemsMap = this.collectPlanDescriptionTemplates(planDescriptionTemplateFields, data);
|
||||
|
||||
|
@ -115,6 +124,7 @@ public class DescriptionBuilder extends BaseBuilder<Description, DescriptionEnti
|
|||
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()));
|
||||
|
||||
FieldSet statusAuthorizationFlags = fields.extractPrefixed(this.asPrefix(Description._statusAuthorizationFlags));
|
||||
List<Description> models = new ArrayList<>();
|
||||
for (DescriptionEntity d : data) {
|
||||
Description m = new Description();
|
||||
|
@ -122,6 +132,7 @@ public class DescriptionBuilder extends BaseBuilder<Description, DescriptionEnti
|
|||
if (fields.hasField(this.asIndexer(Description._tenantId))) m.setTenantId(d.getTenantId());
|
||||
if (fields.hasField(this.asIndexer(Description._label))) m.setLabel(d.getLabel());
|
||||
if (!statusFields.isEmpty() && statusItemsMap != null && statusItemsMap.containsKey(d.getStatusId())) m.setStatus(statusItemsMap.get(d.getStatusId()));
|
||||
if (avaialbleStatusesItemsMap != null && !avaialbleStatusesItemsMap.isEmpty() && avaialbleStatusesItemsMap.containsKey(d.getId())) m.setAvailableStatuses(avaialbleStatusesItemsMap.get(d.getId()));
|
||||
if (fields.hasField(this.asIndexer(Description._description))) m.setDescription(d.getDescription());
|
||||
if (fields.hasField(this.asIndexer(Description._createdAt))) m.setCreatedAt(d.getCreatedAt());
|
||||
if (fields.hasField(this.asIndexer(Description._updatedAt))) m.setUpdatedAt(d.getUpdatedAt());
|
||||
|
@ -140,6 +151,9 @@ public class DescriptionBuilder extends BaseBuilder<Description, DescriptionEnti
|
|||
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)));
|
||||
if (!statusAuthorizationFlags.isEmpty() && !this.conventionService.isListNullOrEmpty(m.getAvailableStatuses())) {
|
||||
m.setStatusAuthorizationFlags(this.evaluateStatusAuthorizationFlags(this.authorizationService, statusAuthorizationFlags, d));
|
||||
}
|
||||
models.add(m);
|
||||
}
|
||||
|
||||
|
@ -178,6 +192,20 @@ public class DescriptionBuilder extends BaseBuilder<Description, DescriptionEnti
|
|||
return itemMap;
|
||||
}
|
||||
|
||||
private Map<UUID, List<DescriptionStatus>> collectAvailableDescriptionStatuses(FieldSet fields, List<DescriptionEntity> data) throws MyApplicationException {
|
||||
if (fields.isEmpty() || data.isEmpty()) return null;
|
||||
this.logger.debug("checking related - {}", DescriptionStatus.class.getSimpleName());
|
||||
|
||||
Map<UUID, List<DescriptionStatus>> itemMap = new HashMap<>();
|
||||
FieldSet fieldSet = new BaseFieldSet(fields.getFields()).ensure(DescriptionStatus._id);
|
||||
for (DescriptionEntity entity: data) {
|
||||
List<DescriptionStatusEntity> statusEntities = this.queryFactory.query(DescriptionStatusQuery.class).authorize(AuthorizationFlags.AllExceptPublic).isActive(IsActive.Active).authorizedStatus(true, entity.getId()).collectAs(fieldSet);
|
||||
itemMap.put(entity.getId(), this.builderFactory.builder(DescriptionStatusBuilder.class).authorize(AuthorizationFlags.AllExceptPublic).build(fieldSet, statusEntities));
|
||||
}
|
||||
|
||||
return itemMap;
|
||||
}
|
||||
|
||||
private Map<UUID, User> collectUsers(FieldSet fields, List<DescriptionEntity> data) throws MyApplicationException {
|
||||
if (fields.isEmpty() || data.isEmpty())
|
||||
return null;
|
||||
|
@ -350,4 +378,24 @@ public class DescriptionBuilder extends BaseBuilder<Description, DescriptionEnti
|
|||
return itemMap;
|
||||
}
|
||||
|
||||
private List<String> evaluateStatusAuthorizationFlags(AuthorizationService authorizationService, FieldSet statusAuthorizationFlags, DescriptionEntity description) {
|
||||
List<String> allowed = new ArrayList<>();
|
||||
if (statusAuthorizationFlags == null) return allowed;
|
||||
if (authorizationService == null) return allowed;
|
||||
if (description == null) return allowed;
|
||||
|
||||
String editPermission = this.customPolicyService.getDescriptionStatusCanEditStatusPermission(description.getStatusId());
|
||||
for (String permission : statusAuthorizationFlags.getFields()) {
|
||||
if (statusAuthorizationFlags.hasField(this.asIndexer(PlanStatusDefinitionAuthorization._edit))) {
|
||||
Boolean isAllowed = authorizationService.authorize(editPermission);
|
||||
if (!isAllowed) {
|
||||
isAllowed = this.authorizationService.authorizeAtLeastOne(List.of(this.authorizationContentResolver.planAffiliation(description.getPlanId())), editPermission);
|
||||
}
|
||||
if (isAllowed) allowed.add(permission);
|
||||
}
|
||||
}
|
||||
|
||||
return allowed;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,12 +14,14 @@ import org.opencdmp.authorization.authorizationcontentresolver.AuthorizationCont
|
|||
import org.opencdmp.commons.JsonHandlingService;
|
||||
import org.opencdmp.commons.XmlHandlingService;
|
||||
import org.opencdmp.commons.enums.EntityType;
|
||||
import org.opencdmp.commons.enums.IsActive;
|
||||
import org.opencdmp.commons.scope.tenant.TenantScope;
|
||||
import org.opencdmp.commons.types.plan.PlanPropertiesEntity;
|
||||
import org.opencdmp.commons.types.planblueprint.DefinitionEntity;
|
||||
import org.opencdmp.convention.ConventionService;
|
||||
import org.opencdmp.data.PlanBlueprintEntity;
|
||||
import org.opencdmp.data.PlanEntity;
|
||||
import org.opencdmp.data.PlanStatusEntity;
|
||||
import org.opencdmp.model.PlanDescriptionTemplate;
|
||||
import org.opencdmp.model.PlanUser;
|
||||
import org.opencdmp.model.EntityDoi;
|
||||
|
@ -33,8 +35,10 @@ import org.opencdmp.model.plan.Plan;
|
|||
import org.opencdmp.model.planblueprint.PlanBlueprint;
|
||||
import org.opencdmp.model.planreference.PlanReference;
|
||||
import org.opencdmp.model.planstatus.PlanStatus;
|
||||
import org.opencdmp.model.planstatus.PlanStatusDefinitionAuthorization;
|
||||
import org.opencdmp.model.user.User;
|
||||
import org.opencdmp.query.*;
|
||||
import org.opencdmp.service.custompolicy.CustomPolicyService;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
|
@ -56,13 +60,14 @@ public class PlanBuilder extends BaseBuilder<Plan, PlanEntity> {
|
|||
private final AuthorizationService authorizationService;
|
||||
private final AuthorizationContentResolver authorizationContentResolver;
|
||||
private final TenantScope tenantScope;
|
||||
private final CustomPolicyService customPolicyService;
|
||||
|
||||
private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None);
|
||||
|
||||
@Autowired
|
||||
public PlanBuilder(ConventionService conventionService,
|
||||
QueryFactory queryFactory,
|
||||
BuilderFactory builderFactory, JsonHandlingService jsonHandlingService, XmlHandlingService xmlHandlingService, AuthorizationService authorizationService, AuthorizationContentResolver authorizationContentResolver, TenantScope tenantScope) {
|
||||
BuilderFactory builderFactory, JsonHandlingService jsonHandlingService, XmlHandlingService xmlHandlingService, AuthorizationService authorizationService, AuthorizationContentResolver authorizationContentResolver, TenantScope tenantScope, CustomPolicyService customPolicyService) {
|
||||
super(conventionService, new LoggerService(LoggerFactory.getLogger(PlanBuilder.class)));
|
||||
this.queryFactory = queryFactory;
|
||||
this.builderFactory = builderFactory;
|
||||
|
@ -71,6 +76,7 @@ public class PlanBuilder extends BaseBuilder<Plan, PlanEntity> {
|
|||
this.authorizationService = authorizationService;
|
||||
this.authorizationContentResolver = authorizationContentResolver;
|
||||
this.tenantScope = tenantScope;
|
||||
this.customPolicyService = customPolicyService;
|
||||
}
|
||||
|
||||
public PlanBuilder authorize(EnumSet<AuthorizationFlags> values) {
|
||||
|
@ -90,6 +96,9 @@ public class PlanBuilder extends BaseBuilder<Plan, PlanEntity> {
|
|||
FieldSet statusFields = fields.extractPrefixed(this.asPrefix(Plan._status));
|
||||
Map<UUID, PlanStatus> statusItemsMap = this.collectPlanStatuses(statusFields, data);
|
||||
|
||||
FieldSet availableStatusesFields = fields.extractPrefixed(this.asPrefix(Plan._availableStatuses));
|
||||
Map<UUID, List<PlanStatus>> avaialbleStatusesItemsMap = this.collectAvailablePlanStatuses(availableStatusesFields, data);
|
||||
|
||||
FieldSet entityDoisFields = fields.extractPrefixed(this.asPrefix(Plan._entityDois));
|
||||
Map<UUID, List<EntityDoi>> entityDoisMap = this.collectEntityDois(entityDoisFields, data);
|
||||
|
||||
|
@ -120,6 +129,7 @@ public class PlanBuilder extends BaseBuilder<Plan, PlanEntity> {
|
|||
Set<String> authorizationFlags = this.extractAuthorizationFlags(fields, Plan._authorizationFlags, this.authorizationContentResolver.getPermissionNames());
|
||||
Map<UUID, AffiliatedResource> affiliatedResourceMap = authorizationFlags == null || authorizationFlags.isEmpty() ? null : this.authorizationContentResolver.plansAffiliation(data.stream().map(PlanEntity::getId).collect(Collectors.toList()));
|
||||
|
||||
FieldSet statusAuthorizationFlags = fields.extractPrefixed(this.asPrefix(Plan._statusAuthorizationFlags));
|
||||
for (PlanEntity d : data) {
|
||||
Plan m = new Plan();
|
||||
if (fields.hasField(this.asIndexer(Plan._id))) m.setId(d.getId());
|
||||
|
@ -127,6 +137,7 @@ public class PlanBuilder extends BaseBuilder<Plan, PlanEntity> {
|
|||
if (fields.hasField(this.asIndexer(Plan._label))) m.setLabel(d.getLabel());
|
||||
if (fields.hasField(this.asIndexer(Plan._version))) m.setVersion(d.getVersion());
|
||||
if (!statusFields.isEmpty() && statusItemsMap != null && statusItemsMap.containsKey(d.getStatusId())) m.setStatus(statusItemsMap.get(d.getStatusId()));
|
||||
if (avaialbleStatusesItemsMap != null && !avaialbleStatusesItemsMap.isEmpty() && avaialbleStatusesItemsMap.containsKey(d.getId())) m.setAvailableStatuses(avaialbleStatusesItemsMap.get(d.getId()));
|
||||
if (fields.hasField(this.asIndexer(Plan._groupId))) m.setGroupId(d.getGroupId());
|
||||
if (fields.hasField(this.asIndexer(Plan._description))) m.setDescription(d.getDescription());
|
||||
if (fields.hasField(this.asIndexer(Plan._createdAt))) m.setCreatedAt(d.getCreatedAt());
|
||||
|
@ -155,6 +166,9 @@ public class PlanBuilder extends BaseBuilder<Plan, PlanEntity> {
|
|||
m.setProperties(this.builderFactory.builder(PlanPropertiesBuilder.class).withDefinition(definitionEntityMap != null ? definitionEntityMap.getOrDefault(d.getBlueprintId(), null) : null).authorize(this.authorize).build(planPropertiesFields, propertyDefinition));
|
||||
}
|
||||
if (affiliatedResourceMap != null && !authorizationFlags.isEmpty()) m.setAuthorizationFlags(this.evaluateAuthorizationFlags(this.authorizationService, authorizationFlags, affiliatedResourceMap.getOrDefault(d.getId(), null)));
|
||||
if (!statusAuthorizationFlags.isEmpty() && !this.conventionService.isListNullOrEmpty(m.getAvailableStatuses())) {
|
||||
m.setStatusAuthorizationFlags(this.evaluateStatusAuthorizationFlags(this.authorizationService, statusAuthorizationFlags, d));
|
||||
}
|
||||
models.add(m);
|
||||
}
|
||||
this.logger.debug("build {} items", Optional.of(models).map(List::size).orElse(0));
|
||||
|
@ -192,6 +206,20 @@ public class PlanBuilder extends BaseBuilder<Plan, PlanEntity> {
|
|||
return itemMap;
|
||||
}
|
||||
|
||||
private Map<UUID, List<PlanStatus>> collectAvailablePlanStatuses(FieldSet fields, List<PlanEntity> data) throws MyApplicationException {
|
||||
if (fields.isEmpty() || data.isEmpty()) return null;
|
||||
this.logger.debug("checking related - {}", PlanStatus.class.getSimpleName());
|
||||
|
||||
Map<UUID, List<PlanStatus>> itemMap = new HashMap<>();
|
||||
FieldSet fieldSet = new BaseFieldSet(fields.getFields()).ensure(PlanStatus._id);
|
||||
for (PlanEntity entity: data) {
|
||||
List<PlanStatusEntity> statusEntities = this.queryFactory.query(PlanStatusQuery.class).authorize(AuthorizationFlags.AllExceptPublic).isActives(IsActive.Active).authorizedStatus(true, entity.getId()).collectAs(fieldSet);
|
||||
itemMap.put(entity.getId(), this.builderFactory.builder(PlanStatusBuilder.class).authorize(AuthorizationFlags.AllExceptPublic).build(fieldSet, statusEntities));
|
||||
}
|
||||
|
||||
return itemMap;
|
||||
}
|
||||
|
||||
private Map<UUID, List<PlanReference>> collectPlanReferences(FieldSet fields, List<PlanEntity> data) throws MyApplicationException {
|
||||
if (fields.isEmpty() || data.isEmpty()) return null;
|
||||
this.logger.debug("checking related - {}", PlanReference.class.getSimpleName());
|
||||
|
@ -377,4 +405,24 @@ public class PlanBuilder extends BaseBuilder<Plan, PlanEntity> {
|
|||
return itemMap;
|
||||
}
|
||||
|
||||
private List<String> evaluateStatusAuthorizationFlags(AuthorizationService authorizationService, FieldSet statusAuthorizationFlags, PlanEntity plan) {
|
||||
List<String> allowed = new ArrayList<>();
|
||||
if (statusAuthorizationFlags == null) return allowed;
|
||||
if (authorizationService == null) return allowed;
|
||||
if (plan == null) return allowed;
|
||||
|
||||
String editPermission = this.customPolicyService.getPlanStatusCanEditStatusPermission(plan.getStatusId());
|
||||
for (String permission : statusAuthorizationFlags.getFields()) {
|
||||
if (statusAuthorizationFlags.hasField(this.asIndexer(PlanStatusDefinitionAuthorization._edit))) {
|
||||
Boolean isAllowed = authorizationService.authorize(editPermission);
|
||||
if (!isAllowed) {
|
||||
isAllowed = this.authorizationService.authorizeAtLeastOne(List.of(this.authorizationContentResolver.planAffiliation(plan.getId())), editPermission);
|
||||
}
|
||||
if (isAllowed) allowed.add(permission);
|
||||
}
|
||||
}
|
||||
|
||||
return allowed;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -86,6 +86,12 @@ public class Description {
|
|||
|
||||
public static final String _plan = "plan";
|
||||
|
||||
private List<DescriptionStatus> availableStatuses;
|
||||
public static final String _availableStatuses = "availableStatuses";
|
||||
|
||||
private List<String> statusAuthorizationFlags;
|
||||
public static final String _statusAuthorizationFlags = "statusAuthorizationFlags";
|
||||
|
||||
private Boolean belongsToCurrentTenant;
|
||||
public static final String _belongsToCurrentTenant = "belongsToCurrentTenant";
|
||||
|
||||
|
@ -231,6 +237,22 @@ public class Description {
|
|||
this.authorizationFlags = authorizationFlags;
|
||||
}
|
||||
|
||||
public List<DescriptionStatus> getAvailableStatuses() {
|
||||
return availableStatuses;
|
||||
}
|
||||
|
||||
public void setAvailableStatuses(List<DescriptionStatus> availableStatuses) {
|
||||
this.availableStatuses = availableStatuses;
|
||||
}
|
||||
|
||||
public List<String> getStatusAuthorizationFlags() {
|
||||
return statusAuthorizationFlags;
|
||||
}
|
||||
|
||||
public void setStatusAuthorizationFlags(List<String> statusAuthorizationFlags) {
|
||||
this.statusAuthorizationFlags = statusAuthorizationFlags;
|
||||
}
|
||||
|
||||
public Boolean getBelongsToCurrentTenant() {
|
||||
return belongsToCurrentTenant;
|
||||
}
|
||||
|
|
|
@ -97,8 +97,11 @@ public class Plan {
|
|||
private List<Plan> otherPlanVersions;
|
||||
public static final String _otherPlanVersions = "otherPlanVersions";
|
||||
|
||||
private List<PlanStatus> availableTransitions;
|
||||
public static final String _availableTransitions = "availableTransitions";
|
||||
private List<PlanStatus> availableStatuses;
|
||||
public static final String _availableStatuses = "availableStatuses";
|
||||
|
||||
private List<String> statusAuthorizationFlags;
|
||||
public static final String _statusAuthorizationFlags = "statusAuthorizationFlags";
|
||||
|
||||
private Boolean belongsToCurrentTenant;
|
||||
public static final String _belongsToCurrentTenant = "belongsToCurrentTenant";
|
||||
|
@ -321,11 +324,19 @@ public class Plan {
|
|||
this.otherPlanVersions = otherPlanVersions;
|
||||
}
|
||||
|
||||
public List<PlanStatus> getAvailableTransitions() {
|
||||
return availableTransitions;
|
||||
public List<PlanStatus> getAvailableStatuses() {
|
||||
return availableStatuses;
|
||||
}
|
||||
|
||||
public void setAvailableTransitions(List<PlanStatus> availableTransitions) {
|
||||
this.availableTransitions = availableTransitions;
|
||||
public void setAvailableStatuses(List<PlanStatus> availableStatuses) {
|
||||
this.availableStatuses = availableStatuses;
|
||||
}
|
||||
|
||||
public List<String> getStatusAuthorizationFlags() {
|
||||
return statusAuthorizationFlags;
|
||||
}
|
||||
|
||||
public void setStatusAuthorizationFlags(List<String> statusAuthorizationFlags) {
|
||||
this.statusAuthorizationFlags = statusAuthorizationFlags;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.opencdmp.data.DescriptionStatusEntity;
|
|||
import org.opencdmp.data.TenantEntityManager;
|
||||
import org.opencdmp.model.descriptionstatus.DescriptionStatus;
|
||||
import org.opencdmp.query.utils.QueryUtilsService;
|
||||
import org.opencdmp.service.descriptionstatus.DescriptionStatusService;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
@ -34,8 +35,14 @@ public class DescriptionStatusQuery extends QueryBase<DescriptionStatusEntity> {
|
|||
|
||||
private Collection<UUID> excludeIds;
|
||||
|
||||
private Boolean authorizedStatus;
|
||||
|
||||
private UUID descriptionId;
|
||||
|
||||
private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None);
|
||||
|
||||
private final DescriptionStatusService descriptionStatusService;
|
||||
|
||||
public DescriptionStatusQuery like(String value) {
|
||||
this.like = value;
|
||||
return this;
|
||||
|
@ -111,6 +118,12 @@ public class DescriptionStatusQuery extends QueryBase<DescriptionStatusEntity> {
|
|||
return this;
|
||||
}
|
||||
|
||||
public DescriptionStatusQuery authorizedStatus(Boolean authorizedStatus, UUID descriptionId) {
|
||||
this.authorizedStatus = authorizedStatus;
|
||||
this.descriptionId = descriptionId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DescriptionStatusQuery authorize(EnumSet<AuthorizationFlags> values) {
|
||||
this.authorize = values;
|
||||
return this;
|
||||
|
@ -120,7 +133,8 @@ public class DescriptionStatusQuery extends QueryBase<DescriptionStatusEntity> {
|
|||
private final TenantEntityManager entityManager;
|
||||
|
||||
public DescriptionStatusQuery(
|
||||
QueryUtilsService queryUtilsService, TenantEntityManager entityManager) {
|
||||
DescriptionStatusService descriptionStatusService, QueryUtilsService queryUtilsService, TenantEntityManager entityManager) {
|
||||
this.descriptionStatusService = descriptionStatusService;
|
||||
this.queryUtilsService = queryUtilsService;
|
||||
this.entityManager = entityManager;
|
||||
}
|
||||
|
@ -172,6 +186,15 @@ public class DescriptionStatusQuery extends QueryBase<DescriptionStatusEntity> {
|
|||
}
|
||||
predicates.add(notInClause.not());
|
||||
}
|
||||
if (this.authorizedStatus != null && this.authorizedStatus && this.descriptionId != null) {
|
||||
List<UUID> notAvailableStatusIds = this.descriptionStatusService.getAuthorizedNotAvailableStatusIds(this.descriptionId);
|
||||
if (!notAvailableStatusIds.isEmpty()) {
|
||||
CriteriaBuilder.In<UUID> notInClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(DescriptionStatusEntity._id));
|
||||
for (UUID id : notAvailableStatusIds)
|
||||
notInClause.value(id);
|
||||
predicates.add(notInClause.not());
|
||||
}
|
||||
}
|
||||
if (!predicates.isEmpty()) {
|
||||
Predicate[] predicatesArray = predicates.toArray(new Predicate[0]);
|
||||
return queryContext.CriteriaBuilder.and(predicatesArray);
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.opencdmp.data.PlanStatusEntity;
|
|||
import org.opencdmp.data.TenantEntityManager;
|
||||
import org.opencdmp.model.planstatus.PlanStatus;
|
||||
import org.opencdmp.query.utils.QueryUtilsService;
|
||||
import org.opencdmp.service.planstatus.PlanStatusService;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
@ -34,8 +35,14 @@ public class PlanStatusQuery extends QueryBase<PlanStatusEntity> {
|
|||
|
||||
private Collection<UUID> excludedIds;
|
||||
|
||||
private Boolean authorizedStatus;
|
||||
|
||||
private UUID planId;
|
||||
|
||||
private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None);
|
||||
|
||||
private final PlanStatusService planStatusService;
|
||||
|
||||
public PlanStatusQuery like(String value) {
|
||||
this.like = value;
|
||||
return this;
|
||||
|
@ -116,11 +123,18 @@ public class PlanStatusQuery extends QueryBase<PlanStatusEntity> {
|
|||
return this;
|
||||
}
|
||||
|
||||
public PlanStatusQuery authorizedStatus(Boolean authorizedStatus, UUID planId) {
|
||||
this.authorizedStatus = authorizedStatus;
|
||||
this.planId = planId;
|
||||
return this;
|
||||
}
|
||||
|
||||
private final QueryUtilsService queryUtilsService;
|
||||
private final TenantEntityManager entityManager;
|
||||
|
||||
public PlanStatusQuery(
|
||||
QueryUtilsService queryUtilsService, TenantEntityManager tenantEntityManager) {
|
||||
PlanStatusService planStatusService, QueryUtilsService queryUtilsService, TenantEntityManager tenantEntityManager) {
|
||||
this.planStatusService = planStatusService;
|
||||
this.queryUtilsService = queryUtilsService;
|
||||
this.entityManager = tenantEntityManager;
|
||||
}
|
||||
|
@ -171,6 +185,15 @@ public class PlanStatusQuery extends QueryBase<PlanStatusEntity> {
|
|||
notInClause.value(item);
|
||||
predicates.add(notInClause.not());
|
||||
}
|
||||
if (this.authorizedStatus != null && this.authorizedStatus && this.planId != null) {
|
||||
List<UUID> notAvailableStatusIds = this.planStatusService.getAuthorizedNotAvailableStatusIds(this.planId);
|
||||
if (!notAvailableStatusIds.isEmpty()) {
|
||||
CriteriaBuilder.In<UUID> notInClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(PlanStatusEntity._id));
|
||||
for (UUID id : notAvailableStatusIds)
|
||||
notInClause.value(id);
|
||||
predicates.add(notInClause.not());
|
||||
}
|
||||
}
|
||||
if (!predicates.isEmpty()) {
|
||||
Predicate[] predicatesArray = predicates.toArray(new Predicate[0]);
|
||||
return queryContext.CriteriaBuilder.and(predicatesArray);
|
||||
|
|
|
@ -4,7 +4,10 @@ package org.opencdmp.service.custompolicy;
|
|||
import gr.cite.tools.cache.CacheService;
|
||||
import org.opencdmp.commons.types.descriptionstatus.DescriptionStatusDefinitionEntity;
|
||||
import org.opencdmp.commons.types.planstatus.PlanStatusDefinitionEntity;
|
||||
import org.opencdmp.event.DescriptionStatusTouchedEvent;
|
||||
import org.opencdmp.event.PlanStatusTouchedEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
@ -54,6 +57,16 @@ public class CustomPolicyCacheService extends CacheService<CustomPolicyCacheServ
|
|||
}
|
||||
}
|
||||
|
||||
@EventListener
|
||||
public void handlePlanTouchedEvent(PlanStatusTouchedEvent event) {
|
||||
this.evict(this.buildKey(event.getTenantCode()));
|
||||
}
|
||||
|
||||
@EventListener
|
||||
public void handleDescriptionStatusTouchedEvent(DescriptionStatusTouchedEvent event) {
|
||||
this.evict(this.buildKey(event.getTenantCode()));
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public CustomPolicyCacheService(CustomPolicyCacheOptions options) {
|
||||
super(options);
|
||||
|
|
|
@ -2,7 +2,6 @@ package org.opencdmp.service.custompolicy;
|
|||
|
||||
|
||||
import gr.cite.commons.web.authz.configuration.Permission;
|
||||
import org.opencdmp.commons.enums.PlanUserRole;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
|
@ -17,7 +16,4 @@ public interface CustomPolicyService {
|
|||
|
||||
String getDescriptionStatusCanEditStatusPermission(UUID id);
|
||||
|
||||
String getPlanStatusCanEditStatusAffiliatedPermission(UUID id, PlanUserRole planUserRole);
|
||||
|
||||
String getDescriptionStatusCanEditStatusAffiliatedPermission(UUID id, PlanUserRole planUserRole);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import gr.cite.tools.fieldset.BaseFieldSet;
|
|||
import gr.cite.tools.logging.LoggerService;
|
||||
import org.opencdmp.commons.XmlHandlingService;
|
||||
import org.opencdmp.commons.enums.IsActive;
|
||||
import org.opencdmp.commons.enums.PlanUserRole;
|
||||
import org.opencdmp.commons.scope.tenant.TenantScope;
|
||||
import org.opencdmp.commons.types.descriptionstatus.DescriptionStatusDefinitionEntity;
|
||||
import org.opencdmp.commons.types.planstatus.PlanStatusDefinitionEntity;
|
||||
|
@ -44,7 +43,7 @@ public class CustomPolicyServiceImpl implements CustomPolicyService{
|
|||
HashMap<String, Permission> policies = new HashMap<>();
|
||||
String tenantCode = null;
|
||||
try {
|
||||
tenantCode = this.tenantScope.isSet() && this.tenantScope.isMultitenant() ? this.tenantScope.getTenantCode() : "";
|
||||
tenantCode = this.tenantScope.isSet() && this.tenantScope.isMultitenant() ? this.tenantScope.getTenantCode() : this.tenantScope.getDefaultTenantCode();
|
||||
} catch (InvalidApplicationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
@ -84,7 +83,7 @@ public class CustomPolicyServiceImpl implements CustomPolicyService{
|
|||
HashMap<String, Permission> policies = new HashMap<>();
|
||||
String tenantCode = null;
|
||||
try {
|
||||
tenantCode = this.tenantScope.isSet() && this.tenantScope.isMultitenant() ? this.tenantScope.getTenantCode() : "";
|
||||
tenantCode = this.tenantScope.isSet() && this.tenantScope.isMultitenant() ? this.tenantScope.getTenantCode() : this.tenantScope.getDefaultTenantCode();
|
||||
} catch (InvalidApplicationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
@ -121,21 +120,11 @@ public class CustomPolicyServiceImpl implements CustomPolicyService{
|
|||
|
||||
@Override
|
||||
public String getPlanStatusCanEditStatusPermission(UUID id){
|
||||
return "PlanStatus" + "_" + id + "_" + PlanStatusDefinitionAuthorization._edit;
|
||||
return ("PlanStatus" + "_" + id + "_" + PlanStatusDefinitionAuthorization._edit).toLowerCase();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescriptionStatusCanEditStatusPermission(UUID id){
|
||||
return "DescriptionStatus" + "_" + id + "_" + DescriptionStatusDefinitionAuthorization._edit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlanStatusCanEditStatusAffiliatedPermission(UUID id, PlanUserRole planUserRole){
|
||||
return "PlanStatus" + "_" + id + "_" + planUserRole.name() + "_" + PlanStatusDefinitionAuthorization._edit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescriptionStatusCanEditStatusAffiliatedPermission(UUID id, PlanUserRole planUserRole){
|
||||
return "DescriptionStatus" + "_" + id + "_" + planUserRole.name() + "_" + DescriptionStatusDefinitionAuthorization._edit;
|
||||
return ("DescriptionStatus" + "_" + id + "_" + DescriptionStatusDefinitionAuthorization._edit).toLowerCase();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -508,8 +508,7 @@ public class DescriptionServiceImpl implements DescriptionService {
|
|||
try {
|
||||
this.authorizationService.authorizeForce(this.customPolicyService.getDescriptionStatusCanEditStatusPermission(model.getStatusId()));
|
||||
} catch (Exception e) {
|
||||
PlanUserEntity planUserEntity = this.queryFactory.query(PlanUserQuery.class).planIds(data.getPlanId()).userIds(this.userScope.getUserId()).isActives(IsActive.Active).firstAs(new BaseFieldSet().ensure(PlanUser._role));
|
||||
this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.planAffiliation(data.getPlanId())), this.customPolicyService.getDescriptionStatusCanEditStatusAffiliatedPermission(model.getStatusId(), planUserEntity.getRole()));
|
||||
this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.planAffiliation(data.getPlanId())), this.customPolicyService.getDescriptionStatusCanEditStatusPermission(model.getStatusId()));
|
||||
}
|
||||
|
||||
if (!this.conventionService.hashValue(data.getUpdatedAt()).equals(model.getHash())) throw new MyValidationException(this.errors.getHashConflict().getCode(), this.errors.getHashConflict().getMessage());
|
||||
|
|
|
@ -19,5 +19,5 @@ public interface DescriptionStatusService {
|
|||
|
||||
void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException;
|
||||
|
||||
List<DescriptionStatus> getAvailableTransitionStatuses(UUID descriptionId) throws InvalidApplicationException;
|
||||
List<UUID> getAuthorizedNotAvailableStatusIds(UUID descriptionId);
|
||||
}
|
||||
|
|
|
@ -15,8 +15,10 @@ import gr.cite.tools.logging.MapLogEntry;
|
|||
import jakarta.xml.bind.JAXBException;
|
||||
import org.opencdmp.authorization.AuthorizationFlags;
|
||||
import org.opencdmp.authorization.Permission;
|
||||
import org.opencdmp.authorization.authorizationcontentresolver.AuthorizationContentResolver;
|
||||
import org.opencdmp.commons.XmlHandlingService;
|
||||
import org.opencdmp.commons.enums.IsActive;
|
||||
import org.opencdmp.commons.scope.tenant.TenantScope;
|
||||
import org.opencdmp.commons.types.descriptionstatus.DescriptionStatusDefinitionAuthorizationEntity;
|
||||
import org.opencdmp.commons.types.descriptionstatus.DescriptionStatusDefinitionAuthorizationItemEntity;
|
||||
import org.opencdmp.commons.types.descriptionstatus.DescriptionStatusDefinitionEntity;
|
||||
|
@ -25,19 +27,20 @@ import org.opencdmp.commons.types.descriptionworkflow.DescriptionWorkflowDefinit
|
|||
import org.opencdmp.convention.ConventionService;
|
||||
import org.opencdmp.data.DescriptionEntity;
|
||||
import org.opencdmp.data.DescriptionStatusEntity;
|
||||
import org.opencdmp.data.PlanStatusEntity;
|
||||
import org.opencdmp.data.TenantEntityManager;
|
||||
import org.opencdmp.event.DescriptionStatusTouchedEvent;
|
||||
import org.opencdmp.event.EventBroker;
|
||||
import org.opencdmp.event.PlanStatusTouchedEvent;
|
||||
import org.opencdmp.model.builder.descriptionstatus.DescriptionStatusBuilder;
|
||||
import org.opencdmp.model.deleter.DescriptionStatusDeleter;
|
||||
import org.opencdmp.model.description.Description;
|
||||
import org.opencdmp.model.descriptionstatus.DescriptionStatus;
|
||||
import org.opencdmp.model.persist.descriptionstatus.DescriptionStatusDefinitionAuthorizationItemPersist;
|
||||
import org.opencdmp.model.persist.descriptionstatus.DescriptionStatusDefinitionAuthorizationPersist;
|
||||
import org.opencdmp.model.persist.descriptionstatus.DescriptionStatusDefinitionPersist;
|
||||
import org.opencdmp.model.persist.descriptionstatus.DescriptionStatusPersist;
|
||||
import org.opencdmp.query.DescriptionStatusQuery;
|
||||
import org.opencdmp.query.PlanStatusQuery;
|
||||
import org.opencdmp.service.custompolicy.CustomPolicyService;
|
||||
import org.opencdmp.service.descriptionworkflow.DescriptionWorkflowService;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.MessageSource;
|
||||
|
@ -64,11 +67,15 @@ public class DescriptionStatusServiceImpl implements DescriptionStatusService {
|
|||
private final ConventionService conventionService;
|
||||
private final MessageSource messageSource;
|
||||
private final XmlHandlingService xmlHandlingService;
|
||||
private final QueryFactory queryFactory;
|
||||
private final DescriptionWorkflowService descriptionWorkflowService;
|
||||
private final EventBroker eventBroker;
|
||||
private final TenantScope tenantScope;
|
||||
private final DescriptionWorkflowService descriptionWorkflowService;
|
||||
private final CustomPolicyService customPolicyService;
|
||||
private final AuthorizationService authorizationService;
|
||||
private final AuthorizationContentResolver authorizationContentResolver;
|
||||
private final QueryFactory queryFactory;
|
||||
|
||||
public DescriptionStatusServiceImpl(BuilderFactory builderFactory, DeleterFactory deleterFactory, AuthorizationService authService, TenantEntityManager entityManager, ConventionService conventionService, MessageSource messageSource, XmlHandlingService xmlHandlingService, QueryFactory queryFactory, DescriptionWorkflowService descriptionWorkflowService, EventBroker eventBroker) {
|
||||
public DescriptionStatusServiceImpl(BuilderFactory builderFactory, DeleterFactory deleterFactory, AuthorizationService authService, TenantEntityManager entityManager, ConventionService conventionService, MessageSource messageSource, XmlHandlingService xmlHandlingService, EventBroker eventBroker, TenantScope tenantScope, DescriptionWorkflowService descriptionWorkflowService, CustomPolicyService customPolicyService, AuthorizationService authorizationService, AuthorizationContentResolver authorizationContentResolver, QueryFactory queryFactory) {
|
||||
this.builderFactory = builderFactory;
|
||||
this.deleterFactory = deleterFactory;
|
||||
|
||||
|
@ -77,9 +84,13 @@ public class DescriptionStatusServiceImpl implements DescriptionStatusService {
|
|||
this.conventionService = conventionService;
|
||||
this.messageSource = messageSource;
|
||||
this.xmlHandlingService = xmlHandlingService;
|
||||
this.queryFactory = queryFactory;
|
||||
this.descriptionWorkflowService = descriptionWorkflowService;
|
||||
this.eventBroker = eventBroker;
|
||||
this.tenantScope = tenantScope;
|
||||
this.descriptionWorkflowService = descriptionWorkflowService;
|
||||
this.customPolicyService = customPolicyService;
|
||||
this.authorizationService = authorizationService;
|
||||
this.authorizationContentResolver = authorizationContentResolver;
|
||||
this.queryFactory = queryFactory;
|
||||
}
|
||||
|
||||
|
||||
|
@ -117,7 +128,7 @@ public class DescriptionStatusServiceImpl implements DescriptionStatusService {
|
|||
|
||||
this.entityManager.flush();
|
||||
|
||||
this.eventBroker.emit(new DescriptionStatusTouchedEvent(data.getId()));
|
||||
this.eventBroker.emit(new DescriptionStatusTouchedEvent(data.getId(), this.tenantScope.getTenantCode()));
|
||||
|
||||
return this.builderFactory.builder(DescriptionStatusBuilder.class).build(BaseFieldSet.build(fields, DescriptionStatus._id), data);
|
||||
}
|
||||
|
@ -164,19 +175,44 @@ public class DescriptionStatusServiceImpl implements DescriptionStatusService {
|
|||
return data;
|
||||
}
|
||||
|
||||
public List<DescriptionStatus> getAvailableTransitionStatuses(UUID descriptionId) throws InvalidApplicationException {
|
||||
DescriptionWorkflowDefinitionEntity definition = this.descriptionWorkflowService.getWorkFlowDefinition();
|
||||
@Override
|
||||
public List<UUID> getAuthorizedNotAvailableStatusIds(UUID descriptionId) {
|
||||
|
||||
DescriptionEntity description = this.entityManager.find(DescriptionEntity.class, descriptionId);
|
||||
if (description == null) throw new MyNotFoundException(this.messageSource.getMessage("General_ItemNotFound", new Object[]{descriptionId, Description.class.getSimpleName()}, LocaleContextHolder.getLocale()));
|
||||
List<UUID> notAuthorizedStatusIds = new ArrayList<>();
|
||||
DescriptionWorkflowDefinitionEntity definition;
|
||||
DescriptionEntity description;
|
||||
try {
|
||||
definition = this.descriptionWorkflowService.getWorkFlowDefinition();
|
||||
description = this.entityManager.find(DescriptionEntity.class, descriptionId, true);
|
||||
if (description == null) throw new MyNotFoundException(this.messageSource.getMessage("General_ItemNotFound", new Object[]{descriptionId, DescriptionEntity.class.getSimpleName()}, LocaleContextHolder.getLocale()));
|
||||
notAuthorizedStatusIds.add(description.getStatusId());
|
||||
} catch (InvalidApplicationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
List<DescriptionWorkflowDefinitionTransitionEntity> availableTransitions = definition.getStatusTransitions().stream().filter(x -> x.getFromStatusId().equals(description.getStatusId())).collect(Collectors.toList());
|
||||
if (!this.conventionService.isListNullOrEmpty(availableTransitions)){
|
||||
DescriptionStatusQuery query = this.queryFactory.query(DescriptionStatusQuery.class).authorize(AuthorizationFlags.AllExceptPublic).isActive(IsActive.Active).ids(availableTransitions.stream().map(DescriptionWorkflowDefinitionTransitionEntity::getToStatusId).distinct().toList());
|
||||
FieldSet fieldSet = new BaseFieldSet().ensure(DescriptionStatus._id).ensure(DescriptionStatus._name).ensure(DescriptionStatus._action).ensure(DescriptionStatus._internalStatus);
|
||||
return this.builderFactory.builder(DescriptionStatusBuilder.class).authorize(AuthorizationFlags.AllExceptPublic).build(fieldSet, query.collectAs(fieldSet));
|
||||
|
||||
if (!this.conventionService.isListNullOrEmpty(availableTransitions)) {
|
||||
List<UUID> availableStatusIds = availableTransitions.stream().map(DescriptionWorkflowDefinitionTransitionEntity::getToStatusId).collect(Collectors.toList());
|
||||
for (UUID statusId: availableStatusIds) {
|
||||
// add status id with no permission
|
||||
String editPermission = this.customPolicyService.getDescriptionStatusCanEditStatusPermission(statusId);
|
||||
Boolean isAllowed = this.authorizationService.authorize(editPermission);
|
||||
if (!isAllowed) {
|
||||
isAllowed = this.authorizationService.authorizeAtLeastOne(List.of(this.authorizationContentResolver.planAffiliation(description.getPlanId())), editPermission);
|
||||
}
|
||||
if (!isAllowed) notAuthorizedStatusIds.add(statusId);
|
||||
}
|
||||
|
||||
return new ArrayList<>();
|
||||
// add status ids that not included in workflow
|
||||
List<DescriptionStatusEntity> statusEntities = this.queryFactory.query(DescriptionStatusQuery.class).authorize(AuthorizationFlags.AllExceptPublic).isActive(IsActive.Active).excludeIds(notAuthorizedStatusIds).collectAs(new BaseFieldSet().ensure(DescriptionStatus._id));
|
||||
if (!this.conventionService.isListNullOrEmpty(statusEntities)) {
|
||||
for (DescriptionStatusEntity status: statusEntities) {
|
||||
if (!availableStatusIds.contains(status.getId())) notAuthorizedStatusIds.add(status.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return notAuthorizedStatusIds;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1617,8 +1617,7 @@ public class PlanServiceImpl implements PlanService {
|
|||
try {
|
||||
this.authorizationService.authorizeForce(this.customPolicyService.getPlanStatusCanEditStatusPermission(newStatusId));
|
||||
} catch (Exception e) {
|
||||
PlanUserEntity planUserEntity = this.queryFactory.query(PlanUserQuery.class).planIds(id).userIds(this.userScope.getUserId()).isActives(IsActive.Active).firstAs(new BaseFieldSet().ensure(PlanUser._role));
|
||||
this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.planAffiliation(id)), this.customPolicyService.getPlanStatusCanEditStatusAffiliatedPermission(newStatusId, planUserEntity.getRole()));
|
||||
this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.planAffiliation(id)), this.customPolicyService.getPlanStatusCanEditStatusPermission(newStatusId));
|
||||
}
|
||||
|
||||
if (plan.getStatusId().equals(newStatusId)) throw new MyApplicationException("Old status equals with new");
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package org.opencdmp.service.planstatus;
|
||||
|
||||
import gr.cite.commons.web.authz.configuration.Permission;
|
||||
import gr.cite.tools.exception.MyApplicationException;
|
||||
import gr.cite.tools.exception.MyForbiddenException;
|
||||
import gr.cite.tools.exception.MyNotFoundException;
|
||||
|
@ -11,7 +10,6 @@ import org.opencdmp.model.persist.planstatus.PlanStatusPersist;
|
|||
import org.opencdmp.model.planstatus.PlanStatus;
|
||||
|
||||
import javax.management.InvalidApplicationException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -20,5 +18,5 @@ public interface PlanStatusService {
|
|||
|
||||
void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException;
|
||||
|
||||
List<PlanStatus> getAvailableTransitionStatuses(UUID planId) throws InvalidApplicationException;
|
||||
List<UUID> getAuthorizedNotAvailableStatusIds(UUID planId);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package org.opencdmp.service.planstatus;
|
||||
|
||||
import gr.cite.commons.web.authz.configuration.PermissionPolicyContext;
|
||||
import gr.cite.commons.web.authz.service.AuthorizationService;
|
||||
import gr.cite.tools.data.builder.BuilderFactory;
|
||||
import gr.cite.tools.data.deleter.DeleterFactory;
|
||||
|
@ -17,8 +16,10 @@ import jakarta.xml.bind.JAXBException;
|
|||
import org.jetbrains.annotations.NotNull;
|
||||
import org.opencdmp.authorization.AuthorizationFlags;
|
||||
import org.opencdmp.authorization.Permission;
|
||||
import org.opencdmp.authorization.authorizationcontentresolver.AuthorizationContentResolver;
|
||||
import org.opencdmp.commons.XmlHandlingService;
|
||||
import org.opencdmp.commons.enums.IsActive;
|
||||
import org.opencdmp.commons.scope.tenant.TenantScope;
|
||||
import org.opencdmp.commons.types.planstatus.PlanStatusDefinitionAuthorizationEntity;
|
||||
import org.opencdmp.commons.types.planstatus.PlanStatusDefinitionAuthorizationItemEntity;
|
||||
import org.opencdmp.commons.types.planstatus.PlanStatusDefinitionEntity;
|
||||
|
@ -31,7 +32,6 @@ import org.opencdmp.data.TenantEntityManager;
|
|||
import org.opencdmp.errorcode.ErrorThesaurusProperties;
|
||||
import org.opencdmp.event.EventBroker;
|
||||
import org.opencdmp.event.PlanStatusTouchedEvent;
|
||||
import org.opencdmp.event.PlanTouchedEvent;
|
||||
import org.opencdmp.model.builder.planstatus.PlanStatusBuilder;
|
||||
import org.opencdmp.model.deleter.PlanStatusDeleter;
|
||||
import org.opencdmp.model.persist.planstatus.PlanStatusDefinitionAuthorizationItemPersist;
|
||||
|
@ -39,8 +39,8 @@ import org.opencdmp.model.persist.planstatus.PlanStatusDefinitionAuthorizationPe
|
|||
import org.opencdmp.model.persist.planstatus.PlanStatusDefinitionPersist;
|
||||
import org.opencdmp.model.persist.planstatus.PlanStatusPersist;
|
||||
import org.opencdmp.model.planstatus.PlanStatus;
|
||||
import org.opencdmp.model.planstatus.PlanStatusDefinitionAuthorization;
|
||||
import org.opencdmp.query.PlanStatusQuery;
|
||||
import org.opencdmp.service.custompolicy.CustomPolicyService;
|
||||
import org.opencdmp.service.planworkflow.PlanWorkflowService;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.MessageSource;
|
||||
|
@ -66,10 +66,14 @@ public class PlanStatusServiceImpl implements PlanStatusService {
|
|||
private final TenantEntityManager entityManager;
|
||||
private final MessageSource messageSource;
|
||||
private final ErrorThesaurusProperties errors;
|
||||
private final QueryFactory queryFactory;
|
||||
private final PlanWorkflowService planWorkflowService;
|
||||
private final EventBroker eventBroker;
|
||||
public PlanStatusServiceImpl(BuilderFactory builderFactory, DeleterFactory deleterFactory, AuthorizationService authorizationService, ConventionService conventionService, XmlHandlingService xmlHandlingService, TenantEntityManager entityManager, MessageSource messageSource, ErrorThesaurusProperties errors, EventBroker eventBroker, QueryFactory queryFactory, PlanWorkflowService planWorkflowService) {
|
||||
private final TenantScope tenantScope;
|
||||
private final PlanWorkflowService planWorkflowService;
|
||||
private final CustomPolicyService customPolicyService;
|
||||
private final AuthorizationContentResolver authorizationContentResolver;
|
||||
private final QueryFactory queryFactory;
|
||||
|
||||
public PlanStatusServiceImpl(BuilderFactory builderFactory, DeleterFactory deleterFactory, AuthorizationService authorizationService, ConventionService conventionService, XmlHandlingService xmlHandlingService, TenantEntityManager entityManager, MessageSource messageSource, ErrorThesaurusProperties errors, EventBroker eventBroker, TenantScope tenantScope, PlanWorkflowService planWorkflowService, CustomPolicyService customPolicyService, AuthorizationContentResolver authorizationContentResolver, QueryFactory queryFactory) {
|
||||
this.builderFactory = builderFactory;
|
||||
this.deleterFactory = deleterFactory;
|
||||
|
||||
|
@ -79,9 +83,12 @@ public class PlanStatusServiceImpl implements PlanStatusService {
|
|||
this.entityManager = entityManager;
|
||||
this.messageSource = messageSource;
|
||||
this.errors = errors;
|
||||
this.queryFactory = queryFactory;
|
||||
this.planWorkflowService = planWorkflowService;
|
||||
this.eventBroker = eventBroker;
|
||||
this.tenantScope = tenantScope;
|
||||
this.planWorkflowService = planWorkflowService;
|
||||
this.customPolicyService = customPolicyService;
|
||||
this.authorizationContentResolver = authorizationContentResolver;
|
||||
this.queryFactory = queryFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -118,7 +125,7 @@ public class PlanStatusServiceImpl implements PlanStatusService {
|
|||
|
||||
this.entityManager.flush();
|
||||
|
||||
this.eventBroker.emit(new PlanStatusTouchedEvent(data.getId()));
|
||||
this.eventBroker.emit(new PlanStatusTouchedEvent(data.getId(), this.tenantScope.getTenantCode()));
|
||||
|
||||
return this.builderFactory.builder(PlanStatusBuilder.class).build(BaseFieldSet.build(fields, PlanStatus._id), data);
|
||||
}
|
||||
|
@ -171,19 +178,44 @@ public class PlanStatusServiceImpl implements PlanStatusService {
|
|||
return data;
|
||||
}
|
||||
|
||||
public List<PlanStatus> getAvailableTransitionStatuses(UUID planId) throws InvalidApplicationException {
|
||||
PlanWorkflowDefinitionEntity definition = this.planWorkflowService.getWorkFlowDefinition();
|
||||
@Override
|
||||
public List<UUID> getAuthorizedNotAvailableStatusIds(UUID planId) {
|
||||
|
||||
PlanEntity plan = this.entityManager.find(PlanEntity.class, planId);
|
||||
List<UUID> notAuthorizedStatusIds = new ArrayList<>();
|
||||
PlanWorkflowDefinitionEntity definition;
|
||||
PlanEntity plan;
|
||||
try {
|
||||
definition = this.planWorkflowService.getWorkFlowDefinition();
|
||||
plan = this.entityManager.find(PlanEntity.class, planId, true);
|
||||
if (plan == null) throw new MyNotFoundException(this.messageSource.getMessage("General_ItemNotFound", new Object[]{planId, PlanEntity.class.getSimpleName()}, LocaleContextHolder.getLocale()));
|
||||
notAuthorizedStatusIds.add(plan.getStatusId());
|
||||
} catch (InvalidApplicationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
List<PlanWorkflowDefinitionTransitionEntity> availableTransitions = definition.getStatusTransitions().stream().filter(x -> x.getFromStatusId().equals(plan.getStatusId())).collect(Collectors.toList());
|
||||
if (!this.conventionService.isListNullOrEmpty(availableTransitions)){
|
||||
PlanStatusQuery query = this.queryFactory.query(PlanStatusQuery.class).authorize(AuthorizationFlags.AllExceptPublic).isActives(IsActive.Active).ids(availableTransitions.stream().map(PlanWorkflowDefinitionTransitionEntity::getToStatusId).distinct().toList());
|
||||
FieldSet fieldSet = new BaseFieldSet().ensure(PlanStatus._id).ensure(PlanStatus._name).ensure(PlanStatus._action).ensure(PlanStatus._internalStatus);
|
||||
return this.builderFactory.builder(PlanStatusBuilder.class).authorize(AuthorizationFlags.AllExceptPublic).build(fieldSet, query.collectAs(fieldSet));
|
||||
|
||||
if (!this.conventionService.isListNullOrEmpty(availableTransitions)) {
|
||||
List<UUID> availableStatusIds = availableTransitions.stream().map(PlanWorkflowDefinitionTransitionEntity::getToStatusId).collect(Collectors.toList());
|
||||
for (UUID statusId: availableStatusIds) {
|
||||
// add status id with no permission
|
||||
String editPermission = this.customPolicyService.getPlanStatusCanEditStatusPermission(statusId);
|
||||
Boolean isAllowed = this.authorizationService.authorize(editPermission);
|
||||
if (!isAllowed) {
|
||||
isAllowed = this.authorizationService.authorizeAtLeastOne(List.of(this.authorizationContentResolver.planAffiliation(plan.getId())), editPermission);
|
||||
}
|
||||
if (!isAllowed) notAuthorizedStatusIds.add(statusId);
|
||||
}
|
||||
|
||||
return new ArrayList<>();
|
||||
// add status ids that not included in workflow
|
||||
List<PlanStatusEntity> statusEntities = this.queryFactory.query(PlanStatusQuery.class).authorize(AuthorizationFlags.AllExceptPublic).isActives(IsActive.Active).excludedIds(notAuthorizedStatusIds).collectAs(new BaseFieldSet().ensure(PlanStatus._id));
|
||||
if (!this.conventionService.isListNullOrEmpty(statusEntities)) {
|
||||
for (PlanStatusEntity status: statusEntities) {
|
||||
if (!availableStatusIds.contains(status.getId())) notAuthorizedStatusIds.add(status.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return notAuthorizedStatusIds;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ public class AffiliatedAuthorizationHandler extends AuthorizationHandler<Affilia
|
|||
boolean hasDescriptionTemplatePermission = policy != null && this.hasPermission(policy.getDescriptionTemplate(), userDescriptionTemplateRoles);
|
||||
|
||||
boolean hasPlanCustomPermission = false;
|
||||
if (permission.startsWith("PlanStatus_") || permission.startsWith("DescriptionStatus_")) {
|
||||
if (permission.startsWith(("PlanStatus_").toLowerCase()) || permission.startsWith(("DescriptionStatus_").toLowerCase())) {
|
||||
HashMap<String, CustomPermissionAttributesProperties. MyPermission> customPolicies = this.opencdmpPermissionPolicyContext.buildAffiliatedCustomPermissions();
|
||||
if (customPolicies == null || customPolicies.isEmpty()) return ACCESS_DENIED;
|
||||
CustomPermissionAttributesProperties.MyPermission customPolicy = customPolicies.get(permission);
|
||||
|
|
|
@ -9,7 +9,7 @@ import org.opencdmp.authorization.CustomPermissionAttributesProperties;
|
|||
import org.opencdmp.authorization.PlanRole;
|
||||
import org.opencdmp.commons.XmlHandlingService;
|
||||
import org.opencdmp.commons.enums.IsActive;
|
||||
import org.opencdmp.commons.enums.PlanUserRole;
|
||||
import org.opencdmp.commons.scope.tenant.TenantScope;
|
||||
import org.opencdmp.commons.types.descriptionstatus.DescriptionStatusDefinitionEntity;
|
||||
import org.opencdmp.commons.types.planstatus.PlanStatusDefinitionEntity;
|
||||
import org.opencdmp.data.DescriptionStatusEntity;
|
||||
|
@ -20,11 +20,13 @@ import org.opencdmp.model.descriptionstatus.DescriptionStatus;
|
|||
import org.opencdmp.model.planstatus.PlanStatus;
|
||||
import org.opencdmp.query.DescriptionStatusQuery;
|
||||
import org.opencdmp.query.PlanStatusQuery;
|
||||
import org.opencdmp.service.custompolicy.CustomPolicyCacheService;
|
||||
import org.opencdmp.service.custompolicy.CustomPolicyService;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.management.InvalidApplicationException;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
|
@ -33,13 +35,17 @@ public class OpencdmpPermissionPolicyContextImpl extends PermissionPolicyContext
|
|||
private final CustomPolicyService customPolicyService;
|
||||
private final QueryFactory queryFactory;
|
||||
private final XmlHandlingService xmlHandlingService;
|
||||
private final CustomPolicyCacheService customPolicyCacheService;
|
||||
private final TenantScope tenantScope;
|
||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(OpencdmpPermissionPolicyContextImpl.class));
|
||||
|
||||
public OpencdmpPermissionPolicyContextImpl(AuthorizationConfiguration authorizationConfiguration, CustomPolicyService customPolicyService, QueryFactory queryFactory, XmlHandlingService xmlHandlingService) {
|
||||
public OpencdmpPermissionPolicyContextImpl(AuthorizationConfiguration authorizationConfiguration, CustomPolicyService customPolicyService, QueryFactory queryFactory, XmlHandlingService xmlHandlingService, CustomPolicyCacheService customPolicyCacheService, TenantScope tenantScope) {
|
||||
super(authorizationConfiguration);
|
||||
this.customPolicyService = customPolicyService;
|
||||
this.queryFactory = queryFactory;
|
||||
this.xmlHandlingService = xmlHandlingService;
|
||||
this.customPolicyCacheService = customPolicyCacheService;
|
||||
this.tenantScope = tenantScope;
|
||||
}
|
||||
|
||||
@EventListener
|
||||
|
@ -65,34 +71,77 @@ public class OpencdmpPermissionPolicyContextImpl extends PermissionPolicyContext
|
|||
|
||||
public HashMap<String, CustomPermissionAttributesProperties.MyPermission> buildAffiliatedCustomPermissions() {
|
||||
HashMap<String, CustomPermissionAttributesProperties.MyPermission> affiliatedCustomPermissions = new HashMap<>();
|
||||
String tenantCode = null;
|
||||
try {
|
||||
tenantCode = this.tenantScope.isSet() && this.tenantScope.isMultitenant() ? this.tenantScope.getTenantCode() : this.tenantScope.getDefaultTenantCode();
|
||||
} catch (InvalidApplicationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
CustomPolicyCacheService.CustomPolicyCacheValue cacheValue = this.customPolicyCacheService.lookup(this.customPolicyCacheService.buildKey(tenantCode));
|
||||
this.buildAffiliatedPlanCustomPermissions(tenantCode, cacheValue, affiliatedCustomPermissions);
|
||||
this.buildAffiliatedDescriptionCustomPermissions(tenantCode, cacheValue, affiliatedCustomPermissions);
|
||||
|
||||
return affiliatedCustomPermissions;
|
||||
}
|
||||
|
||||
private void buildAffiliatedPlanCustomPermissions(String tenantCode, CustomPolicyCacheService.CustomPolicyCacheValue cacheValue, HashMap<String, CustomPermissionAttributesProperties.MyPermission> affiliatedCustomPermissions) {
|
||||
if (cacheValue == null || cacheValue.getPlanStatusDefinitionMap() == null) {
|
||||
Map<UUID, PlanStatusDefinitionEntity> definitionStatusMap = new HashMap<>();
|
||||
List<PlanStatusEntity> planStatusEntities = this.queryFactory.query(PlanStatusQuery.class).isActives(IsActive.Active).collectAs(new BaseFieldSet().ensure(PlanStatus._id).ensure(PlanStatus._definition));
|
||||
if (planStatusEntities != null) {
|
||||
for (PlanStatusEntity entity : planStatusEntities) {
|
||||
PlanStatusDefinitionEntity definition = this.xmlHandlingService.fromXmlSafe(PlanStatusDefinitionEntity.class, entity.getDefinition());
|
||||
if (definition != null && definition.getAuthorization() != null && definition.getAuthorization().getEdit() != null && definition.getAuthorization().getEdit().getPlanRoles() != null){
|
||||
for (PlanUserRole planUserRole: definition.getAuthorization().getEdit().getPlanRoles()) {
|
||||
PlanRole planRole = new PlanRole(new HashSet<>(List.of(planUserRole)));
|
||||
CustomPermissionAttributesProperties.MyPermission myPermission = new CustomPermissionAttributesProperties.MyPermission(planRole, null);
|
||||
affiliatedCustomPermissions.put(this.customPolicyService.getPlanStatusCanEditStatusAffiliatedPermission(entity.getId(), planUserRole), myPermission);
|
||||
CustomPermissionAttributesProperties.MyPermission myPermission = new CustomPermissionAttributesProperties.MyPermission(new PlanRole(new HashSet<>(definition.getAuthorization().getEdit().getPlanRoles())), null);
|
||||
affiliatedCustomPermissions.put(this.customPolicyService.getPlanStatusCanEditStatusPermission(entity.getId()), myPermission);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cacheValue != null && cacheValue.getDescriptionStatusDefinitionMap() != null) {
|
||||
cacheValue = new CustomPolicyCacheService.CustomPolicyCacheValue(tenantCode, definitionStatusMap, cacheValue.getDescriptionStatusDefinitionMap());
|
||||
} else {
|
||||
cacheValue = new CustomPolicyCacheService.CustomPolicyCacheValue(tenantCode, definitionStatusMap, null);
|
||||
}
|
||||
this.customPolicyCacheService.put(cacheValue);
|
||||
} else {
|
||||
for (UUID statusId: cacheValue.getPlanStatusDefinitionMap().keySet()) {
|
||||
PlanStatusDefinitionEntity definition = cacheValue.getPlanStatusDefinitionMap().get(statusId);
|
||||
if (definition != null && definition.getAuthorization() != null && definition.getAuthorization().getEdit() != null) {
|
||||
CustomPermissionAttributesProperties.MyPermission myPermission = new CustomPermissionAttributesProperties.MyPermission(new PlanRole(new HashSet<>(definition.getAuthorization().getEdit().getPlanRoles())), null);
|
||||
affiliatedCustomPermissions.put(this.customPolicyService.getPlanStatusCanEditStatusPermission(statusId), myPermission);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void buildAffiliatedDescriptionCustomPermissions(String tenantCode, CustomPolicyCacheService.CustomPolicyCacheValue cacheValue, HashMap<String, CustomPermissionAttributesProperties.MyPermission> affiliatedCustomPermissions) {
|
||||
if (cacheValue == null || cacheValue.getDescriptionStatusDefinitionMap() == null) {
|
||||
Map<UUID, DescriptionStatusDefinitionEntity> definitionStatusMap = new HashMap<>();
|
||||
List<DescriptionStatusEntity> descriptionStatusEntities = this.queryFactory.query(DescriptionStatusQuery.class).isActive(IsActive.Active).collectAs(new BaseFieldSet().ensure(DescriptionStatus._id).ensure(DescriptionStatus._definition));
|
||||
if (descriptionStatusEntities != null) {
|
||||
for (DescriptionStatusEntity entity : descriptionStatusEntities) {
|
||||
DescriptionStatusDefinitionEntity definition = this.xmlHandlingService.fromXmlSafe(DescriptionStatusDefinitionEntity.class, entity.getDefinition());
|
||||
if (definition != null && definition.getAuthorization() != null && definition.getAuthorization().getEdit() != null && definition.getAuthorization().getEdit().getPlanRoles() != null){
|
||||
for (PlanUserRole planUserRole: definition.getAuthorization().getEdit().getPlanRoles()) {
|
||||
PlanRole planRole = new PlanRole(new HashSet<>(List.of(planUserRole)));
|
||||
CustomPermissionAttributesProperties.MyPermission myPermission = new CustomPermissionAttributesProperties.MyPermission(planRole, null);
|
||||
affiliatedCustomPermissions.put(this.customPolicyService.getDescriptionStatusCanEditStatusAffiliatedPermission(entity.getId(), planUserRole), myPermission);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CustomPermissionAttributesProperties.MyPermission myPermission = new CustomPermissionAttributesProperties.MyPermission(new PlanRole(new HashSet<>(definition.getAuthorization().getEdit().getPlanRoles())), null);
|
||||
affiliatedCustomPermissions.put(this.customPolicyService.getDescriptionStatusCanEditStatusPermission(entity.getId()), myPermission);
|
||||
|
||||
return affiliatedCustomPermissions;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cacheValue != null && cacheValue.getPlanStatusDefinitionMap() != null) {
|
||||
cacheValue = new CustomPolicyCacheService.CustomPolicyCacheValue(tenantCode, cacheValue.getPlanStatusDefinitionMap(), definitionStatusMap);
|
||||
} else {
|
||||
cacheValue = new CustomPolicyCacheService.CustomPolicyCacheValue(tenantCode, null, definitionStatusMap);
|
||||
}
|
||||
this.customPolicyCacheService.put(cacheValue);
|
||||
} else {
|
||||
for (UUID statusId: cacheValue.getDescriptionStatusDefinitionMap().keySet()) {
|
||||
DescriptionStatusDefinitionEntity definition = cacheValue.getDescriptionStatusDefinitionMap().get(statusId);
|
||||
if (definition != null && definition.getAuthorization() != null && definition.getAuthorization().getEdit() != null) {
|
||||
CustomPermissionAttributesProperties.MyPermission myPermission = new CustomPermissionAttributesProperties.MyPermission(new PlanRole(new HashSet<>(definition.getAuthorization().getEdit().getPlanRoles())), null);
|
||||
affiliatedCustomPermissions.put(this.customPolicyService.getDescriptionStatusCanEditStatusPermission(statusId), myPermission);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import { Tag, TagPersist } from "../tag/tag";
|
|||
import { User } from "../user/user";
|
||||
import { AppPermission } from "@app/core/common/enum/permission.enum";
|
||||
import { DescriptionStatus, DescriptionStatusDefinition } from "../description-status/description-status";
|
||||
import { DescriptionStatusPermission } from "@app/core/common/enum/description-status-permission.enum";
|
||||
|
||||
export interface Description extends BaseDescription {
|
||||
label?: string;
|
||||
|
@ -21,7 +22,9 @@ export interface Description extends BaseDescription {
|
|||
descriptionTemplate?: DescriptionTemplate;
|
||||
planDescriptionTemplate?: PlanDescriptionTemplate;
|
||||
plan?: Plan;
|
||||
availableStatuses?: DescriptionStatus[];
|
||||
authorizationFlags?: AppPermission[];
|
||||
statusAuthorizationFlags?: DescriptionStatusPermission[];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ import { IsActive } from '@app/core/common/enum/is-active.enum';
|
|||
import { AppPermission } from '@app/core/common/enum/permission.enum';
|
||||
import { EntityType } from '@app/core/common/enum/entity-type';
|
||||
import { PlanStatus } from '../plan-status/plan-status';
|
||||
import { PlanStatusPermission } from '@app/core/common/enum/plan-status-permission.enum';
|
||||
|
||||
export interface BasePlan extends BaseEntity {
|
||||
label?: string;
|
||||
|
@ -41,7 +42,9 @@ export interface Plan extends BasePlan {
|
|||
descriptions?: Description[];
|
||||
planDescriptionTemplates?: PlanDescriptionTemplate[];
|
||||
otherPlanVersions?: Plan[];
|
||||
availableStatuses?: PlanStatus[];
|
||||
authorizationFlags?: AppPermission[];
|
||||
statusAuthorizationFlags?: PlanStatusPermission[];
|
||||
}
|
||||
|
||||
export interface PublicPlan extends BasePlan {
|
||||
|
|
|
@ -58,15 +58,6 @@ export class DescriptionStatusService {
|
|||
catchError((error: any) => throwError(() => error)));
|
||||
}
|
||||
|
||||
getAvailableTransitions(descriptionId: Guid, reqFields: string[] = []): Observable<Array<DescriptionStatus>> {
|
||||
const url = `${this.apiBase}/available-transitions/${descriptionId}`;
|
||||
const options = { params: { f: reqFields } };
|
||||
|
||||
return this.http
|
||||
.get<Array<DescriptionStatus>>(url, options).pipe(
|
||||
catchError((error: any) => throwError(() => error)));
|
||||
}
|
||||
|
||||
// tslint:disable-next-line: member-ordering
|
||||
singleAutocompleteConfiguration: SingleAutoCompleteConfiguration = {
|
||||
initialItems: (data?: any) => this.query(this.buildAutocompleteLookup([IsActive.Active])).pipe(map(x => x.items)),
|
||||
|
|
|
@ -58,15 +58,6 @@ export class PlanStatusService {
|
|||
catchError((error: any) => throwError(() => error)));
|
||||
}
|
||||
|
||||
getAvailableTransitions(planId: Guid, reqFields: string[] = []): Observable<Array<PlanStatus>> {
|
||||
const url = `${this.apiBase}/available-transitions/${planId}`;
|
||||
const options = { params: { f: reqFields } };
|
||||
|
||||
return this.http
|
||||
.get<Array<PlanStatus>>(url, options).pipe(
|
||||
catchError((error: any) => throwError(() => error)));
|
||||
}
|
||||
|
||||
// tslint:disable-next-line: member-ordering
|
||||
singleAutocompleteConfiguration: SingleAutoCompleteConfiguration = {
|
||||
initialItems: (data?: any) => this.query(this.buildAutocompleteLookup([IsActive.Active])).pipe(map(x => x.items)),
|
||||
|
|
|
@ -67,8 +67,8 @@
|
|||
<button [disabled]="saving" mat-menu-item (click)="saveAndClose()" type="button">{{ 'DESCRIPTION-EDITOR.ACTIONS.SAVE-AND-CLOSE' | translate }}</button>
|
||||
<button [disabled]="saving" mat-menu-item (click)="saveAndContinue()" type="button">{{ 'DESCRIPTION-EDITOR.ACTIONS.SAVE-AND-CONTINUE' | translate }}</button>
|
||||
</mat-menu>
|
||||
<ng-container *ngIf="availableStatusesTransitions && availableStatusesTransitions.length > 0 && !isLocked && item.id && isNotFinalizedPlan()">
|
||||
<button *ngFor='let status of availableStatusesTransitions' [disabled]="saving" mat-button class="rounded-btn neutral mr-2" type="button" (click)="persistStatus(status)">{{ status.action?.length > 0 ? status.action : status.name }}</button>
|
||||
<ng-container *ngIf="canEditStatus && !isNew && item.availableStatuses && item.availableStatuses.length > 0 && !isLocked && item.id && isNotFinalizedPlan()">
|
||||
<button *ngFor='let status of item.availableStatuses' [disabled]="saving" mat-button class="rounded-btn neutral mr-2" type="button" (click)="persistStatus(status)">{{ status.action?.length > 0 ? status.action : status.name }}</button>
|
||||
</ng-container>
|
||||
<button [disabled]="saving" *ngIf="isLocked" mat-button disabled class="rounded-btn neutral cursor-default" type="button">{{ 'PLAN-OVERVIEW.LOCKED' | translate}}</button>
|
||||
</div>
|
||||
|
|
|
@ -45,9 +45,9 @@ import { DescriptionEditorEntityResolver } from './resolvers/description-editor-
|
|||
import { ToCEntry } from './table-of-contents/models/toc-entry';
|
||||
import { TableOfContentsService } from './table-of-contents/services/table-of-contents-service';
|
||||
import { TableOfContentsComponent } from './table-of-contents/table-of-contents.component';
|
||||
import { DescriptionStatusService } from '@app/core/services/description-status/description-status.service';
|
||||
import { DescriptionStatus } from '@app/core/model/description-status/description-status';
|
||||
import { DescriptionStatusAvailableActionType } from '@app/core/common/enum/description-status-available-action-type';
|
||||
import { DescriptionStatusPermission } from '@app/core/common/enum/description-status-permission.enum';
|
||||
|
||||
@Component({
|
||||
selector: 'app-description-editor-component',
|
||||
|
@ -86,7 +86,6 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
private initialTemplateId: string = Guid.EMPTY;
|
||||
private permissionPerSection: Map<Guid, string[]>;
|
||||
|
||||
availableStatusesTransitions: DescriptionStatus[];
|
||||
oldStatusId: Guid;
|
||||
|
||||
constructor(
|
||||
|
@ -118,7 +117,6 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
private tableOfContentsService: TableOfContentsService,
|
||||
private descriptionFormService: DescriptionFormService,
|
||||
private formAnnotationService: FormAnnotationService,
|
||||
private descriptionStatusService: DescriptionStatusService
|
||||
) {
|
||||
const descriptionLabel: string = route.snapshot.data['entity']?.label;
|
||||
if (descriptionLabel) {
|
||||
|
@ -198,7 +196,7 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
}
|
||||
if (this.route.snapshot.url[1] && this.route.snapshot.url[1].path == 'finalize' && !this.lockStatus && !this.viewOnly) {
|
||||
setTimeout(() => {
|
||||
const finalizedStatus = this.availableStatusesTransitions?.find(x => x.internalStatus === DescriptionStatusEnum.Finalized) || null;
|
||||
const finalizedStatus = this.item.availableStatuses?.find(x => x.internalStatus === DescriptionStatusEnum.Finalized) || null;
|
||||
if (finalizedStatus) this.finalize(finalizedStatus.id);
|
||||
}, 0);
|
||||
}
|
||||
|
@ -225,7 +223,6 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
try {
|
||||
this.editorModel = data ? new DescriptionEditorModel().fromModel(data, data.descriptionTemplate) : new DescriptionEditorModel();
|
||||
if (data) {
|
||||
if (data.id) this.getAvailableStatuses(data.id);
|
||||
if (data.status?.id) this.oldStatusId = data.status.id
|
||||
if (data.status?.definition?.availableActions?.filter(x => x === DescriptionStatusAvailableActionType.Export).length > 0) this.canExport = true;
|
||||
}
|
||||
|
@ -270,15 +267,6 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
this.registerFormListeners();
|
||||
}
|
||||
|
||||
getAvailableStatuses(id: Guid){
|
||||
this.descriptionStatusService.getAvailableTransitions(id).pipe(takeUntil(this._destroyed))
|
||||
.subscribe(
|
||||
(statuses) => {
|
||||
this.availableStatusesTransitions = statuses;
|
||||
},
|
||||
(error) => this.httpErrorHandlingService.handleBackedRequestError(error)
|
||||
); }
|
||||
|
||||
calculateMultiplicityRejectedPlanDescriptionTemplates(section: PlanBlueprintDefinitionSection, descriptions: Description[]): PlanDescriptionTemplate[] {
|
||||
if (section.descriptionTemplates?.length > 0) {
|
||||
descriptions = descriptions?.filter(x => x?.planDescriptionTemplate?.sectionId === section.id) || [];
|
||||
|
@ -325,7 +313,7 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
|
||||
persistEntity(onSuccess?: (response) => void): void {
|
||||
const formData = this.formService.getValue(this.formGroup.value) as DescriptionPersist;
|
||||
const finalizedStatus = this.availableStatusesTransitions?.find(x => x.internalStatus === DescriptionStatusEnum.Finalized) || null;
|
||||
const finalizedStatus = this.item.availableStatuses?.find(x => x.internalStatus === DescriptionStatusEnum.Finalized) || null;
|
||||
|
||||
this.descriptionService.persist(formData)
|
||||
.pipe(takeUntil(this._destroyed)).subscribe(
|
||||
|
@ -649,6 +637,10 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
return errorsCount;
|
||||
}
|
||||
|
||||
get canEditStatus(): boolean{
|
||||
return this.item.statusAuthorizationFlags?.some(x => x.toLowerCase() === DescriptionStatusPermission.Edit.toLowerCase())
|
||||
}
|
||||
|
||||
registerFormListeners() {
|
||||
|
||||
this.formGroup.get('descriptionTemplateId').valueChanges
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
||||
import { DescriptionStatusPermission } from '@app/core/common/enum/description-status-permission.enum';
|
||||
import { IsActive } from '@app/core/common/enum/is-active.enum';
|
||||
import { AppPermission } from '@app/core/common/enum/permission.enum';
|
||||
import { DescriptionStatus, DescriptionStatusDefinition } from '@app/core/model/description-status/description-status';
|
||||
|
@ -64,6 +65,8 @@ export class DescriptionEditorEntityResolver extends BaseEditorResolver {
|
|||
[nameof<Description>(x => x.authorizationFlags), AppPermission.FinalizeDescription].join('.'),
|
||||
[nameof<Description>(x => x.authorizationFlags), AppPermission.AnnotateDescription].join('.'),
|
||||
|
||||
[nameof<Description>(x => x.statusAuthorizationFlags), DescriptionStatusPermission.Edit].join('.'),
|
||||
|
||||
[nameof<Description>(x => x.planDescriptionTemplate), nameof<PlanDescriptionTemplate>(x => x.id)].join('.'),
|
||||
[nameof<Description>(x => x.planDescriptionTemplate), nameof<PlanDescriptionTemplate>(x => x.sectionId)].join('.'),
|
||||
[nameof<Description>(x => x.planDescriptionTemplate), nameof<PlanDescriptionTemplate>(x => x.isActive)].join('.'),
|
||||
|
@ -103,7 +106,12 @@ export class DescriptionEditorEntityResolver extends BaseEditorResolver {
|
|||
|
||||
nameof<Description>(x => x.createdAt),
|
||||
nameof<Description>(x => x.hash),
|
||||
nameof<Description>(x => x.isActive)
|
||||
nameof<Description>(x => x.isActive),
|
||||
|
||||
[nameof<Description>(x => x.availableStatuses), nameof<DescriptionStatus>(x => x.id)].join('.'),
|
||||
[nameof<Description>(x => x.availableStatuses), nameof<DescriptionStatus>(x => x.name)].join('.'),
|
||||
[nameof<Description>(x => x.availableStatuses), nameof<DescriptionStatus>(x => x.internalStatus)].join('.'),
|
||||
[nameof<Description>(x => x.availableStatuses), nameof<DescriptionStatus>(x => x.action)].join('.'),
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -134,8 +134,8 @@
|
|||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="frame mb-3 pt-4 pl-4 pr-5 pb-3">
|
||||
<ng-container *ngIf="availableStatusesTransitions && availableStatusesTransitions.length > 0 && !isLocked && isNotFinalizedPlan(description)">
|
||||
<div *ngFor='let status of availableStatusesTransitions'>
|
||||
<ng-container *ngIf="canEditStatus && description.availableStatuses && description.availableStatuses.length > 0 && !isLocked && isNotFinalizedPlan(description)">
|
||||
<div *ngFor='let status of description.availableStatuses'>
|
||||
<div class="row align-items-center" (click)="persistStatus(status, description)">
|
||||
<div class="col-auto pr-0">
|
||||
<button *ngIf="status.internalStatus === descriptionStatusEnum.Finalized && description.status?.internalStatus != descriptionStatusEnum.Finalized" mat-mini-fab class="finalize-btn">
|
||||
|
|
|
@ -45,9 +45,9 @@ import { nameof } from 'ts-simple-nameof';
|
|||
import { DescriptionCopyDialogComponent } from '../description-copy-dialog/description-copy-dialog.component';
|
||||
import { RouterUtilsService } from '@app/core/services/router/router-utils.service';
|
||||
import { DescriptionStatus, DescriptionStatusDefinition } from '@app/core/model/description-status/description-status';
|
||||
import { DescriptionStatusService } from '@app/core/services/description-status/description-status.service';
|
||||
import { PlanStatus } from '@app/core/model/plan-status/plan-status';
|
||||
import { DescriptionStatusAvailableActionType } from '@app/core/common/enum/description-status-available-action-type';
|
||||
import { DescriptionStatusPermission } from '@app/core/common/enum/description-status-permission.enum';
|
||||
|
||||
|
||||
@Component({
|
||||
|
@ -77,7 +77,6 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
|
|||
canFinalize = false;
|
||||
canAnnotate = false;
|
||||
canInvitePlanUsers = false;
|
||||
availableStatusesTransitions: DescriptionStatus[];
|
||||
get canAssignPlanUsers(): boolean {
|
||||
const authorizationFlags = !this.isPublicView ? (this.description?.plan as Plan)?.authorizationFlags : [];
|
||||
return (authorizationFlags?.some(x => x === AppPermission.InvitePlanUsers) || this.authentication.hasPermission(AppPermission.InvitePlanUsers)) &&
|
||||
|
@ -111,7 +110,6 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
|
|||
private breadcrumbService: BreadcrumbService,
|
||||
private httpErrorHandlingService: HttpErrorHandlingService,
|
||||
private userService: UserService,
|
||||
private descriptionStatusService: DescriptionStatusService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
@ -141,7 +139,6 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
|
|||
this.breadcrumbService.addIdResolvedValue(data.id.toString(), data.label);
|
||||
|
||||
this.description = data;
|
||||
this.getAvailableStatuses(this.description.id);
|
||||
this.description.plan.planUsers = this.isActive || this.description.plan.isActive === IsActive.Active ? data.plan.planUsers.filter(x => x.isActive === IsActive.Active) : data.plan.planUsers;
|
||||
this.researchers = this.referenceService.getReferencesForTypes(this.description?.plan?.planReferences, [this.referenceTypeService.getResearcherReferenceType()]);
|
||||
this.checkLockStatus(this.description.id);
|
||||
|
@ -228,17 +225,12 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
|
|||
return this.description?.status?.definition?.availableActions?.filter(x => x === DescriptionStatusAvailableActionType.Export).length > 0;
|
||||
}
|
||||
|
||||
getAvailableStatuses(id: Guid){
|
||||
this.descriptionStatusService.getAvailableTransitions(id).pipe(takeUntil(this._destroyed))
|
||||
.subscribe(
|
||||
(statuses) => {
|
||||
this.availableStatusesTransitions = statuses;
|
||||
},
|
||||
(error) => this.httpErrorHandlingService.handleBackedRequestError(error)
|
||||
); }
|
||||
get canEditStatus(): boolean{
|
||||
return (this.description as Description).statusAuthorizationFlags?.some(x => x.toLowerCase() === DescriptionStatusPermission.Edit.toLowerCase())
|
||||
}
|
||||
|
||||
hasAvailableFinalizeStatus() {
|
||||
return this.availableStatusesTransitions?.find(x => x.internalStatus === DescriptionStatusEnum.Finalized) != null;
|
||||
return (this.description as Description).availableStatuses?.find(x => x.internalStatus === DescriptionStatusEnum.Finalized) != null;
|
||||
}
|
||||
|
||||
checkLockStatus(id: Guid) {
|
||||
|
@ -524,7 +516,7 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
|
|||
}
|
||||
|
||||
hasReversableStatus(description: Description): boolean {
|
||||
return description.plan.status.internalStatus == PlanStatusEnum.Draft && description?.status?.internalStatus == DescriptionStatusEnum.Finalized && this.canFinalize && this.availableStatusesTransitions?.find(x => x.internalStatus === DescriptionStatusEnum.Draft) != null
|
||||
return description.plan.status.internalStatus == PlanStatusEnum.Draft && description?.status?.internalStatus == DescriptionStatusEnum.Finalized && this.canFinalize && (this.description as Description).availableStatuses?.find(x => x.internalStatus === DescriptionStatusEnum.Draft) != null
|
||||
}
|
||||
|
||||
reverseFinalization(description: Description, statusId: Guid) {
|
||||
|
@ -578,6 +570,8 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
|
|||
[nameof<Description>(x => x.authorizationFlags), AppPermission.InvitePlanUsers].join('.'),
|
||||
[nameof<Description>(x => x.authorizationFlags), AppPermission.AnnotateDescription].join('.'),
|
||||
|
||||
[nameof<Description>(x => x.statusAuthorizationFlags), DescriptionStatusPermission.Edit].join('.'),
|
||||
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.id)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.label)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.groupId)].join('.'),
|
||||
|
@ -610,6 +604,11 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
|
|||
[nameof<Description>(x => x.plan), nameof<Plan>(x => x.planReferences), nameof<PlanReference>(x => x.reference), nameof<Reference>(x => x.source)].join('.'),
|
||||
[nameof<Description>(x => x.plan), nameof<Plan>(x => x.planReferences), nameof<PlanReference>(x => x.reference), nameof<Reference>(x => x.reference)].join('.'),
|
||||
[nameof<Description>(x => x.plan), nameof<Plan>(x => x.planReferences), nameof<PlanReference>(x => x.isActive)].join('.'),
|
||||
|
||||
[nameof<Description>(x => x.availableStatuses), nameof<DescriptionStatus>(x => x.id)].join('.'),
|
||||
[nameof<Description>(x => x.availableStatuses), nameof<DescriptionStatus>(x => x.name)].join('.'),
|
||||
[nameof<Description>(x => x.availableStatuses), nameof<DescriptionStatus>(x => x.internalStatus)].join('.'),
|
||||
[nameof<Description>(x => x.availableStatuses), nameof<DescriptionStatus>(x => x.action)].join('.'),
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -181,8 +181,8 @@
|
|||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="frame mb-3 pt-4 pl-4 pr-5 pb-3">
|
||||
<ng-container *ngIf="availableStatusesTransitions && availableStatusesTransitions.length > 0 && !isLocked && plan.versionStatus != planVersionStatusEnum.Previous && hasDoi(plan) && plan.belongsToCurrentTenant != false">
|
||||
<div *ngFor='let status of availableStatusesTransitions'>
|
||||
<ng-container *ngIf="canEditStatus && plan.availableStatuses && plan.availableStatuses.length > 0 && !isLocked && plan.versionStatus != planVersionStatusEnum.Previous && hasDoi(plan) && plan.belongsToCurrentTenant != false">
|
||||
<div *ngFor='let status of plan.availableStatuses'>
|
||||
<div class="row align-items-center" (click)="persistStatus(status)">
|
||||
<div class="col-auto pr-0">
|
||||
<button *ngIf="status.internalStatus === descriptionStatusEnum.Finalized && plan.status?.internalStatus != planStatusEnum.Finalized" mat-mini-fab class="finalize-btn">
|
||||
|
|
|
@ -52,8 +52,8 @@ import { NewVersionPlanDialogComponent } from '../new-version-dialog/plan-new-ve
|
|||
import { RouterUtilsService } from '@app/core/services/router/router-utils.service';
|
||||
import { DescriptionStatus } from '@app/core/model/description-status/description-status';
|
||||
import { PlanStatus, PlanStatusDefinition } from '@app/core/model/plan-status/plan-status';
|
||||
import { PlanStatusService } from '@app/core/services/plan/plan-status.service';
|
||||
import { PlanStatusAvailableActionType } from '@app/core/common/enum/plan-status-available-action-type';
|
||||
import { PlanStatusPermission } from '@app/core/common/enum/plan-status-permission.enum';
|
||||
|
||||
@Component({
|
||||
selector: 'app-plan-overview',
|
||||
|
@ -87,7 +87,6 @@ export class PlanOverviewComponent extends BaseComponent implements OnInit {
|
|||
|
||||
authorFocus: string;
|
||||
userName: string;
|
||||
availableStatusesTransitions: PlanStatus[];
|
||||
|
||||
constructor(
|
||||
public routerUtils: RouterUtilsService,
|
||||
|
@ -113,7 +112,6 @@ export class PlanOverviewComponent extends BaseComponent implements OnInit {
|
|||
private breadcrumbService: BreadcrumbService,
|
||||
private httpErrorHandlingService: HttpErrorHandlingService,
|
||||
private userService: UserService,
|
||||
private pLanStatusService: PlanStatusService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
@ -136,7 +134,6 @@ export class PlanOverviewComponent extends BaseComponent implements OnInit {
|
|||
this.breadcrumbService.addIdResolvedValue(data.id?.toString(), data.label);
|
||||
|
||||
this.plan = data;
|
||||
this.getAvailableStatuses(this.plan.id);
|
||||
this.plan.planUsers = this.isActive ? data?.planUsers?.filter((x) => x.isActive === IsActive.Active) : data?.planUsers;
|
||||
this.plan.otherPlanVersions = data.otherPlanVersions?.filter(x => x.isActive === IsActive.Active) || null;
|
||||
if (this.plan.descriptions && this.isActive) {
|
||||
|
@ -237,14 +234,9 @@ export class PlanOverviewComponent extends BaseComponent implements OnInit {
|
|||
return this.language.instant('PLAN-OVERVIEW.INFOS.UNAUTHORIZED-ORCID');
|
||||
}
|
||||
|
||||
getAvailableStatuses(id: Guid){
|
||||
this.pLanStatusService.getAvailableTransitions(id).pipe(takeUntil(this._destroyed))
|
||||
.subscribe(
|
||||
(statuses) => {
|
||||
this.availableStatusesTransitions = statuses;
|
||||
},
|
||||
(error) => this.httpErrorHandlingService.handleBackedRequestError(error)
|
||||
); }
|
||||
get canEditStatus(): boolean{
|
||||
return (this.plan as Plan).statusAuthorizationFlags ?.some(x => x.toLowerCase() === PlanStatusPermission.Edit.toLowerCase())
|
||||
}
|
||||
|
||||
onFetchingDeletedCallbackError(redirectRoot: string) {
|
||||
this.router.navigate([this.routerUtils.generateUrl(redirectRoot)]);
|
||||
|
@ -691,6 +683,7 @@ export class PlanOverviewComponent extends BaseComponent implements OnInit {
|
|||
[nameof<Plan>(x => x.authorizationFlags), AppPermission.AssignPlanUsers].join('.'),
|
||||
[nameof<Plan>(x => x.authorizationFlags), AppPermission.EditPlan].join('.'),
|
||||
[nameof<Plan>(x => x.authorizationFlags), AppPermission.DepositPlan].join('.'),
|
||||
[nameof<Plan>(x => x.statusAuthorizationFlags), PlanStatusPermission.Edit].join('.'),
|
||||
[nameof<Plan>(x => x.entityDois), nameof<EntityDoi>(x => x.id)].join('.'),
|
||||
[nameof<Plan>(x => x.entityDois), nameof<EntityDoi>(x => x.repositoryId)].join('.'),
|
||||
[nameof<Plan>(x => x.entityDois), nameof<EntityDoi>(x => x.doi)].join('.'),
|
||||
|
@ -734,6 +727,11 @@ export class PlanOverviewComponent extends BaseComponent implements OnInit {
|
|||
[nameof<Plan>(x => x.otherPlanVersions), nameof<Plan>(x => x.version)].join('.'),
|
||||
[nameof<Plan>(x => x.otherPlanVersions), nameof<Plan>(x => x.isActive)].join('.'),
|
||||
|
||||
[nameof<Plan>(x => x.availableStatuses), nameof<PlanStatus>(x => x.id)].join('.'),
|
||||
[nameof<Plan>(x => x.availableStatuses), nameof<PlanStatus>(x => x.name)].join('.'),
|
||||
[nameof<Plan>(x => x.availableStatuses), nameof<PlanStatus>(x => x.internalStatus)].join('.'),
|
||||
[nameof<Plan>(x => x.availableStatuses), nameof<PlanStatus>(x => x.action)].join('.'),
|
||||
|
||||
nameof<Plan>(x => x.hash),
|
||||
]
|
||||
}
|
||||
|
|
|
@ -52,8 +52,8 @@
|
|||
<button [disabled]="saving" mat-menu-item (click)="formSubmit()" type="button">{{ 'PLAN-EDITOR.ACTIONS.SAVE-AND-CONTINUE' | translate }}</button>
|
||||
</mat-menu>
|
||||
</div>
|
||||
<div *ngIf="availableStatusesTransitions && availableStatusesTransitions.length > 0 && item.versionStatus != planVersionStatusEnum.Previous &&!isLocked && !isNew && hasNotDoi()" class="col-auto d-flex align-items-center" [matTooltipDisabled]="formGroup.pristine" matTooltip="{{'PLAN-EDITOR.ACTIONS.FINALIZE.CAN-NOT-FINALIZE' | translate}}">
|
||||
<button *ngFor='let status of availableStatusesTransitions' [disabled]="saving || !formGroup.pristine" mat-button class="rounded-btn primary-inverted mr-2" type="button" (click)="persistStatus(status)">{{ status.action?.length > 0 ? status.action : status.name }}</button>
|
||||
<div *ngIf="canEditStatus && !isNew && item.availableStatuses && item.availableStatuses.length > 0 && item.versionStatus != planVersionStatusEnum.Previous &&!isLocked && !isNew && hasNotDoi()" class="col-auto d-flex align-items-center" [matTooltipDisabled]="formGroup.pristine" matTooltip="{{'PLAN-EDITOR.ACTIONS.FINALIZE.CAN-NOT-FINALIZE' | translate}}">
|
||||
<button *ngFor='let status of item.availableStatuses' [disabled]="saving || !formGroup.pristine" mat-button class="rounded-btn primary-inverted mr-2" type="button" (click)="persistStatus(status)">{{ status.action?.length > 0 ? status.action : status.name }}</button>
|
||||
</div>
|
||||
<div *ngIf="isLocked" class="col-auto d-flex align-items-center">
|
||||
<button class="col-auto d-flex align-items-center" [disabled]="saving" mat-button class="rounded-btn primary-inverted mr-2" type="button">{{ 'PLAN-EDITOR.ACTIONS.LOCKED' | translate}}</button>
|
||||
|
|
|
@ -64,6 +64,7 @@ import { PlanStatusService } from '@app/core/services/plan/plan-status.service';
|
|||
import { PlanStatus } from '@app/core/model/plan-status/plan-status';
|
||||
import { PlanStatusAvailableActionType } from '@app/core/common/enum/plan-status-available-action-type';
|
||||
import { PlanVersionStatus } from '@app/core/common/enum/plan-version-status';
|
||||
import { PlanStatusPermission } from '@app/core/common/enum/plan-status-permission.enum';
|
||||
|
||||
@Component({
|
||||
selector: 'app-plan-editor',
|
||||
|
@ -102,8 +103,6 @@ export class PlanEditorComponent extends BaseEditor<PlanEditorModel, Plan> imple
|
|||
|
||||
hoveredContact: number = -1;
|
||||
|
||||
availableStatusesTransitions: PlanStatus[];
|
||||
|
||||
singleAutocompleteBlueprintConfiguration: SingleAutoCompleteConfiguration = {
|
||||
initialItems: (data?: any) => this.planBlueprintService.query(this.planBlueprintService.buildAutocompleteLookup(null, null, null, [PlanBlueprintStatus.Finalized])).pipe(map(x => x.items)),
|
||||
filterFn: (searchQuery: string, data?: any) => this.planBlueprintService.query(this.planBlueprintService.buildAutocompleteLookup(searchQuery, null, null, [PlanBlueprintStatus.Finalized])).pipe(map(x => x.items)),
|
||||
|
@ -166,6 +165,10 @@ export class PlanEditorComponent extends BaseEditor<PlanEditorModel, Plan> imple
|
|||
return !this.isDeleted && (this.isNew ? this.authService.hasPermission(AppPermission.NewPlan) : this.item.authorizationFlags?.some(x => x === AppPermission.EditPlan) || this.authService.hasPermission(AppPermission.EditPlan));
|
||||
}
|
||||
|
||||
get canEditStatus(): boolean{
|
||||
return this.item.statusAuthorizationFlags?.some(x => x.toLowerCase() === PlanStatusPermission.Edit.toLowerCase())
|
||||
}
|
||||
|
||||
protected canAnnotate(id: Guid): boolean {
|
||||
return !this.isDeleted && this.permissionPerSection && this.permissionPerSection[id.toString()] && this.permissionPerSection[id.toString()].some(x => x === AppPermission.AnnotatePlan);
|
||||
}
|
||||
|
@ -274,7 +277,6 @@ export class PlanEditorComponent extends BaseEditor<PlanEditorModel, Plan> imple
|
|||
this.editorModel = data ? new PlanEditorModel().fromModel(data) : new PlanEditorModel();
|
||||
this.isDeleted = data ? data.isActive === IsActive.Inactive : false;
|
||||
if (data) {
|
||||
if (data.id) this.getAvailableStatuses(data.id);
|
||||
if (data.descriptions && !this.isDeleted) {
|
||||
if (data.status?.internalStatus == PlanStatusEnum.Finalized) {
|
||||
data.descriptions = data.descriptions.filter(x => x.isActive === IsActive.Active && x.status.internalStatus === DescriptionStatusEnum.Finalized);
|
||||
|
@ -326,15 +328,6 @@ export class PlanEditorComponent extends BaseEditor<PlanEditorModel, Plan> imple
|
|||
this.sectionToFieldsMap = this.prepareErrorIndication();
|
||||
}
|
||||
|
||||
getAvailableStatuses(id: Guid){
|
||||
this.pLanStatusService.getAvailableTransitions(id).pipe(takeUntil(this._destroyed))
|
||||
.subscribe(
|
||||
(statuses) => {
|
||||
this.availableStatusesTransitions = statuses;
|
||||
},
|
||||
(error) => this.httpErrorHandlingService.handleBackedRequestError(error)
|
||||
); }
|
||||
|
||||
prepareErrorIndication(): Map<string, PlanFieldIndicator> {
|
||||
if (this.selectedBlueprint?.definition == null) return;
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import { nameof } from 'ts-simple-nameof';
|
|||
import { EntityDoi } from '@app/core/model/entity-doi/entity-doi';
|
||||
import { DescriptionStatus } from '@app/core/model/description-status/description-status';
|
||||
import { PlanStatus, PlanStatusDefinition } from '@app/core/model/plan-status/plan-status';
|
||||
import { PlanStatusPermission } from '@app/core/common/enum/plan-status-permission.enum';
|
||||
|
||||
@Injectable()
|
||||
export class PlanEditorEntityResolver extends BaseEditorResolver {
|
||||
|
@ -53,6 +54,8 @@ export class PlanEditorEntityResolver extends BaseEditorResolver {
|
|||
[nameof<Plan>(x => x.authorizationFlags), AppPermission.EditDescription].join('.'),
|
||||
[nameof<Plan>(x => x.authorizationFlags), AppPermission.ExportPlan].join('.'),
|
||||
|
||||
[nameof<Plan>(x => x.statusAuthorizationFlags), PlanStatusPermission.Edit].join('.'),
|
||||
|
||||
[nameof<Plan>(x => x.properties), nameof<PlanProperties>(x => x.planBlueprintValues), nameof<PlanBlueprintValue>(x => x.fieldId)].join('.'),
|
||||
[nameof<Plan>(x => x.properties), nameof<PlanProperties>(x => x.planBlueprintValues), nameof<PlanBlueprintValue>(x => x.fieldValue)].join('.'),
|
||||
[nameof<Plan>(x => x.properties), nameof<PlanProperties>(x => x.planBlueprintValues), nameof<PlanBlueprintValue>(x => x.dateValue)].join('.'),
|
||||
|
@ -100,6 +103,11 @@ export class PlanEditorEntityResolver extends BaseEditorResolver {
|
|||
[nameof<Plan>(x => x.entityDois), nameof<EntityDoi>(x => x.doi)].join('.'),
|
||||
[nameof<Plan>(x => x.entityDois), nameof<EntityDoi>(x => x.isActive)].join('.'),
|
||||
|
||||
[nameof<Plan>(x => x.availableStatuses), nameof<PlanStatus>(x => x.id)].join('.'),
|
||||
[nameof<Plan>(x => x.availableStatuses), nameof<PlanStatus>(x => x.name)].join('.'),
|
||||
[nameof<Plan>(x => x.availableStatuses), nameof<PlanStatus>(x => x.internalStatus)].join('.'),
|
||||
[nameof<Plan>(x => x.availableStatuses), nameof<PlanStatus>(x => x.action)].join('.'),
|
||||
|
||||
...PlanEditorEntityResolver.blueprintLookupFields(nameof<Plan>(x => x.blueprint)),
|
||||
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue