diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm index 9cd6d310c..5ee65369c 100644 --- a/api-docs/apiLive.htm +++ b/api-docs/apiLive.htm @@ -16766,6 +16766,252 @@ Request Body: + +   +
+
+

Staff Images

+

The current API provides support for the addition of a single + image for a Staff Member
+ Allowed formats: JPEG (.jpg or .jpeg), GIF (.gif) and PNG (.png) +

+

The API supports two different Approaches for manipulating Staff Images +

+
+   +
+
+

Upload an Image for a Staff (Data URI)

+
+
+ +POST https://DomainName/api/v1/staff/{staffId}/images + + +POST staff/1/images +Content-Type: text/plain +Request Body: +data:image/png;base64,iVBORw0KGgoAA +AANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD///+l2Z/dAAAAM0l +EQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4Ug9C9zwz3gVLMDA/A6 +P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC + + +{ + "resourceId": 1, + "changes": {}, + "resourceIdentifier": "1" +} + +
+
+ +   +
+
+

Upload an Image for a Staff Member (Multi-part Form data)

+ + + + + + + +
Mandatory Fields
file +
+

+ The form should contain a required named body part with the + name "file".

+ If you are using a HTML form, a snippet like + <input type="file" name="file"></input> + can be used for uploading the image file +

+
+
+ +POST https://DomainName/api/v1/staff/{staffId}/images + + +POST staff/1/images +Content-Type: multipart/form-data +Request Body: Not shown + + +{ + "resourceId": 1, + "changes": {}, + "resourceIdentifier": "1" +} + +
+
+ +  +
+
+

Get Staff Image (DATA URI)

+

Optional arguments are identical to those of Get Staff Image (Binary file)

+

Example Requests:

+
staff/1/images
+
+
+
+ +GET https://DomainName/api/v1/staff/{staffId}/images +Accept: text/plain + + + +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ +bWFnZVJlYWR5ccllPAAAAJ1JREFUeNpi+P//PwMIA4E9EG8E4idQDGLbw+WhiiqA+D8OXAFVAzbp +DxBvB2JLIGaGYkuoGEjOhhFIHAbij0BdPgxYACMj42ogJQpifwBiXSDeC8JIbt4LxSC5DyxQjTeB ++BeaYb+Q5EBOAVutCzMJHUNNPADzzDokiYdAfAmJvwLkGeTgWQfyKZICS6hYBTwc0QL8ORSjBDhA +gAEAOg13B6R/SAgAAAAASUVORK5CYII= + +
+
+ +  +
+
+

Get Staff Image (Binary file)

+
Optional Arguments
+
+
output
+
+ String optional one of octet or inline_octet +
+
The query parameter overrides the "Accept" Header and sets the Media Type to "application/octet-stream"
+ octet : Returns the image binary file as an attachment. The Content-Disposition header is set to attachment;filename=somefile.ext
+ inline_octet :The Content-Disposition header is set to inline;filename=somefile.ext +
+
maxWidth
+
+ Integer optional +
+
Triggers resizing of the image to the defined width
+ +
maxHeight
+
+
+ Integer optional +
+ +
Triggers resizing of the image to the defined height
+ + +
+
+
+ +GET https://DomainName/api/v1/staff/{staffId}/images +Accept: application/octet-stream + + +POST staff/1/images +Accept: application/octet-stream + + +Not shown: The corresponding binary (image) file + +
+
+ +   +
+
+

Update a Staff Image (Data URI)

+
+
+ +PUT https://DomainName/api/v1/staff/{staffId}/images + + +PUT staff/1/images +Content-Type: text/plain +Request Body: +data:image/png;base64,iVBORw0KGgoAA +AANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD///+l2Z/dAAAAM0l +EQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4Ug9C9zwz3gVLMDA/A6 +P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC + + +{ + "resourceId": 1, + "changes": {}, + "resourceIdentifier": "1" +} + +
+
+ +   +
+
+

Update a Staff Member Image (Multi-part Form data)

+ + + + + + + +
Mandatory Fields
file +
+

+ The form should contain a required named body part with the + name "file".

+ If you are using a HTML form, a snippet like + <input type="file" name="file"></input> + can be used for uploading the image file +

+
+
+ +PUT https://DomainName/api/v1/staff/{staffId}/images + + +PUT staff/1/images +Content-Type: multipart/form-data +Request Body: Not shown + +
+
+ +   +
+
+

Delete a Staff Image

+
+
+ +DELETE https://DomainName/api/v1/staff/{staffId}/images + + +DELETE staff/1/images +Content-Type: application/json +No Request Body: + + +{ + "resourceId": 1, + "changes": {}, + "resourceIdentifier": "1" +} + +
+
  @@ -36251,6 +36497,26 @@ No Request Body: Update a Staff Member + + Staff Images + staff/{staffId}/images + Upload an Image for a Staff Member (as DATA URI) + Get Staff Image (DATA URI) + Update Staff Image (DATA URI) + Delete Staff Image + + + + + + Upload an Image for a Staff Member (Multi-part form data) + + Get Staff Image (Binary file) + + Update Staff Image (Multi-part form data) + + + Charges charges diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/StaffImageApiTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/StaffImageApiTest.java new file mode 100644 index 000000000..ee428c037 --- /dev/null +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/StaffImageApiTest.java @@ -0,0 +1,90 @@ +package org.mifosplatform.integrationtests; + +import com.sun.jersey.core.util.Base64; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mifosplatform.integrationtests.common.ImageHelper; +import org.mifosplatform.integrationtests.common.Utils; +import org.mifosplatform.integrationtests.common.accounting.AccountHelper; +import org.mifosplatform.integrationtests.common.loans.LoanTransactionHelper; +import org.mifosplatform.integrationtests.common.organisation.StaffHelper; + +import com.jayway.restassured.builder.RequestSpecBuilder; +import com.jayway.restassured.builder.ResponseSpecBuilder; +import com.jayway.restassured.http.ContentType; +import com.jayway.restassured.specification.RequestSpecification; +import com.jayway.restassured.specification.ResponseSpecification; + +import java.io.IOException; + +public class StaffImageApiTest { + + private RequestSpecification requestSpec; + private ResponseSpecification responseSpec; + private LoanTransactionHelper loanTransactionHelper; + private AccountHelper accountHelper; + + @Before + public void setup() { + Utils.initializeRESTAssured(); + this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); + this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); + this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); + this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); + this.accountHelper = new AccountHelper(this.requestSpec, this.responseSpec); + + } + + @Test + public void createStaffImage() { + + Integer staffId = StaffHelper.createStaff(this.requestSpec, this.responseSpec); + Integer imageId = ImageHelper.createImageForStaff(this.requestSpec, this.responseSpec, staffId); + Assert.assertNotNull("Image id should not be null", imageId); + + } + + @Test + public void getStaffImage(){ + Integer staffId = StaffHelper.createStaff(this.requestSpec, this.responseSpec); + Integer imageId = ImageHelper.createImageForStaff(this.requestSpec, this.responseSpec, staffId); + Assert.assertNotNull("Image id should not be null", imageId); + String imageAsText = ImageHelper.getStaffImageAsText(this.requestSpec, this.responseSpec, staffId); + Assert.assertNotNull("Image id should not be null", imageAsText); + } + + @Test + public void getStaffImageAsBinary(){ + Integer staffId = StaffHelper.createStaff(this.requestSpec, this.responseSpec); + Integer imageId = ImageHelper.createImageForStaff(this.requestSpec, this.responseSpec, staffId); + Assert.assertNotNull("Image id should not be null", imageId); + byte[] imageAsBytes = ImageHelper.getStaffImageAsBinary(this.requestSpec, this.responseSpec, staffId); + Assert.assertNotNull("Image content should not be null", imageAsBytes); + } + + @Test + public void updateImage() { + + Integer staffId = StaffHelper.createStaff(this.requestSpec, this.responseSpec); + Integer imageId = ImageHelper.createImageForStaff(this.requestSpec, this.responseSpec, staffId); + Assert.assertNotNull("Image id should not be null", imageId); + imageId = ImageHelper.updateImageForStaff(this.requestSpec, this.responseSpec, staffId); + Assert.assertNotNull("Image id should not be null", imageId); + + } + + @Test + public void deleteStaffImage() { + + Integer staffId = StaffHelper.createStaff(this.requestSpec, this.responseSpec); + Integer imageId = ImageHelper.createImageForStaff(this.requestSpec, this.responseSpec, staffId); + Assert.assertNotNull("Image id should not be null", imageId); + imageId = ImageHelper.deleteStaffImage(this.requestSpec, this.responseSpec, staffId); + Assert.assertNotNull("Image id should not be null", imageId); + + } + + + +} diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ImageHelper.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ImageHelper.java new file mode 100644 index 000000000..3bc149a89 --- /dev/null +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ImageHelper.java @@ -0,0 +1,66 @@ +package org.mifosplatform.integrationtests.common; + +import com.jayway.restassured.http.ContentType; +import com.jayway.restassured.specification.RequestSpecification; +import com.jayway.restassured.specification.ResponseSpecification; +import com.sun.jersey.core.util.Base64; +import org.apache.http.HttpHeaders; +import org.mifosplatform.infrastructure.core.domain.Base64EncodedImage; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; + +public class ImageHelper { + + private static final String STAFF_IMAGE_URL = "/mifosng-provider/api/v1/staff/"; + private static final String IMAGES_URI = "/images"; + + public static Integer createImageForStaff(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + Integer staffId) { + System.out.println("---------------------------------CREATING AN IMAGE FOR STAFF---------------------------------------------"); + String URL = STAFF_IMAGE_URL + staffId + IMAGES_URI+ "?" + Utils.TENANT_IDENTIFIER; + return Utils.performServerPost(requestSpec, responseSpec, URL, generateImageAsText(), "resourceId"); + } + + public static Integer updateImageForStaff(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + Integer staffId) { + System.out.println("---------------------------------UPDATING AN IMAGE FOR STAFF---------------------------------------------"); + String URL = STAFF_IMAGE_URL + staffId + IMAGES_URI+ "?" + Utils.TENANT_IDENTIFIER; + requestSpec.header(HttpHeaders.CONTENT_TYPE,"mutlipart/form-data"); + return Utils.performServerPut(requestSpec, responseSpec, URL, generateImageAsText(), "resourceId"); + } + + public static String getStaffImageAsText(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + Integer staffId){ + System.out.println("---------------------------------RETRIEVING STAFF IMAGE---------------------------------------------"); + String URL = STAFF_IMAGE_URL + staffId + IMAGES_URI+ "?" + Utils.TENANT_IDENTIFIER; + requestSpec.header(HttpHeaders.ACCEPT,"text/plain"); + return Utils.performGetTextResponse(requestSpec, responseSpec, URL); + } + + public static byte[] getStaffImageAsBinary(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + Integer staffId){ + System.out.println("---------------------------------RETRIEVING STAFF IMAGE---------------------------------------------"); + String URL = STAFF_IMAGE_URL + staffId + IMAGES_URI+ "?" + Utils.TENANT_IDENTIFIER; + requestSpec.header(HttpHeaders.ACCEPT,"application/octet-stream"); + return Utils.performGetBinaryResponse(requestSpec, responseSpec, URL); + } + + public static Integer deleteStaffImage(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + Integer staffId){ + System.out.println("---------------------------------RETRIEVING STAFF IMAGE---------------------------------------------"); + String URL = STAFF_IMAGE_URL + staffId + IMAGES_URI+ "?" + Utils.TENANT_IDENTIFIER; + return Utils.performServerDelete(requestSpec, responseSpec, URL, "resourceId"); + } + + private static String generateImageAsText() { + return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ\n" + + "bWFnZVJlYWR5ccllPAAAAJ1JREFUeNpi+P//PwMIA4E9EG8E4idQDGLbw+WhiiqA+D8OXAFVAzbp\n" + + "DxBvB2JLIGaGYkuoGEjOhhFIHAbij0BdPgxYACMj42ogJQpifwBiXSDeC8JIbt4LxSC5DyxQjTeB\n" + + "+BeaYb+Q5EBOAVutCzMJHUNNPADzzDokiYdAfAmJvwLkGeTgWQfyKZICS6hYBTwc0QL8ORSjBDhA\n" + "gAEAOg13B6R/SAgAAAAASUVORK5CYII="; + } + private static byte[] generateImageAsBinary(){ + return Base64.decode(generateImageAsText().split("base64,")[1]); + } +} diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/Utils.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/Utils.java index 7671257f9..2640c54bb 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/Utils.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/Utils.java @@ -11,6 +11,10 @@ import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -72,6 +76,16 @@ public class Utils { return (T) from(json).get(jsonAttributeToGetBack); } + public static String performGetTextResponse(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + final String getURL){ + return given().spec(requestSpec).expect().spec(responseSpec).log().ifError().when().get(getURL).andReturn().asString(); + } + + public static byte[] performGetBinaryResponse(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + final String getURL){ + return given().spec(requestSpec).expect().spec(responseSpec).log().ifError().when().get(getURL).andReturn().asByteArray(); + } + public static T performServerPost(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, final String postURL, final String jsonBodyToSend, final String jsonAttributeToGetBack) { final String json = given().spec(requestSpec).body(jsonBodyToSend).expect().spec(responseSpec).log().ifError().when().post(postURL) diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/api/ImagesApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/api/ImagesApiResource.java index 8ee811448..2f0b6c813 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/api/ImagesApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/api/ImagesApiResource.java @@ -7,16 +7,7 @@ package org.mifosplatform.infrastructure.documentmanagement.api; import java.io.InputStream; -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; +import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; @@ -70,9 +61,9 @@ public class ImagesApiResource { @POST @Consumes({ MediaType.MULTIPART_FORM_DATA }) @Produces({ MediaType.APPLICATION_JSON }) - public String addNewClientImage(@PathParam("clientId") final Long clientId, @HeaderParam("Content-Length") final Long fileSize, - @FormDataParam("file") final InputStream inputStream, @FormDataParam("file") final FormDataContentDisposition fileDetails, - @FormDataParam("file") final FormDataBodyPart bodyPart) { + public String addNewClientImage(@PathParam("clients") final String clientName, @PathParam("clientId") final Long clientId, + @HeaderParam("Content-Length") final Long fileSize, @FormDataParam("file") final InputStream inputStream, + @FormDataParam("file") final FormDataContentDisposition fileDetails, @FormDataParam("file") final FormDataBodyPart bodyPart) { // TODO: vishwas might need more advances validation (like reading magic // number) for handling malicious clients @@ -80,8 +71,8 @@ public class ImagesApiResource { ContentRepositoryUtils.validateClientImageNotEmpty(fileDetails.getFileName()); ContentRepositoryUtils.validateImageMimeType(bodyPart.getMediaType().toString()); - final CommandProcessingResult result = this.imageWritePlatformService.saveOrUpdateClientImage(clientId, fileDetails.getFileName(), - inputStream, fileSize); + final CommandProcessingResult result = this.imageWritePlatformService.saveOrUpdateImage(clientName, clientId, + fileDetails.getFileName(), inputStream, fileSize); return this.toApiJsonSerializer.serialize(result); } @@ -92,11 +83,12 @@ public class ImagesApiResource { @POST @Consumes({ MediaType.TEXT_PLAIN, MediaType.TEXT_HTML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) - public String addNewClientImage(@PathParam("clientId") final Long clientId, final String jsonRequestBody) { + public String addNewClientImage(@PathParam("clients") final String clientName, @PathParam("clientId") final Long clientId, + final String jsonRequestBody) { final Base64EncodedImage base64EncodedImage = ContentRepositoryUtils.extractImageFromDataURL(jsonRequestBody); - final CommandProcessingResult result = this.imageWritePlatformService.saveOrUpdateClientImage(clientId, base64EncodedImage); + final CommandProcessingResult result = this.imageWritePlatformService.saveOrUpdateImage(clientName, clientId, base64EncodedImage); return this.toApiJsonSerializer.serialize(result); } @@ -107,14 +99,15 @@ public class ImagesApiResource { @GET @Consumes({ MediaType.TEXT_PLAIN, MediaType.TEXT_HTML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.TEXT_PLAIN }) - public Response retrieveClientImage(@PathParam("clientId") final Long clientId, @QueryParam("maxWidth") final Integer maxWidth, - @QueryParam("maxHeight") final Integer maxHeight, @QueryParam("output") final String output) { - if (output != null && (output.equals("octet") || output.equals("inline_octet"))) { return downloadClientImage(clientId, maxWidth, - maxHeight, output); } + public Response retrieveImage(@PathParam("clients") final String clientName, @PathParam("clientId") final Long clientId, + @QueryParam("maxWidth") final Integer maxWidth, @QueryParam("maxHeight") final Integer maxHeight, + @QueryParam("output") final String output) { + if (output != null && (output.equals("octet") || output.equals("inline_octet"))) { return downloadClientImage(clientName, clientId, + maxWidth, maxHeight, output); } this.context.authenticatedUser().validateHasReadPermission("CLIENTIMAGE"); - final ImageData imageData = this.imageReadPlatformService.retrieveClientImage(clientId); + final ImageData imageData = this.imageReadPlatformService.retrieveImage(clientName, clientId); // TODO: Need a better way of determining image type String imageDataURISuffix = ContentRepositoryUtils.IMAGE_DATA_URI_SUFFIX.JPEG.getValue(); @@ -131,11 +124,12 @@ public class ImagesApiResource { @GET @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_OCTET_STREAM }) - public Response downloadClientImage(@PathParam("clientId") final Long clientId, @QueryParam("maxWidth") final Integer maxWidth, - @QueryParam("maxHeight") final Integer maxHeight, @QueryParam("output") String output) { + public Response downloadClientImage(@PathParam("clients") final String clientName, @PathParam("clientId") final Long clientId, + @QueryParam("maxWidth") final Integer maxWidth, @QueryParam("maxHeight") final Integer maxHeight, + @QueryParam("output") String output) { this.context.authenticatedUser().validateHasReadPermission("CLIENTIMAGE"); - final ImageData imageData = this.imageReadPlatformService.retrieveClientImage(clientId); + final ImageData imageData = this.imageReadPlatformService.retrieveImage(clientName, clientId); final ResponseBuilder response = Response.ok(imageData.getContentOfSize(maxWidth, maxHeight)); String dispositionType = "inline_octet".equals(output) ? "inline" : "attachment"; @@ -155,10 +149,10 @@ public class ImagesApiResource { @PUT @Consumes({ MediaType.MULTIPART_FORM_DATA }) @Produces({ MediaType.APPLICATION_JSON }) - public String updateClientImage(@PathParam("clientId") final Long clientId, @HeaderParam("Content-Length") final Long fileSize, - @FormDataParam("file") final InputStream inputStream, @FormDataParam("file") final FormDataContentDisposition fileDetails, - @FormDataParam("file") final FormDataBodyPart bodyPart) { - return addNewClientImage(clientId, fileSize, inputStream, fileDetails, bodyPart); + public String updateClientImage(@PathParam("clients") final String clientName, @PathParam("clientId") final Long clientId, + @HeaderParam("Content-Length") final Long fileSize, @FormDataParam("file") final InputStream inputStream, + @FormDataParam("file") final FormDataContentDisposition fileDetails, @FormDataParam("file") final FormDataBodyPart bodyPart) { + return addNewClientImage(clientName, clientId, fileSize, inputStream, fileDetails, bodyPart); } /** @@ -170,15 +164,16 @@ public class ImagesApiResource { @PUT @Consumes({ MediaType.TEXT_PLAIN, MediaType.TEXT_HTML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) - public String updateClientImage(@PathParam("clientId") final Long clientId, final String jsonRequestBody) { - return addNewClientImage(clientId, jsonRequestBody); + public String updateClientImage(@PathParam("clients") final String clientName, @PathParam("clientId") final Long clientId, + final String jsonRequestBody) { + return addNewClientImage(clientName, clientId, jsonRequestBody); } @DELETE @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) - public String deleteClientImage(@PathParam("clientId") final Long clientId) { - this.imageWritePlatformService.deleteClientImage(clientId); + public String deleteClientImage(@PathParam("clients") final String clientName, @PathParam("clientId") final Long clientId) { + this.imageWritePlatformService.deleteImage(clientName, clientId); return this.toApiJsonSerializer.serialize(new CommandProcessingResult(clientId)); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/exception/InvalidImageTypeException.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/exception/InvalidImageTypeException.java new file mode 100644 index 000000000..e4356f686 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/exception/InvalidImageTypeException.java @@ -0,0 +1,13 @@ +package org.mifosplatform.infrastructure.documentmanagement.exception; + +import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException; + +/** + * Runtime exception for invalid image types + */ +public class InvalidImageTypeException extends AbstractPlatformResourceNotFoundException { + + public InvalidImageTypeException(String imageType) { + super("error.documentmanagement.imagetype.invalid", "Image type not supported: " + imageType, imageType); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/ImageReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/ImageReadPlatformService.java index eca7a90c6..940563645 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/ImageReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/ImageReadPlatformService.java @@ -9,6 +9,6 @@ import org.mifosplatform.infrastructure.documentmanagement.data.ImageData; public interface ImageReadPlatformService { - ImageData retrieveClientImage(Long clientId); + ImageData retrieveImage(String clientName, Long clientId); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/ImageReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/ImageReadPlatformServiceImpl.java index 9997e9de6..edc6f68f9 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/ImageReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/ImageReadPlatformServiceImpl.java @@ -13,6 +13,8 @@ import org.mifosplatform.infrastructure.core.service.RoutingDataSource; import org.mifosplatform.infrastructure.documentmanagement.contentrepository.ContentRepository; import org.mifosplatform.infrastructure.documentmanagement.contentrepository.ContentRepositoryFactory; import org.mifosplatform.infrastructure.documentmanagement.data.ImageData; +import org.mifosplatform.organisation.staff.domain.Staff; +import org.mifosplatform.organisation.staff.domain.StaffRepositoryWrapper; import org.mifosplatform.portfolio.client.domain.Client; import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper; import org.mifosplatform.portfolio.client.exception.ImageNotFoundException; @@ -28,10 +30,13 @@ public class ImageReadPlatformServiceImpl implements ImageReadPlatformService { private final JdbcTemplate jdbcTemplate; private final ContentRepositoryFactory contentRepositoryFactory; private final ClientRepositoryWrapper clientRepositoryWrapper; + private final StaffRepositoryWrapper staffRepositoryWrapper; @Autowired public ImageReadPlatformServiceImpl(final RoutingDataSource dataSource, final ContentRepositoryFactory documentStoreFactory, - final ClientRepositoryWrapper clientRepositoryWrapper) { + final ClientRepositoryWrapper clientRepositoryWrapper, + StaffRepositoryWrapper staffRepositoryWrapper) { + this.staffRepositoryWrapper = staffRepositoryWrapper; this.jdbcTemplate = new JdbcTemplate(dataSource); this.contentRepositoryFactory = documentStoreFactory; this.clientRepositoryWrapper = clientRepositoryWrapper; @@ -45,9 +50,14 @@ public class ImageReadPlatformServiceImpl implements ImageReadPlatformService { this.entityDisplayName = entityDisplayName; } - public String schema() { - return " image.id as id, image.location as location, image.storage_type_enum as storageType " - + " from m_image image , m_client client " + " where client.image_id = image.id and client.id=?"; + public String schema(String clientName) { + StringBuilder builder = new StringBuilder("image.id as id, image.location as location, image.storage_type_enum as storageType "); + if (ImageWritePlatformServiceJpaRepositoryImpl.IMAGE_TYPE.CLIENTS.toString().equals(clientName)) { + builder.append(" from m_image image , m_client client " + " where client.image_id = image.id and client.id=?"); + } else if (ImageWritePlatformServiceJpaRepositoryImpl.IMAGE_TYPE.STAFF.toString().equals(clientName)) { + builder.append("from m_image image , m_staff staff " + " where staff.image_id = image.id and staff.id=?"); + } + return builder.toString(); } @Override @@ -61,13 +71,24 @@ public class ImageReadPlatformServiceImpl implements ImageReadPlatformService { } @Override - public ImageData retrieveClientImage(final Long clientId) { + public ImageData retrieveImage(String clientName, final Long clientId) { try { - final Client client = this.clientRepositoryWrapper.findOneWithNotFoundDetection(clientId); + Object owner; + String displayName = null; + if (ImageWritePlatformServiceJpaRepositoryImpl.IMAGE_TYPE.CLIENTS + .toString().equals(clientName)) { + owner = this.clientRepositoryWrapper + .findOneWithNotFoundDetection(clientId); + displayName = ((Client) owner).getDisplayName(); + } else if (ImageWritePlatformServiceJpaRepositoryImpl.IMAGE_TYPE.STAFF + .toString().equals(clientName)) { + owner = this.staffRepositoryWrapper + .findOneWithNotFoundDetection(clientId); + displayName = ((Staff) owner).displayName(); + } + final ImageMapper imageMapper = new ImageMapper(displayName); - final ImageMapper imageMapper = new ImageMapper(client.getDisplayName()); - - final String sql = "select " + imageMapper.schema(); + final String sql = "select " + imageMapper.schema(clientName); final ImageData imageData = this.jdbcTemplate.queryForObject(sql, imageMapper, new Object[] { clientId }); final ContentRepository contentRepository = this.contentRepositoryFactory.getRepository(imageData.storageType()); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/ImageWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/ImageWritePlatformService.java index 950fbe126..d45c2017b 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/ImageWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/ImageWritePlatformService.java @@ -14,11 +14,11 @@ import org.springframework.security.access.prepost.PreAuthorize; public interface ImageWritePlatformService { @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'CREATE_CLIENTIMAGE')") - CommandProcessingResult saveOrUpdateClientImage(Long clientId, String imageName, InputStream inputStream, Long fileSize); + CommandProcessingResult saveOrUpdateImage(String clientName, Long clientId, String imageName, InputStream inputStream, Long fileSize); @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'CREATE_CLIENTIMAGE')") - CommandProcessingResult saveOrUpdateClientImage(Long clientId, Base64EncodedImage encodedImage); + CommandProcessingResult saveOrUpdateImage(String clientName, Long clientId, Base64EncodedImage encodedImage); @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'DELETE_CLIENTIMAGE')") - CommandProcessingResult deleteClientImage(Long clientId); + CommandProcessingResult deleteImage(String clientName, Long clientId); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/ImageWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/ImageWritePlatformServiceJpaRepositoryImpl.java index 6d4ccc426..0dbcc9455 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/ImageWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/ImageWritePlatformServiceJpaRepositoryImpl.java @@ -14,6 +14,9 @@ import org.mifosplatform.infrastructure.documentmanagement.contentrepository.Con import org.mifosplatform.infrastructure.documentmanagement.domain.Image; import org.mifosplatform.infrastructure.documentmanagement.domain.ImageRepository; import org.mifosplatform.infrastructure.documentmanagement.domain.StorageType; +import org.mifosplatform.infrastructure.documentmanagement.exception.InvalidImageTypeException; +import org.mifosplatform.organisation.staff.domain.Staff; +import org.mifosplatform.organisation.staff.domain.StaffRepositoryWrapper; import org.mifosplatform.portfolio.client.domain.Client; import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper; import org.springframework.beans.factory.annotation.Autowired; @@ -26,80 +29,155 @@ public class ImageWritePlatformServiceJpaRepositoryImpl implements ImageWritePla private final ContentRepositoryFactory contentRepositoryFactory; private final ClientRepositoryWrapper clientRepositoryWrapper; private final ImageRepository imageRepository; + private final StaffRepositoryWrapper staffRepositoryWrapper; @Autowired public ImageWritePlatformServiceJpaRepositoryImpl(final ContentRepositoryFactory documentStoreFactory, - final ClientRepositoryWrapper clientRepositoryWrapper, final ImageRepository imageRepository) { + final ClientRepositoryWrapper clientRepositoryWrapper, final ImageRepository imageRepository, StaffRepositoryWrapper staffRepositoryWrapper) { this.contentRepositoryFactory = documentStoreFactory; this.clientRepositoryWrapper = clientRepositoryWrapper; this.imageRepository = imageRepository; + this.staffRepositoryWrapper = staffRepositoryWrapper; } @Transactional @Override - public CommandProcessingResult saveOrUpdateClientImage(final Long clientId, final String imageName, final InputStream inputStream, + public CommandProcessingResult saveOrUpdateImage(String clientName, final Long clientId, final String imageName, final InputStream inputStream, final Long fileSize) { - final Client client = this.clientRepositoryWrapper.findOneWithNotFoundDetection(clientId); - deletePreviousClientImage(client); + Object owner = null; + if (IMAGE_TYPE.CLIENTS.toString().equals(clientName)){ + owner =this.clientRepositoryWrapper.findOneWithNotFoundDetection(clientId); + } else if (IMAGE_TYPE.STAFF.toString().equals(clientName)) { + owner = this.staffRepositoryWrapper.findOneWithNotFoundDetection(clientId); + } + deletePreviousImage(owner); final ContentRepository contentRepository = this.contentRepositoryFactory.getRepository(); final String imageLocation = contentRepository.saveImage(inputStream, clientId, imageName, fileSize); - return updateClientImage(client, imageLocation, contentRepository.getStorageType()); + return updateImage(owner, imageLocation, contentRepository.getStorageType()); } @Transactional @Override - public CommandProcessingResult saveOrUpdateClientImage(final Long clientId, final Base64EncodedImage encodedImage) { - final Client client = this.clientRepositoryWrapper.findOneWithNotFoundDetection(clientId); - deletePreviousClientImage(client); + public CommandProcessingResult saveOrUpdateImage(String clientName, final Long clientId, final Base64EncodedImage encodedImage) { + Object owner = null; + if (IMAGE_TYPE.CLIENTS.toString().equals(clientName)){ + owner =this.clientRepositoryWrapper.findOneWithNotFoundDetection(clientId); + } else if (IMAGE_TYPE.STAFF.toString().equals(clientName)) { + owner = this.staffRepositoryWrapper.findOneWithNotFoundDetection(clientId); + } + deletePreviousImage(owner); + validateImageType(clientName); final ContentRepository contenRepository = this.contentRepositoryFactory.getRepository(); final String imageLocation = contenRepository.saveImage(encodedImage, clientId, "image"); - return updateClientImage(client, imageLocation, contenRepository.getStorageType()); + return updateImage(owner, imageLocation, contenRepository.getStorageType()); } @Transactional @Override - public CommandProcessingResult deleteClientImage(final Long clientId) { + public CommandProcessingResult deleteImage(String clientName, final Long clientId) { - final Client client = this.clientRepositoryWrapper.findOneWithNotFoundDetection(clientId); + Object owner = null; + Image image = null; + if (IMAGE_TYPE.CLIENTS.toString().equals(clientName)){ + owner =this.clientRepositoryWrapper.findOneWithNotFoundDetection(clientId); + Client client = (Client) owner; + image = client.getImage(); + client.setImage(null); + this.clientRepositoryWrapper.save(client); - final Image image = client.getImage(); + } else if (IMAGE_TYPE.STAFF.toString().equals(clientName)) { + owner = this.staffRepositoryWrapper.findOneWithNotFoundDetection(clientId); + Staff staff = (Staff) owner; + image = staff.getImage(); + staff.setImage(null); + this.staffRepositoryWrapper.save(staff); + + } // delete image from the file system if (image != null) { final ContentRepository contentRepository = this.contentRepositoryFactory.getRepository(StorageType.fromInt(image .getStorageType())); contentRepository.deleteImage(clientId, image.getLocation()); - client.setImage(null); this.imageRepository.delete(image); - this.clientRepositoryWrapper.save(client); } return new CommandProcessingResult(clientId); } - private void deletePreviousClientImage(final Client client) { - final Image image = client.getImage(); + private void deletePreviousImage(final Object owner) { + Image image = null; + Long clientId=null; + if (owner instanceof Client){ + Client client = (Client) owner; + image = client.getImage(); + clientId = client.getId(); + } else if (owner instanceof Staff){ + Staff staff = (Staff) owner; + image = staff.getImage(); + clientId = staff.getId(); + } if (image != null) { final ContentRepository contentRepository = this.contentRepositoryFactory.getRepository(StorageType.fromInt(image .getStorageType())); - contentRepository.deleteImage(client.getId(), image.getLocation()); + contentRepository.deleteImage(clientId, image.getLocation()); } } - private CommandProcessingResult updateClientImage(final Client client, final String imageLocation, final StorageType storageType) { - Image image = client.getImage(); + private CommandProcessingResult updateImage(final Object owner, final String imageLocation, final StorageType storageType) { + Image image = null; + Long clientId=null; + if (owner instanceof Client){ + Client client = (Client) owner; + image = client.getImage(); + clientId = client.getId(); + image = createImage(image, imageLocation, storageType); + client.setImage(image); + this.clientRepositoryWrapper.save(client); + } else if (owner instanceof Staff){ + Staff staff = (Staff) owner; + image = staff.getImage(); + clientId = staff.getId(); + image = createImage(image, imageLocation, storageType); + staff.setImage(image); + this.staffRepositoryWrapper.save(staff); + } + + this.imageRepository.save(image); + return new CommandProcessingResult(clientId); + } + + private Image createImage(Image image, final String imageLocation, final StorageType storageType) { if (image == null) { image = new Image(imageLocation, storageType); } else { image.setLocation(imageLocation); image.setStorageType(storageType.getValue()); } - this.imageRepository.save(image); - client.setImage(image); - this.clientRepositoryWrapper.save(client); - return new CommandProcessingResult(client.getId()); + return image; } + private void validateImageType(final String clientName) { + if (!checkValidEntityType(clientName)) { throw new InvalidImageTypeException( + clientName); } + } + + private static boolean checkValidEntityType(final String entityType) { + for (final IMAGE_TYPE entities : IMAGE_TYPE.values()) { + if (entities.name().equalsIgnoreCase(entityType)) { return true; } + } + return false; + } + + /*** Entities for document Management **/ + public static enum IMAGE_TYPE { + STAFF,CLIENTS; + + @Override + public String toString() { + return name().toString().toLowerCase(); + }} + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/domain/Staff.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/domain/Staff.java index 59fb93381..2f7ce32ac 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/domain/Staff.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/domain/Staff.java @@ -9,19 +9,13 @@ import java.util.Date; import java.util.LinkedHashMap; import java.util.Map; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.persistence.UniqueConstraint; +import javax.persistence.*; import org.apache.commons.lang.StringUtils; import org.joda.time.LocalDate; import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.data.EnumOptionData; +import org.mifosplatform.infrastructure.documentmanagement.domain.Image; import org.mifosplatform.organisation.office.domain.Office; import org.springframework.data.jpa.domain.AbstractPersistable; @@ -67,6 +61,10 @@ public class Staff extends AbstractPersistable { @JoinColumn(name = "organisational_role_parent_staff_id", nullable = true) private Staff organisationalRoleParentStaff; + @OneToOne(optional = true) + @JoinColumn(name = "image_id", nullable = true) + private Image image; + public static Staff fromJson(final Office staffOffice, final JsonCommand command) { final String firstnameParamName = "firstname"; @@ -196,6 +194,12 @@ public class Staff extends AbstractPersistable { this.joiningDate = newValue.toDate(); } + final String imageIdParamName = "imageId"; + if (command.isChangeInLongParameterNamed(imageIdParamName, this.image.getId())) { + final Long newValue = command.longValueOfParameterNamed(officeIdParamName); + actualChanges.put(officeIdParamName, newValue); + } + return actualChanges; } @@ -242,4 +246,12 @@ public class Staff extends AbstractPersistable { public Office office() { return this.office; } + + public void setImage(Image image) { + this.image = image; + } + + public Image getImage() { + return this.image; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/domain/StaffRepositoryWrapper.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/domain/StaffRepositoryWrapper.java index 168522eff..22d3e85f5 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/domain/StaffRepositoryWrapper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/domain/StaffRepositoryWrapper.java @@ -44,4 +44,7 @@ public class StaffRepositoryWrapper { if (!hierarchy.startsWith(staffhierarchy)) { throw new StaffNotFoundException(staffId); } return staff; } + public void save(final Staff staff){ + this.repository.save(staff); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/resources/sql/migrations/core_db/V256__staff_image_association.sql b/mifosng-provider/src/main/resources/sql/migrations/core_db/V256__staff_image_association.sql new file mode 100644 index 000000000..8d1bcfe17 --- /dev/null +++ b/mifosng-provider/src/main/resources/sql/migrations/core_db/V256__staff_image_association.sql @@ -0,0 +1 @@ +ALTER TABLE `m_staff` ADD COLUMN `image_id` BIGINT(20) NULL; \ No newline at end of file