argos/dmp-backend/core/src/main/java/eu/eudat/service/tenantconfiguration/TenantConfigurationServiceI...

283 lines
17 KiB
Java

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.scope.tenant.TenantScope;
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.TenantEntity;
import eu.eudat.data.TenantEntityManager;
import eu.eudat.errorcode.ErrorThesaurusProperties;
import eu.eudat.event.EventBroker;
import eu.eudat.event.TenantConfigurationTouchedEvent;
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.query.TenantConfigurationQuery;
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.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.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;
private final QueryFactory queryFactory;
private final EventBroker eventBroker;
private final TenantScope tenantScope;
@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, QueryFactory queryFactory, EventBroker eventBroker, TenantScope tenantScope) {
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;
this.queryFactory = queryFactory;
this.eventBroker = eventBroker;
this.tenantScope = tenantScope;
}
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());
}
TenantConfigurationQuery tenantConfigurationQuery = this.queryFactory.query(TenantConfigurationQuery.class).excludedIds(data.getId()).isActive(IsActive.Active).types(data.getType());
if (data.getTenantId() == null) tenantConfigurationQuery.tenantIsSet(false);
else tenantConfigurationQuery.tenantIsSet(true).tenantIds(data.getTenantId());
if (tenantConfigurationQuery.count() > 0)throw new MyValidationException(this.errors.getMultipleTenantConfigurationTypeNotAllowed().getCode(), this.errors.getMultipleTenantConfigurationTypeNotAllowed().getMessage());
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();
if (data.getTenantId() != null) {
TenantEntity tenant = this.entityManager.find(TenantEntity.class, data.getTenantId());
if (tenant == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{data.getTenantId(), TenantEntity.class.getSimpleName()}, LocaleContextHolder.getLocale()));
this.eventBroker.emit(new TenantConfigurationTouchedEvent(tenant.getId(), tenant.getCode(), data.getType()));
} else {
this.eventBroker.emit(new TenantConfigurationTouchedEvent(data.getId(), this.tenantScope.getDefaultTenantCode(), data.getType()));
}
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.setDisableSystemSources(persist.getDisableSystemSources());
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.setDisableSystemSources(persist.getDisableSystemSources());
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));
if (data.getTenantId() != null) {
TenantEntity tenant = this.entityManager.find(TenantEntity.class, data.getTenantId());
if (tenant == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{data.getTenantId(), TenantEntity.class.getSimpleName()}, LocaleContextHolder.getLocale()));
this.eventBroker.emit(new TenantConfigurationTouchedEvent(tenant.getId(), tenant.getCode(), data.getType()));
} else {
this.eventBroker.emit(new TenantConfigurationTouchedEvent(data.getId(), this.tenantScope.getDefaultTenantCode(), data.getType()));
}
}
}