initials files for client image management.
This commit is contained in:
committed by
Keith Woodlock
parent
3d5c0d88c0
commit
2325878e4e
@@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+4
-20
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
+1
-1
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
+3
-2
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+8
@@ -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);
|
||||||
|
|||||||
+68
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
+13
-1
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -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;
|
||||||
|
|||||||
+3
-3
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+15
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+10
@@ -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 ");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user