diff --git a/annotation-service/annotation/src/main/java/gr/cite/annotation/common/scope/tenant/TenantScope.java b/annotation-service/annotation/src/main/java/gr/cite/annotation/common/scope/tenant/TenantScope.java index e42eaebcf..ed39ac7a5 100644 --- a/annotation-service/annotation/src/main/java/gr/cite/annotation/common/scope/tenant/TenantScope.java +++ b/annotation-service/annotation/src/main/java/gr/cite/annotation/common/scope/tenant/TenantScope.java @@ -11,6 +11,8 @@ import javax.management.InvalidApplicationException; import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; +@Component +@RequestScope public class TenantScope { public static final String TenantReplaceParameter = "::TenantCode::"; private final MultitenancyProperties multitenancy; diff --git a/dmp-backend/core/src/main/java/eu/eudat/audit/AuditableAction.java b/dmp-backend/core/src/main/java/eu/eudat/audit/AuditableAction.java index d400b79c0..447a8da61 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/audit/AuditableAction.java +++ b/dmp-backend/core/src/main/java/eu/eudat/audit/AuditableAction.java @@ -162,5 +162,10 @@ public class AuditableAction { public static final EventId PrefillingSource_Delete = new EventId(260003, "PrefillingSource_Delete"); public static final EventId PrefillingSource_Generate = new EventId(260004, "PrefillingSource_Generate"); + public static final EventId TenantConfiguration_Query = new EventId(270000, "TenantConfiguration_Query"); + public static final EventId TenantConfiguration_Lookup = new EventId(270001, "TenantConfiguration_Lookup"); + public static final EventId TenantConfiguration_Persist = new EventId(270002, "TenantConfiguration_Persist"); + public static final EventId TenantConfiguration_Delete = new EventId(270003, "TenantConfiguration_Delete"); + } diff --git a/dmp-backend/core/src/main/java/eu/eudat/errorcode/ErrorThesaurusProperties.java b/dmp-backend/core/src/main/java/eu/eudat/errorcode/ErrorThesaurusProperties.java index 23cc87410..f3e518eff 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/errorcode/ErrorThesaurusProperties.java +++ b/dmp-backend/core/src/main/java/eu/eudat/errorcode/ErrorThesaurusProperties.java @@ -174,4 +174,14 @@ public class ErrorThesaurusProperties { public void setTenantTampering(ErrorDescription tenantTampering) { this.tenantTampering = tenantTampering; } + + private ErrorDescription tenantConfigurationTypeCanNotChange; + + public ErrorDescription getTenantConfigurationTypeCanNotChange() { + return tenantConfigurationTypeCanNotChange; + } + + public void setTenantConfigurationTypeCanNotChange(ErrorDescription tenantConfigurationTypeCanNotChange) { + this.tenantConfigurationTypeCanNotChange = tenantConfigurationTypeCanNotChange; + } } diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/builder/deposit/DepositSourceBuilder.java b/dmp-backend/core/src/main/java/eu/eudat/model/builder/deposit/DepositSourceBuilder.java index 770923ee5..416df7c70 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/model/builder/deposit/DepositSourceBuilder.java +++ b/dmp-backend/core/src/main/java/eu/eudat/model/builder/deposit/DepositSourceBuilder.java @@ -1,14 +1,12 @@ package eu.eudat.model.builder.deposit; import eu.eudat.authorization.AuthorizationFlags; -import eu.eudat.commons.XmlHandlingService; -import eu.eudat.commons.scope.tenant.TenantScope; import eu.eudat.commons.types.deposit.DepositSourceEntity; import eu.eudat.convention.ConventionService; import eu.eudat.model.builder.BaseBuilder; import eu.eudat.model.deposit.DepositSource; -import gr.cite.tools.data.builder.BuilderFactory; -import gr.cite.tools.data.query.QueryFactory; +import eu.eudat.service.encryption.EncryptionService; +import eu.eudat.service.tenant.TenantProperties; import gr.cite.tools.exception.MyApplicationException; import gr.cite.tools.fieldset.FieldSet; import gr.cite.tools.logging.DataLogEntry; @@ -25,11 +23,16 @@ import java.util.*; @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class DepositSourceBuilder extends BaseBuilder { private EnumSet authorize = EnumSet.of(AuthorizationFlags.None); + private boolean encrypted; + private final EncryptionService encryptionService; + private final TenantProperties tenantProperties; @Autowired public DepositSourceBuilder( - ConventionService conventionService) { + ConventionService conventionService, EncryptionService encryptionService, TenantProperties tenantProperties) { super(conventionService, new LoggerService(LoggerFactory.getLogger(DepositSourceBuilder.class))); + this.encryptionService = encryptionService; + this.tenantProperties = tenantProperties; } public DepositSourceBuilder authorize(EnumSet values) { @@ -37,6 +40,11 @@ public class DepositSourceBuilder extends BaseBuilder build(FieldSet fields, List data) throws MyApplicationException { this.logger.debug("building for {} items requesting {} fields", Optional.ofNullable(data).map(List::size).orElse(0), Optional.ofNullable(fields).map(FieldSet::getFields).map(Set::size).orElse(0)); @@ -51,7 +59,17 @@ public class DepositSourceBuilder extends BaseBuilder { private EnumSet authorize = EnumSet.of(AuthorizationFlags.None); - + private final EncryptionService encryptionService; + private final TenantProperties tenantProperties; + private boolean encrypted; @Autowired public FileTransformerSourceBuilder( - ConventionService conventionService) { + ConventionService conventionService, EncryptionService encryptionService, TenantProperties tenantProperties) { super(conventionService, new LoggerService(LoggerFactory.getLogger(FileTransformerSourceBuilder.class))); + this.encryptionService = encryptionService; + this.tenantProperties = tenantProperties; } public FileTransformerSourceBuilder authorize(EnumSet values) { @@ -33,6 +45,11 @@ public class FileTransformerSourceBuilder extends BaseBuilder build(FieldSet fields, List data) throws MyApplicationException { this.logger.debug("building for {} items requesting {} fields", Optional.ofNullable(data).map(List::size).orElse(0), Optional.ofNullable(fields).map(FieldSet::getFields).map(Set::size).orElse(0)); @@ -47,7 +64,17 @@ public class FileTransformerSourceBuilder extends BaseBuilder ids = data.stream().map(TenantEntity::getId).distinct().collect(Collectors.toList()); + { + logger.debug("checking related - {}", TenantConfigurationEntity.class.getSimpleName()); + List items = this.queryFactory.query(TenantConfigurationQuery.class).tenantIds(ids).collect(); + TenantConfigurationDeleter deleter = this.deleterFactory.deleter(TenantConfigurationDeleter.class); + deleter.delete(items); + } + Instant now = Instant.now(); for (TenantEntity item : data) { diff --git a/dmp-backend/core/src/main/java/eu/eudat/query/TenantConfigurationQuery.java b/dmp-backend/core/src/main/java/eu/eudat/query/TenantConfigurationQuery.java index 2baed8d7d..8dce7d98e 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/query/TenantConfigurationQuery.java +++ b/dmp-backend/core/src/main/java/eu/eudat/query/TenantConfigurationQuery.java @@ -6,7 +6,6 @@ import eu.eudat.commons.enums.IsActive; import eu.eudat.commons.enums.TenantConfigurationType; import eu.eudat.data.TenantConfigurationEntity; import eu.eudat.model.tenantconfiguration.TenantConfiguration; -import eu.eudat.query.utils.QueryUtilsService; import gr.cite.tools.data.query.FieldResolver; import gr.cite.tools.data.query.QueryBase; import gr.cite.tools.data.query.QueryContext; @@ -25,16 +24,15 @@ import java.util.*; public class TenantConfigurationQuery extends QueryBase { private Collection ids; + private Collection tenantIds; + private Boolean tenantIsSet; private Collection isActives; private Collection types; private Collection excludedIds; private EnumSet authorize = EnumSet.of(AuthorizationFlags.None); - private final QueryUtilsService queryUtilsService; - - public TenantConfigurationQuery(QueryUtilsService queryUtilsService) { - this.queryUtilsService = queryUtilsService; + public TenantConfigurationQuery() { } public TenantConfigurationQuery ids(UUID value) { @@ -52,6 +50,26 @@ public class TenantConfigurationQuery extends QueryBase values) { + this.tenantIds = values; + return this; + } + + public TenantConfigurationQuery tenantIsSet(Boolean values) { + this.tenantIsSet = values; + return this; + } + public TenantConfigurationQuery isActive(IsActive value) { this.isActives = List.of(value); return this; @@ -104,7 +122,7 @@ public class TenantConfigurationQuery extends QueryBase inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(TenantConfigurationEntity._tenantId)); + for (UUID item : this.tenantIds) inClause.value(item); + predicates.add(inClause); + } if (this.isActives != null) { CriteriaBuilder.In inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(TenantConfigurationEntity._isActive)); @@ -128,6 +151,12 @@ public class TenantConfigurationQuery extends QueryBase inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(TenantConfigurationEntity._type)); diff --git a/dmp-backend/core/src/main/java/eu/eudat/query/lookup/EntityDoiLookup.java b/dmp-backend/core/src/main/java/eu/eudat/query/lookup/EntityDoiLookup.java index a6c15e357..8528a8718 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/query/lookup/EntityDoiLookup.java +++ b/dmp-backend/core/src/main/java/eu/eudat/query/lookup/EntityDoiLookup.java @@ -21,6 +21,46 @@ public class EntityDoiLookup extends Lookup { private List dois; + public List getIsActive() { + return isActive; + } + + public void setIsActive(List isActive) { + this.isActive = isActive; + } + + public List getTypes() { + return types; + } + + public void setTypes(List types) { + this.types = types; + } + + public List getIds() { + return ids; + } + + public void setIds(List ids) { + this.ids = ids; + } + + public List getExcludedIds() { + return excludedIds; + } + + public void setExcludedIds(List excludedIds) { + this.excludedIds = excludedIds; + } + + public List getDois() { + return dois; + } + + public void setDois(List dois) { + this.dois = dois; + } + public EntityDoiQuery enrich(QueryFactory queryFactory) { EntityDoiQuery query = queryFactory.query(EntityDoiQuery.class); if (this.isActive != null) diff --git a/dmp-backend/core/src/main/java/eu/eudat/query/lookup/TenantConfigurationLookup.java b/dmp-backend/core/src/main/java/eu/eudat/query/lookup/TenantConfigurationLookup.java index 3ac81a423..d8f7a8091 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/query/lookup/TenantConfigurationLookup.java +++ b/dmp-backend/core/src/main/java/eu/eudat/query/lookup/TenantConfigurationLookup.java @@ -14,7 +14,9 @@ public class TenantConfigurationLookup extends Lookup { private List isActive; private List types; private List ids; + private List tenantIds; private List excludedIds; + private Boolean tenantIsSet; public List getIsActive() { @@ -49,12 +51,30 @@ public class TenantConfigurationLookup extends Lookup { this.types = types; } + public List getTenantIds() { + return tenantIds; + } + + public void setTenantIds(List tenantIds) { + this.tenantIds = tenantIds; + } + + public Boolean getTenantIsSet() { + return tenantIsSet; + } + + public void setTenantIsSet(Boolean tenantIsSet) { + this.tenantIsSet = tenantIsSet; + } + public TenantConfigurationQuery enrich(QueryFactory queryFactory) { TenantConfigurationQuery query = queryFactory.query(TenantConfigurationQuery.class); if (this.types != null) query.types(this.types); if (this.isActive != null) query.isActive(this.isActive); if (this.ids != null) query.ids(this.ids); if (this.excludedIds != null) query.excludedIds(this.excludedIds); + if (this.tenantIds != null) query.tenantIds(this.tenantIds); + if (this.tenantIsSet != null) query.tenantIsSet(this.tenantIsSet); this.enrichCommon(query); diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/tenant/TenantService.java b/dmp-backend/core/src/main/java/eu/eudat/service/tenant/TenantService.java index 311b91c15..aaf06e5ad 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/tenant/TenantService.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/tenant/TenantService.java @@ -25,6 +25,5 @@ public interface TenantService { Tenant persist(TenantPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException; - Tenant decryptTenant(Tenant model) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException, InvalidApplicationException; void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException; } diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/tenant/TenantServiceImpl.java b/dmp-backend/core/src/main/java/eu/eudat/service/tenant/TenantServiceImpl.java index 7848f8dbb..a1f729271 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/tenant/TenantServiceImpl.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/tenant/TenantServiceImpl.java @@ -51,7 +51,6 @@ import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.time.Instant; -import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -190,28 +189,7 @@ public class TenantServiceImpl implements TenantService { } - @Override - public Tenant decryptTenant(Tenant model) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException, InvalidApplicationException { -// if (model.getConfig() != null && model.getConfig().getDeposit() != null && model.getConfig().getDeposit().getSources() != null) { -// for (TenantSource source : model.getConfig().getDeposit().getSources().stream().toList()) { -// source.setClientSecret(this.encryptionService.decryptAES(source.getClientSecret(), properties.getConfigEncryptionAesKey(), properties.getConfigEncryptionAesIv())); -// } -// } -// if (model.getConfig() != null && model.getConfig().getFileTransformers() != null && model.getConfig().getFileTransformers().getSources() != null) { -// for (TenantSource source : model.getConfig().getFileTransformers().getSources().stream().toList()) { -// source.setClientSecret(this.encryptionService.decryptAES(source.getClientSecret(), properties.getConfigEncryptionAesKey(), properties.getConfigEncryptionAesIv())); -// } -// } - - TenantEntity data = this.entityManager.find(TenantEntity.class, model.getId()); - if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), Tenant.class.getSimpleName()}, LocaleContextHolder.getLocale())); - - TenantTouchedIntegrationEvent tenantTouchedIntegrationEvent = new TenantTouchedIntegrationEvent(); - tenantTouchedIntegrationEvent.setId(data.getId()); - tenantTouchedIntegrationEvent.setCode(data.getCode()); - this.tenantTouchedIntegrationEventHandler.handle(tenantTouchedIntegrationEvent); - return model; - } + @Override public void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException { diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/tenantconfiguration/TenantConfigurationService.java b/dmp-backend/core/src/main/java/eu/eudat/service/tenantconfiguration/TenantConfigurationService.java new file mode 100644 index 000000000..fbc587643 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/service/tenantconfiguration/TenantConfigurationService.java @@ -0,0 +1,27 @@ +package eu.eudat.service.tenantconfiguration; + +import com.fasterxml.jackson.core.JsonProcessingException; +import eu.eudat.model.persist.tenantconfiguration.TenantConfigurationPersist; +import eu.eudat.model.tenantconfiguration.TenantConfiguration; +import gr.cite.tools.exception.MyApplicationException; +import gr.cite.tools.exception.MyForbiddenException; +import gr.cite.tools.exception.MyNotFoundException; +import gr.cite.tools.exception.MyValidationException; +import gr.cite.tools.fieldset.FieldSet; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.management.InvalidApplicationException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.UUID; + +public interface TenantConfigurationService { + + TenantConfiguration persist(TenantConfigurationPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JsonProcessingException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException; + + void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException; + +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/tenantconfiguration/TenantConfigurationServiceImpl.java b/dmp-backend/core/src/main/java/eu/eudat/service/tenantconfiguration/TenantConfigurationServiceImpl.java new file mode 100644 index 000000000..d5f0f5ad4 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/service/tenantconfiguration/TenantConfigurationServiceImpl.java @@ -0,0 +1,248 @@ +package eu.eudat.service.tenantconfiguration; + +import com.fasterxml.jackson.core.JsonProcessingException; +import eu.eudat.authorization.AuthorizationFlags; +import eu.eudat.authorization.Permission; +import eu.eudat.commons.JsonHandlingService; +import eu.eudat.commons.enums.IsActive; +import eu.eudat.commons.enums.StorageType; +import eu.eudat.commons.enums.TenantConfigurationType; +import eu.eudat.commons.types.deposit.DepositSourceEntity; +import eu.eudat.commons.types.filetransformer.FileTransformerSourceEntity; +import eu.eudat.commons.types.tenantconfiguration.*; +import eu.eudat.convention.ConventionService; +import eu.eudat.data.TenantConfigurationEntity; +import eu.eudat.data.TenantEntityManager; +import eu.eudat.errorcode.ErrorThesaurusProperties; +import eu.eudat.model.StorageFile; +import eu.eudat.model.builder.tenantconfiguration.TenantConfigurationBuilder; +import eu.eudat.model.deleter.TenantConfigurationDeleter; +import eu.eudat.model.persist.deposit.DepositSourcePersist; +import eu.eudat.model.persist.filetransformer.FileTransformerSourcePersist; +import eu.eudat.model.persist.tenantconfiguration.*; +import eu.eudat.model.tenantconfiguration.TenantConfiguration; +import eu.eudat.service.encryption.EncryptionService; +import eu.eudat.service.storage.StorageFileService; +import eu.eudat.service.tenant.TenantProperties; +import gr.cite.commons.web.authz.service.AuthorizationService; +import gr.cite.tools.data.builder.BuilderFactory; +import gr.cite.tools.data.deleter.DeleterFactory; +import gr.cite.tools.exception.MyApplicationException; +import gr.cite.tools.exception.MyForbiddenException; +import gr.cite.tools.exception.MyNotFoundException; +import gr.cite.tools.exception.MyValidationException; +import gr.cite.tools.fieldset.BaseFieldSet; +import gr.cite.tools.fieldset.FieldSet; +import gr.cite.tools.logging.LoggerService; +import gr.cite.tools.logging.MapLogEntry; +import org.jetbrains.annotations.NotNull; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.MessageSource; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.stereotype.Service; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.management.InvalidApplicationException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@Service +public class TenantConfigurationServiceImpl implements TenantConfigurationService { + + private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantConfigurationServiceImpl.class)); + + private final TenantEntityManager entityManager; + + private final AuthorizationService authorizationService; + + private final DeleterFactory deleterFactory; + + private final BuilderFactory builderFactory; + + private final ConventionService conventionService; + + private final ErrorThesaurusProperties errors; + + private final MessageSource messageSource; + + private final JsonHandlingService jsonHandlingService; + + private final EncryptionService encryptionService; + + private final TenantProperties tenantProperties; + private final StorageFileService storageFileService; + @Autowired + public TenantConfigurationServiceImpl( + TenantEntityManager entityManager, + AuthorizationService authorizationService, + DeleterFactory deleterFactory, + BuilderFactory builderFactory, + ConventionService conventionService, + ErrorThesaurusProperties errors, + MessageSource messageSource, JsonHandlingService jsonHandlingService, EncryptionService encryptionService, TenantProperties tenantProperties, StorageFileService storageFileService) { + this.entityManager = entityManager; + this.authorizationService = authorizationService; + this.deleterFactory = deleterFactory; + this.builderFactory = builderFactory; + this.conventionService = conventionService; + this.errors = errors; + this.messageSource = messageSource; + this.jsonHandlingService = jsonHandlingService; + this.encryptionService = encryptionService; + this.tenantProperties = tenantProperties; + this.storageFileService = storageFileService; + } + + public TenantConfiguration persist(TenantConfigurationPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JsonProcessingException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException { + logger.debug(new MapLogEntry("persisting data TenantConfiguration").And("model", model).And("fields", fields)); + + this.authorizationService.authorizeForce(Permission.EditTenantConfiguration); + + Boolean isUpdate = this.conventionService.isValidGuid(model.getId()); + + TenantConfigurationEntity data; + if (isUpdate) { + data = this.entityManager.find(TenantConfigurationEntity.class, model.getId()); + if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), TenantConfiguration.class.getSimpleName()}, LocaleContextHolder.getLocale())); + if (!this.conventionService.hashValue(data.getUpdatedAt()).equals(model.getHash())) throw new MyValidationException(this.errors.getHashConflict().getCode(), this.errors.getHashConflict().getMessage()); + if (!data.getType().equals(model.getType())) throw new MyValidationException(this.errors.getTenantConfigurationTypeCanNotChange().getCode(), this.errors.getTenantConfigurationTypeCanNotChange().getMessage()); + } else { + data = new TenantConfigurationEntity(); + data.setId(UUID.randomUUID()); + data.setIsActive(IsActive.Active); + data.setCreatedAt(Instant.now()); + data.setType(model.getType()); + } + + + switch (data.getType()){ + case CssColors -> data.setValue(this.jsonHandlingService.toJson(this.buildCssColorsTenantConfigurationEntity(model.getCssColors()))); + case DefaultUserLocale -> data.setValue(this.jsonHandlingService.toJson(this.buildDefaultUserLocaleTenantConfigurationEntity(model.getDefaultUserLocale()))); + case DepositPlugins -> data.setValue(this.jsonHandlingService.toJson(this.buildDepositTenantConfigurationEntity(model.getDepositPlugins()))); + case FileTransformerPlugins -> data.setValue(this.jsonHandlingService.toJson(this.buildFileTransformerTenantConfigurationEntity(model.getFileTransformerPlugins()))); + case Logo -> { + LogoTenantConfigurationEntity oldValue = this.conventionService.isNullOrEmpty(data.getValue()) ? null : this.jsonHandlingService.fromJsonSafe(LogoTenantConfigurationEntity.class, data.getValue()); + data.setValue(this.jsonHandlingService.toJson(this.buildLogoTenantConfigurationEntity(model.getLogo(), oldValue))); + } + default -> throw new InternalError("unknown type: " + data.getType()); + } + data.setUpdatedAt(Instant.now()); + if (isUpdate) + this.entityManager.merge(data); + else + this.entityManager.persist(data); + + this.entityManager.flush(); + + return this.builderFactory.builder(TenantConfigurationBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(BaseFieldSet.build(fields, TenantConfiguration._id), data); + } + + private @NotNull DepositTenantConfigurationEntity buildDepositTenantConfigurationEntity(DepositTenantConfigurationPersist persist) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException { + DepositTenantConfigurationEntity data = new DepositTenantConfigurationEntity(); + if (persist == null || this.conventionService.isListNullOrEmpty(persist.getSources())) return data; + data.setSources(new ArrayList<>()); + for (DepositSourcePersist depositSourcePersist : persist.getSources()) { + data.getSources().add(this.buildDepositSourceEntity(depositSourcePersist)); + } + return data; + } + + private DepositSourceEntity buildDepositSourceEntity(DepositSourcePersist depositSourcePersist) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException { + DepositSourceEntity depositSourceEntity = new DepositSourceEntity(); + depositSourceEntity.setClientId(depositSourcePersist.getClientId()); + if (!this.conventionService.isNullOrEmpty(depositSourcePersist.getClientSecret())) depositSourceEntity.setClientSecret(this.encryptionService.encryptAES(depositSourcePersist.getClientSecret(), this.tenantProperties.getConfigEncryptionAesKey(), this.tenantProperties.getConfigEncryptionAesIv())); + depositSourceEntity.setRepositoryId(depositSourcePersist.getRepositoryId()); + depositSourceEntity.setUrl(depositSourcePersist.getUrl()); + depositSourceEntity.setIssuerUrl(depositSourcePersist.getIssuerUrl()); + depositSourceEntity.setScope(depositSourcePersist.getScope()); + depositSourceEntity.setPdfTransformerId(depositSourcePersist.getPdfTransformerId()); + depositSourceEntity.setRdaTransformerId(depositSourcePersist.getRdaTransformerId()); + return depositSourceEntity; + } + + private @NotNull FileTransformerTenantConfigurationEntity buildFileTransformerTenantConfigurationEntity(FileTransformerTenantConfigurationPersist persist) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException { + FileTransformerTenantConfigurationEntity data = new FileTransformerTenantConfigurationEntity(); + if (persist == null || this.conventionService.isListNullOrEmpty(persist.getSources())) return data; + data.setSources(new ArrayList<>()); + for (FileTransformerSourcePersist depositSourcePersist : persist.getSources()) { + data.getSources().add(this.buildFileTransformerSourceEntity(depositSourcePersist)); + } + return data; + } + + private FileTransformerSourceEntity buildFileTransformerSourceEntity(FileTransformerSourcePersist depositSourcePersist) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException { + FileTransformerSourceEntity depositSourceEntity = new FileTransformerSourceEntity(); + depositSourceEntity.setClientId(depositSourcePersist.getClientId()); + if (!this.conventionService.isNullOrEmpty(depositSourcePersist.getClientSecret())) depositSourceEntity.setClientSecret(this.encryptionService.encryptAES(depositSourcePersist.getClientSecret(), this.tenantProperties.getConfigEncryptionAesKey(), this.tenantProperties.getConfigEncryptionAesIv())); + depositSourceEntity.setUrl(depositSourcePersist.getUrl()); + depositSourceEntity.setIssuerUrl(depositSourcePersist.getIssuerUrl()); + depositSourceEntity.setScope(depositSourcePersist.getScope()); + depositSourceEntity.setTransformerId(depositSourcePersist.getTransformerId()); + return depositSourceEntity; + } + + private @NotNull CssColorsTenantConfigurationEntity buildCssColorsTenantConfigurationEntity(CssColorsTenantConfigurationPersist persist){ + CssColorsTenantConfigurationEntity data = new CssColorsTenantConfigurationEntity(); + if (persist == null) return data; + data.setPrimaryColor(persist.getPrimaryColor()); + data.setPrimaryColor2(persist.getPrimaryColor2()); + data.setPrimaryColor3(persist.getPrimaryColor3()); + data.setSecondaryColor(persist.getSecondaryColor()); + return data; + } + + private @NotNull DefaultUserLocaleTenantConfigurationEntity buildDefaultUserLocaleTenantConfigurationEntity(DefaultUserLocaleTenantConfigurationPersist persist){ + DefaultUserLocaleTenantConfigurationEntity data = new DefaultUserLocaleTenantConfigurationEntity(); + if (persist == null) return data; + data.setCulture(persist.getCulture()); + data.setLanguage(persist.getLanguage()); + data.setTimezone(persist.getTimezone()); + return data; + } + + private @NotNull LogoTenantConfigurationEntity buildLogoTenantConfigurationEntity(LogoTenantConfigurationPersist persist, LogoTenantConfigurationEntity oldValue) throws InvalidApplicationException { + LogoTenantConfigurationEntity data = new LogoTenantConfigurationEntity(); + if (persist == null) return data; + data.setStorageFileId(persist.getStorageFileId()); + + UUID existingFileId = oldValue != null ? oldValue.getStorageFileId() : null; + if (persist.getStorageFileId() != null){ + if (!persist.getStorageFileId().equals(existingFileId)) { + StorageFile storageFile = this.storageFileService.copyToStorage(persist.getStorageFileId(), StorageType.Main, true, new BaseFieldSet().ensure(StorageFile._id)); + this.storageFileService.updatePurgeAt(storageFile.getId(), null); + if (existingFileId != null) this.storageFileService.updatePurgeAt(existingFileId, Instant.now().minusSeconds(60)); + data.setStorageFileId(storageFile.getId()); + } else { + data.setStorageFileId(existingFileId); + } + } else { + if (existingFileId != null) this.storageFileService.updatePurgeAt(existingFileId, Instant.now().minusSeconds(60)); + data.setStorageFileId(null); + } + return data; + } + + public void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException { + logger.debug("deleting dataset: {}", id); + + this.authorizationService.authorizeForce(Permission.DeleteTenantConfiguration); + + TenantConfigurationEntity data = this.entityManager.find(TenantConfigurationEntity.class, id); + if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, TenantConfiguration.class.getSimpleName()}, LocaleContextHolder.getLocale())); + + if (data.getType().equals(TenantConfigurationType.Logo)){ + LogoTenantConfigurationEntity oldValue = this.conventionService.isNullOrEmpty(data.getValue()) ? null : this.jsonHandlingService.fromJsonSafe(LogoTenantConfigurationEntity.class, data.getValue()); + if (oldValue != null && oldValue.getStorageFileId() != null) this.storageFileService.updatePurgeAt(oldValue.getStorageFileId(), Instant.now().minusSeconds(60)); + } + this.deleterFactory.deleter(TenantConfigurationDeleter.class).deleteAndSaveByIds(List.of(id)); + } + +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/EntityDoiController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/EntityDoiController.java index 156339675..be56098f1 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/EntityDoiController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/EntityDoiController.java @@ -37,7 +37,7 @@ import java.util.*; @RequestMapping(path = "api/entity-doi") public class EntityDoiController { - private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(DescriptionTemplateTypeController.class)); + private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(EntityDoiController.class)); private final BuilderFactory builderFactory; diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/TenantConfigurationController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/TenantConfigurationController.java new file mode 100644 index 000000000..2c8b5236d --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/TenantConfigurationController.java @@ -0,0 +1,135 @@ +package eu.eudat.controllers; + +import com.fasterxml.jackson.core.JsonProcessingException; +import eu.eudat.audit.AuditableAction; +import eu.eudat.authorization.AuthorizationFlags; +import eu.eudat.data.TenantConfigurationEntity; +import eu.eudat.model.DescriptionTemplateType; +import eu.eudat.model.builder.tenantconfiguration.TenantConfigurationBuilder; +import eu.eudat.model.censorship.tenantconfiguration.TenantConfigurationCensor; +import eu.eudat.model.persist.tenantconfiguration.TenantConfigurationPersist; +import eu.eudat.model.result.QueryResult; +import eu.eudat.model.tenantconfiguration.TenantConfiguration; +import eu.eudat.query.TenantConfigurationQuery; +import eu.eudat.query.lookup.TenantConfigurationLookup; +import eu.eudat.service.tenantconfiguration.TenantConfigurationService; +import gr.cite.tools.auditing.AuditService; +import gr.cite.tools.data.builder.BuilderFactory; +import gr.cite.tools.data.censor.CensorFactory; +import gr.cite.tools.data.query.QueryFactory; +import gr.cite.tools.exception.MyApplicationException; +import gr.cite.tools.exception.MyForbiddenException; +import gr.cite.tools.exception.MyNotFoundException; +import gr.cite.tools.fieldset.FieldSet; +import gr.cite.tools.logging.LoggerService; +import gr.cite.tools.logging.MapLogEntry; +import gr.cite.tools.validation.ValidationFilterAnnotation; +import org.slf4j.LoggerFactory; +import org.springframework.context.MessageSource; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.management.InvalidApplicationException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.*; + +@RestController +@RequestMapping(path = "api/tenant-configuration") +public class TenantConfigurationController { + + private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantConfigurationController.class)); + + private final BuilderFactory builderFactory; + + private final AuditService auditService; + + private final TenantConfigurationService tenantConfigurationService; + + private final CensorFactory censorFactory; + + private final QueryFactory queryFactory; + + private final MessageSource messageSource; + + public TenantConfigurationController( + BuilderFactory builderFactory, + AuditService auditService, + TenantConfigurationService tenantConfigurationService, CensorFactory censorFactory, + QueryFactory queryFactory, + MessageSource messageSource) { + this.builderFactory = builderFactory; + this.auditService = auditService; + this.tenantConfigurationService = tenantConfigurationService; + this.censorFactory = censorFactory; + this.queryFactory = queryFactory; + this.messageSource = messageSource; + } + + @PostMapping("query") + public QueryResult Query(@RequestBody TenantConfigurationLookup lookup) throws MyApplicationException, MyForbiddenException { + logger.debug("querying {}", TenantConfiguration.class.getSimpleName()); + + this.censorFactory.censor(TenantConfigurationCensor.class).censor(lookup.getProject(), null); + + TenantConfigurationQuery query = lookup.enrich(this.queryFactory).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission); + + List data = query.collectAs(lookup.getProject()); + List models = this.builderFactory.builder(TenantConfigurationBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(lookup.getProject(), data); + long count = (lookup.getMetadata() != null && lookup.getMetadata().getCountAll()) ? query.count() : models.size(); + + this.auditService.track(AuditableAction.TenantConfiguration_Query, "lookup", lookup); + + return new QueryResult<>(models, count); + } + + @GetMapping("{id}") + public TenantConfiguration Get(@PathVariable("id") UUID id, FieldSet fieldSet, Locale locale) throws MyApplicationException, MyForbiddenException, MyNotFoundException { + logger.debug(new MapLogEntry("retrieving" + TenantConfiguration.class.getSimpleName()).And("id", id).And("fields", fieldSet)); + + this.censorFactory.censor(TenantConfigurationCensor.class).censor(fieldSet, null); + + TenantConfigurationQuery query = this.queryFactory.query(TenantConfigurationQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).ids(id); + TenantConfiguration model = this.builderFactory.builder(TenantConfigurationBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(fieldSet, query.firstAs(fieldSet)); + if (model == null) + throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, TenantConfiguration.class.getSimpleName()}, LocaleContextHolder.getLocale())); + + this.auditService.track(AuditableAction.TenantConfiguration_Lookup, Map.ofEntries( + new AbstractMap.SimpleEntry("id", id), + new AbstractMap.SimpleEntry("fields", fieldSet) + )); + + return model; + } + + @PostMapping("persist") + @Transactional + @ValidationFilterAnnotation(validator = TenantConfigurationPersist.TenantConfigurationPersistValidator.ValidatorName, argumentName = "model") + public TenantConfiguration Persist(@RequestBody TenantConfigurationPersist model, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, JsonProcessingException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException { + logger.debug(new MapLogEntry("persisting" + DescriptionTemplateType.class.getSimpleName()).And("model", model).And("fieldSet", fieldSet)); + TenantConfiguration persisted = this.tenantConfigurationService.persist(model, fieldSet); + + this.auditService.track(AuditableAction.TenantConfiguration_Persist, Map.ofEntries( + new AbstractMap.SimpleEntry("model", model), + new AbstractMap.SimpleEntry("fields", fieldSet) + )); + + return persisted; + } + + @DeleteMapping("{id}") + @Transactional + public void Delete(@PathVariable("id") UUID id) throws MyForbiddenException, InvalidApplicationException { + logger.debug(new MapLogEntry("retrieving" + TenantConfiguration.class.getSimpleName()).And("id", id)); + + this.tenantConfigurationService.deleteAndSave(id); + + this.auditService.track(AuditableAction.TenantConfiguration_Delete, "id", id); + } + +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/TenantController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/TenantController.java index feef64391..7533320b9 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/TenantController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/TenantController.java @@ -86,9 +86,6 @@ public class TenantController { List data = query.collectAs(lookup.getProject()); List models = this.builderFactory.builder(TenantBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(lookup.getProject(), data); - for (Tenant model : models) { - models.set(models.indexOf(model), this.tenantService.decryptTenant(model)); - } long count = (lookup.getMetadata() != null && lookup.getMetadata().getCountAll()) ? query.count() : models.size(); this.auditService.track(AuditableAction.Tenant_Query, "lookup", lookup); @@ -107,8 +104,6 @@ public class TenantController { if (model == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, Tenant.class.getSimpleName()}, LocaleContextHolder.getLocale())); - model = this.tenantService.decryptTenant(model); - this.auditService.track(AuditableAction.Tenant_Lookup, Map.ofEntries( new AbstractMap.SimpleEntry("id", id), new AbstractMap.SimpleEntry("fields", fieldSet) diff --git a/dmp-backend/web/src/main/resources/config/errors.yml b/dmp-backend/web/src/main/resources/config/errors.yml index 6b3580195..7cdda0db9 100644 --- a/dmp-backend/web/src/main/resources/config/errors.yml +++ b/dmp-backend/web/src/main/resources/config/errors.yml @@ -59,3 +59,7 @@ error-thesaurus: tenant-tampering: code: 123 message: Tenant tampering + tenant-configuration-type-can-not-change: + code: 124 + message: Tenant configuration type can not change + diff --git a/dmp-frontend/src/app/core/services/description/description.service.ts b/dmp-frontend/src/app/core/services/description/description.service.ts index eb0f75948..305022023 100644 --- a/dmp-frontend/src/app/core/services/description/description.service.ts +++ b/dmp-frontend/src/app/core/services/description/description.service.ts @@ -126,9 +126,9 @@ export class DescriptionService { // // tslint:disable-next-line: member-ordering singleAutocompleteConfiguration: SingleAutoCompleteConfiguration = { - initialItems: (data?: any) => this.query(this.buildAutocompleteLookup()).pipe(map(x => x.items)), - filterFn: (searchQuery: string, data?: any) => this.query(this.buildAutocompleteLookup(searchQuery)).pipe(map(x => x.items)), - getSelectedItem: (selectedItem: any) => this.query(this.buildAutocompleteLookup(null, null, [selectedItem])).pipe(map(x => x.items[0])), + initialItems: (data?: any) => this.query(this.buildAutocompleteLookup([IsActive.Active])).pipe(map(x => x.items)), + filterFn: (searchQuery: string, data?: any) => this.query(this.buildAutocompleteLookup([IsActive.Active], searchQuery)).pipe(map(x => x.items)), + getSelectedItem: (selectedItem: any) => this.query(this.buildAutocompleteLookup([IsActive.Active, IsActive.Inactive], null, null, [selectedItem])).pipe(map(x => x.items[0])), displayFn: (item: Description) => item.label, titleFn: (item: Description) => item.label, valueAssign: (item: Description) => item.id, @@ -136,20 +136,20 @@ export class DescriptionService { // tslint:disable-next-line: member-ordering multipleAutocompleteConfiguration: MultipleAutoCompleteConfiguration = { - initialItems: (excludedItems: any[], data?: any) => this.query(this.buildAutocompleteLookup(null, excludedItems ? excludedItems : null)).pipe(map(x => x.items)), - filterFn: (searchQuery: string, excludedItems: any[]) => this.query(this.buildAutocompleteLookup(searchQuery, excludedItems)).pipe(map(x => x.items)), - getSelectedItems: (selectedItems: any[]) => this.query(this.buildAutocompleteLookup(null, null, selectedItems)).pipe(map(x => x.items)), + initialItems: (excludedItems: any[], data?: any) => this.query(this.buildAutocompleteLookup([IsActive.Active], null, excludedItems ? excludedItems : null)).pipe(map(x => x.items)), + filterFn: (searchQuery: string, excludedItems: any[]) => this.query(this.buildAutocompleteLookup([IsActive.Active], searchQuery, excludedItems)).pipe(map(x => x.items)), + getSelectedItems: (selectedItems: any[]) => this.query(this.buildAutocompleteLookup([IsActive.Active, IsActive.Inactive], null, null, selectedItems)).pipe(map(x => x.items)), displayFn: (item: Description) => item.label, titleFn: (item: Description) => item.label, valueAssign: (item: Description) => item.id, }; - public buildAutocompleteLookup(like?: string, excludedIds?: Guid[], ids?: Guid[]): DescriptionLookup { + public buildAutocompleteLookup(isActive: IsActive[], like?: string, excludedIds?: Guid[], ids?: Guid[]): DescriptionLookup { const lookup: DescriptionLookup = new DescriptionLookup(); lookup.page = { size: 100, offset: 0 }; if (excludedIds && excludedIds.length > 0) { lookup.excludedIds = excludedIds; } if (ids && ids.length > 0) { lookup.ids = ids; } - lookup.isActive = [IsActive.Active]; + lookup.isActive = isActive; lookup.project = { fields: [ nameof(x => x.id), diff --git a/dmp-frontend/src/app/core/services/dmp/dmp.service.ts b/dmp-frontend/src/app/core/services/dmp/dmp.service.ts index 0f6a3c315..e195c7532 100644 --- a/dmp-frontend/src/app/core/services/dmp/dmp.service.ts +++ b/dmp-frontend/src/app/core/services/dmp/dmp.service.ts @@ -208,9 +208,9 @@ export class DmpService { // // tslint:disable-next-line: member-ordering singleAutocompleteConfiguration: SingleAutoCompleteConfiguration = { - initialItems: (data?: any) => this.query(this.buildAutocompleteLookup()).pipe(map(x => x.items)), - filterFn: (searchQuery: string, data?: any) => this.query(this.buildAutocompleteLookup(searchQuery)).pipe(map(x => x.items)), - getSelectedItem: (selectedItem: any) => this.query(this.buildAutocompleteLookup(null, null, [selectedItem])).pipe(map(x => x.items[0])), + initialItems: (data?: any) => this.query(this.buildAutocompleteLookup([IsActive.Active])).pipe(map(x => x.items)), + filterFn: (searchQuery: string, data?: any) => this.query(this.buildAutocompleteLookup([IsActive.Active], searchQuery)).pipe(map(x => x.items)), + getSelectedItem: (selectedItem: any) => this.query(this.buildAutocompleteLookup([IsActive.Active, IsActive.Inactive], null, null, [selectedItem])).pipe(map(x => x.items[0])), displayFn: (item: Dmp) => item.label, titleFn: (item: Dmp) => item.label, valueAssign: (item: Dmp) => item.id, @@ -218,20 +218,20 @@ export class DmpService { // tslint:disable-next-line: member-ordering multipleAutocompleteConfiguration: MultipleAutoCompleteConfiguration = { - initialItems: (excludedItems: any[], data?: any) => this.query(this.buildAutocompleteLookup(null, excludedItems ? excludedItems : null)).pipe(map(x => x.items)), - filterFn: (searchQuery: string, excludedItems: any[]) => this.query(this.buildAutocompleteLookup(searchQuery, excludedItems)).pipe(map(x => x.items)), - getSelectedItems: (selectedItems: any[]) => this.query(this.buildAutocompleteLookup(null, null, selectedItems)).pipe(map(x => x.items)), + initialItems: (excludedItems: any[], data?: any) => this.query(this.buildAutocompleteLookup([IsActive.Active], null, excludedItems ? excludedItems : null)).pipe(map(x => x.items)), + filterFn: (searchQuery: string, excludedItems: any[]) => this.query(this.buildAutocompleteLookup([IsActive.Active],searchQuery, excludedItems)).pipe(map(x => x.items)), + getSelectedItems: (selectedItems: any[]) => this.query(this.buildAutocompleteLookup([IsActive.Active, IsActive.Inactive], null, null, selectedItems)).pipe(map(x => x.items)), displayFn: (item: Dmp) => item.label, titleFn: (item: Dmp) => item.label, valueAssign: (item: Dmp) => item.id, }; - public buildAutocompleteLookup(like?: string, excludedIds?: Guid[], ids?: Guid[], statuses?: DmpStatus[], dmpDescriptionTemplateSubQuery?: DmpDescriptionTemplateLookup): DmpLookup { + public buildAutocompleteLookup(isActive: IsActive[], like?: string, excludedIds?: Guid[], ids?: Guid[], statuses?: DmpStatus[], dmpDescriptionTemplateSubQuery?: DmpDescriptionTemplateLookup): DmpLookup { const lookup: DmpLookup = new DmpLookup(); lookup.page = { size: 100, offset: 0 }; if (excludedIds && excludedIds.length > 0) { lookup.excludedIds = excludedIds; } if (ids && ids.length > 0) { lookup.ids = ids; } - lookup.isActive = [IsActive.Active]; + lookup.isActive = isActive; lookup.statuses = statuses; lookup.project = { fields: [ diff --git a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete-configuration.ts b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete-configuration.ts index 33ec75ee1..17898d24f 100644 --- a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete-configuration.ts +++ b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete-configuration.ts @@ -30,6 +30,8 @@ export interface MultipleAutoCompleteConfiguration { valueAssign?: (selectedItem: any) => any; // Callback to provide equals function betwen the values uniqueAssign?: (selectedItem: any) => any; + // Get selected items. Used when valueAssign is used so the full object can be retrieved for presentation. + canRemoveItem?: (selectedItem: any) => { canRemove: boolean, message: string }; // Property formating template optionTemplate?: TemplateRef; // Property formatting component @@ -39,8 +41,9 @@ export interface MultipleAutoCompleteConfiguration { // Display icon that opens popup popupItemActionIcon?: string; + autoSelectFirstOptionOnBlur?: boolean; - appendClassToItem?: {class: string, applyFunc: (item:any) => boolean}[]; + appendClassToItem?: { class: string, applyFunc: (item: any) => boolean }[]; } diff --git a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.html b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.html index b69c9919d..43f8b0746 100644 --- a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.html +++ b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.html @@ -4,14 +4,14 @@
- + {{_displayFn(selectedItem)}} - diff --git a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.ts b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.ts index 920d1d346..abad96f88 100644 --- a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.ts +++ b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.ts @@ -96,7 +96,6 @@ export class MultipleAutoCompleteComponent extends _CustomComponentMixinBase imp _selectedItems: Map = new Map(); _groupedItems: Observable; selectable = false; - removable = true; selected: boolean = false; get empty() { @@ -434,6 +433,21 @@ export class MultipleAutoCompleteComponent extends _CustomComponentMixinBase imp this._items = null; } + _canRemoveItem(item: any): boolean { + if(this.configuration.canRemoveItem != null) { + return this.configuration.canRemoveItem(item).canRemove; + } + return true; + } + + _canRemoveItemMessage(item: any): string { + if(this.configuration.canRemoveItem != null) { + const canRemoveResuslt = this.configuration.canRemoveItem(item); + if (canRemoveResuslt.canRemove) return canRemoveResuslt.message; + } + return null; + } + _removeSelectedItem(item: any, event: MouseEvent): void { if (event != null) { event.stopPropagation(); } const valueToDelete = this._valueToAssign(item); diff --git a/notification-service/notification/src/main/java/gr/cite/notification/common/scope/tenant/TenantScope.java b/notification-service/notification/src/main/java/gr/cite/notification/common/scope/tenant/TenantScope.java index 0a27d4cc6..349cf0707 100644 --- a/notification-service/notification/src/main/java/gr/cite/notification/common/scope/tenant/TenantScope.java +++ b/notification-service/notification/src/main/java/gr/cite/notification/common/scope/tenant/TenantScope.java @@ -11,6 +11,8 @@ import javax.management.InvalidApplicationException; import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; +@Component +@RequestScope public class TenantScope { public static final String TenantReplaceParameter = "::TenantCode::"; private final MultitenancyProperties multitenancy; @@ -120,6 +122,3 @@ public class TenantScope { } } } - - - diff --git a/notification-service/notification/src/main/java/gr/cite/notification/data/tenant/TenantListener.java b/notification-service/notification/src/main/java/gr/cite/notification/data/tenant/TenantListener.java index 04b6ad2fb..40ef56aee 100644 --- a/notification-service/notification/src/main/java/gr/cite/notification/data/tenant/TenantListener.java +++ b/notification-service/notification/src/main/java/gr/cite/notification/data/tenant/TenantListener.java @@ -14,6 +14,7 @@ import org.springframework.beans.factory.annotation.Autowired; import javax.management.InvalidApplicationException; import java.util.UUID; + public class TenantListener { private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantListener.class)); private final TenantScope tenantScope;