From 625a322467c8fefee5bc82e9c7d8bc7282ae9955 Mon Sep 17 00:00:00 2001 From: George Kalampokis Date: Mon, 18 Dec 2023 12:55:19 +0200 Subject: [PATCH] Add File transformer integration --- dmp-backend/core/pom.xml | 5 + .../FileTransformerConfigurationCache.java | 24 + .../transformer/TransformerCacheOptions.java | 8 + .../transformer/TransformerConfiguration.java | 9 + .../transformer/TransformerProperties.java | 65 +++ .../model/file/TransformerCacheModel.java | 22 + .../repository/TransformerRepository.java | 51 ++ .../description/DescriptionService.java | 4 + .../description/DescriptionServiceImpl.java | 42 +- .../java/eu/eudat/service/dmp/DmpService.java | 4 +- .../eu/eudat/service/dmp/DmpServiceImpl.java | 27 +- .../transformer/FileTransformerService.java | 466 ++++++++++++++++++ .../utilities/webclient/WebClientUtils.java | 52 ++ .../controllers/v2/DescriptionController.java | 10 + .../eudat/controllers/v2/DmpController.java | 6 +- .../src/main/resources/config/application.yml | 4 +- .../web/src/main/resources/config/cache.yml | 24 +- .../src/main/resources/config/transformer.yml | 11 + .../description/description.service.ts | 11 +- .../src/app/core/services/dmp/dmp.service.ts | 14 + .../core/services/matomo/matomo-service.ts | 2 +- .../description-listing-item.component.ts | 36 +- .../description-overview.component.ts | 35 +- .../dmp-listing-item.component.ts | 34 +- .../ui/dmp/overview/dmp-overview.component.ts | 35 +- 25 files changed, 912 insertions(+), 89 deletions(-) create mode 100644 dmp-backend/core/src/main/java/eu/eudat/cache/transformer/FileTransformerConfigurationCache.java create mode 100644 dmp-backend/core/src/main/java/eu/eudat/configurations/transformer/TransformerCacheOptions.java create mode 100644 dmp-backend/core/src/main/java/eu/eudat/configurations/transformer/TransformerConfiguration.java create mode 100644 dmp-backend/core/src/main/java/eu/eudat/configurations/transformer/TransformerProperties.java create mode 100644 dmp-backend/core/src/main/java/eu/eudat/model/file/TransformerCacheModel.java create mode 100644 dmp-backend/core/src/main/java/eu/eudat/repository/TransformerRepository.java create mode 100644 dmp-backend/core/src/main/java/eu/eudat/service/transformer/FileTransformerService.java create mode 100644 dmp-backend/core/src/main/java/eu/eudat/utilities/webclient/WebClientUtils.java create mode 100644 dmp-backend/web/src/main/resources/config/transformer.yml diff --git a/dmp-backend/core/pom.xml b/dmp-backend/core/pom.xml index 6c607edd2..9f1a83c88 100644 --- a/dmp-backend/core/pom.xml +++ b/dmp-backend/core/pom.xml @@ -39,6 +39,11 @@ repositorydepositbase 2.0.0 + + gr.cite.opendmp + file-transformer-base + 1.0-SNAPSHOT + gr.cite elastic diff --git a/dmp-backend/core/src/main/java/eu/eudat/cache/transformer/FileTransformerConfigurationCache.java b/dmp-backend/core/src/main/java/eu/eudat/cache/transformer/FileTransformerConfigurationCache.java new file mode 100644 index 000000000..cff46434e --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/cache/transformer/FileTransformerConfigurationCache.java @@ -0,0 +1,24 @@ +package eu.eudat.cache.transformer; + + +import eu.eudat.configurations.deposit.DepositCacheOptions; +import eu.eudat.configurations.transformer.TransformerCacheOptions; +import eu.eudat.model.file.TransformerCacheModel; +import gr.cite.tools.cache.CacheService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +public class FileTransformerConfigurationCache extends CacheService { + @Autowired + public FileTransformerConfigurationCache(TransformerCacheOptions options) { + super(options); + } + + @Override + protected Class valueClass() { + return TransformerCacheModel.class; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/configurations/transformer/TransformerCacheOptions.java b/dmp-backend/core/src/main/java/eu/eudat/configurations/transformer/TransformerCacheOptions.java new file mode 100644 index 000000000..a7a1508d6 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/configurations/transformer/TransformerCacheOptions.java @@ -0,0 +1,8 @@ +package eu.eudat.configurations.transformer; + +import gr.cite.tools.cache.CacheOptions; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties(prefix = "cache.transformer") +public class TransformerCacheOptions extends CacheOptions { +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/configurations/transformer/TransformerConfiguration.java b/dmp-backend/core/src/main/java/eu/eudat/configurations/transformer/TransformerConfiguration.java new file mode 100644 index 000000000..bdf666a01 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/configurations/transformer/TransformerConfiguration.java @@ -0,0 +1,9 @@ +package eu.eudat.configurations.transformer; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableConfigurationProperties({TransformerProperties.class, TransformerCacheOptions.class}) +public class TransformerConfiguration { +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/configurations/transformer/TransformerProperties.java b/dmp-backend/core/src/main/java/eu/eudat/configurations/transformer/TransformerProperties.java new file mode 100644 index 000000000..7457f28a3 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/configurations/transformer/TransformerProperties.java @@ -0,0 +1,65 @@ +package eu.eudat.configurations.transformer; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.bind.ConstructorBinding; + +import java.util.List; + +@ConfigurationProperties(prefix = "transformer") +public class TransformerProperties { + + private final List sources; + + @ConstructorBinding + public TransformerProperties(List sources) { + this.sources = sources; + } + + public List getSources() { + return sources; + } + + public static class TransformerSource { + + private final String url; + private final List codes; + private final String issuerUrl; + private final String clientId; + private final String clientSecret; + private final String scope; + + @ConstructorBinding + public TransformerSource(String url, List codes, String issuerUrl, String clientId, String clientSecret, String scope) { + this.url = url; + this.codes = codes; + this.issuerUrl = issuerUrl; + this.clientId = clientId; + this.clientSecret = clientSecret; + this.scope = scope; + } + + public String getUrl() { + return url; + } + + public String getIssuerUrl() { + return issuerUrl; + } + + public String getClientId() { + return clientId; + } + + public String getClientSecret() { + return clientSecret; + } + + public String getScope() { + return scope; + } + + public List getCodes() { + return codes; + } + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/file/TransformerCacheModel.java b/dmp-backend/core/src/main/java/eu/eudat/model/file/TransformerCacheModel.java new file mode 100644 index 000000000..2be248f43 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/model/file/TransformerCacheModel.java @@ -0,0 +1,22 @@ +package eu.eudat.model.file; + +import java.util.List; + +public class TransformerCacheModel { + private List formats; + + public TransformerCacheModel() { + } + + public TransformerCacheModel(List formats) { + this.formats = formats; + } + + public List getFormats() { + return formats; + } + + public void setFormats(List formats) { + this.formats = formats; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/repository/TransformerRepository.java b/dmp-backend/core/src/main/java/eu/eudat/repository/TransformerRepository.java new file mode 100644 index 000000000..d33508d60 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/repository/TransformerRepository.java @@ -0,0 +1,51 @@ +package eu.eudat.repository; + +import eu.eudat.file.transformer.executor.FileTransformerExecutor; +import eu.eudat.file.transformer.model.DescriptionFileTransformerModel; +import eu.eudat.file.transformer.model.DmpFileTransformerModel; +import eu.eudat.file.transformer.model.ExtraPropertiesModel; +import eu.eudat.file.transformer.model.file.FileEnvelope; +import eu.eudat.utilities.webclient.WebClientUtils; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.web.reactive.function.client.WebClient; + +import javax.management.InvalidApplicationException; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +public class TransformerRepository implements FileTransformerExecutor { + + private final WebClient transformerClient; + + public TransformerRepository(WebClient transformerClient) { + this.transformerClient = transformerClient; + } + + @Override + public FileEnvelope exportDmp(DmpFileTransformerModel dmpFileTransformerModel, ExtraPropertiesModel map) throws InvalidApplicationException, IOException { + return transformerClient.post().uri("/export/dmp", uriBuilder -> WebClientUtils.buildParameters(uriBuilder, map)).bodyValue(dmpFileTransformerModel).exchangeToMono(mono -> mono.bodyToMono(FileEnvelope.class)).block(); + } + + @Override + public DmpFileTransformerModel importFileToDmp(FileEnvelope fileEnvelope) { + return transformerClient.post().uri("/import/dmp").bodyValue(fileEnvelope).exchangeToMono(mono -> mono.bodyToMono(DmpFileTransformerModel.class)).block(); + } + + @Override + public FileEnvelope exportDescription(DescriptionFileTransformerModel descriptionFileTransformerModel, ExtraPropertiesModel map) throws InvalidApplicationException, IOException { + return transformerClient.post().uri("/export/description", uriBuilder -> WebClientUtils.buildParameters(uriBuilder, map)).bodyValue(descriptionFileTransformerModel).exchangeToMono(mono -> mono.bodyToMono(FileEnvelope.class)).block(); + } + + @Override + public DescriptionFileTransformerModel importFileToDescription(FileEnvelope fileEnvelope) { + return transformerClient.post().uri("/import/description").bodyValue(fileEnvelope).exchangeToMono(mono -> mono.bodyToMono(DescriptionFileTransformerModel.class)).block(); + } + + @Override + public List getSupportedFileFormats() { + return transformerClient.get().uri("/formats").exchangeToMono(mono -> mono.bodyToMono(new ParameterizedTypeReference>() {})).block(); + } + + +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/description/DescriptionService.java b/dmp-backend/core/src/main/java/eu/eudat/service/description/DescriptionService.java index e7c6df3fe..42ad3f7af 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/description/DescriptionService.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/description/DescriptionService.java @@ -9,6 +9,7 @@ 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 org.springframework.http.ResponseEntity; import javax.management.InvalidApplicationException; import java.io.IOException; @@ -23,4 +24,7 @@ public interface DescriptionService { void clone(UUID dmpId, UUID descriptionId) throws InvalidApplicationException; + ResponseEntity export(UUID id, DescriptionServiceImpl.DescriptionExportType exportType) throws InvalidApplicationException, IOException; + + } diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/description/DescriptionServiceImpl.java b/dmp-backend/core/src/main/java/eu/eudat/service/description/DescriptionServiceImpl.java index c343dbae1..bb2901e7a 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/description/DescriptionServiceImpl.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/description/DescriptionServiceImpl.java @@ -28,6 +28,7 @@ import eu.eudat.model.builder.DescriptionBuilder; import eu.eudat.model.deleter.DescriptionDeleter; import eu.eudat.model.deleter.DescriptionReferenceDeleter; import eu.eudat.model.deleter.DescriptionTagDeleter; +import eu.eudat.model.file.FileEnvelope; import eu.eudat.model.persist.DescriptionPersist; import eu.eudat.model.persist.DescriptionReferencePersist; import eu.eudat.model.persist.DescriptionStatusPersist; @@ -36,6 +37,7 @@ import eu.eudat.model.persist.descriptionproperties.FieldPersist; import eu.eudat.model.persist.descriptionproperties.PropertyDefinitionPersist; import eu.eudat.model.persist.referencedefinition.DefinitionPersist; import eu.eudat.query.*; +import eu.eudat.service.transformer.FileTransformerService; import gr.cite.commons.web.authz.service.AuthorizationService; import gr.cite.tools.data.builder.BuilderFactory; import gr.cite.tools.data.deleter.DeleterFactory; @@ -55,10 +57,15 @@ 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.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import javax.management.InvalidApplicationException; import java.io.IOException; +import java.nio.file.Files; import java.time.Instant; import java.util.*; import java.util.stream.Collectors; @@ -90,6 +97,7 @@ public class DescriptionServiceImpl implements DescriptionService { private final UserScope userScope; private final XmlHandlingService xmlHandlingService; + private final FileTransformerService fileTransformerService; private final NotificationIntegrationEventHandler eventHandler; @@ -109,7 +117,7 @@ public class DescriptionServiceImpl implements DescriptionService { QueryFactory queryFactory, JsonHandlingService jsonHandlingService, UserScope userScope, - XmlHandlingService xmlHandlingService, NotificationIntegrationEventHandler eventHandler, NotificationProperties notificationProperties) { + XmlHandlingService xmlHandlingService, NotificationIntegrationEventHandler eventHandler, NotificationProperties notificationProperties, FileTransformerService fileTransformerService) { this.entityManager = entityManager; this.authorizationService = authorizationService; this.deleterFactory = deleterFactory; @@ -124,6 +132,7 @@ public class DescriptionServiceImpl implements DescriptionService { this.xmlHandlingService = xmlHandlingService; this.eventHandler = eventHandler; this.notificationProperties = notificationProperties; + this.fileTransformerService = fileTransformerService; } //region Persist @@ -571,4 +580,35 @@ public class DescriptionServiceImpl implements DescriptionService { //endregion + //region file export + + public enum DescriptionExportType { + Word, Pdf, Xml; + } + @Override + public ResponseEntity export(UUID id, DescriptionExportType exportType) throws InvalidApplicationException, IOException { + HttpHeaders headers = new HttpHeaders(); + String type = switch(exportType) { + case Word -> "docx"; + case Pdf -> "pdf"; + case Xml -> "xml"; + }; + + FileEnvelope fileEnvelope = this.fileTransformerService.exportDescription(id, type); + headers.add("Content-Disposition", "attachment;filename=" + fileEnvelope.getFilename()); + byte[] data = Files.readAllBytes(fileEnvelope.getFile().toPath()); + switch (exportType){ + case Xml -> { + headers.setContentType(MediaType.APPLICATION_XML); + return new ResponseEntity<>(data, headers, HttpStatus.OK); + } + case Word, Pdf -> { + headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); + return new ResponseEntity<>(data, headers, HttpStatus.OK); + } + } + return ResponseEntity.badRequest().body(new byte[]{}); + } + + //endregion } diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpService.java b/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpService.java index f1ed3d6b0..040657145 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpService.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpService.java @@ -24,7 +24,7 @@ import java.util.UUID; public interface DmpService { enum DmpExportType { - Word, Json, Xml; + Word, Pdf, Json, Xml; } Dmp persist(DmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JsonProcessingException; @@ -38,7 +38,7 @@ public interface DmpService { List assignUsers(UUID dmp, List model, FieldSet fields) throws InvalidApplicationException; Dmp removeUser(DmpUserRemovePersist model, FieldSet fields) throws InvalidApplicationException; - ResponseEntity export(UUID id, DmpExportType exportType); + ResponseEntity export(UUID id, DmpExportType exportType) throws InvalidApplicationException, IOException; void inviteUsers(UUID id, DmpUserInvitePersist model) throws InvalidApplicationException, JAXBException; diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpServiceImpl.java b/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpServiceImpl.java index 770955a3a..388374026 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpServiceImpl.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpServiceImpl.java @@ -30,6 +30,7 @@ import eu.eudat.model.UserContactInfo; import eu.eudat.model.builder.DmpBuilder; import eu.eudat.model.builder.DmpUserBuilder; import eu.eudat.model.deleter.*; +import eu.eudat.model.file.FileEnvelope; import eu.eudat.model.persist.*; import eu.eudat.model.persist.actionconfirmation.DmpInvitationPersist; import eu.eudat.model.persist.dmpproperties.DmpBlueprintValuePersist; @@ -40,6 +41,7 @@ import eu.eudat.model.persist.referencedefinition.FieldPersist; import eu.eudat.query.*; import eu.eudat.service.actionconfirmation.ActionConfirmationService; import eu.eudat.service.description.DescriptionService; +import eu.eudat.service.transformer.FileTransformerService; import gr.cite.commons.web.authz.service.AuthorizationService; import gr.cite.tools.data.builder.BuilderFactory; import gr.cite.tools.data.deleter.DeleterFactory; @@ -69,6 +71,7 @@ import javax.management.InvalidApplicationException; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import java.io.IOException; +import java.nio.file.Files; import java.time.Instant; import java.util.*; import java.util.stream.Collectors; @@ -103,6 +106,7 @@ public class DmpServiceImpl implements DmpService { private final EventBroker eventBroker; private final DescriptionService descriptionService; + private final FileTransformerService fileTransformerService; private final NotificationIntegrationEventHandler eventHandler; @@ -122,7 +126,7 @@ public class DmpServiceImpl implements DmpService { MessageSource messageSource, XmlHandlingService xmlHandlingService, JsonHandlingService jsonHandlingService, - UserScope userScope, EventBroker eventBroker, DescriptionService descriptionService, NotificationIntegrationEventHandler eventHandler, NotificationProperties notificationProperties, ActionConfirmationService actionConfirmationService) { + UserScope userScope, EventBroker eventBroker, DescriptionService descriptionService, NotificationIntegrationEventHandler eventHandler, NotificationProperties notificationProperties, ActionConfirmationService actionConfirmationService, FileTransformerService fileTransformerService) { this.entityManager = entityManager; this.authorizationService = authorizationService; this.deleterFactory = deleterFactory; @@ -136,6 +140,7 @@ public class DmpServiceImpl implements DmpService { this.userScope = userScope; this.eventBroker = eventBroker; this.descriptionService = descriptionService; + this.fileTransformerService = fileTransformerService; this.eventHandler = eventHandler; this.notificationProperties = notificationProperties; this.actionConfirmationService = actionConfirmationService; @@ -451,20 +456,30 @@ public class DmpServiceImpl implements DmpService { } @Override - public ResponseEntity export(UUID id, DmpExportType exportType) { + public ResponseEntity export(UUID id, DmpExportType exportType) throws InvalidApplicationException, IOException { HttpHeaders headers = new HttpHeaders(); + String type = switch(exportType) { + case Word -> "docx"; + case Pdf -> "pdf"; + case Json -> "json"; + case Xml -> "xml"; + }; + + FileEnvelope fileEnvelope = this.fileTransformerService.exportDmp(id, type); + headers.add("Content-Disposition", "attachment;filename=" + fileEnvelope.getFilename()); + byte[] data = Files.readAllBytes(fileEnvelope.getFile().toPath()); switch (exportType){ case Xml -> { headers.setContentType(MediaType.APPLICATION_XML); - return new ResponseEntity<>(new byte[]{}, headers, HttpStatus.OK); + return new ResponseEntity<>(data, headers, HttpStatus.OK); } case Json -> { headers.setContentType(MediaType.APPLICATION_JSON); - return new ResponseEntity<>(new byte[]{}, headers, HttpStatus.OK); + return new ResponseEntity<>(data, headers, HttpStatus.OK); } - case Word -> { + case Word, Pdf -> { headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); - return new ResponseEntity<>(new byte[]{}, headers, HttpStatus.OK); + return new ResponseEntity<>(data, headers, HttpStatus.OK); } } return ResponseEntity.badRequest().body(new byte[]{}); diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/transformer/FileTransformerService.java b/dmp-backend/core/src/main/java/eu/eudat/service/transformer/FileTransformerService.java new file mode 100644 index 000000000..38b47cf38 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/service/transformer/FileTransformerService.java @@ -0,0 +1,466 @@ +package eu.eudat.service.transformer; + +import eu.eudat.authorization.AuthorizationFlags; +import eu.eudat.authorization.Permission; +import eu.eudat.cache.transformer.FileTransformerConfigurationCache; +import eu.eudat.commons.JsonHandlingService; +import eu.eudat.commons.enums.DmpUserRole; +import eu.eudat.configurations.transformer.TransformerProperties; +import eu.eudat.convention.ConventionService; +import eu.eudat.file.transformer.model.DescriptionFileTransformerModel; +import eu.eudat.file.transformer.model.DmpFileTransformerModel; +import eu.eudat.file.transformer.model.ExtraPropertiesModel; +import eu.eudat.file.transformer.model.descriptiontemplatedefinition.Field; +import eu.eudat.file.transformer.model.descriptiontemplatedefinition.Rule; +import eu.eudat.model.*; +import eu.eudat.model.builder.DescriptionBuilder; +import eu.eudat.model.builder.DmpBuilder; +import eu.eudat.model.descriptionproperties.PropertyDefinition; +import eu.eudat.model.descriptiontemplatedefinition.Definition; +import eu.eudat.model.descriptiontemplatedefinition.Multiplicity; +import eu.eudat.model.descriptiontemplatedefinition.Page; +import eu.eudat.model.descriptiontemplatedefinition.Section; +import eu.eudat.model.descriptiontemplatedefinition.fielddata.AutoCompleteData; +import eu.eudat.model.descriptiontemplatedefinition.fielddata.AutoCompleteSingleData; +import eu.eudat.model.descriptiontemplatedefinition.fielddata.BaseFieldData; +import eu.eudat.model.descriptiontemplatedefinition.fielddata.ComboBoxOption; +import eu.eudat.model.dmpblueprintdefinition.ExtraField; +import eu.eudat.model.dmpblueprintdefinition.SystemField; +import eu.eudat.model.file.FileEnvelope; +import eu.eudat.model.file.TransformerCacheModel; +import eu.eudat.query.DescriptionQuery; +import eu.eudat.query.DmpQuery; +import eu.eudat.query.EntityDoiQuery; +import eu.eudat.repository.TransformerRepository; +import eu.eudat.service.entitydoi.EntityDoiService; +import gr.cite.commons.web.authz.service.AuthorizationService; +import gr.cite.commons.web.oidc.filter.webflux.TokenExchangeCacheService; +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.fieldset.BaseFieldSet; +import gr.cite.tools.fieldset.FieldSet; +import jakarta.persistence.EntityManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Service; +import org.springframework.web.reactive.function.client.ExchangeFilterFunction; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; + +import javax.management.InvalidApplicationException; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URI; +import java.nio.file.Path; +import java.util.*; + +@Service +public class FileTransformerService { + private static final Logger logger = LoggerFactory.getLogger(FileTransformerService.class); + + private final TransformerProperties transformerProperties; + private final Map clients; + private final TokenExchangeCacheService tokenExchangeCacheService; + private final FileTransformerConfigurationCache fileTransformerConfigurationCache; + private final AuthorizationService authorizationService; + private final ConventionService conventionService; + private final Environment environment; + private final WebClient.Builder webClientBuilder; + private final EntityDoiService doiService; + private final ApplicationContext applicationContext; + private final JsonHandlingService jsonHandlingService; + private final QueryFactory queryFactory; + private final BuilderFactory builderFactory; + + + @Autowired + public FileTransformerService(TransformerProperties transformerProperties, TokenExchangeCacheService tokenExchangeCacheService, FileTransformerConfigurationCache fileTransformerConfigurationCache, WebClient.Builder builder, EntityManager entityManager, AuthorizationService authorizationService, ConventionService conventionService, Environment environment, DmpQuery dmpQuery, EntityDoiQuery doiQuery, EntityDoiService doiService, ApplicationContext applicationContext, JsonHandlingService jsonHandlingService, QueryFactory queryFactory, BuilderFactory builderFactory) { + this.transformerProperties = transformerProperties; + this.tokenExchangeCacheService = tokenExchangeCacheService; + this.fileTransformerConfigurationCache = fileTransformerConfigurationCache; + this.authorizationService = authorizationService; + this.conventionService = conventionService; + this.environment = environment; + this.webClientBuilder = builder; + this.doiService = doiService; + this.applicationContext = applicationContext; + this.jsonHandlingService = jsonHandlingService; + this.queryFactory = queryFactory; + this.builderFactory = builderFactory; + this.clients = new HashMap<>(); + } + + private TransformerRepository getRepository(String repoId) { + if (this.clients.containsKey(repoId)) return this.clients.get(repoId); + + //GK: It's register time + TransformerProperties.TransformerSource source = transformerProperties.getSources().stream().filter(depositSource -> depositSource.getCodes().contains(repoId)).findFirst().orElse(null); + if (source != null) { + String host = URI.create(source.getUrl()).getHost(); + TokenExchangeModel tokenExchangeModel = new TokenExchangeModel(host + "_" + source.getClientId(), source.getIssuerUrl(), source.getClientId(), source.getClientSecret(), source.getScope()); + TokenExchangeFilterFunction tokenExchangeFilterFunction = new TokenExchangeFilterFunction(this.tokenExchangeCacheService, tokenExchangeModel); + TransformerRepository repository = new TransformerRepository(webClientBuilder.baseUrl(source.getUrl() + "/api/file").filters(exchangeFilterFunctions -> { + exchangeFilterFunctions.add(tokenExchangeFilterFunction); + exchangeFilterFunctions.add(logRequest()); + }).build()); + source.getCodes().forEach(code -> this.clients.put(code, repository)); + return repository; + } + return null; + } + + + public List getAvailableConfigurations() { + TransformerCacheModel configs = fileTransformerConfigurationCache.lookup("base"); + if (configs == null) { + List configurations = new ArrayList<>(); + //GK: So much for lazy loading + List repositories = transformerProperties.getSources().stream().map(depositSource -> getRepository(depositSource.getCodes().get(0))).toList(); + + repositories.forEach((client) -> { + List repositoryConfigs = client.getSupportedFileFormats(); + if (repositoryConfigs != null && !repositoryConfigs.isEmpty()) { + configurations.addAll(repositoryConfigs); + } + }); + + configs = new TransformerCacheModel(configurations); + this.fileTransformerConfigurationCache.put("base", configs); + } + + return configs.getFormats(); + } + + public FileEnvelope exportDmp(UUID dmpId, String format) throws InvalidApplicationException, IOException { + this.authorizationService.authorize(Permission.EditDmp); + //GK: Why it is in that service, and why it's not static? + this.conventionService.isValidGuid(dmpId); + //GK: First get the right client + TransformerRepository repository = getRepository(format); + //GK: Second get the Target Data Management Plan + FieldSet fieldSet = new BaseFieldSet(Dmp._id, + Dmp._accessType, + Dmp._dmpReferences, + Dmp._blueprint, + Dmp._dmpUsers, + Dmp._createdAt, + Dmp._creator, + Dmp._description, + Dmp._descriptions, + Dmp._entityDois, + Dmp._finalizedAt, + Dmp._groupId, + Dmp._isActive, + Dmp._label, + Dmp._properties, + Dmp._language, + Dmp._publicAfter, + Dmp._status, + Dmp._updatedAt, + Dmp._version, + Dmp._versionStatus, + Dmp._dmpReferences + "." + DmpReference._id, + Dmp._dmpReferences + "." + DmpReference._data, + Dmp._dmpReferences + "." + DmpReference._reference + "." + Reference._id, + Dmp._dmpReferences + "." + DmpReference._reference + "." + Reference._description, + Dmp._dmpReferences + "." + DmpReference._reference + "." + Reference._abbreviation, + Dmp._dmpReferences + "." + DmpReference._reference + "." + Reference._definition, + Dmp._dmpReferences + "." + DmpReference._reference + "." + Reference._label, + Dmp._dmpReferences + "." + DmpReference._reference + "." + Reference._source, + Dmp._dmpReferences + "." + DmpReference._reference + "." + Reference._sourceType, + Dmp._dmpReferences + "." + DmpReference._reference + "." + Reference._type, + Dmp._dmpReferences + "." + DmpReference._reference + "." + Reference._isActive, + Dmp._dmpReferences + "." + DmpReference._reference + "." + Reference._reference, + Dmp._creator + "." + User._id, + Dmp._creator + "." + User._additionalInfo + "." + UserAdditionalInfo._avatarUrl, + Dmp._creator + "." + User._additionalInfo + "." + UserAdditionalInfo._culture, + Dmp._creator + "." + User._additionalInfo + "." + UserAdditionalInfo._language, + Dmp._creator + "." + User._additionalInfo + "." + UserAdditionalInfo._timezone, + Dmp._creator + "." + User._additionalInfo + "." + UserAdditionalInfo._roleOrganization, + Dmp._creator + "." + User._additionalInfo + "." + UserAdditionalInfo._organization, + Dmp._creator + "." + User._createdAt, + Dmp._creator + "." + User._isActive, + Dmp._creator + "." + User._name, + Dmp._creator + "." + User._roles + "." + UserRole._id, + Dmp._creator + "." + User._roles + "." + UserRole._role, + Dmp._descriptions + "." + Description._id, + Dmp._descriptions + "." + Description._label, + Dmp._descriptions + "." + Description._properties, + Dmp._descriptions + "." + Description._description, + Dmp._descriptions + "." + Description._status, + Dmp._descriptions + "." + Description._descriptionTags, + Dmp._descriptions + "." + Description._descriptionTemplate, + Dmp._descriptions + "." + Description._descriptionReferences, + Dmp._descriptions + "." + Description._isActive, + Dmp._descriptions + "." + Description._properties + "." + PropertyDefinition._fields + "." + eu.eudat.model.descriptionproperties.Field._key, + Dmp._descriptions + "." + Description._properties + "." + PropertyDefinition._fields + "." + eu.eudat.model.descriptionproperties.Field._value, + Dmp._descriptions + "." + Description._descriptionReferences + "." + DescriptionReference._id, + Dmp._descriptions + "." + Description._descriptionReferences + "." + DescriptionReference._reference, + Dmp._descriptions + "." + Description._descriptionReferences + "." + DescriptionReference._reference + "." + Reference._id, + Dmp._descriptions + "." + Description._descriptionReferences + "." + DescriptionReference._reference + "." + Reference._description, + Dmp._descriptions + "." + Description._descriptionReferences + "." + DescriptionReference._reference + "." + Reference._abbreviation, + Dmp._descriptions + "." + Description._descriptionReferences + "." + DescriptionReference._reference + "." + Reference._definition, + Dmp._descriptions + "." + Description._descriptionReferences + "." + DescriptionReference._reference + "." + Reference._label, + Dmp._descriptions + "." + Description._descriptionReferences + "." + DescriptionReference._reference + "." + Reference._source, + Dmp._descriptions + "." + Description._descriptionReferences + "." + DescriptionReference._reference + "." + Reference._sourceType, + Dmp._descriptions + "." + Description._descriptionReferences + "." + DescriptionReference._reference + "." + Reference._type, + Dmp._descriptions + "." + Description._descriptionReferences + "." + DescriptionReference._reference + "." + Reference._isActive, + Dmp._descriptions + "." + Description._descriptionReferences + "." + DescriptionReference._reference + "." + Reference._reference, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._id, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._description, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._label, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._language, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._status, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._isActive, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._groupId, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._type, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._version, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._id, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._description, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._sections, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._title, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._page, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._ordinal, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._defaultVisibility, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._extendedDescription, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._multiplicity + "." + Multiplicity._max, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._multiplicity + "." + Multiplicity._min, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._multiplicity + "." + Multiplicity._placeholder, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._multiplicity + "." + Multiplicity._tableView, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._numbering, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._id, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._title, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._description, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._ordinal, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._numbering, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._multiplicity + "." + Multiplicity._max, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._multiplicity + "." + Multiplicity._min, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._multiplicity + "." + Multiplicity._tableView, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._multiplicity + "." + Multiplicity._placeholder, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._hasCommentField, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._additionalInformation, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._extendedDescription, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._id, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._ordinal, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._numbering, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._data + "." + BaseFieldData._label, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._data + "." + BaseFieldData._fieldType, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._data + "." + AutoCompleteData._multiAutoComplete, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._data + "." + AutoCompleteData._autoCompleteSingleDataList + "." + AutoCompleteSingleData._autoCompleteOptions + "." + ComboBoxOption._label, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._data + "." + AutoCompleteData._autoCompleteSingleDataList + "." + AutoCompleteSingleData._autoCompleteOptions + "." + ComboBoxOption._uri, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._data + "." + AutoCompleteData._autoCompleteSingleDataList + "." + AutoCompleteSingleData._autoCompleteOptions + "." + ComboBoxOption._source, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._data + "." + AutoCompleteData._autoCompleteSingleDataList + "." + AutoCompleteSingleData._autoCompleteOptions + "." + ComboBoxOption._value, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._defaultValue, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._includeInExport, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._schematics, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._validations, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._visibilityRules + "." + Rule._target, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._visibilityRules + "." + Rule._value, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._pages + "." + Page._id, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._pages + "." + Page._ordinal, + Dmp._descriptions + "." + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._pages + "." + Page._title, + Dmp._descriptions + "." + Description._descriptionTags + "." + DescriptionTag._id, + Dmp._descriptions + "." + Description._descriptionTags + "." + DescriptionTag._tag + "." + Tag._id, + Dmp._descriptions + "." + Description._descriptionTags + "." + DescriptionTag._tag + "." + Tag._label, + Dmp._descriptions + "." + Description._dmpDescriptionTemplate + "." + DmpDescriptionTemplate._sectionId, + Dmp._blueprint + "." + DmpBlueprint._id, + Dmp._blueprint + "." + DmpBlueprint._label, + Dmp._blueprint + "." + DmpBlueprint._definition, + Dmp._blueprint + "." + DmpBlueprint._definition + "." + eu.eudat.model.dmpblueprintdefinition.Definition._sections + "." + eu.eudat.model.dmpblueprintdefinition.Section._id, + Dmp._blueprint + "." + DmpBlueprint._definition + "." + eu.eudat.model.dmpblueprintdefinition.Definition._sections + "." + eu.eudat.model.dmpblueprintdefinition.Section._description, + Dmp._blueprint + "." + DmpBlueprint._definition + "." + eu.eudat.model.dmpblueprintdefinition.Definition._sections + "." + eu.eudat.model.dmpblueprintdefinition.Section._label, + Dmp._blueprint + "." + DmpBlueprint._definition + "." + eu.eudat.model.dmpblueprintdefinition.Definition._sections + "." + eu.eudat.model.dmpblueprintdefinition.Section._ordinal, + Dmp._blueprint + "." + DmpBlueprint._definition + "." + eu.eudat.model.dmpblueprintdefinition.Definition._sections + "." + eu.eudat.model.dmpblueprintdefinition.Section._fields + "." + eu.eudat.model.dmpblueprintdefinition.Field._id, + Dmp._blueprint + "." + DmpBlueprint._definition + "." + eu.eudat.model.dmpblueprintdefinition.Definition._sections + "." + eu.eudat.model.dmpblueprintdefinition.Section._fields + "." + eu.eudat.model.dmpblueprintdefinition.Field._description, + Dmp._blueprint + "." + DmpBlueprint._definition + "." + eu.eudat.model.dmpblueprintdefinition.Definition._sections + "." + eu.eudat.model.dmpblueprintdefinition.Section._fields + "." + eu.eudat.model.dmpblueprintdefinition.Field._ordinal, + Dmp._blueprint + "." + DmpBlueprint._definition + "." + eu.eudat.model.dmpblueprintdefinition.Definition._sections + "." + eu.eudat.model.dmpblueprintdefinition.Section._fields + "." + eu.eudat.model.dmpblueprintdefinition.Field._label, + Dmp._blueprint + "." + DmpBlueprint._definition + "." + eu.eudat.model.dmpblueprintdefinition.Definition._sections + "." + eu.eudat.model.dmpblueprintdefinition.Section._fields + "." + eu.eudat.model.dmpblueprintdefinition.Field._placeholder, + Dmp._blueprint + "." + DmpBlueprint._definition + "." + eu.eudat.model.dmpblueprintdefinition.Definition._sections + "." + eu.eudat.model.dmpblueprintdefinition.Section._fields + "." + eu.eudat.model.dmpblueprintdefinition.Field._category, + Dmp._blueprint + "." + DmpBlueprint._definition + "." + eu.eudat.model.dmpblueprintdefinition.Definition._sections + "." + eu.eudat.model.dmpblueprintdefinition.Section._fields + "." + eu.eudat.model.dmpblueprintdefinition.Field._required, + Dmp._blueprint + "." + DmpBlueprint._definition + "." + eu.eudat.model.dmpblueprintdefinition.Definition._sections + "." + eu.eudat.model.dmpblueprintdefinition.Section._fields + "." + SystemField._systemFieldType, + Dmp._blueprint + "." + DmpBlueprint._definition + "." + eu.eudat.model.dmpblueprintdefinition.Definition._sections + "." + eu.eudat.model.dmpblueprintdefinition.Section._fields + "." + ExtraField._dataType, + Dmp._blueprint + "." + DmpBlueprint._definition + "." + eu.eudat.model.dmpblueprintdefinition.Definition._sections + "." + eu.eudat.model.dmpblueprintdefinition.Section._descriptionTemplates + "." + eu.eudat.model.dmpblueprintdefinition.DescriptionTemplate._id, + Dmp._blueprint + "." + DmpBlueprint._definition + "." + eu.eudat.model.dmpblueprintdefinition.Definition._sections + "." + eu.eudat.model.dmpblueprintdefinition.Section._descriptionTemplates + "." + eu.eudat.model.dmpblueprintdefinition.DescriptionTemplate._label, + Dmp._blueprint + "." + DmpBlueprint._definition + "." + eu.eudat.model.dmpblueprintdefinition.Definition._sections + "." + eu.eudat.model.dmpblueprintdefinition.Section._descriptionTemplates + "." + eu.eudat.model.dmpblueprintdefinition.DescriptionTemplate._descriptionTemplateId, + Dmp._blueprint + "." + DmpBlueprint._definition + "." + eu.eudat.model.dmpblueprintdefinition.Definition._sections + "." + eu.eudat.model.dmpblueprintdefinition.Section._descriptionTemplates + "." + eu.eudat.model.dmpblueprintdefinition.DescriptionTemplate._maxMultiplicity, + Dmp._blueprint + "." + DmpBlueprint._definition + "." + eu.eudat.model.dmpblueprintdefinition.Definition._sections + "." + eu.eudat.model.dmpblueprintdefinition.Section._descriptionTemplates + "." + eu.eudat.model.dmpblueprintdefinition.DescriptionTemplate._minMultiplicity, + Dmp._blueprint + "." + DmpBlueprint._definition + "." + eu.eudat.model.dmpblueprintdefinition.Definition._sections + "." + eu.eudat.model.dmpblueprintdefinition.Section._hasTemplates, + Dmp._entityDois + "." + EntityDoi._doi, + Dmp._entityDois + "." + EntityDoi._id, + Dmp._entityDois + "." + EntityDoi._entityType, + Dmp._dmpUsers + "." + DmpUser._id, + Dmp._dmpUsers + "." + DmpUser._user + "." + User._id, + Dmp._dmpUsers + "." + DmpUser._user + "." + User._additionalInfo, + Dmp._dmpUsers + "." + DmpUser._user + "." + User._createdAt, + Dmp._dmpUsers + "." + DmpUser._user + "." + User._isActive, + Dmp._dmpUsers + "." + DmpUser._user + "." + User._name, + Dmp._dmpUsers + "." + DmpUser._user + "." + User._roles + "." + UserRole._id, + Dmp._dmpUsers + "." + DmpUser._user + "." + User._roles + "." + UserRole._role, + Dmp._dmpUsers + "." + DmpUser._role + ); + DmpQuery query = this.queryFactory.query(DmpQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).ids(dmpId); + Dmp model = this.builderFactory.builder(DmpBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).build(fieldSet, query.firstAs(fieldSet)); + DmpFileTransformerModel dmpFileTransformerModel = this.jsonHandlingService.fromJsonSafe(DmpFileTransformerModel.class, this.jsonHandlingService.toJsonSafe(model)); + ExtraPropertiesModel extraPropertiesModel = new ExtraPropertiesModel(); + extraPropertiesModel.setFormat(format); + eu.eudat.file.transformer.model.file.FileEnvelope fileEnvelope = repository.exportDmp(dmpFileTransformerModel, extraPropertiesModel); + FileEnvelope result = new FileEnvelope(); + File temp = new File(environment.getProperty("path.path") + UUID.randomUUID()); + try (FileOutputStream fos = new FileOutputStream(temp)) { + fos.write(fileEnvelope.getFile()); + } + result.setFile(temp); + result.setFilename(fileEnvelope.getFilename()); + return result; + } + + public FileEnvelope exportDescription(UUID descriptionId, String format) throws InvalidApplicationException, IOException { + this.authorizationService.authorize(Permission.EditDmp); + //GK: Why it is in that service, and why it's not static? + this.conventionService.isValidGuid(descriptionId); + //GK: First get the right client + TransformerRepository repository = getRepository(format); + //GK: Second get the Target Data Management Plan + FieldSet fieldSet = new BaseFieldSet( + Description._dmp + "." + Dmp._id, + Description._dmp + "." + Dmp._createdAt, + Description._dmp + "." + Dmp._finalizedAt, + Description._dmp + "." + Dmp._groupId, + Description._dmp + "." + Dmp._isActive, + Description._dmp + "." + Dmp._label, + Description._dmp + "." + Dmp._language, + Description._dmp + "." + Dmp._publicAfter, + Description._dmp + "." + Dmp._status, + Description._dmp + "." + Dmp._updatedAt, + Description._dmp + "." + Dmp._version, + Description._dmp + "." + Dmp._properties, + Description._dmp + "." + Dmp._versionStatus, + Description._dmp + "." + Dmp._dmpReferences + "." + DmpReference._id, + Description._dmp + "." + Dmp._dmpReferences + "." + DmpReference._data, + Description._dmp + "." + Dmp._dmpReferences + "." + DmpReference._reference + "." + Reference._id, + Description._dmp + "." + Dmp._dmpReferences + "." + DmpReference._reference + "." + Reference._description, + Description._dmp + "." + Dmp._dmpReferences + "." + DmpReference._reference + "." + Reference._abbreviation, + Description._dmp + "." + Dmp._dmpReferences + "." + DmpReference._reference + "." + Reference._definition, + Description._dmp + "." + Dmp._dmpReferences + "." + DmpReference._reference + "." + Reference._label, + Description._dmp + "." + Dmp._dmpReferences + "." + DmpReference._reference + "." + Reference._source, + Description._dmp + "." + Dmp._dmpReferences + "." + DmpReference._reference + "." + Reference._sourceType, + Description._dmp + "." + Dmp._dmpReferences + "." + DmpReference._reference + "." + Reference._type, + Description._dmp + "." + Dmp._dmpReferences + "." + DmpReference._reference + "." + Reference._isActive, + Description._dmp + "." + Dmp._dmpReferences + "." + DmpReference._reference + "." + Reference._reference, + Description._id, + Description._label, + Description._properties, + Description._description, + Description._status, + Description._descriptionTags, + Description._descriptionTemplate, + Description._descriptionReferences, + Description._isActive, + Description._properties + "." + PropertyDefinition._fields + "." + eu.eudat.model.descriptionproperties.Field._key, + Description._properties + "." + PropertyDefinition._fields + "." + eu.eudat.model.descriptionproperties.Field._value, + Description._descriptionReferences + "." + DescriptionReference._id, + Description._descriptionReferences + "." + DescriptionReference._reference, + Description._descriptionReferences + "." + DescriptionReference._reference + "." + Reference._id, + Description._descriptionReferences + "." + DescriptionReference._reference + "." + Reference._description, + Description._descriptionReferences + "." + DescriptionReference._reference + "." + Reference._abbreviation, + Description._descriptionReferences + "." + DescriptionReference._reference + "." + Reference._definition, + Description._descriptionReferences + "." + DescriptionReference._reference + "." + Reference._label, + Description._descriptionReferences + "." + DescriptionReference._reference + "." + Reference._source, + Description._descriptionReferences + "." + DescriptionReference._reference + "." + Reference._sourceType, + Description._descriptionReferences + "." + DescriptionReference._reference + "." + Reference._type, + Description._descriptionReferences + "." + DescriptionReference._reference + "." + Reference._isActive, + Description._descriptionReferences + "." + DescriptionReference._reference + "." + Reference._reference, + Description._descriptionTemplate + "." + DescriptionTemplate._id, + Description._descriptionTemplate + "." + DescriptionTemplate._description, + Description._descriptionTemplate + "." + DescriptionTemplate._label, + Description._descriptionTemplate + "." + DescriptionTemplate._language, + Description._descriptionTemplate + "." + DescriptionTemplate._status, + Description._descriptionTemplate + "." + DescriptionTemplate._isActive, + Description._descriptionTemplate + "." + DescriptionTemplate._groupId, + Description._descriptionTemplate + "." + DescriptionTemplate._type, + Description._descriptionTemplate + "." + DescriptionTemplate._version, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._pages, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._id, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._description, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._sections, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._title, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._page, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._ordinal, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._defaultVisibility, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._extendedDescription, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._multiplicity + "." + Multiplicity._max, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._multiplicity + "." + Multiplicity._min, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._multiplicity + "." + Multiplicity._placeholder, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._multiplicity + "." + Multiplicity._tableView, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._numbering, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._id, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._title, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._description, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._ordinal, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._numbering, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._multiplicity + "." + Multiplicity._max, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._multiplicity + "." + Multiplicity._min, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._multiplicity + "." + Multiplicity._tableView, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._multiplicity + "." + Multiplicity._placeholder, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._hasCommentField, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._additionalInformation, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._extendedDescription, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._id, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._ordinal, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._numbering, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._data + "." + BaseFieldData._label, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._data + "." + BaseFieldData._fieldType, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._data + "." + AutoCompleteData._multiAutoComplete, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._data + "." + AutoCompleteData._autoCompleteSingleDataList + "." + AutoCompleteSingleData._autoCompleteOptions + "." + ComboBoxOption._label, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._data + "." + AutoCompleteData._autoCompleteSingleDataList + "." + AutoCompleteSingleData._autoCompleteOptions + "." + ComboBoxOption._uri, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._data + "." + AutoCompleteData._autoCompleteSingleDataList + "." + AutoCompleteSingleData._autoCompleteOptions + "." + ComboBoxOption._source, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._data + "." + AutoCompleteData._autoCompleteSingleDataList + "." + AutoCompleteSingleData._autoCompleteOptions + "." + ComboBoxOption._value, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._defaultValue, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._includeInExport, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._schematics, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._validations, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._visibilityRules, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._visibilityRules + "." + Rule._target, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._sections + "." + Section._fieldSets + "." + eu.eudat.model.descriptiontemplatedefinition.FieldSet._fields + "." + Field._visibilityRules + "." + Rule._value, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._pages + "." + Page._id, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._pages + "." + Page._ordinal, + Description._descriptionTemplate + "." + DescriptionTemplate._definition + "." + Definition._pages + "." + Page._title, + Description._descriptionTags + "." + DescriptionTag._id, + Description._descriptionTags + "." + DescriptionTag._tag + "." + Tag._id, + Description._descriptionTags + "." + DescriptionTag._tag + "." + Tag._label, + Description._dmp + "." + Dmp._entityDois + "." + EntityDoi._doi, + Description._dmp + "." + Dmp._entityDois + "." + EntityDoi._id, + Description._dmp + "." + Dmp._entityDois + "." + EntityDoi._entityType + ); + DescriptionQuery query = this.queryFactory.query(DescriptionQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).ids(descriptionId); + Description model = this.builderFactory.builder(DescriptionBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).build(fieldSet, query.firstAs(fieldSet)); + DescriptionFileTransformerModel descriptionFileTransformerModel = this.jsonHandlingService.fromJsonSafe(DescriptionFileTransformerModel.class, this.jsonHandlingService.toJsonSafe(model)); + ExtraPropertiesModel extraPropertiesModel = new ExtraPropertiesModel(); + extraPropertiesModel.setFormat(format); + eu.eudat.file.transformer.model.file.FileEnvelope fileEnvelope = repository.exportDescription(descriptionFileTransformerModel, extraPropertiesModel); + FileEnvelope result = new FileEnvelope(); + File temp = new File(environment.getProperty("path.path") + UUID.randomUUID()); + try (FileOutputStream fos = new FileOutputStream(temp)) { + fos.write(fileEnvelope.getFile()); + } + result.setFile(temp); + result.setFilename(fileEnvelope.getFilename()); + return result; + } + + // This method returns filter function which will log request data + private static ExchangeFilterFunction logRequest() { + return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> { + logger.info("Request: {} {}", clientRequest.method(), clientRequest.url()); + clientRequest.headers().forEach((name, values) -> values.forEach(value -> logger.info("{}={}", name, value))); + return Mono.just(clientRequest); + }); + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/utilities/webclient/WebClientUtils.java b/dmp-backend/core/src/main/java/eu/eudat/utilities/webclient/WebClientUtils.java new file mode 100644 index 000000000..7dd35ceeb --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/utilities/webclient/WebClientUtils.java @@ -0,0 +1,52 @@ +package eu.eudat.utilities.webclient; + +import org.springframework.web.util.UriBuilder; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URI; +import java.util.List; +import java.util.Locale; +import java.util.stream.Stream; + +public class WebClientUtils { + + public static URI buildParameters(UriBuilder builder, Object data) { + List fields = List.of(data.getClass().getDeclaredFields()); + List getters = Stream.of(data.getClass().getDeclaredMethods()).filter(method -> method.getName().startsWith("get")).toList(); + fields.forEach(field -> { + Method getter = getters.stream().filter(method -> method.getName().equals(makeGetterMethodName(field.getName()))).findFirst().orElse(null); + if (getter != null && getter.canAccess(data)) { + try { + registerParameter(builder, getter.invoke(data), field); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } else if (field.canAccess(data)) { + try { + registerParameter(builder, field.get(data), field); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } else { + throw new RuntimeException("Field " + field.getName() + " is not public and has no public getter Method"); + } + }); + return builder.build(); + } + + private static void registerParameter(UriBuilder builder, Object value, Field field) { + if (value != null) { + builder.queryParam(getParameterName(field), value); + } + } + + private static String makeGetterMethodName(String fieldName) { + return "get" + fieldName.substring(0, 1).toUpperCase(Locale.ROOT) + fieldName.substring(1); + } + + private static String getParameterName(Field field) { + return field.getName(); + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/v2/DescriptionController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/v2/DescriptionController.java index fbedf9fb9..ac315984b 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/v2/DescriptionController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/v2/DescriptionController.java @@ -19,6 +19,8 @@ import eu.eudat.query.DescriptionQuery; import eu.eudat.query.DmpQuery; import eu.eudat.query.lookup.DescriptionLookup; import eu.eudat.service.description.DescriptionService; +import eu.eudat.service.description.DescriptionServiceImpl; +import eu.eudat.service.dmp.DmpService; import eu.eudat.service.elastic.ElasticQueryHelperService; import gr.cite.tools.auditing.AuditService; import gr.cite.tools.data.builder.BuilderFactory; @@ -34,6 +36,7 @@ import gr.cite.tools.validation.MyValidate; import org.slf4j.LoggerFactory; import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; @@ -182,4 +185,11 @@ public class DescriptionController { this.auditService.track(AuditableAction.Description_Delete, "id", id); } + @GetMapping("{id}/export/{type}") + public ResponseEntity export(@PathVariable("id") UUID id, @PathVariable("type") String exportType) throws InvalidApplicationException, IOException { + logger.debug(new MapLogEntry("exporting description")); + + return this.descriptionService.export(id, DescriptionServiceImpl.DescriptionExportType.valueOf(exportType)); + } + } diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/v2/DmpController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/v2/DmpController.java index 824525213..33355d0d1 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/v2/DmpController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/v2/DmpController.java @@ -4,12 +4,11 @@ import com.fasterxml.jackson.core.JsonProcessingException; import eu.eudat.audit.AuditableAction; import eu.eudat.authorization.AuthorizationFlags; import eu.eudat.data.DmpEntity; -import eu.eudat.data.DmpUserEntity; import eu.eudat.model.Dmp; import eu.eudat.model.DmpUser; import eu.eudat.model.builder.DmpBuilder; -import eu.eudat.model.builder.DmpUserBuilder; import eu.eudat.model.censorship.DmpCensor; +import eu.eudat.model.file.FileEnvelope; import eu.eudat.model.persist.*; import eu.eudat.model.result.QueryResult; import eu.eudat.models.data.dmp.DataManagementPlan; @@ -17,6 +16,7 @@ import eu.eudat.models.data.helpers.responses.ResponseItem; import eu.eudat.query.DmpQuery; import eu.eudat.query.lookup.DmpLookup; import eu.eudat.service.dmp.DmpService; +import eu.eudat.service.transformer.FileTransformerService; import eu.eudat.types.ApiMessageCode; import gr.cite.tools.auditing.AuditService; import gr.cite.tools.data.builder.BuilderFactory; @@ -200,7 +200,7 @@ public class DmpController { } @GetMapping("{id}/export/{type}") - public ResponseEntity export(@PathVariable("id") UUID id, @PathVariable("type") String exportType){ + public ResponseEntity export(@PathVariable("id") UUID id, @PathVariable("type") String exportType) throws InvalidApplicationException, IOException { logger.debug(new MapLogEntry("exporting dmp")); return this.dmpService.export(id, DmpService.DmpExportType.valueOf(exportType)); diff --git a/dmp-backend/web/src/main/resources/config/application.yml b/dmp-backend/web/src/main/resources/config/application.yml index 1d4ec23db..49dc175ed 100644 --- a/dmp-backend/web/src/main/resources/config/application.yml +++ b/dmp-backend/web/src/main/resources/config/application.yml @@ -27,6 +27,6 @@ spring: optional:classpath:config/reference-type.yml[.yml], optional:classpath:config/reference-type-${spring.profiles.active}.yml[.yml], optional:file:../config/reference-type-${spring.profiles.active}.yml[.yml], optional:classpath:config/tenant.yml[.yml], optional:classpath:config/tenant-${spring.profiles.active}.yml[.yml], optional:file:../config/tenant-${spring.profiles.active}.yml[.yml], optional:classpath:config/queue.yml[.yml], optional:classpath:config/queue-${spring.profiles.active}.yml[.yml], optional:file:../config/queue-${spring.profiles.active}.yml[.yml], - optional:classpath:config/notification.yml[.yml], optional:classpath:config/notification-${spring.profiles.active}.yml[.yml], optional:file:../config/notification-${spring.profiles.active}.yml[.yml] - + optional:classpath:config/notification.yml[.yml], optional:classpath:config/notification-${spring.profiles.active}.yml[.yml], optional:file:../config/notification-${spring.profiles.active}.yml[.yml], + optional:classpath:config/transformer.yml[.yml], optional:classpath:config/transformer-${spring.profiles.active}.yml[.yml], optional:file:../config/transformer-${spring.profiles.active}.yml[.yml] diff --git a/dmp-backend/web/src/main/resources/config/cache.yml b/dmp-backend/web/src/main/resources/config/cache.yml index 7de1237d9..5f2b1abfb 100644 --- a/dmp-backend/web/src/main/resources/config/cache.yml +++ b/dmp-backend/web/src/main/resources/config/cache.yml @@ -42,6 +42,22 @@ cache: expireAfterWriteMinutes: 1 expireAfterAccessMinutes: 1 refreshAfterWriteMinutes: 1 + - names: [ "transformer" ] + allowNullValues: true + initialCapacity: 100 + maximumSize: 500 + enableRecordStats: false + expireAfterWriteMinutes: 10 + expireAfterAccessMinutes: 10 + refreshAfterWriteMinutes: 10 + - names: [ "tokenExchangeKey" ] + allowNullValues: true + initialCapacity: 100 + maximumSize: 500 + enableRecordStats: false + expireAfterWriteMinutes: 10 + expireAfterAccessMinutes: 10 + refreshAfterWriteMinutes: 10 mapCaches: userBySubjectId: name: userBySubjectId @@ -57,4 +73,10 @@ cache: keyPattern: dashboard_stats_by_usr_$key$:v0 depositConfigById: name: depositConfigById - keyPattern: deposit_config_by_id_$repositoryId$:v0 \ No newline at end of file + keyPattern: deposit_config_by_id_$repositoryId$:v0 + transformer: + name: transformer + keyPattern: base:v0 + token-exchange-key: + name: tokenExchangeKey + keyPattern: resolve_$keyhash$:v0 \ No newline at end of file diff --git a/dmp-backend/web/src/main/resources/config/transformer.yml b/dmp-backend/web/src/main/resources/config/transformer.yml new file mode 100644 index 000000000..6416b0de4 --- /dev/null +++ b/dmp-backend/web/src/main/resources/config/transformer.yml @@ -0,0 +1,11 @@ +transformer: + sources: + - url: http://localhost:8084 + codes: [ docx, pdf ] + issuer-url: ${IDP_ISSUER_URI_TOKEN:} + client-id: ${IDP_APIKEY_CLIENT_ID:} + client-secret: ${IDP_APIKEY_CLIENT_SECRET:} + scope: ${IDP_APIKEY_SCOPE:} + +temp: + temp: ${TEMP_STORAGE} \ No newline at end of file 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 aa82928f0..cbd8c79f5 100644 --- a/dmp-frontend/src/app/core/services/description/description.service.ts +++ b/dmp-frontend/src/app/core/services/description/description.service.ts @@ -1,4 +1,4 @@ -import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { IsActive } from '@app/core/common/enum/is-active.enum'; import { Description, DescriptionPersist, DescriptionStatusPersist, PublicDescription } from '@app/core/model/description/description'; @@ -76,6 +76,15 @@ export class DescriptionService { catchError((error: any) => throwError(error))); } + public downloadPDF(id: string): Observable> { + return this.httpClient.get(`${this.apiBase}/${id}/export/Pdf`, { responseType: 'blob', observe: 'response', headers: this.headers }); + } + + public downloadDOCX(id: string): Observable> { + let headerDocx: HttpHeaders = this.headers.set('Content-Type', 'application/msword') + return this.httpClient.get(`${this.apiBase}/${id}/export/Word`, { responseType: 'blob', observe: 'response', headers: headerDocx }); + } + // // Autocomplete Commons // 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 958f64d48..e03f825d0 100644 --- a/dmp-frontend/src/app/core/services/dmp/dmp.service.ts +++ b/dmp-frontend/src/app/core/services/dmp/dmp.service.ts @@ -125,6 +125,20 @@ export class DmpServiceNew { catchError((error: any) => throwError(error))); } + public downloadDocx(id: string): Observable> { + let headerDoc: HttpHeaders = this.headers.set('Content-Type', 'application/msword') + return this.httpClient.get(`${this.apiBase}/${id}/export/Word`, { responseType: 'blob', observe: 'response', headers: headerDoc }); + } + + public downloadPDF(id: string): Observable> { + let headerPdf: HttpHeaders = this.headers.set('Content-Type', 'application/pdf') + return this.httpClient.get(`${this.apiBase}/${id}/export/Pdf`, { responseType: 'blob', observe: 'response', headers: headerPdf }); + } + + // public downloadJson(id: string): Observable> { + // return this.httpClient.get(this.actionUrl + 'rda/' + id, { responseType: 'blob', observe: 'response' }); + // } + downloadXML(id: Guid): Observable> { const url = `${this.apiBase}/xml/export/${id}`; let headerXml: HttpHeaders = this.headers.set('Content-Type', 'application/xml'); diff --git a/dmp-frontend/src/app/core/services/matomo/matomo-service.ts b/dmp-frontend/src/app/core/services/matomo/matomo-service.ts index d7dbec8ad..94b5654a7 100644 --- a/dmp-frontend/src/app/core/services/matomo/matomo-service.ts +++ b/dmp-frontend/src/app/core/services/matomo/matomo-service.ts @@ -37,7 +37,7 @@ export class MatomoService { } } - trackDownload(category: "dmps" | "datasets", type: "docx" | "pdf" | "xml" | "json", id: string): void { + trackDownload(category: "dmps" | "datasets" | "descriptions", type: "docx" | "pdf" | "xml" | "json", id: string): void { if (this.configurationService.matomoEnabled) { var principalid = this.authService.userId(); if (principalid != null) { this.matomoTracker.setUserId(principalid.toString()); } diff --git a/dmp-frontend/src/app/ui/description/listing/listing-item/description-listing-item.component.ts b/dmp-frontend/src/app/ui/description/listing/listing-item/description-listing-item.component.ts index 68dfe4c74..b4769f897 100644 --- a/dmp-frontend/src/app/ui/description/listing/listing-item/description-listing-item.component.ts +++ b/dmp-frontend/src/app/ui/description/listing/listing-item/description-listing-item.component.ts @@ -104,29 +104,27 @@ export class DescriptionListingItemComponent extends BaseComponent implements On } downloadPDF(description: Description): void { - //TODO: add file transformer service - // this.descriptionService.downloadPDF(description.id as string) - // .pipe(takeUntil(this._destroyed)) - // .subscribe(response => { - // const blob = new Blob([response.body], { type: 'application/pdf' }); - // const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + this.descriptionService.downloadPDF(description.id.toString()) + .pipe(takeUntil(this._destroyed)) + .subscribe(response => { + const blob = new Blob([response.body], { type: 'application/pdf' }); + const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); - // FileSaver.saveAs(blob, filename); - // this.matomoService.trackDownload('descriptions', "pdf", description.id); - // }); + FileSaver.saveAs(blob, filename); + this.matomoService.trackDownload('descriptions', "pdf", description.id.toString()); + }); } downloadDOCX(description: Description): void { - //TODO: add file transformer service - // this.descriptionService.downloadDOCX(description.id as string) - // .pipe(takeUntil(this._destroyed)) - // .subscribe(response => { - // const blob = new Blob([response.body], { type: 'application/msword' }); - // const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + this.descriptionService.downloadDOCX(description.id.toString()) + .pipe(takeUntil(this._destroyed)) + .subscribe(response => { + const blob = new Blob([response.body], { type: 'application/msword' }); + const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); - // FileSaver.saveAs(blob, filename); - // this.matomoService.trackDownload('descriptions', "docx", description.id); - // }); + FileSaver.saveAs(blob, filename); + this.matomoService.trackDownload('descriptions', "docx", description.id.toString()); + }); } @@ -240,7 +238,7 @@ export class DescriptionListingItemComponent extends BaseComponent implements On this.uiNotificationService.snackBarNotification(error.error.message ? error.error.message : this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-DELETE'), SnackBarNotificationLevel.Error); } - + isUserDescriptionRelated(): boolean { const principalId: Guid = this.authService.userId(); diff --git a/dmp-frontend/src/app/ui/description/overview/description-overview.component.ts b/dmp-frontend/src/app/ui/description/overview/description-overview.component.ts index 10fb19d5a..e2a401b2a 100644 --- a/dmp-frontend/src/app/ui/description/overview/description-overview.component.ts +++ b/dmp-frontend/src/app/ui/description/overview/description-overview.component.ts @@ -33,6 +33,7 @@ import { filter, takeUntil } from 'rxjs/operators'; import { nameof } from 'ts-simple-nameof'; import { DescriptionCopyDialogComponent } from '../description-copy-dialog/description-copy-dialog.component'; import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; +import * as FileSaver from 'file-saver'; @Component({ @@ -291,29 +292,27 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni } downloadPDF(id: string) { - // TODO: add download - // this.descriptionService.downloadPDF(id) - // .pipe(takeUntil(this._destroyed)) - // .subscribe(response => { - // const blob = new Blob([response.body], { type: 'application/pdf' }); - // const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + this.descriptionService.downloadPDF(id) + .pipe(takeUntil(this._destroyed)) + .subscribe(response => { + const blob = new Blob([response.body], { type: 'application/pdf' }); + const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); - // FileSaver.saveAs(blob, filename); - // this.matomoService.trackDownload('descriptions', "pdf", id); - // }); + FileSaver.saveAs(blob, filename); + this.matomoService.trackDownload('descriptions', "pdf", id); + }); } downloadDocx(id: string) { - // TODO: add download - // this.descriptionService.downloadDocx(id) - // .pipe(takeUntil(this._destroyed)) - // .subscribe(response => { - // const blob = new Blob([response.body], { type: 'application/msword' }); - // const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + this.descriptionService.downloadDOCX(id) + .pipe(takeUntil(this._destroyed)) + .subscribe(response => { + const blob = new Blob([response.body], { type: 'application/msword' }); + const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); - // FileSaver.saveAs(blob, filename); - // this.matomoService.trackDownload('descriptions', "docx", id); - // }); + FileSaver.saveAs(blob, filename); + this.matomoService.trackDownload('descriptions', "docx", id); + }); } downloadXml(id: string) { diff --git a/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.ts b/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.ts index 1e1a282ae..b838c6847 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.ts +++ b/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.ts @@ -22,6 +22,7 @@ import { TranslateService } from '@ngx-translate/core'; import { takeUntil } from 'rxjs/operators'; import { DmpStatus } from '../../../../core/common/enum/dmp-status'; import { AuthService } from '../../../../core/services/auth/auth.service'; +import * as FileSaver from 'file-saver'; @Component({ selector: 'app-dmp-listing-item-component', @@ -192,28 +193,27 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit { downloadDocx(id: Guid) { // TODO: Add this - // this.dmpService.downloadDocx(id) - // .pipe(takeUntil(this._destroyed)) - // .subscribe(response => { - // const blob = new Blob([response.body], { type: 'application/msword' }); - // const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + this.dmpService.downloadDocx(id.toString()) + .pipe(takeUntil(this._destroyed)) + .subscribe(response => { + const blob = new Blob([response.body], { type: 'application/msword' }); + const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); - // FileSaver.saveAs(blob, filename); - // this.matomoService.trackDownload('dmps', "docx", id); - // }); + FileSaver.saveAs(blob, filename); + this.matomoService.trackDownload('dmps', "docx", id.toString()); + }); } downloadPDF(id: Guid) { - // TODO: Add this - // this.dmpService.downloadPDF(id) - // .pipe(takeUntil(this._destroyed)) - // .subscribe(response => { - // const blob = new Blob([response.body], { type: 'application/pdf' }); - // const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + this.dmpService.downloadPDF(id.toString()) + .pipe(takeUntil(this._destroyed)) + .subscribe(response => { + const blob = new Blob([response.body], { type: 'application/pdf' }); + const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); - // FileSaver.saveAs(blob, filename); - // this.matomoService.trackDownload('dmps', "pdf", id); - // }); + FileSaver.saveAs(blob, filename); + this.matomoService.trackDownload('dmps', "pdf", id.toString()); + }); } downloadJson(id: Guid) { diff --git a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts index 7e64784ac..4de426621 100644 --- a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts +++ b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts @@ -35,6 +35,7 @@ import { Guid } from '@common/types/guid'; import { TranslateService } from '@ngx-translate/core'; import { takeUntil } from 'rxjs/operators'; import { nameof } from 'ts-simple-nameof'; +import * as FileSaver from 'file-saver'; @Component({ selector: 'app-dmp-overview', @@ -355,29 +356,27 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { } downloadDocx(id: string) { - //TODO: add this - // this.dmpService.downloadDocx(id) - // .pipe(takeUntil(this._destroyed)) - // .subscribe(response => { - // const blob = new Blob([response.body], { type: 'application/msword' }); - // const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + this.dmpService.downloadDocx(id) + .pipe(takeUntil(this._destroyed)) + .subscribe(response => { + const blob = new Blob([response.body], { type: 'application/msword' }); + const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); - // FileSaver.saveAs(blob, filename); - // this.matomoService.trackDownload('dmps', "docx", id); - // }); + FileSaver.saveAs(blob, filename); + this.matomoService.trackDownload('dmps', "docx", id); + }); } downloadPDF(id: string) { - //TODO: add this - // this.dmpService.downloadPDF(id) - // .pipe(takeUntil(this._destroyed)) - // .subscribe(response => { - // const blob = new Blob([response.body], { type: 'application/pdf' }); - // const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + this.dmpService.downloadPDF(id) + .pipe(takeUntil(this._destroyed)) + .subscribe(response => { + const blob = new Blob([response.body], { type: 'application/pdf' }); + const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); - // FileSaver.saveAs(blob, filename); - // this.matomoService.trackDownload('dmps', "pdf", id); - // }); + FileSaver.saveAs(blob, filename); + this.matomoService.trackDownload('dmps', "pdf", id); + }); } downloadJson(id: string) {