package eu.eudat.service.deposit; import eu.eudat.authorization.AuthorizationFlags; import eu.eudat.authorization.Permission; import eu.eudat.authorization.authorizationcontentresolver.AuthorizationContentResolver; import eu.eudat.commonmodels.models.FileEnvelopeModel; import eu.eudat.commonmodels.models.dmp.DmpModel; import eu.eudat.commons.enums.StorageType; import eu.eudat.commons.scope.user.UserScope; import eu.eudat.data.DmpEntity; import eu.eudat.depositinterface.repository.DepositClient; import eu.eudat.depositinterface.repository.DepositConfiguration; import eu.eudat.model.EntityDoi; import eu.eudat.model.StorageFile; import eu.eudat.model.builder.commonmodels.DepositConfigurationBuilder; import eu.eudat.model.builder.commonmodels.dmp.DmpCommonModelBuilder; import eu.eudat.model.persist.StorageFilePersist; import eu.eudat.model.persist.deposit.DepositAuthenticateRequest; import eu.eudat.model.persist.deposit.DepositRequest; import eu.eudat.model.persist.EntityDoiPersist; import eu.eudat.query.DmpQuery; import eu.eudat.service.entitydoi.EntityDoiService; import eu.eudat.service.storage.StorageFileProperties; import eu.eudat.service.storage.StorageFileService; import eu.eudat.service.transformer.FileTransformerService; import gr.cite.commons.web.oidc.filter.webflux.TokenExchangeCacheService; import gr.cite.commons.web.authz.service.AuthorizationService; import gr.cite.commons.web.oidc.filter.webflux.TokenExchangeFilterFunction; import gr.cite.commons.web.oidc.filter.webflux.TokenExchangeModel; import gr.cite.tools.data.builder.BuilderFactory; import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.exception.MyNotFoundException; import gr.cite.tools.fieldset.BaseFieldSet; import gr.cite.tools.fieldset.FieldSet; import gr.cite.tools.validation.ValidatorFactory; import org.apache.commons.io.FilenameUtils; import org.slf4j.Logger; 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 org.springframework.web.reactive.function.client.WebClient; import java.io.IOException; import java.net.URI; import java.net.URLConnection; import java.time.Duration; import java.util.*; @Service public class DepositServiceImpl implements DepositService { private static final Logger logger = LoggerFactory.getLogger(DepositServiceImpl.class); private final DepositProperties depositProperties; private final Map clients; private final TokenExchangeCacheService tokenExchangeCacheService; private final AuthorizationService authorizationService; private final EntityDoiService doiService; private final QueryFactory queryFactory; private final MessageSource messageSource; private final BuilderFactory builderFactory; private final DepositConfigurationCacheService depositConfigurationCacheService; private final FileTransformerService fileTransformerService; private final StorageFileService storageFileService; private final UserScope userScope; private final ValidatorFactory validatorFactory; private final StorageFileProperties storageFileProperties; private final AuthorizationContentResolver authorizationContentResolver; @Autowired public DepositServiceImpl(DepositProperties depositProperties, TokenExchangeCacheService tokenExchangeCacheService, AuthorizationService authorizationService, EntityDoiService doiService, QueryFactory queryFactory, MessageSource messageSource, BuilderFactory builderFactory, DepositConfigurationCacheService depositConfigurationCacheService, FileTransformerService fileTransformerService, StorageFileService storageFileService, UserScope userScope, ValidatorFactory validatorFactory, StorageFileProperties storageFileProperties, AuthorizationContentResolver authorizationContentResolver) { this.depositProperties = depositProperties; this.tokenExchangeCacheService = tokenExchangeCacheService; this.authorizationService = authorizationService; this.doiService = doiService; this.queryFactory = queryFactory; this.messageSource = messageSource; this.builderFactory = builderFactory; this.depositConfigurationCacheService = depositConfigurationCacheService; this.fileTransformerService = fileTransformerService; this.storageFileService = storageFileService; this.userScope = userScope; this.validatorFactory = validatorFactory; this.storageFileProperties = storageFileProperties; this.authorizationContentResolver = authorizationContentResolver; this.clients = new HashMap<>(); } private DepositClient getDepositClient(String repositoryId) { if (this.clients.containsKey(repositoryId)) return this.clients.get(repositoryId); //GK: It's register time DepositProperties.DepositSource source = depositProperties.getSources().stream().filter(depositSource -> depositSource.getRepositoryId().equals(repositoryId)).findFirst().orElse(null); if (source != null) { String host = URI.create(source.getUrl()).getHost(); TokenExchangeModel tokenExchangeModel = new TokenExchangeModel("deposit:" + source.getRepositoryId(), source.getIssuerUrl(), source.getClientId(), source.getClientSecret(), source.getScope()); TokenExchangeFilterFunction apiKeyExchangeFilterFunction = new TokenExchangeFilterFunction(this.tokenExchangeCacheService, tokenExchangeModel); WebClient webClient = WebClient.builder().baseUrl(source.getUrl() + "/api/deposit").filters(exchangeFilterFunctions -> exchangeFilterFunctions.add(apiKeyExchangeFilterFunction)).build(); DepositClientImpl repository = new DepositClientImpl(webClient); this.clients.put(source.getRepositoryId(), repository); return repository; } return null; } @Override public List getAvailableConfigurations(FieldSet fieldSet) { this.authorizationService.authorizeForce(Permission.BrowseDeposit, Permission.DeferredAffiliation); List configurations = new ArrayList<>(); for (DepositProperties.DepositSource depositSource : depositProperties.getSources()) { DepositConfigurationCacheService.DepositConfigurationCacheValue cacheValue = this.depositConfigurationCacheService.lookup(this.depositConfigurationCacheService.buildKey(depositSource.getRepositoryId())); if (cacheValue == null){ DepositClient depositClient = getDepositClient(depositSource.getRepositoryId()); if (depositClient == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{depositSource.getRepositoryId(), DepositClient.class.getSimpleName()}, LocaleContextHolder.getLocale())); DepositConfiguration configuration = depositClient.getConfiguration(); cacheValue = new DepositConfigurationCacheService.DepositConfigurationCacheValue(depositSource.getRepositoryId(), configuration); this.depositConfigurationCacheService.put(cacheValue); } eu.eudat.model.deposit.DepositConfiguration depositConfiguration = this.builderFactory.builder(DepositConfigurationBuilder.class).build(fieldSet, cacheValue.getConfiguration()); configurations.add(depositConfiguration); } return configurations; } @Override public EntityDoi deposit(DepositRequest dmpDepositModel) throws Exception { this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.dmpAffiliation(dmpDepositModel.getDmpId())), Permission.DepositDmp); //GK: First get the right client DepositClient depositClient = getDepositClient(dmpDepositModel.getRepositoryId()); if (depositClient == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{dmpDepositModel.getRepositoryId(), DepositClient.class.getSimpleName()}, LocaleContextHolder.getLocale())); //GK: Second get the Target Data Management Plan DmpEntity dmpEntity = this.queryFactory.query(DmpQuery.class).ids(dmpDepositModel.getDmpId()).first(); if (dmpEntity == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{dmpDepositModel.getDmpId(), DmpEntity.class.getSimpleName()}, LocaleContextHolder.getLocale())); //GK: Forth make the required files to be uploaded with the deposit //TODO: Properly create required files DepositProperties.DepositSource source = depositProperties.getSources().stream().filter(depositSource -> depositSource.getRepositoryId().equals(dmpDepositModel.getRepositoryId())).findFirst().orElse(null); if (source == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{dmpDepositModel.getRepositoryId(), DepositProperties.DepositSource.class.getSimpleName()}, LocaleContextHolder.getLocale())); eu.eudat.model.file.FileEnvelope pdfFile = this.fileTransformerService.exportDmp(dmpEntity.getId(), source.getPdfTransformerId(),"pdf"); eu.eudat.model.file.FileEnvelope rda = this.fileTransformerService.exportDmp(dmpEntity.getId(), source.getRdaTransformerId(),"json"); FileEnvelopeModel pdfEnvelope = new FileEnvelopeModel(); FileEnvelopeModel jsonEnvelope = new FileEnvelopeModel(); pdfEnvelope.setFilename(pdfFile.getFilename()); jsonEnvelope.setMimeType("application/pdf"); jsonEnvelope.setFilename(rda.getFilename()); jsonEnvelope.setMimeType("application/json"); if (!depositClient.getConfiguration().isUseSharedStorage()){ pdfEnvelope.setFile(pdfFile.getFile()); jsonEnvelope.setFile(rda.getFile()); } else { pdfEnvelope.setFileRef(this.addFileToSharedStorage(pdfFile)); jsonEnvelope.setFileRef(this.addFileToSharedStorage(rda)); } //GK: Fifth Transform them to the DepositModel DmpModel depositModel = this.builderFactory.builder(DmpCommonModelBuilder.class).useSharedStorage(depositClient.getConfiguration().isUseSharedStorage()).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission) .setRepositoryId(dmpDepositModel.getRepositoryId()).setPdfFile(pdfEnvelope).setRdaJsonFile(jsonEnvelope).build(dmpEntity); //GK: Sixth Perform the deposit String doi = depositClient.deposit(depositModel, dmpDepositModel.getAccessToken()); //GK: Something has gone wrong return null if (doi.isEmpty()) return null; //GK: doi is fine store it in database EntityDoiPersist doiPersist = new EntityDoiPersist(); doiPersist.setRepositoryId(dmpDepositModel.getRepositoryId()); doiPersist.setDoi(doi); doiPersist.setEntityId(dmpEntity.getId()); return doiService.persist(doiPersist, dmpDepositModel.getProject()); } private String addFileToSharedStorage(eu.eudat.model.file.FileEnvelope file) throws IOException { StorageFilePersist storageFilePersist = new StorageFilePersist(); storageFilePersist.setName(FilenameUtils.removeExtension(file.getFilename())); storageFilePersist.setExtension(FilenameUtils.getExtension(file.getFilename())); storageFilePersist.setMimeType(URLConnection.guessContentTypeFromName(file.getFilename())); storageFilePersist.setOwnerId(this.userScope.getUserIdSafe()); storageFilePersist.setStorageType(StorageType.Temp); storageFilePersist.setLifetime(Duration.ofSeconds(this.storageFileProperties.getTempStoreLifetimeSeconds())); //TODO this.validatorFactory.validator(StorageFilePersist.StorageFilePersistValidator.class).validateForce(storageFilePersist); StorageFile persisted = this.storageFileService.persistBytes(storageFilePersist, file.getFile(), new BaseFieldSet(StorageFile._id, StorageFile._fileRef)); return persisted.getFileRef(); } @Override public String getLogo(String repositoryId) { this.authorizationService.authorizeForce(Permission.BrowseDeposit, Permission.DeferredAffiliation); DepositClient depositClient = getDepositClient(repositoryId); if (depositClient == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{repositoryId, DepositClient.class.getSimpleName()}, LocaleContextHolder.getLocale())); return depositClient.getLogo(); } @Override public String authenticate(DepositAuthenticateRequest model) { this.authorizationService.authorizeForce(Permission.BrowseDeposit, Permission.DeferredAffiliation); DepositClient depositClient = getDepositClient(model.getRepositoryId()); if (depositClient == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getRepositoryId(), DepositClient.class.getSimpleName()}, LocaleContextHolder.getLocale())); return depositClient.authenticate(model.getCode()); } }