Adding new image upload services for Data URLs (Webcam integration)
This commit is contained in:
@@ -35,6 +35,7 @@ import org.mifosng.platform.api.infrastructure.PortfolioApiJsonSerializerService
|
|||||||
import org.mifosng.platform.client.service.ClientReadPlatformService;
|
import org.mifosng.platform.client.service.ClientReadPlatformService;
|
||||||
import org.mifosng.platform.client.service.ClientWritePlatformService;
|
import org.mifosng.platform.client.service.ClientWritePlatformService;
|
||||||
import org.mifosng.platform.common.ApplicationConstants;
|
import org.mifosng.platform.common.ApplicationConstants;
|
||||||
|
import org.mifosng.platform.common.Base64EncodedImage;
|
||||||
import org.mifosng.platform.common.FileUtils;
|
import org.mifosng.platform.common.FileUtils;
|
||||||
import org.mifosng.platform.exceptions.ClientNotFoundException;
|
import org.mifosng.platform.exceptions.ClientNotFoundException;
|
||||||
import org.mifosng.platform.exceptions.ImageNotFoundException;
|
import org.mifosng.platform.exceptions.ImageNotFoundException;
|
||||||
@@ -325,6 +326,14 @@ public class ClientsApiResource {
|
|||||||
return Response.ok().entity(identifier).build();
|
return Response.ok().entity(identifier).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Upload images through multi-part form upload
|
||||||
|
* @param clientId
|
||||||
|
* @param fileSize
|
||||||
|
* @param inputStream
|
||||||
|
* @param fileDetails
|
||||||
|
* @param bodyPart
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
@POST
|
@POST
|
||||||
@Path("{clientId}/image")
|
@Path("{clientId}/image")
|
||||||
@Consumes({ MediaType.MULTIPART_FORM_DATA })
|
@Consumes({ MediaType.MULTIPART_FORM_DATA })
|
||||||
@@ -355,8 +364,33 @@ public class ClientsApiResource {
|
|||||||
return Response.ok().entity(entityIdentifier).build();
|
return Response.ok().entity(entityIdentifier).build();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**Returns a base 64 encoded client image
|
/** Upload image as a Data URL (essentially a base64 encoded stream)
|
||||||
|
* @param clientId
|
||||||
|
* @param jsonRequestBody
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@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 identifier of the client whose image was updated
|
||||||
|
return Response.ok().entity(entityIdentifier).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a base 64 encoded client image
|
||||||
* @param clientId
|
* @param clientId
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@@ -413,4 +447,25 @@ public class ClientsApiResource {
|
|||||||
this.clientWritePlatformService.deleteClientImage(clientId);
|
this.clientWritePlatformService.deleteClientImage(clientId);
|
||||||
return Response.ok(new EntityIdentifier(clientId)).build();
|
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)
|
||||||
|
* @param clientId
|
||||||
|
* @param jsonRequestBody
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+4
@@ -6,6 +6,7 @@ import org.mifosng.platform.api.commands.ClientCommand;
|
|||||||
import org.mifosng.platform.api.commands.ClientIdentifierCommand;
|
import org.mifosng.platform.api.commands.ClientIdentifierCommand;
|
||||||
import org.mifosng.platform.api.commands.NoteCommand;
|
import org.mifosng.platform.api.commands.NoteCommand;
|
||||||
import org.mifosng.platform.api.data.EntityIdentifier;
|
import org.mifosng.platform.api.data.EntityIdentifier;
|
||||||
|
import org.mifosng.platform.common.Base64EncodedImage;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
|
||||||
public interface ClientWritePlatformService {
|
public interface ClientWritePlatformService {
|
||||||
@@ -19,6 +20,9 @@ public interface ClientWritePlatformService {
|
|||||||
@PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE')")
|
@PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE')")
|
||||||
EntityIdentifier saveOrUpdateClientImage(Long clientId, String imageName, InputStream inputStream);
|
EntityIdentifier saveOrUpdateClientImage(Long clientId, String imageName, InputStream inputStream);
|
||||||
|
|
||||||
|
@PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE')")
|
||||||
|
EntityIdentifier saveOrUpdateClientImage(Long clientId, Base64EncodedImage encodedImage);
|
||||||
|
|
||||||
@PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE')")
|
@PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE')")
|
||||||
EntityIdentifier deleteClientImage(Long clientId);
|
EntityIdentifier deleteClientImage(Long clientId);
|
||||||
|
|
||||||
|
|||||||
+63
-24
@@ -16,6 +16,7 @@ import org.mifosng.platform.client.domain.ClientRepository;
|
|||||||
import org.mifosng.platform.client.domain.Note;
|
import org.mifosng.platform.client.domain.Note;
|
||||||
import org.mifosng.platform.client.domain.NoteRepository;
|
import org.mifosng.platform.client.domain.NoteRepository;
|
||||||
import org.mifosng.platform.common.ApplicationConstants;
|
import org.mifosng.platform.common.ApplicationConstants;
|
||||||
|
import org.mifosng.platform.common.Base64EncodedImage;
|
||||||
import org.mifosng.platform.common.FileUtils;
|
import org.mifosng.platform.common.FileUtils;
|
||||||
import org.mifosng.platform.exceptions.ClientIdentifierNotFoundException;
|
import org.mifosng.platform.exceptions.ClientIdentifierNotFoundException;
|
||||||
import org.mifosng.platform.exceptions.ClientNotFoundException;
|
import org.mifosng.platform.exceptions.ClientNotFoundException;
|
||||||
@@ -333,34 +334,14 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
|||||||
String imageName, InputStream inputStream) {
|
String imageName, InputStream inputStream) {
|
||||||
try {
|
try {
|
||||||
final Client client = this.clientRepository.findOne(clientId);
|
final Client client = this.clientRepository.findOne(clientId);
|
||||||
if (client == null || client.isDeleted()) {
|
String imageUploadLocation = setupForClientImageUpdate(clientId,
|
||||||
throw new ClientNotFoundException(clientId);
|
client);
|
||||||
}
|
|
||||||
|
|
||||||
String imageUploadLocation = FileUtils
|
|
||||||
.generateImageParentDirectory(
|
|
||||||
ApplicationConstants.IMAGE_MANAGEMENT_ENTITY.CLIENTS,
|
|
||||||
clientId);
|
|
||||||
// delete previous image from the file system
|
|
||||||
if (StringUtils.isNotEmpty(client.getImageKey())) {
|
|
||||||
FileUtils.deleteImage(
|
|
||||||
ApplicationConstants.IMAGE_MANAGEMENT_ENTITY.CLIENTS,
|
|
||||||
clientId, client.getImageKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Recursively create the directory if it does not exist **/
|
|
||||||
if (!new File(imageUploadLocation).isDirectory()) {
|
|
||||||
new File(imageUploadLocation).mkdirs();
|
|
||||||
}
|
|
||||||
|
|
||||||
String imageLocation = FileUtils.saveToFileSystem(inputStream,
|
String imageLocation = FileUtils.saveToFileSystem(inputStream,
|
||||||
imageUploadLocation, imageName);
|
imageUploadLocation, imageName);
|
||||||
|
|
||||||
|
|
||||||
client.setImageKey(imageLocation);
|
return updateClientImage(clientId, client, imageLocation);
|
||||||
this.clientRepository.save(client);
|
|
||||||
|
|
||||||
return new EntityIdentifier(clientId);
|
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
logger.error(ioe.getMessage(), ioe);
|
logger.error(ioe.getMessage(), ioe);
|
||||||
throw new DocumentManagementException(imageName);
|
throw new DocumentManagementException(imageName);
|
||||||
@@ -380,8 +361,66 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
|||||||
ApplicationConstants.IMAGE_MANAGEMENT_ENTITY.CLIENTS,
|
ApplicationConstants.IMAGE_MANAGEMENT_ENTITY.CLIENTS,
|
||||||
clientId, client.getImageKey());
|
clientId, client.getImageKey());
|
||||||
}
|
}
|
||||||
client.setImageKey(null);
|
return updateClientImage(clientId, client, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityIdentifier saveOrUpdateClientImage(Long clientId,
|
||||||
|
Base64EncodedImage encodedImage) {
|
||||||
|
try {
|
||||||
|
final Client client = this.clientRepository.findOne(clientId);
|
||||||
|
String imageUploadLocation = setupForClientImageUpdate(clientId,
|
||||||
|
client);
|
||||||
|
|
||||||
|
String imageLocation = FileUtils.saveToFileSystem(encodedImage, imageUploadLocation, "image");
|
||||||
|
|
||||||
|
return updateClientImage(clientId, client, imageLocation);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
logger.error(ioe.getMessage(), ioe);
|
||||||
|
throw new DocumentManagementException("image");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param clientId
|
||||||
|
* @param client
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String setupForClientImageUpdate(Long clientId, final Client client) {
|
||||||
|
if (client == null || client.isDeleted()) {
|
||||||
|
throw new ClientNotFoundException(clientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
String imageUploadLocation = FileUtils
|
||||||
|
.generateImageParentDirectory(
|
||||||
|
ApplicationConstants.IMAGE_MANAGEMENT_ENTITY.CLIENTS,
|
||||||
|
clientId);
|
||||||
|
// delete previous image from the file system
|
||||||
|
if (StringUtils.isNotEmpty(client.getImageKey())) {
|
||||||
|
FileUtils.deleteImage(
|
||||||
|
ApplicationConstants.IMAGE_MANAGEMENT_ENTITY.CLIENTS,
|
||||||
|
clientId, client.getImageKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Recursively create the directory if it does not exist **/
|
||||||
|
if (!new File(imageUploadLocation).isDirectory()) {
|
||||||
|
new File(imageUploadLocation).mkdirs();
|
||||||
|
}
|
||||||
|
return imageUploadLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param clientId
|
||||||
|
* @param client
|
||||||
|
* @param imageLocation
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private EntityIdentifier updateClientImage(Long clientId,
|
||||||
|
final Client client, String imageLocation) {
|
||||||
|
client.setImageKey(imageLocation);
|
||||||
this.clientRepository.save(client);
|
this.clientRepository.save(client);
|
||||||
|
|
||||||
return new EntityIdentifier(clientId);
|
return new EntityIdentifier(clientId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
package org.mifosng.platform.common;
|
||||||
|
|
||||||
|
public class Base64EncodedImage {
|
||||||
|
|
||||||
|
private final String base64EncodedString;
|
||||||
|
private final String fileExtension;
|
||||||
|
|
||||||
|
public Base64EncodedImage(String base64EncodedString, String fileExtension) {
|
||||||
|
this.base64EncodedString = base64EncodedString;
|
||||||
|
this.fileExtension = fileExtension;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBase64EncodedString() {
|
||||||
|
return base64EncodedString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFileExtension() {
|
||||||
|
return fileExtension;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -11,12 +11,15 @@ import java.util.Random;
|
|||||||
|
|
||||||
import org.mifosng.platform.api.data.ApiParameterError;
|
import org.mifosng.platform.api.data.ApiParameterError;
|
||||||
import org.mifosng.platform.exceptions.DocumentManagementException;
|
import org.mifosng.platform.exceptions.DocumentManagementException;
|
||||||
|
import org.mifosng.platform.exceptions.ImageDataURLNotValidException;
|
||||||
import org.mifosng.platform.exceptions.ImageUploadException;
|
import org.mifosng.platform.exceptions.ImageUploadException;
|
||||||
import org.mifosng.platform.exceptions.PlatformApiDataValidationException;
|
import org.mifosng.platform.exceptions.PlatformApiDataValidationException;
|
||||||
import org.mifosng.platform.infrastructure.ThreadLocalContextUtil;
|
import org.mifosng.platform.infrastructure.ThreadLocalContextUtil;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.lowagie.text.pdf.codec.Base64;
|
||||||
|
|
||||||
public class FileUtils {
|
public class FileUtils {
|
||||||
|
|
||||||
private final static Logger logger = LoggerFactory
|
private final static Logger logger = LoggerFactory
|
||||||
@@ -107,6 +110,25 @@ public class FileUtils {
|
|||||||
out.close();
|
out.close();
|
||||||
return fileLocation;
|
return fileLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param base64EncodedImage
|
||||||
|
* @param uploadedFileLocation
|
||||||
|
* @param fileName
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static String saveToFileSystem(Base64EncodedImage base64EncodedImage,
|
||||||
|
String uploadedFileLocation, String fileName) throws IOException {
|
||||||
|
String fileLocation = uploadedFileLocation + File.separator + fileName + base64EncodedImage.getFileExtension();
|
||||||
|
OutputStream out = new FileOutputStream(new File(fileLocation));
|
||||||
|
byte[] imgBytes = Base64.decode(base64EncodedImage.getBase64EncodedString());
|
||||||
|
out.write(imgBytes);
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
return fileLocation;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param fileSize
|
* @param fileSize
|
||||||
@@ -137,8 +159,35 @@ public class FileUtils {
|
|||||||
throw new ImageUploadException();
|
throw new ImageUploadException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts Image from a Data URL
|
||||||
|
*
|
||||||
|
* @param mimeType
|
||||||
|
*/
|
||||||
|
public static Base64EncodedImage extractImageFromDataURL(String dataURL) {
|
||||||
|
String fileExtension = "";
|
||||||
|
String base64EncodedString = null;
|
||||||
|
String gifDataURLSnippet = "data:image/gif;base64,";
|
||||||
|
String pngDataURLSnippet = "data:image/png;base64,";
|
||||||
|
String jpegDataURLSnippet = "data:image/jpeg;base64,";
|
||||||
|
|
||||||
|
if (dataURL.contains(gifDataURLSnippet)) {
|
||||||
|
base64EncodedString = dataURL.replaceAll(gifDataURLSnippet, "");
|
||||||
|
fileExtension = ".gif";
|
||||||
|
} else if (dataURL.contains(pngDataURLSnippet)) {
|
||||||
|
base64EncodedString = dataURL.replaceAll(pngDataURLSnippet, "");
|
||||||
|
fileExtension = ".png";
|
||||||
|
} else if (dataURL.contains(jpegDataURLSnippet)) {
|
||||||
|
base64EncodedString = dataURL.replaceAll(jpegDataURLSnippet, "");
|
||||||
|
fileExtension = ".jpeg";
|
||||||
|
} else {
|
||||||
|
throw new ImageDataURLNotValidException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Base64EncodedImage(base64EncodedString, fileExtension);
|
||||||
|
}
|
||||||
|
|
||||||
public static void validateClientImageNotEmpty(String imageFileName) {
|
public static void validateClientImageNotEmpty(String imageFileName) {
|
||||||
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
if (imageFileName == null) {
|
if (imageFileName == null) {
|
||||||
|
|||||||
Executable
+11
@@ -0,0 +1,11 @@
|
|||||||
|
package org.mifosng.platform.exceptions;
|
||||||
|
|
||||||
|
public class ImageDataURLNotValidException extends
|
||||||
|
AbstractPlatformDomainRuleException {
|
||||||
|
|
||||||
|
public ImageDataURLNotValidException() {
|
||||||
|
super("error.msg.dataURL.save",
|
||||||
|
"Only GIF, PNG and JPEG Data URL's are allowed");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user