diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/api/MakercheckersApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/api/MakercheckersApiResource.java index a53994c11..593d3e186 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/api/MakercheckersApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/api/MakercheckersApiResource.java @@ -28,6 +28,7 @@ import org.mifosplatform.commands.data.AuditSearchData; import org.mifosplatform.commands.data.CommandSourceData; import org.mifosplatform.commands.service.AuditReadPlatformService; import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService; +import org.mifosplatform.infrastructure.core.api.ApiParameterHelper; import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.exception.UnrecognizedQueryParamException; @@ -44,45 +45,66 @@ import org.springframework.stereotype.Component; public class MakercheckersApiResource { private final Set RESPONSE_DATA_PARAMETERS = new HashSet( - Arrays.asList("id", "actionName", "entityName", "resourceId", "subresourceId", - "maker", "madeOnDate", "checker", "checkedOnDate", "processingResult", - "commandAsJson", "officeName", "groupLevelName", "groupName", "clientName", "loanAccountNo", "savingsAccountNo")); - private final String resourceNameForPermissions = "MAKERCHECKER"; + Arrays.asList("id", "actionName", "entityName", "resourceId", + "subresourceId", "maker", "madeOnDate", "checker", + "checkedOnDate", "processingResult", "commandAsJson", + "officeName", "groupLevelName", "groupName", "clientName", + "loanAccountNo", "savingsAccountNo")); + private final String resourceNameForPermissions = "MAKERCHECKER"; - private final PlatformSecurityContext context; - private final AuditReadPlatformService readPlatformService; - private final DefaultToApiJsonSerializer toApiJsonSerializer; - private final DefaultToApiJsonSerializer toApiJsonSerializerAudit; + private final PlatformSecurityContext context; + private final AuditReadPlatformService readPlatformService; + private final DefaultToApiJsonSerializer toApiJsonSerializer; + private final DefaultToApiJsonSerializer toApiJsonSerializerAudit; private final DefaultToApiJsonSerializer toApiJsonSerializerSearchTemplate; - private final ApiRequestParameterHelper apiRequestParameterHelper; - private final PortfolioCommandSourceWritePlatformService writePlatformService; + private final ApiRequestParameterHelper apiRequestParameterHelper; + private final PortfolioCommandSourceWritePlatformService writePlatformService; - @Autowired - public MakercheckersApiResource(final PlatformSecurityContext context, final AuditReadPlatformService readPlatformService, - final DefaultToApiJsonSerializer toApiJsonSerializer, final DefaultToApiJsonSerializer toApiJsonSerializerAudit, - final DefaultToApiJsonSerializer toApiJsonSerializerSearchTemplate, - final ApiRequestParameterHelper apiRequestParameterHelper, final PortfolioCommandSourceWritePlatformService writePlatformService) { - this.context = context; - this.readPlatformService = readPlatformService; - this.toApiJsonSerializer = toApiJsonSerializer; - this.apiRequestParameterHelper = apiRequestParameterHelper; - this.toApiJsonSerializerAudit = toApiJsonSerializerAudit; - this.toApiJsonSerializerSearchTemplate = toApiJsonSerializerSearchTemplate; - this.writePlatformService = writePlatformService; - } + @Autowired + public MakercheckersApiResource( + final PlatformSecurityContext context, + final AuditReadPlatformService readPlatformService, + final DefaultToApiJsonSerializer toApiJsonSerializer, + final DefaultToApiJsonSerializer toApiJsonSerializerAudit, + final DefaultToApiJsonSerializer toApiJsonSerializerSearchTemplate, + final ApiRequestParameterHelper apiRequestParameterHelper, + final PortfolioCommandSourceWritePlatformService writePlatformService) { + this.context = context; + this.readPlatformService = readPlatformService; + this.toApiJsonSerializer = toApiJsonSerializer; + this.apiRequestParameterHelper = apiRequestParameterHelper; + this.toApiJsonSerializerAudit = toApiJsonSerializerAudit; + this.toApiJsonSerializerSearchTemplate = toApiJsonSerializerSearchTemplate; + this.writePlatformService = writePlatformService; + } - @GET - @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) - public String retrieveCommands(@Context final UriInfo uriInfo) { + @GET + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveCommands(@Context final UriInfo uriInfo, + @QueryParam("actionName") final String actionName, + @QueryParam("entityName") final String entityName, + @QueryParam("resourceId") final Long resourceId, + @QueryParam("makerId") final Long makerId, + @QueryParam("makerDateTimeFrom") final String makerDateTimeFrom, + @QueryParam("makerDateTimeTo") final String makerDateTimeTo) { - context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions); + context.authenticatedUser().validateHasReadPermission( + resourceNameForPermissions); - final Collection entries = this.readPlatformService.retrieveAllEntriesToBeChecked(); + final String extraCriteria = getExtraCriteria(actionName, entityName, + resourceId, makerId, makerDateTimeFrom, makerDateTimeTo); - final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); - return this.toApiJsonSerializerAudit.serialize(settings, entries, RESPONSE_DATA_PARAMETERS); - } + final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper + .process(uriInfo.getQueryParameters()); + + final Collection entries = this.readPlatformService + .retrieveAllEntriesToBeChecked(extraCriteria, + settings.isIncludeJson()); + + return this.toApiJsonSerializerAudit.serialize(settings, entries, + RESPONSE_DATA_PARAMETERS); + } @GET @Path("/searchtemplate") @@ -105,35 +127,77 @@ public class MakercheckersApiResource { return this.toApiJsonSerializerSearchTemplate.serialize(settings, auditSearchData, RESPONSE_DATA_PARAMETERS_SEARCH_TEMPLATE); } - - @POST - @Path("{commandId}") - @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) - public String approveMakerCheckerEntry(@PathParam("commandId") final Long commandId, @QueryParam("command") final String commandParam) { - CommandProcessingResult result = null; - if (is(commandParam, "approve")) { - result = this.writePlatformService.approveEntry(commandId); - } else { - throw new UnrecognizedQueryParamException("command", commandParam); - } + @POST + @Path("{commandId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String approveMakerCheckerEntry( + @PathParam("commandId") final Long commandId, + @QueryParam("command") final String commandParam) { - return this.toApiJsonSerializer.serialize(result); - } + CommandProcessingResult result = null; + if (is(commandParam, "approve")) { + result = this.writePlatformService.approveEntry(commandId); + } else { + throw new UnrecognizedQueryParamException("command", commandParam); + } - private boolean is(final String commandParam, final String commandValue) { - return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue); - } + return this.toApiJsonSerializer.serialize(result); + } - @DELETE - @Path("{commandId}") - @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) - public String deleteMakerCheckerEntry(@PathParam("commandId") final Long commandId) { + private boolean is(final String commandParam, final String commandValue) { + return StringUtils.isNotBlank(commandParam) + && commandParam.trim().equalsIgnoreCase(commandValue); + } - final Long id = this.writePlatformService.deleteEntry(commandId); + @DELETE + @Path("{commandId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String deleteMakerCheckerEntry( + @PathParam("commandId") final Long commandId) { - return this.toApiJsonSerializer.serialize(CommandProcessingResult.commandOnlyResult(id)); - } + final Long id = this.writePlatformService.deleteEntry(commandId); + + return this.toApiJsonSerializer.serialize(CommandProcessingResult + .commandOnlyResult(id)); + } + + private String getExtraCriteria(final String actionName, + final String entityName, final Long resourceId, final Long makerId, + final String makerDateTimeFrom, final String makerDateTimeTo) { + + String extraCriteria = ""; + + if (actionName != null) { + extraCriteria += " and aud.action_name = " + + ApiParameterHelper.sqlEncodeString(actionName); + } + if (entityName != null) { + extraCriteria += " and aud.entity_name like " + + ApiParameterHelper.sqlEncodeString(entityName + "%"); + } + + if (resourceId != null) { + extraCriteria += " and aud.resource_id = " + resourceId; + } + if (makerId != null) { + extraCriteria += " and aud.maker_id = " + makerId; + } + if (makerDateTimeFrom != null) { + extraCriteria += " and aud.made_on_date >= " + + ApiParameterHelper.sqlEncodeString(makerDateTimeFrom); + } + if (makerDateTimeTo != null) { + extraCriteria += " and aud.made_on_date <= " + + ApiParameterHelper.sqlEncodeString(makerDateTimeTo); + } + + if (StringUtils.isNotBlank(extraCriteria)) { + extraCriteria = extraCriteria.substring(4); + } + + return extraCriteria; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/AuditReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/AuditReadPlatformService.java index e1d40bce1..a8c7cae6e 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/AuditReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/AuditReadPlatformService.java @@ -14,10 +14,10 @@ public interface AuditReadPlatformService { Collection retrieveAuditEntries(String extraCriteria, boolean includeJson); + Collection retrieveAllEntriesToBeChecked(String extraCriteria, boolean includeJson); + AuditData retrieveAuditEntry(Long auditId); AuditSearchData retrieveSearchTemplate(String useType); - Collection retrieveAllEntriesToBeChecked(); - } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/AuditReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/AuditReadPlatformServiceImpl.java index 1a44c7a2d..335ff593d 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/AuditReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/AuditReadPlatformServiceImpl.java @@ -20,6 +20,7 @@ import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityExce import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.useradministration.data.AppUserData; +import org.mifosplatform.useradministration.domain.AppUser; import org.mifosplatform.useradministration.service.AppUserReadPlatformService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,14 +48,14 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService { } private static final class AuditMapper implements RowMapper { -//TODO - jpw need to break this down, also data scope etc. - public String schema(boolean includeJson) { + + public String schema(boolean includeJson, String hierarchy) { String commandAsJsonString = ""; if (includeJson) commandAsJsonString = ", aud.command_as_json as commandAsJson "; - return " aud.id as id, aud.action_name as actionName, aud.entity_name as entityName," + String partSql = " aud.id as id, aud.action_name as actionName, aud.entity_name as entityName," + " aud.resource_id as resourceId, aud.subresource_id as subresourceId," + " mk.username as maker, aud.made_on_date as madeOnDate, " + "ck.username as checker, aud.checked_on_date as checkedOnDate, ev.enum_message_property as processingResult " @@ -72,6 +73,15 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService { + " left join m_loan l on l.id = aud.loan_id" + " left join m_savings_account s on s.id = aud.savings_account_id" + " left join r_enum_value ev on ev.enum_name = 'processing_result_enum' and ev.enum_id = aud.processing_result_enum"; + + // data scoping: head office (hierarchy = ".") can see all audit + // entries + if (!(hierarchy.equals("."))) { + partSql += " join m_office o on o.id = aud.office_id and o.hierarchy like '" + + hierarchy + "%' "; + } + + return partSql; } @Override @@ -117,25 +127,55 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService { @Override public Collection retrieveAuditEntries(String extraCriteria, boolean includeJson) { - context.authenticatedUser(); + + String updatedExtraCriteria = ""; + if (StringUtils.isNotBlank(extraCriteria)) + updatedExtraCriteria = " where (" + extraCriteria + ")"; + + updatedExtraCriteria += " order by aud.id DESC"; + return retrieveEntries(updatedExtraCriteria, includeJson); + } + + @Override + public Collection retrieveAllEntriesToBeChecked( + String extraCriteria, boolean includeJson) { + + String updatedExtraCriteria = ""; + if (StringUtils.isNotBlank(extraCriteria)) + updatedExtraCriteria = " where (" + extraCriteria + ")" + + " and aud.processing_result_enum = 2"; + else + updatedExtraCriteria = " where aud.processing_result_enum = 2"; + + updatedExtraCriteria += " order by aud.id"; + //TODO - should only be pulling back makerchecker entries that the user has maker-checker permissions for + return retrieveEntries(updatedExtraCriteria, includeJson); + } + + public Collection retrieveEntries(String extraCriteria, + boolean includeJson) { + + AppUser currentUser = context.authenticatedUser(); + String hierarchy = currentUser.getOffice().getHierarchy(); final AuditMapper rm = new AuditMapper(); - String sql = "select " + rm.schema(includeJson); - if (StringUtils.isNotBlank(extraCriteria)) - sql += " where (" + extraCriteria + ")"; - sql += " order by aud.id DESC"; + String sql = "select " + rm.schema(includeJson, hierarchy) + + extraCriteria; logger.info("sql: " + sql); + return this.jdbcTemplate.query(sql, rm, new Object[] {}); } @Override public AuditData retrieveAuditEntry(Long auditId) { - context.authenticatedUser(); + + AppUser currentUser = context.authenticatedUser(); + String hierarchy = currentUser.getOffice().getHierarchy(); final AuditMapper rm = new AuditMapper(); - String sql = "select " + rm.schema(true); + String sql = "select " + rm.schema(true, hierarchy); sql += " where aud.id = " + auditId; return this.jdbcTemplate.queryForObject(sql, rm, new Object[] {}); @@ -143,11 +183,13 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService { @Override public AuditSearchData retrieveSearchTemplate(String useType) { - - if (!(useType.equals("audit") || useType.equals("makerchecker"))) { - throw new PlatformDataIntegrityException("error.msg.invalid.auditSearchTemplate.useType", - "Invalid Audit Search Template UseType: " + useType); } - + + if (!(useType.equals("audit") || useType.equals("makerchecker"))) { + throw new PlatformDataIntegrityException( + "error.msg.invalid.auditSearchTemplate.useType", + "Invalid Audit Search Template UseType: " + useType); + } + final Collection appUsers = appUserReadPlatformService .retrieveSearchTemplate(); @@ -162,27 +204,14 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService { Collection processingResults = null; if (useType.equals("audit")) { ProcessingResultsMapper mapper3 = new ProcessingResultsMapper(); - processingResults = this.jdbcTemplate.query(mapper3.schema(), mapper3, new Object[] {}); + processingResults = this.jdbcTemplate.query(mapper3.schema(), + mapper3, new Object[] {}); } - + return new AuditSearchData(appUsers, actionNames, entityNames, processingResults); } - @Override - public Collection retrieveAllEntriesToBeChecked() { - context.authenticatedUser(); - - final AuditMapper rm = new AuditMapper(); - - final String sql = "select " + rm.schema(false) - + " where aud.checker_id is null and aud.processing_result_enum = 2 order by aud.id"; - //+ " where mc.checker_id is null and mc.processing_result_enum = 2 order by mc.made_on_date DESC, mc.entity_name ASC, mc.action_name ASC"; - logger.info("sql: " + sql); - - return this.jdbcTemplate.query(sql, rm, new Object[] {}); - } - private static final class ActionNamesMapper implements RowMapper { @Override