address review comments for client search and minor updates to document search api
This commit is contained in:
@@ -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'
|
||||
|
||||
|
||||
+127
-28
@@ -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<String> modifiedParams = new HashSet<String>();
|
||||
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 })
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+21
-9
@@ -16,21 +16,17 @@ import org.mifosng.platform.user.domain.AppUser;
|
||||
@Table(name = "m_client_identifier")
|
||||
public class ClientIdentifier extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
@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<AppUser, Long> {
|
||||
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<AppUser, Long> {
|
||||
command.getDescription(), null);
|
||||
}
|
||||
}
|
||||
|
||||
public Client getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
public CodeValue getDocumentType() {
|
||||
return documentType;
|
||||
}
|
||||
|
||||
public String getDocumentKey() {
|
||||
return documentKey;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
}
|
||||
+2
@@ -37,4 +37,6 @@ public interface ClientReadPlatformService {
|
||||
* @return
|
||||
*/
|
||||
ClientIdentifierData retrieveNewClientIdentifierDetails();
|
||||
Boolean existsClientIdentifier(Long clientId,Long identifierTypeId);
|
||||
ClientLookup getClientByIdentifier(Long identifierTypeId, String identifierKey);
|
||||
}
|
||||
+76
-19
@@ -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<CodeValueData>(
|
||||
codeValuePlatformService
|
||||
.retrieveAllCodeValues(ApplicationConstants.CLIENT_IDENTITY_CODE_ID)));
|
||||
clientIdentifierData
|
||||
.setAllowedDocumentTypes(new ArrayList<CodeValueData>(
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+80
-2
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
+64
-8
@@ -13,35 +13,27 @@ import org.mifosng.platform.user.domain.AppUser;
|
||||
@Table(name = "m_document")
|
||||
public class Document extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
@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<AppUser, Long> {
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
+3
-8
@@ -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",
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+20
-11
@@ -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(
|
||||
|
||||
Executable
+22
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
-11
@@ -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);
|
||||
}
|
||||
}
|
||||
+23
@@ -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);
|
||||
}
|
||||
}
|
||||
+16
-2
@@ -15,11 +15,9 @@ import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
"code_id", "code_value" }, name = "code_value_duplicate") })
|
||||
public class CodeValue extends AbstractPersistable<Long> {
|
||||
|
||||
@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<Long> {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user