diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/ClientsApiResource.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/ClientsApiResource.java index e7688f382..1ef79f558 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/ClientsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/ClientsApiResource.java @@ -60,436 +60,402 @@ import com.sun.jersey.multipart.FormDataParam; @Scope("singleton") public class ClientsApiResource { - private final static Logger logger = LoggerFactory.getLogger(ClientsApiResource.class); + private final static Logger logger = LoggerFactory.getLogger(ClientsApiResource.class); - @Autowired - private ClientReadPlatformService clientReadPlatformService; + @Autowired + private ClientReadPlatformService clientReadPlatformService; - @Autowired - private ClientWritePlatformService clientWritePlatformService; - - @Autowired - private PortfolioCommandsReadPlatformService commandSourceReadPlatformService; - - @Autowired - private PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; + @Autowired + private ClientWritePlatformService clientWritePlatformService; - @Autowired - private OfficeReadPlatformService officeReadPlatformService; + @Autowired + private PortfolioCommandsReadPlatformService commandSourceReadPlatformService; + + @Autowired + private PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; + + @Autowired + private OfficeReadPlatformService officeReadPlatformService; + + @Autowired + private PortfolioApiDataConversionService apiDataConversionService; + + @Autowired + private PortfolioApiJsonSerializerService apiJsonSerializerService; - @Autowired - private PortfolioApiDataConversionService apiDataConversionService; - - @Autowired - private PortfolioApiJsonSerializerService apiJsonSerializerService; - @Autowired private PlatformSecurityContext context; - - @GET - @Consumes({MediaType.APPLICATION_JSON}) - @Produces({MediaType.APPLICATION_JSON}) - public String retrieveAllIndividualClients(@Context final UriInfo uriInfo, - @QueryParam("sqlSearch") final String sqlSearch, - @QueryParam("officeId") final Integer officeId, - @QueryParam("externalId") final String externalId, - @QueryParam("displayName") final String displayName, - @QueryParam("firstName") final String firstName, - @QueryParam("lastName") final String lastName, - @QueryParam("underHierarchy") final String hierarchy) { - context.authenticatedUser().validateHasReadPermission("CLIENT"); - - final String extraCriteria = getClientCriteria(sqlSearch, officeId, externalId, displayName, firstName, lastName, hierarchy); - - final Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); - final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); + @GET + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveAllIndividualClients(@Context final UriInfo uriInfo, @QueryParam("sqlSearch") final String sqlSearch, + @QueryParam("officeId") final Integer officeId, @QueryParam("externalId") final String externalId, + @QueryParam("displayName") final String displayName, @QueryParam("firstName") final String firstName, + @QueryParam("lastName") final String lastName, @QueryParam("underHierarchy") final String hierarchy) { - final Collection clients = this.clientReadPlatformService.retrieveAllIndividualClients(extraCriteria); - - return this.apiJsonSerializerService.serializeClientDataToJson(prettyPrint, responseParameters, clients); - } + context.authenticatedUser().validateHasReadPermission("CLIENT"); - private String getClientCriteria(String sqlSearch, Integer officeId, - String externalId, String displayName, String firstName, - String lastName, String hierarchy) { + final String extraCriteria = getClientCriteria(sqlSearch, officeId, externalId, displayName, firstName, lastName, hierarchy); - String extraCriteria = ""; + final Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); + final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); - if (sqlSearch != null) { - extraCriteria = " and (" + sqlSearch + ")"; - } + final Collection clients = this.clientReadPlatformService.retrieveAllIndividualClients(extraCriteria); - if (officeId != null) { - extraCriteria += " and office_id = " + officeId; - } - - if (externalId != null) { - extraCriteria += " and external_id like " + ApiParameterHelper.sqlEncodeString(externalId); - } - - if (displayName != null) { - extraCriteria += " and concat(ifnull(firstname, ''), if(firstname > '',' ', '') , ifnull(lastname, '')) like " - + ApiParameterHelper.sqlEncodeString(displayName); - } - - if (firstName != null) { - extraCriteria += " and firstname like " + ApiParameterHelper.sqlEncodeString(firstName); - } - - if (lastName != null) { - extraCriteria += " and lastname like " + ApiParameterHelper.sqlEncodeString(lastName); - } - - if (hierarchy != null) { - extraCriteria += " and o.hierarchy like " + ApiParameterHelper.sqlEncodeString(hierarchy+"%"); - } + return this.apiJsonSerializerService.serializeClientDataToJson(prettyPrint, responseParameters, clients); + } - if (StringUtils.isNotBlank(extraCriteria)) { - extraCriteria = extraCriteria.substring(4); - } + private String getClientCriteria(String sqlSearch, Integer officeId, String externalId, String displayName, String firstName, + String lastName, String hierarchy) { - logger.info("extraCriteria; " + extraCriteria); + String extraCriteria = ""; - return extraCriteria; - } + if (sqlSearch != null) { + extraCriteria = " and (" + sqlSearch + ")"; + } - @GET - @Path("{clientId}") - @Consumes({MediaType.APPLICATION_JSON}) - @Produces({MediaType.APPLICATION_JSON}) - public String retrieveClient( - @PathParam("clientId") final Long clientId, - @Context final UriInfo uriInfo) { + if (officeId != null) { + extraCriteria += " and office_id = " + officeId; + } - context.authenticatedUser().validateHasReadPermission("CLIENT"); - - final Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); - final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); - final boolean template = ApiParameterHelper.template(uriInfo.getQueryParameters()); - final Long makerCheckerId = ApiParameterHelper.makerCheckerId(uriInfo.getQueryParameters()); - - ClientData clientData = this.clientReadPlatformService.retrieveIndividualClient(clientId); - if (template) { - final List allowedOffices = new ArrayList(officeReadPlatformService.retrieveAllOfficesForLookup()); - clientData = ClientData.templateOnTop(clientData, allowedOffices); - } - if (makerCheckerId != null) { - clientData = handleMakerCheckerRequest(clientId, makerCheckerId, clientData); - } - - boolean retrieveChanges = true; - if (retrieveChanges) { - final Collection dataChanges = retrieveAllUnprocessedDataChanges(clientId); - clientData = ClientData.integrateChanges(clientData, clientData.currentChange(), dataChanges); - } + if (externalId != null) { + extraCriteria += " and external_id like " + ApiParameterHelper.sqlEncodeString(externalId); + } - return this.apiJsonSerializerService.serializeClientDataToJson(prettyPrint, responseParameters, clientData); - } + if (displayName != null) { + extraCriteria += " and concat(ifnull(firstname, ''), if(firstname > '',' ', '') , ifnull(lastname, '')) like " + + ApiParameterHelper.sqlEncodeString(displayName); + } - private ClientData handleMakerCheckerRequest(final Long clientId, final Long makerCheckerId, ClientData clientData) { - final CommandSourceData entry = this.commandSourceReadPlatformService.retrieveById(makerCheckerId); - final ClientData currentChange = this.apiDataConversionService.convertInternalJsonFormatToClientDataChange(clientId, entry.json()); - - final Collection dataChanges = retrieveAllUnprocessedDataChanges(clientId); - clientData = ClientData.integrateChanges(clientData, currentChange, dataChanges); - return clientData; - } + if (firstName != null) { + extraCriteria += " and firstname like " + ApiParameterHelper.sqlEncodeString(firstName); + } - private Collection retrieveAllUnprocessedDataChanges(final Long clientId) { - Collection dataChanges = new ArrayList(); - - boolean retrieveChanges = true; - if (retrieveChanges) { - Collection unprocessedChanges = this.commandSourceReadPlatformService.retrieveUnprocessChangesByResourceId("clients", clientId); - for (CommandSourceData commandSourceData : unprocessedChanges) { - ClientData change = this.apiDataConversionService.convertInternalJsonFormatToClientDataChange(clientId, commandSourceData.json()); - dataChanges.add(change); - } - } - - if (dataChanges.isEmpty()) { - dataChanges = null; - } - - return dataChanges; - } + if (lastName != null) { + extraCriteria += " and lastname like " + ApiParameterHelper.sqlEncodeString(lastName); + } - @GET - @Path("template") - @Consumes({MediaType.APPLICATION_JSON}) - @Produces({MediaType.APPLICATION_JSON}) - public String newClientDetails(@Context final UriInfo uriInfo) { + if (hierarchy != null) { + extraCriteria += " and o.hierarchy like " + ApiParameterHelper.sqlEncodeString(hierarchy + "%"); + } - context.authenticatedUser().validateHasReadPermission("CLIENT"); - - final Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); - final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); - final Long makerCheckerId = ApiParameterHelper.makerCheckerId(uriInfo.getQueryParameters()); - - ClientData clientData = this.clientReadPlatformService.retrieveNewClientDetails(); - if (makerCheckerId != null) { - clientData = handleMakerCheckerRequest(null, makerCheckerId, clientData); - } - - return this.apiJsonSerializerService.serializeClientDataToJson(prettyPrint, responseParameters, clientData); - } + if (StringUtils.isNotBlank(extraCriteria)) { + extraCriteria = extraCriteria.substring(4); + } - @POST - @Consumes({MediaType.APPLICATION_JSON}) - @Produces({MediaType.APPLICATION_JSON}) - public String createClient(final String jsonRequestBody) { - - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE", "clients", null, jsonRequestBody); - - return this.apiJsonSerializerService.serializeEntityIdentifier(result); - } + logger.info("extraCriteria; " + extraCriteria); - @PUT - @Path("{clientId}") - @Consumes({MediaType.APPLICATION_JSON}) - @Produces({MediaType.APPLICATION_JSON}) - public String updateClient(@PathParam("clientId") final Long clientId, final String jsonRequestBody) { + return extraCriteria; + } - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", "clients", clientId, jsonRequestBody); - - return this.apiJsonSerializerService.serializeEntityIdentifier(result); - } - - @DELETE - @Path("{clientId}") - @Consumes({MediaType.APPLICATION_JSON}) - @Produces({MediaType.APPLICATION_JSON}) - public String deleteClient(@PathParam("clientId") final Long clientId) { + @GET + @Path("{clientId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveClient(@PathParam("clientId") final Long clientId, @Context final UriInfo uriInfo) { - final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("DELETE", "clients", clientId, "{}"); - - return this.apiJsonSerializerService.serializeEntityIdentifier(result); - } + context.authenticatedUser().validateHasReadPermission("CLIENT"); - @GET - @Path("{clientId}/loans") - @Consumes({MediaType.APPLICATION_JSON}) - @Produces({MediaType.APPLICATION_JSON}) - public String retrieveClientAccount(@PathParam("clientId") final Long clientId, - @Context final UriInfo uriInfo) { + final Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); + final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); + final boolean template = ApiParameterHelper.template(uriInfo.getQueryParameters()); + final Long makerCheckerId = ApiParameterHelper.makerCheckerId(uriInfo.getQueryParameters()); - context.authenticatedUser().validateHasReadPermission("CLIENT"); - - Set typicalResponseParameters = new HashSet( - Arrays.asList("pendingApprovalLoans", "awaitingDisbursalLoans", "openLoans", "closedLoans", - "anyLoanCount", "pendingApprovalLoanCount", "awaitingDisbursalLoanCount", "activeLoanCount", "closedLoanCount", - "pendingApprovalDespositAccountsCount", "pendingApprovalDespositAccounts", "approvedDespositAccountsCount", "approvedDespositAccounts", - "withdrawnByClientDespositAccountsCount","withdrawnByClientDespositAccounts","closedDepositAccountsCount","closedDepositAccounts", - "rejectedDepositAccountsCount","rejectedDepositAccounts","preclosedDepositAccountsCount","preclosedDepositAccounts") - ); - - Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); - if (responseParameters.isEmpty()) { - responseParameters.addAll(typicalResponseParameters); - } - boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); - - ClientAccountSummaryCollectionData clientAccount = this.clientReadPlatformService.retrieveClientAccountDetails(clientId); - - return this.apiJsonSerializerService.serializeClientAccountSummaryCollectionDataToJson(prettyPrint, responseParameters, clientAccount); - } + ClientData clientData = this.clientReadPlatformService.retrieveIndividualClient(clientId); + if (template) { + final List allowedOffices = new ArrayList(officeReadPlatformService.retrieveAllOfficesForLookup()); + clientData = ClientData.templateOnTop(clientData, allowedOffices); + } + if (makerCheckerId != null) { + clientData = handleMakerCheckerRequest(clientId, makerCheckerId, clientData); + } - @GET - @Path("{clientId}/notes") - @Consumes({MediaType.APPLICATION_JSON}) - @Produces({MediaType.APPLICATION_JSON}) - public String retrieveAllClientNotes(@PathParam("clientId") final Long clientId, @Context final UriInfo uriInfo) { + boolean retrieveChanges = true; + if (retrieveChanges) { + final Collection dataChanges = retrieveAllUnprocessedDataChanges(clientId); + clientData = ClientData.integrateChanges(clientData, clientData.currentChange(), dataChanges); + } - context.authenticatedUser().validateHasReadPermission("CLIENTNOTE"); - - Set typicalResponseParameters = new HashSet( - Arrays.asList("id", "clientId", "loanId", "loanTransactionId", "noteType", "note", "createdById", "createdByUsername", - "createdOn", "updatedById", "updatedByUsername", "updatedOn") - ); - - Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); - if (responseParameters.isEmpty()) { - responseParameters.addAll(typicalResponseParameters); - } - boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); - - Collection notes = this.clientReadPlatformService.retrieveAllClientNotes(clientId); - - return this.apiJsonSerializerService.serializeNoteDataToJson(prettyPrint, responseParameters, notes); - } + return this.apiJsonSerializerService.serializeClientDataToJson(prettyPrint, responseParameters, clientData); + } - @POST - @Path("{clientId}/notes") - @Consumes({MediaType.APPLICATION_JSON}) - @Produces({MediaType.APPLICATION_JSON}) - public Response addNewClientNote(@PathParam("clientId") final Long clientId, final String jsonRequestBody) { + private ClientData handleMakerCheckerRequest(final Long clientId, final Long makerCheckerId, ClientData clientData) { + final CommandSourceData entry = this.commandSourceReadPlatformService.retrieveById(makerCheckerId); + final ClientData currentChange = this.apiDataConversionService.convertInternalJsonFormatToClientDataChange(clientId, entry.json()); - NoteCommand command = this.apiDataConversionService.convertJsonToNoteCommand(null, clientId, jsonRequestBody); - - EntityIdentifier identifier = this.clientWritePlatformService.addClientNote(command); + final Collection dataChanges = retrieveAllUnprocessedDataChanges(clientId); + clientData = ClientData.integrateChanges(clientData, currentChange, dataChanges); + return clientData; + } - return Response.ok().entity(identifier).build(); - } + private Collection retrieveAllUnprocessedDataChanges(final Long clientId) { + Collection dataChanges = new ArrayList(); - @GET - @Path("{clientId}/notes/{noteId}") - @Consumes({MediaType.APPLICATION_JSON}) - @Produces({MediaType.APPLICATION_JSON}) - public String retrieveClientNote( - @PathParam("clientId") final Long clientId, - @PathParam("noteId") final Long noteId, - @Context final UriInfo uriInfo) { + boolean retrieveChanges = true; + if (retrieveChanges) { + Collection unprocessedChanges = this.commandSourceReadPlatformService.retrieveUnprocessChangesByResourceId( + "clients", clientId); + for (CommandSourceData commandSourceData : unprocessedChanges) { + ClientData change = this.apiDataConversionService.convertInternalJsonFormatToClientDataChange(clientId, + commandSourceData.json()); + dataChanges.add(change); + } + } - context.authenticatedUser().validateHasReadPermission("CLIENTNOTE"); - - Set typicalResponseParameters = new HashSet( - Arrays.asList("id", "clientId", "loanId", "loanTransactionId", "noteType", "note", "createdById", "createdByUsername", - "createdOn", "updatedById", "updatedByUsername", "updatedOn") - ); - - Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); - if (responseParameters.isEmpty()) { - responseParameters.addAll(typicalResponseParameters); - } - boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); - - NoteData note = this.clientReadPlatformService.retrieveClientNote(clientId, noteId); - - return this.apiJsonSerializerService.serializeNoteDataToJson(prettyPrint, responseParameters, note); - } + if (dataChanges.isEmpty()) { + dataChanges = null; + } - @PUT - @Path("{clientId}/notes/{noteId}") - @Consumes({MediaType.APPLICATION_JSON}) - @Produces({MediaType.APPLICATION_JSON}) - public Response updateClientNote( - @PathParam("clientId") final Long clientId, - @PathParam("noteId") final Long noteId, final String jsonRequestBody) { + return dataChanges; + } - NoteCommand command = this.apiDataConversionService.convertJsonToNoteCommand(noteId, clientId, jsonRequestBody); - - EntityIdentifier identifier = this.clientWritePlatformService.updateNote(command); + @GET + @Path("template") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String newClientDetails(@Context final UriInfo uriInfo) { - return Response.ok().entity(identifier).build(); - } - - /** - * Upload images through multi-part form upload - */ - @POST - @Path("{clientId}/image") - @Consumes({ MediaType.MULTIPART_FORM_DATA }) - @Produces({ MediaType.APPLICATION_JSON }) - public Response addNewClientImage( - @PathParam("clientId") final Long clientId, - @HeaderParam("Content-Length") Long fileSize, - @FormDataParam("file") InputStream inputStream, - @FormDataParam("file") FormDataContentDisposition fileDetails, - @FormDataParam("file") FormDataBodyPart bodyPart) { + context.authenticatedUser().validateHasReadPermission("CLIENT"); - - //TODO: vishwas might need more advances validation (like reading magic number) for handling malicious clients - //and clients not setting mime type - FileUtils.validateClientImageNotEmpty(fileDetails.getFileName()); - FileUtils.validateImageMimeType(bodyPart.getMediaType().toString()); - FileUtils.validateFileSizeWithinPermissibleRange(fileSize, - fileDetails.getFileName(), - ApiConstants.MAX_FILE_UPLOAD_SIZE_IN_MB); - - logger.debug(bodyPart.getMediaType().toString()); + final Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); + final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); + final Long makerCheckerId = ApiParameterHelper.makerCheckerId(uriInfo.getQueryParameters()); - EntityIdentifier entityIdentifier = this.clientWritePlatformService - .saveOrUpdateClientImage(clientId, fileDetails.getFileName(), - inputStream); + ClientData clientData = this.clientReadPlatformService.retrieveNewClientDetails(); + if (makerCheckerId != null) { + clientData = handleMakerCheckerRequest(null, makerCheckerId, clientData); + } - return Response.ok().entity(entityIdentifier).build(); - } - + return this.apiJsonSerializerService.serializeClientDataToJson(prettyPrint, responseParameters, clientData); + } - /** - * Upload image as a Data URL (essentially a base64 encoded stream) - */ - @POST - @Path("{clientId}/image") - @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) - public Response addNewClientImage( - @PathParam("clientId") final Long clientId, - final String jsonRequestBody) { + @POST + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String createClient(final String jsonRequestBody) { - Base64EncodedImage base64EncodedImage = FileUtils - .extractImageFromDataURL(jsonRequestBody); + final EntityIdentifier result = this.commandsSourceWritePlatformService + .logCommandSource("CREATE", "clients", null, jsonRequestBody); - EntityIdentifier entityIdentifier = this.clientWritePlatformService - .saveOrUpdateClientImage(clientId, base64EncodedImage); + return this.apiJsonSerializerService.serializeEntityIdentifier(result); + } - return Response.ok().entity(entityIdentifier).build(); - } + @PUT + @Path("{clientId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String updateClient(@PathParam("clientId") final Long clientId, final String jsonRequestBody) { - /** - * Returns a base 64 encoded client image - */ - @GET - @Path("{clientId}/image") - @Consumes({MediaType.APPLICATION_JSON}) - @Produces({MediaType.APPLICATION_JSON}) - public Response retrieveClientImage( - @PathParam("clientId") final Long clientId) { + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", "clients", clientId, + jsonRequestBody); - context.authenticatedUser().validateHasReadPermission("CLIENTIMAGE"); - - final ClientData clientData = this.clientReadPlatformService.retrieveIndividualClient(clientId); + return this.apiJsonSerializerService.serializeEntityIdentifier(result); + } - if (clientData.imageKeyDoesNotExist()) { - throw new ImageNotFoundException("clients", clientId); - } - return Response.ok().entity(Base64.encodeFromFile(clientData.imageKey())).build(); - } - - /** - * This method is added only for consistency with other URL patterns - * and for maintaining consistency of usage of the HTTP "verb" - * at the client side - */ - @PUT - @Path("{clientId}/image") - @Consumes({ MediaType.MULTIPART_FORM_DATA }) - @Produces({ MediaType.APPLICATION_JSON }) - public Response updateClientImage( - @PathParam("clientId") final Long clientId, - @HeaderParam("Content-Length") Long fileSize, - @FormDataParam("file") InputStream inputStream, - @FormDataParam("file") FormDataContentDisposition fileDetails, - @FormDataParam("file") FormDataBodyPart bodyPart) { - return addNewClientImage(clientId, fileSize, inputStream, fileDetails, - bodyPart); - } - - @DELETE - @Path("{clientId}/image") - @Consumes({MediaType.APPLICATION_JSON}) - @Produces({MediaType.APPLICATION_JSON}) - public Response deleteClientImage(@PathParam("clientId") final Long clientId) { - this.clientWritePlatformService.deleteClientImage(clientId); - return Response.ok(new EntityIdentifier(clientId)).build(); - } - - - /** - * This method is added only for consistency with other URL patterns - * and for maintaining consistency of usage of the HTTP "verb" - * at the client side - * - * Upload image as a Data URL (essentially a base64 encoded stream) - */ - @PUT - @Path("{clientId}/image") - @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) - public Response updateClientImage( - @PathParam("clientId") final Long clientId, - final String jsonRequestBody) { - return addNewClientImage(clientId, jsonRequestBody); - } + @DELETE + @Path("{clientId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String deleteClient(@PathParam("clientId") final Long clientId) { + + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("DELETE", "clients", clientId, "{}"); + + return this.apiJsonSerializerService.serializeEntityIdentifier(result); + } + + @GET + @Path("{clientId}/loans") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveClientAccount(@PathParam("clientId") final Long clientId, @Context final UriInfo uriInfo) { + + context.authenticatedUser().validateHasReadPermission("CLIENT"); + + Set typicalResponseParameters = new HashSet(Arrays.asList("pendingApprovalLoans", "awaitingDisbursalLoans", + "openLoans", "closedLoans", "anyLoanCount", "pendingApprovalLoanCount", "awaitingDisbursalLoanCount", "activeLoanCount", + "closedLoanCount", "pendingApprovalDespositAccountsCount", "pendingApprovalDespositAccounts", + "approvedDespositAccountsCount", "approvedDespositAccounts", "withdrawnByClientDespositAccountsCount", + "withdrawnByClientDespositAccounts", "closedDepositAccountsCount", "closedDepositAccounts", "rejectedDepositAccountsCount", + "rejectedDepositAccounts", "preclosedDepositAccountsCount", "preclosedDepositAccounts")); + + Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); + if (responseParameters.isEmpty()) { + responseParameters.addAll(typicalResponseParameters); + } + boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); + + ClientAccountSummaryCollectionData clientAccount = this.clientReadPlatformService.retrieveClientAccountDetails(clientId); + + return this.apiJsonSerializerService.serializeClientAccountSummaryCollectionDataToJson(prettyPrint, responseParameters, + clientAccount); + } + + @GET + @Path("{clientId}/notes") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveAllClientNotes(@PathParam("clientId") final Long clientId, @Context final UriInfo uriInfo) { + + context.authenticatedUser().validateHasReadPermission("CLIENTNOTE"); + + Set typicalResponseParameters = new HashSet(Arrays.asList("id", "clientId", "loanId", "loanTransactionId", + "noteType", "note", "createdById", "createdByUsername", "createdOn", "updatedById", "updatedByUsername", "updatedOn")); + + Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); + if (responseParameters.isEmpty()) { + responseParameters.addAll(typicalResponseParameters); + } + boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); + + Collection notes = this.clientReadPlatformService.retrieveAllClientNotes(clientId); + + return this.apiJsonSerializerService.serializeNoteDataToJson(prettyPrint, responseParameters, notes); + } + + @POST + @Path("{clientId}/notes") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response addNewClientNote(@PathParam("clientId") final Long clientId, final String jsonRequestBody) { + + NoteCommand command = this.apiDataConversionService.convertJsonToNoteCommand(null, clientId, jsonRequestBody); + + EntityIdentifier identifier = this.clientWritePlatformService.addClientNote(command); + + return Response.ok().entity(identifier).build(); + } + + @GET + @Path("{clientId}/notes/{noteId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveClientNote(@PathParam("clientId") final Long clientId, @PathParam("noteId") final Long noteId, + @Context final UriInfo uriInfo) { + + context.authenticatedUser().validateHasReadPermission("CLIENTNOTE"); + + Set typicalResponseParameters = new HashSet(Arrays.asList("id", "clientId", "loanId", "loanTransactionId", + "noteType", "note", "createdById", "createdByUsername", "createdOn", "updatedById", "updatedByUsername", "updatedOn")); + + Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); + if (responseParameters.isEmpty()) { + responseParameters.addAll(typicalResponseParameters); + } + boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); + + NoteData note = this.clientReadPlatformService.retrieveClientNote(clientId, noteId); + + return this.apiJsonSerializerService.serializeNoteDataToJson(prettyPrint, responseParameters, note); + } + + @PUT + @Path("{clientId}/notes/{noteId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response updateClientNote(@PathParam("clientId") final Long clientId, @PathParam("noteId") final Long noteId, + final String jsonRequestBody) { + + NoteCommand command = this.apiDataConversionService.convertJsonToNoteCommand(noteId, clientId, jsonRequestBody); + + EntityIdentifier identifier = this.clientWritePlatformService.updateNote(command); + + return Response.ok().entity(identifier).build(); + } + + /** + * Upload images through multi-part form upload + */ + @POST + @Path("{clientId}/image") + @Consumes({ MediaType.MULTIPART_FORM_DATA }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response addNewClientImage(@PathParam("clientId") final Long clientId, @HeaderParam("Content-Length") Long fileSize, + @FormDataParam("file") InputStream inputStream, @FormDataParam("file") FormDataContentDisposition fileDetails, + @FormDataParam("file") FormDataBodyPart bodyPart) { + + // TODO: vishwas might need more advances validation (like reading magic + // number) for handling malicious clients + // and clients not setting mime type + FileUtils.validateClientImageNotEmpty(fileDetails.getFileName()); + FileUtils.validateImageMimeType(bodyPart.getMediaType().toString()); + FileUtils.validateFileSizeWithinPermissibleRange(fileSize, fileDetails.getFileName(), ApiConstants.MAX_FILE_UPLOAD_SIZE_IN_MB); + + logger.debug(bodyPart.getMediaType().toString()); + + EntityIdentifier entityIdentifier = this.clientWritePlatformService.saveOrUpdateClientImage(clientId, fileDetails.getFileName(), + inputStream); + + return Response.ok().entity(entityIdentifier).build(); + } + + /** + * Upload image as a Data URL (essentially a base64 encoded stream) + */ + @POST + @Path("{clientId}/image") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response addNewClientImage(@PathParam("clientId") final Long clientId, final String jsonRequestBody) { + + Base64EncodedImage base64EncodedImage = FileUtils.extractImageFromDataURL(jsonRequestBody); + + EntityIdentifier entityIdentifier = this.clientWritePlatformService.saveOrUpdateClientImage(clientId, base64EncodedImage); + + return Response.ok().entity(entityIdentifier).build(); + } + + /** + * Returns a base 64 encoded client image + */ + @GET + @Path("{clientId}/image") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response retrieveClientImage(@PathParam("clientId") final Long clientId) { + + context.authenticatedUser().validateHasReadPermission("CLIENTIMAGE"); + + final ClientData clientData = this.clientReadPlatformService.retrieveIndividualClient(clientId); + + if (clientData.imageKeyDoesNotExist()) { throw new ImageNotFoundException("clients", clientId); } + return Response.ok().entity(Base64.encodeFromFile(clientData.imageKey())).build(); + } + + /** + * This method is added only for consistency with other URL patterns and for + * maintaining consistency of usage of the HTTP "verb" at the client side + */ + @PUT + @Path("{clientId}/image") + @Consumes({ MediaType.MULTIPART_FORM_DATA }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response updateClientImage(@PathParam("clientId") final Long clientId, @HeaderParam("Content-Length") Long fileSize, + @FormDataParam("file") InputStream inputStream, @FormDataParam("file") FormDataContentDisposition fileDetails, + @FormDataParam("file") FormDataBodyPart bodyPart) { + return addNewClientImage(clientId, fileSize, inputStream, fileDetails, bodyPart); + } + + @DELETE + @Path("{clientId}/image") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response deleteClientImage(@PathParam("clientId") final Long clientId) { + this.clientWritePlatformService.deleteClientImage(clientId); + return Response.ok(new EntityIdentifier(clientId)).build(); + } + + /** + * This method is added only for consistency with other URL patterns and for + * maintaining consistency of usage of the HTTP "verb" at the client side + * + * Upload image as a Data URL (essentially a base64 encoded stream) + */ + @PUT + @Path("{clientId}/image") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response updateClientImage(@PathParam("clientId") final Long clientId, final String jsonRequestBody) { + return addNewClientImage(clientId, jsonRequestBody); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/RolesApiResource.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/RolesApiResource.java index 6f484b5a1..4eb8c09c8 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/RolesApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/RolesApiResource.java @@ -25,6 +25,7 @@ import org.mifosng.platform.api.data.RolePermissionsData; import org.mifosng.platform.api.infrastructure.PortfolioApiDataConversionService; import org.mifosng.platform.api.infrastructure.PortfolioApiJsonSerializerService; import org.mifosng.platform.infrastructure.api.ApiParameterHelper; +import org.mifosng.platform.makerchecker.service.PortfolioCommandSourceWritePlatformService; import org.mifosng.platform.security.PlatformSecurityContext; import org.mifosng.platform.user.service.PermissionReadPlatformService; import org.mifosng.platform.user.service.RoleReadPlatformService; @@ -52,6 +53,9 @@ public class RolesApiResource { @Autowired private PortfolioApiJsonSerializerService apiJsonSerializerService; + + @Autowired + private PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; @Autowired private PlatformSecurityContext context; @@ -77,7 +81,7 @@ public class RolesApiResource { @Path("template") @Consumes({MediaType.APPLICATION_JSON}) @Produces({MediaType.APPLICATION_JSON}) - public String retrieveNewRoleDetails(@Context final UriInfo uriInfo) { + public String retrieveRoleTemplate(@Context final UriInfo uriInfo) { context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions); @@ -94,13 +98,11 @@ public class RolesApiResource { @POST @Consumes({MediaType.APPLICATION_JSON}) @Produces({MediaType.APPLICATION_JSON}) - public String createRole(final String jsonRequestBody) { + public String createRole(final String apiRequestBodyAsJson) { + + final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE", "roles", null, apiRequestBodyAsJson); - final RoleCommand command = this.apiDataConversionService.convertJsonToRoleCommand(null, jsonRequestBody); - - final Long roleId = this.roleWritePlatformService.createRole(command); - - return this.apiJsonSerializerService.serializeEntityIdentifier(new EntityIdentifier(roleId)); + return this.apiJsonSerializerService.serializeEntityIdentifier(result); } // TODO - General thing to fix about REST API is if use partial response @@ -140,7 +142,7 @@ public class RolesApiResource { @Produces({MediaType.APPLICATION_JSON}) public String updateRole(@PathParam("roleId") final Long roleId, final String jsonRequestBody) { - final RoleCommand command = this.apiDataConversionService.convertJsonToRoleCommand(roleId, jsonRequestBody); + final RoleCommand command = this.apiDataConversionService.convertApiRequestJsonToRoleCommand(roleId, jsonRequestBody); this.roleWritePlatformService.updateRole(command); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/ClientCommand.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/ClientCommand.java index a846f459a..ede9caf5b 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/ClientCommand.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/ClientCommand.java @@ -9,92 +9,85 @@ import org.joda.time.LocalDate; */ public class ClientCommand { - private final String externalId; - private final String firstname; - private final String lastname; - private final String clientOrBusinessName; - private final Long officeId; - private final LocalDate joiningDate; + private final String externalId; + private final String firstname; + private final String lastname; + private final String clientOrBusinessName; + private final Long officeId; + private final LocalDate joiningDate; - // made transient as dont want them to be serialized/converted to JSON - private final transient Long id; - private final transient boolean makerCheckerApproval; - private final transient Set parametersPassedInRequest; - - public ClientCommand( - final Set modifiedParameters, - final Long id, - final String externalId, - final String firstname, - final String lastname, - final String clientOrBusinessName, - final Long officeId, - final LocalDate joiningDate, - final boolean makerCheckerApproval) { - this.parametersPassedInRequest = modifiedParameters; - this.id = id; - this.externalId = externalId; - this.firstname = firstname; - this.lastname = lastname; - this.clientOrBusinessName = clientOrBusinessName; - this.officeId = officeId; - this.joiningDate = joiningDate; - this.makerCheckerApproval = makerCheckerApproval; - } + // made transient as dont want them to be serialized/converted to JSON + private final transient Long id; + private final transient boolean makerCheckerApproval; + private final transient Set parametersPassedInRequest; - public Long getId() { - return id; - } + public ClientCommand(final Set modifiedParameters, final Long id, final String externalId, final String firstname, + final String lastname, final String clientOrBusinessName, final Long officeId, final LocalDate joiningDate, + final boolean makerCheckerApproval) { + this.parametersPassedInRequest = modifiedParameters; + this.id = id; + this.externalId = externalId; + this.firstname = firstname; + this.lastname = lastname; + this.clientOrBusinessName = clientOrBusinessName; + this.officeId = officeId; + this.joiningDate = joiningDate; + this.makerCheckerApproval = makerCheckerApproval; + } - public String getExternalId() { - return externalId; - } + public Long getId() { + return id; + } - public String getFirstname() { - return firstname; - } + public String getExternalId() { + return externalId; + } - public String getLastname() { - return lastname; - } + public String getFirstname() { + return firstname; + } - public String getClientOrBusinessName() { - return clientOrBusinessName; - } + public String getLastname() { + return lastname; + } - public Long getOfficeId() { - return officeId; - } + public String getClientOrBusinessName() { + return clientOrBusinessName; + } - public LocalDate getJoiningDate() { - return joiningDate; - } - - public boolean isFirstnameChanged() { - return this.parametersPassedInRequest.contains("firstname"); - } - - public boolean isLastnameChanged() { - return this.parametersPassedInRequest.contains("lastname"); - } - - public boolean isClientOrBusinessNameChanged() { - return this.parametersPassedInRequest.contains("clientOrBusinessName"); - } - - public boolean isExternalIdChanged() { - return this.parametersPassedInRequest.contains("externalId"); - } - - public boolean isJoiningDateChanged() { - return this.parametersPassedInRequest.contains("joiningDate"); - } - - public boolean isOfficeChanged() { - return this.parametersPassedInRequest.contains("officeId"); - } + public Long getOfficeId() { + return officeId; + } - public boolean isApprovedByChecker() { - return this.makerCheckerApproval; - } + public LocalDate getJoiningDate() { + return joiningDate; + } + + public boolean isFirstnameChanged() { + return this.parametersPassedInRequest.contains("firstname"); + } + + public boolean isLastnameChanged() { + return this.parametersPassedInRequest.contains("lastname"); + } + + public boolean isClientOrBusinessNameChanged() { + return this.parametersPassedInRequest.contains("clientOrBusinessName"); + } + + public boolean isExternalIdChanged() { + return this.parametersPassedInRequest.contains("externalId"); + } + + public boolean isJoiningDateChanged() { + return this.parametersPassedInRequest.contains("joiningDate"); + } + + public boolean isOfficeChanged() { + return this.parametersPassedInRequest.contains("officeId"); + } + + public boolean isApprovedByChecker() { + return this.makerCheckerApproval; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/RoleCommand.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/RoleCommand.java index 0779957d4..5496fe8e3 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/RoleCommand.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/RoleCommand.java @@ -4,17 +4,26 @@ import java.util.Set; /** * Immutable command for creating or updating details of a role. + * + *

Fields that are transient are intended not to be serialized into JSON.

*/ public class RoleCommand { - private final Long id; + private final transient Long id; private final String name; private final String description; - private final Set modifiedParameters; + private final transient boolean makerCheckerApproval; + private final transient Set modifiedParameters; - public RoleCommand(Set modifiedParameters, final Long id, final String name, final String description) { + public RoleCommand( + final Set modifiedParameters, + final boolean makerCheckerApproval, + final Long id, + final String name, + final String description) { this.modifiedParameters = modifiedParameters; + this.makerCheckerApproval = makerCheckerApproval; this.id = id; this.name = name; this.description = description; @@ -39,4 +48,8 @@ public class RoleCommand { public boolean isDescriptionChanged() { return this.modifiedParameters.contains("description"); } + + public boolean isApprovedByChecker() { + return this.makerCheckerApproval; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioApiDataConversionService.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioApiDataConversionService.java index 395f580ad..8b1a56061 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioApiDataConversionService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioApiDataConversionService.java @@ -40,7 +40,7 @@ public interface PortfolioApiDataConversionService { OfficeCommand convertJsonToOfficeCommand(Long resourceIdentifier, String json); - RoleCommand convertJsonToRoleCommand(Long resourceIdentifier, String json); + RoleCommand convertApiRequestJsonToRoleCommand(Long resourceIdentifier, String json); RolePermissionCommand convertJsonToRolePermissionCommand(Long roleId, String jsonRequestBody); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioApiDataConversionServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioApiDataConversionServiceImpl.java index 7eae7e78d..3c08f59b5 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioApiDataConversionServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioApiDataConversionServiceImpl.java @@ -53,6 +53,7 @@ import org.mifosng.platform.exceptions.PlatformApiDataValidationException; import org.mifosng.platform.infrastructure.api.JsonParserHelper; import org.mifosng.platform.infrastructure.errorhandling.InvalidJsonException; import org.mifosng.platform.infrastructure.errorhandling.UnsupportedParameterException; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.format.number.NumberFormatter; import org.springframework.stereotype.Service; @@ -66,9 +67,20 @@ import com.google.gson.reflect.TypeToken; @Service public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataConversionService { + /** + * Used in places where the support json of the api request is not any + * different to that of the json of a serialized command object. + */ + private final PortfolioCommandDeserializerService portfolioCommandDeserializerService; + + /** + * Google-gson class for converting to and from json. + */ private final Gson gsonConverter; - public PortfolioApiDataConversionServiceImpl() { + @Autowired + public PortfolioApiDataConversionServiceImpl(final PortfolioCommandDeserializerService portfolioCommandDeserializerService) { + this.portfolioCommandDeserializerService = portfolioCommandDeserializerService; gsonConverter = new Gson(); } @@ -229,22 +241,20 @@ public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataCo } @Override - public RoleCommand convertJsonToRoleCommand(final Long resourceIdentifier, final String json) { + public RoleCommand convertApiRequestJsonToRoleCommand(final Long resourceIdentifier, final String json) { if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } - Type typeOfMap = new TypeToken>() {}.getType(); - Map requestMap = gsonConverter.fromJson(json, typeOfMap); + final Type typeOfMap = new TypeToken>() {}.getType(); + final Map requestMap = gsonConverter.fromJson(json, typeOfMap); - Set supportedParams = new HashSet(Arrays.asList("name", "description", "permissions")); + final Set supportedParams = new HashSet(Arrays.asList("id", "name", "description")); checkForUnsupportedParameters(requestMap, supportedParams); - Set modifiedParameters = new HashSet(); - - String name = extractStringParameter("name", requestMap, modifiedParameters); - String description = extractStringParameter("description", requestMap, modifiedParameters); - - return new RoleCommand(modifiedParameters, resourceIdentifier, name, description); + // no difference between the api json and internal command + // representation of json so reuse this code to de-serialize into + // command object + return this.portfolioCommandDeserializerService.deserializeRoleCommand(resourceIdentifier, json, false); } @Override diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioApiJsonSerializerService.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioApiJsonSerializerService.java index 6edc533c1..f51a20307 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioApiJsonSerializerService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioApiJsonSerializerService.java @@ -13,6 +13,7 @@ import org.mifosng.platform.api.data.ClientAccountSummaryCollectionData; import org.mifosng.platform.api.data.ClientData; import org.mifosng.platform.api.data.ClientIdentifierData; import org.mifosng.platform.api.data.CodeData; +import org.mifosng.platform.api.data.CommandSourceData; import org.mifosng.platform.api.data.ConfigurationData; import org.mifosng.platform.api.data.DatatableData; import org.mifosng.platform.api.data.DepositAccountData; @@ -30,7 +31,6 @@ import org.mifosng.platform.api.data.LoanProductData; import org.mifosng.platform.api.data.LoanReassignmentData; import org.mifosng.platform.api.data.LoanScheduleData; import org.mifosng.platform.api.data.LoanTransactionData; -import org.mifosng.platform.api.data.CommandSourceData; import org.mifosng.platform.api.data.NoteData; import org.mifosng.platform.api.data.OfficeData; import org.mifosng.platform.api.data.OfficeTransactionData; @@ -157,9 +157,9 @@ public interface PortfolioApiJsonSerializerService { String serializeSavingAccountsDataToJson(boolean prettyPrint, Set responseParameters, Collection accounts); - // TODO - KW - might devide serialize up into portfolio and account to reduce interface - String serializeChartOfAccountDataToJson(boolean prettyPrint, Set responseParameters, ChartOfAccountsData chartOfAccounts); - - String serializeGuarantorDataToJson(boolean prettyPrint,Set responseParameters, GuarantorData guarantorData); - + String serializeGuarantorDataToJson(boolean prettyPrint, Set responseParameters, GuarantorData guarantorData); + + // TODO - KW - might devide serialize up into portfolio and account to + // reduce interface + String serializeChartOfAccountDataToJson(boolean prettyPrint, Set responseParameters, ChartOfAccountsData chartOfAccounts); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandDeerializerServiceGoogleGson.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandDeerializerServiceGoogleGson.java new file mode 100644 index 000000000..7796c6046 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandDeerializerServiceGoogleGson.java @@ -0,0 +1,42 @@ +package org.mifosng.platform.api.infrastructure; + +import java.util.HashSet; +import java.util.Set; + +import org.apache.commons.lang.StringUtils; +import org.mifosng.platform.api.commands.RoleCommand; +import org.mifosng.platform.infrastructure.api.JsonParserHelper; +import org.mifosng.platform.infrastructure.errorhandling.InvalidJsonException; +import org.springframework.stereotype.Service; + +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; + +/** + * Implementation of {@link PortfolioCommandDeserializerService} that de-serializes + * JSON of commands into Java object representation using google-gson. + */ +@Service +public class PortfolioCommandDeerializerServiceGoogleGson implements PortfolioCommandDeserializerService { + + private final JsonParser parser; + + public PortfolioCommandDeerializerServiceGoogleGson() { + parser = new JsonParser(); + } + + @Override + public RoleCommand deserializeRoleCommand(final Long roleId, final String commandAsJson, final boolean makerCheckerApproval) { + if (StringUtils.isBlank(commandAsJson)) { throw new InvalidJsonException(); } + + final JsonParserHelper helper = new JsonParserHelper(); + final JsonElement element = parser.parse(commandAsJson); + + final Set parametersPassedInRequest = new HashSet(); + + final String name = helper.extractStringNamed("name", element, parametersPassedInRequest); + final String description = helper.extractStringNamed("description", element, parametersPassedInRequest); + + return new RoleCommand(parametersPassedInRequest, makerCheckerApproval, roleId, name, description); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandDeserializerService.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandDeserializerService.java new file mode 100644 index 000000000..a9d4c0f29 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandDeserializerService.java @@ -0,0 +1,18 @@ +package org.mifosng.platform.api.infrastructure; + +import org.mifosng.platform.api.commands.RoleCommand; + +/** + * Service for de-serializing JSON for a command into the platforms internal + * Java object representation of the command. + * + *

+ * Known implementations: + *

+ * + * @see PortfolioCommandDeerializerServiceGoogleGson + */ +public interface PortfolioCommandDeserializerService { + + RoleCommand deserializeRoleCommand(Long roleId, String commandAsJson, boolean makerCheckerApproval); +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandSerializerService.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandSerializerService.java new file mode 100644 index 000000000..a6e1bea19 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandSerializerService.java @@ -0,0 +1,14 @@ +package org.mifosng.platform.api.infrastructure; + +import org.mifosng.platform.api.commands.RoleCommand; + +/** + * Service for serializing commands into another format. + * + *

Known implementations:

+ * @see PortfolioCommandSerializerServiceJson + */ +public interface PortfolioCommandSerializerService { + + String serializeRoleCommandToJson(RoleCommand command); +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandSerializerServiceJson.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandSerializerServiceJson.java new file mode 100644 index 000000000..4b689b63e --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandSerializerServiceJson.java @@ -0,0 +1,32 @@ +package org.mifosng.platform.api.infrastructure; + +import java.util.HashSet; + +import org.mifosng.platform.api.commands.RoleCommand; +import org.mifosng.platform.infrastructure.api.GoogleGsonSerializerHelper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.google.gson.Gson; + +/** + * Implementation of {@link PortfolioCommandSerializerService} that serializes + * the commands into JSON using google-gson. + */ +@Service +public class PortfolioCommandSerializerServiceJson implements PortfolioCommandSerializerService { + + private final GoogleGsonSerializerHelper helper; + + @Autowired + public PortfolioCommandSerializerServiceJson(final GoogleGsonSerializerHelper helper) { + this.helper = helper; + } + + @Override + public String serializeRoleCommandToJson(final RoleCommand command) { + final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(new HashSet(), false, + new HashSet()); + return helper.serializedJsonFrom(gsonDeserializer, command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/infrastructure/api/JsonParserHelper.java b/mifosng-provider/src/main/java/org/mifosng/platform/infrastructure/api/JsonParserHelper.java index 276769923..a574f44cc 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/infrastructure/api/JsonParserHelper.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/infrastructure/api/JsonParserHelper.java @@ -27,522 +27,424 @@ import com.google.gson.JsonPrimitive; * Helper class to extract values of json named attributes. */ public class JsonParserHelper { - - public Boolean extractBooleanNamed(final String parameterName, final JsonElement element, final Set requestParamatersDetected) { - Boolean value = null; - if (element.isJsonObject()) { - JsonObject object = element.getAsJsonObject(); - if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) { - requestParamatersDetected.add(parameterName); - - JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive(); - value = primitive.getAsBoolean(); - } - } - return value; - } - public Long extractLongNamed(final String parameterName, - final JsonElement element, final Set parametersPassedInRequest) { - Long longValue = null; - if (element.isJsonObject()) { - JsonObject object = element.getAsJsonObject(); - if (object.has(parameterName) - && object.get(parameterName).isJsonPrimitive()) { - parametersPassedInRequest.add(parameterName); - JsonPrimitive primitive = object.get(parameterName) - .getAsJsonPrimitive(); - final String stringValue = primitive.getAsString(); - if (StringUtils.isNotBlank(stringValue)) { - longValue = Long.valueOf(stringValue); - } - } - } - return longValue; - } + public Boolean extractBooleanNamed(final String parameterName, final JsonElement element, final Set requestParamatersDetected) { + Boolean value = null; + if (element.isJsonObject()) { + JsonObject object = element.getAsJsonObject(); + if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) { + requestParamatersDetected.add(parameterName); - public String extractStringNamed(final String parameterName, final JsonElement element, final Set parametersPassedInRequest) { - String stringValue = null; - if (element.isJsonObject()) { - JsonObject object = element.getAsJsonObject(); - if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) { - parametersPassedInRequest.add(parameterName); - final JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive(); - final String valueAsString = primitive.getAsString(); - if (StringUtils.isNotBlank(valueAsString)) { - stringValue = valueAsString; - } - } - } - return stringValue; - } + JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive(); + value = primitive.getAsBoolean(); + } + } + return value; + } - public BigDecimal extractBigDecimalNamed( - final String parameterName, - final JsonElement element, - final Set modifiedParameters) { - BigDecimal value = null; - if (element.isJsonObject()) { - final JsonObject object = element.getAsJsonObject(); - final Locale locale = extractLocaleValue(object); - value = extractBigDecimalNamed(parameterName, object, locale, modifiedParameters); - } - return value; - } - - public BigDecimal extractBigDecimalNamed( - final String parameterName, - final JsonObject element, - final Locale locale, - final Set modifiedParameters) { - BigDecimal value = null; - if (element.isJsonObject()) { - JsonObject object = element.getAsJsonObject(); - if (object.has(parameterName) - && object.get(parameterName).isJsonPrimitive()) { - modifiedParameters.add(parameterName); - JsonPrimitive primitive = object.get(parameterName) - .getAsJsonPrimitive(); - String valueAsString = primitive.getAsString(); - if (StringUtils.isNotBlank(valueAsString)) { - value = convertFrom(valueAsString, parameterName, locale); - } - } - } - return value; - } + public Long extractLongNamed(final String parameterName, final JsonElement element, final Set parametersPassedInRequest) { + Long longValue = null; + if (element.isJsonObject()) { + JsonObject object = element.getAsJsonObject(); + if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) { + parametersPassedInRequest.add(parameterName); + JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive(); + final String stringValue = primitive.getAsString(); + if (StringUtils.isNotBlank(stringValue)) { + longValue = Long.valueOf(stringValue); + } + } + } + return longValue; + } - public Integer extractIntegerNamed( - final String parameterName, - final JsonElement element, - final Set modifiedParameters) { - Integer value = null; - if (element.isJsonObject()) { - final JsonObject object = element.getAsJsonObject(); - final Locale locale = extractLocaleValue(object); - value = extractIntegerNamed(parameterName, object, locale, modifiedParameters); - } - return value; - } - - public Integer extractIntegerNamed( - final String parameterName, - final JsonElement element, - final Locale locale, - final Set modifiedParameters) { - Integer value = null; - if (element.isJsonObject()) { - final JsonObject object = element.getAsJsonObject(); - if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) { - modifiedParameters.add(parameterName); - JsonPrimitive primitive = object.get(parameterName) - .getAsJsonPrimitive(); - String valueAsString = primitive.getAsString(); - if (StringUtils.isNotBlank(valueAsString)) { - value = convertToInteger(valueAsString, parameterName, locale); - } - } - } - return value; - } - - public String extractDateFormatParameter(final JsonObject element) { - String value = null; - if (element.isJsonObject()) { - JsonObject object = element.getAsJsonObject(); + public String extractStringNamed(final String parameterName, final JsonElement element, final Set parametersPassedInRequest) { + String stringValue = null; + if (element.isJsonObject()) { + JsonObject object = element.getAsJsonObject(); + if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) { + parametersPassedInRequest.add(parameterName); + final JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive(); + final String valueAsString = primitive.getAsString(); + if (StringUtils.isNotBlank(valueAsString)) { + stringValue = valueAsString; + } + } + } + return stringValue; + } - final String dateFormatParameter = "dateFormat"; - if (object.has(dateFormatParameter) - && object.get(dateFormatParameter).isJsonPrimitive()) { - final JsonPrimitive primitive = object.get(dateFormatParameter).getAsJsonPrimitive(); - value = primitive.getAsString(); - } - } - return value; - } - - public Locale extractLocaleParameter(final JsonObject element) { - Locale clientApplicationLocale = null; - if (element.isJsonObject()) { - JsonObject object = element.getAsJsonObject(); - - String locale = null; - final String localeParameter = "locale"; - if (object.has(localeParameter) - && object.get(localeParameter).isJsonPrimitive()) { - final JsonPrimitive primitive = object.get(localeParameter).getAsJsonPrimitive(); - locale = primitive.getAsString(); - clientApplicationLocale = localeFromString(locale); - } - } - return clientApplicationLocale; - } - - /** - * Used with the local date is in array format - */ - public LocalDate extractLocalDateAsArrayNamed(final String parameterName, final JsonElement element, final Set parametersPassedInCommand) { - LocalDate value = null; - if (element.isJsonObject()) { - JsonObject object = element.getAsJsonObject(); + public BigDecimal extractBigDecimalNamed(final String parameterName, final JsonElement element, final Set modifiedParameters) { + BigDecimal value = null; + if (element.isJsonObject()) { + final JsonObject object = element.getAsJsonObject(); + final Locale locale = extractLocaleValue(object); + value = extractBigDecimalNamed(parameterName, object, locale, modifiedParameters); + } + return value; + } - if (object.has(parameterName) && object.get(parameterName).isJsonArray()) { - - parametersPassedInCommand.add(parameterName); + public BigDecimal extractBigDecimalNamed(final String parameterName, final JsonObject element, final Locale locale, + final Set modifiedParameters) { + BigDecimal value = null; + if (element.isJsonObject()) { + JsonObject object = element.getAsJsonObject(); + if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) { + modifiedParameters.add(parameterName); + JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive(); + String valueAsString = primitive.getAsString(); + if (StringUtils.isNotBlank(valueAsString)) { + value = convertFrom(valueAsString, parameterName, locale); + } + } + } + return value; + } - - final JsonArray dateArray = object.get(parameterName).getAsJsonArray(); - - Integer year = dateArray.get(0).getAsInt(); - Integer month = dateArray.get(1).getAsInt(); - Integer day = dateArray.get(2).getAsInt(); - - value = new LocalDate().withYearOfEra(year).withMonthOfYear(month).withDayOfMonth(day); - } + public Integer extractIntegerNamed(final String parameterName, final JsonElement element, final Set modifiedParameters) { + Integer value = null; + if (element.isJsonObject()) { + final JsonObject object = element.getAsJsonObject(); + final Locale locale = extractLocaleValue(object); + value = extractIntegerNamed(parameterName, object, locale, modifiedParameters); + } + return value; + } - } - return value; - } + public Integer extractIntegerNamed(final String parameterName, final JsonElement element, final Locale locale, + final Set modifiedParameters) { + Integer value = null; + if (element.isJsonObject()) { + final JsonObject object = element.getAsJsonObject(); + if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) { + modifiedParameters.add(parameterName); + JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive(); + String valueAsString = primitive.getAsString(); + if (StringUtils.isNotBlank(valueAsString)) { + value = convertToInteger(valueAsString, parameterName, locale); + } + } + } + return value; + } - public LocalDate extractLocalDateNamed( - final String parameterName, - final JsonElement element, - final Set parametersPassedInCommand) { + public String extractDateFormatParameter(final JsonObject element) { + String value = null; + if (element.isJsonObject()) { + JsonObject object = element.getAsJsonObject(); - LocalDate value = null; - - if (element.isJsonObject()) { - JsonObject object = element.getAsJsonObject(); + final String dateFormatParameter = "dateFormat"; + if (object.has(dateFormatParameter) && object.get(dateFormatParameter).isJsonPrimitive()) { + final JsonPrimitive primitive = object.get(dateFormatParameter).getAsJsonPrimitive(); + value = primitive.getAsString(); + } + } + return value; + } - final String dateFormat = extractDateFormatParameter(object); - final Locale clientApplicationLocale = extractLocaleParameter(object); - value = extractLocalDateNamed(parameterName, object, dateFormat, clientApplicationLocale, parametersPassedInCommand); - } - return value; - } - - public LocalDate extractLocalDateNamed( - final String parameterName, - final JsonObject element, - final String dateFormat, - final Locale clientApplicationLocale, - final Set parametersPassedInCommand) { - LocalDate value = null; - if (element.isJsonObject()) { - JsonObject object = element.getAsJsonObject(); + public Locale extractLocaleParameter(final JsonObject element) { + Locale clientApplicationLocale = null; + if (element.isJsonObject()) { + JsonObject object = element.getAsJsonObject(); - if (object.has(parameterName) - && object.get(parameterName).isJsonPrimitive()) { - - parametersPassedInCommand.add(parameterName); - - final JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive(); - final String valueAsString = primitive.getAsString(); - if (StringUtils.isNotBlank(valueAsString)) { - value = convertFrom(valueAsString, parameterName, dateFormat, clientApplicationLocale); - } - } + String locale = null; + final String localeParameter = "locale"; + if (object.has(localeParameter) && object.get(localeParameter).isJsonPrimitive()) { + final JsonPrimitive primitive = object.get(localeParameter).getAsJsonPrimitive(); + locale = primitive.getAsString(); + clientApplicationLocale = localeFromString(locale); + } + } + return clientApplicationLocale; + } - } - return value; - } + /** + * Used with the local date is in array format + */ + public LocalDate extractLocalDateAsArrayNamed(final String parameterName, final JsonElement element, + final Set parametersPassedInCommand) { + LocalDate value = null; + if (element.isJsonObject()) { + JsonObject object = element.getAsJsonObject(); - public LocalDate convertFrom(final String dateAsString, - final String parameterName, final String dateFormat, - final Locale clientApplicationLocale) { + if (object.has(parameterName) && object.get(parameterName).isJsonArray()) { - if (StringUtils.isBlank(dateFormat) || clientApplicationLocale == null) { + parametersPassedInCommand.add(parameterName); - List dataValidationErrors = new ArrayList(); - if (StringUtils.isBlank(dateFormat)) { - String defaultMessage = new StringBuilder( - "The parameter '" - + parameterName - + "' requires a 'dateFormat' parameter to be passed with it.") - .toString(); - ApiParameterError error = ApiParameterError.parameterError( - "validation.msg.missing.dateFormat.parameter", - defaultMessage, parameterName); - dataValidationErrors.add(error); - } - if (clientApplicationLocale == null) { - String defaultMessage = new StringBuilder( - "The parameter '" - + parameterName - + "' requires a 'locale' parameter to be passed with it.") - .toString(); - ApiParameterError error = ApiParameterError.parameterError( - "validation.msg.missing.locale.parameter", - defaultMessage, parameterName); - dataValidationErrors.add(error); - } - throw new PlatformApiDataValidationException( - "validation.msg.validation.errors.exist", - "Validation errors exist.", dataValidationErrors); - } + final JsonArray dateArray = object.get(parameterName).getAsJsonArray(); - LocalDate eventLocalDate = null; - if (StringUtils.isNotBlank(dateAsString)) { - try { - // Locale locale = LocaleContextHolder.getLocale(); - eventLocalDate = DateTimeFormat - .forPattern(dateFormat) - .withLocale(clientApplicationLocale) - .parseLocalDate( - dateAsString - .toLowerCase(clientApplicationLocale)); - } catch (IllegalArgumentException e) { - List dataValidationErrors = new ArrayList(); - ApiParameterError error = ApiParameterError.parameterError( - "validation.msg.invalid.date.format", "The parameter " - + parameterName - + " is invalid based on the dateFormat: '" - + dateFormat + "' and locale: '" - + clientApplicationLocale + "' provided:", - parameterName, dateAsString, dateFormat); - dataValidationErrors.add(error); + Integer year = dateArray.get(0).getAsInt(); + Integer month = dateArray.get(1).getAsInt(); + Integer day = dateArray.get(2).getAsInt(); - throw new PlatformApiDataValidationException( - "validation.msg.validation.errors.exist", - "Validation errors exist.", dataValidationErrors); - } - } + value = new LocalDate().withYearOfEra(year).withMonthOfYear(month).withDayOfMonth(day); + } - return eventLocalDate; - } + } + return value; + } - public Integer convertToInteger(final String numericalValueFormatted, - final String parameterName, final Locale clientApplicationLocale) { + public LocalDate extractLocalDateNamed(final String parameterName, final JsonElement element, + final Set parametersPassedInCommand) { - if (clientApplicationLocale == null) { + LocalDate value = null; - List dataValidationErrors = new ArrayList(); - String defaultMessage = new StringBuilder("The parameter '" - + parameterName - + "' requires a 'locale' parameter to be passed with it.") - .toString(); - ApiParameterError error = ApiParameterError.parameterError( - "validation.msg.missing.locale.parameter", defaultMessage, - parameterName); - dataValidationErrors.add(error); + if (element.isJsonObject()) { + JsonObject object = element.getAsJsonObject(); - throw new PlatformApiDataValidationException( - "validation.msg.validation.errors.exist", - "Validation errors exist.", dataValidationErrors); - } + final String dateFormat = extractDateFormatParameter(object); + final Locale clientApplicationLocale = extractLocaleParameter(object); + value = extractLocalDateNamed(parameterName, object, dateFormat, clientApplicationLocale, parametersPassedInCommand); + } + return value; + } - try { - Integer number = null; + public LocalDate extractLocalDateNamed(final String parameterName, final JsonObject element, final String dateFormat, + final Locale clientApplicationLocale, final Set parametersPassedInCommand) { + LocalDate value = null; + if (element.isJsonObject()) { + JsonObject object = element.getAsJsonObject(); - if (StringUtils.isNotBlank(numericalValueFormatted)) { + if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) { - String source = numericalValueFormatted.trim(); + parametersPassedInCommand.add(parameterName); - NumberFormat format = NumberFormat - .getInstance(clientApplicationLocale); - DecimalFormat df = (DecimalFormat) format; - DecimalFormatSymbols symbols = df.getDecimalFormatSymbols(); - df.setParseBigDecimal(true); + final JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive(); + final String valueAsString = primitive.getAsString(); + if (StringUtils.isNotBlank(valueAsString)) { + value = convertFrom(valueAsString, parameterName, dateFormat, clientApplicationLocale); + } + } - // http://bugs.sun.com/view_bug.do?bug_id=4510618 - char groupingSeparator = symbols.getGroupingSeparator(); - if (groupingSeparator == '\u00a0') { - source = source.replaceAll(" ", - Character.toString('\u00a0')); - } + } + return value; + } - Number parsedNumber = df.parse(source); + public LocalDate convertFrom(final String dateAsString, final String parameterName, final String dateFormat, + final Locale clientApplicationLocale) { - double parsedNumberDouble = parsedNumber.doubleValue(); - int parsedNumberInteger = parsedNumber.intValue(); + if (StringUtils.isBlank(dateFormat) || clientApplicationLocale == null) { - if (source.contains(Character.toString(symbols - .getDecimalSeparator()))) { - throw new ParseException(source, 0); - } + List dataValidationErrors = new ArrayList(); + if (StringUtils.isBlank(dateFormat)) { + String defaultMessage = new StringBuilder("The parameter '" + parameterName + + "' requires a 'dateFormat' parameter to be passed with it.").toString(); + ApiParameterError error = ApiParameterError.parameterError("validation.msg.missing.dateFormat.parameter", defaultMessage, + parameterName); + dataValidationErrors.add(error); + } + if (clientApplicationLocale == null) { + String defaultMessage = new StringBuilder("The parameter '" + parameterName + + "' requires a 'locale' parameter to be passed with it.").toString(); + ApiParameterError error = ApiParameterError.parameterError("validation.msg.missing.locale.parameter", defaultMessage, + parameterName); + dataValidationErrors.add(error); + } + throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", + dataValidationErrors); + } - if (!Double.valueOf(parsedNumberDouble).equals( - Double.valueOf(Integer.valueOf(parsedNumberInteger)))) { - throw new ParseException(source, 0); - } + LocalDate eventLocalDate = null; + if (StringUtils.isNotBlank(dateAsString)) { + try { + // Locale locale = LocaleContextHolder.getLocale(); + eventLocalDate = DateTimeFormat.forPattern(dateFormat).withLocale(clientApplicationLocale) + .parseLocalDate(dateAsString.toLowerCase(clientApplicationLocale)); + } catch (IllegalArgumentException e) { + List dataValidationErrors = new ArrayList(); + ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.date.format", "The parameter " + + parameterName + " is invalid based on the dateFormat: '" + dateFormat + "' and locale: '" + + clientApplicationLocale + "' provided:", parameterName, dateAsString, dateFormat); + dataValidationErrors.add(error); - number = parsedNumber.intValue(); - } + throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", + dataValidationErrors); + } + } - return number; - } catch (ParseException e) { + return eventLocalDate; + } - List dataValidationErrors = new ArrayList(); - ApiParameterError error = ApiParameterError - .parameterError( - "validation.msg.invalid.integer.format", - "The parameter " - + parameterName - + " has value: " - + numericalValueFormatted - + " which is invalid integer value for provided locale of [" - + clientApplicationLocale.toString() + "].", - parameterName, numericalValueFormatted, - clientApplicationLocale); - dataValidationErrors.add(error); + public Integer convertToInteger(final String numericalValueFormatted, final String parameterName, final Locale clientApplicationLocale) { - throw new PlatformApiDataValidationException( - "validation.msg.validation.errors.exist", - "Validation errors exist.", dataValidationErrors); - } - } + if (clientApplicationLocale == null) { - public BigDecimal convertFrom(final String numericalValueFormatted, - final String parameterName, final Locale clientApplicationLocale) { + List dataValidationErrors = new ArrayList(); + String defaultMessage = new StringBuilder("The parameter '" + parameterName + + "' requires a 'locale' parameter to be passed with it.").toString(); + ApiParameterError error = ApiParameterError.parameterError("validation.msg.missing.locale.parameter", defaultMessage, + parameterName); + dataValidationErrors.add(error); - if (clientApplicationLocale == null) { + throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", + dataValidationErrors); + } - List dataValidationErrors = new ArrayList(); - String defaultMessage = new StringBuilder("The parameter '" - + parameterName - + "' requires a 'locale' parameter to be passed with it.") - .toString(); - ApiParameterError error = ApiParameterError.parameterError( - "validation.msg.missing.locale.parameter", defaultMessage, - parameterName); - dataValidationErrors.add(error); + try { + Integer number = null; - throw new PlatformApiDataValidationException( - "validation.msg.validation.errors.exist", - "Validation errors exist.", dataValidationErrors); - } + if (StringUtils.isNotBlank(numericalValueFormatted)) { - try { - BigDecimal number = null; + String source = numericalValueFormatted.trim(); - if (StringUtils.isNotBlank(numericalValueFormatted)) { + NumberFormat format = NumberFormat.getInstance(clientApplicationLocale); + DecimalFormat df = (DecimalFormat) format; + DecimalFormatSymbols symbols = df.getDecimalFormatSymbols(); + df.setParseBigDecimal(true); - String source = numericalValueFormatted.trim(); + // http://bugs.sun.com/view_bug.do?bug_id=4510618 + char groupingSeparator = symbols.getGroupingSeparator(); + if (groupingSeparator == '\u00a0') { + source = source.replaceAll(" ", Character.toString('\u00a0')); + } - NumberFormat format = NumberFormat - .getNumberInstance(clientApplicationLocale); - DecimalFormat df = (DecimalFormat) format; - DecimalFormatSymbols symbols = df.getDecimalFormatSymbols(); - // http://bugs.sun.com/view_bug.do?bug_id=4510618 - char groupingSeparator = symbols.getGroupingSeparator(); - if (groupingSeparator == '\u00a0') { - source = source.replaceAll(" ", - Character.toString('\u00a0')); - } + Number parsedNumber = df.parse(source); - NumberFormatter numberFormatter = new NumberFormatter(); - Number parsedNumber = numberFormatter.parse(source, - clientApplicationLocale); - number = BigDecimal.valueOf(Double.valueOf(parsedNumber - .doubleValue())); - } + double parsedNumberDouble = parsedNumber.doubleValue(); + int parsedNumberInteger = parsedNumber.intValue(); - return number; - } catch (ParseException e) { + if (source.contains(Character.toString(symbols.getDecimalSeparator()))) { throw new ParseException(source, 0); } - List dataValidationErrors = new ArrayList(); - ApiParameterError error = ApiParameterError - .parameterError( - "validation.msg.invalid.decimal.format", - "The parameter " - + parameterName - + " has value: " - + numericalValueFormatted - + " which is invalid decimal value for provided locale of [" - + clientApplicationLocale.toString() + "].", - parameterName, numericalValueFormatted, - clientApplicationLocale); - dataValidationErrors.add(error); + if (!Double.valueOf(parsedNumberDouble).equals(Double.valueOf(Integer.valueOf(parsedNumberInteger)))) { throw new ParseException( + source, 0); } - throw new PlatformApiDataValidationException( - "validation.msg.validation.errors.exist", - "Validation errors exist.", dataValidationErrors); - } - } + number = parsedNumber.intValue(); + } - private Locale localeFromString(final String localeAsString) { + return number; + } catch (ParseException e) { - if (StringUtils.isBlank(localeAsString)) { - List dataValidationErrors = new ArrayList(); - ApiParameterError error = ApiParameterError.parameterError( - "validation.msg.invalid.locale.format", - "The parameter locale is invalid. It cannot be blank.", - "locale"); - dataValidationErrors.add(error); + List dataValidationErrors = new ArrayList(); + ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.integer.format", "The parameter " + + parameterName + " has value: " + numericalValueFormatted + " which is invalid integer value for provided locale of [" + + clientApplicationLocale.toString() + "].", parameterName, numericalValueFormatted, clientApplicationLocale); + dataValidationErrors.add(error); - throw new PlatformApiDataValidationException( - "validation.msg.validation.errors.exist", - "Validation errors exist.", dataValidationErrors); - } + throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", + dataValidationErrors); + } + } - String languageCode = ""; - String courntryCode = ""; - String variantCode = ""; + public BigDecimal convertFrom(final String numericalValueFormatted, final String parameterName, final Locale clientApplicationLocale) { - String[] localeParts = localeAsString.split("_"); + if (clientApplicationLocale == null) { - if (localeParts != null && localeParts.length == 1) { - languageCode = localeParts[0]; - } + List dataValidationErrors = new ArrayList(); + String defaultMessage = new StringBuilder("The parameter '" + parameterName + + "' requires a 'locale' parameter to be passed with it.").toString(); + ApiParameterError error = ApiParameterError.parameterError("validation.msg.missing.locale.parameter", defaultMessage, + parameterName); + dataValidationErrors.add(error); - if (localeParts != null && localeParts.length == 2) { - languageCode = localeParts[0]; - courntryCode = localeParts[1]; - } + throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", + dataValidationErrors); + } - if (localeParts != null && localeParts.length == 3) { - languageCode = localeParts[0]; - courntryCode = localeParts[1]; - variantCode = localeParts[2]; - } + try { + BigDecimal number = null; - return localeFrom(languageCode, courntryCode, variantCode); - } + if (StringUtils.isNotBlank(numericalValueFormatted)) { - private Locale localeFrom(final String languageCode, - final String courntryCode, final String variantCode) { + String source = numericalValueFormatted.trim(); - List dataValidationErrors = new ArrayList(); + NumberFormat format = NumberFormat.getNumberInstance(clientApplicationLocale); + DecimalFormat df = (DecimalFormat) format; + DecimalFormatSymbols symbols = df.getDecimalFormatSymbols(); + // http://bugs.sun.com/view_bug.do?bug_id=4510618 + char groupingSeparator = symbols.getGroupingSeparator(); + if (groupingSeparator == '\u00a0') { + source = source.replaceAll(" ", Character.toString('\u00a0')); + } - List allowedLanguages = Arrays.asList(Locale.getISOLanguages()); - if (!allowedLanguages.contains(languageCode.toLowerCase())) { - ApiParameterError error = ApiParameterError.parameterError( - "validation.msg.invalid.locale.format", - "The parameter locale has an invalid language value " - + languageCode + " .", "locale", languageCode); - dataValidationErrors.add(error); - } + NumberFormatter numberFormatter = new NumberFormatter(); + Number parsedNumber = numberFormatter.parse(source, clientApplicationLocale); + number = BigDecimal.valueOf(Double.valueOf(parsedNumber.doubleValue())); + } - if (StringUtils.isNotBlank(courntryCode.toUpperCase())) { - List allowedCountries = Arrays.asList(Locale - .getISOCountries()); - if (!allowedCountries.contains(courntryCode)) { - ApiParameterError error = ApiParameterError.parameterError( - "validation.msg.invalid.locale.format", - "The parameter locale has an invalid country value " - + courntryCode + " .", "locale", courntryCode); - dataValidationErrors.add(error); - } - } + return number; + } catch (ParseException e) { - if (!dataValidationErrors.isEmpty()) { - throw new PlatformApiDataValidationException( - "validation.msg.validation.errors.exist", - "Validation errors exist.", dataValidationErrors); - } + List dataValidationErrors = new ArrayList(); + ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.decimal.format", "The parameter " + + parameterName + " has value: " + numericalValueFormatted + " which is invalid decimal value for provided locale of [" + + clientApplicationLocale.toString() + "].", parameterName, numericalValueFormatted, clientApplicationLocale); + dataValidationErrors.add(error); - return new Locale(languageCode.toLowerCase(), - courntryCode.toUpperCase(), variantCode); - } + throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", + dataValidationErrors); + } + } - private Locale extractLocaleValue(final JsonObject object) { - Locale clientApplicationLocale = null; - String locale = null; - if (object.has("locale") && object.get("locale").isJsonPrimitive()) { - JsonPrimitive primitive = object.get("locale").getAsJsonPrimitive(); - locale = primitive.getAsString(); - clientApplicationLocale = localeFromString(locale); - } - return clientApplicationLocale; - } + private Locale localeFromString(final String localeAsString) { + + if (StringUtils.isBlank(localeAsString)) { + List dataValidationErrors = new ArrayList(); + ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.locale.format", + "The parameter locale is invalid. It cannot be blank.", "locale"); + dataValidationErrors.add(error); + + throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", + dataValidationErrors); + } + + String languageCode = ""; + String courntryCode = ""; + String variantCode = ""; + + String[] localeParts = localeAsString.split("_"); + + if (localeParts != null && localeParts.length == 1) { + languageCode = localeParts[0]; + } + + if (localeParts != null && localeParts.length == 2) { + languageCode = localeParts[0]; + courntryCode = localeParts[1]; + } + + if (localeParts != null && localeParts.length == 3) { + languageCode = localeParts[0]; + courntryCode = localeParts[1]; + variantCode = localeParts[2]; + } + + return localeFrom(languageCode, courntryCode, variantCode); + } + + private Locale localeFrom(final String languageCode, final String courntryCode, final String variantCode) { + + List dataValidationErrors = new ArrayList(); + + List allowedLanguages = Arrays.asList(Locale.getISOLanguages()); + if (!allowedLanguages.contains(languageCode.toLowerCase())) { + ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.locale.format", + "The parameter locale has an invalid language value " + languageCode + " .", "locale", languageCode); + dataValidationErrors.add(error); + } + + if (StringUtils.isNotBlank(courntryCode.toUpperCase())) { + List allowedCountries = Arrays.asList(Locale.getISOCountries()); + if (!allowedCountries.contains(courntryCode)) { + ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.locale.format", + "The parameter locale has an invalid country value " + courntryCode + " .", "locale", courntryCode); + dataValidationErrors.add(error); + } + } + + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", + "Validation errors exist.", dataValidationErrors); } + + return new Locale(languageCode.toLowerCase(), courntryCode.toUpperCase(), variantCode); + } + + private Locale extractLocaleValue(final JsonObject object) { + Locale clientApplicationLocale = null; + String locale = null; + if (object.has("locale") && object.get("locale").isJsonPrimitive()) { + JsonPrimitive primitive = object.get("locale").getAsJsonPrimitive(); + locale = primitive.getAsString(); + clientApplicationLocale = localeFromString(locale); + } + return clientApplicationLocale; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/domain/CommandSource.java b/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/domain/CommandSource.java index 5f02e55c1..e9a9314c1 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/domain/CommandSource.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/domain/CommandSource.java @@ -108,10 +108,6 @@ public class CommandSource extends AbstractPersistable { return this.apiOperation; } - public boolean isClientResource() { - return this.resource.equalsIgnoreCase("CLIENTS"); - } - public boolean isCreate() { return this.apiOperation.equalsIgnoreCase("CREATE"); } @@ -123,4 +119,12 @@ public class CommandSource extends AbstractPersistable { public boolean isDelete() { return this.apiOperation.equalsIgnoreCase("DELETE") && this.resourceId != null; } + + public boolean isClientResource() { + return this.resource.equalsIgnoreCase("CLIENTS"); + } + + public boolean isRoleResource() { + return this.resource.equalsIgnoreCase("ROLES"); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/CommandSourceHandlerDelegator.java b/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/CommandSourceHandlerDelegator.java index 7d15e6cc1..04be4bc54 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/CommandSourceHandlerDelegator.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/CommandSourceHandlerDelegator.java @@ -14,11 +14,15 @@ public class CommandSourceHandlerDelegator { private final PlatformSecurityContext context; private final ClientCommandHandler clientCommandHandler; + private final RoleCommandHandler roleCommandHandler; @Autowired - public CommandSourceHandlerDelegator(final PlatformSecurityContext context, final ClientCommandHandler clientCommandHandler) { + public CommandSourceHandlerDelegator(final PlatformSecurityContext context, + final ClientCommandHandler clientCommandHandler, + final RoleCommandHandler roleCommandHandler) { this.context = context; this.clientCommandHandler = clientCommandHandler; + this.roleCommandHandler = roleCommandHandler; } public CommandSource handle(final CommandSource commandSource, final String apiRequestBodyInJson) { @@ -27,6 +31,8 @@ public class CommandSourceHandlerDelegator { CommandSource commandSourceResult = null; if (commandSource.isClientResource()) { commandSourceResult = clientCommandHandler.handle(commandSource, apiRequestBodyInJson); + } else if (commandSource.isRoleResource()) { + commandSourceResult = roleCommandHandler.handle(commandSource, apiRequestBodyInJson); } else { throw new UnsupportedCommandException(commandSource.commandName()); } @@ -39,6 +45,8 @@ public class CommandSourceHandlerDelegator { CommandSource commandSourceResult = null; if (commandSource.isClientResource()) { commandSourceResult = clientCommandHandler.handle(commandSource); + } else if (commandSource.isRoleResource()) { + commandSourceResult = roleCommandHandler.handle(commandSource); } else { throw new UnsupportedCommandException(commandSource.commandName()); } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/RoleCommandHandler.java b/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/RoleCommandHandler.java new file mode 100644 index 000000000..09368b9bf --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/RoleCommandHandler.java @@ -0,0 +1,110 @@ +package org.mifosng.platform.makerchecker.service; + +import org.joda.time.LocalDate; +import org.mifosng.platform.api.commands.RoleCommand; +import org.mifosng.platform.api.infrastructure.PortfolioApiDataConversionService; +import org.mifosng.platform.api.infrastructure.PortfolioCommandDeserializerService; +import org.mifosng.platform.api.infrastructure.PortfolioCommandSerializerService; +import org.mifosng.platform.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; +import org.mifosng.platform.infrastructure.errorhandling.UnsupportedCommandException; +import org.mifosng.platform.makerchecker.domain.CommandSource; +import org.mifosng.platform.security.PlatformSecurityContext; +import org.mifosng.platform.user.domain.AppUser; +import org.mifosng.platform.user.service.RoleWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class RoleCommandHandler implements CommandSourceHandler { + + private final PlatformSecurityContext context; + private final ChangeDetectionService changeDetectionService; + private final PortfolioApiDataConversionService apiDataConversionService; + private final PortfolioCommandSerializerService commandSerializerService; + private final PortfolioCommandDeserializerService commandDeserializerService; + private final RoleWritePlatformService writePlatformService; + + @Autowired + public RoleCommandHandler(final PlatformSecurityContext context, final ChangeDetectionService changeDetectionService, + final PortfolioApiDataConversionService apiDataConversionService, + final PortfolioCommandSerializerService commandSerializerService, + final PortfolioCommandDeserializerService commandDeserializerService, + final RoleWritePlatformService writePlatformService) { + this.context = context; + this.changeDetectionService = changeDetectionService; + this.apiDataConversionService = apiDataConversionService; + this.commandSerializerService = commandSerializerService; + this.commandDeserializerService = commandDeserializerService; + this.writePlatformService = writePlatformService; + } + + /* + * Used when users with 'create' capability create a command. If 'maker-checker' is not + * enabled for this specific command then the 'creator' is also marked 'as the checker' and command + * automatically is processed and changes state of system. + */ + public CommandSource handle(final CommandSource commandSource, final String apiRequestBodyInJson) { + + final AppUser maker = context.authenticatedUser(); + final LocalDate asToday = new LocalDate(); + + CommandSource commandSourceResult = commandSource.copy(); + + final Long resourceId = commandSource.resourceId(); + Long newResourceId = null; + + final RoleCommand command = this.apiDataConversionService.convertApiRequestJsonToRoleCommand(resourceId, apiRequestBodyInJson); + final String commandSerializedAsJson = this.commandSerializerService.serializeRoleCommandToJson(command); + commandSourceResult.updateJsonTo(commandSerializedAsJson); + + if (commandSource.isCreate()) { + try { + newResourceId = this.writePlatformService.createRole(command); + commandSourceResult.markAsChecked(maker, asToday); + commandSourceResult.updateResourceId(newResourceId); + } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { + // swallow this rollback transaction by design + } + } else if (commandSource.isUpdate()) { + try { + final String jsonOfChangesOnly = this.changeDetectionService.detectChangesOnUpdate(commandSource.resourceName(), commandSource.resourceId(), commandSerializedAsJson); + commandSourceResult.updateJsonTo(jsonOfChangesOnly); + + final RoleCommand changesOnly = this.commandDeserializerService.deserializeRoleCommand(resourceId, jsonOfChangesOnly, false); + + newResourceId = this.writePlatformService.updateRole(changesOnly); + + commandSourceResult.markAsChecked(maker, asToday); + } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { + // swallow this rollback transaction by design + } + } else if (commandSource.isDelete()) { + throw new UnsupportedCommandException(commandSource.commandName()); + } + + return commandSourceResult; + } + + /* + * Used when users with 'checker' capability approve a command. + */ + public CommandSource handle(final CommandSource commandSourceResult) { + + Long resourceId = null; + if (commandSourceResult.isRoleResource()) { + final RoleCommand command = this.commandDeserializerService.deserializeRoleCommand(resourceId, commandSourceResult.json(), true); + + if (commandSourceResult.isCreate()) { + resourceId = this.writePlatformService.createRole(command); + } else if (commandSourceResult.isUpdate()) { + resourceId = this.writePlatformService.updateRole(command); + } else if (commandSourceResult.isDelete()) { + throw new UnsupportedCommandException(commandSourceResult.commandName()); + } + } + + commandSourceResult.updateResourceId(resourceId); + + return commandSourceResult; + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/Permission.java b/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/Permission.java index c6ad4d522..ab2dc353a 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/Permission.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/Permission.java @@ -12,27 +12,26 @@ import org.springframework.data.jpa.domain.AbstractPersistable; public class Permission extends AbstractPersistable { @SuppressWarnings("unused") - @Column(name = "grouping", nullable = false, length=45) - private final String grouping; - - @Column(name = "code", nullable = false, length=100) - private final String code; + @Column(name = "grouping", nullable = false, length = 45) + private final String grouping; - @Column(name = "default_name", nullable = false, length=100) - private final String defaultName; + @Column(name = "code", nullable = false, length = 100) + private final String code; - @Column(name = "default_description", nullable = false, length=500) - private final String defaultDescription; + @Column(name = "default_name", nullable = false, length = 100) + private final String defaultName; + + @Column(name = "default_description", nullable = false, length = 500) + private final String defaultDescription; @SuppressWarnings("unused") - @Column(name = "entity_name", nullable = true, length=100) - private final String entityName; + @Column(name = "entity_name", nullable = true, length = 100) + private final String entityName; @SuppressWarnings("unused") - @Column(name = "action_name", nullable = true, length=100) - private final String actionName; - - + @Column(name = "action_name", nullable = true, length = 100) + private final String actionName; + protected Permission() { this.grouping = null; this.code = null; @@ -42,15 +41,15 @@ public class Permission extends AbstractPersistable { this.actionName = null; } - public boolean hasCode(String checkCode) { - return this.code.equalsIgnoreCase(checkCode); - } + public boolean hasCode(final String checkCode) { + return this.code.equalsIgnoreCase(checkCode); + } - public String code() { - return this.code; - } + public String code() { + return this.code; + } - public PermissionData toData() { - return new PermissionData(this.getId(), this.defaultName, this.defaultDescription, this.code); - } + public PermissionData toData() { + return new PermissionData(this.getId(), this.defaultName, this.defaultDescription, this.code); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/user/service/RoleWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/user/service/RoleWritePlatformServiceJpaRepositoryImpl.java index 69c1c2ef1..6c3635c66 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/user/service/RoleWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/user/service/RoleWritePlatformServiceJpaRepositoryImpl.java @@ -5,6 +5,7 @@ import java.util.Map; import org.mifosng.platform.accounting.api.commands.RolePermissionCommand; import org.mifosng.platform.api.commands.RoleCommand; +import org.mifosng.platform.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; import org.mifosng.platform.exceptions.PermissionNotFoundException; import org.mifosng.platform.exceptions.RoleNotFoundException; import org.mifosng.platform.security.PlatformSecurityContext; @@ -17,108 +18,102 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service -public class RoleWritePlatformServiceJpaRepositoryImpl implements - RoleWritePlatformService { +public class RoleWritePlatformServiceJpaRepositoryImpl implements RoleWritePlatformService { - private final PlatformSecurityContext context; - private final RoleRepository roleRepository; + private final PlatformSecurityContext context; + private final RoleRepository roleRepository; + private final PermissionRepository permissionRepository; - private final PermissionRepository permissionRepository; + // FIXME - kw - this value is hardcoded for now but will be retrieved from + // configuration + private boolean makerCheckerEnabledForTask = false; + + @Autowired + public RoleWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final RoleRepository roleRepository, + final PermissionRepository permissionRepository) { + this.context = context; + this.roleRepository = roleRepository; + this.permissionRepository = permissionRepository; + } - @Autowired - public RoleWritePlatformServiceJpaRepositoryImpl( - final PlatformSecurityContext context, - final RoleRepository roleRepository, - final PermissionRepository permissionRepository) { - this.context = context; - this.roleRepository = roleRepository; - this.permissionRepository = permissionRepository; - } + @Transactional + @Override + public Long createRole(final RoleCommand command) { - @Transactional - @Override - public Long createRole(final RoleCommand command) { + context.authenticatedUser(); - context.authenticatedUser(); + RoleCommandValidator validator = new RoleCommandValidator(command); + validator.validateForCreate(); - RoleCommandValidator validator = new RoleCommandValidator(command); - validator.validateForCreate(); + Role entity = new Role(command.getName(), command.getDescription()); - Role entity = new Role(command.getName(), command.getDescription()); + this.roleRepository.save(entity); + + if (this.makerCheckerEnabledForTask && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } - this.roleRepository.save(entity); + return entity.getId(); + } - return entity.getId(); - } + @Transactional + @Override + public Long updateRole(RoleCommand command) { - @Transactional - @Override - public Long updateRole(RoleCommand command) { + context.authenticatedUser(); - context.authenticatedUser(); + RoleCommandValidator validator = new RoleCommandValidator(command); + validator.validateForUpdate(); - RoleCommandValidator validator = new RoleCommandValidator(command); - validator.validateForUpdate(); + Role role = this.roleRepository.findOne(command.getId()); + if (role == null) { throw new RoleNotFoundException(command.getId()); } + role.update(command); - Role role = this.roleRepository.findOne(command.getId()); - if (role == null) { - throw new RoleNotFoundException(command.getId()); - } - role.update(command); + this.roleRepository.save(role); + + if (this.makerCheckerEnabledForTask && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } - this.roleRepository.save(role); + return role.getId(); + } - return role.getId(); - } + @Transactional + @Override + public Long updateRolePermissions(final RolePermissionCommand command) { + context.authenticatedUser(); - @Transactional - @Override - public Long updateRolePermissions(final RolePermissionCommand command) { - context.authenticatedUser(); + final Role role = this.roleRepository.findOne(command.getRoleId()); + if (role == null) { throw new RoleNotFoundException(command.getRoleId()); } - final Role role = this.roleRepository.findOne(command.getRoleId()); - if (role == null) { - throw new RoleNotFoundException(command.getRoleId()); - } + Collection allPermissions = this.permissionRepository.findAll(); - Collection allPermissions = this.permissionRepository - .findAll(); + Map commandPermissions = command.getPermissions(); + for (String permissionCode : commandPermissions.keySet()) { + Boolean selected = commandPermissions.get(permissionCode); - Map commandPermissions = command.getPermissions(); - for (String permissionCode : commandPermissions.keySet()) { - Boolean selected = commandPermissions.get(permissionCode); + final Permission permission = findPermissionByCode(allPermissions, permissionCode); - Permission permission = getPermissionByCode(allPermissions, - permissionCode); + if (role.getPermissions().contains(permission)) { + if (!(selected)) { + role.getPermissions().remove(permission); + } + } else { + if (selected) { + role.getPermissions().add(permission); + } + } + } - if (role.getPermissions().contains(permission)) { - if (!(selected)) { - role.getPermissions().remove(permission); - } + this.roleRepository.save(role); - } else { - if (selected) { - role.getPermissions().add(permission); - } + return role.getId(); + } - } - } + private Permission findPermissionByCode(Collection allPermissions, String permissionCode) { - this.roleRepository.save(role); + if (allPermissions != null) { + for (Permission permission : allPermissions) { + if (permission.hasCode(permissionCode)) {return permission;} + } + } - return role.getId(); - } - - private Permission getPermissionByCode( - Collection allPermissions, String permissionCode) { - - if (allPermissions != null) { - for (Permission permission : allPermissions) { - if (permission.code().equals(permissionCode)) return permission; - - } - } - - throw new PermissionNotFoundException(permissionCode); - } + throw new PermissionNotFoundException(permissionCode); + } } \ No newline at end of file