Skip to content

Commit

Permalink
Merge branch 'dev' into #343_suggest_change_and_log
Browse files Browse the repository at this point in the history
  • Loading branch information
marcos-lg committed May 21, 2021
2 parents 9041605 + 435bc66 commit e4db80a
Show file tree
Hide file tree
Showing 8 changed files with 272 additions and 0 deletions.
8 changes: 8 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
<woodstox.version>4.4.1</woodstox.version>
<zookeeper.version>3.4.14</zookeeper.version>
<owasp-java-html-sanitizer.version>20200713.1</owasp-java-html-sanitizer.version>
<super-csv.version>2.4.0</super-csv.version>

<!-- Test -->
<junit.version>5.6.3</junit.version>
Expand Down Expand Up @@ -589,6 +590,13 @@
<version>${elasticsearch.version}</version>
</dependency>

<!-- CSV exports -->
<dependency>
<groupId>net.sf.supercsv</groupId>
<artifactId>super-csv</artifactId>
<version>${super-csv.version}</version>
</dependency>

<!-- Caching -->
<dependency>
<groupId>org.cache2k</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@
import java.net.URI;
import java.util.UUID;

import org.apache.ibatis.type.LocalDateTimeTypeHandler;
import org.apache.ibatis.type.LocalDateTypeHandler;
import org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand Down Expand Up @@ -229,6 +231,7 @@ ConfigurationCustomizer mybatisConfigCustomizer() {
configuration
.getTypeAliasRegistry()
.registerAlias("IDigBioCollectionDto", IDigBioCollectionDto.class);

};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.gbif.api.model.common.paging.Pageable;
import org.gbif.api.model.common.search.Facet;
import org.gbif.api.model.occurrence.Download;
import org.gbif.api.model.occurrence.DownloadStatistics;

import java.util.Date;
import java.util.List;
Expand Down Expand Up @@ -81,4 +82,19 @@ List<Facet.Count> getDownloadsByDataset(
@Nullable @Param("publishingCountry") String publishingCountry,
@Nullable @Param("datasetKey") UUID datasetKey,
@Nullable @Param("publishingOrgKey") UUID publishingOrgKey);

List<DownloadStatistics> getDownloadStatistics(
@Nullable @Param("fromDate") Date fromDate,
@Nullable @Param("toDate") Date toDate,
@Nullable @Param("publishingCountry") String publishingCountry,
@Nullable @Param("datasetKey") UUID datasetKey,
@Nullable @Param("publishingOrgKey") UUID publishingOrgKey,
@Nullable @Param("page") Pageable page);

long countDownloadStatistics(
@Nullable @Param("fromDate") Date fromDate,
@Nullable @Param("toDate") Date toDate,
@Nullable @Param("publishingCountry") String publishingCountry,
@Nullable @Param("datasetKey") UUID datasetKey,
@Nullable @Param("publishingOrgKey") UUID publishingOrgKey);
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@
<result property="count" column="total_records" />
</resultMap>

<resultMap id="DOWNLOAD_STATISTICS" type="org.gbif.api.model.occurrence.DownloadStatistics" autoMapping="true"/>

<sql id="OCCURRENCE_DOWNLOAD_FIELDS">
key,doi,license,filter,status,download_link,size,total_records,notification_addresses,created_by,send_notification,format,created,modified,erase_after
</sql>
Expand Down Expand Up @@ -259,4 +261,37 @@
GROUP BY year_month
ORDER BY year_month DESC;
</select>

<select id="getDownloadStatistics" resultMap="DOWNLOAD_STATISTICS" parameterType="map">
SELECT year_month, dataset_key, SUM(number_downloads) AS number_downloads, SUM(total_records) AS total_records
FROM download_statistics
<if test="publishingOrgKey != null">
JOIN dataset d ON d.key = dataset_key AND d.publishing_organization_key = #{publishingOrgKey,jdbcType=OTHER}
</if>
<where>
<if test="publishingCountry != null">AND publishing_organization_country = #{publishingCountry,jdbcType=OTHER}</if>
<if test="datasetKey != null">AND dataset_key = #{datasetKey,jdbcType=OTHER}</if>
<if test="fromDate != null"><![CDATA[AND year_month >= #{fromDate,jdbcType=TIMESTAMP}]]></if>
<if test="toDate != null"><![CDATA[AND year_month < #{toDate,jdbcType=TIMESTAMP}]]></if>
</where>
GROUP BY dataset_key, year_month
ORDER BY year_month DESC
<if test="page != null" >
LIMIT #{page.limit} OFFSET #{page.offset}
</if>
</select>

<select id="countDownloadStatistics" resultType="Long" parameterType="map">
SELECT COUNT(*)
FROM download_statistics
<if test="publishingOrgKey != null">
JOIN dataset d ON d.key = dataset_key AND d.publishing_organization_key = #{publishingOrgKey,jdbcType=OTHER}
</if>
<where>
<if test="publishingCountry != null">AND publishing_organization_country = #{publishingCountry,jdbcType=OTHER}</if>
<if test="datasetKey != null">AND dataset_key = #{datasetKey,jdbcType=OTHER}</if>
<if test="fromDate != null"><![CDATA[AND year_month >= #{fromDate,jdbcType=TIMESTAMP}]]></if>
<if test="toDate != null"><![CDATA[AND year_month < #{toDate,jdbcType=TIMESTAMP}]]></if>
</where>
</select>
</mapper>
12 changes: 12 additions & 0 deletions registry-ws/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
</properties>

<dependencies>
<!-- Tools -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>

<!-- Spring dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
Expand Down Expand Up @@ -76,6 +82,12 @@
<artifactId>springdoc-openapi-ui</artifactId>
</dependency>

<!-- CSV exports -->
<dependency>
<groupId>net.sf.supercsv</groupId>
<artifactId>super-csv</artifactId>
</dependency>

<!-- GBIF dependencies -->
<dependency>
<groupId>org.gbif.registry</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package org.gbif.registry.ws.export;

import org.gbif.api.model.common.export.ExportFormat;
import org.gbif.api.model.common.paging.Pageable;
import org.gbif.api.model.occurrence.DownloadStatistics;
import org.gbif.api.service.registry.OccurrenceDownloadService;
import org.gbif.api.vocabulary.Country;

import java.io.Writer;
import java.util.Date;
import java.util.UUID;


import lombok.Builder;
import lombok.Data;
import lombok.SneakyThrows;
import org.supercsv.cellprocessor.Optional;
import org.supercsv.cellprocessor.ParseInt;
import org.supercsv.cellprocessor.ift.CellProcessor;
import org.supercsv.io.CsvBeanWriter;
import org.supercsv.io.ICsvBeanWriter;
import org.supercsv.prefs.CsvPreference;
import org.supercsv.util.CsvContext;

@Data
@Builder
public class CsvWriter<T> {

private final String[] header;

private final String[] fields;

private final CellProcessor[] processors;

private final Iterable<T> pager;

private final ExportFormat preference;


private CsvPreference csvPreference() {
if (ExportFormat.CSV == preference) {
return CsvPreference.STANDARD_PREFERENCE;
} else if (ExportFormat.TSV == preference) {
return CsvPreference.TAB_PREFERENCE;
}
throw new IllegalArgumentException("Export format not supported " + preference);
}

@SneakyThrows
public void export(Writer writer) {
try (ICsvBeanWriter beanWriter = new CsvBeanWriter(writer, csvPreference())) {
beanWriter.writeHeader(header);
for (T o : pager) {
beanWriter.write(o, fields, processors);
}
writer.flush();
}
}

/**
* Creates and CsvWriter/exporter DownloadStatistics.
*/
public static CsvWriter<DownloadStatistics> downloadStatisticsTsvWriter(Iterable<DownloadStatistics> pager,
ExportFormat preference) {

return CsvWriter.<DownloadStatistics>builder()
.fields(new String[]{"datasetKey", "totalRecords", "numberDownloads", "year", "month"})
.header(new String[]{"dataset_key", "total_records", "number_downloads", "year", "month"})
.processors(new CellProcessor[]{new UUIDProcessor(),
new Optional(new ParseInt()),
new Optional(new ParseInt()),
new Optional(new ParseInt()),
new Optional(new ParseInt())})
.preference(preference)
.pager(pager)
.build();
}

/**
* Null aware UUID processor.
*/
private static class UUIDProcessor implements CellProcessor {
@Override
public String execute(Object value, CsvContext csvContext) {
return value != null ? ((UUID) value).toString() : "";
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,29 @@
import org.gbif.api.annotation.Trim;
import org.gbif.api.model.common.DOI;
import org.gbif.api.model.common.GbifUser;
import org.gbif.api.model.common.export.ExportFormat;
import org.gbif.api.model.common.paging.Pageable;
import org.gbif.api.model.common.paging.PagingResponse;
import org.gbif.api.model.common.search.Facet;
import org.gbif.api.model.occurrence.Download;
import org.gbif.api.model.occurrence.DownloadStatistics;
import org.gbif.api.model.registry.DatasetOccurrenceDownloadUsage;
import org.gbif.api.model.registry.PostPersist;
import org.gbif.api.model.registry.PrePersist;
import org.gbif.api.service.common.IdentityAccessService;
import org.gbif.api.service.registry.OccurrenceDownloadService;
import org.gbif.api.util.iterables.Iterables;
import org.gbif.api.vocabulary.Country;
import org.gbif.api.vocabulary.License;
import org.gbif.registry.doi.DoiIssuingService;
import org.gbif.registry.doi.DownloadDoiDataCiteHandlingService;
import org.gbif.registry.persistence.mapper.DatasetOccurrenceDownloadMapper;
import org.gbif.registry.persistence.mapper.OccurrenceDownloadMapper;
import org.gbif.registry.ws.export.CsvWriter;
import org.gbif.registry.ws.provider.PartialDate;
import org.gbif.ws.WebApplicationException;

import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;
Expand All @@ -47,6 +52,7 @@
import java.util.UUID;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import javax.validation.groups.Default;

Expand All @@ -56,8 +62,13 @@
import org.slf4j.MarkerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
Expand Down Expand Up @@ -343,6 +354,57 @@ public Map<Integer, Map<Integer, Long>> getDownloadsByDataset(
publishingOrgKey));
}

@GetMapping("statistics")
@Override
public PagingResponse<DownloadStatistics> getDownloadStatistics(
@PartialDate Date fromDate,
@PartialDate Date toDate,
Country publishingCountry,
@RequestParam(value = "datasetKey", required = false) UUID datasetKey,
@RequestParam(value = "publishingOrgKey", required = false) UUID publishingOrgKey,
Pageable page
) {
String country = Optional.ofNullable(publishingCountry).map(Country::getIso2LetterCode).orElse(null);
return new PagingResponse<>(page,
occurrenceDownloadMapper.countDownloadStatistics(fromDate,
toDate,
country,
datasetKey,
publishingOrgKey),
occurrenceDownloadMapper.getDownloadStatistics(fromDate,
toDate,
country,
datasetKey,
publishingOrgKey,
page));
}

@GetMapping("statistics/export")
public void getDownloadStatistics(
HttpServletResponse response,
@RequestParam(value = "format", defaultValue = "TSV") ExportFormat format,
@PartialDate Date fromDate,
@PartialDate Date toDate,
Country publishingCountry,
@RequestParam(value = "datasetKey", required = false) UUID datasetKey,
@RequestParam(value = "publishingOrgKey", required = false) UUID publishingOrgKey) throws
IOException {

String headerValue = String.format("attachment; filename=\"download_statistics.%s\"",
format.name().toLowerCase());
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, headerValue);


CsvWriter.downloadStatisticsTsvWriter(Iterables.downloadStatistics(this,
fromDate,
toDate,
publishingCountry,
datasetKey,
publishingOrgKey),
format)
.export(response.getWriter());
}

/** Aggregates the download statistics in tree structure of month grouped by year. */
private Map<Integer, Map<Integer, Long>> groupByYear(List<Facet.Count> counts) {
Map<Integer, Map<Integer, Long>> yearsGrouping = new TreeMap<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package org.gbif.registry.ws.export;

import org.gbif.api.model.common.export.ExportFormat;
import org.gbif.api.model.occurrence.DownloadStatistics;

import java.io.StringWriter;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class CsvWriterTest {

@Test
public void downloadStatisticsTest() {

List<DownloadStatistics> stats = Arrays.asList(
new DownloadStatistics(UUID.randomUUID(), 10, 10, LocalDate.of(2020,1,1)),
new DownloadStatistics(UUID.randomUUID(), 10, 10, LocalDate.of(2021, 2,1)));

StringWriter writer = new StringWriter();

CsvWriter.downloadStatisticsTsvWriter(stats, ExportFormat.TSV)
.export(writer);

String export = writer.toString();
String[] lines = export.split("\\n");

//Number of lines is header + list.size
assertEquals(stats.size() + 1, lines.length);

//Each line has 4 tabs
assertEquals((stats.size() + 1) * 4, export.chars().filter(ch -> ch == '\t').count());

//Year test
assertEquals("2020", lines[1].split("\\t")[3]);
assertEquals("2021", lines[2].split("\\t")[3]);

//Month test
assertEquals("1", lines[1].split("\\t")[4]);
assertEquals("2", lines[2].split("\\t")[4]);
}
}

0 comments on commit e4db80a

Please sign in to comment.