work through cleaner implementation of error handling support for http api for the office resource.
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
package org.mifosng.data;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
@XmlRootElement(name="messageArg")
|
||||
public class ApiErrorMessageArg {
|
||||
|
||||
/**
|
||||
* The actual value of the parameter (if any) as passed to API.
|
||||
*/
|
||||
private Object value;
|
||||
|
||||
public static ApiErrorMessageArg from(Object object) {
|
||||
return new ApiErrorMessageArg(object);
|
||||
}
|
||||
|
||||
protected ApiErrorMessageArg() {
|
||||
//
|
||||
}
|
||||
|
||||
public ApiErrorMessageArg(Object object) {
|
||||
this.value = object;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
package org.mifosng.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlElementWrapper;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@XmlRootElement
|
||||
public class ApiGlobalErrorResponse {
|
||||
|
||||
/**
|
||||
* A developer friendly plain English description of why the HTTP error response was returned from the API.
|
||||
*/
|
||||
private String developerMessage;
|
||||
|
||||
/**
|
||||
* A link to a URL which provides more information on the details of this type of error.
|
||||
*/
|
||||
private String developerDocLink;
|
||||
|
||||
/**
|
||||
* The HTTP status code of the response.
|
||||
*/
|
||||
private String httpStatusCode;
|
||||
|
||||
/**
|
||||
* A user friendly plain English description of why the HTTP error response was returned from the API that can be presented to end users.
|
||||
*/
|
||||
private String defaultUserMessage;
|
||||
|
||||
/**
|
||||
* A code that can be used for globalisation support by client applications of the API.
|
||||
*/
|
||||
private String userMessageGlobalisationCode;
|
||||
|
||||
/**
|
||||
* A list of zero or more of the actual reasons for the HTTP error should they be needed. Typically used to express data validation errors with parameters passed to API.
|
||||
*/
|
||||
private List<ApiParameterError> errors = new ArrayList<ApiParameterError>();
|
||||
|
||||
public static ApiGlobalErrorResponse unAuthenticated() {
|
||||
|
||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||
globalErrorResponse.setHttpStatusCode("401");
|
||||
globalErrorResponse.setDeveloperMessage("No authentication details were passed in api request.");
|
||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
||||
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.not.authenticated");
|
||||
globalErrorResponse.setDefaultUserMessage("Unauthenticated. Please login.");
|
||||
|
||||
return globalErrorResponse;
|
||||
}
|
||||
|
||||
public static ApiGlobalErrorResponse unAuthorized() {
|
||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||
globalErrorResponse.setHttpStatusCode("403");
|
||||
globalErrorResponse.setDeveloperMessage("The user associated with credentials passed on this request does not have sufficient privileges to perform this action.");
|
||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
||||
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.not.authorized");
|
||||
globalErrorResponse.setDefaultUserMessage("Insufficient priviledges to perform this action.");
|
||||
|
||||
return globalErrorResponse;
|
||||
}
|
||||
|
||||
|
||||
public static ApiGlobalErrorResponse notFound(String globalisationMessageCode, String defaultUserMessage, Object... defaultUserMessageArgs) {
|
||||
|
||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||
globalErrorResponse.setHttpStatusCode("404");
|
||||
globalErrorResponse.setDeveloperMessage("The requested resource is not available.");
|
||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
||||
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.resource.not.found");
|
||||
globalErrorResponse.setDefaultUserMessage("The requested resource is not available.");
|
||||
|
||||
List<ApiParameterError> errors = new ArrayList<ApiParameterError>();
|
||||
errors.add(ApiParameterError.resourceIdentifierNotFound(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs));
|
||||
globalErrorResponse.setErrors(errors);
|
||||
|
||||
return globalErrorResponse;
|
||||
}
|
||||
|
||||
public static ApiGlobalErrorResponse dataIntegrityError(final String globalisationMessageCode, final String defaultUserMessage, final String parameterName, final Object... defaultUserMessageArgs) {
|
||||
|
||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||
globalErrorResponse.setHttpStatusCode("400");
|
||||
globalErrorResponse.setDeveloperMessage("The request caused a data integrity issue to be fired by the database.");
|
||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
||||
globalErrorResponse.setUserMessageGlobalisationCode(globalisationMessageCode);
|
||||
globalErrorResponse.setDefaultUserMessage(defaultUserMessage);
|
||||
|
||||
List<ApiParameterError> errors = new ArrayList<ApiParameterError>();
|
||||
errors.add(ApiParameterError.parameterError(globalisationMessageCode, defaultUserMessage, parameterName, defaultUserMessageArgs));
|
||||
globalErrorResponse.setErrors(errors);
|
||||
|
||||
return globalErrorResponse;
|
||||
}
|
||||
|
||||
public static ApiGlobalErrorResponse badClientRequest(final String globalisationMessageCode, final String defaultUserMessage,
|
||||
List<ApiParameterError> errors) {
|
||||
|
||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||
globalErrorResponse.setHttpStatusCode("400");
|
||||
globalErrorResponse.setDeveloperMessage("The request was invalid. This typically will happen due to validation errors which are provided.");
|
||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
||||
globalErrorResponse.setUserMessageGlobalisationCode(globalisationMessageCode);
|
||||
globalErrorResponse.setDefaultUserMessage(defaultUserMessage);
|
||||
|
||||
globalErrorResponse.setErrors(errors);
|
||||
|
||||
return globalErrorResponse;
|
||||
}
|
||||
|
||||
protected ApiGlobalErrorResponse() {
|
||||
//
|
||||
}
|
||||
|
||||
public ApiGlobalErrorResponse(final List<ApiParameterError> errors) {
|
||||
this.errors = errors;
|
||||
}
|
||||
|
||||
@XmlElementWrapper(name="errors")
|
||||
@XmlElement(name="errorResponse")
|
||||
public List<ApiParameterError> getErrors() {
|
||||
return errors;
|
||||
}
|
||||
|
||||
public void setErrors(List<ApiParameterError> errors) {
|
||||
this.errors = errors;
|
||||
}
|
||||
|
||||
public String getDeveloperMessage() {
|
||||
return developerMessage;
|
||||
}
|
||||
|
||||
public void setDeveloperMessage(String developerMessage) {
|
||||
this.developerMessage = developerMessage;
|
||||
}
|
||||
|
||||
public String getHttpStatusCode() {
|
||||
return httpStatusCode;
|
||||
}
|
||||
|
||||
public void setHttpStatusCode(String httpStatusCode) {
|
||||
this.httpStatusCode = httpStatusCode;
|
||||
}
|
||||
|
||||
public String getDefaultUserMessage() {
|
||||
return defaultUserMessage;
|
||||
}
|
||||
|
||||
public void setDefaultUserMessage(String defaultUserMessage) {
|
||||
this.defaultUserMessage = defaultUserMessage;
|
||||
}
|
||||
|
||||
public String getUserMessageGlobalisationCode() {
|
||||
return userMessageGlobalisationCode;
|
||||
}
|
||||
|
||||
public void setUserMessageGlobalisationCode(String userMessageGlobalisationCode) {
|
||||
this.userMessageGlobalisationCode = userMessageGlobalisationCode;
|
||||
}
|
||||
|
||||
public String getDeveloperDocLink() {
|
||||
return developerDocLink;
|
||||
}
|
||||
|
||||
public void setDeveloperDocLink(String developerDocLink) {
|
||||
this.developerDocLink = developerDocLink;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package org.mifosng.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
@XmlRootElement(name="apiParameterError")
|
||||
public class ApiParameterError {
|
||||
|
||||
/**
|
||||
* A developer friendly plain English description of why the HTTP error response was returned from the API.
|
||||
*/
|
||||
private String developerMessage;
|
||||
|
||||
/**
|
||||
* A user friendly plain English description of why the HTTP error response was returned from the API that can be presented to end users.
|
||||
*/
|
||||
private String defaultUserMessage;
|
||||
|
||||
/**
|
||||
* A code that can be used for globalisation support by client applications of the API.
|
||||
*/
|
||||
private String userMessageGlobalisationCode;
|
||||
|
||||
/**
|
||||
* The name of the field or parameter passed to the API that this error relates to.
|
||||
*/
|
||||
private String parameterName;
|
||||
|
||||
/**
|
||||
* The actual value of the parameter (if any) as passed to API.
|
||||
*/
|
||||
private Object value;
|
||||
|
||||
/**
|
||||
* Arguments related to the user error message.
|
||||
*/
|
||||
private List<ApiErrorMessageArg> args = new ArrayList<ApiErrorMessageArg>();
|
||||
|
||||
|
||||
public static ApiParameterError resourceIdentifierNotFound(String globalisationMessageCode, String defaultUserMessage, Object... defaultUserMessageArgs) {
|
||||
return new ApiParameterError(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs);
|
||||
}
|
||||
|
||||
public static ApiParameterError parameterError(final String globalisationMessageCode, final String defaultUserMessage,
|
||||
final String parameterName, final Object... defaultUserMessageArgs) {
|
||||
ApiParameterError error = new ApiParameterError(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs);
|
||||
error.setParameterName(parameterName);
|
||||
return error;
|
||||
}
|
||||
|
||||
protected ApiParameterError() {
|
||||
//
|
||||
}
|
||||
|
||||
private ApiParameterError(final String globalisationMessageCode, final String defaultUserMessage, final Object[] defaultUserMessageArgs) {
|
||||
this.userMessageGlobalisationCode = globalisationMessageCode;
|
||||
this.developerMessage = defaultUserMessage;
|
||||
this.defaultUserMessage = defaultUserMessage;
|
||||
|
||||
List<ApiErrorMessageArg> messageArgs = new ArrayList<ApiErrorMessageArg>();
|
||||
if (defaultUserMessageArgs != null) {
|
||||
for (Object object : defaultUserMessageArgs) {
|
||||
messageArgs.add(ApiErrorMessageArg.from(object));
|
||||
}
|
||||
}
|
||||
this.args = messageArgs;
|
||||
|
||||
this.parameterName="identifier";
|
||||
}
|
||||
|
||||
public String getDeveloperMessage() {
|
||||
return developerMessage;
|
||||
}
|
||||
|
||||
public void setDeveloperMessage(String developerMessage) {
|
||||
this.developerMessage = developerMessage;
|
||||
}
|
||||
|
||||
public String getDefaultUserMessage() {
|
||||
return defaultUserMessage;
|
||||
}
|
||||
|
||||
public void setDefaultUserMessage(String defaultUserMessage) {
|
||||
this.defaultUserMessage = defaultUserMessage;
|
||||
}
|
||||
|
||||
public String getUserMessageGlobalisationCode() {
|
||||
return userMessageGlobalisationCode;
|
||||
}
|
||||
|
||||
public void setUserMessageGlobalisationCode(String userMessageGlobalisationCode) {
|
||||
this.userMessageGlobalisationCode = userMessageGlobalisationCode;
|
||||
}
|
||||
|
||||
public String getParameterName() {
|
||||
return parameterName;
|
||||
}
|
||||
|
||||
public void setParameterName(String parameterName) {
|
||||
this.parameterName = parameterName;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public List<ApiErrorMessageArg> getArgs() {
|
||||
return args;
|
||||
}
|
||||
|
||||
public void setArgs(List<ApiErrorMessageArg> args) {
|
||||
this.args = args;
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ public class UpdateLoanProductCommand implements LoanProductCommandData {
|
||||
repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod, toleranceAmount, flexibleRepaymentSchedule, interestRebateAllowed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
@@ -41,6 +42,7 @@ public class UpdateLoanProductCommand implements LoanProductCommandData {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
@@ -49,6 +51,7 @@ public class UpdateLoanProductCommand implements LoanProductCommandData {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrencyCode() {
|
||||
return this.commonLoanProperties.getCurrencyCode();
|
||||
}
|
||||
@@ -57,6 +60,7 @@ public class UpdateLoanProductCommand implements LoanProductCommandData {
|
||||
this.commonLoanProperties.setCurrencyCode(currencyCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getDigitsAfterDecimal() {
|
||||
return this.commonLoanProperties.getDigitsAfterDecimal();
|
||||
}
|
||||
@@ -65,6 +69,7 @@ public class UpdateLoanProductCommand implements LoanProductCommandData {
|
||||
this.commonLoanProperties.setDigitsAfterDecimal(digitsAfterDecimal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getRepaymentEvery() {
|
||||
return this.commonLoanProperties.getRepaymentEvery();
|
||||
}
|
||||
@@ -73,6 +78,7 @@ public class UpdateLoanProductCommand implements LoanProductCommandData {
|
||||
this.commonLoanProperties.setRepaymentEvery(repaymentEvery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getRepaymentFrequency() {
|
||||
return this.commonLoanProperties.getRepaymentFrequency();
|
||||
}
|
||||
@@ -81,6 +87,7 @@ public class UpdateLoanProductCommand implements LoanProductCommandData {
|
||||
this.commonLoanProperties.setRepaymentFrequency(repaymentFrequency);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isFlexibleRepaymentSchedule() {
|
||||
return this.commonLoanProperties.isFlexibleRepaymentSchedule();
|
||||
}
|
||||
@@ -90,6 +97,7 @@ public class UpdateLoanProductCommand implements LoanProductCommandData {
|
||||
this.commonLoanProperties.setFlexibleRepaymentSchedule(flexibleRepaymentSchedule);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isInterestRebateAllowed() {
|
||||
return this.commonLoanProperties.isInterestRebateAllowed();
|
||||
}
|
||||
@@ -98,6 +106,7 @@ public class UpdateLoanProductCommand implements LoanProductCommandData {
|
||||
this.commonLoanProperties.setInterestRebateAllowed(interestRebateAllowed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getPrincipal() {
|
||||
return this.commonLoanProperties.getPrincipal();
|
||||
}
|
||||
@@ -114,6 +123,7 @@ public class UpdateLoanProductCommand implements LoanProductCommandData {
|
||||
// return this.commonLoanProperties.getInterestRebateAllowed();
|
||||
// }
|
||||
|
||||
@Override
|
||||
public Integer getInterestRateFrequencyMethod() {
|
||||
return commonLoanProperties.getInterestRateFrequencyMethod();
|
||||
}
|
||||
@@ -122,6 +132,7 @@ public class UpdateLoanProductCommand implements LoanProductCommandData {
|
||||
this.commonLoanProperties.setInterestRateFrequencyMethod(interestRateFrequencyMethod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getInterestMethod() {
|
||||
return commonLoanProperties.getInterestMethod();
|
||||
}
|
||||
@@ -130,6 +141,7 @@ public class UpdateLoanProductCommand implements LoanProductCommandData {
|
||||
this.commonLoanProperties.setInterestMethod(interestMethod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getAmortizationMethod() {
|
||||
return commonLoanProperties.getAmortizationMethod();
|
||||
}
|
||||
@@ -138,6 +150,7 @@ public class UpdateLoanProductCommand implements LoanProductCommandData {
|
||||
this.commonLoanProperties.setAmortizationMethod(amortizationMethod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getNumberOfRepayments() {
|
||||
return commonLoanProperties.getNumberOfRepayments();
|
||||
}
|
||||
@@ -146,6 +159,7 @@ public class UpdateLoanProductCommand implements LoanProductCommandData {
|
||||
this.commonLoanProperties.setNumberOfRepayments(numberOfRepayments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getInterestRatePerPeriod() {
|
||||
return commonLoanProperties.getInterestRatePerPeriod();
|
||||
}
|
||||
@@ -154,6 +168,7 @@ public class UpdateLoanProductCommand implements LoanProductCommandData {
|
||||
this.commonLoanProperties.setInterestRatePerPeriod(interestRatePerPeriod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonLoanProperties getCommonLoanProperties() {
|
||||
return commonLoanProperties;
|
||||
}
|
||||
@@ -162,6 +177,7 @@ public class UpdateLoanProductCommand implements LoanProductCommandData {
|
||||
this.commonLoanProperties = commonLoanProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getInArrearsToleranceAmount() {
|
||||
return this.commonLoanProperties.getInArrearsToleranceAmount();
|
||||
}
|
||||
|
||||
+1
@@ -56,6 +56,7 @@ public class CustomOAuthConsumerContextFilter extends OAuthConsumerContextFilter
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
|
||||
HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
HttpServletResponse response = (HttpServletResponse) servletResponse;
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ error.msg.client.id.invalid=Client does not exist.
|
||||
error.msg.office.id.invalid=Office does not exist.
|
||||
error.msg.office.duplicate.externalId=An office with 'External Id' already exists.
|
||||
error.msg.office.duplicate.name=An office with 'name' already exists.
|
||||
error.msg.office.unknown.data.integretity.issue=An unknown data integrity issue occured.
|
||||
error.msg.office.unknown.data.integrity.issue=An unknown data integrity issue occured.
|
||||
|
||||
dialog.title.confirmation.required=Confirmation required
|
||||
text.confirmation.required=Are you sure?
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ error.msg.client.id.invalid=Client does not exist.(fr)
|
||||
error.msg.office.id.invalid=Office does not exist.(fr)
|
||||
error.msg.office.duplicate.externalId=An office with 'External Id' already exists.(fr)
|
||||
error.msg.office.duplicate.name=An office with 'name' already exists.(fr)
|
||||
error.msg.office.unknown.data.integretity.issue=An unknown data integrity issue occured.(fr)
|
||||
error.msg.office.unknown.data.integrity.issue=An unknown data integrity issue occured.(fr)
|
||||
|
||||
dialog.title.confirmation.required=Confirmation required(fr)
|
||||
text.confirmation.required=Are you sure?(fr)
|
||||
|
||||
+1
@@ -28,6 +28,7 @@ import org.springframework.security.oauth.provider.token.OAuthProviderToken;
|
||||
public class CustomProtectedResourceProcessingFilter extends
|
||||
ProtectedResourceProcessingFilter {
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
|
||||
HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
HttpServletResponse response = (HttpServletResponse) servletResponse;
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
package org.mifosng.platform;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosng.data.ErrorResponse;
|
||||
import org.mifosng.platform.exceptions.NewDataValidationException;
|
||||
|
||||
public class OfficeValidator {
|
||||
|
||||
private final String name;
|
||||
private final Long parentId;
|
||||
private final LocalDate openingDate;
|
||||
private final String externalId;
|
||||
|
||||
public OfficeValidator(String name, Long parentId, LocalDate openingDate, String externalId) {
|
||||
this.name = name;
|
||||
this.parentId = parentId;
|
||||
this.openingDate = openingDate;
|
||||
this.externalId = externalId;
|
||||
}
|
||||
|
||||
public void validate() {
|
||||
List<ErrorResponse> dataValidationErrors = new ArrayList<ErrorResponse>();
|
||||
|
||||
if (StringUtils.isBlank(this.name)) {
|
||||
ErrorResponse error = new ErrorResponse("validation.msg.office.name.cannot.be.blank", "name");
|
||||
dataValidationErrors.add(error);
|
||||
}
|
||||
|
||||
if (this.parentId == null || parentId.equals(Long.valueOf(-1))) {
|
||||
ErrorResponse error = new ErrorResponse("validation.msg.office.parent.cannot.be.blank", "parentId");
|
||||
dataValidationErrors.add(error);
|
||||
}
|
||||
|
||||
if (this.openingDate == null) {
|
||||
ErrorResponse error = new ErrorResponse("validation.msg.office.opening.date.cannot.be.blank", "openingDate");
|
||||
dataValidationErrors.add(error);
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(this.externalId)) {
|
||||
|
||||
if (this.externalId.trim().length() > 100) {
|
||||
ErrorResponse error = new ErrorResponse("validation.msg.office.externalId.exceeds.max.length", "externalId");
|
||||
dataValidationErrors.add(error);
|
||||
}
|
||||
}
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new NewDataValidationException(dataValidationErrors, "Data validation errors exist.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -33,7 +33,6 @@ import org.mifosng.data.ClientDataWithAccountsData;
|
||||
import org.mifosng.data.CurrencyData;
|
||||
import org.mifosng.data.DerivedLoanData;
|
||||
import org.mifosng.data.EnumOptionReadModel;
|
||||
import org.mifosng.data.ErrorResponse;
|
||||
import org.mifosng.data.ExtraDatasets;
|
||||
import org.mifosng.data.LoanAccountData;
|
||||
import org.mifosng.data.LoanProductData;
|
||||
@@ -53,7 +52,7 @@ import org.mifosng.platform.client.domain.ClientRepository;
|
||||
import org.mifosng.platform.currency.domain.ApplicationCurrency;
|
||||
import org.mifosng.platform.currency.domain.ApplicationCurrencyRepository;
|
||||
import org.mifosng.platform.currency.domain.Money;
|
||||
import org.mifosng.platform.exceptions.ApplicationDomainRuleException;
|
||||
import org.mifosng.platform.exceptions.PlatformResourceNotFoundException;
|
||||
import org.mifosng.platform.exceptions.UnAuthenticatedUserException;
|
||||
import org.mifosng.platform.loan.domain.AmortizationMethod;
|
||||
import org.mifosng.platform.loan.domain.Loan;
|
||||
@@ -200,11 +199,7 @@ public class ReadPlatformServiceImpl implements ReadPlatformService {
|
||||
new Object[] { currentUser.getOrganisation().getId(),
|
||||
clientId, noteId });
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
ErrorResponse errorResponse = new ErrorResponse(
|
||||
"error.msg.client.id.invalid", "id");
|
||||
throw new ApplicationDomainRuleException(
|
||||
Arrays.asList(errorResponse), "Client with identifier "
|
||||
+ clientId.toString() + " does not exist.");
|
||||
throw new PlatformResourceNotFoundException("error.msg.client.id.invalid", "Client with identifier {0} does not exist", clientId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,11 +398,7 @@ public class ReadPlatformServiceImpl implements ReadPlatformService {
|
||||
|
||||
return selectedOffice;
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
ErrorResponse errorResponse = new ErrorResponse(
|
||||
"error.msg.office.id.invalid", "id");
|
||||
throw new ApplicationDomainRuleException(
|
||||
Arrays.asList(errorResponse), "Office with identifier "
|
||||
+ officeId.toString() + " does not exist.");
|
||||
throw new PlatformResourceNotFoundException("error.msg.office.id.invalid", "Office with identifier {0} does not exist", officeId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,11 +417,7 @@ public class ReadPlatformServiceImpl implements ReadPlatformService {
|
||||
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] {
|
||||
clientId, currentUser.getOrganisation().getId() });
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
ErrorResponse errorResponse = new ErrorResponse(
|
||||
"error.msg.client.id.invalid", "id");
|
||||
throw new ApplicationDomainRuleException(
|
||||
Arrays.asList(errorResponse), "Client with identifier "
|
||||
+ clientId.toString() + " does not exist.");
|
||||
throw new PlatformResourceNotFoundException("error.msg.client.id.invalid", "Client with identifier {0} does not exist", clientId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -575,6 +562,7 @@ public class ReadPlatformServiceImpl implements ReadPlatformService {
|
||||
return loanRepaymentData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NewLoanWorkflowStepOneData retrieveClientAndProductDetails(final Long clientId, final Long productId) {
|
||||
|
||||
AppUser currentUser = extractAuthenticatedUser();
|
||||
|
||||
+24
-20
@@ -1,6 +1,10 @@
|
||||
package org.mifosng.platform;
|
||||
|
||||
import static org.mifosng.platform.Specifications.*;
|
||||
import static org.mifosng.platform.Specifications.loansThatMatch;
|
||||
import static org.mifosng.platform.Specifications.officesThatMatch;
|
||||
import static org.mifosng.platform.Specifications.productThatMatches;
|
||||
import static org.mifosng.platform.Specifications.rolesThatMatch;
|
||||
import static org.mifosng.platform.Specifications.usersThatMatch;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
@@ -44,10 +48,11 @@ import org.mifosng.platform.currency.domain.ApplicationCurrencyRepository;
|
||||
import org.mifosng.platform.currency.domain.MonetaryCurrency;
|
||||
import org.mifosng.platform.currency.domain.Money;
|
||||
import org.mifosng.platform.exceptions.ApplicationDomainRuleException;
|
||||
import org.mifosng.platform.exceptions.UnAuthenticatedUserException;
|
||||
import org.mifosng.platform.exceptions.InvalidSignupException;
|
||||
import org.mifosng.platform.exceptions.NewDataValidationException;
|
||||
import org.mifosng.platform.exceptions.NoAuthorizationException;
|
||||
import org.mifosng.platform.exceptions.PlatformDataIntegrityException;
|
||||
import org.mifosng.platform.exceptions.UnAuthenticatedUserException;
|
||||
import org.mifosng.platform.infrastructure.BasicPasswordEncodablePlatformUser;
|
||||
import org.mifosng.platform.infrastructure.PlatformPasswordEncoder;
|
||||
import org.mifosng.platform.infrastructure.PlatformUser;
|
||||
@@ -74,6 +79,7 @@ import org.mifosng.platform.organisation.domain.OfficeRepository;
|
||||
import org.mifosng.platform.organisation.domain.Organisation;
|
||||
import org.mifosng.platform.organisation.domain.OrganisationCurrency;
|
||||
import org.mifosng.platform.organisation.domain.OrganisationRepository;
|
||||
import org.mifosng.platform.organisation.service.OfficeCommandValidator;
|
||||
import org.mifosng.platform.user.domain.AppUser;
|
||||
import org.mifosng.platform.user.domain.AppUserRepository;
|
||||
import org.mifosng.platform.user.domain.Permission;
|
||||
@@ -331,7 +337,7 @@ public class WritePlatformServiceJpaRepositoryImpl implements
|
||||
try {
|
||||
AppUser currentUser = extractAuthenticatedUser();
|
||||
|
||||
OfficeValidator validator = new OfficeValidator(command.getName(), command.getParentId(), command.getOpeningDate(), command.getExternalId());
|
||||
OfficeCommandValidator validator = new OfficeCommandValidator(command.getName(), command.getParentId(), command.getOpeningDate(), command.getExternalId());
|
||||
validator.validate();
|
||||
|
||||
Office parent = validateUserPriviledgeOnOfficeAndRetrieve(currentUser, command.getParentId());
|
||||
@@ -347,8 +353,8 @@ public class WritePlatformServiceJpaRepositoryImpl implements
|
||||
|
||||
return office.getId();
|
||||
} catch (DataIntegrityViolationException dve) {
|
||||
List<ErrorResponse> dataValidationErrors = handleOfficeDataIntegrityIssues(command, dve);
|
||||
throw new ApplicationDomainRuleException(dataValidationErrors, "Errors exist.");
|
||||
handleOfficeDataIntegrityIssues(command, dve);
|
||||
return Long.valueOf(-1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,7 +365,7 @@ public class WritePlatformServiceJpaRepositoryImpl implements
|
||||
try {
|
||||
AppUser currentUser = extractAuthenticatedUser();
|
||||
|
||||
OfficeValidator validator = new OfficeValidator(command.getName(), command.getParentId(), command.getOpeningDate(), command.getExternalId());
|
||||
OfficeCommandValidator validator = new OfficeCommandValidator(command.getName(), command.getParentId(), command.getOpeningDate(), command.getExternalId());
|
||||
validator.validate();
|
||||
|
||||
Office office = validateUserPriviledgeOnOfficeAndRetrieve(currentUser, command.getId());
|
||||
@@ -370,27 +376,25 @@ public class WritePlatformServiceJpaRepositoryImpl implements
|
||||
|
||||
return office.getId();
|
||||
} catch (DataIntegrityViolationException dve) {
|
||||
List<ErrorResponse> dataValidationErrors = handleOfficeDataIntegrityIssues(command, dve);
|
||||
throw new ApplicationDomainRuleException(dataValidationErrors, "Errors exist.");
|
||||
handleOfficeDataIntegrityIssues(command, dve);
|
||||
return Long.valueOf(-1);
|
||||
}
|
||||
}
|
||||
|
||||
private List<ErrorResponse> handleOfficeDataIntegrityIssues(final OfficeCommand command, DataIntegrityViolationException dve) {
|
||||
/*
|
||||
* Guaranteed to throw an exception no matter what the data integrity issue is.
|
||||
*/
|
||||
private void handleOfficeDataIntegrityIssues(final OfficeCommand command, DataIntegrityViolationException dve) {
|
||||
|
||||
List<ErrorResponse> dataValidationErrors = new ArrayList<ErrorResponse>();
|
||||
Throwable realCause = dve.getMostSpecificCause();
|
||||
if (realCause.getMessage().contains("externalid_org")) {
|
||||
ErrorResponse error = new ErrorResponse("error.msg.office.duplicate.externalId", "externalId", command.getExternalId());
|
||||
dataValidationErrors.add(error);
|
||||
throw new PlatformDataIntegrityException("error.msg.office.duplicate.externalId", "Office with externalId {0} already exists", "externalId", command.getExternalId());
|
||||
} else if (realCause.getMessage().contains("name_org")) {
|
||||
ErrorResponse error = new ErrorResponse("error.msg.office.duplicate.name", "name", command.getName());
|
||||
dataValidationErrors.add(error);
|
||||
} else {
|
||||
logger.error(dve.getMessage(), dve);
|
||||
ErrorResponse error = new ErrorResponse("error.msg.office.unknown.data.integretity.issue", "id");
|
||||
dataValidationErrors.add(error);
|
||||
}
|
||||
return dataValidationErrors;
|
||||
throw new PlatformDataIntegrityException("error.msg.office.duplicate.name", "Office with name {0} already exists", "name", command.getName());
|
||||
}
|
||||
|
||||
logger.error(dve.getMessage(), dve);
|
||||
throw new PlatformDataIntegrityException("error.msg.office.unknown.data.integrity.issue", "Unknown data integrity issue with resource.");
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,31 +1,16 @@
|
||||
package org.mifosng.platform.api;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.mifosng.data.EntityIdentifier;
|
||||
import org.mifosng.data.ErrorResponse;
|
||||
import org.mifosng.data.ErrorResponseList;
|
||||
import org.mifosng.data.ExtraDatasets;
|
||||
import org.mifosng.data.reports.GenericResultset;
|
||||
import org.mifosng.platform.InvalidSqlException;
|
||||
import org.mifosng.platform.ReadPlatformService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -37,8 +22,7 @@ import org.springframework.stereotype.Component;
|
||||
@Scope("singleton")
|
||||
public class ExtraDataApiResource {
|
||||
|
||||
private final static Logger logger = LoggerFactory
|
||||
.getLogger(ExtraDataApiResource.class);
|
||||
private final static Logger logger = LoggerFactory.getLogger(ExtraDataApiResource.class);
|
||||
|
||||
@Autowired
|
||||
private ReadPlatformService readPlatformService;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.mifosng.platform.api;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
@@ -16,7 +15,6 @@ import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
import org.mifosng.data.EntityIdentifier;
|
||||
import org.mifosng.data.ErrorResponse;
|
||||
import org.mifosng.data.ErrorResponseList;
|
||||
import org.mifosng.data.LoanProductData;
|
||||
import org.mifosng.data.LoanProductList;
|
||||
@@ -30,7 +28,6 @@ import org.mifosng.platform.user.domain.AppUser;
|
||||
import org.mifosng.platform.user.domain.AppUserRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
@@ -38,7 +35,6 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/*
|
||||
*
|
||||
* @see http://viewfromthefringe.blogspot.com/2010/06/versioning-rest-services.html
|
||||
* @see http://jersey.576304.n2.nabble.com/Restful-Service-Versioning-td6332833.html
|
||||
*
|
||||
@@ -57,7 +53,6 @@ import org.springframework.stereotype.Component;
|
||||
* 8. @PUT /loanproducts/{productId} updates loan product of that identifier
|
||||
* 9. Using /resource/template pattern for UI specific function of get 'data with defaults' for new resource.
|
||||
*/
|
||||
|
||||
@Path("/v1/loanproducts")
|
||||
@Component
|
||||
@Scope("singleton")
|
||||
@@ -113,10 +108,6 @@ public class LoanProductApiResource {
|
||||
EntityIdentifier entityIdentifier = this.writePlatformService.createLoanProduct(command);
|
||||
|
||||
return Response.ok().entity(entityIdentifier).build();
|
||||
} catch (AccessDeniedException e) {
|
||||
ErrorResponse errorResponse = new ErrorResponse("error.msg.no.permission", "id");
|
||||
ErrorResponseList list = new ErrorResponseList(Arrays.asList(errorResponse));
|
||||
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(list).build());
|
||||
} catch (ApplicationDomainRuleException e) {
|
||||
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getErrors())).build());
|
||||
} catch (NewDataValidationException e) {
|
||||
@@ -135,10 +126,6 @@ public class LoanProductApiResource {
|
||||
Collection<LoanProductData> products = this.readPlatformService.retrieveAllLoanProducts();
|
||||
|
||||
return Response.ok().entity(new LoanProductList(products)).build();
|
||||
} catch (AccessDeniedException e) {
|
||||
ErrorResponse errorResponse = new ErrorResponse("error.msg.no.permission", "id");
|
||||
ErrorResponseList list = new ErrorResponseList(Arrays.asList(errorResponse));
|
||||
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(list).build());
|
||||
} catch (ApplicationDomainRuleException e) {
|
||||
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getErrors())).build());
|
||||
} catch (NewDataValidationException e) {
|
||||
@@ -161,10 +148,6 @@ public class LoanProductApiResource {
|
||||
LoanProductData loanProduct = this.readPlatformService.retrieveNewLoanProductDetails();
|
||||
|
||||
return Response.ok().entity(loanProduct).build();
|
||||
} catch (AccessDeniedException e) {
|
||||
ErrorResponse errorResponse = new ErrorResponse("error.msg.no.permission", "id");
|
||||
ErrorResponseList list = new ErrorResponseList(Arrays.asList(errorResponse));
|
||||
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(list).build());
|
||||
} catch (ApplicationDomainRuleException e) {
|
||||
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getErrors())).build());
|
||||
} catch (NewDataValidationException e) {
|
||||
@@ -184,10 +167,6 @@ public class LoanProductApiResource {
|
||||
LoanProductData loanProduct = this.readPlatformService.retrieveLoanProduct(productId);
|
||||
|
||||
return Response.ok().entity(loanProduct).build();
|
||||
} catch (AccessDeniedException e) {
|
||||
ErrorResponse errorResponse = new ErrorResponse("error.msg.no.permission", "id");
|
||||
ErrorResponseList list = new ErrorResponseList(Arrays.asList(errorResponse));
|
||||
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(list).build());
|
||||
} catch (ApplicationDomainRuleException e) {
|
||||
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getErrors())).build());
|
||||
} catch (NewDataValidationException e) {
|
||||
@@ -230,10 +209,6 @@ public class LoanProductApiResource {
|
||||
EntityIdentifier entityIdentifier = this.writePlatformService.updateLoanProduct(command);
|
||||
|
||||
return Response.ok().entity(entityIdentifier).build();
|
||||
} catch (AccessDeniedException e) {
|
||||
ErrorResponse errorResponse = new ErrorResponse("error.msg.no.permission", "id");
|
||||
ErrorResponseList list = new ErrorResponseList(Arrays.asList(errorResponse));
|
||||
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(list).build());
|
||||
} catch (ApplicationDomainRuleException e) {
|
||||
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getErrors())).build());
|
||||
} catch (NewDataValidationException e) {
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
package org.mifosng.platform.api;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
import org.mifosng.data.EntityIdentifier;
|
||||
import org.mifosng.data.ErrorResponse;
|
||||
import org.mifosng.data.ErrorResponseList;
|
||||
import org.mifosng.data.OfficeData;
|
||||
import org.mifosng.data.OfficeList;
|
||||
import org.mifosng.data.command.OfficeCommand;
|
||||
import org.mifosng.platform.ReadPlatformService;
|
||||
import org.mifosng.platform.WritePlatformService;
|
||||
import org.mifosng.platform.exceptions.ApplicationDomainRuleException;
|
||||
import org.mifosng.platform.exceptions.NewDataValidationException;
|
||||
import org.mifosng.platform.user.domain.AppUser;
|
||||
import org.mifosng.platform.user.domain.AppUserRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Path("/v1/offices")
|
||||
@Component
|
||||
@Scope("singleton")
|
||||
public class OfficeApiResource {
|
||||
|
||||
@Autowired
|
||||
private ReadPlatformService readPlatformService;
|
||||
|
||||
@Autowired
|
||||
private WritePlatformService writePlatformService;
|
||||
|
||||
@Autowired
|
||||
private AppUserRepository appUserRepository;
|
||||
|
||||
private void hardcodeUserIntoSecurityContext() {
|
||||
AppUser currentUser = this.appUserRepository.findOne(Long.valueOf(1));
|
||||
|
||||
Authentication auth = new UsernamePasswordAuthenticationToken(currentUser, currentUser, currentUser.getAuthorities());
|
||||
SecurityContext context = SecurityContextHolder.getContext();
|
||||
context.setAuthentication(auth);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
|
||||
@Produces({MediaType.APPLICATION_JSON})
|
||||
public Response retrieveOffices() {
|
||||
|
||||
try {
|
||||
hardcodeUserIntoSecurityContext();
|
||||
|
||||
Collection<OfficeData> offices = this.readPlatformService.retrieveAllOffices();
|
||||
|
||||
return Response.ok().entity(new OfficeList(offices)).build();
|
||||
} catch (AccessDeniedException e) {
|
||||
ErrorResponse errorResponse = new ErrorResponse("error.msg.no.permission", "id");
|
||||
ErrorResponseList list = new ErrorResponseList(Arrays.asList(errorResponse));
|
||||
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(list).build());
|
||||
} catch (ApplicationDomainRuleException e) {
|
||||
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getErrors())).build());
|
||||
} catch (NewDataValidationException e) {
|
||||
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getValidationErrors())).build());
|
||||
}
|
||||
}
|
||||
|
||||
@POST
|
||||
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
|
||||
@Produces({ MediaType.APPLICATION_JSON})
|
||||
public Response createOffice(final OfficeCommand command) {
|
||||
|
||||
try {
|
||||
hardcodeUserIntoSecurityContext();
|
||||
|
||||
Long officeId = this.writePlatformService.createOffice(command);
|
||||
|
||||
return Response.ok().entity(new EntityIdentifier(officeId)).build();
|
||||
} catch (AccessDeniedException e) {
|
||||
ErrorResponse errorResponse = new ErrorResponse("error.msg.no.permission", "id");
|
||||
ErrorResponseList list = new ErrorResponseList(Arrays.asList(errorResponse));
|
||||
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(list).build());
|
||||
} catch (ApplicationDomainRuleException e) {
|
||||
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getErrors())).build());
|
||||
} catch (NewDataValidationException e) {
|
||||
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getValidationErrors())).build());
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{officeId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
|
||||
@Produces({ MediaType.APPLICATION_JSON})
|
||||
public Response retreiveOffice(@PathParam("officeId") final Long officeId) {
|
||||
|
||||
try {
|
||||
hardcodeUserIntoSecurityContext();
|
||||
|
||||
OfficeData office = this.readPlatformService.retrieveOffice(officeId);
|
||||
|
||||
return Response.ok().entity(office).build();
|
||||
} catch (AccessDeniedException e) {
|
||||
ErrorResponse errorResponse = new ErrorResponse("error.msg.no.permission", "id");
|
||||
ErrorResponseList list = new ErrorResponseList(Arrays.asList(errorResponse));
|
||||
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(list).build());
|
||||
} catch (ApplicationDomainRuleException e) {
|
||||
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getErrors())).build());
|
||||
} catch (NewDataValidationException e) {
|
||||
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getValidationErrors())).build());
|
||||
}
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("{officeId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
|
||||
@Produces({ MediaType.APPLICATION_JSON})
|
||||
public Response updateOffice(@PathParam("officeId") final Long officeId, final OfficeCommand command) {
|
||||
|
||||
try {
|
||||
hardcodeUserIntoSecurityContext();
|
||||
|
||||
command.setId(officeId);
|
||||
Long entityId = this.writePlatformService.updateOffice(command);
|
||||
|
||||
return Response.ok().entity(new EntityIdentifier(entityId)).build();
|
||||
} catch (AccessDeniedException e) {
|
||||
ErrorResponse errorResponse = new ErrorResponse("error.msg.no.permission", "id");
|
||||
ErrorResponseList list = new ErrorResponseList(Arrays.asList(errorResponse));
|
||||
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(list).build());
|
||||
} catch (ApplicationDomainRuleException e) {
|
||||
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getErrors())).build());
|
||||
} catch (NewDataValidationException e) {
|
||||
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getValidationErrors())).build());
|
||||
}
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package org.mifosng.platform.api.errorhandling;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
|
||||
import org.mifosng.data.ApiGlobalErrorResponse;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* An {@link ExceptionMapper} to map {@link AccessDeniedException} thrown by platform into a HTTP API friendly format.
|
||||
*
|
||||
* The {@link AccessDeniedException} is thrown by spring security on platform when an attempt is made to use functionality
|
||||
* for which the user does have sufficient privileges.
|
||||
*/
|
||||
@Provider
|
||||
@Component
|
||||
@Scope("singleton")
|
||||
public class AccessDeniedExceptionMapper implements ExceptionMapper<AccessDeniedException> {
|
||||
|
||||
@Override
|
||||
public Response toResponse(AccessDeniedException exception) {
|
||||
// Status code 403 really reads as: "Authenticated - but not authorized":
|
||||
return Response.status(Status.FORBIDDEN).entity(ApiGlobalErrorResponse.unAuthorized()).build();
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package org.mifosng.platform.api.errorhandling;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
|
||||
import org.mifosng.data.ApiGlobalErrorResponse;
|
||||
import org.mifosng.platform.exceptions.NoAuthorizationException;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* An {@link ExceptionMapper} to map {@link NoAuthorizationException} thrown by platform into a HTTP API friendly format.
|
||||
*
|
||||
* The {@link NoAuthorizationException} is thrown on platform when an attempt is made to use functionality
|
||||
* for which the user does have sufficient privileges.
|
||||
*/
|
||||
@Provider
|
||||
@Component
|
||||
@Scope("singleton")
|
||||
public class NoAuthorizationExceptionMapper implements ExceptionMapper<NoAuthorizationException> {
|
||||
|
||||
@Override
|
||||
public Response toResponse(NoAuthorizationException exception) {
|
||||
// Status code 403 really reads as: "Authenticated - but not authorized":
|
||||
return Response.status(Status.FORBIDDEN).entity(ApiGlobalErrorResponse.unAuthorized()).build();
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package org.mifosng.platform.api.errorhandling;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
|
||||
import org.mifosng.data.ApiGlobalErrorResponse;
|
||||
import org.mifosng.platform.exceptions.PlatformApiDataValidationException;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* An {@link ExceptionMapper} to map {@link PlatformApiDataValidationException} thrown by platform into a HTTP API friendly format.
|
||||
*
|
||||
* The {@link PlatformApiDataValidationException} is typically thrown in data validation of the parameters passed in with an api request.
|
||||
*/
|
||||
@Provider
|
||||
@Component
|
||||
@Scope("singleton")
|
||||
public class PlatformApiDataValidationExceptionMapper implements ExceptionMapper<PlatformApiDataValidationException> {
|
||||
|
||||
@Override
|
||||
public Response toResponse(PlatformApiDataValidationException exception) {
|
||||
|
||||
ApiGlobalErrorResponse dataIntegrityError = ApiGlobalErrorResponse.badClientRequest(exception.getGlobalisationMessageCode(),
|
||||
exception.getDefaultUserMessage(), exception.getErrors());
|
||||
|
||||
return Response.status(Status.BAD_REQUEST).entity(dataIntegrityError).build();
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package org.mifosng.platform.api.errorhandling;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
|
||||
import org.mifosng.data.ApiGlobalErrorResponse;
|
||||
import org.mifosng.platform.exceptions.PlatformDataIntegrityException;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* An {@link ExceptionMapper} to map {@link PlatformDataIntegrityException} thrown by platform into a HTTP API friendly format.
|
||||
*
|
||||
* The {@link PlatformDataIntegrityException} is thrown when modifying api call result in data integrity checks to be fired.
|
||||
*/
|
||||
@Provider
|
||||
@Component
|
||||
@Scope("singleton")
|
||||
public class PlatformDataIntegrityExceptionMapper implements ExceptionMapper<PlatformDataIntegrityException> {
|
||||
|
||||
@Override
|
||||
public Response toResponse(PlatformDataIntegrityException exception) {
|
||||
|
||||
ApiGlobalErrorResponse dataIntegrityError = ApiGlobalErrorResponse.dataIntegrityError(exception.getGlobalisationMessageCode(), exception.getDefaultUserMessage(),
|
||||
exception.getParameterName(), exception.getDefaultUserMessageArgs());
|
||||
|
||||
return Response.status(Status.BAD_REQUEST).entity(dataIntegrityError).build();
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package org.mifosng.platform.api.errorhandling;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
|
||||
import org.mifosng.data.ApiGlobalErrorResponse;
|
||||
import org.mifosng.platform.exceptions.PlatformResourceNotFoundException;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* An {@link ExceptionMapper} to map {@link PlatformResourceNotFoundException} thrown by platform into a HTTP API friendly format.
|
||||
*
|
||||
* The {@link PlatformResourceNotFoundException} is thrown when an api call for a resource that is expected to exist does not.
|
||||
*/
|
||||
@Provider
|
||||
@Component
|
||||
@Scope("singleton")
|
||||
public class PlatformResourceNotFoundExceptionMapper implements ExceptionMapper<PlatformResourceNotFoundException> {
|
||||
|
||||
@Override
|
||||
public Response toResponse(PlatformResourceNotFoundException exception) {
|
||||
|
||||
ApiGlobalErrorResponse notFoundErrorResponse = ApiGlobalErrorResponse.notFound(exception.getGlobalisationMessageCode(), exception.getDefaultUserMessage(), exception.getDefaultUserMessageArgs());
|
||||
return Response.status(Status.NOT_FOUND).entity(notFoundErrorResponse).build();
|
||||
}
|
||||
}
|
||||
+3
-8
@@ -1,14 +1,11 @@
|
||||
package org.mifosng.platform.api.errorhandling;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
|
||||
import org.mifosng.data.ErrorResponse;
|
||||
import org.mifosng.data.ErrorResponseList;
|
||||
import org.mifosng.data.ApiGlobalErrorResponse;
|
||||
import org.mifosng.platform.exceptions.UnAuthenticatedUserException;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -23,9 +20,7 @@ public class UnAuthenticatedUserExceptionMapper implements ExceptionMapper<UnAut
|
||||
|
||||
@Override
|
||||
public Response toResponse(UnAuthenticatedUserException exception) {
|
||||
ErrorResponse errorResponse = new ErrorResponse("error.msg.not.authorized", "id");
|
||||
ErrorResponseList list = new ErrorResponseList(Arrays.asList(errorResponse));
|
||||
|
||||
return Response.status(Status.UNAUTHORIZED).entity(list).build();
|
||||
// Status code 401 really reads as: "Unauthenticated":
|
||||
return Response.status(Status.UNAUTHORIZED).entity(ApiGlobalErrorResponse.unAuthenticated()).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package org.mifosng.platform.api.office;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.mifosng.data.EntityIdentifier;
|
||||
import org.mifosng.data.OfficeData;
|
||||
import org.mifosng.data.OfficeList;
|
||||
import org.mifosng.data.command.OfficeCommand;
|
||||
import org.mifosng.platform.WritePlatformService;
|
||||
import org.mifosng.platform.organisation.service.OfficeReadPlatformService;
|
||||
import org.mifosng.platform.user.domain.AppUser;
|
||||
import org.mifosng.platform.user.domain.AppUserRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Path("/v1/offices")
|
||||
@Component
|
||||
@Scope("singleton")
|
||||
public class OfficeApiResource {
|
||||
|
||||
@Autowired
|
||||
private OfficeReadPlatformService readPlatformService;
|
||||
|
||||
@Autowired
|
||||
private WritePlatformService writePlatformService;
|
||||
|
||||
@Autowired
|
||||
private AppUserRepository appUserRepository;
|
||||
|
||||
private void hardcodeUserIntoSecurityContext() {
|
||||
AppUser currentUser = this.appUserRepository.findOne(Long.valueOf(1));
|
||||
|
||||
Authentication auth = new UsernamePasswordAuthenticationToken(currentUser, currentUser, currentUser.getAuthorities());
|
||||
SecurityContext context = SecurityContextHolder.getContext();
|
||||
context.setAuthentication(auth);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
|
||||
@Produces({MediaType.APPLICATION_JSON})
|
||||
public Response retrieveOffices() {
|
||||
hardcodeUserIntoSecurityContext();
|
||||
|
||||
Collection<OfficeData> offices = this.readPlatformService.retrieveAllOffices();
|
||||
|
||||
return Response.ok().entity(new OfficeList(offices)).build();
|
||||
}
|
||||
|
||||
@POST
|
||||
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
|
||||
@Produces({ MediaType.APPLICATION_JSON})
|
||||
public Response createOffice(final OfficeCommand command) {
|
||||
hardcodeUserIntoSecurityContext();
|
||||
|
||||
Long officeId = this.writePlatformService.createOffice(command);
|
||||
|
||||
return Response.ok().entity(new EntityIdentifier(officeId)).build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{officeId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
|
||||
@Produces({ MediaType.APPLICATION_JSON})
|
||||
public Response retreiveOffice(@PathParam("officeId") final Long officeId) {
|
||||
hardcodeUserIntoSecurityContext();
|
||||
|
||||
OfficeData office = this.readPlatformService.retrieveOffice(officeId);
|
||||
|
||||
return Response.ok().entity(office).build();
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("{officeId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
|
||||
@Produces({ MediaType.APPLICATION_JSON})
|
||||
public Response updateOffice(@PathParam("officeId") final Long officeId, final OfficeCommand command) {
|
||||
hardcodeUserIntoSecurityContext();
|
||||
|
||||
command.setId(officeId);
|
||||
Long entityId = this.writePlatformService.updateOffice(command);
|
||||
|
||||
return Response.ok().entity(new EntityIdentifier(entityId)).build();
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package org.mifosng.platform.exceptions;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.mifosng.data.ApiParameterError;
|
||||
|
||||
public class PlatformApiDataValidationException extends RuntimeException {
|
||||
|
||||
private final String globalisationMessageCode;
|
||||
private final String defaultUserMessage;
|
||||
private final List<ApiParameterError> errors;
|
||||
|
||||
public PlatformApiDataValidationException(final String globalisationMessageCode, final String defaultUserMessage, List<ApiParameterError> errors) {
|
||||
this.globalisationMessageCode = globalisationMessageCode;
|
||||
this.defaultUserMessage = defaultUserMessage;
|
||||
this.errors = errors;
|
||||
}
|
||||
|
||||
public String getGlobalisationMessageCode() {
|
||||
return globalisationMessageCode;
|
||||
}
|
||||
|
||||
public String getDefaultUserMessage() {
|
||||
return defaultUserMessage;
|
||||
}
|
||||
|
||||
public List<ApiParameterError> getErrors() {
|
||||
return errors;
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package org.mifosng.platform.exceptions;
|
||||
|
||||
/**
|
||||
* A {@link RuntimeException} thrown when data integrity problems happen due to state modifying actions.
|
||||
*/
|
||||
public class PlatformDataIntegrityException extends RuntimeException {
|
||||
|
||||
private final String globalisationMessageCode;
|
||||
private final String defaultUserMessage;
|
||||
private final String parameterName;
|
||||
private final Object[] defaultUserMessageArgs;
|
||||
|
||||
public PlatformDataIntegrityException(final String globalisationMessageCode, final String defaultUserMessage, final Object... defaultUserMessageArgs) {
|
||||
this.globalisationMessageCode = globalisationMessageCode;
|
||||
this.defaultUserMessage = defaultUserMessage;
|
||||
this.parameterName = "";
|
||||
this.defaultUserMessageArgs = defaultUserMessageArgs;
|
||||
}
|
||||
|
||||
public PlatformDataIntegrityException(final String globalisationMessageCode, final String defaultUserMessage, final String parameterName, final Object... defaultUserMessageArgs) {
|
||||
this.globalisationMessageCode = globalisationMessageCode;
|
||||
this.defaultUserMessage = defaultUserMessage;
|
||||
this.parameterName = parameterName;
|
||||
this.defaultUserMessageArgs = defaultUserMessageArgs;
|
||||
}
|
||||
|
||||
public String getGlobalisationMessageCode() {
|
||||
return globalisationMessageCode;
|
||||
}
|
||||
|
||||
public String getDefaultUserMessage() {
|
||||
return defaultUserMessage;
|
||||
}
|
||||
|
||||
public Object[] getDefaultUserMessageArgs() {
|
||||
return defaultUserMessageArgs;
|
||||
}
|
||||
|
||||
public String getParameterName() {
|
||||
return parameterName;
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package org.mifosng.platform.exceptions;
|
||||
|
||||
/**
|
||||
* A {@link RuntimeException} thrown when resources that are queried for are not found.
|
||||
*/
|
||||
public class PlatformResourceNotFoundException extends RuntimeException {
|
||||
|
||||
private final String globalisationMessageCode;
|
||||
private final String defaultUserMessage;
|
||||
private final Object[] defaultUserMessageArgs;
|
||||
|
||||
public PlatformResourceNotFoundException(String globalisationMessageCode, String defaultUserMessage, Object... defaultUserMessageArgs) {
|
||||
this.globalisationMessageCode = globalisationMessageCode;
|
||||
this.defaultUserMessage = defaultUserMessage;
|
||||
this.defaultUserMessageArgs = defaultUserMessageArgs;
|
||||
}
|
||||
|
||||
public String getGlobalisationMessageCode() {
|
||||
return globalisationMessageCode;
|
||||
}
|
||||
|
||||
public String getDefaultUserMessage() {
|
||||
return defaultUserMessage;
|
||||
}
|
||||
|
||||
public Object[] getDefaultUserMessageArgs() {
|
||||
return defaultUserMessageArgs;
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -35,7 +35,8 @@ public class CustomAuthenticationFailureHandler implements AuthenticationFailure
|
||||
* If redirecting or forwarding, {@code saveException} will be called to cache the exception for use in
|
||||
* the target view.
|
||||
*/
|
||||
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
|
||||
@Override
|
||||
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException exception) throws IOException, ServletException {
|
||||
|
||||
if (defaultFailureUrl == null) {
|
||||
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package org.mifosng.platform.organisation.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosng.data.ApiParameterError;
|
||||
import org.mifosng.platform.exceptions.PlatformApiDataValidationException;
|
||||
|
||||
public class OfficeCommandValidator {
|
||||
|
||||
private final String name;
|
||||
private final Long parentId;
|
||||
private final LocalDate openingDate;
|
||||
private final String externalId;
|
||||
|
||||
public OfficeCommandValidator(String name, Long parentId, LocalDate openingDate, String externalId) {
|
||||
this.name = name;
|
||||
this.parentId = parentId;
|
||||
this.openingDate = openingDate;
|
||||
this.externalId = externalId;
|
||||
}
|
||||
|
||||
public void validate() {
|
||||
|
||||
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
|
||||
if (StringUtils.isBlank(this.name)) {
|
||||
ApiParameterError error = ApiParameterError.parameterError("validation.msg.office.name.cannot.be.blank", "The parameter name cannot be blank.", "name");
|
||||
dataValidationErrors.add(error);
|
||||
}
|
||||
|
||||
if (this.parentId == null || parentId.intValue() <= 0) {
|
||||
ApiParameterError error = ApiParameterError.parameterError("validation.msg.office.parent.cannot.be.blank", "A valid parentId must be provided.", "parentId");
|
||||
dataValidationErrors.add(error);
|
||||
}
|
||||
|
||||
if (this.openingDate == null) {
|
||||
ApiParameterError error = ApiParameterError.parameterError("validation.msg.office.opening.date.cannot.be.blank", "The parameter openingDate cannot be blank", "openingDate");
|
||||
dataValidationErrors.add(error);
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(this.externalId)) {
|
||||
if (this.externalId.trim().length() > 100) {
|
||||
ApiParameterError error = ApiParameterError.parameterError("validation.msg.office.externalId.exceeds.max.length", "The parameter externalId exceeds max length of {0}", "externalId", 100);
|
||||
dataValidationErrors.add(error);
|
||||
}
|
||||
}
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
package org.mifosng.platform.organisation.service;
|
||||
|
||||
import static org.mifosng.platform.Specifications.officesThatMatch;
|
||||
|
||||
import org.mifosng.data.command.OfficeCommand;
|
||||
import org.mifosng.platform.exceptions.NoAuthorizationException;
|
||||
import org.mifosng.platform.exceptions.PlatformDataIntegrityException;
|
||||
import org.mifosng.platform.organisation.domain.Office;
|
||||
import org.mifosng.platform.organisation.domain.OfficeRepository;
|
||||
import org.mifosng.platform.user.domain.AppUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class OfficePlatformServiceJpaRepositoryImpl implements OfficeWritePlatformService {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(OfficePlatformServiceJpaRepositoryImpl.class);
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final OfficeRepository officeRepository;
|
||||
|
||||
@Autowired
|
||||
public OfficePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final OfficeRepository officeRepository) {
|
||||
this.context = context;
|
||||
this.officeRepository = officeRepository;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public Long createOffice(final OfficeCommand command) {
|
||||
|
||||
try {
|
||||
AppUser currentUser = context.authenticatedUser();
|
||||
|
||||
OfficeCommandValidator validator = new OfficeCommandValidator(command.getName(), command.getParentId(), command.getOpeningDate(), command.getExternalId());
|
||||
validator.validate();
|
||||
|
||||
Office parent = validateUserPriviledgeOnOfficeAndRetrieve(currentUser, command.getParentId());
|
||||
|
||||
Office office = Office.createNew(currentUser.getOrganisation(), parent, command.getName(), command.getOpeningDate(), command.getExternalId());
|
||||
|
||||
// pre save to generate id for use in office hierarchy
|
||||
this.officeRepository.save(office);
|
||||
|
||||
office.generateHierarchy();
|
||||
|
||||
this.officeRepository.save(office);
|
||||
|
||||
return office.getId();
|
||||
} catch (DataIntegrityViolationException dve) {
|
||||
handleOfficeDataIntegrityIssues(command, dve);
|
||||
return Long.valueOf(-1);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public Long updateOffice(final OfficeCommand command) {
|
||||
|
||||
try {
|
||||
AppUser currentUser = context.authenticatedUser();
|
||||
|
||||
OfficeCommandValidator validator = new OfficeCommandValidator(command.getName(), command.getParentId(), command.getOpeningDate(), command.getExternalId());
|
||||
validator.validate();
|
||||
|
||||
Office office = validateUserPriviledgeOnOfficeAndRetrieve(currentUser, command.getId());
|
||||
|
||||
office.update(command.getName(), command.getExternalId(), command.getOpeningDate());
|
||||
|
||||
this.officeRepository.save(office);
|
||||
|
||||
return office.getId();
|
||||
} catch (DataIntegrityViolationException dve) {
|
||||
handleOfficeDataIntegrityIssues(command, dve);
|
||||
return Long.valueOf(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Guaranteed to throw an exception no matter what the data integrity issue is.
|
||||
*/
|
||||
private void handleOfficeDataIntegrityIssues(final OfficeCommand command, DataIntegrityViolationException dve) {
|
||||
|
||||
Throwable realCause = dve.getMostSpecificCause();
|
||||
if (realCause.getMessage().contains("externalid_org")) {
|
||||
throw new PlatformDataIntegrityException("error.msg.office.duplicate.externalId", "Office with externalId {0} already exists", "externalId", command.getExternalId());
|
||||
} else if (realCause.getMessage().contains("name_org")) {
|
||||
throw new PlatformDataIntegrityException("error.msg.office.duplicate.name", "Office with name {0} already exists", "name", command.getName());
|
||||
}
|
||||
|
||||
logger.error(dve.getMessage(), dve);
|
||||
throw new PlatformDataIntegrityException("error.msg.office.unknown.data.integrity.issue", "Unknown data integrity issue with resource.");
|
||||
}
|
||||
|
||||
/*
|
||||
* used to restrict modifying operations to office that are either the users office or lower (child) in the office hierarchy
|
||||
*/
|
||||
private Office validateUserPriviledgeOnOfficeAndRetrieve(AppUser currentUser, Long officeId) {
|
||||
|
||||
Office userOffice = this.officeRepository.findOne(officesThatMatch(currentUser.getOrganisation(), currentUser.getOffice().getId()));
|
||||
|
||||
if (userOffice.doesNotHaveAnOfficeInHierarchyWithId(officeId)) {
|
||||
throw new NoAuthorizationException("User does not have sufficient priviledges to act on the provided office.");
|
||||
}
|
||||
|
||||
Office officeToReturn = userOffice;
|
||||
if (!userOffice.identifiedBy(officeId)) {
|
||||
officeToReturn = this.officeRepository.findOne(officesThatMatch(currentUser.getOrganisation(), officeId));
|
||||
}
|
||||
|
||||
return officeToReturn;
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package org.mifosng.platform.organisation.service;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mifosng.data.OfficeData;
|
||||
|
||||
public interface OfficeReadPlatformService {
|
||||
|
||||
Collection<OfficeData> retrieveAllOffices();
|
||||
|
||||
OfficeData retrieveOffice(Long officeId);
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
package org.mifosng.platform.organisation.service;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosng.data.OfficeData;
|
||||
import org.mifosng.platform.exceptions.PlatformResourceNotFoundException;
|
||||
import org.mifosng.platform.user.domain.AppUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class OfficeReadPlatformServiceImpl implements OfficeReadPlatformService {
|
||||
|
||||
private final SimpleJdbcTemplate jdbcTemplate;
|
||||
private final PlatformSecurityContext context;
|
||||
|
||||
@Autowired
|
||||
public OfficeReadPlatformServiceImpl(final PlatformSecurityContext context, final DataSource dataSource) {
|
||||
this.context = context;
|
||||
this.jdbcTemplate = new SimpleJdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
private static final class OfficeMapper implements RowMapper<OfficeData> {
|
||||
|
||||
public String officeSchema() {
|
||||
return " o.id as id, o.name as name, o.external_id as externalId, o.opening_date as openingDate, o.hierarchy as hierarchy, parent.id as parentId, parent.name as parentName "
|
||||
+ "from org_office o LEFT JOIN org_office AS parent ON parent.id = o.parent_id ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public OfficeData mapRow(final ResultSet rs, final int rowNum)
|
||||
throws SQLException {
|
||||
|
||||
Long id = rs.getLong("id");
|
||||
String name = rs.getString("name");
|
||||
String externalId = rs.getString("externalId");
|
||||
LocalDate openingDate = new LocalDate(rs.getDate("openingDate"));
|
||||
String hierarchy = rs.getString("hierarchy");
|
||||
Long parentId = rs.getLong("parentId");
|
||||
String parentName = rs.getString("parentName");
|
||||
|
||||
return new OfficeData(id, name, externalId, openingDate, hierarchy, parentId, parentName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<OfficeData> retrieveAllOffices() {
|
||||
|
||||
AppUser currentUser = context.authenticatedUser();
|
||||
|
||||
String hierarchy = currentUser.getOffice().getHierarchy();
|
||||
String hierarchySearchString = hierarchy + "%";
|
||||
|
||||
OfficeMapper rm = new OfficeMapper();
|
||||
String sql = "select " + rm.officeSchema() + "where o.org_id = ? and o.hierarchy like ? order by o.hierarchy";
|
||||
|
||||
return this.jdbcTemplate.query(sql, rm, new Object[] {currentUser.getOrganisation().getId(), hierarchySearchString});
|
||||
}
|
||||
|
||||
@Override
|
||||
public OfficeData retrieveOffice(final Long officeId) {
|
||||
|
||||
try {
|
||||
AppUser currentUser = context.authenticatedUser();
|
||||
|
||||
OfficeMapper rm = new OfficeMapper();
|
||||
String sql = "select " + rm.officeSchema()
|
||||
+ " where o.org_id = ? and o.id = ?";
|
||||
|
||||
OfficeData selectedOffice = this.jdbcTemplate.queryForObject(sql,
|
||||
rm, new Object[] { currentUser.getOrganisation().getId(),
|
||||
officeId });
|
||||
|
||||
List<OfficeData> allowedParents = new ArrayList<OfficeData>();
|
||||
|
||||
if (StringUtils.isNotBlank(selectedOffice.getParentName())) {
|
||||
Collection<OfficeData> allOffices = retrieveAllOffices();
|
||||
|
||||
for (OfficeData office : allOffices) {
|
||||
|
||||
if (!office.getId().equals(selectedOffice.getId())) {
|
||||
allowedParents.add(office);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
selectedOffice.setAllowedParents(allowedParents);
|
||||
|
||||
return selectedOffice;
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
throw new PlatformResourceNotFoundException("error.msg.office.id.invalid", "Office with identifier {0} does not exist", officeId);
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package org.mifosng.platform.organisation.service;
|
||||
|
||||
import org.mifosng.data.command.OfficeCommand;
|
||||
|
||||
public interface OfficeWritePlatformService {
|
||||
|
||||
Long createOffice(OfficeCommand command);
|
||||
|
||||
Long updateOffice(OfficeCommand command);
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package org.mifosng.platform.organisation.service;
|
||||
|
||||
import org.mifosng.platform.user.domain.AppUser;
|
||||
|
||||
public interface PlatformSecurityContext {
|
||||
|
||||
AppUser authenticatedUser();
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package org.mifosng.platform.organisation.service;
|
||||
|
||||
import org.mifosng.platform.exceptions.UnAuthenticatedUserException;
|
||||
import org.mifosng.platform.user.domain.AppUser;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* Responsible for returning the current authenticated user that is currently set in the {@link SecurityContext}.
|
||||
*/
|
||||
@Service
|
||||
public class PlatformSecurityContextThroughSpringSecurity implements PlatformSecurityContext {
|
||||
|
||||
@Override
|
||||
public AppUser authenticatedUser() {
|
||||
AppUser currentUser = null;
|
||||
SecurityContext context = SecurityContextHolder.getContext();
|
||||
if (context != null) {
|
||||
Authentication auth = context.getAuthentication();
|
||||
if (auth != null) {
|
||||
currentUser = (AppUser) auth.getPrincipal();
|
||||
}
|
||||
}
|
||||
|
||||
if (currentUser == null) {
|
||||
throw new UnAuthenticatedUserException();
|
||||
}
|
||||
|
||||
return currentUser;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user