This is an automated email from the ASF dual-hosted git repository. awasum pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/fineract-cn-reporting.git
commit dc8dc1f2522d106a86a804e296af1802ed285587 Author: mgeiss <[email protected]> AuthorDate: Thu Jul 6 11:04:00 2017 +0200 added first report --- .../reporting/api/v1/PermittableGroupIds.java | 3 +- .../reporting/api/v1/client/ReportManager.java | 14 ++ .../mifos/reporting/api/v1/domain/ReportPage.java | 19 +- .../io/mifos/reporting/api/v1/domain/Value.java | 10 +- service/build.gradle | 3 +- .../reporting/service/ReportingConfiguration.java | 7 +- .../provider/ReportSpecificationProvider.java | 12 ++ .../CustomerListReportSpecification.java | 197 +++++++++++++++++++-- .../service/rest/ReportingRestController.java | 24 ++- .../reporting/service/spi/CriteriaBuilder.java | 83 +++++++++ .../reporting/service/spi/ReportSpecification.java | 2 +- 11 files changed, 327 insertions(+), 47 deletions(-) diff --git a/api/src/main/java/io/mifos/reporting/api/v1/PermittableGroupIds.java b/api/src/main/java/io/mifos/reporting/api/v1/PermittableGroupIds.java index d0a3bed..8e28149 100644 --- a/api/src/main/java/io/mifos/reporting/api/v1/PermittableGroupIds.java +++ b/api/src/main/java/io/mifos/reporting/api/v1/PermittableGroupIds.java @@ -17,6 +17,5 @@ package io.mifos.reporting.api.v1; @SuppressWarnings("unused") public interface PermittableGroupIds { - String SAMPLE_MANAGEMENT = "reporting__v1__samples"; - String SELF_MANAGEMENT = "reporting__v1__self"; + String REPORT_MANAGEMENT = "reporting__v1__general"; } diff --git a/api/src/main/java/io/mifos/reporting/api/v1/client/ReportManager.java b/api/src/main/java/io/mifos/reporting/api/v1/client/ReportManager.java index 50a1b6c..950ba6b 100644 --- a/api/src/main/java/io/mifos/reporting/api/v1/client/ReportManager.java +++ b/api/src/main/java/io/mifos/reporting/api/v1/client/ReportManager.java @@ -18,12 +18,15 @@ package io.mifos.reporting.api.v1.client; import io.mifos.core.api.annotation.ThrowsException; import io.mifos.core.api.annotation.ThrowsExceptions; import io.mifos.core.api.util.CustomFeignClientsConfiguration; +import io.mifos.core.lang.ServiceException; +import io.mifos.reporting.api.v1.PermittableGroupIds; import io.mifos.reporting.api.v1.domain.ReportDefinition; import io.mifos.reporting.api.v1.domain.ReportPage; import io.mifos.reporting.api.v1.domain.ReportRequest; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -69,4 +72,15 @@ public interface ReportManager { @RequestBody final ReportRequest reportRequest, @RequestParam(value = "pageIndex", required = false) final Integer pageIndex, @RequestParam(value = "size", required = false) final Integer size); + + @RequestMapping( + value = "categories/{category}/definitions/{identifier}", + method = RequestMethod.GET, + produces = MediaType.ALL_VALUE, + consumes = MediaType.APPLICATION_JSON_VALUE) + @ThrowsExceptions({ + @ThrowsException(status = HttpStatus.NOT_FOUND, exception = ReportNotFoundException.class) + }) + ReportDefinition findReportDefinition(@PathVariable("category") final String category, + @PathVariable("identifier") final String identifier); } diff --git a/api/src/main/java/io/mifos/reporting/api/v1/domain/ReportPage.java b/api/src/main/java/io/mifos/reporting/api/v1/domain/ReportPage.java index 90db8f7..2bd088f 100644 --- a/api/src/main/java/io/mifos/reporting/api/v1/domain/ReportPage.java +++ b/api/src/main/java/io/mifos/reporting/api/v1/domain/ReportPage.java @@ -26,8 +26,7 @@ public class ReportPage { private Header header; private List<Row> rows; private Footer footer; - private Integer totalPages; - private Long totalElements; + private boolean hasMore; public ReportPage() { super(); @@ -89,19 +88,11 @@ public class ReportPage { this.footer = footer; } - public Integer getTotalPages() { - return this.totalPages; + public void setHasMore(final boolean hasMore) { + this.hasMore = hasMore; } - public void setTotalPages(final Integer totalPages) { - this.totalPages = totalPages; - } - - public Long getTotalElements() { - return this.totalElements; - } - - public void setTotalElements(final Long totalElements) { - this.totalElements = totalElements; + public boolean isHasMore() { + return hasMore; } } diff --git a/api/src/main/java/io/mifos/reporting/api/v1/domain/Value.java b/api/src/main/java/io/mifos/reporting/api/v1/domain/Value.java index a94be09..6887781 100644 --- a/api/src/main/java/io/mifos/reporting/api/v1/domain/Value.java +++ b/api/src/main/java/io/mifos/reporting/api/v1/domain/Value.java @@ -17,19 +17,19 @@ package io.mifos.reporting.api.v1.domain; public class Value { - private String value; + private String[] values; private Type type; public Value() { super(); } - public String getValue() { - return this.value; + public String[] getValues() { + return this.values; } - public void setValue(final String value) { - this.value = value; + public void setValues(final String[] values) { + this.values = values; } public Type getType() { diff --git a/service/build.gradle b/service/build.gradle index 9b9708a..7f74364 100644 --- a/service/build.gradle +++ b/service/build.gradle @@ -38,7 +38,8 @@ dependencies { [group: 'io.mifos.core', name: 'cassandra', version: versions.frameworkcassandra], [group: 'io.mifos.core', name: 'mariadb', version: versions.frameworkmariadb], [group: 'io.mifos.core', name: 'command', version: versions.frameworkcommand], - [group: 'org.hibernate', name: 'hibernate-validator', version: versions.validator] + [group: 'org.hibernate', name: 'hibernate-validator', version: versions.validator], + [group: 'org.owasp.esapi', name: 'esapi', version: '2.1.0.1'] ) } diff --git a/service/src/main/java/io/mifos/reporting/service/ReportingConfiguration.java b/service/src/main/java/io/mifos/reporting/service/ReportingConfiguration.java index f0ab979..6bf4fed 100644 --- a/service/src/main/java/io/mifos/reporting/service/ReportingConfiguration.java +++ b/service/src/main/java/io/mifos/reporting/service/ReportingConfiguration.java @@ -27,7 +27,6 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; -import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @@ -42,11 +41,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter @EnableServiceException @ComponentScan({ "io.mifos.reporting.service.rest", - "io.mifos.reporting.service.internal", - "io.mifos.reporting.service.repository" -}) -@EnableJpaRepositories({ - "io.mifos.reporting.service.repository" + "io.mifos.reporting.service.internal" }) public class ReportingConfiguration extends WebMvcConfigurerAdapter { diff --git a/service/src/main/java/io/mifos/reporting/service/internal/provider/ReportSpecificationProvider.java b/service/src/main/java/io/mifos/reporting/service/internal/provider/ReportSpecificationProvider.java index 7ef4871..3c9b646 100644 --- a/service/src/main/java/io/mifos/reporting/service/internal/provider/ReportSpecificationProvider.java +++ b/service/src/main/java/io/mifos/reporting/service/internal/provider/ReportSpecificationProvider.java @@ -92,4 +92,16 @@ public class ReportSpecificationProvider implements ApplicationContextAware { private String buildKeyForSpecificationCache(final String category, final String identifier) { return category + "~" + identifier; } + + public Optional<ReportDefinition> findReportDefinition(final String category, final String identifier) { + final List<ReportDefinition> reportDefinitions = this.reportCategoryCache.get(category); + if (reportDefinitions != null) { + return reportDefinitions + .stream() + .filter(reportDefinition -> reportDefinition.getIdentifier().equals(identifier)) + .findAny(); + } else { + return Optional.empty(); + } + } } diff --git a/service/src/main/java/io/mifos/reporting/service/internal/specification/CustomerListReportSpecification.java b/service/src/main/java/io/mifos/reporting/service/internal/specification/CustomerListReportSpecification.java index b166b53..f56657f 100644 --- a/service/src/main/java/io/mifos/reporting/service/internal/specification/CustomerListReportSpecification.java +++ b/service/src/main/java/io/mifos/reporting/service/internal/specification/CustomerListReportSpecification.java @@ -15,13 +15,19 @@ */ package io.mifos.reporting.service.internal.specification; +import io.mifos.core.api.util.UserContextHolder; +import io.mifos.core.lang.DateConverter; import io.mifos.reporting.api.v1.domain.DisplayableField; +import io.mifos.reporting.api.v1.domain.Header; import io.mifos.reporting.api.v1.domain.QueryParameter; import io.mifos.reporting.api.v1.domain.ReportDefinition; import io.mifos.reporting.api.v1.domain.ReportPage; import io.mifos.reporting.api.v1.domain.ReportRequest; +import io.mifos.reporting.api.v1.domain.Row; import io.mifos.reporting.api.v1.domain.Type; +import io.mifos.reporting.api.v1.domain.Value; import io.mifos.reporting.service.ServiceConstants; +import io.mifos.reporting.service.spi.CriteriaBuilder; import io.mifos.reporting.service.spi.DisplayableFieldBuilder; import io.mifos.reporting.service.spi.QueryParameterBuilder; import io.mifos.reporting.service.spi.Report; @@ -30,6 +36,11 @@ import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import javax.persistence.EntityManager; +import javax.persistence.Query; +import java.text.DecimalFormat; +import java.time.Clock; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -40,12 +51,17 @@ import java.util.stream.Collectors; public class CustomerListReportSpecification implements ReportSpecification { private final Logger logger; - private final HashMap<String, String> columnMapping = new HashMap<>(); + private final EntityManager entityManager; + private final HashMap<String, String> customerColumnMapping = new HashMap<>(); + private final HashMap<String, String> addressColumnMapping = new HashMap<>(); + private final HashMap<String, String> accountColumnMapping = new HashMap<>(); @Autowired - public CustomerListReportSpecification(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger) { + public CustomerListReportSpecification(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger, + final EntityManager entityManager) { super(); this.logger = logger; + this.entityManager = entityManager; this.initializeMapping(); } @@ -61,21 +77,40 @@ public class CustomerListReportSpecification implements ReportSpecification { } @Override - public ReportPage generateReport(final ReportRequest reportRequest) { - return null; + public ReportPage generateReport(final ReportRequest reportRequest, final int pageIndex, final int size) { + final ReportDefinition reportDefinition = this.getReportDefinition(); + this.logger.info("Generating report {0}.", reportDefinition.getIdentifier()); + + final ReportPage reportPage = new ReportPage(); + reportPage.setName(reportDefinition.getName()); + reportPage.setDescription(reportDefinition.getDescription()); + reportPage.setHeader(this.createHeader(reportRequest.getDisplayableFields())); + + final Query customerQuery = this.entityManager.createNativeQuery(this.buildCustomerQuery(reportRequest, pageIndex, size)); + final List<?> customerResultList = customerQuery.getResultList(); + reportPage.setRows(this.buildRows(reportRequest, customerResultList)); + + reportPage.setHasMore( + !this.entityManager.createNativeQuery(this.buildCustomerQuery(reportRequest, pageIndex + 1, size)) + .getResultList().isEmpty() + ); + + reportPage.setGeneratedBy(UserContextHolder.checkedGetUser()); + reportPage.setGeneratedOn(DateConverter.toIsoString(LocalDateTime.now(Clock.systemUTC()))); + return reportPage; } @Override public void validate(final ReportRequest reportRequest) throws IllegalArgumentException { final ArrayList<String> unknownFields = new ArrayList<>(); reportRequest.getQueryParameters().forEach(queryParameter -> { - if (!this.columnMapping.keySet().contains(queryParameter.getName())) { + if (!this.customerColumnMapping.keySet().contains(queryParameter.getName())) { unknownFields.add(queryParameter.getName()); } }); reportRequest.getDisplayableFields().forEach(displayableField -> { - if (!this.columnMapping.keySet().contains(displayableField.getName())) { + if (!this.customerColumnMapping.keySet().contains(displayableField.getName())) { unknownFields.add(displayableField.getName()); } }); @@ -88,15 +123,71 @@ public class CustomerListReportSpecification implements ReportSpecification { } private void initializeMapping() { - this.columnMapping.put("Date Range", "createdBy"); - this.columnMapping.put("State", "currentState"); - this.columnMapping.put("Customer", "identifier"); - this.columnMapping.put("Account number", "identifier"); - this.columnMapping.put("First name", "givenName"); - this.columnMapping.put("Middle Name", "middleName"); - this.columnMapping.put("Last Name", "surname"); - this.columnMapping.put("Balance", "balance"); - this.columnMapping.put("Address", "address"); + this.customerColumnMapping.put("Date Range", "cst.created_on"); + this.customerColumnMapping.put("State", "cst.current_state"); + this.customerColumnMapping.put("Customer", "cst.identifier"); + this.customerColumnMapping.put("First name", "cst.given_name"); + this.customerColumnMapping.put("Middle Name", "cst.middle_name"); + this.customerColumnMapping.put("Last Name", "cst.surname"); + + this.accountColumnMapping.put("Account number", "acc.identifier, acc.balance"); + + this.addressColumnMapping.put("Address", "CONCAT(adr.street, ', ', adr.postal_code, ', ', adr.city)"); + } + + private Header createHeader(final List<DisplayableField> displayableFields) { + final Header header = new Header(); + header.setColumnNames( + displayableFields + .stream() + .map(DisplayableField::getName) + .collect(Collectors.toList()) + ); + return header; + } + + private List<Row> buildRows(final ReportRequest reportRequest, final List<?> customerResultList) { + final ArrayList<Row> rows = new ArrayList<>(); + + customerResultList.forEach(result -> { + final Row row = new Row(); + row.setValues(new ArrayList<>()); + final Object[] resultValues = (Object[]) result; + for (final Object resultValue : resultValues) { + final Value value = new Value(); + value.setValues(new String[]{resultValue.toString()}); + row.getValues().add(value); + } + + final DecimalFormat decimalFormat = new DecimalFormat(".##"); + final Query accountQuery = this.entityManager.createNativeQuery(this.buildAccountQuery(reportRequest, resultValues[0].toString())); + final List<?> accountResultList = accountQuery.getResultList(); + final ArrayList<String> values = new ArrayList<>(); + accountResultList.forEach(accountResult -> { + if (accountResult instanceof Object[]) { + final Object[] accountResultValues = (Object[]) accountResult; + final String accountValue = accountResultValues[0].toString() + " (" + + decimalFormat.format(Double.valueOf(accountResultValues[1].toString())) + ")"; + values.add(accountValue); + } + }); + final Value accountValue = new Value(); + accountValue.setValues(values.toArray(new String[values.size()])); + row.getValues().add(accountValue); + + final String addressQueryString = this.buildAddressQuery(reportRequest, resultValues[0].toString()); + if (addressQueryString != null) { + final Query addressQuery = this.entityManager.createNativeQuery(addressQueryString); + final List<?> resultList = addressQuery.getResultList(); + final Value addressValue = new Value(); + addressValue.setValues(new String[]{resultList.get(0).toString()}); + row.getValues().add(addressValue); + } + + rows.add(row); + }); + + return rows; } private List<QueryParameter> buildQueryParameters() { @@ -113,8 +204,82 @@ public class CustomerListReportSpecification implements ReportSpecification { DisplayableFieldBuilder.create("Middle name", Type.TEXT).build(), DisplayableFieldBuilder.create("Last name", Type.TEXT).build(), DisplayableFieldBuilder.create("Account number", Type.TEXT).mandatory().build(), - DisplayableFieldBuilder.create("Balance", Type.NUMBER).build(), DisplayableFieldBuilder.create("Address", Type.TEXT).build() ); } + + private String buildCustomerQuery(final ReportRequest reportRequest, int pageIndex, int size) { + final StringBuilder query = new StringBuilder("SELECT "); + + final List<DisplayableField> displayableFields = reportRequest.getDisplayableFields(); + final ArrayList<String> columns = new ArrayList<>(); + displayableFields.forEach(displayableField -> { + final String column = this.customerColumnMapping.get(displayableField.getName()); + if (column != null) { + columns.add(column); + } + }); + + query.append(columns.stream().collect(Collectors.joining(", "))) + .append(" FROM ") + .append("maat_customers cst "); + + final List<QueryParameter> queryParameters = reportRequest.getQueryParameters(); + if (!queryParameters.isEmpty()) { + query.append(" WHERE "); + final ArrayList<String> criteria = new ArrayList<>(); + queryParameters.forEach(queryParameter -> criteria.add( + CriteriaBuilder.buildCriteria(this.customerColumnMapping.get(queryParameter.getName()), queryParameter)) + ); + query.append(criteria.stream().collect(Collectors.joining(" AND "))); + } + query.append(" ORDER BY cst.identifier"); + + query.append(" LIMIT "); + query.append(size); + if (pageIndex > 0) { + query.append(" OFFSET "); + query.append(size * pageIndex); + } + + return query.toString(); + } + + private String buildAccountQuery(final ReportRequest reportRequest, final String customerIdentifier) { + final List<DisplayableField> displayableFields = reportRequest.getDisplayableFields(); + final ArrayList<String> columns = new ArrayList<>(); + displayableFields.forEach(displayableField -> { + final String column = this.accountColumnMapping.get(displayableField.getName()); + if (column != null) { + columns.add(column); + } + }); + + return "SELECT " + columns.stream().collect(Collectors.joining(", ")) + " " + + "FROM thoth_accounts acc " + + "LEFT JOIN maat_customers cst on acc.holders = cst.identifier " + + "WHERE cst.identifier ='" + customerIdentifier + "' " + + "ORDER BY acc.identifier"; + } + + private String buildAddressQuery(final ReportRequest reportRequest, final String customerIdentifier) { + + final List<DisplayableField> displayableFields = reportRequest.getDisplayableFields(); + final ArrayList<String> columns = new ArrayList<>(); + displayableFields.forEach(displayableField -> { + final String column = this.addressColumnMapping.get(displayableField.getName()); + if (column != null) { + columns.add(column); + } + }); + + if (!columns.isEmpty()) { + return "SELECT " + columns.stream().collect(Collectors.joining(", ")) + " " + + "FROM thoth_accounts acc " + + "LEFT JOIN maat_customers cst on acc.holders = cst.identifier " + + "WHERE cst.identifier ='" + customerIdentifier + "' " + + "ORDER BY acc.identifier"; + } + return null; + } } diff --git a/service/src/main/java/io/mifos/reporting/service/rest/ReportingRestController.java b/service/src/main/java/io/mifos/reporting/service/rest/ReportingRestController.java index 16307c5..a23e355 100644 --- a/service/src/main/java/io/mifos/reporting/service/rest/ReportingRestController.java +++ b/service/src/main/java/io/mifos/reporting/service/rest/ReportingRestController.java @@ -18,6 +18,7 @@ package io.mifos.reporting.service.rest; import io.mifos.anubis.annotation.AcceptedTokenType; import io.mifos.anubis.annotation.Permittable; import io.mifos.core.lang.ServiceException; +import io.mifos.reporting.api.v1.PermittableGroupIds; import io.mifos.reporting.api.v1.domain.ReportDefinition; import io.mifos.reporting.api.v1.domain.ReportPage; import io.mifos.reporting.api.v1.domain.ReportRequest; @@ -66,9 +67,10 @@ public class ReportingRestController { public @ResponseBody ResponseEntity<Void> initialize() { - return ResponseEntity.accepted().build(); + return ResponseEntity.ok().build(); } + @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.REPORT_MANAGEMENT) @RequestMapping( value = "/categories", method = RequestMethod.GET, @@ -80,6 +82,7 @@ public class ReportingRestController { return ResponseEntity.ok(this.reportSpecificationProvider.getAvailableCategories()); } + @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.REPORT_MANAGEMENT) @RequestMapping( value = "categories/{category}", method = RequestMethod.GET, @@ -90,6 +93,7 @@ public class ReportingRestController { return ResponseEntity.ok(this.reportSpecificationProvider.getAvailableReports(category)); } + @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.REPORT_MANAGEMENT) @RequestMapping( value = "/categories/{category}/reports/{identifier}", method = RequestMethod.POST, @@ -114,9 +118,25 @@ public class ReportingRestController { throw ServiceException.badRequest(iaex.getMessage()); } - return ResponseEntity.ok(reportSpecification.generateReport(reportRequest)); + return ResponseEntity.ok(reportSpecification.generateReport(reportRequest, pageIndex, size)); } else { throw ServiceException.notFound("Report {0} not found.", identifier); } } + + @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.REPORT_MANAGEMENT) + @RequestMapping( + value = "categories/{category}/definitions/{identifier}", + method = RequestMethod.GET, + produces = MediaType.APPLICATION_JSON_VALUE, + consumes = MediaType.ALL_VALUE) + public + ResponseEntity<ReportDefinition> findReportDefinition( + @PathVariable("category") final String category, + @PathVariable("identifier") final String identifier) { + return ResponseEntity.ok( + this.reportSpecificationProvider.findReportDefinition(category, identifier) + .orElseThrow(() -> ServiceException.notFound("Report definition {0} not found.", identifier)) + ); + } } diff --git a/service/src/main/java/io/mifos/reporting/service/spi/CriteriaBuilder.java b/service/src/main/java/io/mifos/reporting/service/spi/CriteriaBuilder.java new file mode 100644 index 0000000..a0dc841 --- /dev/null +++ b/service/src/main/java/io/mifos/reporting/service/spi/CriteriaBuilder.java @@ -0,0 +1,83 @@ +/* + * Copyright 2017 The Mifos Initiative. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.mifos.reporting.service.spi; + +import io.mifos.reporting.api.v1.domain.QueryParameter; +import org.owasp.esapi.ESAPI; +import org.owasp.esapi.Encoder; +import org.owasp.esapi.codecs.MySQLCodec; +import org.springframework.util.StringUtils; + +import java.util.Set; +import java.util.stream.Collectors; + +public class CriteriaBuilder { + + // https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet + private static final Encoder ENCODER = ESAPI.encoder(); + private static final MySQLCodec MY_SQL_CODEC = new MySQLCodec(MySQLCodec.Mode.ANSI); + + private CriteriaBuilder() { + super(); + } + + public static String buildCriteria(final String field, final QueryParameter queryParameter) { + final StringBuilder criteria = new StringBuilder(field); + + switch (queryParameter.getOperator()) { + case EQUALS: + criteria.append(" = '"); + criteria.append(CriteriaBuilder.ENCODER.encodeForSQL(CriteriaBuilder.MY_SQL_CODEC, queryParameter.getValue())); + criteria.append("'"); + break; + case LIKE: + criteria.append(" LIKE '%"); + criteria.append(CriteriaBuilder.ENCODER.encodeForSQL(CriteriaBuilder.MY_SQL_CODEC, queryParameter.getValue())); + criteria.append("%'"); + break; + case GREATER: + criteria.append(" > '"); + criteria.append(CriteriaBuilder.ENCODER.encodeForSQL(CriteriaBuilder.MY_SQL_CODEC, queryParameter.getValue())); + criteria.append("'"); + break; + case LESSER: + criteria.append(" < '"); + criteria.append(CriteriaBuilder.ENCODER.encodeForSQL(CriteriaBuilder.MY_SQL_CODEC, queryParameter.getValue())); + criteria.append("'"); + break; + case IN: + criteria.append(" in ("); + final Set<String> strings = StringUtils.commaDelimitedListToSet(queryParameter.getValue()); + criteria.append( + strings + .stream() + .map(s -> "'" + CriteriaBuilder.ENCODER.encodeForSQL(CriteriaBuilder.MY_SQL_CODEC, s) + "'") + .collect(Collectors.joining(",")) + ); + break; + case BETWEEN: + final String[] splitString = queryParameter.getValue().split("\\.\\."); + criteria.append(" BETWEEN '"); + criteria.append(CriteriaBuilder.ENCODER.encodeForSQL(CriteriaBuilder.MY_SQL_CODEC, splitString[0])); + criteria.append("' AND '"); + criteria.append(CriteriaBuilder.ENCODER.encodeForSQL(CriteriaBuilder.MY_SQL_CODEC, splitString[1])); + criteria.append("'"); + break; + } + + return criteria.toString(); + } +} diff --git a/service/src/main/java/io/mifos/reporting/service/spi/ReportSpecification.java b/service/src/main/java/io/mifos/reporting/service/spi/ReportSpecification.java index 3502b94..0508411 100644 --- a/service/src/main/java/io/mifos/reporting/service/spi/ReportSpecification.java +++ b/service/src/main/java/io/mifos/reporting/service/spi/ReportSpecification.java @@ -23,7 +23,7 @@ public interface ReportSpecification { ReportDefinition getReportDefinition(); - ReportPage generateReport(final ReportRequest reportRequest); + ReportPage generateReport(final ReportRequest reportRequest, int pageIndex, int size); void validate(final ReportRequest reportRequest) throws IllegalArgumentException; }
