diff --git a/mifosng-provider/build.gradle b/mifosng-provider/build.gradle index 11cbac5ba..8c889bf0e 100644 --- a/mifosng-provider/build.gradle +++ b/mifosng-provider/build.gradle @@ -19,7 +19,7 @@ apply plugin: 'project-report' project.ext.springVersion = '3.1.1.RELEASE' project.ext.springSecurityVersion = '3.1.0.RELEASE' project.ext.hibernateValidatorVersion = '4.3.0.Final' -project.ext.hibernateCoreVersion = '4.1.3.Final' +project.ext.hibernateCoreVersion = '3.6.10.Final' project.ext.jerseyVersion = '1.13' project.ext.springDataJpaVersion = '1.0.3.RELEASE' 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 456c84187..bec528e43 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 @@ -27,8 +27,10 @@ import org.mifosng.platform.api.data.DocumentData; 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.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; @@ -55,6 +57,12 @@ public class DocumentManagementApiResource { Arrays.asList("id", "parentEntityType", "parentEntityId", "name", "fileName", "type", "size", "description")); + /** + * @param uriInfo + * @param entityType + * @param entityId + * @return + */ @GET @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) @@ -78,29 +86,43 @@ public class DocumentManagementApiResource { prettyPrint, responseParameters, documentDatas); } + /** + * @param entityType + * @param entityId + * @param fileSize + * @param inputStream + * @param fileDetails + * @param bodyPart + * @param name + * @param description + * @return + */ @POST @Consumes({ MediaType.MULTIPART_FORM_DATA }) @Produces({ MediaType.APPLICATION_JSON }) public Response createDocument(@PathParam("entityType") String entityType, @PathParam("entityId") Long entityId, + @HeaderParam("Content-Length") Long fileSize, @FormDataParam("file") InputStream inputStream, @FormDataParam("file") FormDataContentDisposition fileDetails, @FormDataParam("file") FormDataBodyPart bodyPart, - @HeaderParam("Content-Length") Long fileSize) { + @FormDataParam("name") String name, + @FormDataParam("description") String description) { - // TODO: Using Content-Length gives me size of the entire request, need - // to filter out only the size of the file + initialFileCheckerFastFail(fileSize, name); - // TODO: Need to add a Fast fail for checking size of file depending on - // the size sent by client, also need to have a backup and stop reading - // from stream after size is reached to protect against malicious - // clients + /** + * TODO: also need to have a backup and stop reading from stream after + * max size is reached to protect against malicious clients + **/ + + /** + * TODO: need to extract the actual file type and determine fi they are + * permissable + **/ DocumentCommand documentCommand = new DocumentCommand(null, null, - entityType, entityId, "test", fileDetails.getFileName(), - fileSize, bodyPart.getMediaType().toString(), "description", - null); - - bodyPart.getMediaType(); + entityType, entityId, name, fileDetails.getFileName(), + fileSize, bodyPart.getMediaType().toString(), description, null); Long documentId = this.documentWritePlatformService.createDocument( documentCommand, inputStream); @@ -108,6 +130,87 @@ public class DocumentManagementApiResource { return Response.ok().entity(new EntityIdentifier(documentId)).build(); } + /** + * @param entityType + * @param entityId + * @param documentId + * @param fileSize + * @param inputStream + * @param fileDetails + * @param bodyPart + * @param name + * @param description + * @return + */ + @PUT + @Path("{documentId}") + @Consumes({ MediaType.MULTIPART_FORM_DATA }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response updateDocument(@PathParam("entityType") String entityType, + @PathParam("entityId") Long entityId, + @PathParam("documentId") Long documentId, + @HeaderParam("Content-Length") Long fileSize, + @FormDataParam("file") InputStream inputStream, + @FormDataParam("file") FormDataContentDisposition fileDetails, + @FormDataParam("file") FormDataBodyPart bodyPart, + @FormDataParam("name") String name, + @FormDataParam("description") String description) { + + initialFileCheckerFastFail(fileSize, name); + + Set modifiedParams = new HashSet(); + modifiedParams.add("name"); + modifiedParams.add("description"); + + /*** + * Populate Document command based on whether a file has also been + * passed in as a part of the update + ***/ + DocumentCommand documentCommand = null; + if (inputStream != null) { + modifiedParams.add("fileName"); + modifiedParams.add("size"); + modifiedParams.add("type"); + modifiedParams.add("location"); + documentCommand = new DocumentCommand(modifiedParams, documentId, + entityType, entityId, name, fileDetails.getFileName(), + fileSize, bodyPart.getMediaType().toString(), description, + null); + } else { + documentCommand = new DocumentCommand(modifiedParams, documentId, + entityType, entityId, name, null, null, null, description, + null); + } + EntityIdentifier identifier = this.documentWritePlatformService + .updateDocument(documentCommand, inputStream); + + 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 entityId + * @param documentId + * @param uriInfo + * @return + */ @GET @Path("{documentId}") @Consumes({ MediaType.APPLICATION_JSON }) @@ -134,6 +237,12 @@ public class DocumentManagementApiResource { prettyPrint, responseParameters, documentData); } + /** + * @param entityType + * @param entityId + * @param documentId + * @return + */ @GET @Path("{documentId}/attachment") @Consumes({ MediaType.APPLICATION_JSON }) @@ -152,22 +261,12 @@ public class DocumentManagementApiResource { return response.build(); } - @PUT - @Path("{documentId}") - @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) - public Response updateDocument(@PathParam("entityType") String entityType, - @PathParam("entityId") Long entityId, - @PathParam("documentId") Long documentId) { - - // TODO - // EntityIdentifier identifier = - // this.documentWritePlatformService.updateDocument(documentCommand, - // inputStream, fileDetails) - - return Response.ok().entity(null).build(); - } - + /** + * @param entityType + * @param entityId + * @param documentId + * @return + */ @DELETE @Path("{documentId}") @Consumes({ MediaType.APPLICATION_JSON }) diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/ClientLookup.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/ClientLookup.java index 75a186a8b..46797c270 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/ClientLookup.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/ClientLookup.java @@ -5,11 +5,8 @@ import org.apache.commons.lang.StringUtils; public class ClientLookup { private final Long id; - @SuppressWarnings("unused") private final String displayName; - @SuppressWarnings("unused") private final Long officeId; - @SuppressWarnings("unused") private final String officeName; public ClientLookup(final Long id, final String firstname, final String lastname, final Long officeId, final String officeName) { @@ -52,4 +49,22 @@ public class ClientLookup { public int hashCode() { return this.id.hashCode(); } + + public Long getId() { + return id; + } + + public String getDisplayName() { + return displayName; + } + + public Long getOfficeId() { + return officeId; + } + + public String getOfficeName() { + return officeName; + } + + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/client/domain/ClientIdentifier.java b/mifosng-provider/src/main/java/org/mifosng/platform/client/domain/ClientIdentifier.java index 4c48b8d0b..07efa1b23 100755 --- a/mifosng-provider/src/main/java/org/mifosng/platform/client/domain/ClientIdentifier.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/client/domain/ClientIdentifier.java @@ -16,21 +16,17 @@ import org.mifosng.platform.user.domain.AppUser; @Table(name = "m_client_identifier") public class ClientIdentifier extends AbstractAuditableCustom { - @SuppressWarnings("unused") @ManyToOne @JoinColumn(name = "client_id", nullable = false) private Client client; - @SuppressWarnings("unused") @ManyToOne @JoinColumn(name = "document_type_id", nullable = false) private CodeValue documentType; - @SuppressWarnings("unused") @Column(name = "document_key", length = 1000) private String documentKey; - @SuppressWarnings("unused") @Column(name = "description", length = 1000) private String description; @@ -41,12 +37,11 @@ public class ClientIdentifier extends AbstractAuditableCustom { this.description = null; } - public static ClientIdentifier createNew( - final Client client, - final CodeValue documentType, - final String documentKey, + public static ClientIdentifier createNew(final Client client, + final CodeValue documentType, final String documentKey, final String description) { - return new ClientIdentifier(client, documentType, documentKey, description); + return new ClientIdentifier(client, documentType, documentKey, + description); } private ClientIdentifier(final Client client, final CodeValue documentType, @@ -73,4 +68,21 @@ public class ClientIdentifier extends AbstractAuditableCustom { command.getDescription(), null); } } + + public Client getClient() { + return client; + } + + public CodeValue getDocumentType() { + return documentType; + } + + public String getDocumentKey() { + return documentKey; + } + + public String getDescription() { + return description; + } + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientReadPlatformService.java index 34b6f8f37..0822c3eee 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientReadPlatformService.java @@ -37,4 +37,6 @@ public interface ClientReadPlatformService { * @return */ ClientIdentifierData retrieveNewClientIdentifierDetails(); + Boolean existsClientIdentifier(Long clientId,Long identifierTypeId); + ClientLookup getClientByIdentifier(Long identifierTypeId, String identifierKey); } \ 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 3ddc6c932..f22a39440 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 @@ -9,9 +9,19 @@ import java.util.List; import org.apache.commons.lang.StringUtils; import org.joda.time.DateTime; import org.joda.time.LocalDate; -import org.mifosng.platform.api.data.*; +import org.mifosng.platform.api.data.AppUserData; +import org.mifosng.platform.api.data.ClientAccountSummaryCollectionData; +import org.mifosng.platform.api.data.ClientAccountSummaryData; +import org.mifosng.platform.api.data.ClientData; +import org.mifosng.platform.api.data.ClientIdentifierData; +import org.mifosng.platform.api.data.ClientLookup; +import org.mifosng.platform.api.data.CodeValueData; +import org.mifosng.platform.api.data.EnumOptionData; +import org.mifosng.platform.api.data.NoteData; +import org.mifosng.platform.api.data.OfficeLookup; import org.mifosng.platform.client.domain.NoteEnumerations; import org.mifosng.platform.common.ApplicationConstants; +import org.mifosng.platform.exceptions.ClientIdentifierNotFoundException; import org.mifosng.platform.exceptions.ClientNotFoundException; import org.mifosng.platform.exceptions.NoteNotFoundException; import org.mifosng.platform.infrastructure.JdbcSupport; @@ -156,9 +166,17 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService "c.office_id as officeId, o.name as officeName " + "from m_client c join m_office o on o.id = c.office_id where c.is_deleted=0 "; } + + public String clientLookupByIdentifierSchema() { + return "c.id as id, c.firstname as firstname, c.lastname as lastname, " + + "c.office_id as officeId, o.name as officeName " + + "from m_client c, m_office o, m_client_identifier ci " + + "where o.id = c.office_id and c.id=ci.client_id " + + "and ci.document_type_id= ? and ci.document_key like ?"; + } @Override - public ClientLookup mapRow(ResultSet rs, @SuppressWarnings("unused") int rowNum) throws SQLException { + public ClientLookup mapRow(ResultSet rs, int rowNum) throws SQLException { Long id = rs.getLong("id"); String firstname = rs.getString("firstname"); String lastname = rs.getString("lastname"); @@ -428,27 +446,30 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService @Override public ClientIdentifierData retrieveClientIdentifier(Long clientId, Long clientIdentifierId) { - AppUser currentUser = context.authenticatedUser(); - String hierarchy = currentUser.getOffice().getHierarchy(); - String hierarchySearchString = hierarchy + "%"; + try { + AppUser currentUser = context.authenticatedUser(); + String hierarchy = currentUser.getOffice().getHierarchy(); + String hierarchySearchString = hierarchy + "%"; - ClientIdentityMapper rm = new ClientIdentityMapper(); + ClientIdentityMapper rm = new ClientIdentityMapper(); - String sql = "select " + rm.schema(); + String sql = "select " + rm.schema(); - sql += " and ci.id = ?"; + sql += " and ci.id = ?"; - ClientIdentifierData clientIdentifierData = this.jdbcTemplate - .queryForObject(sql, rm, new Object[] { clientId, - hierarchySearchString, clientIdentifierId }); + ClientIdentifierData clientIdentifierData = this.jdbcTemplate + .queryForObject(sql, rm, new Object[] { clientId, + hierarchySearchString, clientIdentifierId }); - if(clientIdentifierData!=null){ - clientIdentifierData.setAllowedDocumentTypes(new ArrayList( - codeValuePlatformService - .retrieveAllCodeValues(ApplicationConstants.CLIENT_IDENTITY_CODE_ID))); + clientIdentifierData + .setAllowedDocumentTypes(new ArrayList( + codeValuePlatformService + .retrieveAllCodeValues(ApplicationConstants.CLIENT_IDENTITY_CODE_ID))); + return clientIdentifierData; + } catch (EmptyResultDataAccessException e) { + throw new ClientIdentifierNotFoundException(clientIdentifierId); } - return clientIdentifierData; - + } @Override @@ -495,7 +516,43 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService } - - + @Override + public Boolean existsClientIdentifier(Long clientId, Long identifierTypeId) { + try { + AppUser currentUser = context.authenticatedUser(); + String hierarchy = currentUser.getOffice().getHierarchy(); + String hierarchySearchString = hierarchy + "%"; + + ClientIdentityMapper rm = new ClientIdentityMapper(); + + String sql = "select " + rm.schema() + " and ci.document_type_id=?"; + /****query for Object throws an exception if exactly one row is not returned***/ + this.jdbcTemplate.queryForObject(sql, rm, new Object[] { clientId, + hierarchySearchString, identifierTypeId }); + return true; + } catch (EmptyResultDataAccessException e) { + return false; + } + } + + + @Override + public ClientLookup getClientByIdentifier(Long identifierTypeId, + String identifierKey) { + try { + ClientLookupMapper mapper = new ClientLookupMapper(); + + String sql = "select " + mapper.clientLookupByIdentifierSchema(); + /**** + * query for Object throws an exception if exactly one row is not + * returned + ***/ + ClientLookup clientLookup = jdbcTemplate.queryForObject(sql, + mapper, new Object[] { identifierTypeId, identifierKey }); + return clientLookup; + } catch (EmptyResultDataAccessException e) { + return null; + } + } } \ No newline at end of file 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 edd4b1011..22e387b90 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 @@ -4,6 +4,7 @@ import org.apache.commons.lang.StringUtils; import org.mifosng.platform.api.commands.ClientCommand; import org.mifosng.platform.api.commands.ClientIdentifierCommand; import org.mifosng.platform.api.commands.NoteCommand; +import org.mifosng.platform.api.data.ClientLookup; import org.mifosng.platform.api.data.EntityIdentifier; import org.mifosng.platform.client.domain.Client; import org.mifosng.platform.client.domain.ClientIdentifier; @@ -14,6 +15,7 @@ import org.mifosng.platform.client.domain.NoteRepository; import org.mifosng.platform.exceptions.ClientIdentifierNotFoundException; import org.mifosng.platform.exceptions.ClientNotFoundException; import org.mifosng.platform.exceptions.CodeValueNotFoundException; +import org.mifosng.platform.exceptions.DuplicateClientIdentifierException; import org.mifosng.platform.exceptions.NoteNotFoundException; import org.mifosng.platform.exceptions.OfficeNotFoundException; import org.mifosng.platform.exceptions.PlatformDataIntegrityException; @@ -42,6 +44,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements private final OfficeRepository officeRepository; private final NoteRepository noteRepository; private final CodeValueRepository codeValueRepository; + private final ClientReadPlatformService clientReadPlatformService; @Autowired public ClientWritePlatformServiceJpaRepositoryImpl( @@ -50,13 +53,15 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements final ClientIdentifierRepository clientIdentifierRepository, final OfficeRepository officeRepository, NoteRepository noteRepository, - final CodeValueRepository codeValueRepository) { + final CodeValueRepository codeValueRepository, + final ClientReadPlatformService clientReadPlatformService) { this.context = context; this.clientRepository = clientRepository; this.clientIdentifierRepository = clientIdentifierRepository; this.officeRepository = officeRepository; this.noteRepository = noteRepository; this.codeValueRepository = codeValueRepository; + this.clientReadPlatformService = clientReadPlatformService; } @Transactional @@ -209,7 +214,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements @Transactional @Override - public Long addClientIdentifier(ClientIdentifierCommand clientIdentifierCommand) { + public Long addClientIdentifier( + ClientIdentifierCommand clientIdentifierCommand) { try { context.authenticatedUser(); @@ -234,6 +240,22 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements String documentKey = clientIdentifierCommand.getDocumentKey(); String description = clientIdentifierCommand.getDescription(); + /** + * check if a client identifier of the given type already exists for + * the client + **/ + if (clientReadPlatformService.existsClientIdentifier( + clientIdentifierCommand.getClientId(), + clientIdentifierCommand.getDocumentTypeId())) { + throw new DuplicateClientIdentifierException( + documentType.getLabel()); + } + + /*** Check if any Client has the same identifier ***/ + checkIdentifierUniqueness(documentType.getId(), + documentType.getLabel(), documentKey, + clientIdentifierCommand.getClientId()); + ClientIdentifier clientIdentifier = ClientIdentifier.createNew( client, documentType, documentKey, description); @@ -248,6 +270,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements } } + + @Transactional @Override public EntityIdentifier updateClientIdentifier( ClientIdentifierCommand clientIdentifierCommand) { @@ -276,6 +300,45 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements throw new ClientIdentifierNotFoundException( clientIdentifierCommand.getId()); } + + /** + * check if a client identifier of the given type already exists for + * the client + **/ + if (clientIdentifierForUpdate.getDocumentType().getId() != clientIdentifierCommand + .getDocumentTypeId()) { + if (clientReadPlatformService.existsClientIdentifier( + clientIdentifierCommand.getClientId(), + clientIdentifierCommand.getDocumentTypeId())) { + throw new DuplicateClientIdentifierException( + documentType.getLabel()); + } + } + + /*** Check if any Client has the same identifier ***/ + + if (clientIdentifierCommand.isDocumentTypeChanged() + && clientIdentifierCommand.isDocumentKeyChanged()) { + checkIdentifierUniqueness( + clientIdentifierCommand.getDocumentTypeId(), + documentType.getLabel(), + clientIdentifierCommand.getDocumentKey(), + clientIdentifierForUpdate.getClient().getId()); + } else if (clientIdentifierCommand.isDocumentTypeChanged() + && !clientIdentifierCommand.isDocumentKeyChanged()) { + checkIdentifierUniqueness( + clientIdentifierCommand.getDocumentTypeId(), + documentType.getLabel(), + clientIdentifierForUpdate.getDocumentKey(), + clientIdentifierForUpdate.getClient().getId()); + } else if (!clientIdentifierCommand.isDocumentTypeChanged() + && clientIdentifierCommand.isDocumentKeyChanged()) { + checkIdentifierUniqueness(clientIdentifierForUpdate + .getDocumentType().getId(), documentType.getLabel(), + clientIdentifierCommand.getDocumentKey(), + clientIdentifierForUpdate.getClient().getId()); + } + clientIdentifierForUpdate.update(clientIdentifierCommand, documentType); @@ -303,4 +366,19 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements return new EntityIdentifier(clientIdentifierId); } + + /** + * @param documentTypeId + * @param documentTypeLabel + * @param documentKey + */ + private void checkIdentifierUniqueness(Long documentTypeId, + String documentTypeLabel, String documentKey, Long callingClientId) { + ClientLookup clientLookup = clientReadPlatformService + .getClientByIdentifier(documentTypeId, documentKey); + if (clientLookup != null && clientLookup.getId()!=callingClientId) { + throw new DuplicateClientIdentifierException(clientLookup.getDisplayName(), + clientLookup.getOfficeName(), documentTypeLabel, documentKey); + } + } } \ 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 69ceeb597..1c2d7c6f9 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 @@ -4,6 +4,9 @@ public class ApplicationConstants { public static final Long CLIENT_IDENTITY_CODE_ID = 9L; + // TODO:Vishwas Need to move these settings to a database flag + public static final Integer MAX_FILE_UPLOAD_SIZE_IN_MB = 5; + /*** Entities for document Management **/ public static enum DOCUMENT_MANAGEMENT_ENTITIES { CLIENTs, STAFF, LOANS; diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/domain/Document.java b/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/domain/Document.java index ac822cb80..975673aa6 100755 --- a/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/domain/Document.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/domain/Document.java @@ -13,35 +13,27 @@ import org.mifosng.platform.user.domain.AppUser; @Table(name = "m_document") public class Document extends AbstractAuditableCustom { - @SuppressWarnings("unused") @Column(name = "parent_entity_type", length = 50) private String parentEntityType; - @SuppressWarnings("unused") @Column(name = "parent_entity_id", length = 1000) private Long parentEntityId; - @SuppressWarnings("unused") @Column(name = "name", length = 250) private String name; - @SuppressWarnings("unused") @Column(name = "file_name", length = 250) private String fileName; - @SuppressWarnings("unused") @Column(name = "size") private Long size; - @SuppressWarnings("unused") @Column(name = "type", length = 50) private String type; - @SuppressWarnings("unused") @Column(name = "description", length = 1000) private String description; - @SuppressWarnings("unused") @Column(name = "location", length = 500) private String location; @@ -91,4 +83,68 @@ public class Document extends AbstractAuditableCustom { } + public String getParentEntityType() { + return parentEntityType; + } + + public void setParentEntityType(String parentEntityType) { + this.parentEntityType = parentEntityType; + } + + public Long getParentEntityId() { + return parentEntityId; + } + + public void setParentEntityId(Long parentEntityId) { + this.parentEntityId = parentEntityId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public Long getSize() { + return size; + } + + public void setSize(Long size) { + this.size = size; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentCommandValidator.java b/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentCommandValidator.java index d6fa60b0f..40a3f386f 100755 --- a/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentCommandValidator.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentCommandValidator.java @@ -24,16 +24,13 @@ public class DocumentCommandValidator { baseDataValidator.reset().parameter("name").value(command.getName()) .ignoreIfNull().notBlank(); - /*** TODO:Validate for max length of File to be stored **/ baseDataValidator.reset().parameter("size").value(command.getSize()) .ignoreIfNull().integerGreaterThanZero(); baseDataValidator.reset().parameter("fileName") .value(command.getFileName()).ignoreIfNull().notBlank() - .integerGreaterThanZero(); + .notExceedingLengthOf(250); baseDataValidator.reset().parameter("location") - .value(command.getLocation()).ignoreIfNull().notBlank() - .integerGreaterThanZero(); - /*** TODO: Validate for permissable types ***/ + .value(command.getLocation()).ignoreIfNull().notBlank(); baseDataValidator.reset().parameter("type").value(command.getName()) .ignoreIfNull().notBlank().notExceedingLengthOf(250); baseDataValidator.reset().parameter("description") @@ -63,18 +60,16 @@ public class DocumentCommandValidator { .value(command.getParentEntityId()).integerGreaterThanZero(); baseDataValidator.reset().parameter("name").value(command.getName()) .notBlank().notExceedingLengthOf(250); - /*** TODO:Validate for max length of File to be stored **/ baseDataValidator.reset().parameter("size").value(command.getSize()) .integerGreaterThanZero(); baseDataValidator.reset().parameter("fileName") .value(command.getFileName()).notBlank() .notExceedingLengthOf(250); - /*** TODO: Validate for permissable types ***/ baseDataValidator.reset().parameter("type").value(command.getName()) .notBlank().notExceedingLengthOf(250); baseDataValidator.reset().parameter("description") .value(command.getName()).notExceedingLengthOf(250); - + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException( "validation.msg.validation.errors.exist", diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentReadPlatformServiceImpl.java index c72f4aeec..46cded421 100755 --- a/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentReadPlatformServiceImpl.java @@ -26,7 +26,7 @@ public class DocumentReadPlatformServiceImpl implements private final JdbcTemplate jdbcTemplate; - // TODO: use these services to check if passed n entities for document + // TODO: use these services to check if passed in entities for document // management exists (and ensure appropriate errors are thrown) private final PlatformSecurityContext context; private final OfficeReadPlatformService officeReadPlatformService; 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 97f668b3e..87bd08ae3 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 @@ -12,7 +12,7 @@ import org.mifosng.platform.common.FileUtils; import org.mifosng.platform.documentmanagement.domain.Document; import org.mifosng.platform.documentmanagement.domain.DocumentRepository; import org.mifosng.platform.exceptions.DocumentNotFoundException; -import org.mifosng.platform.exceptions.DocumentSaveException; +import org.mifosng.platform.exceptions.DocumentManagementException; import org.mifosng.platform.exceptions.InvalidEntityTypeForDocumentManagementException; import org.mifosng.platform.exceptions.PlatformDataIntegrityException; import org.mifosng.platform.loan.domain.LoanRepository; @@ -79,9 +79,6 @@ public class DocumentWritePlatformServiceJpaRepositoryImpl implements new File(fileUploadLocation).mkdirs(); } - // TODO check if entity id is valid and within data scope for the - // user - // TODO replace file system appender with an Amazon S3 appender String fileLocation = FileUtils.saveToFileSystem(inputStream, fileUploadLocation, documentCommand.getFileName()); @@ -102,7 +99,7 @@ public class DocumentWritePlatformServiceJpaRepositoryImpl implements "Unknown data integrity issue with resource."); } catch (IOException ioe) { logger.error(ioe.getMessage(), ioe); - throw new DocumentSaveException(documentCommand.getName()); + throw new DocumentManagementException(documentCommand.getName()); } } @@ -111,7 +108,7 @@ public class DocumentWritePlatformServiceJpaRepositoryImpl implements public EntityIdentifier updateDocument(DocumentCommand documentCommand, InputStream inputStream) { try { - + String oldLocation = null; DocumentCommandValidator validator = new DocumentCommandValidator( documentCommand); validator.validateForUpdate(); @@ -125,7 +122,7 @@ public class DocumentWritePlatformServiceJpaRepositoryImpl implements documentCommand.getParentEntityId(), documentCommand.getId()); } - + oldLocation = documentForUpdate.getLocation(); // if a new file is also passed in if (inputStream != null) { String fileUploadLocation = FileUtils @@ -142,11 +139,16 @@ public class DocumentWritePlatformServiceJpaRepositoryImpl implements // TODO delete the file at the previous location String fileLocation = FileUtils.saveToFileSystem(inputStream, fileUploadLocation, documentCommand.getFileName()); - documentCommand.setSize(documentCommand.getSize()); + documentCommand.setLocation(fileLocation); } documentForUpdate.update(documentCommand); + if (inputStream != null) { + // delete previous file + deleteFile(documentCommand.getName(), oldLocation); + } + this.documentRepository.saveAndFlush(documentForUpdate); return new EntityIdentifier(documentForUpdate.getId()); @@ -157,7 +159,7 @@ public class DocumentWritePlatformServiceJpaRepositoryImpl implements "Unknown data integrity issue with resource."); } catch (IOException ioe) { logger.error(ioe.getMessage(), ioe); - throw new DocumentSaveException(documentCommand.getName()); + throw new DocumentManagementException(documentCommand.getName()); } } @@ -176,11 +178,18 @@ public class DocumentWritePlatformServiceJpaRepositoryImpl implements } this.documentRepository.delete(document); - // TODO: delete the actual file from File system/ Amazon S3 - + deleteFile(document.getName(), document.getLocation()); return new EntityIdentifier(document.getId()); } + private void deleteFile(String documentName, String location) { + File fileToBeDeleted = new File(location); + boolean fileDeleted = fileToBeDeleted.delete(); + if (!fileDeleted) { + throw new DocumentManagementException(documentName); + } + } + private void validateParentEntityType(DocumentCommand documentCommand) { if (!checkValidEntityType(documentCommand.getParentEntityType())) { throw new InvalidEntityTypeForDocumentManagementException( 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 new file mode 100755 index 000000000..8278569f5 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/DocumentManagementException.java @@ -0,0 +1,22 @@ +package org.mifosng.platform.exceptions; + +import org.mifosng.platform.common.ApplicationConstants; + +public class DocumentManagementException extends + AbstractPlatformDomainRuleException { + + public DocumentManagementException(final String name) { + super("error.msg.document.save", "Error while manipulating file " + + name + " due to a File system / Amazon S3 issue", name); + } + + public DocumentManagementException(final String name, final Long fileSize) { + 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 + + " MB", name, fileSize); + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/DocumentSaveException.java b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/DocumentSaveException.java deleted file mode 100755 index f11596ba9..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/DocumentSaveException.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.mifosng.platform.exceptions; - -public class DocumentSaveException extends - AbstractPlatformResourceNotFoundException { - - public DocumentSaveException(final String name) { - super("error.msg.document.id.save", - "Unable to save the document with name" + name - + " due to a File system / Amazon S3 issue", name); - } -} diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/DuplicateClientIdentifierException.java b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/DuplicateClientIdentifierException.java new file mode 100755 index 000000000..6f7dc9122 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/DuplicateClientIdentifierException.java @@ -0,0 +1,23 @@ +package org.mifosng.platform.exceptions; + +/** + * A {@link RuntimeException} thrown when a client Identifer of the particular + * type is already present + */ +public class DuplicateClientIdentifierException extends + AbstractPlatformDomainRuleException { + + public DuplicateClientIdentifierException(String identifierType) { + super("error.msg.clientIdentifier.type.duplicate", + "Client Identifier of type " + identifierType + + " is already present for this client", identifierType); + } + + public DuplicateClientIdentifierException(String clientName, + String officeName, String identifierType, String identifierKey) { + super("error.msg.clientIdentifier.identityKey.duplicate", "Client " + + clientName + "under " + officeName + " Branch already has a " + + identifierType + " with unique key " + identifierKey, + clientName, officeName, identifierType, identifierKey); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/organisation/domain/CodeValue.java b/mifosng-provider/src/main/java/org/mifosng/platform/organisation/domain/CodeValue.java index 39748d097..e47fcc3f2 100755 --- a/mifosng-provider/src/main/java/org/mifosng/platform/organisation/domain/CodeValue.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/organisation/domain/CodeValue.java @@ -15,11 +15,9 @@ import org.springframework.data.jpa.domain.AbstractPersistable; "code_id", "code_value" }, name = "code_value_duplicate") }) public class CodeValue extends AbstractPersistable { - @SuppressWarnings("unused") @Column(name = "code_value", length = 100) private String label; - @SuppressWarnings("unused") @Column(name = "order_position") private int position; @@ -44,4 +42,20 @@ public class CodeValue extends AbstractPersistable { this.position = position; } + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public int getPosition() { + return position; + } + + public void setPosition(int position) { + this.position = position; + } + } \ No newline at end of file