diff --git a/mifosng-db/patches/00005_client_image_location.sql b/mifosng-db/patches/00005_client_image_location.sql new file mode 100644 index 000000000..3c6f33982 --- /dev/null +++ b/mifosng-db/patches/00005_client_image_location.sql @@ -0,0 +1,2 @@ +ALTER TABLE `m_client` + ADD COLUMN `image_key` VARCHAR(500) NULL DEFAULT NULL AFTER `display_name`; \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/ClientsApiResource.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/ClientsApiResource.java index 21662719e..cf28c9241 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/ClientsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/ClientsApiResource.java @@ -1,5 +1,6 @@ package org.mifosng.platform.api; +import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -9,6 +10,7 @@ import java.util.Set; 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; @@ -23,8 +25,8 @@ import javax.ws.rs.core.UriInfo; import org.apache.commons.lang.StringUtils; import org.mifosng.platform.api.commands.ClientCommand; import org.mifosng.platform.api.commands.NoteCommand; -import org.mifosng.platform.api.data.ClientData; import org.mifosng.platform.api.data.ClientAccountSummaryCollectionData; +import org.mifosng.platform.api.data.ClientData; import org.mifosng.platform.api.data.EntityIdentifier; import org.mifosng.platform.api.data.NoteData; import org.mifosng.platform.api.data.OfficeLookup; @@ -33,6 +35,10 @@ import org.mifosng.platform.api.infrastructure.ApiJsonSerializerService; import org.mifosng.platform.api.infrastructure.ApiParameterHelper; import org.mifosng.platform.client.service.ClientReadPlatformService; import org.mifosng.platform.client.service.ClientWritePlatformService; +import org.mifosng.platform.common.ApplicationConstants; +import org.mifosng.platform.common.FileUtils; +import org.mifosng.platform.exceptions.ClientNotFoundException; +import org.mifosng.platform.exceptions.ImageNotFoundException; import org.mifosng.platform.organisation.service.OfficeReadPlatformService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,6 +46,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; +import com.lowagie.text.pdf.codec.Base64; +import com.sun.jersey.core.header.FormDataContentDisposition; +import com.sun.jersey.multipart.FormDataBodyPart; +import com.sun.jersey.multipart.FormDataParam; + @Path("/clients") @Component @Scope("singleton") @@ -63,7 +74,7 @@ public class ClientsApiResource { private ApiJsonSerializerService apiJsonSerializerService; private static final Set typicalResponseParameters = new HashSet( - Arrays.asList("id", "officeId", "officeName", "externalId", "firstname", "lastname", "joinedDate", "displayName", "clientOrBusinessName") + Arrays.asList("id", "officeId", "officeName", "externalId", "firstname", "lastname", "joinedDate", "displayName", "clientOrBusinessName", "imagePresent") ); @GET @@ -313,4 +324,93 @@ public class ClientsApiResource { return Response.ok().entity(identifier).build(); } + + @POST + @Path("{clientId}/image") + @Consumes({ MediaType.MULTIPART_FORM_DATA }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response addNewClientImage( + @PathParam("clientId") final Long clientId, + @HeaderParam("Content-Length") Long fileSize, + @FormDataParam("file") InputStream inputStream, + @FormDataParam("file") FormDataContentDisposition fileDetails, + @FormDataParam("file") FormDataBodyPart bodyPart) { + + + //TODO: vishwas might need more advances validation (like reading magic number) for handling malicious clients + //and clients not setting mime type + FileUtils.validateClientImageNotEmpty(fileDetails.getFileName()); + FileUtils.validateImageMimeType(bodyPart.getMediaType().toString()); + FileUtils.validateFileSizeWithinPermissibleRange(fileSize, + fileDetails.getFileName(), + ApplicationConstants.MAX_FILE_UPLOAD_SIZE_IN_MB); + + System.out.println( bodyPart.getMediaType().toString()); + + EntityIdentifier entityIdentifier = this.clientWritePlatformService + .saveOrUpdateClientImage(clientId, fileDetails.getFileName(), + inputStream); + + // return identifier of the client whose image was updated + return Response.ok().entity(entityIdentifier).build(); + + } + + /**Returns a base 64 encoded client image + * @param clientId + * @return + */ + @GET + @Path("{clientId}/image") + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) + public Response retrieveClientImage( + @PathParam("clientId") final Long clientId) { + + ClientData clientData = this.clientReadPlatformService.retrieveIndividualClient(clientId); + //validate if client does not exist or image key is null + if(clientData == null){ + throw new ClientNotFoundException(clientId); + } + else if(clientData.getImageKey()== null){ + throw new ImageNotFoundException(ApplicationConstants.IMAGE_MANAGEMENT_ENTITY.CLIENTS, clientId); + } + return Response.ok().entity(Base64.encodeFromFile(clientData.getImageKey())).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 + * + * @param clientId + * @param fileSize + * @param inputStream + * @param fileDetails + * @param bodyPart + * @return + */ + @PUT + @Path("{clientId}/image") + @Consumes({ MediaType.MULTIPART_FORM_DATA }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response updateClientImage( + @PathParam("clientId") final Long clientId, + @HeaderParam("Content-Length") Long fileSize, + @FormDataParam("file") InputStream inputStream, + @FormDataParam("file") FormDataContentDisposition fileDetails, + @FormDataParam("file") FormDataBodyPart bodyPart) { + return addNewClientImage(clientId, fileSize, inputStream, fileDetails, + bodyPart); + } + + @DELETE + @Path("{clientId}/image") + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) + public Response deleteClientImage(@PathParam("clientId") final Long clientId) { + this.clientWritePlatformService.deleteClientImage(clientId); + return Response.ok(new EntityIdentifier(clientId)).build(); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/DocumentManagementApiResource.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/DocumentManagementApiResource.java index fcad27e63..e58f0d045 100755 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/DocumentManagementApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/DocumentManagementApiResource.java @@ -28,9 +28,9 @@ import org.mifosng.platform.api.data.EntityIdentifier; import org.mifosng.platform.api.infrastructure.ApiJsonSerializerService; import org.mifosng.platform.api.infrastructure.ApiParameterHelper; import org.mifosng.platform.common.ApplicationConstants; +import org.mifosng.platform.common.FileUtils; import org.mifosng.platform.documentmanagement.service.DocumentReadPlatformService; import org.mifosng.platform.documentmanagement.service.DocumentWritePlatformService; -import org.mifosng.platform.exceptions.DocumentManagementException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @@ -109,7 +109,7 @@ public class DocumentManagementApiResource { @FormDataParam("name") String name, @FormDataParam("description") String description) { - initialFileCheckerFastFail(fileSize, name); + FileUtils.validateFileSizeWithinPermissibleRange(fileSize, name, ApplicationConstants.MAX_FILE_UPLOAD_SIZE_IN_MB); /** * TODO: also need to have a backup and stop reading from stream after @@ -117,7 +117,7 @@ public class DocumentManagementApiResource { **/ /** - * TODO: need to extract the actual file type and determine fi they are + * TODO: need to extract the actual file type and determine if they are * permissable **/ DocumentCommand documentCommand = new DocumentCommand(null, null, @@ -156,7 +156,7 @@ public class DocumentManagementApiResource { @FormDataParam("name") String name, @FormDataParam("description") String description) { - initialFileCheckerFastFail(fileSize, name); + FileUtils.validateFileSizeWithinPermissibleRange(fileSize, name, ApplicationConstants.MAX_FILE_UPLOAD_SIZE_IN_MB); Set modifiedParams = new HashSet(); modifiedParams.add("name"); @@ -187,22 +187,6 @@ public class DocumentManagementApiResource { return Response.ok().entity(identifier).build(); } - /** - * @param fileSize - * @param name - */ - private void initialFileCheckerFastFail(Long fileSize, String name) { - /** - * Using Content-Length gives me size of the entire request, which is - * good enough for now for a fast fail as the length of the rest of the - * content i.e name and description while compared to the uploaded file - * size is negligible - **/ - if (fileSize != null - && ((fileSize / (1024 * 1024)) > ApplicationConstants.MAX_FILE_UPLOAD_SIZE_IN_MB)) { - throw new DocumentManagementException(name, fileSize); - } - } /** * @param entityType diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/ClientData.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/ClientData.java index 58f78e4ce..cc23535c2 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/ClientData.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/ClientData.java @@ -20,6 +20,8 @@ public class ClientData { private final String officeName; private final String externalId; private final LocalDate joinedDate; + private final String imageKey; + private boolean imagePresent; private List allowedOffices = new ArrayList(); @@ -36,13 +38,14 @@ public class ClientData { } displayNameBuilder.append(lastname); - return new ClientData(officeId, officeName, id, firstname, lastname, displayNameBuilder.toString(), null, null); + return new ClientData(officeId, officeName, id, firstname, lastname, displayNameBuilder.toString(), null, null, null); } public ClientData(final Long officeId, final String officeName, final Long id, final String firstname, final String lastname, final String displayName, final String externalId, - final LocalDate joinedDate) { + final LocalDate joinedDate, + final String imageKey) { this.officeId = officeId; this.officeName = officeName; this.id = id; @@ -60,6 +63,13 @@ public class ClientData { this.externalId = externalId; this.joinedDate = joinedDate; + this.imageKey = imageKey; + if (imageKey == null) { + imagePresent = false; + }else{ + imagePresent = true; + } + } public ClientData(final Long officeId, final LocalDate joinedDate, @@ -74,6 +84,7 @@ public class ClientData { this.externalId = null; this.joinedDate = joinedDate; this.allowedOffices = offices; + this.imageKey = null; } public Long getId() { @@ -127,4 +138,20 @@ public class ClientData { public String officeName() { return this.officeName; } + + public String getImageKey() { + return imageKey; + } + + public boolean isImagePresent() { + return imagePresent; + } + + public void setImagePresent(boolean imagePresent) { + this.imagePresent = imagePresent; + } + + + + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/GoogleGsonApiJsonSerializerService.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/GoogleGsonApiJsonSerializerService.java index 1e80edc46..08cbcdcaa 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/GoogleGsonApiJsonSerializerService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/GoogleGsonApiJsonSerializerService.java @@ -122,7 +122,7 @@ public class GoogleGsonApiJsonSerializerService implements ApiJsonSerializerServ private static final Set CLIENT_DATA_PARAMETERS = new HashSet( Arrays.asList("id", "officeId", "officeName", "externalId", "firstname", "lastname", "joinedDate", "displayName", - "clientOrBusinessName", "allowedOffices")); + "clientOrBusinessName", "allowedOffices", "imagePresent")); private static final Set CLIENT_IDENTIFIER_DATA_PARAMETERS = new HashSet( Arrays.asList("id", "clientId", "documentTypeId", "documentKey", diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/client/domain/Client.java b/mifosng-provider/src/main/java/org/mifosng/platform/client/domain/Client.java index 8e900df59..5b1bb95f9 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/client/domain/Client.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/client/domain/Client.java @@ -43,6 +43,9 @@ public class Client extends AbstractAuditableCustom { @Column(name = "is_deleted", nullable=false) private boolean deleted = false; + + @Column(name = "image_key", length=500) + private String imageKey; public static Client newClient(Office clientOffice, String firstname, String lastname, LocalDate joiningDate, String externalId) { return new Client(clientOffice, firstname, lastname, joiningDate, externalId); @@ -207,6 +210,16 @@ public class Client extends AbstractAuditableCustom { public void setDeleted(boolean deleted) { this.deleted = deleted; } + + public String getImageKey() { + return imageKey; + } + + public void setImageKey(String imageKey) { + this.imageKey = imageKey; + } + + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientReadPlatformServiceImpl.java index 5ed3f4a22..8c8a07797 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientReadPlatformServiceImpl.java @@ -143,7 +143,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService public String clientSchema() { return "c.office_id as officeId, o.name as officeName, c.id as id, c.firstname as firstname, c.lastname as lastname, c.display_name as displayName, " + - "c.external_id as externalId, c.joining_date as joinedDate from m_client c join m_office o on o.id = c.office_id " + + "c.external_id as externalId, c.joining_date as joinedDate, c.image_key as imagekey from m_client c join m_office o on o.id = c.office_id " + " where o.hierarchy like ? and c.is_deleted=0 "; } @@ -161,11 +161,12 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService String displayName = rs.getString("displayName"); String externalId = rs.getString("externalId"); LocalDate joinedDate = JdbcSupport.getLocalDate(rs, "joinedDate"); + String imageKey = rs.getString("imageKey"); String officeName = rs.getString("officeName"); return new ClientData(officeId, officeName, id, firstname, - lastname, displayName, externalId, joinedDate); + lastname, displayName, externalId, joinedDate,imageKey); } } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientWritePlatformService.java index b06ee6703..493e4d6f3 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientWritePlatformService.java @@ -1,5 +1,7 @@ package org.mifosng.platform.client.service; +import java.io.InputStream; + import org.mifosng.platform.api.commands.ClientCommand; import org.mifosng.platform.api.commands.ClientIdentifierCommand; import org.mifosng.platform.api.commands.NoteCommand; @@ -13,6 +15,12 @@ public interface ClientWritePlatformService { @PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE')") EntityIdentifier updateClientDetails(ClientCommand command); + + @PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE')") + EntityIdentifier saveOrUpdateClientImage(Long clientId, String imageName, InputStream inputStream); + + @PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE')") + EntityIdentifier deleteClientImage(Long clientId); @PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE')") EntityIdentifier addClientNote(NoteCommand command); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java index 2107a6bc6..213885840 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java @@ -1,5 +1,9 @@ package org.mifosng.platform.client.service; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + import org.apache.commons.lang.StringUtils; import org.mifosng.platform.api.commands.ClientCommand; import org.mifosng.platform.api.commands.ClientIdentifierCommand; @@ -11,9 +15,12 @@ import org.mifosng.platform.client.domain.ClientIdentifierRepository; import org.mifosng.platform.client.domain.ClientRepository; import org.mifosng.platform.client.domain.Note; import org.mifosng.platform.client.domain.NoteRepository; +import org.mifosng.platform.common.ApplicationConstants; +import org.mifosng.platform.common.FileUtils; import org.mifosng.platform.exceptions.ClientIdentifierNotFoundException; import org.mifosng.platform.exceptions.ClientNotFoundException; import org.mifosng.platform.exceptions.CodeValueNotFoundException; +import org.mifosng.platform.exceptions.DocumentManagementException; import org.mifosng.platform.exceptions.DuplicateClientIdentifierException; import org.mifosng.platform.exceptions.NoteNotFoundException; import org.mifosng.platform.exceptions.OfficeNotFoundException; @@ -319,4 +326,65 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP return new EntityIdentifier(clientIdentifierId); } + + @Transactional + @Override + public EntityIdentifier saveOrUpdateClientImage(Long clientId, + String imageName, InputStream inputStream) { + try { + final Client client = this.clientRepository.findOne(clientId); + 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(); + } + + String imageLocation = FileUtils.saveToFileSystem(inputStream, + imageUploadLocation, imageName); + + + client.setImageKey(imageLocation); + this.clientRepository.save(client); + + return new EntityIdentifier(clientId); + } catch (IOException ioe) { + logger.error(ioe.getMessage(), ioe); + throw new DocumentManagementException(imageName); + } + } + + @Transactional + @Override + public EntityIdentifier deleteClientImage(Long clientId) { + final Client client = this.clientRepository.findOne(clientId); + if (client == null || client.isDeleted()) { + throw new ClientNotFoundException(clientId); + } + // delete image from the file system + if (StringUtils.isNotEmpty(client.getImageKey())) { + FileUtils.deleteImage( + ApplicationConstants.IMAGE_MANAGEMENT_ENTITY.CLIENTS, + clientId, client.getImageKey()); + } + client.setImageKey(null); + this.clientRepository.save(client); + return new EntityIdentifier(clientId); + } + + + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/common/ApplicationConstants.java b/mifosng-provider/src/main/java/org/mifosng/platform/common/ApplicationConstants.java index 2cde551ec..161b482a1 100755 --- a/mifosng-provider/src/main/java/org/mifosng/platform/common/ApplicationConstants.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/common/ApplicationConstants.java @@ -7,8 +7,11 @@ public class ApplicationConstants { // TODO:Vishwas Need to move these settings to the Database public static final Integer MAX_FILE_UPLOAD_SIZE_IN_MB = 5; + // TODO:Vishwas Need to move these settings to the Database + public static final Integer MAX_IMAGE_UPLOAD_SIZE_IN_MB = 1; + /*** Entities for document Management **/ - public static enum DOCUMENT_MANAGEMENT_ENTITIES { + public static enum DOCUMENT_MANAGEMENT_ENTITY { CLIENTS, CLIENT_IDENTIFIERS, STAFF, LOANS, SAVINGS; @Override public String toString() { @@ -16,4 +19,13 @@ public class ApplicationConstants { } } + /*** Entities for image Management **/ + public static enum IMAGE_MANAGEMENT_ENTITY { + CLIENTS, STAFF; + @Override + public String toString() { + return name().toString().toLowerCase(); + } + } + } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/common/FileUtils.java b/mifosng-provider/src/main/java/org/mifosng/platform/common/FileUtils.java index 7dc985503..fd0563346 100755 --- a/mifosng-provider/src/main/java/org/mifosng/platform/common/FileUtils.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/common/FileUtils.java @@ -5,12 +5,23 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; import java.util.Random; +import org.mifosng.platform.api.data.ApiParameterError; +import org.mifosng.platform.exceptions.DocumentManagementException; +import org.mifosng.platform.exceptions.ImageUploadException; +import org.mifosng.platform.exceptions.PlatformApiDataValidationException; import org.mifosng.platform.infrastructure.ThreadLocalContextUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class FileUtils { + private final static Logger logger = LoggerFactory + .getLogger(FileUtils.class); + public static final String MIFOSX_BASE_DIR = System .getProperty("user.home") + File.separator + ".mifosx"; @@ -42,7 +53,7 @@ public class FileUtils { } /** - * Generate the directory path for storing the new document Type + * Generate the directory path for storing the new document * * @param entityType * @param entityId @@ -54,8 +65,26 @@ public class FileUtils { + File.separator + ThreadLocalContextUtil.getTenant().getName() .replaceAll(" ", "").trim() + File.separator - + entityType + File.separator + entityId + File.separator - + FileUtils.generateRandomString(); + + "documents" + File.separator + entityType + File.separator + + entityId + File.separator + FileUtils.generateRandomString(); + } + + /** + * Generate directory path for storing new Image + * + * @param entityType + * @param entityId + * @return + */ + public static String generateImageParentDirectory( + ApplicationConstants.IMAGE_MANAGEMENT_ENTITY entityType, + Long entityId) { + return FileUtils.MIFOSX_BASE_DIR + + File.separator + + ThreadLocalContextUtil.getTenant().getName() + .replaceAll(" ", "").trim() + File.separator + "images" + + File.separator + entityType.toString() + File.separator + + entityId; } /** @@ -78,4 +107,69 @@ public class FileUtils { out.close(); return fileLocation; } + + /** + * @param fileSize + * @param name + */ + public static void validateFileSizeWithinPermissibleRange(Long fileSize, + String name, int maxFileSize) { + /** + * Using Content-Length gives me size of the entire request, which is + * good enough for now for a fast fail as the length of the rest of the + * content i.e name and description while compared to the uploaded file + * size is negligible + **/ + if (fileSize != null && ((fileSize / (1024 * 1024)) > maxFileSize)) { + throw new DocumentManagementException(name, fileSize, maxFileSize); + } + } + + /** + * Validates that passed in Mime type maps to known image mime types + * + * @param mimeType + */ + public static void validateImageMimeType(String mimeType) { + if (!(mimeType.equalsIgnoreCase("image/gif") + || mimeType.equalsIgnoreCase("image/jpeg") || mimeType + .equalsIgnoreCase("image/png"))) { + throw new ImageUploadException(); + } + } + + + public static void validateClientImageNotEmpty(String imageFileName) { + List dataValidationErrors = new ArrayList(); + if (imageFileName == null) { + StringBuilder validationErrorCode = new StringBuilder( + "validation.msg.clientImage.cannot.be.blank"); + StringBuilder defaultEnglishMessage = new StringBuilder( + "The parameter image cannot be blank."); + ApiParameterError error = ApiParameterError.parameterError( + validationErrorCode.toString(), + defaultEnglishMessage.toString(), "image"); + dataValidationErrors.add(error); + throw new PlatformApiDataValidationException( + "validation.msg.validation.errors.exist", + "Validation errors exist.", dataValidationErrors); + } + } + + /** + * @param entityType + * @param entityId + * @param location + */ + public static void deleteImage( + ApplicationConstants.IMAGE_MANAGEMENT_ENTITY entityType, + Long entityId, String location) { + File fileToBeDeleted = new File(location); + boolean fileDeleted = fileToBeDeleted.delete(); + if (!fileDeleted) { + // no need to throw an Error, simply log a warning + logger.warn("Unable to delete image associated with " + + entityType.toString() + " with Id " + entityId); + } + } } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentWritePlatformServiceJpaRepositoryImpl.java index 955866990..cc2eedeee 100755 --- a/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentWritePlatformServiceJpaRepositoryImpl.java @@ -193,7 +193,7 @@ public class DocumentWritePlatformServiceJpaRepositoryImpl implements } private static boolean checkValidEntityType(String entityType) { - for (ApplicationConstants.DOCUMENT_MANAGEMENT_ENTITIES entities : ApplicationConstants.DOCUMENT_MANAGEMENT_ENTITIES + for (ApplicationConstants.DOCUMENT_MANAGEMENT_ENTITY entities : ApplicationConstants.DOCUMENT_MANAGEMENT_ENTITY .values()) { if (entities.name().equalsIgnoreCase(entityType)) { return true; diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/DocumentManagementException.java b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/DocumentManagementException.java index 8278569f5..ffeb686ce 100755 --- a/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/DocumentManagementException.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/DocumentManagementException.java @@ -1,6 +1,5 @@ package org.mifosng.platform.exceptions; -import org.mifosng.platform.common.ApplicationConstants; public class DocumentManagementException extends AbstractPlatformDomainRuleException { @@ -10,12 +9,13 @@ public class DocumentManagementException extends + name + " due to a File system / Amazon S3 issue", name); } - public DocumentManagementException(final String name, final Long fileSize) { + public DocumentManagementException(final String name, final Long fileSize, + final int maxFileSize) { super("error.msg.document.file.too.big", "Unable to save the document with name" + name + " since its file Size of " + fileSize / (1024 * 1024) + " MB exceeds the max permissable file size of " - + ApplicationConstants.MAX_FILE_UPLOAD_SIZE_IN_MB + + maxFileSize + " MB", name, fileSize); } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/ImageNotFoundException.java b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/ImageNotFoundException.java new file mode 100644 index 000000000..6cfad41c6 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/ImageNotFoundException.java @@ -0,0 +1,15 @@ +package org.mifosng.platform.exceptions; + +import org.mifosng.platform.common.ApplicationConstants; + +public class ImageNotFoundException extends AbstractPlatformDomainRuleException { + + public ImageNotFoundException( + ApplicationConstants.IMAGE_MANAGEMENT_ENTITY entityType, + Long entityId) { + super("error.msg.entity.image.invalid", "Image for entity " + + entityType.toString() + " with Identifier " + entityId + + " does not exist", entityType.toString(), entityId); + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/ImageUploadException.java b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/ImageUploadException.java new file mode 100644 index 000000000..51dc4212b --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/ImageUploadException.java @@ -0,0 +1,10 @@ +package org.mifosng.platform.exceptions; + +public class ImageUploadException extends AbstractPlatformDomainRuleException { + + public ImageUploadException() { + super("error.msg.image.type.upload", + "Only image files of type GIF,PNG and JPG are allowed "); + } + +}