From bf08f06627610cbfa2b2f70a8c9c091067b9d024 Mon Sep 17 00:00:00 2001 From: Martin Lowe Date: Wed, 21 Sep 2022 15:42:41 -0400 Subject: [PATCH 1/4] Update report to use stored procedure, add calls to proto-supported func --- application/pom.xml | 4 - pom.xml | 6 +- .../eclipsedb/dto/EventLogSessions.java | 151 ++++++++++++++++++ .../namespaces/EclipseDBParameterNames.java | 5 +- .../reports/MemberAdoptionReportItem.java | 44 +++++ .../portal/resources/ReportsResource.java | 83 ++++++++++ 6 files changed, 287 insertions(+), 6 deletions(-) create mode 100644 portal/src/main/java/org/eclipsefoundation/eclipsedb/dto/EventLogSessions.java create mode 100644 portal/src/main/java/org/eclipsefoundation/membership/portal/model/reports/MemberAdoptionReportItem.java create mode 100644 portal/src/main/java/org/eclipsefoundation/membership/portal/resources/ReportsResource.java diff --git a/application/pom.xml b/application/pom.xml index 81e0b9ed..3eed9228 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -12,10 +12,6 @@ 1.0.9 - - com.fasterxml.jackson.dataformat - jackson-dataformat-csv - com.openhtmltopdf diff --git a/pom.xml b/pom.xml index 5240e0bf..020d3c7f 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 1.4.10-SNAPSHOT pom - 0.6.6 + 0.6.7-SNAPSHOT 2.22.1 3.8.1 11 @@ -84,6 +84,10 @@ io.quarkus quarkus-resteasy-jackson + + com.fasterxml.jackson.dataformat + jackson-dataformat-csv + com.fasterxml.jackson.datatype diff --git a/portal/src/main/java/org/eclipsefoundation/eclipsedb/dto/EventLogSessions.java b/portal/src/main/java/org/eclipsefoundation/eclipsedb/dto/EventLogSessions.java new file mode 100644 index 00000000..2f41124c --- /dev/null +++ b/portal/src/main/java/org/eclipsefoundation/eclipsedb/dto/EventLogSessions.java @@ -0,0 +1,151 @@ +package org.eclipsefoundation.eclipsedb.dto; + +import java.sql.Date; +import java.time.LocalDateTime; +import java.util.Calendar; + +import javax.inject.Inject; +import javax.inject.Singleton; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.ws.rs.core.MultivaluedMap; + +import org.eclipsefoundation.eclipsedb.namespaces.EclipseDBParameterNames; +import org.eclipsefoundation.persistence.dto.BareNode; +import org.eclipsefoundation.persistence.dto.filter.DtoFilter; +import org.eclipsefoundation.persistence.model.DtoTable; +import org.eclipsefoundation.persistence.model.ParameterizedCallStatement; +import org.eclipsefoundation.persistence.model.ParameterizedSQLStatement; +import org.eclipsefoundation.persistence.model.ParameterizedSQLStatementBuilder; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +@Entity +public class EventLogSessions extends BareNode { + public static final DtoTable TABLE = new DtoTable(EventLogSessions.class, "els"); + + @Id + @Column(name = "pk1") + private int organizationId; + private int uniqueHits; + private int totalHits; + private LocalDateTime earliestHit; + private LocalDateTime latestHit; + + @JsonIgnore + @Override + public Object getId() { + return getOrganizationId(); + } + + /** + * @return the organizationId + */ + public int getOrganizationId() { + return organizationId; + } + + /** + * @param organizationId the organizationId to set + */ + public void setOrganizationId(int organizationId) { + this.organizationId = organizationId; + } + + /** + * @return the uniqueHits + */ + public int getUniqueHits() { + return uniqueHits; + } + + /** + * @param uniqueHits the uniqueHits to set + */ + public void setUniqueHits(int uniqueHits) { + this.uniqueHits = uniqueHits; + } + + /** + * @return the totalHits + */ + public int getTotalHits() { + return totalHits; + } + + /** + * @param totalHits the totalHits to set + */ + public void setTotalHits(int totalHits) { + this.totalHits = totalHits; + } + + /** + * @return the earliestHit + */ + public LocalDateTime getEarliestHit() { + return earliestHit; + } + + /** + * @param earliestHit the earliestHit to set + */ + public void setEarliestHit(LocalDateTime earliestHit) { + this.earliestHit = earliestHit; + } + + /** + * @return the latestHit + */ + public LocalDateTime getLatestHit() { + return latestHit; + } + + /** + * @param latestHit the latestHit to set + */ + public void setLatestHit(LocalDateTime latestHit) { + this.latestHit = latestHit; + } + + @Singleton + public static class SysEventLogFilter implements DtoFilter { + @Inject + ParameterizedSQLStatementBuilder builder; + + @Override + public ParameterizedSQLStatement getFilters(MultivaluedMap params, boolean isRoot) { + ParameterizedCallStatement stmt = builder.buildSpecial(TABLE); + stmt.setCallStatement("sp_evtlog_sessions"); + + // since check + String since = params.getFirst(EclipseDBParameterNames.SINCE.getName()); + if (since != null) { + stmt.addClause(new ParameterizedSQLStatement.Clause("", new Object[] { since })); + } else { + Calendar c = Calendar.getInstance(); + c.set(1, 2020); + stmt + .addClause(new ParameterizedSQLStatement.Clause("", + new Object[] { new Date(c.toInstant().getNano()) })); + } + + // servername check + String serverName = params.getFirst(EclipseDBParameterNames.SERVER_NAME.getName()); + if (serverName != null) { + stmt.addClause(new ParameterizedSQLStatement.Clause("", new Object[] { serverName })); + } else { + stmt.addClause(new ParameterizedSQLStatement.Clause("", new Object[] { "" })); + } + + return stmt; + } + + @Override + public Class getType() { + return EventLogSessions.class; + } + } + +} diff --git a/portal/src/main/java/org/eclipsefoundation/eclipsedb/namespaces/EclipseDBParameterNames.java b/portal/src/main/java/org/eclipsefoundation/eclipsedb/namespaces/EclipseDBParameterNames.java index 0a5b6047..5a7adebb 100644 --- a/portal/src/main/java/org/eclipsefoundation/eclipsedb/namespaces/EclipseDBParameterNames.java +++ b/portal/src/main/java/org/eclipsefoundation/eclipsedb/namespaces/EclipseDBParameterNames.java @@ -15,9 +15,12 @@ public class EclipseDBParameterNames implements UrlParameterNamespace { public static final UrlParameter PRODUCT_ID = new UrlParameter("product_id"); public static final UrlParameter ORGANIZATION_ID = new UrlParameter("organization_id"); public static final UrlParameter USERNAME = new UrlParameter("username"); + public static final UrlParameter SERVER_NAME = new UrlParameter("server_name"); + public static final UrlParameter SINCE = new UrlParameter("since"); + public static final UrlParameter LOG_TABLE = new UrlParameter("log_table"); private static final List params = Collections - .unmodifiableList(Arrays.asList(PRODUCT_ID, ORGANIZATION_ID, USERNAME)); + .unmodifiableList(Arrays.asList(PRODUCT_ID, ORGANIZATION_ID, USERNAME, SERVER_NAME, SINCE, LOG_TABLE)); @Override public List getParameters() { diff --git a/portal/src/main/java/org/eclipsefoundation/membership/portal/model/reports/MemberAdoptionReportItem.java b/portal/src/main/java/org/eclipsefoundation/membership/portal/model/reports/MemberAdoptionReportItem.java new file mode 100644 index 00000000..92bff23c --- /dev/null +++ b/portal/src/main/java/org/eclipsefoundation/membership/portal/model/reports/MemberAdoptionReportItem.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2022 Eclipse Foundation + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Author: Martin Lowe + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipsefoundation.membership.portal.model.reports; + +import java.time.LocalDateTime; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import com.google.auto.value.AutoValue; + +@AutoValue +@JsonDeserialize(builder = AutoValue_MemberAdoptionReportItem.Builder.class) +public abstract class MemberAdoptionReportItem { + + public abstract int getOrganizationId(); + public abstract String getOrganizationName(); + public abstract LocalDateTime getFirstHit(); + public abstract int getTotalHits(); + public abstract int getUniqueHits(); + + public static Builder builder() { + return new AutoValue_MemberAdoptionReportItem.Builder(); + } + + @AutoValue.Builder + @JsonPOJOBuilder(withPrefix = "set") + public abstract static class Builder { + public abstract Builder setOrganizationId(int orgId); + public abstract Builder setOrganizationName(String orgName); + public abstract Builder setFirstHit(LocalDateTime firstHit); + public abstract Builder setTotalHits(int totalHits); + public abstract Builder setUniqueHits(int uniqueHits); + public abstract MemberAdoptionReportItem build(); + } +} diff --git a/portal/src/main/java/org/eclipsefoundation/membership/portal/resources/ReportsResource.java b/portal/src/main/java/org/eclipsefoundation/membership/portal/resources/ReportsResource.java new file mode 100644 index 00000000..81226773 --- /dev/null +++ b/portal/src/main/java/org/eclipsefoundation/membership/portal/resources/ReportsResource.java @@ -0,0 +1,83 @@ +package org.eclipsefoundation.membership.portal.resources; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.List; +import java.util.stream.Collectors; + +import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.eclipsefoundation.eclipsedb.dto.EventLogSessions; +import org.eclipsefoundation.eclipsedb.dto.SysEventLog; +import org.eclipsefoundation.eclipsedb.namespaces.EclipseDBParameterNames; +import org.eclipsefoundation.membership.portal.model.reports.MemberAdoptionReportItem; +import org.eclipsefoundation.persistence.dao.impl.DefaultHibernateDao; +import org.eclipsefoundation.persistence.model.RDBMSQuery; +import org.eclipsefoundation.persistence.service.MapperService; +import org.jboss.resteasy.specimpl.MultivaluedMapImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.SequenceWriter; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.dataformat.csv.CsvMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; + +@Path("reports") +//@Authenticated +public class ReportsResource extends AbstractRESTResource { + public static final Logger LOGGER = LoggerFactory.getLogger(ReportsResource.class); + + @ConfigProperty(name = "eclipse.security.log.table", defaultValue = "sessions") + String loggingTable; + + @Inject + DefaultHibernateDao dao; + + final CsvMapper CSV_MAPPER = (CsvMapper) new CsvMapper() + .registerModule(new JavaTimeModule()) + .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + + @GET + @Path("adoption_rate") + @Produces(MediaType.TEXT_PLAIN) + public Response ok() throws IOException { + MultivaluedMap params = new MultivaluedMapImpl<>(); + params.add(EclipseDBParameterNames.SERVER_NAME.getName(), request.getServerName()); + RDBMSQuery q = new RDBMSQuery<>(wrap, filters.get(EventLogSessions.class), params); + + try (StringWriter sw = new StringWriter()) { + // create the CSV writer for membership forms + SequenceWriter writer = CSV_MAPPER + .writer(CSV_MAPPER.schemaFor(MemberAdoptionReportItem.class).withHeader()) + .writeValues(sw); + // retrieve the membership form for the current state and write to output + writer.writeAll(adapt(dao.get(q))); + return Response.ok(sw.toString()).build(); + } + } + + private List adapt(List origin) { + return origin + .stream() + .map(o -> MemberAdoptionReportItem + .builder() + .setOrganizationId(o.getOrganizationId()) + .setFirstHit(o.getEarliestHit()) + .setTotalHits(o.getTotalHits()) + .setUniqueHits(o.getUniqueHits()) + .setOrganizationName( + orgService.getByID(Integer.toString(o.getOrganizationId())).get().getName()) + .build()) + .collect(Collectors.toList()); + } + +} -- GitLab From 72273df14fa95dfc2605735f616da538292bfab7 Mon Sep 17 00:00:00 2001 From: Martin Lowe Date: Fri, 21 Oct 2022 14:08:19 -0400 Subject: [PATCH 2/4] Add authentication barrier to reports endpoint, update report defaults --- .../eclipsedb/dto/EventLogSessions.java | 3 ++- .../portal/resources/AbstractRESTResource.java | 2 -- .../portal/resources/ReportsResource.java | 18 +++++++++++------- .../src/main/resources/application.properties | 1 + 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/portal/src/main/java/org/eclipsefoundation/eclipsedb/dto/EventLogSessions.java b/portal/src/main/java/org/eclipsefoundation/eclipsedb/dto/EventLogSessions.java index 2f41124c..6e8297ce 100644 --- a/portal/src/main/java/org/eclipsefoundation/eclipsedb/dto/EventLogSessions.java +++ b/portal/src/main/java/org/eclipsefoundation/eclipsedb/dto/EventLogSessions.java @@ -124,8 +124,9 @@ public class EventLogSessions extends BareNode { if (since != null) { stmt.addClause(new ParameterizedSQLStatement.Clause("", new Object[] { since })); } else { + // default to 1 year in the past Calendar c = Calendar.getInstance(); - c.set(1, 2020); + c.set(Calendar.YEAR, c.get(Calendar.YEAR) - 1); stmt .addClause(new ParameterizedSQLStatement.Clause("", new Object[] { new Date(c.toInstant().getNano()) })); diff --git a/portal/src/main/java/org/eclipsefoundation/membership/portal/resources/AbstractRESTResource.java b/portal/src/main/java/org/eclipsefoundation/membership/portal/resources/AbstractRESTResource.java index a2c8cca9..f193bd1b 100644 --- a/portal/src/main/java/org/eclipsefoundation/membership/portal/resources/AbstractRESTResource.java +++ b/portal/src/main/java/org/eclipsefoundation/membership/portal/resources/AbstractRESTResource.java @@ -65,8 +65,6 @@ public abstract class AbstractRESTResource { @Inject RequestWrapper wrap; - @Inject - ResponseHelper responseBuider; @Inject CSRFHelper csrfHelper; diff --git a/portal/src/main/java/org/eclipsefoundation/membership/portal/resources/ReportsResource.java b/portal/src/main/java/org/eclipsefoundation/membership/portal/resources/ReportsResource.java index 81226773..328be20f 100644 --- a/portal/src/main/java/org/eclipsefoundation/membership/portal/resources/ReportsResource.java +++ b/portal/src/main/java/org/eclipsefoundation/membership/portal/resources/ReportsResource.java @@ -13,15 +13,12 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; -import org.apache.commons.lang3.StringUtils; import org.eclipse.microprofile.config.inject.ConfigProperty; import org.eclipsefoundation.eclipsedb.dto.EventLogSessions; -import org.eclipsefoundation.eclipsedb.dto.SysEventLog; import org.eclipsefoundation.eclipsedb.namespaces.EclipseDBParameterNames; import org.eclipsefoundation.membership.portal.model.reports.MemberAdoptionReportItem; import org.eclipsefoundation.persistence.dao.impl.DefaultHibernateDao; import org.eclipsefoundation.persistence.model.RDBMSQuery; -import org.eclipsefoundation.persistence.service.MapperService; import org.jboss.resteasy.specimpl.MultivaluedMapImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,18 +28,20 @@ import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.dataformat.csv.CsvMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import io.quarkus.security.Authenticated; + @Path("reports") -//@Authenticated +@Authenticated public class ReportsResource extends AbstractRESTResource { public static final Logger LOGGER = LoggerFactory.getLogger(ReportsResource.class); - @ConfigProperty(name = "eclipse.security.log.table", defaultValue = "sessions") - String loggingTable; + @ConfigProperty(name = "eclipse.security.reports.allowed-users") + List allowedUsers; @Inject DefaultHibernateDao dao; - final CsvMapper CSV_MAPPER = (CsvMapper) new CsvMapper() + private static final CsvMapper CSV_MAPPER = (CsvMapper) new CsvMapper() .registerModule(new JavaTimeModule()) .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); @@ -50,6 +49,11 @@ public class ReportsResource extends AbstractRESTResource { @Path("adoption_rate") @Produces(MediaType.TEXT_PLAIN) public Response ok() throws IOException { + // check that the user is in the allowed user list + if (!allowedUsers.contains(ident.getPrincipal().getName())) { + return Response.status(403).build(); + } + // set filters for db query, matching on events for current host MultivaluedMap params = new MultivaluedMapImpl<>(); params.add(EclipseDBParameterNames.SERVER_NAME.getName(), request.getServerName()); RDBMSQuery q = new RDBMSQuery<>(wrap, filters.get(EventLogSessions.class), params); diff --git a/portal/src/main/resources/application.properties b/portal/src/main/resources/application.properties index 379f529b..bc235c6c 100644 --- a/portal/src/main/resources/application.properties +++ b/portal/src/main/resources/application.properties @@ -75,6 +75,7 @@ quarkus.resteasy.path=/api eclipse.image-store.file-path=/app/organization/imagestore eclipse.image-store.web-root=${eclipse.app.base-url}/images/organization/ eclipse.api.application-group=eclipse +eclipse.security.reports.allowed-users=zfazli,webdev security.csrf.enabled=true security.csrf.enabled.distributed-mode=true eclipse.image-store.default-image-url=https://www.eclipse.org/eclipse.org-common/themes/solstice/public/images/logo/eclipse-foundation-white-orange.svg -- GitLab From 93c392e948aa5abf7cf6d84d0f4eb6c1525718ac Mon Sep 17 00:00:00 2001 From: Martin Lowe Date: Mon, 24 Oct 2022 11:23:40 -0400 Subject: [PATCH 3/4] Update EFCA version, report filter for real call statement generation --- pom.xml | 2 +- .../org/eclipsefoundation/eclipsedb/dto/EventLogSessions.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 020d3c7f..3e9de2e9 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 1.4.10-SNAPSHOT pom - 0.6.7-SNAPSHOT + 0.6.7 2.22.1 3.8.1 11 diff --git a/portal/src/main/java/org/eclipsefoundation/eclipsedb/dto/EventLogSessions.java b/portal/src/main/java/org/eclipsefoundation/eclipsedb/dto/EventLogSessions.java index 6e8297ce..74c809e6 100644 --- a/portal/src/main/java/org/eclipsefoundation/eclipsedb/dto/EventLogSessions.java +++ b/portal/src/main/java/org/eclipsefoundation/eclipsedb/dto/EventLogSessions.java @@ -116,7 +116,7 @@ public class EventLogSessions extends BareNode { @Override public ParameterizedSQLStatement getFilters(MultivaluedMap params, boolean isRoot) { - ParameterizedCallStatement stmt = builder.buildSpecial(TABLE); + ParameterizedCallStatement stmt = builder.buildCallStatement(TABLE); stmt.setCallStatement("sp_evtlog_sessions"); // since check -- GitLab From 18ba6269f318fbd825adadb23cde28abe9ef1fe6 Mon Sep 17 00:00:00 2001 From: Martin Lowe Date: Fri, 28 Oct 2022 10:17:24 -0400 Subject: [PATCH 4/4] Fix missing copyright headers --- .../eclipsedb/dto/EventLogSessions.java | 11 +++++++++++ .../membership/portal/resources/ReportsResource.java | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/portal/src/main/java/org/eclipsefoundation/eclipsedb/dto/EventLogSessions.java b/portal/src/main/java/org/eclipsefoundation/eclipsedb/dto/EventLogSessions.java index 74c809e6..8e2c23ec 100644 --- a/portal/src/main/java/org/eclipsefoundation/eclipsedb/dto/EventLogSessions.java +++ b/portal/src/main/java/org/eclipsefoundation/eclipsedb/dto/EventLogSessions.java @@ -1,3 +1,14 @@ +/** + * Copyright (c) 2022 Eclipse Foundation + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Author: Martin Lowe + * + * SPDX-License-Identifier: EPL-2.0 + */ package org.eclipsefoundation.eclipsedb.dto; import java.sql.Date; diff --git a/portal/src/main/java/org/eclipsefoundation/membership/portal/resources/ReportsResource.java b/portal/src/main/java/org/eclipsefoundation/membership/portal/resources/ReportsResource.java index 328be20f..627daae5 100644 --- a/portal/src/main/java/org/eclipsefoundation/membership/portal/resources/ReportsResource.java +++ b/portal/src/main/java/org/eclipsefoundation/membership/portal/resources/ReportsResource.java @@ -1,3 +1,14 @@ +/** + * Copyright (c) 2022 Eclipse Foundation + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Author: Martin Lowe + * + * SPDX-License-Identifier: EPL-2.0 + */ package org.eclipsefoundation.membership.portal.resources; import java.io.IOException; -- GitLab