From f98742f577a448afef1686faccea5f903f84c0d2 Mon Sep 17 00:00:00 2001 From: sgiannopoulos Date: Thu, 11 Apr 2024 17:26:04 +0300 Subject: [PATCH 1/2] metrics impl --- .../eudat/commons/metrics}/MetricNames.java | 2 +- .../eudat/service/metrics/MetricsService.java | 11 ++ .../service/metrics/MetricsServiceImpl.java | 92 +++++++++++++ .../service/metrics/UpdateMetricsTask.java | 130 ++++++++++++++++++ .../UpdateMetricsTaskConfiguration.java | 9 ++ .../metrics/UpdateMetricsTaskProperties.java | 27 ++++ .../eudat/logic/managers/MetricsManager.java | 64 ++++----- .../src/main/resources/config/application.yml | 5 +- .../web/src/main/resources/config/metrics.yml | 30 ++++ .../src/main/resources/config/security.yml | 2 +- 10 files changed, 336 insertions(+), 36 deletions(-) rename dmp-backend/{web/src/main/java/eu/eudat/types => core/src/main/java/eu/eudat/commons/metrics}/MetricNames.java (97%) create mode 100644 dmp-backend/core/src/main/java/eu/eudat/service/metrics/MetricsService.java create mode 100644 dmp-backend/core/src/main/java/eu/eudat/service/metrics/MetricsServiceImpl.java create mode 100644 dmp-backend/core/src/main/java/eu/eudat/service/metrics/UpdateMetricsTask.java create mode 100644 dmp-backend/core/src/main/java/eu/eudat/service/metrics/UpdateMetricsTaskConfiguration.java create mode 100644 dmp-backend/core/src/main/java/eu/eudat/service/metrics/UpdateMetricsTaskProperties.java create mode 100644 dmp-backend/web/src/main/resources/config/metrics.yml diff --git a/dmp-backend/web/src/main/java/eu/eudat/types/MetricNames.java b/dmp-backend/core/src/main/java/eu/eudat/commons/metrics/MetricNames.java similarity index 97% rename from dmp-backend/web/src/main/java/eu/eudat/types/MetricNames.java rename to dmp-backend/core/src/main/java/eu/eudat/commons/metrics/MetricNames.java index bc9d0f4a1..cb4c80f3b 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/types/MetricNames.java +++ b/dmp-backend/core/src/main/java/eu/eudat/commons/metrics/MetricNames.java @@ -1,4 +1,4 @@ -package eu.eudat.types; +package eu.eudat.commons.metrics; public class MetricNames { public static final String DATASET_TEMPLATE = "argos_dmp_templates"; diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/metrics/MetricsService.java b/dmp-backend/core/src/main/java/eu/eudat/service/metrics/MetricsService.java new file mode 100644 index 000000000..05945fce5 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/service/metrics/MetricsService.java @@ -0,0 +1,11 @@ +package eu.eudat.service.metrics; + +import io.prometheus.client.Gauge; + +import javax.management.InvalidApplicationException; +import java.util.Map; + +public interface MetricsService { + void calculate(Map gauges) throws InvalidApplicationException; + Map gaugesBuild(); +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/metrics/MetricsServiceImpl.java b/dmp-backend/core/src/main/java/eu/eudat/service/metrics/MetricsServiceImpl.java new file mode 100644 index 000000000..eb8133590 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/service/metrics/MetricsServiceImpl.java @@ -0,0 +1,92 @@ +package eu.eudat.service.metrics; + +import eu.eudat.commons.enums.DmpStatus; +import eu.eudat.commons.enums.IsActive; +import eu.eudat.commons.metrics.MetricNames; +import eu.eudat.data.TenantEntityManager; +import eu.eudat.query.DmpQuery; +import gr.cite.tools.data.query.QueryFactory; +import io.micrometer.prometheus.PrometheusMeterRegistry; +import io.prometheus.client.Gauge; +import org.springframework.stereotype.Service; + +import javax.management.InvalidApplicationException; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Service +public class MetricsServiceImpl implements MetricsService { + private final PrometheusMeterRegistry registry; + private final QueryFactory queryFactory; + private final TenantEntityManager entityManager; + + public MetricsServiceImpl(PrometheusMeterRegistry registry, QueryFactory queryFactory, TenantEntityManager entityManager) { + this.registry = registry; + this.queryFactory = queryFactory; + this.entityManager = entityManager; + } + + @Override + public void calculate(Map gauges) throws InvalidApplicationException { + try { + this.entityManager.disableTenantFilters(); + + this.setGauseValue(gauges, MetricNames.DMP, calculateFinalizedDmps(), MetricNames.FINALIZED); + }finally { + this.entityManager.enableTenantFilters(); + } + } + + @Override + public Map gaugesBuild() { + registry.clear(); + + return Stream.of( new Object[][]{ + {MetricNames.DMP, Gauge.build().name(MetricNames.DMP).help("Number of managed DMPs").labelNames("status").register(registry.getPrometheusRegistry())}, + {MetricNames.NEXUS + MetricNames.DMP, Gauge.build().name(MetricNames.NEXUS + MetricNames.DMP).help("Number of managed DMPs during Nexus").labelNames("status").register(registry.getPrometheusRegistry())}, + + {MetricNames.FUNDERS, Gauge.build().name(MetricNames.FUNDERS).help("Number of registered Funders").register(registry.getPrometheusRegistry())}, + {MetricNames.GRANTS, Gauge.build().name(MetricNames.GRANTS).help("Number of registered Grants").register(registry.getPrometheusRegistry())}, + {MetricNames.PROJECT, Gauge.build().name(MetricNames.PROJECT).help("Number of registered Projects").register(registry.getPrometheusRegistry())}, + {MetricNames.RESEARCHER, Gauge.build().name(MetricNames.RESEARCHER).help("Number of Colaborators/Researchers").register(registry.getPrometheusRegistry())}, + + {MetricNames.NEXUS + MetricNames.FUNDERS, Gauge.build().name(MetricNames.NEXUS + MetricNames.FUNDERS).help("Number of registered Funders during Nexus").register(registry.getPrometheusRegistry())}, + {MetricNames.NEXUS + MetricNames.GRANTS, Gauge.build().name(MetricNames.NEXUS + MetricNames.GRANTS).help("Number of registered Grants during Nexus").register(registry.getPrometheusRegistry())}, + {MetricNames.NEXUS + MetricNames.PROJECT, Gauge.build().name(MetricNames.NEXUS + MetricNames.PROJECT).help("Number of registered Projects during Nexus").register(registry.getPrometheusRegistry())}, + {MetricNames.NEXUS + MetricNames.RESEARCHER, Gauge.build().name(MetricNames.NEXUS + MetricNames.RESEARCHER).help("Number of Colaborators/Researchers during Nexus").register(registry.getPrometheusRegistry())}, + + {MetricNames.DATASET, Gauge.build().name(MetricNames.DATASET).help("Number of managed Dataset Descriptions").labelNames("status").register(registry.getPrometheusRegistry())}, + + {MetricNames.NEXUS + MetricNames.DATASET, Gauge.build().name(MetricNames.NEXUS + MetricNames.DATASET).help("Number of managed Dataset Descriptions during Nexus").labelNames("status").register(registry.getPrometheusRegistry())}, + + {MetricNames.DATASET_TEMPLATE, Gauge.build().name(MetricNames.DATASET_TEMPLATE).help("Number of dataset Templates").labelNames("status").register(registry.getPrometheusRegistry())}, + + {MetricNames.NEXUS + MetricNames.DATASET_TEMPLATE, Gauge.build().name(MetricNames.NEXUS + MetricNames.DATASET_TEMPLATE).help("Number of dataset Templates during Nexus").labelNames("status").register(registry.getPrometheusRegistry())}, + + {MetricNames.USERS, Gauge.build().name(MetricNames.USERS).help("Number of users").labelNames("type").register(registry.getPrometheusRegistry())}, + + {MetricNames.LANGUAGES, Gauge.build().name(MetricNames.LANGUAGES).help("Number of Languages").register(registry.getPrometheusRegistry())}, + + {MetricNames.DMP_WITH_GRANT, Gauge.build().name(MetricNames.DMP_WITH_GRANT).help("Number of Grants based on the status of the DMP that is using them").labelNames("status").register(registry.getPrometheusRegistry())}, + + {MetricNames.NEXUS + MetricNames.DMP_WITH_GRANT, Gauge.build().name(MetricNames.NEXUS + MetricNames.DMP_WITH_GRANT).help("Number of Grants based on the status of the DMP that is using them during Nexus").labelNames("status").register(registry.getPrometheusRegistry())}, + + {MetricNames.INSTALLATIONS, Gauge.build().name(MetricNames.INSTALLATIONS).help("Number of Installations").register(registry.getPrometheusRegistry())}, + {MetricNames.NEXUS + MetricNames.INSTALLATIONS, Gauge.build().name(MetricNames.NEXUS + MetricNames.INSTALLATIONS).help("Number of Installations").register(registry.getPrometheusRegistry())}, + + }).collect(Collectors.toMap(data -> (String)data[0], data -> (Gauge) data[1])); + } + + private double calculateFinalizedDmps(){ + return this.queryFactory.query(DmpQuery.class).statuses(DmpStatus.Finalized).isActive(IsActive.Active).count(); + } + + private void setGauseValue(Map gauges, String name, Double amount, String label) { + if(label != null) { + gauges.get(name).labels(label).set(amount); + } else { + gauges.get(name).set(amount); + } + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/metrics/UpdateMetricsTask.java b/dmp-backend/core/src/main/java/eu/eudat/service/metrics/UpdateMetricsTask.java new file mode 100644 index 000000000..212b448e3 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/service/metrics/UpdateMetricsTask.java @@ -0,0 +1,130 @@ +package eu.eudat.service.metrics; + +import eu.eudat.commons.enums.IsActive; +import eu.eudat.commons.fake.FakeRequestScope; +import eu.eudat.commons.metrics.MetricNames; +import eu.eudat.commons.scope.tenant.TenantScope; +import eu.eudat.data.QueueInboxEntity; +import eu.eudat.data.StorageFileEntity; +import eu.eudat.data.TenantEntity; +import eu.eudat.data.TenantEntityManager; +import eu.eudat.integrationevent.inbox.EventProcessingStatus; +import eu.eudat.model.StorageFile; +import eu.eudat.model.Tenant; +import eu.eudat.query.QueueInboxQuery; +import eu.eudat.query.StorageFileQuery; +import eu.eudat.query.TenantQuery; +import eu.eudat.service.storage.StorageFileService; +import gr.cite.queueinbox.entity.QueueInboxStatus; +import gr.cite.queueinbox.repository.CandidateInfo; +import gr.cite.tools.data.query.Ordering; +import gr.cite.tools.data.query.QueryFactory; +import gr.cite.tools.logging.LoggerService; +import io.micrometer.prometheus.PrometheusMeterRegistry; +import io.prometheus.client.Gauge; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import jakarta.persistence.OptimisticLockException; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationListener; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Service; + +import java.io.Closeable; +import java.io.IOException; +import java.time.Instant; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Service +@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON) +public class UpdateMetricsTask implements Closeable, ApplicationListener { + + private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(UpdateMetricsTask.class)); + private final UpdateMetricsTaskProperties _config; + private final ApplicationContext applicationContext; + private ScheduledExecutorService scheduler; + private Map gauges; + + public UpdateMetricsTask( + UpdateMetricsTaskProperties config, + ApplicationContext applicationContext) { + this._config = config; + this.applicationContext = applicationContext; + this.gauges = null; + } + + @Override + public void onApplicationEvent(ApplicationReadyEvent event) { + long intervalSeconds = this._config .getIntervalSeconds(); + if (this._config .getEnable() && intervalSeconds > 0) { + logger.info("File clean up run in {} seconds", intervalSeconds); + + scheduler = Executors.newScheduledThreadPool(1); + scheduler.scheduleAtFixedRate(this::process, 10, intervalSeconds, TimeUnit.SECONDS); + } else { + scheduler = null; + } + } + + @Override + public void close() throws IOException { + if (scheduler != null) this.scheduler.close(); + } + + protected void process() { + if (!this._config.getEnable()) return; + try { + this.ensureGauges(); + this.calculate(); + } catch (Exception ex) { + logger.error("Problem processing file cleanups. Breaking for next interval", ex); + } + } + + private void ensureGauges() { + if (this.gauges != null) return; + try (FakeRequestScope ignored = new FakeRequestScope()) { + MetricsService metricsService = this.applicationContext.getBean(MetricsService.class); + this.gauges = metricsService.gaugesBuild(); + } catch (Exception ex) { + logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex); + } + } + + private void calculate() { + EntityManager entityManager = null; + + try (FakeRequestScope ignored = new FakeRequestScope()) { + try { + + EntityManagerFactory entityManagerFactory = this.applicationContext.getBean(EntityManagerFactory.class); + + entityManager = entityManagerFactory.createEntityManager(); + + TenantEntityManager tenantEntityManager = this.applicationContext.getBean(TenantEntityManager.class); + tenantEntityManager.setEntityManager(entityManager); + TenantScope tenantScope = this.applicationContext.getBean(TenantScope.class); + tenantScope.setTenant(null, tenantScope.getDefaultTenantCode()); + + MetricsService metricsService = this.applicationContext.getBean(MetricsService.class); + + metricsService.calculate(this.gauges); + } finally { + if (entityManager != null) entityManager.close(); + } + } catch (Exception ex) { + logger.error("Problem executing purge. rolling back any db changes and marking error. Continuing...", ex); + } + } + +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/metrics/UpdateMetricsTaskConfiguration.java b/dmp-backend/core/src/main/java/eu/eudat/service/metrics/UpdateMetricsTaskConfiguration.java new file mode 100644 index 000000000..6adbbfafa --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/service/metrics/UpdateMetricsTaskConfiguration.java @@ -0,0 +1,9 @@ +package eu.eudat.service.metrics; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableConfigurationProperties(UpdateMetricsTaskProperties.class) +public class UpdateMetricsTaskConfiguration { +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/metrics/UpdateMetricsTaskProperties.java b/dmp-backend/core/src/main/java/eu/eudat/service/metrics/UpdateMetricsTaskProperties.java new file mode 100644 index 000000000..8ee52bba7 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/service/metrics/UpdateMetricsTaskProperties.java @@ -0,0 +1,27 @@ +package eu.eudat.service.metrics; + + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties(prefix = "metrics.task") +public class UpdateMetricsTaskProperties { + private boolean enable; + private int intervalSeconds; + + public boolean getEnable() { + return enable; + } + + public void setEnable(boolean enable) { + this.enable = enable; + } + + public int getIntervalSeconds() { + return intervalSeconds; + } + + public void setIntervalSeconds(int intervalSeconds) { + this.intervalSeconds = intervalSeconds; + } +} + diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/MetricsManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/MetricsManager.java index 9881aa269..ef82532fe 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/MetricsManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/MetricsManager.java @@ -1,7 +1,7 @@ package eu.eudat.logic.managers; import eu.eudat.commons.enums.DescriptionTemplateStatus; -import eu.eudat.types.MetricNames; +import eu.eudat.commons.metrics.MetricNames; import io.micrometer.prometheus.PrometheusMeterRegistry; import io.prometheus.client.Gauge; import jakarta.annotation.PostConstruct; @@ -75,37 +75,37 @@ public class MetricsManager { public MetricsManager(PrometheusMeterRegistry registry) { registry.clear(); this.gauges = Stream.of( new Object[][]{ - {MetricNames.DMP, Gauge.build().name(MetricNames.DMP).help("Number of managed DMPs").labelNames("status").register(registry.getPrometheusRegistry())}, - {MetricNames.NEXUS + MetricNames.DMP, Gauge.build().name(MetricNames.NEXUS + MetricNames.DMP).help("Number of managed DMPs during Nexus").labelNames("status").register(registry.getPrometheusRegistry())}, - - {MetricNames.FUNDERS, Gauge.build().name(MetricNames.FUNDERS).help("Number of registered Funders").register(registry.getPrometheusRegistry())}, - {MetricNames.GRANTS, Gauge.build().name(MetricNames.GRANTS).help("Number of registered Grants").register(registry.getPrometheusRegistry())}, - {MetricNames.PROJECT, Gauge.build().name(MetricNames.PROJECT).help("Number of registered Projects").register(registry.getPrometheusRegistry())}, - {MetricNames.RESEARCHER, Gauge.build().name(MetricNames.RESEARCHER).help("Number of Colaborators/Researchers").register(registry.getPrometheusRegistry())}, - - {MetricNames.NEXUS + MetricNames.FUNDERS, Gauge.build().name(MetricNames.NEXUS + MetricNames.FUNDERS).help("Number of registered Funders during Nexus").register(registry.getPrometheusRegistry())}, - {MetricNames.NEXUS + MetricNames.GRANTS, Gauge.build().name(MetricNames.NEXUS + MetricNames.GRANTS).help("Number of registered Grants during Nexus").register(registry.getPrometheusRegistry())}, - {MetricNames.NEXUS + MetricNames.PROJECT, Gauge.build().name(MetricNames.NEXUS + MetricNames.PROJECT).help("Number of registered Projects during Nexus").register(registry.getPrometheusRegistry())}, - {MetricNames.NEXUS + MetricNames.RESEARCHER, Gauge.build().name(MetricNames.NEXUS + MetricNames.RESEARCHER).help("Number of Colaborators/Researchers during Nexus").register(registry.getPrometheusRegistry())}, - - {MetricNames.DATASET, Gauge.build().name(MetricNames.DATASET).help("Number of managed Dataset Descriptions").labelNames("status").register(registry.getPrometheusRegistry())}, - - {MetricNames.NEXUS + MetricNames.DATASET, Gauge.build().name(MetricNames.NEXUS + MetricNames.DATASET).help("Number of managed Dataset Descriptions during Nexus").labelNames("status").register(registry.getPrometheusRegistry())}, - - {MetricNames.DATASET_TEMPLATE, Gauge.build().name(MetricNames.DATASET_TEMPLATE).help("Number of dataset Templates").labelNames("status").register(registry.getPrometheusRegistry())}, - - {MetricNames.NEXUS + MetricNames.DATASET_TEMPLATE, Gauge.build().name(MetricNames.NEXUS + MetricNames.DATASET_TEMPLATE).help("Number of dataset Templates during Nexus").labelNames("status").register(registry.getPrometheusRegistry())}, - - {MetricNames.USERS, Gauge.build().name(MetricNames.USERS).help("Number of users").labelNames("type").register(registry.getPrometheusRegistry())}, - - {MetricNames.LANGUAGES, Gauge.build().name(MetricNames.LANGUAGES).help("Number of Languages").register(registry.getPrometheusRegistry())}, - - {MetricNames.DMP_WITH_GRANT, Gauge.build().name(MetricNames.DMP_WITH_GRANT).help("Number of Grants based on the status of the DMP that is using them").labelNames("status").register(registry.getPrometheusRegistry())}, - - {MetricNames.NEXUS + MetricNames.DMP_WITH_GRANT, Gauge.build().name(MetricNames.NEXUS + MetricNames.DMP_WITH_GRANT).help("Number of Grants based on the status of the DMP that is using them during Nexus").labelNames("status").register(registry.getPrometheusRegistry())}, - - {MetricNames.INSTALLATIONS, Gauge.build().name(MetricNames.INSTALLATIONS).help("Number of Installations").register(registry.getPrometheusRegistry())}, - {MetricNames.NEXUS + MetricNames.INSTALLATIONS, Gauge.build().name(MetricNames.NEXUS + MetricNames.INSTALLATIONS).help("Number of Installations").register(registry.getPrometheusRegistry())}, +// {MetricNames.DMP, Gauge.build().name(MetricNames.DMP).help("Number of managed DMPs").labelNames("status").register(registry.getPrometheusRegistry())}, +// {MetricNames.NEXUS + MetricNames.DMP, Gauge.build().name(MetricNames.NEXUS + MetricNames.DMP).help("Number of managed DMPs during Nexus").labelNames("status").register(registry.getPrometheusRegistry())}, +// +// {MetricNames.FUNDERS, Gauge.build().name(MetricNames.FUNDERS).help("Number of registered Funders").register(registry.getPrometheusRegistry())}, +// {MetricNames.GRANTS, Gauge.build().name(MetricNames.GRANTS).help("Number of registered Grants").register(registry.getPrometheusRegistry())}, +// {MetricNames.PROJECT, Gauge.build().name(MetricNames.PROJECT).help("Number of registered Projects").register(registry.getPrometheusRegistry())}, +// {MetricNames.RESEARCHER, Gauge.build().name(MetricNames.RESEARCHER).help("Number of Colaborators/Researchers").register(registry.getPrometheusRegistry())}, +// +// {MetricNames.NEXUS + MetricNames.FUNDERS, Gauge.build().name(MetricNames.NEXUS + MetricNames.FUNDERS).help("Number of registered Funders during Nexus").register(registry.getPrometheusRegistry())}, +// {MetricNames.NEXUS + MetricNames.GRANTS, Gauge.build().name(MetricNames.NEXUS + MetricNames.GRANTS).help("Number of registered Grants during Nexus").register(registry.getPrometheusRegistry())}, +// {MetricNames.NEXUS + MetricNames.PROJECT, Gauge.build().name(MetricNames.NEXUS + MetricNames.PROJECT).help("Number of registered Projects during Nexus").register(registry.getPrometheusRegistry())}, +// {MetricNames.NEXUS + MetricNames.RESEARCHER, Gauge.build().name(MetricNames.NEXUS + MetricNames.RESEARCHER).help("Number of Colaborators/Researchers during Nexus").register(registry.getPrometheusRegistry())}, +// +// {MetricNames.DATASET, Gauge.build().name(MetricNames.DATASET).help("Number of managed Dataset Descriptions").labelNames("status").register(registry.getPrometheusRegistry())}, +// +// {MetricNames.NEXUS + MetricNames.DATASET, Gauge.build().name(MetricNames.NEXUS + MetricNames.DATASET).help("Number of managed Dataset Descriptions during Nexus").labelNames("status").register(registry.getPrometheusRegistry())}, +// +// {MetricNames.DATASET_TEMPLATE, Gauge.build().name(MetricNames.DATASET_TEMPLATE).help("Number of dataset Templates").labelNames("status").register(registry.getPrometheusRegistry())}, +// +// {MetricNames.NEXUS + MetricNames.DATASET_TEMPLATE, Gauge.build().name(MetricNames.NEXUS + MetricNames.DATASET_TEMPLATE).help("Number of dataset Templates during Nexus").labelNames("status").register(registry.getPrometheusRegistry())}, +// +// {MetricNames.USERS, Gauge.build().name(MetricNames.USERS).help("Number of users").labelNames("type").register(registry.getPrometheusRegistry())}, +// +// {MetricNames.LANGUAGES, Gauge.build().name(MetricNames.LANGUAGES).help("Number of Languages").register(registry.getPrometheusRegistry())}, +// +// {MetricNames.DMP_WITH_GRANT, Gauge.build().name(MetricNames.DMP_WITH_GRANT).help("Number of Grants based on the status of the DMP that is using them").labelNames("status").register(registry.getPrometheusRegistry())}, +// +// {MetricNames.NEXUS + MetricNames.DMP_WITH_GRANT, Gauge.build().name(MetricNames.NEXUS + MetricNames.DMP_WITH_GRANT).help("Number of Grants based on the status of the DMP that is using them during Nexus").labelNames("status").register(registry.getPrometheusRegistry())}, +// +// {MetricNames.INSTALLATIONS, Gauge.build().name(MetricNames.INSTALLATIONS).help("Number of Installations").register(registry.getPrometheusRegistry())}, +// {MetricNames.NEXUS + MetricNames.INSTALLATIONS, Gauge.build().name(MetricNames.NEXUS + MetricNames.INSTALLATIONS).help("Number of Installations").register(registry.getPrometheusRegistry())}, }).collect(Collectors.toMap(data -> (String)data[0], data -> (Gauge) data[1])); diff --git a/dmp-backend/web/src/main/resources/config/application.yml b/dmp-backend/web/src/main/resources/config/application.yml index 686f12bc6..be3428ab1 100644 --- a/dmp-backend/web/src/main/resources/config/application.yml +++ b/dmp-backend/web/src/main/resources/config/application.yml @@ -32,6 +32,7 @@ spring: optional:classpath:config/dashboard.yml[.yml], optional:classpath:config/dashboard-${spring.profiles.active}.yml[.yml], optional:file:../config/dashboard-${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], optional:classpath:config/authorization.yml[.yml], optional:classpath:config/authorization-${spring.profiles.active}.yml[.yml], optional:file:../config/authorization-${spring.profiles.active}.yml[.yml], + optional:classpath:config/metrics.yml[.yml], optional:classpath:config/metrics-${spring.profiles.active}.yml[.yml], optional:file:../config/metrics-${spring.profiles.active}.yml[.yml], optional:classpath:config/lock.yml[.yml], optional:classpath:config/lock-${spring.profiles.active}.yml[.yml], optional:file:../config/lock-${spring.profiles.active}.yml[.yml] - - + + diff --git a/dmp-backend/web/src/main/resources/config/metrics.yml b/dmp-backend/web/src/main/resources/config/metrics.yml new file mode 100644 index 000000000..b059adca9 --- /dev/null +++ b/dmp-backend/web/src/main/resources/config/metrics.yml @@ -0,0 +1,30 @@ +metrics: + task: + enable: true + intervalSeconds: 600 +management: + endpoint: + metrics: + enabled: true + prometheus: + enabled: true + health: + show-details: always + web: + base-path: / + exposure: + include: ["prometheus","health","metrics" ] + + metrics: + enabled: true + export: + prometheus: + enabled: true + enable: + http: true + jvm: true + jdbc: true + tomcat: true + logback: true + hikaricp: true + cache: true diff --git a/dmp-backend/web/src/main/resources/config/security.yml b/dmp-backend/web/src/main/resources/config/security.yml index 2c7e3f241..5776031be 100644 --- a/dmp-backend/web/src/main/resources/config/security.yml +++ b/dmp-backend/web/src/main/resources/config/security.yml @@ -2,7 +2,7 @@ web: security: enabled: true authorized-endpoints: [ api ] - allowed-endpoints: [ api/public, api/dmp/public, api/description/public, /api/supportive-material/public, api/language/public, api/contact-support/public, api/dashboard/public ] + allowed-endpoints: [ api/public, api/dmp/public, api/description/public, /api/supportive-material/public, api/language/public, api/contact-support/public, api/dashboard/public, prometheus, health, metrics ] idp: api-key: enabled: false From 15b4c7fbc61013c8680966e2901724705baf5002 Mon Sep 17 00:00:00 2001 From: amentis Date: Thu, 11 Apr 2024 17:30:55 +0300 Subject: [PATCH 2/2] description template upload changes, dmp description tag field type fix --- .../java/eu/eudat/audit/AuditableAction.java | 1 + .../FieldBuilder.java | 17 ++-- .../description/DescriptionServiceImpl.java | 38 ++++++--- .../controllers/StorageFileController.java | 46 +++++++---- .../storage-file/storage-file.service.ts | 17 ++-- ...ption-template-editor-field.component.html | 4 +- .../form-field/form-field.component.html | 18 ++--- .../form-field/form-field.component.ts | 79 ++++++++----------- 8 files changed, 121 insertions(+), 99 deletions(-) diff --git a/dmp-backend/core/src/main/java/eu/eudat/audit/AuditableAction.java b/dmp-backend/core/src/main/java/eu/eudat/audit/AuditableAction.java index 49de636cb..d400b79c0 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/audit/AuditableAction.java +++ b/dmp-backend/core/src/main/java/eu/eudat/audit/AuditableAction.java @@ -114,6 +114,7 @@ public class AuditableAction { public static final EventId StorageFile_Download = new EventId(14000, "StorageFile_Download"); public static final EventId StorageFile_Upload = new EventId(14001, "StorageFile_Upload"); + public static final EventId StorageFile_Query = new EventId(14002, "StorageFile_Query"); public static final EventId Dashboard_MyRecentActivityItems = new EventId(15000, "Dashboard_MyRecentActivityItems"); public static final EventId Dashboard_MyDashboardStatistics = new EventId(15001, "Dashboard_MyDashboardStatistics"); diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/builder/descriptionpropertiesdefinition/FieldBuilder.java b/dmp-backend/core/src/main/java/eu/eudat/model/builder/descriptionpropertiesdefinition/FieldBuilder.java index 50be8a7e7..1b98a3f69 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/model/builder/descriptionpropertiesdefinition/FieldBuilder.java +++ b/dmp-backend/core/src/main/java/eu/eudat/model/builder/descriptionpropertiesdefinition/FieldBuilder.java @@ -3,6 +3,7 @@ package eu.eudat.model.builder.descriptionpropertiesdefinition; import eu.eudat.authorization.AuthorizationFlags; import eu.eudat.commons.enums.FieldType; import eu.eudat.commons.types.description.FieldEntity; +import eu.eudat.commons.types.descriptiontemplate.fielddata.LabelAndMultiplicityDataEntity; import eu.eudat.commons.types.descriptiontemplate.fielddata.SelectDataEntity; import eu.eudat.convention.ConventionService; import eu.eudat.model.Reference; @@ -72,12 +73,16 @@ public class FieldBuilder extends BaseBuilder { if (fields.hasField(this.asIndexer(Field._dateValue)) && FieldType.isDateType(fieldType)) m.setDateValue(d.getDateValue()); if (fields.hasField(this.asIndexer(Field._textValue)) && FieldType.isTextType(fieldType)) m.setTextValue(d.getTextValue()); if (fields.hasField(this.asIndexer(Field._textListValue)) && FieldType.isTextListType(fieldType)) { - boolean isSelectMultiSelect = true; - if(this.fieldEntity != null && this.fieldEntity.getData() != null && this.fieldEntity.getData().getFieldType().equals(FieldType.SELECT) && this.fieldEntity.getData() instanceof SelectDataEntity){ - isSelectMultiSelect = ((SelectDataEntity) this.fieldEntity.getData()).getMultipleSelect(); - } - if (fieldType.equals(FieldType.SELECT) && !isSelectMultiSelect && !this.conventionService.isListNullOrEmpty(d.getTextListValue())){ - m.setTextValue(d.getTextListValue().stream().findFirst().orElse(null)); + boolean isMultiSelect = true; + if(this.fieldEntity != null && this.fieldEntity.getData() != null && (this.fieldEntity.getData().getFieldType().equals(FieldType.SELECT) || this.fieldEntity.getData().getFieldType().equals(FieldType.INTERNAL_ENTRIES_DMPS) || this.fieldEntity.getData().getFieldType().equals(FieldType.INTERNAL_ENTRIES_DESCRIPTIONS))){ + if (this.fieldEntity.getData() instanceof SelectDataEntity) isMultiSelect = ((SelectDataEntity) this.fieldEntity.getData()).getMultipleSelect(); + else if (this.fieldEntity.getData() instanceof LabelAndMultiplicityDataEntity) isMultiSelect = ((LabelAndMultiplicityDataEntity) this.fieldEntity.getData()).getMultipleSelect(); + + if (!isMultiSelect && !this.conventionService.isListNullOrEmpty(d.getTextListValue())){ + m.setTextValue(d.getTextListValue().stream().findFirst().orElse(null)); + }else{ + m.setTextListValue(d.getTextListValue()); + } } else{ m.setTextListValue(d.getTextListValue()); } 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 39e4268d2..31d6c6dbf 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 @@ -516,22 +516,38 @@ public class DescriptionServiceImpl implements DescriptionService { } } else if (FieldType.isTextListType(fieldType)) { - if (FieldType.INTERNAL_ENTRIES_DMPS.equals(fieldType) && !this.conventionService.isListNullOrEmpty(persist.getTextListValue())){ - List ids = persist.getTextListValue().stream().map(UUID::fromString).toList(); - Set existingIds = this.queryFactory.query(DmpQuery.class).ids(ids).isActive(IsActive.Active).collectAs(new BaseFieldSet().ensure(Dmp._id)).stream().map(DmpEntity::getId).collect(Collectors.toSet()); - for (UUID id : ids){ - if (!existingIds.contains(id)) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, Dmp.class.getSimpleName()}, LocaleContextHolder.getLocale())); + List ids = new ArrayList<>(); + if (FieldType.INTERNAL_ENTRIES_DMPS.equals(fieldType)) { + if (!this.conventionService.isListNullOrEmpty(persist.getTextListValue())) persist.getTextListValue().stream().map(UUID::fromString).toList(); + else if (!this.conventionService.isNullOrEmpty(persist.getTextValue())) ids.add(UUID.fromString(persist.getTextValue())); + + if (ids.size() > 0){ + Set existingIds = this.queryFactory.query(DmpQuery.class).ids(ids).isActive(IsActive.Active).collectAs(new BaseFieldSet().ensure(Dmp._id)).stream().map(DmpEntity::getId).collect(Collectors.toSet()); + for (UUID id : ids){ + if (!existingIds.contains(id)) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, Dmp.class.getSimpleName()}, LocaleContextHolder.getLocale())); + } } - } if (FieldType.INTERNAL_ENTRIES_DESCRIPTIONS.equals(fieldType) && !this.conventionService.isListNullOrEmpty(persist.getTextListValue())){ - List ids = persist.getTextListValue().stream().map(UUID::fromString).toList(); - Set existingIds = this.queryFactory.query(DescriptionQuery.class).ids(ids).isActive(IsActive.Active).collectAs(new BaseFieldSet().ensure(Description._id)).stream().map(DescriptionEntity::getId).collect(Collectors.toSet()); - for (UUID id : ids){ - if (!existingIds.contains(id)) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, Description.class.getSimpleName()}, LocaleContextHolder.getLocale())); + + } if (FieldType.INTERNAL_ENTRIES_DESCRIPTIONS.equals(fieldType)){ + if ( !this.conventionService.isListNullOrEmpty(persist.getTextListValue())) ids = persist.getTextListValue().stream().map(UUID::fromString).toList(); + else if (!this.conventionService.isNullOrEmpty(persist.getTextValue())) ids.add(UUID.fromString(persist.getTextValue())); + + if (ids.size() > 0) { + Set existingIds = this.queryFactory.query(DescriptionQuery.class).ids(ids).isActive(IsActive.Active).collectAs(new BaseFieldSet().ensure(Description._id)).stream().map(DescriptionEntity::getId).collect(Collectors.toSet()); + for (UUID id : ids){ + if (!existingIds.contains(id)) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, Description.class.getSimpleName()}, LocaleContextHolder.getLocale())); + } } } + if (!ids.isEmpty()){ + if (ids.size() > 1) data.setTextListValue(persist.getTextListValue()); + else data.setTextListValue(List.of(persist.getTextValue())); + }else{ + data.setTextListValue(persist.getTextListValue()); + } if (fieldType.equals(FieldType.SELECT) && this.conventionService.isListNullOrEmpty(persist.getTextListValue()) && !this.conventionService.isNullOrEmpty(persist.getTextValue())){ data.setTextListValue(List.of(persist.getTextValue())); - } else{ + } else if (fieldType.equals(FieldType.SELECT) || fieldType.equals(FieldType.TAGS)){ data.setTextListValue(persist.getTextListValue()); } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/StorageFileController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/StorageFileController.java index d9e1d0fd9..ad608cee2 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/StorageFileController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/StorageFileController.java @@ -1,23 +1,27 @@ package eu.eudat.controllers; import eu.eudat.audit.AuditableAction; +import eu.eudat.authorization.AuthorizationFlags; import eu.eudat.authorization.Permission; import eu.eudat.commons.enums.StorageType; import eu.eudat.commons.scope.user.UserScope; import eu.eudat.convention.ConventionService; import eu.eudat.data.StorageFileEntity; import eu.eudat.model.StorageFile; +import eu.eudat.model.builder.StorageFileBuilder; import eu.eudat.model.persist.StorageFilePersist; import eu.eudat.query.StorageFileQuery; import eu.eudat.service.storage.StorageFileProperties; import eu.eudat.service.storage.StorageFileService; import gr.cite.commons.web.authz.service.AuthorizationService; import gr.cite.tools.auditing.AuditService; +import gr.cite.tools.data.builder.BuilderFactory; import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.exception.MyApplicationException; import gr.cite.tools.exception.MyForbiddenException; import gr.cite.tools.exception.MyNotFoundException; import gr.cite.tools.fieldset.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; @@ -25,8 +29,8 @@ import org.apache.commons.io.FilenameUtils; import org.slf4j.LoggerFactory; import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; -import org.springframework.core.io.ByteArrayResource; import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; @@ -45,6 +49,7 @@ public class StorageFileController { private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(StorageFileController.class)); private final AuditService auditService; private final QueryFactory queryFactory; + private final BuilderFactory builderFactory; private final MessageSource messageSource; private final StorageFileService storageFileService; private final StorageFileProperties config; @@ -55,13 +60,14 @@ public class StorageFileController { public StorageFileController( AuditService auditService, QueryFactory queryFactory, - MessageSource messageSource, + BuilderFactory builderFactory, MessageSource messageSource, StorageFileService storageFileService, StorageFileProperties config, UserScope userScope, AuthorizationService authorizationService, ConventionService conventionService, ValidatorFactory validatorFactory) { this.auditService = auditService; this.queryFactory = queryFactory; + this.builderFactory = builderFactory; this.messageSource = messageSource; this.storageFileService = storageFileService; this.config = config; @@ -71,21 +77,23 @@ public class StorageFileController { this.validatorFactory = validatorFactory; } - @GetMapping("/name/{id}") - public String getName(@PathVariable("id") UUID id) throws MyApplicationException, MyForbiddenException, MyNotFoundException { - logger.debug(new MapLogEntry("get name" ).And("id", id)); + @GetMapping("{id}") + public StorageFile get(@PathVariable("id") UUID id, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException { + logger.debug(new MapLogEntry("retrieving " + StorageFile.class.getSimpleName()).And("id", id).And("fields", fieldSet)); this.authorizationService.authorizeForce(Permission.BrowseStorageFile); - StorageFileEntity storageFile = this.queryFactory.query(StorageFileQuery.class).ids(id).firstAs(new BaseFieldSet().ensure(StorageFile._fullName)); - if (storageFile == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, StorageFile.class.getSimpleName()}, LocaleContextHolder.getLocale())); + StorageFileQuery query = this.queryFactory.query(StorageFileQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).ids(id); + StorageFile model = this.builderFactory.builder(StorageFileBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(fieldSet, query.firstAs(fieldSet)); + if (model == null) + throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, StorageFile.class.getSimpleName()}, LocaleContextHolder.getLocale())); - this.auditService.track(AuditableAction.StorageFile_Download, Map.ofEntries( - new AbstractMap.SimpleEntry("id", id) + this.auditService.track(AuditableAction.StorageFile_Query, Map.ofEntries( + new AbstractMap.SimpleEntry("id", id), + new AbstractMap.SimpleEntry("fields", fieldSet) )); - - return storageFile.getName(); + return model; } @@ -115,8 +123,8 @@ public class StorageFileController { return addedFiles; } - @GetMapping("{id}") - public ResponseEntity get(@PathVariable("id") UUID id) throws MyApplicationException, MyForbiddenException, MyNotFoundException { + @GetMapping("download/{id}") + public ResponseEntity get(@PathVariable("id") UUID id) throws MyApplicationException, MyForbiddenException, MyNotFoundException { logger.debug(new MapLogEntry("download" ).And("id", id)); this.authorizationService.authorizeForce(Permission.BrowseStorageFile); @@ -134,10 +142,14 @@ public class StorageFileController { String contentType = storageFile.getMimeType(); if (this.conventionService.isNullOrEmpty(contentType)) contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE; - return ResponseEntity.ok() - .contentType(MediaType.valueOf(contentType)) - .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + storageFile.getName() + (storageFile.getExtension().startsWith(".") ? "" : ".") + storageFile.getExtension() + "\"") - .body(new ByteArrayResource(file)); + HttpHeaders responseHeaders = new HttpHeaders(); + responseHeaders.setContentLength(file.length); + responseHeaders.setContentType(MediaType.valueOf(contentType)); + responseHeaders.set("Content-Disposition", "attachment; filename=\"" + storageFile.getName() + (storageFile.getExtension().startsWith(".") ? "" : ".") + storageFile.getExtension() + "\""); + responseHeaders.set("Access-Control-Expose-Headers", "Content-Disposition"); + responseHeaders.get("Access-Control-Expose-Headers").add("Content-Type"); + + return new ResponseEntity<>(file, responseHeaders, HttpStatus.OK); } } diff --git a/dmp-frontend/src/app/core/services/storage-file/storage-file.service.ts b/dmp-frontend/src/app/core/services/storage-file/storage-file.service.ts index b228e0091..ae1f33a4e 100644 --- a/dmp-frontend/src/app/core/services/storage-file/storage-file.service.ts +++ b/dmp-frontend/src/app/core/services/storage-file/storage-file.service.ts @@ -21,20 +21,25 @@ export class StorageFileService { private get apiBase(): string { return `${this.configurationService.server}storage-file`; } - getName(id: Guid ): Observable { - const url = `${this.apiBase}/name/${id}`; + getSingle(id: Guid, reqFields: string[] = []): Observable { + const url = `${this.apiBase}/${id}`; + const options = { params: { f: reqFields } }; return this.http - .get(url).pipe( + .get(url, options).pipe( catchError((error: any) => throwError(error))); } download(id: Guid ): Observable> { - const url = `${this.apiBase}/${id}`; + const url = `${this.apiBase}/download/${id}`; + + const params = new BaseHttpParams(); + params.interceptorContext = { + excludedInterceptors: [InterceptorType.JSONContentType, InterceptorType.ResponsePayload] + }; return this.http - .get>(url).pipe( - catchError((error: any) => throwError(error))); + .get(url, {params: params, responeType: 'blob', observe: 'response'}); } uploadTempFiles(item: File): Observable { diff --git a/dmp-frontend/src/app/ui/admin/description-template/editor/components/field/description-template-editor-field.component.html b/dmp-frontend/src/app/ui/admin/description-template/editor/components/field/description-template-editor-field.component.html index 8fed87433..1701b1b4b 100644 --- a/dmp-frontend/src/app/ui/admin/description-template/editor/components/field/description-template-editor-field.component.html +++ b/dmp-frontend/src/app/ui/admin/description-template/editor/components/field/description-template-editor-field.component.html @@ -177,8 +177,8 @@ - - + + \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field/form-field.component.html b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field/form-field.component.html index e8fa69b76..a577c8820 100644 --- a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field/form-field.component.html +++ b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field/form-field.component.html @@ -47,13 +47,13 @@
- + {{propertiesFormGroup?.get(field.id).get('textListValue').getError('backendError').message}} {{'GENERAL.VALIDATION.REQUIRED' | translate}} - + {{propertiesFormGroup?.get(field.id).get('textValue').getError('backendError').message}} {{'GENERAL.VALIDATION.REQUIRED' | translate}} @@ -62,17 +62,17 @@
-
+
- + {{propertiesFormGroup?.get(field.id).get('textListValue').getError('backendError').message}} {{'GENERAL.VALIDATION.REQUIRED' | translate}} - + {{propertiesFormGroup?.get(field.id).get('textValue').getError('backendError').message}} {{'GENERAL.VALIDATION.REQUIRED' | translate}} @@ -107,9 +107,9 @@
- - - {{ fileNameDisplay}} + + + {{ fileNameDisplay }}
@@ -157,7 +157,7 @@
- + {{'GENERAL.VALIDATION.REQUIRED' | translate}}
diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field/form-field.component.ts b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field/form-field.component.ts index 46991c269..db8bb346d 100644 --- a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field/form-field.component.ts +++ b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field/form-field.component.ts @@ -6,10 +6,13 @@ import { MatDialog } from "@angular/material/dialog"; import { DescriptionTemplateFieldType } from '@app/core/common/enum/description-template-field-type'; import { DescriptionTemplateFieldValidationType } from '@app/core/common/enum/description-template-field-validation-type'; import { DescriptionTemplateField, DescriptionTemplateFieldSet, DescriptionTemplateLabelAndMultiplicityData, DescriptionTemplateUploadData } from '@app/core/model/description-template/description-template'; +import { StorageFile } from '@app/core/model/storage-file/storage-file'; +import { DescriptionService } from '@app/core/services/description/description.service'; import { DmpService } from '@app/core/services/dmp/dmp.service'; import { SnackBarNotificationLevel, UiNotificationService } from "@app/core/services/notification/ui-notification-service"; import { ReferenceService } from '@app/core/services/reference/reference.service'; import { StorageFileService } from '@app/core/services/storage-file/storage-file.service'; +import { TagService } from '@app/core/services/tag/tag.service'; import { FileUtils } from '@app/core/services/utilities/file-utils.service'; import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration'; import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration'; @@ -21,6 +24,7 @@ import { TranslateService } from '@ngx-translate/core'; import * as FileSaver from 'file-saver'; import { Observable } from 'rxjs'; import { distinctUntilChanged, map, takeUntil } from 'rxjs/operators'; +import { nameof } from 'ts-simple-nameof'; @Component({ selector: 'app-description-form-field', @@ -70,11 +74,13 @@ export class DescriptionFormFieldComponent extends BaseComponent implements OnIn ]; filesToUpload: FileList; - fileNameDisplay: string; + fileNameDisplay: string = null; constructor( private language: TranslateService, - private dmpService: DmpService, + public dmpService: DmpService, + public descriptionService: DescriptionService, + public tagService: TagService, private cdr: ChangeDetectorRef, private uiNotificationService: UiNotificationService, public dialog: MatDialog, @@ -92,8 +98,24 @@ export class DescriptionFormFieldComponent extends BaseComponent implements OnIn ngOnInit() { - if(this.field?.data?.fieldType == DescriptionTemplateFieldType.UPLOAD && this.field && this.field.id && (this.propertiesFormGroup?.get(this.field.id).get('textValue').value != undefined)) this.getUploadFileName(); + if(this.field?.data?.fieldType == DescriptionTemplateFieldType.UPLOAD && this.field && this.field.id && (this.propertiesFormGroup?.get(this.field.id).get('textValue').value != undefined) && !this.fileNameDisplay) { + const id = Guid.parse((this.propertiesFormGroup?.get(this.field.id).get('textValue').value as string)); + const fields = [ + nameof(x => x.id), + nameof(x => x.name), + ] + + this.storageFileService.getSingle(id, fields).pipe(takeUntil(this._destroyed)).subscribe(storageFile => { + this.fileNameDisplay = storageFile.name; + this.applyFieldType(); + }); + } else { + this.applyFieldType(); + } + } + + private applyFieldType(){ this.isRequired = this.field.validations?.includes(DescriptionTemplateFieldValidationType.Required); switch (this.field?.data?.fieldType) { @@ -140,12 +162,6 @@ export class DescriptionFormFieldComponent extends BaseComponent implements OnIn // this.form.disable(); // } break; - case DescriptionTemplateFieldType.INTERNAL_ENTRIES_DESCRIPTIONS: - this.makeAutocompleteConfiguration(this.searchDatasets.bind(this), "label"); - break; - case DescriptionTemplateFieldType.INTERNAL_ENTRIES_DMPS: - this.makeAutocompleteConfiguration(this.searchDmps.bind(this), "label"); - break; } // this.form = this.visibilityRulesService.getFormGroup(this.field.id); @@ -161,28 +177,6 @@ export class DescriptionFormFieldComponent extends BaseComponent implements OnIn }); } - searchDatasets(query: string) { - //TODO refactor - return null; - // let fields: Array = new Array(); - // const datasetsAutocompleteRequestItem: DataTableRequest = new DataTableRequest(0, 25, { fields: fields }); - // datasetsAutocompleteRequestItem.criteria = new DatasetCriteria(); - // datasetsAutocompleteRequestItem.criteria.like = query; - // //TODO: refactor this - // // return this.datasetService.getPaged(datasetsAutocompleteRequestItem).pipe(map(item => item.data)); - // return null; - } - - searchDmps(query: string) { - //TODO refactor - return null; - // let fields: Array = new Array(); - // const dmpsAutocompleteRequestItem: DataTableRequest = new DataTableRequest(0, 25, { fields: fields }); - // dmpsAutocompleteRequestItem.criteria = new DmpCriteria(); - // dmpsAutocompleteRequestItem.criteria.like = query; - // return this.dmpService.getPaged(dmpsAutocompleteRequestItem).pipe(map(item => item.data)); - } - makeAutocompleteConfiguration(myfunc: Function, title: string, subtitle?: string): void { if (!((this.field.data as DescriptionTemplateLabelAndMultiplicityData).multipleSelect)) { this.singleAutoCompleteConfiguration = { @@ -275,16 +269,6 @@ export class DescriptionFormFieldComponent extends BaseComponent implements OnIn } - private getUploadFileName(){ - const id = Guid.parse((this.propertiesFormGroup?.get(this.field.id).get('textValue').value as string)); - - this.storageFileService.getName(id) - .pipe(takeUntil(this._destroyed)).subscribe((name) => { - this.fileNameDisplay = name; - }, error => { - this.fileNameDisplay = null; - }) - } public upload() { this.storageFileService.uploadTempFiles(this.filesToUpload[0]) @@ -364,13 +348,12 @@ export class DescriptionFormFieldComponent extends BaseComponent implements OnIn if (this.propertiesFormGroup?.get(this.field.id).get('textValue').value) { const id = Guid.parse((this.propertiesFormGroup?.get(this.field.id).get('textValue').value as string)); - this.storageFileService.download(id).subscribe((response) => { - const blob = new Blob([response.body]); - const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); - FileSaver.saveAs(blob, filename); - }, error => { - this.onCallbackUploadFail(error.error); - }) + this.storageFileService.download(id).pipe(takeUntil(this._destroyed)) + .subscribe(response => { + const blob = new Blob([response.body]); + const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + FileSaver.saveAs(blob, filename); + }); } }