initials files for client image management.

This commit is contained in:
Vishwas Babu AJ
2012-10-28 14:43:33 +00:00
committed by Keith Woodlock
parent 3d5c0d88c0
commit 2325878e4e
15 changed files with 369 additions and 35 deletions
@@ -0,0 +1,2 @@
ALTER TABLE `m_client`
ADD COLUMN `image_key` VARCHAR(500) NULL DEFAULT NULL AFTER `display_name`;
@@ -1,5 +1,6 @@
package org.mifosng.platform.api; package org.mifosng.platform.api;
import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@@ -9,6 +10,7 @@ import java.util.Set;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE; import javax.ws.rs.DELETE;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST; import javax.ws.rs.POST;
import javax.ws.rs.PUT; import javax.ws.rs.PUT;
import javax.ws.rs.Path; import javax.ws.rs.Path;
@@ -23,8 +25,8 @@ import javax.ws.rs.core.UriInfo;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.mifosng.platform.api.commands.ClientCommand; import org.mifosng.platform.api.commands.ClientCommand;
import org.mifosng.platform.api.commands.NoteCommand; 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.ClientAccountSummaryCollectionData;
import org.mifosng.platform.api.data.ClientData;
import org.mifosng.platform.api.data.EntityIdentifier; import org.mifosng.platform.api.data.EntityIdentifier;
import org.mifosng.platform.api.data.NoteData; import org.mifosng.platform.api.data.NoteData;
import org.mifosng.platform.api.data.OfficeLookup; 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.api.infrastructure.ApiParameterHelper;
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.FileUtils;
import org.mifosng.platform.exceptions.ClientNotFoundException;
import org.mifosng.platform.exceptions.ImageNotFoundException;
import org.mifosng.platform.organisation.service.OfficeReadPlatformService; import org.mifosng.platform.organisation.service.OfficeReadPlatformService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -40,6 +46,11 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component; 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") @Path("/clients")
@Component @Component
@Scope("singleton") @Scope("singleton")
@@ -63,7 +74,7 @@ public class ClientsApiResource {
private ApiJsonSerializerService apiJsonSerializerService; private ApiJsonSerializerService apiJsonSerializerService;
private static final Set<String> typicalResponseParameters = new HashSet<String>( private static final Set<String> typicalResponseParameters = new HashSet<String>(
Arrays.asList("id", "officeId", "officeName", "externalId", "firstname", "lastname", "joinedDate", "displayName", "clientOrBusinessName") Arrays.asList("id", "officeId", "officeName", "externalId", "firstname", "lastname", "joinedDate", "displayName", "clientOrBusinessName", "imagePresent")
); );
@GET @GET
@@ -313,4 +324,93 @@ public class ClientsApiResource {
return Response.ok().entity(identifier).build(); 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();
}
} }
@@ -28,9 +28,9 @@ import org.mifosng.platform.api.data.EntityIdentifier;
import org.mifosng.platform.api.infrastructure.ApiJsonSerializerService; import org.mifosng.platform.api.infrastructure.ApiJsonSerializerService;
import org.mifosng.platform.api.infrastructure.ApiParameterHelper; import org.mifosng.platform.api.infrastructure.ApiParameterHelper;
import org.mifosng.platform.common.ApplicationConstants; 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.DocumentReadPlatformService;
import org.mifosng.platform.documentmanagement.service.DocumentWritePlatformService; import org.mifosng.platform.documentmanagement.service.DocumentWritePlatformService;
import org.mifosng.platform.exceptions.DocumentManagementException;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -109,7 +109,7 @@ public class DocumentManagementApiResource {
@FormDataParam("name") String name, @FormDataParam("name") String name,
@FormDataParam("description") String description) { @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 * 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 * permissable
**/ **/
DocumentCommand documentCommand = new DocumentCommand(null, null, DocumentCommand documentCommand = new DocumentCommand(null, null,
@@ -156,7 +156,7 @@ public class DocumentManagementApiResource {
@FormDataParam("name") String name, @FormDataParam("name") String name,
@FormDataParam("description") String description) { @FormDataParam("description") String description) {
initialFileCheckerFastFail(fileSize, name); FileUtils.validateFileSizeWithinPermissibleRange(fileSize, name, ApplicationConstants.MAX_FILE_UPLOAD_SIZE_IN_MB);
Set<String> modifiedParams = new HashSet<String>(); Set<String> modifiedParams = new HashSet<String>();
modifiedParams.add("name"); modifiedParams.add("name");
@@ -187,22 +187,6 @@ public class DocumentManagementApiResource {
return Response.ok().entity(identifier).build(); 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 * @param entityType
@@ -20,6 +20,8 @@ public class ClientData {
private final String officeName; private final String officeName;
private final String externalId; private final String externalId;
private final LocalDate joinedDate; private final LocalDate joinedDate;
private final String imageKey;
private boolean imagePresent;
private List<OfficeLookup> allowedOffices = new ArrayList<OfficeLookup>(); private List<OfficeLookup> allowedOffices = new ArrayList<OfficeLookup>();
@@ -36,13 +38,14 @@ public class ClientData {
} }
displayNameBuilder.append(lastname); 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, public ClientData(final Long officeId, final String officeName,
final Long id, final String firstname, final String lastname, final Long id, final String firstname, final String lastname,
final String displayName, final String externalId, final String displayName, final String externalId,
final LocalDate joinedDate) { final LocalDate joinedDate,
final String imageKey) {
this.officeId = officeId; this.officeId = officeId;
this.officeName = officeName; this.officeName = officeName;
this.id = id; this.id = id;
@@ -60,6 +63,13 @@ public class ClientData {
this.externalId = externalId; this.externalId = externalId;
this.joinedDate = joinedDate; this.joinedDate = joinedDate;
this.imageKey = imageKey;
if (imageKey == null) {
imagePresent = false;
}else{
imagePresent = true;
}
} }
public ClientData(final Long officeId, final LocalDate joinedDate, public ClientData(final Long officeId, final LocalDate joinedDate,
@@ -74,6 +84,7 @@ public class ClientData {
this.externalId = null; this.externalId = null;
this.joinedDate = joinedDate; this.joinedDate = joinedDate;
this.allowedOffices = offices; this.allowedOffices = offices;
this.imageKey = null;
} }
public Long getId() { public Long getId() {
@@ -127,4 +138,20 @@ public class ClientData {
public String officeName() { public String officeName() {
return this.officeName; return this.officeName;
} }
public String getImageKey() {
return imageKey;
}
public boolean isImagePresent() {
return imagePresent;
}
public void setImagePresent(boolean imagePresent) {
this.imagePresent = imagePresent;
}
} }
@@ -122,7 +122,7 @@ public class GoogleGsonApiJsonSerializerService implements ApiJsonSerializerServ
private static final Set<String> CLIENT_DATA_PARAMETERS = new HashSet<String>( private static final Set<String> CLIENT_DATA_PARAMETERS = new HashSet<String>(
Arrays.asList("id", "officeId", "officeName", "externalId", Arrays.asList("id", "officeId", "officeName", "externalId",
"firstname", "lastname", "joinedDate", "displayName", "firstname", "lastname", "joinedDate", "displayName",
"clientOrBusinessName", "allowedOffices")); "clientOrBusinessName", "allowedOffices", "imagePresent"));
private static final Set<String> CLIENT_IDENTIFIER_DATA_PARAMETERS = new HashSet<String>( private static final Set<String> CLIENT_IDENTIFIER_DATA_PARAMETERS = new HashSet<String>(
Arrays.asList("id", "clientId", "documentTypeId", "documentKey", Arrays.asList("id", "clientId", "documentTypeId", "documentKey",
@@ -43,6 +43,9 @@ public class Client extends AbstractAuditableCustom<AppUser, Long> {
@Column(name = "is_deleted", nullable=false) @Column(name = "is_deleted", nullable=false)
private boolean deleted = 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) { public static Client newClient(Office clientOffice, String firstname, String lastname, LocalDate joiningDate, String externalId) {
return new Client(clientOffice, firstname, lastname, joiningDate, externalId); return new Client(clientOffice, firstname, lastname, joiningDate, externalId);
@@ -207,6 +210,16 @@ public class Client extends AbstractAuditableCustom<AppUser, Long> {
public void setDeleted(boolean deleted) { public void setDeleted(boolean deleted) {
this.deleted = deleted; this.deleted = deleted;
} }
public String getImageKey() {
return imageKey;
}
public void setImageKey(String imageKey) {
this.imageKey = imageKey;
}
} }
@@ -143,7 +143,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
public String clientSchema() { 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, " + 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 "; " where o.hierarchy like ? and c.is_deleted=0 ";
} }
@@ -161,11 +161,12 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
String displayName = rs.getString("displayName"); String displayName = rs.getString("displayName");
String externalId = rs.getString("externalId"); String externalId = rs.getString("externalId");
LocalDate joinedDate = JdbcSupport.getLocalDate(rs, "joinedDate"); LocalDate joinedDate = JdbcSupport.getLocalDate(rs, "joinedDate");
String imageKey = rs.getString("imageKey");
String officeName = rs.getString("officeName"); String officeName = rs.getString("officeName");
return new ClientData(officeId, officeName, id, firstname, return new ClientData(officeId, officeName, id, firstname,
lastname, displayName, externalId, joinedDate); lastname, displayName, externalId, joinedDate,imageKey);
} }
} }
@@ -1,5 +1,7 @@
package org.mifosng.platform.client.service; package org.mifosng.platform.client.service;
import java.io.InputStream;
import org.mifosng.platform.api.commands.ClientCommand; 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;
@@ -13,6 +15,12 @@ public interface ClientWritePlatformService {
@PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE')") @PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE')")
EntityIdentifier updateClientDetails(ClientCommand command); 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')") @PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE')")
EntityIdentifier addClientNote(NoteCommand command); EntityIdentifier addClientNote(NoteCommand command);
@@ -1,5 +1,9 @@
package org.mifosng.platform.client.service; 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.apache.commons.lang.StringUtils;
import org.mifosng.platform.api.commands.ClientCommand; import org.mifosng.platform.api.commands.ClientCommand;
import org.mifosng.platform.api.commands.ClientIdentifierCommand; 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.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.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;
import org.mifosng.platform.exceptions.CodeValueNotFoundException; import org.mifosng.platform.exceptions.CodeValueNotFoundException;
import org.mifosng.platform.exceptions.DocumentManagementException;
import org.mifosng.platform.exceptions.DuplicateClientIdentifierException; import org.mifosng.platform.exceptions.DuplicateClientIdentifierException;
import org.mifosng.platform.exceptions.NoteNotFoundException; import org.mifosng.platform.exceptions.NoteNotFoundException;
import org.mifosng.platform.exceptions.OfficeNotFoundException; import org.mifosng.platform.exceptions.OfficeNotFoundException;
@@ -319,4 +326,65 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
return new EntityIdentifier(clientIdentifierId); 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);
}
} }
@@ -7,8 +7,11 @@ public class ApplicationConstants {
// TODO:Vishwas Need to move these settings to the Database // TODO:Vishwas Need to move these settings to the Database
public static final Integer MAX_FILE_UPLOAD_SIZE_IN_MB = 5; 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 **/ /*** Entities for document Management **/
public static enum DOCUMENT_MANAGEMENT_ENTITIES { public static enum DOCUMENT_MANAGEMENT_ENTITY {
CLIENTS, CLIENT_IDENTIFIERS, STAFF, LOANS, SAVINGS; CLIENTS, CLIENT_IDENTIFIERS, STAFF, LOANS, SAVINGS;
@Override @Override
public String toString() { 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();
}
}
} }
@@ -5,12 +5,23 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Random; 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.mifosng.platform.infrastructure.ThreadLocalContextUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FileUtils { public class FileUtils {
private final static Logger logger = LoggerFactory
.getLogger(FileUtils.class);
public static final String MIFOSX_BASE_DIR = System public static final String MIFOSX_BASE_DIR = System
.getProperty("user.home") + File.separator + ".mifosx"; .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 entityType
* @param entityId * @param entityId
@@ -54,8 +65,26 @@ public class FileUtils {
+ File.separator + File.separator
+ ThreadLocalContextUtil.getTenant().getName() + ThreadLocalContextUtil.getTenant().getName()
.replaceAll(" ", "").trim() + File.separator .replaceAll(" ", "").trim() + File.separator
+ entityType + File.separator + entityId + File.separator + "documents" + File.separator + entityType + File.separator
+ FileUtils.generateRandomString(); + 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(); out.close();
return fileLocation; 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<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
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);
}
}
} }
@@ -193,7 +193,7 @@ public class DocumentWritePlatformServiceJpaRepositoryImpl implements
} }
private static boolean checkValidEntityType(String entityType) { 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()) { .values()) {
if (entities.name().equalsIgnoreCase(entityType)) { if (entities.name().equalsIgnoreCase(entityType)) {
return true; return true;
@@ -1,6 +1,5 @@
package org.mifosng.platform.exceptions; package org.mifosng.platform.exceptions;
import org.mifosng.platform.common.ApplicationConstants;
public class DocumentManagementException extends public class DocumentManagementException extends
AbstractPlatformDomainRuleException { AbstractPlatformDomainRuleException {
@@ -10,12 +9,13 @@ public class DocumentManagementException extends
+ name + " due to a File system / Amazon S3 issue", name); + 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", super("error.msg.document.file.too.big",
"Unable to save the document with name" + name "Unable to save the document with name" + name
+ " since its file Size of " + fileSize / (1024 * 1024) + " since its file Size of " + fileSize / (1024 * 1024)
+ " MB exceeds the max permissable file size of " + " MB exceeds the max permissable file size of "
+ ApplicationConstants.MAX_FILE_UPLOAD_SIZE_IN_MB + maxFileSize
+ " MB", name, fileSize); + " MB", name, fileSize);
} }
@@ -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);
}
}
@@ -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 ");
}
}