diff --git a/backend/core/src/main/java/org/opencdmp/model/PublicDmp.java b/backend/core/src/main/java/org/opencdmp/model/PublicDmp.java index 82a7875b9..d3314df09 100644 --- a/backend/core/src/main/java/org/opencdmp/model/PublicDmp.java +++ b/backend/core/src/main/java/org/opencdmp/model/PublicDmp.java @@ -60,6 +60,9 @@ public class PublicDmp { private List entityDois; public static final String _entityDois = "entityDois"; + private List otherDmpVersions; + public static final String _otherDmpVersions = "otherDmpVersions"; + public UUID getId() { return id; } @@ -171,4 +174,12 @@ public class PublicDmp { public void setEntityDois(List entityDois) { this.entityDois = entityDois; } + + public List getOtherDmpVersions() { + return otherDmpVersions; + } + + public void setOtherDmpVersions(List otherDmpVersions) { + this.otherDmpVersions = otherDmpVersions; + } } diff --git a/backend/core/src/main/java/org/opencdmp/model/builder/PublicDmpBuilder.java b/backend/core/src/main/java/org/opencdmp/model/builder/PublicDmpBuilder.java index 10f4a4ff7..1190118c4 100644 --- a/backend/core/src/main/java/org/opencdmp/model/builder/PublicDmpBuilder.java +++ b/backend/core/src/main/java/org/opencdmp/model/builder/PublicDmpBuilder.java @@ -9,13 +9,11 @@ import gr.cite.tools.logging.DataLogEntry; import gr.cite.tools.logging.LoggerService; import org.opencdmp.authorization.AuthorizationFlags; import org.opencdmp.commons.enums.EntityType; +import org.opencdmp.commons.enums.IsActive; import org.opencdmp.convention.ConventionService; import org.opencdmp.data.DmpEntity; import org.opencdmp.model.*; -import org.opencdmp.query.DescriptionQuery; -import org.opencdmp.query.DmpReferenceQuery; -import org.opencdmp.query.DmpUserQuery; -import org.opencdmp.query.EntityDoiQuery; +import org.opencdmp.query.*; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.ConfigurableBeanFactory; @@ -70,6 +68,9 @@ public class PublicDmpBuilder extends BaseBuilder { FieldSet entityDoisFields = fields.extractPrefixed(this.asPrefix(PublicDmp._entityDois)); Map> entityDoisMap = this.collectEntityDois(entityDoisFields, data); + FieldSet otherDmpVersionsFields = fields.extractPrefixed(this.asPrefix(PublicDmp._otherDmpVersions)); + Map> otherDmpVersionsMap = this.collectOtherDmpVersions(otherDmpVersionsFields, data); + for (DmpEntity d : data) { PublicDmp m = new PublicDmp(); if (fields.hasField(this.asIndexer(PublicDmp._id))) m.setId(d.getId()); @@ -87,6 +88,7 @@ public class PublicDmpBuilder extends BaseBuilder { if (dmpUsersMap != null && !dmpUsersMap.isEmpty() && dmpUsersMap.containsKey(d.getId())) m.setDmpUsers(dmpUsersMap.get(d.getId())); if (descriptionsMap != null && !descriptionsMap.isEmpty() && descriptionsMap.containsKey(d.getId())) m.setDescriptions(descriptionsMap.get(d.getId())); if (entityDoisMap != null && !entityDoisMap.isEmpty() && entityDoisMap.containsKey(d.getId())) m.setEntityDois(entityDoisMap.get(d.getId())); + if (otherDmpVersionsMap != null && !otherDmpVersionsMap.isEmpty() && otherDmpVersionsMap.containsKey(d.getGroupId())) m.setOtherDmpVersions(otherDmpVersionsMap.get(d.getGroupId())); models.add(m); } @@ -167,4 +169,22 @@ public class PublicDmpBuilder extends BaseBuilder { return itemMap; } + private Map> collectOtherDmpVersions(FieldSet fields, List data) throws MyApplicationException { + if (fields.isEmpty() || data.isEmpty()) return null; + this.logger.debug("checking related - {}", PublicDmp.class.getSimpleName()); + + Map> itemMap; + FieldSet clone = new BaseFieldSet(fields.getFields()).ensure(PublicDmp._id); + DmpQuery query = this.queryFactory.query(DmpQuery.class).disableTracking().authorize(this.authorize).groupIds(data.stream().map(DmpEntity::getGroupId).distinct().collect(Collectors.toList())).isActive(IsActive.Active); + itemMap = this.builderFactory.builder(PublicDmpBuilder.class).authorize(this.authorize).asMasterKey(query, clone, x -> x.getGroupId()); + + if (!fields.hasField(this.asIndexer(PublicDmp._otherDmpVersions, PublicDmp._id))) { + itemMap.values().stream().flatMap(List::stream).filter(x -> x != null).peek(x -> { + x.setId(null); + }); + } + + return itemMap; + } + } diff --git a/backend/core/src/main/java/org/opencdmp/model/builder/dmp/DmpBuilder.java b/backend/core/src/main/java/org/opencdmp/model/builder/dmp/DmpBuilder.java index 316ff01a6..0c594f941 100644 --- a/backend/core/src/main/java/org/opencdmp/model/builder/dmp/DmpBuilder.java +++ b/backend/core/src/main/java/org/opencdmp/model/builder/dmp/DmpBuilder.java @@ -105,6 +105,9 @@ public class DmpBuilder extends BaseBuilder { FieldSet dmpDescriptionTemplatesFields = fields.extractPrefixed(this.asPrefix(Dmp._dmpDescriptionTemplates)); Map> dmpDescriptionTemplatesMap = this.collectDmpDescriptionTemplates(dmpDescriptionTemplatesFields, data); + FieldSet otherDmpVersionsFields = fields.extractPrefixed(this.asPrefix(Dmp._otherDmpVersions)); + Map> otherDmpVersionsMap = this.collectOtherDmpVersions(otherDmpVersionsFields, data); + Set authorizationFlags = this.extractAuthorizationFlags(fields, Dmp._authorizationFlags, this.authorizationContentResolver.getPermissionNames()); Map affiliatedResourceMap = authorizationFlags == null || authorizationFlags.isEmpty() ? null : this.authorizationContentResolver.dmpsAffiliation(data.stream().map(DmpEntity::getId).collect(Collectors.toList())); @@ -134,6 +137,7 @@ public class DmpBuilder extends BaseBuilder { if (dmpUsersMap != null && !dmpUsersMap.isEmpty() && dmpUsersMap.containsKey(d.getId())) m.setDmpUsers(dmpUsersMap.get(d.getId())); if (descriptionsMap != null && !descriptionsMap.isEmpty() && descriptionsMap.containsKey(d.getId())) m.setDescriptions(descriptionsMap.get(d.getId())); if (dmpDescriptionTemplatesMap != null && !dmpDescriptionTemplatesMap.isEmpty() && dmpDescriptionTemplatesMap.containsKey(d.getId())) m.setDmpDescriptionTemplates(dmpDescriptionTemplatesMap.get(d.getId())); + if (otherDmpVersionsMap != null && !otherDmpVersionsMap.isEmpty() && otherDmpVersionsMap.containsKey(d.getGroupId())) m.setOtherDmpVersions(otherDmpVersionsMap.get(d.getGroupId())); if (!propertiesFields.isEmpty() && d.getProperties() != null){ DmpPropertiesEntity propertyDefinition = this.jsonHandlingService.fromJsonSafe(DmpPropertiesEntity.class, d.getProperties()); m.setProperties(this.builderFactory.builder(DmpPropertiesBuilder.class).authorize(this.authorize).build(propertiesFields, propertyDefinition)); @@ -297,4 +301,22 @@ public class DmpBuilder extends BaseBuilder { return itemMap; } + private Map> collectOtherDmpVersions(FieldSet fields, List data) throws MyApplicationException { + if (fields.isEmpty() || data.isEmpty()) return null; + this.logger.debug("checking related - {}", Dmp.class.getSimpleName()); + + Map> itemMap; + FieldSet clone = new BaseFieldSet(fields.getFields()).ensure(Dmp._id); + DmpQuery query = this.queryFactory.query(DmpQuery.class).disableTracking().authorize(this.authorize).groupIds(data.stream().map(DmpEntity::getGroupId).distinct().collect(Collectors.toList())); + itemMap = this.builderFactory.builder(DmpBuilder.class).authorize(this.authorize).asMasterKey(query, clone, x -> x.getGroupId()); + + if (!fields.hasField(this.asIndexer(Dmp._otherDmpVersions, Dmp._id))) { + itemMap.values().stream().flatMap(List::stream).filter(x -> x != null).peek(x -> { + x.setId(null); + }); + } + + return itemMap; + } + } diff --git a/backend/core/src/main/java/org/opencdmp/model/censorship/PublicDmpCensor.java b/backend/core/src/main/java/org/opencdmp/model/censorship/PublicDmpCensor.java index d0993170b..7e3a43605 100644 --- a/backend/core/src/main/java/org/opencdmp/model/censorship/PublicDmpCensor.java +++ b/backend/core/src/main/java/org/opencdmp/model/censorship/PublicDmpCensor.java @@ -44,6 +44,8 @@ public class PublicDmpCensor extends BaseCensor { this.censorFactory.censor(PublicDmpUserCensor.class).censor(dmpDescriptionsFields); FieldSet dmpReferencesFields = fields.extractPrefixed(this.asIndexerPrefix(PublicDmp._dmpReferences)); this.censorFactory.censor(PublicDmpReferenceCensor.class).censor(dmpReferencesFields); + FieldSet otherDmpVersionsFields = fields.extractPrefixed(this.asIndexerPrefix(PublicDmp._otherDmpVersions)); + this.censorFactory.censor(PublicDmpCensor.class).censor(otherDmpVersionsFields); } } diff --git a/backend/core/src/main/java/org/opencdmp/model/censorship/dmp/DmpCensor.java b/backend/core/src/main/java/org/opencdmp/model/censorship/dmp/DmpCensor.java index d0cb6b249..27ae23df5 100644 --- a/backend/core/src/main/java/org/opencdmp/model/censorship/dmp/DmpCensor.java +++ b/backend/core/src/main/java/org/opencdmp/model/censorship/dmp/DmpCensor.java @@ -52,5 +52,7 @@ public class DmpCensor extends BaseCensor { this.censorFactory.censor(EntityDoiCensor.class).censor(doisFields, userId); FieldSet propertiesFields = fields.extractPrefixed(this.asIndexerPrefix(Dmp._properties)); this.censorFactory.censor(DmpPropertiesCensor.class).censor(propertiesFields, userId); + FieldSet otherDmpVersionsFields = fields.extractPrefixed(this.asIndexerPrefix(Dmp._otherDmpVersions)); + this.censorFactory.censor(DmpCensor.class).censor(otherDmpVersionsFields, userId); } } diff --git a/backend/core/src/main/java/org/opencdmp/model/dmp/Dmp.java b/backend/core/src/main/java/org/opencdmp/model/dmp/Dmp.java index 9c42c1a93..2cf87e636 100644 --- a/backend/core/src/main/java/org/opencdmp/model/dmp/Dmp.java +++ b/backend/core/src/main/java/org/opencdmp/model/dmp/Dmp.java @@ -91,6 +91,9 @@ public class Dmp { private List authorizationFlags; public static final String _authorizationFlags = "authorizationFlags"; + private List otherDmpVersions; + public static final String _otherDmpVersions = "otherDmpVersions"; + private Boolean belongsToCurrentTenant; public static final String _belongsToCurrentTenant = "belongsToCurrentTenant"; @@ -302,4 +305,12 @@ public class Dmp { public void setBelongsToCurrentTenant(Boolean belongsToCurrentTenant) { this.belongsToCurrentTenant = belongsToCurrentTenant; } + + public List getOtherDmpVersions() { + return otherDmpVersions; + } + + public void setOtherDmpVersions(List otherDmpVersions) { + this.otherDmpVersions = otherDmpVersions; + } } diff --git a/backend/core/src/main/java/org/opencdmp/service/deposit/DepositClientImpl.java b/backend/core/src/main/java/org/opencdmp/service/deposit/DepositClientImpl.java index bb982580b..369e31a70 100644 --- a/backend/core/src/main/java/org/opencdmp/service/deposit/DepositClientImpl.java +++ b/backend/core/src/main/java/org/opencdmp/service/deposit/DepositClientImpl.java @@ -1,16 +1,12 @@ package org.opencdmp.service.deposit; +import gr.cite.tools.logging.LoggerService; +import gr.cite.tools.logging.MapLogEntry; import org.opencdmp.commonmodels.models.dmp.DmpModel; import org.opencdmp.depositbase.repository.DepositClient; import org.opencdmp.depositbase.repository.DepositConfiguration; -import gr.cite.tools.exception.MyApplicationException; -import gr.cite.tools.logging.LoggerService; -import gr.cite.tools.logging.MapLogEntry; import org.slf4j.LoggerFactory; import org.springframework.core.ParameterizedTypeReference; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatusCode; -import org.springframework.http.MediaType; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; @@ -26,21 +22,25 @@ public class DepositClientImpl implements DepositClient { @Override public String deposit(DmpModel dmpDepositModel, String repositoryAccessToken) throws Exception { - return depositClient.post().uri("", uriBuilder -> uriBuilder.queryParam("authToken", repositoryAccessToken).build()).bodyValue(dmpDepositModel).exchangeToMono(mono -> mono.statusCode().isError() ? mono.createException().flatMap(Mono::error) : mono.bodyToMono(String.class)).block(); + logger.debug(new MapLogEntry("deposit").And("dmpDepositModel", dmpDepositModel)); + return this.depositClient.post().uri("", uriBuilder -> uriBuilder.queryParam("authToken", repositoryAccessToken).build()).bodyValue(dmpDepositModel).exchangeToMono(mono -> mono.statusCode().isError() ? mono.createException().flatMap(Mono::error) : mono.bodyToMono(String.class)).block(); } @Override public String authenticate(String code) { - return depositClient.get().uri("/authenticate/", uriBuilder -> uriBuilder.queryParam("authToken", code).build()).exchangeToMono(mono -> mono.statusCode().isError() ? mono.createException().flatMap(Mono::error) : mono.bodyToMono(String.class)).block(); + logger.debug(new MapLogEntry("code")); + return this.depositClient.get().uri("/authenticate/", uriBuilder -> uriBuilder.queryParam("authToken", code).build()).exchangeToMono(mono -> mono.statusCode().isError() ? mono.createException().flatMap(Mono::error) : mono.bodyToMono(String.class)).block(); } @Override public DepositConfiguration getConfiguration() { - return depositClient.get().uri("/configuration").exchangeToMono(mono -> mono.statusCode().isError() ? mono.createException().flatMap(Mono::error) : mono.bodyToMono(new ParameterizedTypeReference() {})).block(); + logger.debug(new MapLogEntry("getConfiguration")); + return this.depositClient.get().uri("/configuration").exchangeToMono(mono -> mono.statusCode().isError() ? mono.createException().flatMap(Mono::error) : mono.bodyToMono(new ParameterizedTypeReference() {})).block(); } @Override public String getLogo() { - return depositClient.get().uri("/logo").exchangeToMono(mono -> mono.statusCode().isError() ? mono.createException().flatMap(Mono::error) : mono.bodyToMono(String.class)).block(); + logger.debug(new MapLogEntry("getLogo")); + return this.depositClient.get().uri("/logo").exchangeToMono(mono -> mono.statusCode().isError() ? mono.createException().flatMap(Mono::error) : mono.bodyToMono(String.class)).block(); } } diff --git a/backend/core/src/main/java/org/opencdmp/service/deposit/DepositServiceImpl.java b/backend/core/src/main/java/org/opencdmp/service/deposit/DepositServiceImpl.java index 5091bfaea..dc9b170c3 100644 --- a/backend/core/src/main/java/org/opencdmp/service/deposit/DepositServiceImpl.java +++ b/backend/core/src/main/java/org/opencdmp/service/deposit/DepositServiceImpl.java @@ -10,6 +10,8 @@ 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.logging.LoggerService; +import gr.cite.tools.logging.MapLogEntry; import gr.cite.tools.validation.ValidatorFactory; import org.apache.commons.io.FilenameUtils; import org.opencdmp.authorization.AuthorizationFlags; @@ -55,14 +57,15 @@ import org.opencdmp.service.filetransformer.FileTransformerService; import org.opencdmp.service.storage.StorageFileProperties; import org.opencdmp.service.storage.StorageFileService; import org.opencdmp.service.tenant.TenantProperties; -import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.context.event.EventListener; import org.springframework.context.i18n.LocaleContextHolder; 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.crypto.BadPaddingException; import javax.crypto.IllegalBlockSizeException; @@ -82,7 +85,7 @@ import java.util.stream.Collectors; @Service public class DepositServiceImpl implements DepositService { - private static final Logger logger = LoggerFactory.getLogger(DepositServiceImpl.class); + private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(DepositServiceImpl.class)); private final DepositProperties depositProperties; private final Map clients; @@ -150,7 +153,12 @@ public class DepositServiceImpl implements DepositService { if (source != null) { TokenExchangeModel tokenExchangeModel = new TokenExchangeModel("deposit:" + repositoryIdByTenant, 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(); + WebClient webClient = WebClient.builder().baseUrl(source.getUrl() + "/api/deposit") + .filters(exchangeFilterFunctions -> { + exchangeFilterFunctions.add(apiKeyExchangeFilterFunction); + exchangeFilterFunctions.add(logRequest()); + exchangeFilterFunctions.add(logResponse()); + }).build(); DepositClientImpl repository = new DepositClientImpl(webClient); this.clients.put(repositoryIdByTenant, repository); return repository; @@ -376,4 +384,25 @@ public class DepositServiceImpl implements DepositService { return depositClient.authenticate(model.getCode()); } + private static ExchangeFilterFunction logRequest() { + return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> { + logger.debug(new MapLogEntry("Request").And("method", clientRequest.method().toString()).And("url", clientRequest.url())); + return Mono.just(clientRequest); + }); + } + + private static ExchangeFilterFunction logResponse() { + return ExchangeFilterFunction.ofResponseProcessor(response -> { + if (response.statusCode().isError()) { + return response.mutate().build().bodyToMono(String.class) + .flatMap(body -> { + logger.error(new MapLogEntry("Response").And("method", response.request().getMethod().toString()).And("url", response.request().getURI()).And("status", response.statusCode().toString()).And("body", body)); + return Mono.just(response); + }); + } + return Mono.just(response); + + }); + } + } diff --git a/backend/core/src/main/java/org/opencdmp/service/externalfetcher/ExternalFetcherServiceImpl.java b/backend/core/src/main/java/org/opencdmp/service/externalfetcher/ExternalFetcherServiceImpl.java index a3e8ec9ad..805d10b94 100644 --- a/backend/core/src/main/java/org/opencdmp/service/externalfetcher/ExternalFetcherServiceImpl.java +++ b/backend/core/src/main/java/org/opencdmp/service/externalfetcher/ExternalFetcherServiceImpl.java @@ -6,18 +6,19 @@ import com.jayway.jsonpath.DocumentContext; import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.PathNotFoundException; import gr.cite.tools.exception.MyApplicationException; +import gr.cite.tools.logging.LoggerService; +import gr.cite.tools.logging.MapLogEntry; import net.minidev.json.JSONArray; import org.opencdmp.commons.JsonHandlingService; import org.opencdmp.commons.enums.ExternalFetcherSourceType; import org.opencdmp.commons.types.externalfetcher.StaticOptionEntity; import org.opencdmp.convention.ConventionService; import org.opencdmp.data.ReferenceEntity; -import org.opencdmp.model.reference.Reference; import org.opencdmp.model.reference.Field; +import org.opencdmp.model.reference.Reference; import org.opencdmp.service.externalfetcher.config.entities.*; import org.opencdmp.service.externalfetcher.criteria.ExternalReferenceCriteria; import org.opencdmp.service.externalfetcher.models.ExternalDataResult; -import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.ParameterizedTypeReference; @@ -28,7 +29,9 @@ import org.springframework.http.ResponseEntity; import org.springframework.http.client.reactive.ReactorClientHttpConnector; import org.springframework.http.codec.json.Jackson2JsonDecoder; 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 reactor.netty.http.client.HttpClient; import java.util.*; @@ -38,7 +41,7 @@ import java.util.stream.Collectors; @Service public class ExternalFetcherServiceImpl implements ExternalFetcherService { - private static final Logger logger = LoggerFactory.getLogger(ExternalFetcherServiceImpl.class); + private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(ExternalFetcherServiceImpl.class)); private WebClient webClient; private final ConventionService conventionService; @@ -51,10 +54,13 @@ public class ExternalFetcherServiceImpl implements ExternalFetcherService { private WebClient getWebClient() { if (this.webClient == null) { - this.webClient = WebClient.builder().codecs(clientCodecConfigurer -> { - clientCodecConfigurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(new ObjectMapper(), MediaType.APPLICATION_JSON)); - clientCodecConfigurer.defaultCodecs().maxInMemorySize(2 * ((int) Math.pow(1024, 3))); //GK: Why here??? - } + this.webClient = WebClient.builder().filters(exchangeFilterFunctions -> { + exchangeFilterFunctions.add(logRequest()); + exchangeFilterFunctions.add(logResponse()); + }).codecs(clientCodecConfigurer -> { + clientCodecConfigurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(new ObjectMapper(), MediaType.APPLICATION_JSON)); + clientCodecConfigurer.defaultCodecs().maxInMemorySize(2 * ((int) Math.pow(1024, 3))); //GK: Why here??? + } ).clientConnector(new ReactorClientHttpConnector(HttpClient.create().followRedirect(true))).build(); } return this.webClient; @@ -147,12 +153,14 @@ public class ExternalFetcherServiceImpl implements ExternalFetcherService { case POST -> method =HttpMethod.POST; default -> throw new MyApplicationException("unrecognized type " + authenticationConfiguration.getAuthMethod()); } - + + logger.debug(new MapLogEntry("Authentication").And("url", authenticationConfiguration.getAuthUrl())); Map response = this.getWebClient().method(method).uri(authenticationConfiguration.getAuthUrl()) .contentType(MediaType.APPLICATION_JSON) .bodyValue(this.parseBodyString(authenticationConfiguration.getAuthRequestBody())) - .exchangeToMono(mono -> mono.bodyToMono(new ParameterizedTypeReference>() { - })).block(); + .exchangeToMono(mono -> mono.statusCode().isError() ? + mono.createException().flatMap(Mono::error) : mono.bodyToMono(new ParameterizedTypeReference>() {})) + .block(); if (response == null) throw new MyApplicationException("Authentication " + authenticationConfiguration.getAuthUrl() + " failed"); return authenticationConfiguration.getType() + " " + response.getOrDefault(authenticationConfiguration.getAuthTokenPath(), null); @@ -259,7 +267,10 @@ public class ExternalFetcherServiceImpl implements ExternalFetcherService { case POST -> method =HttpMethod.POST; default -> throw new MyApplicationException("unrecognized type " + apiSource.getHttpMethod()); } - + + logger.debug(new MapLogEntry("Fetch data") + .And("url", urlString) + .And("body", jsonBody)); ResponseEntity response = this.getWebClient().method(method).uri(urlString).headers(httpHeaders -> { if (this.conventionService.isNullOrEmpty(apiSource.getContentType())) { httpHeaders.setAccept(Collections.singletonList(MediaType.valueOf(apiSource.getContentType()))); @@ -374,4 +385,25 @@ public class ExternalFetcherServiceImpl implements ExternalFetcherService { return finalBodyString; } + private static ExchangeFilterFunction logRequest() { + return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> { + logger.debug(new MapLogEntry("Request").And("method", clientRequest.method().toString()).And("url", clientRequest.url())); + return Mono.just(clientRequest); + }); + } + + private static ExchangeFilterFunction logResponse() { + return ExchangeFilterFunction.ofResponseProcessor(response -> { + if (response.statusCode().isError()) { + return response.mutate().build().bodyToMono(String.class) + .flatMap(body -> { + logger.error(new MapLogEntry("Response").And("method", response.request().getMethod().toString()).And("url", response.request().getURI()).And("status", response.statusCode().toString()).And("body", body)); + return Mono.just(response); + }); + } + return Mono.just(response); + + }); + } + } diff --git a/backend/core/src/main/java/org/opencdmp/service/filetransformer/FileTransformerRepository.java b/backend/core/src/main/java/org/opencdmp/service/filetransformer/FileTransformerRepository.java index 1a28fa2ff..214d32831 100644 --- a/backend/core/src/main/java/org/opencdmp/service/filetransformer/FileTransformerRepository.java +++ b/backend/core/src/main/java/org/opencdmp/service/filetransformer/FileTransformerRepository.java @@ -1,16 +1,20 @@ package org.opencdmp.service.filetransformer; +import gr.cite.tools.logging.LoggerService; +import gr.cite.tools.logging.MapLogEntry; import org.opencdmp.commonmodels.models.FileEnvelopeModel; import org.opencdmp.commonmodels.models.description.DescriptionModel; import org.opencdmp.commonmodels.models.dmp.DmpModel; import org.opencdmp.filetransformerbase.interfaces.FileTransformerClient; import org.opencdmp.filetransformerbase.interfaces.FileTransformerConfiguration; +import org.slf4j.LoggerFactory; import org.springframework.core.ParameterizedTypeReference; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; public class FileTransformerRepository implements FileTransformerClient { + private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(FileTransformerRepository.class)); private final WebClient transformerClient; @@ -20,30 +24,35 @@ public class FileTransformerRepository implements FileTransformerClient { @Override public FileEnvelopeModel exportDmp(DmpModel dmpModel, String format) { + logger.debug(new MapLogEntry("exportDmp").And("format", format).And("dmpModel", dmpModel)); return this.transformerClient.post().uri("/export/dmp", uriBuilder -> uriBuilder.queryParam("format", format).build()).bodyValue(dmpModel) .exchangeToMono(mono -> mono.statusCode().isError() ? mono.createException().flatMap(Mono::error) : mono.bodyToMono(FileEnvelopeModel.class)).block(); } @Override public DmpModel importDmp(FileEnvelopeModel fileEnvelope) { + logger.debug(new MapLogEntry("importDmp").And("fileEnvelope", fileEnvelope)); return this.transformerClient.post().uri("/import/dmp").bodyValue(fileEnvelope) .exchangeToMono(mono -> mono.statusCode().isError() ? mono.createException().flatMap(Mono::error) : mono.bodyToMono(DmpModel.class)).block(); } @Override public FileEnvelopeModel exportDescription(DescriptionModel descriptionModel, String format) { + logger.debug(new MapLogEntry("exportDescription").And("format", format).And("descriptionModel", descriptionModel)); return this.transformerClient.post().uri("/export/description", uriBuilder -> uriBuilder.queryParam("format", format).build()).bodyValue(descriptionModel) .exchangeToMono(mono -> mono.statusCode().isError() ? mono.createException().flatMap(Mono::error) : mono.bodyToMono(FileEnvelopeModel.class)).block(); } @Override public DescriptionModel importDescription(FileEnvelopeModel fileEnvelope) { + logger.debug(new MapLogEntry("importDescription").And("fileEnvelope", fileEnvelope)); return this.transformerClient.post().uri("/import/description").bodyValue(fileEnvelope) .exchangeToMono(mono -> mono.statusCode().isError() ? mono.createException().flatMap(Mono::error) : mono.bodyToMono(DescriptionModel.class)).block(); } @Override public FileTransformerConfiguration getConfiguration() { + logger.debug(new MapLogEntry("getConfiguration")); return this.transformerClient.get().uri("/formats") .exchangeToMono(mono -> mono.statusCode().isError() ? mono.createException().flatMap(Mono::error) : mono.bodyToMono(new ParameterizedTypeReference() {})).block(); } diff --git a/backend/core/src/main/java/org/opencdmp/service/filetransformer/FileTransformerServiceImpl.java b/backend/core/src/main/java/org/opencdmp/service/filetransformer/FileTransformerServiceImpl.java index 548e7b739..875439623 100644 --- a/backend/core/src/main/java/org/opencdmp/service/filetransformer/FileTransformerServiceImpl.java +++ b/backend/core/src/main/java/org/opencdmp/service/filetransformer/FileTransformerServiceImpl.java @@ -8,6 +8,8 @@ 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.logging.LoggerService; +import gr.cite.tools.logging.MapLogEntry; import org.opencdmp.authorization.AuthorizationFlags; import org.opencdmp.authorization.Permission; import org.opencdmp.commonmodels.models.FileEnvelopeModel; @@ -36,7 +38,6 @@ import org.opencdmp.query.TenantConfigurationQuery; import org.opencdmp.service.encryption.EncryptionService; import org.opencdmp.service.storage.StorageFileService; import org.opencdmp.service.tenant.TenantProperties; -import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; @@ -58,8 +59,7 @@ import java.util.*; @Service public class FileTransformerServiceImpl implements FileTransformerService { - private static final Logger logger = LoggerFactory.getLogger(FileTransformerServiceImpl.class); - + private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(FileTransformerServiceImpl.class)); private final FileTransformerProperties fileTransformerProperties; private final Map clients; private final TokenExchangeCacheService tokenExchangeCacheService; @@ -108,6 +108,7 @@ public class FileTransformerServiceImpl implements FileTransformerService { FileTransformerRepository repository = new FileTransformerRepository(WebClient.builder().baseUrl(source.getUrl() + "/api/file-transformer").filters(exchangeFilterFunctions -> { exchangeFilterFunctions.add(tokenExchangeFilterFunction); exchangeFilterFunctions.add(logRequest()); + exchangeFilterFunctions.add(logResponse()); }).build()); this.clients.put(repositoryIdByTenant, repository); return repository; @@ -259,12 +260,24 @@ public class FileTransformerServiceImpl implements FileTransformerService { 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))); + logger.debug(new MapLogEntry("Request").And("method", clientRequest.method().toString()).And("url", clientRequest.url())); return Mono.just(clientRequest); }); } + + private static ExchangeFilterFunction logResponse() { + return ExchangeFilterFunction.ofResponseProcessor(response -> { + if (response.statusCode().isError()) { + return response.mutate().build().bodyToMono(String.class) + .flatMap(body -> { + logger.error(new MapLogEntry("Response").And("method", response.request().getMethod().toString()).And("url", response.request().getURI()).And("status", response.statusCode().toString()).And("body", body)); + return Mono.just(response); + }); + } + return Mono.just(response); + + }); + } } diff --git a/dmp-frontend/src/app/core/model/dmp/dmp.ts b/dmp-frontend/src/app/core/model/dmp/dmp.ts index 02dbc9af4..a896f255f 100644 --- a/dmp-frontend/src/app/core/model/dmp/dmp.ts +++ b/dmp-frontend/src/app/core/model/dmp/dmp.ts @@ -35,6 +35,7 @@ export interface Dmp extends BaseEntity { descriptions?: Description[]; dmpDescriptionTemplates?: DmpDescriptionTemplate[]; entityDois?: EntityDoi[]; + otherDmpVersions?: Dmp[]; authorizationFlags?: AppPermission[]; } @@ -169,6 +170,7 @@ export interface PublicDmp extends BaseEntity { dmpUsers: PublicDmpUser[]; descriptions: PublicDescription[]; entityDois: PublicEntityDoi[]; + otherDmpVersions?: PublicDmp[]; } export interface PublicDmpReference { diff --git a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html index c641d9cc1..b2e24692a 100644 --- a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html +++ b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html @@ -34,8 +34,8 @@
- - + + {{'DMP-OVERVIEW.VERSION' | translate}} {{version.version}} 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 3e081a54e..d663a7c9c 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 @@ -58,6 +58,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { dmp: any; selectedBlueprint: DmpBlueprint; + selectedDmpVersion: any; researchers: DmpReference[] = []; isNew = true; isFinalized = false; @@ -67,7 +68,6 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { // isUserOwner: boolean; isLocked: Boolean; textMessage: any; - pastVersions: Dmp[]; //TODO: get these from the backend selectedModel: EntityDoi; fileTransformerEntityTypeEnum = FileTransformerEntityType; @@ -121,6 +121,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { .subscribe(data => { this.dmp = data; this.dmp.dmpUsers = data.dmpUsers.filter(x => x.isActive === IsActive.Active); + this.dmp.otherDmpVersions = data.otherDmpVersions?.filter(x => x.isActive === IsActive.Active) || null; if (this.dmp.descriptions) { if (this.dmp.status == DmpStatus.Finalized) { this.dmp.descriptions = data.descriptions.filter(x => x.isActive === IsActive.Active && x.status === DescriptionStatus.Finalized); @@ -134,9 +135,9 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { if (!this.hasDoi()) { this.selectedModel = this.dmp.entityDois[0]; } + this.selectedDmpVersion = this.dmp; this.checkLockStatus(this.dmp.id); // this.setIsUserOwner(); - this.getAllVersions(this.dmp); // const breadCrumbs = []; // breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.MY-DMPS'), url: "/plans" }); // breadCrumbs.push({ parentComponentName: 'DmpListingComponent', label: this.dmp.label, url: '/plans/overview/' + this.dmp.id }); @@ -162,8 +163,8 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { if (!this.hasDoi()) { this.selectedModel = this.dmp.entityDois[0]; } + this.selectedDmpVersion = this.dmp; // this.checkLockStatus(this.dmp.id); - this.getAllVersions(this.dmp); // const breadCrumbs = []; // breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.PUBLIC-DMPS'), url: "/explore-plans" }); // breadCrumbs.push({ parentComponentName: 'DmpListingComponent', label: this.dmp.label, url: '/plans/overview/public/' + this.dmp.id }); @@ -476,15 +477,6 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { return (this.dmp.entityDois == null || this.dmp.entityDois.length == 0); } - getAllVersions(dmp: Dmp) { - //TODO: add this - // this.dmpService.getAllVersions(dmp.groupId, this.isPublicView) - // .pipe(takeUntil(this._destroyed)) - // .subscribe(items => { - // this.versions = items; - // }); - } - afterDeposit(result: EntityDoi[]) { if (result.length > 0) { this.dmp.entityDois = result; @@ -771,6 +763,11 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { [nameof(x => x.blueprint), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.id)].join('.'), [nameof(x => x.blueprint), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.label)].join('.'), + [nameof(x => x.otherDmpVersions), nameof(x => x.id)].join('.'), + [nameof(x => x.otherDmpVersions), nameof(x => x.groupId)].join('.'), + [nameof(x => x.otherDmpVersions), nameof(x => x.version)].join('.'), + [nameof(x => x.otherDmpVersions), nameof(x => x.isActive)].join('.'), + nameof(x => x.hash), ] } diff --git a/dmp-frontend/src/assets/i18n/en.json b/dmp-frontend/src/assets/i18n/en.json index 26f39838b..8f50accb6 100644 --- a/dmp-frontend/src/assets/i18n/en.json +++ b/dmp-frontend/src/assets/i18n/en.json @@ -348,7 +348,7 @@ "LANGUAGE": "Language", "PRIMARY-COLOR": "Primary Color", "PRIMARY-COLOR-2": "Primary Color 2", - "PRIMARY-COLOR-3": "Primary Color 2", + "PRIMARY-COLOR-3": "Primary Color 3", "SECONDARY-COLOR": "Secondary Color", "DISABLE-SYSTEM-SOURCES": "Disable System Sources", "DEPOSIT-PLUGINS": "Plugin", diff --git a/docs/docs/documentation/administration/tenant-configuration.md b/docs/docs/documentation/administration/tenant-configuration.md index 694d23ad2..718c297da 100644 --- a/docs/docs/documentation/administration/tenant-configuration.md +++ b/docs/docs/documentation/administration/tenant-configuration.md @@ -5,4 +5,71 @@ description: Configure the tenant you are logged in with # Tenant Configuration -TODO: thgiannos \ No newline at end of file +On this page, we can configure the tenant we are logged in with. The configuration options are separated in the following sections. + +:::info + +Only tenant administrators can access this page. + +::: + +
+ Default Tenant Locale + +Here we specify the locale configuration, which will be applied by default to the users of this tenant. + +- **Timezone** +- **Culture** +- **Language** +
+ +
+ App Colors + +Here we specify the color accents, which will be applied to the UI when this tenant is selected. Every tenant can have a different theme. + +- **Primary Color** +- **Primary Color 2** +- **Primary Color 3** +- **Secondary Color** +
+ +
+ Deposit Plugins + +Here we specify the deposit plugins, which will be available for this tenant. We can add plugins by pressing the `Add Source` button. For every plugin, we have to specify the following. + +- **Repository Id**: An identifier for the deposit plugin. +- **Url**: The url of the endpoint the deposit listens to. +- **Issuer Url**: The authentication token issuer url. +- **Client Id**: The authentication client. +- **Client Secret**: The authentication client secret. +- **Scope**: The authentication token scope. +- **Pdf Transformer Id**: The id of the file transformer plugin used for pdf files, if configured and available.
*Please refer to the next section.* +- **Rda Transformer Id**: The id of the file transformer plugin used for rda files, if configured and available.
*Please refer to the next section.* +
+ +
+ File Transformer Plugins + +Here we specify the file transformer plugins, which will be available for this tenant. We can add plugins by pressing the `Add Source` button. For every plugin, we have to specify the following. + +- **Transformer Id**: An identifier for the transformer plugin.
*This id can be added on deposit plugin configurations.* +- **Url**: The url of the endpoint the deposit listens to. +- **Issuer Url**: The authentication token issuer url. +- **Client Id**: The authentication client. +- **Client Secret**: The authentication client secret. +- **Scope**: The authentication token scope. +
+ +
+ Extra Logo + +Here we can upload an extra logo, which will be displayed next to the platform logo. It is a great way for tenant branding. +
+ +
+ Notification Preferences + +Here we specify the notification preferences, which will be applied by default to the users of this tenant. For every notification case, we can specify the channels which will be used and their priority. +
\ No newline at end of file