Merge pull request #694 from ashok-conflux/MIFOSX-824

Added pagination support to audit API
This commit is contained in:
Vishwas Babu A J
2013-12-12 22:58:37 -08:00
6 changed files with 316 additions and 8 deletions
+90 -2
View File
@@ -10657,8 +10657,8 @@ Content-Type: application/json
<div class="method-section">
<div class="method-description">
<h4>List Audits</h4>
<p>Get a list of audits that match the criteria supplied,
and are within the requestors' data scope.</p>
<p>Get a 200 list of audits that match the criteria supplied and sorted by audit id in descending order,
and are within the requestors' data scope. Also it supports pagination and sorting</p>
<h5>Arguments</h5>
<dl class="argument-list">
<dt>actionName</dt>
@@ -10749,6 +10749,35 @@ Content-Type: application/json
<dd>optional, <span>
Values are true, false. Default is false.</span>
</dd>
<dt>paged</dt>
<dd>
Boolean <span>optional</span>, defaults to false
</dd>
<dd>If paged is true then results will be paginated.</dd>
<dt>offset</dt>
<dd>
Integer <span>optional</span>, defaults to 0
</dd>
<dd>Indicates from what result to start from.</dd>
<dt>limit</dt>
<dd>
Integer <span>optional</span>, defaults to 200
</dd>
<dd>Restricts the size of results returned. To override the default and return all entries you must explicitly pass a non-positive integer value for limit e.g. limit=0, or limit=-1</dd>
<dt>orderBy</dt>
<dd>
String <span>optional</span>, one of <span>id, actionName, entityName, resourceId, subresourceId, madeOnDate, checkedOnDate, officeName, groupName, clientName, loanAccountNo, savingsAccountNo</span>
</dd>
<dd>Orders the results by the field indicated.</dd>
<dt>sortBy</dt>
<dd>
String <span>optional</span>, one of <span>ASC, DESC</span>
</dd>
<dd>Indicates what way to order results if <i>orderBy</i> is used.</dd>
</dl>
<p>Example Requests:</p>
@@ -10842,6 +10871,65 @@ GET https://DomainName/api/v1/audits
},...
]
</code>
<code class="method-declaration">
GET https://DomainName/api/v1/audits?paged=true&limit=5
</code>
<code class="method-response">
{
"totalFilteredRecords": 30,
"pageItems": [
{
"id": 671,
"actionName": "PERMISSIONS",
"entityName": "ROLE",
"resourceId": 6,
"maker": "keithwoodlock",
"madeOnDate": 1365014262000,
"processingResult": "processed"
},
{
"id": 670,
"actionName": "CREATE",
"entityName": "CLIENTNOTE",
"resourceId": 287,
"maker": "keithwoodlock",
"madeOnDate": 1365014204000,
"processingResult": "awaiting.approval",
"officeName": "my office",
"clientName": "gg ggg"
},
{
"id": 668,
"actionName": "UPDATE",
"entityName": "PERMISSION",
"maker": "keithwoodlock",
"madeOnDate": 1365014186000,
"processingResult": "processed"
},
{
"id": 667,
"actionName": "CREATE",
"entityName": "CLIENTNOTE",
"resourceId": 286,
"maker": "keithwoodlock",
"madeOnDate": 1365014169000,
"processingResult": "processed",
"officeName": "my office name",
"clientName": "gg ggg"
},
{
"id": 666,
"actionName": "CREATE",
"entityName": "CLIENT",
"resourceId": 363,
"maker": "keithwoodlock",
"madeOnDate": 1365012843000,
"processingResult": "awaiting.approval",
"officeName": "my office name"
}
]
}
</code>
</div>
</div>
@@ -26,8 +26,10 @@ import org.mifosplatform.commands.data.AuditSearchData;
import org.mifosplatform.commands.service.AuditReadPlatformService;
import org.mifosplatform.infrastructure.core.api.ApiParameterHelper;
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
import org.mifosplatform.infrastructure.core.data.PaginationParameters;
import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.mifosplatform.infrastructure.core.service.Page;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
@@ -72,15 +74,22 @@ public class AuditsApiResource {
@QueryParam("checkerDateTimeTo") final String checkerDateTimeTo,
@QueryParam("processingResult") final Integer processingResult, @QueryParam("officeId") final Integer officeId,
@QueryParam("groupId") final Integer groupId, @QueryParam("clientId") final Integer clientId,
@QueryParam("loanid") final Integer loanId, @QueryParam("savingsAccountId") final Integer savingsAccountId) {
@QueryParam("loanid") final Integer loanId, @QueryParam("savingsAccountId") final Integer savingsAccountId,
@QueryParam("paged") final Boolean paged, @QueryParam("offset") final Integer offset, @QueryParam("limit") final Integer limit,
@QueryParam("orderBy") final String orderBy, @QueryParam("sortOrder") final String sortOrder) {
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
final PaginationParameters parameters = PaginationParameters.instance(paged, offset, limit, orderBy, sortOrder);
final String extraCriteria = getExtraCriteria(actionName, entityName, resourceId, makerId, makerDateTimeFrom, makerDateTimeTo,
checkerId, checkerDateTimeFrom, checkerDateTimeTo, processingResult, officeId, groupId, clientId, loanId, savingsAccountId);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
if (parameters.isPaged()){
final Page<AuditData> auditEntries = this.auditReadPlatformService.retrievePaginatedAuditEntries(extraCriteria, settings.isIncludeJson(), parameters);
return this.toApiJsonSerializer.serialize(settings, auditEntries, this.RESPONSE_DATA_PARAMETERS);
}
final Collection<AuditData> auditEntries = this.auditReadPlatformService.retrieveAuditEntries(extraCriteria,
settings.isIncludeJson());
@@ -9,10 +9,14 @@ import java.util.Collection;
import org.mifosplatform.commands.data.AuditData;
import org.mifosplatform.commands.data.AuditSearchData;
import org.mifosplatform.infrastructure.core.data.PaginationParameters;
import org.mifosplatform.infrastructure.core.service.Page;
public interface AuditReadPlatformService {
Collection<AuditData> retrieveAuditEntries(String extraCriteria, boolean includeJson);
Page<AuditData> retrievePaginatedAuditEntries(String extraCriteria, boolean includeJson, PaginationParameters parameters);
Collection<AuditData> retrieveAllEntriesToBeChecked(String extraCriteria, boolean includeJson);
@@ -8,18 +8,25 @@ package org.mifosplatform.commands.service;
import java.lang.reflect.Type;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;
import org.mifosplatform.commands.data.AuditData;
import org.mifosplatform.commands.data.AuditSearchData;
import org.mifosplatform.commands.data.ProcessingResultLookup;
import org.mifosplatform.infrastructure.core.data.PaginationParameters;
import org.mifosplatform.infrastructure.core.data.PaginationParametersDataValidator;
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.infrastructure.core.service.Page;
import org.mifosplatform.infrastructure.core.service.PaginationHelper;
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.organisation.office.data.OfficeData;
@@ -49,6 +56,9 @@ import com.google.gson.JsonObject;
public class AuditReadPlatformServiceImpl implements AuditReadPlatformService {
private final static Logger logger = LoggerFactory.getLogger(AuditReadPlatformServiceImpl.class);
private final static Set<String> supportedOrderByValues = new HashSet<String>(Arrays.asList("id", "actionName", "entityName",
"resourceId", "subresourceId", "madeOnDate", "checkedOnDate", "officeName", "groupName", "clientName", "loanAccountNo",
"savingsAccountNo"));
private final JdbcTemplate jdbcTemplate;
private final PlatformSecurityContext context;
@@ -58,12 +68,15 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService {
private final ClientReadPlatformService clientReadPlatformService;
private final LoanProductReadPlatformService loanProductReadPlatformService;
private final StaffReadPlatformService staffReadPlatformService;
private final PaginationHelper<AuditData> paginationHelper = new PaginationHelper<AuditData>();
private final PaginationParametersDataValidator paginationParametersDataValidator;
@Autowired
public AuditReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
final FromJsonHelper fromApiJsonHelper, final AppUserReadPlatformService appUserReadPlatformService,
final OfficeReadPlatformService officeReadPlatformService, final ClientReadPlatformService clientReadPlatformService,
final LoanProductReadPlatformService loanProductReadPlatformService, final StaffReadPlatformService staffReadPlatformService) {
final LoanProductReadPlatformService loanProductReadPlatformService, final StaffReadPlatformService staffReadPlatformService,
final PaginationParametersDataValidator paginationParametersDataValidator) {
this.context = context;
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.fromApiJsonHelper = fromApiJsonHelper;
@@ -72,6 +85,7 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService {
this.clientReadPlatformService = clientReadPlatformService;
this.loanProductReadPlatformService = loanProductReadPlatformService;
this.staffReadPlatformService = staffReadPlatformService;
this.paginationParametersDataValidator = paginationParametersDataValidator;
}
private static final class AuditMapper implements RowMapper<AuditData> {
@@ -145,10 +159,44 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService {
if (StringUtils.isNotBlank(extraCriteria)) {
updatedExtraCriteria = " where (" + extraCriteria + ")";
}
updatedExtraCriteria += " order by aud.id DESC";
updatedExtraCriteria += " order by aud.id DESC limit " + PaginationParameters.getCheckedLimit(null);
return retrieveEntries("audit", updatedExtraCriteria, includeJson);
}
@Override
public Page<AuditData> retrievePaginatedAuditEntries(final String extraCriteria, final boolean includeJson, final PaginationParameters parameters) {
this.paginationParametersDataValidator.validateParameterValues(parameters, supportedOrderByValues, "audits");
final AppUser currentUser = this.context.authenticatedUser();
final String hierarchy = currentUser.getOffice().getHierarchy();
String updatedExtraCriteria = "";
if (StringUtils.isNotBlank(extraCriteria)) {
updatedExtraCriteria = " where (" + extraCriteria + ")";
}
final AuditMapper rm = new AuditMapper();
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
sqlBuilder.append(rm.schema(includeJson, hierarchy));
sqlBuilder.append(' ').append(updatedExtraCriteria);
if (parameters.isOrderByRequested()) {
sqlBuilder.append(' ').append(parameters.orderBySql());
}else {
sqlBuilder.append(' ').append(' ').append(" order by aud.id DESC");
}
if (parameters.isLimited()) {
sqlBuilder.append(' ').append(parameters.limitSql());
}
logger.info("sql: " + sqlBuilder.toString());
final String sqlCountRows = "SELECT FOUND_ROWS()";
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), new Object[] {}, rm);
}
@Override
public Collection<AuditData> retrieveAllEntriesToBeChecked(final String extraCriteria, final boolean includeJson) {
@@ -195,7 +243,7 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService {
return this.jdbcTemplate.query(sql, rm, new Object[] {});
}
@Override
public AuditData retrieveAuditEntry(final Long auditId) {
@@ -0,0 +1,115 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.infrastructure.core.data;
import org.apache.commons.lang.StringUtils;
/**
* <p>
* Immutable data object representing pagination parameter values.
* </p>
*/
public class PaginationParameters {
private final boolean paged;
private final Integer offset;
private final Integer limit;
private final String orderBy;
private final String sortOrder;
public static PaginationParameters instance (Boolean paged, Integer offset, Integer limit, String orderBy, String sortOrder){
if( null == paged) {
paged = false;
}
final Integer maxLimitAllowed = getCheckedLimit(limit);
return new PaginationParameters(paged, offset, maxLimitAllowed, orderBy, sortOrder);
}
private PaginationParameters(boolean paged, Integer offset, Integer limit, String orderBy, String sortOrder) {
this.paged = paged;
this.offset = offset;
this.limit = limit;
this.orderBy = orderBy;
this.sortOrder = sortOrder;
}
public static Integer getCheckedLimit(final Integer limit) {
final Integer maxLimitAllowed = 200;
// default to max limit first off
Integer checkedLimit = maxLimitAllowed;
if (limit != null && limit > 0) {
checkedLimit = limit;
} else if (limit != null) {
// unlimited case: limit provided and 0 or less
checkedLimit = null;
}
return checkedLimit;
}
public boolean isPaged() {
return this.paged;
}
public Integer getOffset() {
return this.offset;
}
public Integer getLimit() {
return this.limit;
}
public String getOrderBy() {
return this.orderBy;
}
public String getSortOrder() {
return this.sortOrder;
}
public boolean isOrderByRequested() {
return StringUtils.isNotBlank(this.orderBy);
}
public boolean isSortOrderProvided() {
return StringUtils.isNotBlank(this.sortOrder);
}
public boolean isLimited() {
return this.limit != null && this.limit.intValue() > 0;
}
public boolean isOffset() {
return this.offset != null;
}
public String orderBySql(){
final StringBuffer sql = new StringBuffer();
if (this.isOrderByRequested()) {
sql.append(" order by ").append(this.getOrderBy());
if (this.isSortOrderProvided()) {
sql.append(' ').append(this.getSortOrder());
}
}
return sql.toString();
}
public String limitSql(){
final StringBuffer sql = new StringBuffer();
if (this.isLimited()) {
sql.append(" limit ").append(this.getLimit());
if (this.isOffset()) {
sql.append(" offset ").append(this.getOffset());
}
}
return sql.toString();
}
}
@@ -0,0 +1,44 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.infrastructure.core.data;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
import org.springframework.stereotype.Component;
@Component
public class PaginationParametersDataValidator {
public static Set<String> sortOrderValues = new HashSet<String>(Arrays.asList("ASC", "DESC"));
public void validateParameterValues(PaginationParameters parameters, final Set<String> supportedOrdeByValues, final String resourceName) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
if (parameters.isOrderByRequested() && !supportedOrdeByValues.contains(parameters.getOrderBy())){
final String defaultUserMessage = "The orderBy value '" + parameters.getOrderBy() + "' is not supported. The supported orderBy values are " + supportedOrdeByValues.toString();
final ApiParameterError error = ApiParameterError.parameterError("validation.msg."+resourceName+".orderBy.value.is.not.supported",
defaultUserMessage, "orderBy", parameters.getOrderBy(), supportedOrdeByValues.toString());
dataValidationErrors.add(error);
}
if (parameters.isSortOrderProvided() && !sortOrderValues.contains(parameters.getSortOrder().toUpperCase())){
final String defaultUserMessage = "The sortOrder value '" + parameters.getSortOrder() + "' is not supported. The supported sortOrder values are " + sortOrderValues.toString();
final ApiParameterError error = ApiParameterError.parameterError("validation.msg."+resourceName+".sortOrder.value.is.not.supported",
defaultUserMessage, "sortOrder", parameters.getSortOrder(), sortOrderValues.toString());
dataValidationErrors.add(error);
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
}