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
+
+ - Data URI's:
+ For easier manipulation by Javascript clients etc in supported Browsers.
+
+ -
+ Multi-part form data:
+ Images can be uploaded using Multi part forms and downloaded as regular binary files
+
+
+
+
+
+
+
+
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