add source for individual lending app.
This commit is contained in:
+9
@@ -0,0 +1,9 @@
|
||||
package org.mifosng.configuration;
|
||||
|
||||
public interface ApplicationConfigurationService {
|
||||
|
||||
OAuthProviderDetails retrieveOAuthProviderDetails();
|
||||
|
||||
void update(OAuthProviderDetails newDetails);
|
||||
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package org.mifosng.configuration;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* When application goes down or rebooted, configuration values return to defaults provided here.
|
||||
*/
|
||||
@Service
|
||||
public class InMemoryApplicationConfigurationService implements
|
||||
ApplicationConfigurationService {
|
||||
|
||||
private String oauthProviderUrl = "http://localhost:8085/mifosng-provider/";
|
||||
private String requestTokenURL = "oauth/request_token";
|
||||
private String userAuthorizationURL = "oauth/confirm_access";
|
||||
private String accessTokenURL = "oauth/access_token";
|
||||
|
||||
private String individualLendingResourceConsumerkey = "mifosng-ui-consumer-key";
|
||||
private String individualLendingConsumerSharedSecret = "testmifosng";
|
||||
|
||||
public InMemoryApplicationConfigurationService() {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuthProviderDetails retrieveOAuthProviderDetails() {
|
||||
|
||||
String requestTokenFullUrl = this.oauthProviderUrl
|
||||
.concat(this.requestTokenURL);
|
||||
String userAuthorizationFullURL = this.oauthProviderUrl
|
||||
.concat(this.userAuthorizationURL);
|
||||
String accessTokenFullURL = this.oauthProviderUrl
|
||||
.concat(this.accessTokenURL);
|
||||
|
||||
return new OAuthProviderDetails(this.oauthProviderUrl, requestTokenFullUrl,
|
||||
userAuthorizationFullURL, accessTokenFullURL,
|
||||
this.individualLendingResourceConsumerkey,
|
||||
this.individualLendingConsumerSharedSecret);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(OAuthProviderDetails newDetails) {
|
||||
this.oauthProviderUrl = newDetails.getProviderBaseUrl();
|
||||
if (!this.oauthProviderUrl.endsWith("/")) {
|
||||
this.oauthProviderUrl = this.oauthProviderUrl.concat("/");
|
||||
}
|
||||
|
||||
this.individualLendingResourceConsumerkey = newDetails.getConsumerkey();
|
||||
this.individualLendingConsumerSharedSecret = newDetails.getSharedSecret();
|
||||
}
|
||||
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package org.mifosng.configuration;
|
||||
|
||||
public class OAuthProviderDetails {
|
||||
|
||||
private final String requestTokenUrl;
|
||||
private final String userAuthorizationUrl;
|
||||
private final String accessTokenUrl;
|
||||
private final String sharedSecret;
|
||||
private final String consumerkey;
|
||||
private final String providerBaseUrl;
|
||||
|
||||
public OAuthProviderDetails(String providerBaseUrl, String requestTokenUrl,
|
||||
String userAuthorizationUrl, String accessTokenUrl,
|
||||
String consumerkey, String sharedSecret) {
|
||||
this.providerBaseUrl = providerBaseUrl;
|
||||
this.requestTokenUrl = requestTokenUrl;
|
||||
this.userAuthorizationUrl = userAuthorizationUrl;
|
||||
this.accessTokenUrl = accessTokenUrl;
|
||||
this.consumerkey = consumerkey;
|
||||
this.sharedSecret = sharedSecret;
|
||||
}
|
||||
|
||||
public OAuthProviderDetails(String oauthProviderUrl, String consumerkey,
|
||||
String sharedSecret) {
|
||||
this.providerBaseUrl = oauthProviderUrl;
|
||||
this.consumerkey = consumerkey;
|
||||
this.sharedSecret = sharedSecret;
|
||||
this.accessTokenUrl = "";
|
||||
this.userAuthorizationUrl = "";
|
||||
this.requestTokenUrl = "";
|
||||
}
|
||||
|
||||
public String getRequestTokenUrl() {
|
||||
return requestTokenUrl;
|
||||
}
|
||||
|
||||
public String getUserAuthorizationUrl() {
|
||||
return userAuthorizationUrl;
|
||||
}
|
||||
|
||||
public String getAccessTokenUrl() {
|
||||
return accessTokenUrl;
|
||||
}
|
||||
|
||||
public String getSharedSecret() {
|
||||
return sharedSecret;
|
||||
}
|
||||
|
||||
public String getConsumerkey() {
|
||||
return consumerkey;
|
||||
}
|
||||
|
||||
public String getProviderBaseUrl() {
|
||||
return providerBaseUrl;
|
||||
}
|
||||
}
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
package org.mifosng.oauth;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
public class ConsumerUserDetails implements UserDetails {
|
||||
|
||||
private final String username;
|
||||
private final Collection<GrantedAuthority> authorities;
|
||||
|
||||
public ConsumerUserDetails(String username, Collection<GrantedAuthority> authorities) {
|
||||
this.username = username;
|
||||
this.authorities = authorities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return authorities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean hasNoReportingAuthority() {
|
||||
return !hasReportingAuthority();
|
||||
}
|
||||
|
||||
private boolean hasReportingAuthority() {
|
||||
SimpleGrantedAuthority reportingAuthority = new SimpleGrantedAuthority("REPORTING_SUPER_USER_ROLE");
|
||||
return this.authorities.contains(reportingAuthority);
|
||||
}
|
||||
|
||||
public boolean hasNoAuthorityToSumitLoanApplication() {
|
||||
return !hasAuthorityToSumitLoanApplication();
|
||||
}
|
||||
|
||||
private boolean hasAuthorityToSumitLoanApplication() {
|
||||
return containsAnyOf(portfolioAllAuthority(), sumbitLoanApplicationAuthority(), sumbitHistoricLoanApplicationAuthority());
|
||||
}
|
||||
|
||||
private boolean containsAnyOf(SimpleGrantedAuthority... authorities) {
|
||||
boolean match = false;
|
||||
for (SimpleGrantedAuthority authority : authorities) {
|
||||
match = this.authorities.contains(authority);
|
||||
if (match) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
private SimpleGrantedAuthority portfolioAllAuthority() {
|
||||
return new SimpleGrantedAuthority("PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE");
|
||||
}
|
||||
|
||||
private SimpleGrantedAuthority sumbitLoanApplicationAuthority() {
|
||||
return new SimpleGrantedAuthority("CAN_SUBMIT_NEW_LOAN_APPLICATION_ROLE");
|
||||
}
|
||||
|
||||
private SimpleGrantedAuthority sumbitHistoricLoanApplicationAuthority() {
|
||||
return new SimpleGrantedAuthority("CAN_SUBMIT_HISTORIC_LOAN_APPLICATION_ROLE");
|
||||
}
|
||||
}
|
||||
+270
@@ -0,0 +1,270 @@
|
||||
package org.mifosng.oauth;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.mifosng.configuration.ApplicationConfigurationService;
|
||||
import org.mifosng.data.AuthenticatedUserData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.context.SecurityContextImpl;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.oauth.common.OAuthProviderParameter;
|
||||
import org.springframework.security.oauth.consumer.OAuthConsumerToken;
|
||||
import org.springframework.security.oauth.consumer.OAuthRequestFailedException;
|
||||
import org.springframework.security.oauth.consumer.OAuthSecurityContextHolder;
|
||||
import org.springframework.security.oauth.consumer.OAuthSecurityContextImpl;
|
||||
import org.springframework.security.oauth.consumer.ProtectedResourceDetails;
|
||||
import org.springframework.security.oauth.consumer.client.CoreOAuthConsumerSupport;
|
||||
import org.springframework.security.oauth.consumer.filter.OAuthConsumerContextFilter;
|
||||
import org.springframework.security.web.DefaultRedirectStrategy;
|
||||
import org.springframework.security.web.RedirectStrategy;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
|
||||
public class CustomOAuthConsumerContextFilter extends OAuthConsumerContextFilter {
|
||||
|
||||
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
|
||||
private final ApplicationConfigurationService applicationConfigurationService;
|
||||
|
||||
@Autowired
|
||||
public CustomOAuthConsumerContextFilter(final ApplicationConfigurationService applicationConfigurationService) {
|
||||
this.applicationConfigurationService = applicationConfigurationService;
|
||||
|
||||
}
|
||||
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
|
||||
HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
HttpServletResponse response = (HttpServletResponse) servletResponse;
|
||||
|
||||
OAuthSecurityContextImpl context = new OAuthSecurityContextImpl();
|
||||
context.setDetails(request);
|
||||
|
||||
Map<String, OAuthConsumerToken> rememberedTokens = getRememberMeServices().loadRememberedTokens(request, response);
|
||||
Map<String, OAuthConsumerToken> accessTokens = new TreeMap<String, OAuthConsumerToken>();
|
||||
Map<String, OAuthConsumerToken> requestTokens = new TreeMap<String, OAuthConsumerToken>();
|
||||
if (rememberedTokens != null) {
|
||||
for (Map.Entry<String, OAuthConsumerToken> tokenEntry : rememberedTokens.entrySet()) {
|
||||
OAuthConsumerToken token = tokenEntry.getValue();
|
||||
if (token != null) {
|
||||
if (token.isAccessToken()) {
|
||||
accessTokens.put(tokenEntry.getKey(), token);
|
||||
}
|
||||
else {
|
||||
requestTokens.put(tokenEntry.getKey(), token);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context.setAccessTokens(accessTokens);
|
||||
OAuthSecurityContextHolder.setContext(context);
|
||||
// if (LOG.isDebugEnabled()) {
|
||||
// LOG.debug("Storing access tokens in request attribute '" + getAccessTokensRequestAttribute() + "'.");
|
||||
// }
|
||||
|
||||
try {
|
||||
try {
|
||||
request.setAttribute(getAccessTokensRequestAttribute(), new ArrayList<OAuthConsumerToken>(accessTokens.values()));
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
catch (Exception e) {
|
||||
try {
|
||||
ProtectedResourceDetails resourceThatNeedsAuthorization = checkForResourceThatNeedsAuthorization(e);
|
||||
String neededResourceId = resourceThatNeedsAuthorization.getId();
|
||||
while (!accessTokens.containsKey(neededResourceId)) {
|
||||
OAuthConsumerToken token = requestTokens.remove(neededResourceId);
|
||||
if (token == null) {
|
||||
token = getTokenServices().getToken(neededResourceId);
|
||||
}
|
||||
|
||||
String verifier = request.getParameter(OAuthProviderParameter.oauth_verifier.toString());
|
||||
// if the token is null OR
|
||||
// if there is NO access token and (we're not using 1.0a or the verifier is not null)
|
||||
if (token == null || (!token.isAccessToken() && (!resourceThatNeedsAuthorization.isUse10a() || verifier == null))) {
|
||||
//no token associated with the resource, start the oauth flow.
|
||||
//if there's a request token, but no verifier, we'll assume that a previous oauth request failed and we need to get a new request token.
|
||||
// if (LOG.isDebugEnabled()) {
|
||||
// LOG.debug("Obtaining request token for resource: " + neededResourceId);
|
||||
// }
|
||||
|
||||
//obtain authorization.
|
||||
String callbackURL = response.encodeRedirectURL(getCallbackURL(request));
|
||||
token = getConsumerSupport().getUnauthorizedRequestToken(neededResourceId, callbackURL);
|
||||
// if (LOG.isDebugEnabled()) {
|
||||
// LOG.debug("Request token obtained for resource " + neededResourceId + ": " + token);
|
||||
// }
|
||||
|
||||
//okay, we've got a request token, now we need to authorize it.
|
||||
requestTokens.put(neededResourceId, token);
|
||||
getTokenServices().storeToken(neededResourceId, token);
|
||||
|
||||
|
||||
try {
|
||||
String baseURL = this.applicationConfigurationService.retrieveOAuthProviderDetails().getUserAuthorizationUrl();
|
||||
StringBuilder builder = new StringBuilder(baseURL);
|
||||
char appendChar = baseURL.indexOf('?') < 0 ? '?' : '&';
|
||||
builder.append(appendChar).append("oauth_token=");
|
||||
builder.append(URLEncoder.encode(token.getValue(), "UTF-8"));
|
||||
builder.append('&').append("oauth_callback=");
|
||||
builder.append(URLEncoder.encode(callbackURL, "UTF-8"));
|
||||
|
||||
String redirect = builder.toString();
|
||||
|
||||
request.setAttribute("org.springframework.security.oauth.consumer.AccessTokenRequiredException", e);
|
||||
this.redirectStrategy.sendRedirect(request, response, redirect);
|
||||
return;
|
||||
}
|
||||
catch (UnsupportedEncodingException use) {
|
||||
throw new IllegalStateException(use);
|
||||
}
|
||||
}
|
||||
else if (!token.isAccessToken()) {
|
||||
//we have a presumably authorized request token, let's try to get an access token with it.
|
||||
// if (LOG.isDebugEnabled()) {
|
||||
// LOG.debug("Obtaining access token for resource: " + neededResourceId);
|
||||
// }
|
||||
|
||||
//authorize the request token and store it.
|
||||
try {
|
||||
token = getConsumerSupport().getAccessToken(token, verifier);
|
||||
}
|
||||
finally {
|
||||
getTokenServices().removeToken(neededResourceId);
|
||||
}
|
||||
|
||||
// if (LOG.isDebugEnabled()) {
|
||||
// LOG.debug("Access token " + token + " obtained for resource " + neededResourceId + ". Now storing and using.");
|
||||
// }
|
||||
|
||||
getTokenServices().storeToken(neededResourceId, token);
|
||||
}
|
||||
|
||||
accessTokens.put(neededResourceId, token);
|
||||
|
||||
// hack here to detect this situation which happens once user is authenticated successfully on provider
|
||||
// and redirected back to this client application
|
||||
String oauthAccessToken = request.getParameter("oauth_token");
|
||||
String oauthVerifier = request.getParameter("oauth_verifier");
|
||||
|
||||
if (StringUtils.isNotBlank(oauthAccessToken) && StringUtils.isNotBlank(oauthVerifier)) {
|
||||
CoreOAuthConsumerSupport support = (CoreOAuthConsumerSupport)getConsumerSupport();
|
||||
|
||||
MifosNgOauthRestTemplate oauthRestTemplate = new MifosNgOauthRestTemplate(support.getProtectedResourceDetailsService());
|
||||
try {
|
||||
URI restUri = URI
|
||||
.create(getBaseServerUrl().concat("api/protected/user/"
|
||||
+ oauthAccessToken));
|
||||
|
||||
ResponseEntity<AuthenticatedUserData> s = oauthRestTemplate.exchange(restUri, HttpMethod.GET, emptyRequest(), AuthenticatedUserData.class);
|
||||
|
||||
AuthenticatedUserData userData = s.getBody();
|
||||
|
||||
SecurityContextHolder.clearContext();
|
||||
SecurityContext springSecurityContext = new SecurityContextImpl();
|
||||
|
||||
Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
|
||||
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
|
||||
for (String permissionCode : userData.getPermissions()) {
|
||||
authorities.add(new SimpleGrantedAuthority(permissionCode));
|
||||
}
|
||||
|
||||
UserDetails principal = new ConsumerUserDetails(userData.getUsername(), authorities);
|
||||
Authentication auth = new UsernamePasswordAuthenticationToken(principal, principal, principal.getAuthorities());
|
||||
springSecurityContext.setAuthentication(auth);
|
||||
|
||||
SecurityContextHolder.setContext(springSecurityContext);
|
||||
|
||||
} catch (HttpStatusCodeException ex) {
|
||||
System.err.println(ex.getResponseBodyAsString());
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
//try again
|
||||
if (!response.isCommitted()) {
|
||||
request.setAttribute(getAccessTokensRequestAttribute(), new ArrayList<OAuthConsumerToken>(accessTokens.values()));
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
else {
|
||||
//dang. what do we do now?
|
||||
throw new IllegalStateException("Unable to reprocess filter chain with needed OAuth2 resources because the response is already committed.");
|
||||
}
|
||||
}
|
||||
catch (Exception e1) {
|
||||
resourceThatNeedsAuthorization = checkForResourceThatNeedsAuthorization(e1);
|
||||
neededResourceId = resourceThatNeedsAuthorization.getId();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (OAuthRequestFailedException eo) {
|
||||
fail(request, response, eo);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Throwable[] causeChain = getThrowableAnalyzer().determineCauseChain(ex);
|
||||
OAuthRequestFailedException rfe = (OAuthRequestFailedException) getThrowableAnalyzer().getFirstThrowableOfType(OAuthRequestFailedException.class, causeChain);
|
||||
if (rfe != null) {
|
||||
fail(request, response, rfe);
|
||||
}
|
||||
else {
|
||||
// Rethrow ServletExceptions and RuntimeExceptions as-is
|
||||
if (ex instanceof ServletException) {
|
||||
throw (ServletException) ex;
|
||||
}
|
||||
else if (ex instanceof RuntimeException) {
|
||||
throw (RuntimeException) ex;
|
||||
}
|
||||
|
||||
// Wrap other Exceptions. These are not expected to happen
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
OAuthSecurityContextHolder.setContext(null);
|
||||
HashMap<String, OAuthConsumerToken> tokensToRemember = new HashMap<String, OAuthConsumerToken>();
|
||||
tokensToRemember.putAll(requestTokens);
|
||||
tokensToRemember.putAll(accessTokens);
|
||||
getRememberMeServices().rememberTokens(tokensToRemember, request, response);
|
||||
}
|
||||
}
|
||||
|
||||
private HttpEntity<Object> emptyRequest() {
|
||||
HttpHeaders requestHeaders = new HttpHeaders();
|
||||
requestHeaders.set("Accept", "application/xml");
|
||||
requestHeaders.set("Content-Type", "application/xml");
|
||||
|
||||
HttpEntity<Object> requestEntity = new HttpEntity<Object>(
|
||||
requestHeaders);
|
||||
return requestEntity;
|
||||
}
|
||||
|
||||
private String getBaseServerUrl() {
|
||||
return this.applicationConfigurationService.retrieveOAuthProviderDetails().getProviderBaseUrl();
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package org.mifosng.oauth;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.security.authentication.InsufficientAuthenticationException;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.oauth.consumer.AccessTokenRequiredException;
|
||||
import org.springframework.security.oauth.consumer.OAuthConsumerToken;
|
||||
import org.springframework.security.oauth.consumer.OAuthSecurityContext;
|
||||
import org.springframework.security.oauth.consumer.OAuthSecurityContextHolder;
|
||||
import org.springframework.security.oauth.consumer.filter.OAuthConsumerProcessingFilter;
|
||||
|
||||
public class CustomOAuthConsumerProcessingFilter extends
|
||||
OAuthConsumerProcessingFilter {
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest servletRequest,
|
||||
ServletResponse servletResponse, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
HttpServletResponse response = (HttpServletResponse) servletResponse;
|
||||
|
||||
Set<String> accessTokenDeps = getAccessTokenDependencies(request,
|
||||
response, chain);
|
||||
if (!accessTokenDeps.isEmpty()) {
|
||||
Authentication authentication = SecurityContextHolder.getContext()
|
||||
.getAuthentication();
|
||||
if (isRequireAuthenticated() && !authentication.isAuthenticated()) {
|
||||
throw new InsufficientAuthenticationException(
|
||||
"An authenticated principal must be present.");
|
||||
}
|
||||
|
||||
OAuthSecurityContext context = OAuthSecurityContextHolder
|
||||
.getContext();
|
||||
if (context == null) {
|
||||
throw new IllegalStateException(
|
||||
"No OAuth security context has been established. Unable to access resources.");
|
||||
}
|
||||
|
||||
Map<String, OAuthConsumerToken> accessTokens = context
|
||||
.getAccessTokens();
|
||||
|
||||
for (String dependency : accessTokenDeps) {
|
||||
if (!accessTokens.containsKey(dependency)) {
|
||||
throw new AccessTokenRequiredException(
|
||||
getProtectedResourceDetailsService()
|
||||
.loadProtectedResourceDetailsById(
|
||||
dependency));
|
||||
}
|
||||
}
|
||||
|
||||
chain.doFilter(request, response);
|
||||
} else {
|
||||
chain.doFilter(servletRequest, servletResponse);
|
||||
}
|
||||
}
|
||||
}
|
||||
+233
@@ -0,0 +1,233 @@
|
||||
package org.mifosng.oauth;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.mifosng.ui.JaxRs311ErrorResponseHandler;
|
||||
import org.springframework.security.oauth.common.OAuthProviderParameter;
|
||||
import org.springframework.security.oauth.consumer.OAuthConsumerToken;
|
||||
import org.springframework.security.oauth.consumer.OAuthRequestFailedException;
|
||||
import org.springframework.security.oauth.consumer.OAuthSecurityContextHolder;
|
||||
import org.springframework.security.oauth.consumer.OAuthSecurityContextImpl;
|
||||
import org.springframework.security.oauth.consumer.ProtectedResourceDetails;
|
||||
import org.springframework.security.oauth.consumer.filter.OAuthConsumerContextFilter;
|
||||
import org.springframework.web.client.DefaultResponseErrorHandler;
|
||||
import org.springframework.web.client.ResponseErrorHandler;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
public class MifosNgOauthConsumerContextFilter extends
|
||||
OAuthConsumerContextFilter {
|
||||
|
||||
private static final Log LOG = LogFactory
|
||||
.getLog(MifosNgOauthConsumerContextFilter.class);
|
||||
|
||||
private RestTemplate noAuthRestTemplate;
|
||||
|
||||
@Override
|
||||
public void doFilter(final ServletRequest servletRequest,
|
||||
final ServletResponse servletResponse, final FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
|
||||
ResponseErrorHandler defaultResponseErrorHandler = new DefaultResponseErrorHandler();
|
||||
ResponseErrorHandler jaxrs311ErrorResponseHandler = new JaxRs311ErrorResponseHandler(
|
||||
defaultResponseErrorHandler);
|
||||
this.noAuthRestTemplate = new RestTemplate();
|
||||
this.noAuthRestTemplate.setErrorHandler(jaxrs311ErrorResponseHandler);
|
||||
|
||||
HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
HttpServletResponse response = (HttpServletResponse) servletResponse;
|
||||
OAuthSecurityContextImpl context = new OAuthSecurityContextImpl();
|
||||
context.setDetails(request);
|
||||
|
||||
Map<String, OAuthConsumerToken> rememberedTokens = getRememberMeServices()
|
||||
.loadRememberedTokens(request, response);
|
||||
Map<String, OAuthConsumerToken> accessTokens = new TreeMap<String, OAuthConsumerToken>();
|
||||
Map<String, OAuthConsumerToken> requestTokens = new TreeMap<String, OAuthConsumerToken>();
|
||||
if (rememberedTokens != null) {
|
||||
for (Map.Entry<String, OAuthConsumerToken> tokenEntry : rememberedTokens
|
||||
.entrySet()) {
|
||||
OAuthConsumerToken token = tokenEntry.getValue();
|
||||
if (token != null) {
|
||||
if (token.isAccessToken()) {
|
||||
accessTokens.put(tokenEntry.getKey(), token);
|
||||
} else {
|
||||
requestTokens.put(tokenEntry.getKey(), token);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context.setAccessTokens(accessTokens);
|
||||
OAuthSecurityContextHolder.setContext(context);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Storing access tokens in request attribute '"
|
||||
+ getAccessTokensRequestAttribute() + "'.");
|
||||
}
|
||||
|
||||
try {
|
||||
try {
|
||||
request.setAttribute(
|
||||
getAccessTokensRequestAttribute(),
|
||||
new ArrayList<OAuthConsumerToken>(accessTokens.values()));
|
||||
chain.doFilter(request, response);
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
ProtectedResourceDetails resourceThatNeedsAuthorization = checkForResourceThatNeedsAuthorization(e);
|
||||
String neededResourceId = resourceThatNeedsAuthorization
|
||||
.getId();
|
||||
while (!accessTokens.containsKey(neededResourceId)) {
|
||||
OAuthConsumerToken token = requestTokens
|
||||
.remove(neededResourceId);
|
||||
if (token == null) {
|
||||
token = getTokenServices().getToken(
|
||||
neededResourceId);
|
||||
}
|
||||
|
||||
String verifier = request
|
||||
.getParameter(OAuthProviderParameter.oauth_verifier
|
||||
.toString());
|
||||
// if the token is null OR
|
||||
// if there is NO access token and (we're not using 1.0a
|
||||
// or the verifier is not null)
|
||||
if (token == null
|
||||
|| !token.isAccessToken()
|
||||
&& (!resourceThatNeedsAuthorization.isUse10a() || verifier == null)) {
|
||||
// no token associated with the resource, start the
|
||||
// oauth flow.
|
||||
// if there's a request token, but no verifier,
|
||||
// we'll assume that a previous oauth request failed
|
||||
// and we need to get a new request token.
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Obtaining request token for resource: "
|
||||
+ neededResourceId);
|
||||
}
|
||||
|
||||
// obtain authorization.
|
||||
String callbackURL = response
|
||||
.encodeRedirectURL(getCallbackURL(request));
|
||||
token = getConsumerSupport()
|
||||
.getUnauthorizedRequestToken(
|
||||
neededResourceId, callbackURL);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Request token obtained for resource "
|
||||
+ neededResourceId + ": " + token);
|
||||
}
|
||||
|
||||
// okay, we've got a request token, now we need to
|
||||
// authorize it.
|
||||
requestTokens.put(neededResourceId, token);
|
||||
getTokenServices().storeToken(neededResourceId,
|
||||
token);
|
||||
String redirect = getUserAuthorizationRedirectURL(
|
||||
resourceThatNeedsAuthorization, token,
|
||||
callbackURL);
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Redirecting request to "
|
||||
+ redirect
|
||||
+ " for user authorization of the request token for resource "
|
||||
+ neededResourceId + ".");
|
||||
}
|
||||
|
||||
request.setAttribute(
|
||||
"org.springframework.security.oauth.consumer.AccessTokenRequiredException",
|
||||
e);
|
||||
getRedirectStrategy().sendRedirect(request,
|
||||
response, redirect);
|
||||
return;
|
||||
} else if (!token.isAccessToken()) {
|
||||
// we have a presumably authorized request token,
|
||||
// let's try to get an access token with it.
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Obtaining access token for resource: "
|
||||
+ neededResourceId);
|
||||
}
|
||||
|
||||
// authorize the request token and store it.
|
||||
try {
|
||||
token = getConsumerSupport().getAccessToken(
|
||||
token, verifier);
|
||||
} finally {
|
||||
getTokenServices()
|
||||
.removeToken(neededResourceId);
|
||||
}
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Access token " + token
|
||||
+ " obtained for resource "
|
||||
+ neededResourceId
|
||||
+ ". Now storing and using.");
|
||||
}
|
||||
|
||||
getTokenServices().storeToken(neededResourceId,
|
||||
token);
|
||||
}
|
||||
|
||||
accessTokens.put(neededResourceId, token);
|
||||
|
||||
try {
|
||||
// try again
|
||||
if (!response.isCommitted()) {
|
||||
request.setAttribute(
|
||||
getAccessTokensRequestAttribute(),
|
||||
new ArrayList<OAuthConsumerToken>(
|
||||
accessTokens.values()));
|
||||
chain.doFilter(request, response);
|
||||
} else {
|
||||
// dang. what do we do now?
|
||||
throw new IllegalStateException(
|
||||
"Unable to reprocess filter chain with needed OAuth2 resources because the response is already committed.");
|
||||
}
|
||||
} catch (Exception e1) {
|
||||
resourceThatNeedsAuthorization = checkForResourceThatNeedsAuthorization(e1);
|
||||
neededResourceId = resourceThatNeedsAuthorization
|
||||
.getId();
|
||||
}
|
||||
}
|
||||
} catch (OAuthRequestFailedException eo) {
|
||||
fail(request, response, eo);
|
||||
} catch (Exception ex) {
|
||||
Throwable[] causeChain = getThrowableAnalyzer()
|
||||
.determineCauseChain(ex);
|
||||
OAuthRequestFailedException rfe = (OAuthRequestFailedException) getThrowableAnalyzer()
|
||||
.getFirstThrowableOfType(
|
||||
OAuthRequestFailedException.class,
|
||||
causeChain);
|
||||
if (rfe != null) {
|
||||
fail(request, response, rfe);
|
||||
} else {
|
||||
// Rethrow ServletExceptions and RuntimeExceptions as-is
|
||||
if (ex instanceof ServletException) {
|
||||
throw (ServletException) ex;
|
||||
} else if (ex instanceof RuntimeException) {
|
||||
throw (RuntimeException) ex;
|
||||
}
|
||||
|
||||
// Wrap other Exceptions. These are not expected to
|
||||
// happen
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
OAuthSecurityContextHolder.setContext(null);
|
||||
HashMap<String, OAuthConsumerToken> tokensToRemember = new HashMap<String, OAuthConsumerToken>();
|
||||
tokensToRemember.putAll(requestTokens);
|
||||
tokensToRemember.putAll(accessTokens);
|
||||
getRememberMeServices().rememberTokens(tokensToRemember, request,
|
||||
response);
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package org.mifosng.oauth;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.oauth.consumer.ProtectedResourceDetailsService;
|
||||
import org.springframework.security.oauth.consumer.client.OAuthRestTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service(value="oauthRestServiceTemplate")
|
||||
public class MifosNgOauthRestTemplate extends OAuthRestTemplate {
|
||||
|
||||
@Autowired
|
||||
public MifosNgOauthRestTemplate(ProtectedResourceDetailsService protectedResourceDetailsService) {
|
||||
super(protectedResourceDetailsService.loadProtectedResourceDetailsById("protectedMifosNgServices"));
|
||||
}
|
||||
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package org.mifosng.oauth;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.mifosng.configuration.ApplicationConfigurationService;
|
||||
import org.mifosng.configuration.OAuthProviderDetails;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.oauth.common.signature.SharedConsumerSecret;
|
||||
import org.springframework.security.oauth.consumer.BaseProtectedResourceDetails;
|
||||
import org.springframework.security.oauth.consumer.ProtectedResourceDetails;
|
||||
import org.springframework.security.oauth.consumer.ProtectedResourceDetailsService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service(value="mifosNgInMemoryResourceDetailsService")
|
||||
public class MifosNgProtectedResourceDetailsService implements
|
||||
ProtectedResourceDetailsService, RefreshableProtectedResourceDetailsService {
|
||||
|
||||
private Map<String, ProtectedResourceDetails> resourceDetailsStore = new HashMap<String, ProtectedResourceDetails>();
|
||||
private final ApplicationConfigurationService applicationConfigurationService;
|
||||
|
||||
@Autowired
|
||||
public MifosNgProtectedResourceDetailsService(ApplicationConfigurationService applicationConfigurationService) {
|
||||
this.applicationConfigurationService = applicationConfigurationService;
|
||||
addHardcodedMifosNgResourceIdToStore();
|
||||
}
|
||||
|
||||
private void addHardcodedMifosNgResourceIdToStore() {
|
||||
BaseProtectedResourceDetails individualLendingResourceDetails = new BaseProtectedResourceDetails();
|
||||
individualLendingResourceDetails.setId("protectedMifosNgServices");
|
||||
|
||||
OAuthProviderDetails oauthProviderDetails = applicationConfigurationService
|
||||
.retrieveOAuthProviderDetails();
|
||||
|
||||
individualLendingResourceDetails
|
||||
.setRequestTokenURL(oauthProviderDetails.getRequestTokenUrl());
|
||||
individualLendingResourceDetails
|
||||
.setUserAuthorizationURL(oauthProviderDetails
|
||||
.getUserAuthorizationUrl());
|
||||
individualLendingResourceDetails.setAccessTokenURL(oauthProviderDetails
|
||||
.getAccessTokenUrl());
|
||||
|
||||
individualLendingResourceDetails.setConsumerKey(oauthProviderDetails
|
||||
.getConsumerkey());
|
||||
individualLendingResourceDetails
|
||||
.setSharedSecret(new SharedConsumerSecret(oauthProviderDetails
|
||||
.getSharedSecret()));
|
||||
|
||||
resourceDetailsStore.put(
|
||||
individualLendingResourceDetails.getId(),
|
||||
individualLendingResourceDetails);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtectedResourceDetails loadProtectedResourceDetailsById(
|
||||
final String id) throws IllegalArgumentException {
|
||||
return resourceDetailsStore.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
resourceDetailsStore.clear();
|
||||
addHardcodedMifosNgResourceIdToStore();
|
||||
}
|
||||
|
||||
public ApplicationConfigurationService getApplicationConfigurationService() {
|
||||
return applicationConfigurationService;
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package org.mifosng.oauth;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.access.SecurityConfig;
|
||||
import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.web.util.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.RequestMatcher;
|
||||
|
||||
public class OAuthConsumerFilterFilterInvocationSecurityMetadataSource
|
||||
implements FilterInvocationSecurityMetadataSource {
|
||||
|
||||
private final FilterInvocationSecurityMetadataSource metadataSource;
|
||||
|
||||
public OAuthConsumerFilterFilterInvocationSecurityMetadataSource() {
|
||||
LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>();
|
||||
RequestMatcher key = new AntPathRequestMatcher("/sparklr/**");
|
||||
Collection<ConfigAttribute> value = new ArrayList<ConfigAttribute>();
|
||||
value.add(new SecurityConfig("sparklrPhotos"));
|
||||
requestMap.put(key, value);
|
||||
|
||||
this.metadataSource = new DefaultFilterInvocationSecurityMetadataSource(
|
||||
requestMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ConfigAttribute> getAttributes(final Object object)
|
||||
throws IllegalArgumentException {
|
||||
return this.metadataSource.getAttributes(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ConfigAttribute> getAllConfigAttributes() {
|
||||
return this.metadataSource.getAllConfigAttributes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(final Class<?> clazz) {
|
||||
return this.metadataSource.supports(clazz);
|
||||
}
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
package org.mifosng.oauth;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.mifosng.configuration.OAuthProviderDetails;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth.consumer.OAuthConsumerToken;
|
||||
import org.springframework.security.oauth.consumer.OAuthSecurityContextHolder;
|
||||
import org.springframework.security.oauth.consumer.OAuthSecurityContextImpl;
|
||||
import org.springframework.security.oauth.consumer.rememberme.OAuthRememberMeServices;
|
||||
import org.springframework.security.web.authentication.logout.LogoutHandler;
|
||||
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
|
||||
|
||||
/**
|
||||
* Logout Filter process before oauth filters are applied so need create OAuthSercurityContext and populate with 'remembered tokens' first.
|
||||
*/
|
||||
public class OAuthLogoutHandler implements LogoutHandler {
|
||||
|
||||
private final SecurityContextLogoutHandler delegate;
|
||||
private final MifosNgProtectedResourceDetailsService protectedResourceDetailsService;
|
||||
private final OAuthRememberMeServices oAuthRememberMeServices;
|
||||
|
||||
public OAuthLogoutHandler(final SecurityContextLogoutHandler delegate, final MifosNgProtectedResourceDetailsService protectedResourceDetailsService,
|
||||
final OAuthRememberMeServices oAuthRememberMeServices) {
|
||||
this.delegate = delegate;
|
||||
this.protectedResourceDetailsService = protectedResourceDetailsService;
|
||||
this.oAuthRememberMeServices = oAuthRememberMeServices;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logout(HttpServletRequest request,
|
||||
HttpServletResponse response, Authentication authentication) {
|
||||
|
||||
this.delegate.logout(request, response, authentication);
|
||||
|
||||
OAuthSecurityContextImpl context = new OAuthSecurityContextImpl();
|
||||
context.setDetails(request);
|
||||
|
||||
Map<String, OAuthConsumerToken> rememberedTokens = this.oAuthRememberMeServices.loadRememberedTokens(request, response);
|
||||
Map<String, OAuthConsumerToken> accessTokens = new TreeMap<String, OAuthConsumerToken>();
|
||||
if (rememberedTokens != null) {
|
||||
for (Map.Entry<String, OAuthConsumerToken> tokenEntry : rememberedTokens.entrySet()) {
|
||||
OAuthConsumerToken token = tokenEntry.getValue();
|
||||
if (token != null) {
|
||||
if (token.isAccessToken()) {
|
||||
accessTokens.put(tokenEntry.getKey(), token);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context.setAccessTokens(accessTokens);
|
||||
OAuthSecurityContextHolder.setContext(context);
|
||||
|
||||
if (!accessTokens.isEmpty()) {
|
||||
MifosNgOauthRestTemplate oauthRestTemplate = new MifosNgOauthRestTemplate(
|
||||
protectedResourceDetailsService);
|
||||
|
||||
OAuthProviderDetails providerDetails = this.protectedResourceDetailsService
|
||||
.getApplicationConfigurationService()
|
||||
.retrieveOAuthProviderDetails();
|
||||
|
||||
URI restUri = URI.create(providerDetails.getProviderBaseUrl()
|
||||
.concat("api/protected/user/signout"));
|
||||
|
||||
oauthRestTemplate.exchange(restUri, HttpMethod.GET, emptyRequest(),
|
||||
null);
|
||||
}
|
||||
|
||||
OAuthSecurityContextHolder.setContext(null);
|
||||
}
|
||||
|
||||
|
||||
private HttpEntity<Object> emptyRequest() {
|
||||
HttpHeaders requestHeaders = new HttpHeaders();
|
||||
requestHeaders.set("Accept", "application/xml");
|
||||
requestHeaders.set("Content-Type", "application/xml");
|
||||
|
||||
HttpEntity<Object> requestEntity = new HttpEntity<Object>(
|
||||
requestHeaders);
|
||||
return requestEntity;
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package org.mifosng.oauth;
|
||||
|
||||
public interface RefreshableProtectedResourceDetailsService {
|
||||
|
||||
void refresh();
|
||||
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
package org.mifosng.ui;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.mifosng.data.AppUserData;
|
||||
import org.mifosng.data.ClientData;
|
||||
import org.mifosng.data.ClientDataWithAccountsData;
|
||||
import org.mifosng.data.CurrencyData;
|
||||
import org.mifosng.data.EntityIdentifier;
|
||||
import org.mifosng.data.EnumOptionReadModel;
|
||||
import org.mifosng.data.ExtraDatasets;
|
||||
import org.mifosng.data.LoanAccountData;
|
||||
import org.mifosng.data.LoanProductData;
|
||||
import org.mifosng.data.LoanRepaymentData;
|
||||
import org.mifosng.data.LoanSchedule;
|
||||
import org.mifosng.data.NewLoanWorkflowStepOneData;
|
||||
import org.mifosng.data.NoteData;
|
||||
import org.mifosng.data.OfficeData;
|
||||
import org.mifosng.data.PermissionData;
|
||||
import org.mifosng.data.RoleData;
|
||||
import org.mifosng.data.command.AdjustLoanTransactionCommand;
|
||||
import org.mifosng.data.command.CalculateLoanScheduleCommand;
|
||||
import org.mifosng.data.command.ChangePasswordCommand;
|
||||
import org.mifosng.data.command.CreateLoanProductCommand;
|
||||
import org.mifosng.data.command.EnrollClientCommand;
|
||||
import org.mifosng.data.command.LoanStateTransitionCommand;
|
||||
import org.mifosng.data.command.LoanTransactionCommand;
|
||||
import org.mifosng.data.command.NoteCommand;
|
||||
import org.mifosng.data.command.OfficeCommand;
|
||||
import org.mifosng.data.command.RoleCommand;
|
||||
import org.mifosng.data.command.SubmitLoanApplicationCommand;
|
||||
import org.mifosng.data.command.UndoLoanApprovalCommand;
|
||||
import org.mifosng.data.command.UndoLoanDisbursalCommand;
|
||||
import org.mifosng.data.command.UpdateLoanProductCommand;
|
||||
import org.mifosng.data.command.UpdateOrganisationCurrencyCommand;
|
||||
import org.mifosng.data.command.UserCommand;
|
||||
import org.mifosng.data.reports.GenericResultset;
|
||||
import org.springframework.security.oauth.consumer.ProtectedResourceDetails;
|
||||
|
||||
public interface CommonRestOperations {
|
||||
|
||||
void logout(String accessToken);
|
||||
|
||||
void updateProtectedResource(
|
||||
ProtectedResourceDetails loadProtectedResourceDetailsById);
|
||||
|
||||
void updateOrganisationCurrencies(UpdateOrganisationCurrencyCommand command);
|
||||
|
||||
Collection<OfficeData> retrieveAllOffices();
|
||||
|
||||
OfficeData retrieveOffice(Long officeId);
|
||||
|
||||
Collection<AppUserData> retrieveAllUsers();
|
||||
|
||||
AppUserData retrieveNewUserDetails();
|
||||
|
||||
AppUserData retrieveUser(Long userId);
|
||||
|
||||
AppUserData retrieveCurrentUser();
|
||||
|
||||
EntityIdentifier createUser(UserCommand command);
|
||||
|
||||
EntityIdentifier updateUser(UserCommand command);
|
||||
|
||||
EntityIdentifier updateCurrentUserPassword(ChangePasswordCommand command);
|
||||
|
||||
void deleteUser(Long userId);
|
||||
|
||||
Collection<RoleData> retrieveAllRoles();
|
||||
|
||||
RoleData retrieveRole(Long roleId);
|
||||
|
||||
RoleData retrieveNewRoleDetails();
|
||||
|
||||
EntityIdentifier updateRole(RoleCommand command);
|
||||
|
||||
Collection<PermissionData> retrieveAllPermissions();
|
||||
|
||||
Collection<EnumOptionReadModel> retrieveAllPermissionGroups();
|
||||
|
||||
EntityIdentifier createRole(RoleCommand command);
|
||||
|
||||
EntityIdentifier createOffice(OfficeCommand command);
|
||||
|
||||
EntityIdentifier updateOffice(OfficeCommand command);
|
||||
|
||||
Collection<ClientData> retrieveAllIndividualClients();
|
||||
|
||||
Collection<LoanProductData> retrieveAllLoanProducts();
|
||||
|
||||
Collection<CurrencyData> retrieveAllowedCurrencies();
|
||||
|
||||
Collection<CurrencyData> retrieveAllPlatformCurrencies();
|
||||
|
||||
Collection<EnumOptionReadModel> retrieveAllowedLoanAmortizationMethodOptions();
|
||||
|
||||
Collection<EnumOptionReadModel> retrieveAllowedLoanInterestMethodOptions();
|
||||
|
||||
Collection<EnumOptionReadModel> retrieveAllowedRepaymentFrequencyOptions();
|
||||
|
||||
Collection<EnumOptionReadModel> retrieveAllowedNominalInterestFrequencyOptions();
|
||||
|
||||
EntityIdentifier createLoanProduct(CreateLoanProductCommand command);
|
||||
|
||||
EntityIdentifier updateLoanProduct(UpdateLoanProductCommand command);
|
||||
|
||||
LoanProductData retrieveLoanProductDetails(Long selectedLoanProductOption);
|
||||
|
||||
LoanProductData retrieveNewLoanProductDetails();
|
||||
|
||||
LoanSchedule calculateLoanSchedule(CalculateLoanScheduleCommand command);
|
||||
|
||||
NewLoanWorkflowStepOneData retrieveNewLoanApplicationStepOneDetails(
|
||||
Long clientId);
|
||||
|
||||
Long submitLoanApplication(SubmitLoanApplicationCommand command);
|
||||
|
||||
EntityIdentifier deleteLoan(Long loanId);
|
||||
|
||||
EntityIdentifier approveLoan(LoanStateTransitionCommand command);
|
||||
|
||||
EntityIdentifier undoLoanApproval(UndoLoanApprovalCommand command);
|
||||
|
||||
EntityIdentifier rejectLoan(LoanStateTransitionCommand command);
|
||||
|
||||
EntityIdentifier withdrawLoan(LoanStateTransitionCommand command);
|
||||
|
||||
EntityIdentifier disburseLoan(LoanStateTransitionCommand command);
|
||||
|
||||
EntityIdentifier undloLoanDisbursal(UndoLoanDisbursalCommand command);
|
||||
|
||||
LoanRepaymentData retrieveNewLoanRepaymentDetails(Long loanId);
|
||||
|
||||
LoanRepaymentData retrieveLoanRepaymentDetails(Long loanId, Long repaymentId);
|
||||
|
||||
EntityIdentifier makeLoanRepayment(LoanTransactionCommand command);
|
||||
|
||||
EntityIdentifier adjustLoanRepayment(AdjustLoanTransactionCommand command);
|
||||
|
||||
LoanRepaymentData retrieveNewLoanWaiverDetails(Long loanId);
|
||||
|
||||
EntityIdentifier waiveLoanAmount(LoanTransactionCommand command);
|
||||
|
||||
EntityIdentifier updateCurrentUserDetails(UserCommand command);
|
||||
|
||||
ClientData retrieveNewIndividualClient();
|
||||
|
||||
ClientData retrieveClientDetails(Long clientId);
|
||||
|
||||
EntityIdentifier enrollClient(EnrollClientCommand command);
|
||||
|
||||
EntityIdentifier addNote(NoteCommand command);
|
||||
|
||||
EntityIdentifier updateNote(NoteCommand command);
|
||||
|
||||
NoteData retrieveClientNote(Long clientId, Long noteId);
|
||||
|
||||
Collection<NoteData> retrieveClientNotes(Long clientId);
|
||||
|
||||
ClientDataWithAccountsData retrieveClientAccount(Long clientId);
|
||||
|
||||
LoanAccountData retrieveLoanAccount(Long loanId);
|
||||
|
||||
ExtraDatasets retrieveExtraDatasets(String datasetType);
|
||||
|
||||
GenericResultset retrieveExtraData(String datasetType, String datasetName,
|
||||
String datasetPKValue);
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
EntityIdentifier saveExtraData(String datasetType, String datasetName,
|
||||
String datasetPKValue, Map map);
|
||||
|
||||
GenericResultset retrieveReportingData(String rptDB, String name, String type, Map<String, String> extractedQueryParams);
|
||||
|
||||
NewLoanWorkflowStepOneData retrieveNewLoanApplicationDetails(Long clientId, Long productId);
|
||||
}
|
||||
+1353
File diff suppressed because it is too large
Load Diff
+34
@@ -0,0 +1,34 @@
|
||||
package org.mifosng.ui;
|
||||
|
||||
import org.mifosng.data.ErrorResponse;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
|
||||
public class Jax2bRestClientException extends RestClientException {
|
||||
|
||||
private final HttpStatus statusCode;
|
||||
private final MediaType contentType;
|
||||
private final ErrorResponse errorResponse;
|
||||
|
||||
public Jax2bRestClientException(final HttpStatus statusCode,
|
||||
final MediaType contentType, final ErrorResponse errorResponse) {
|
||||
super(statusCode.name() + ": on client http rest request.");
|
||||
this.statusCode = statusCode;
|
||||
this.contentType = contentType;
|
||||
this.errorResponse = errorResponse;
|
||||
}
|
||||
|
||||
public HttpStatus getStatusCode() {
|
||||
return this.statusCode;
|
||||
}
|
||||
|
||||
public MediaType getContentType() {
|
||||
return this.contentType;
|
||||
}
|
||||
|
||||
public ErrorResponse getErrorResponse() {
|
||||
return this.errorResponse;
|
||||
}
|
||||
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package org.mifosng.ui;
|
||||
|
||||
import org.mifosng.data.ErrorResponse;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
|
||||
public class Jax2bRestServerException extends RestClientException {
|
||||
|
||||
private final HttpStatus statusCode;
|
||||
private final MediaType contentType;
|
||||
private final ErrorResponse errorResponse;
|
||||
|
||||
public Jax2bRestServerException(final HttpStatus statusCode,
|
||||
final MediaType contentType, final ErrorResponse errorResponse) {
|
||||
super(statusCode.name() + ": on client http rest request.");
|
||||
this.statusCode = statusCode;
|
||||
this.contentType = contentType;
|
||||
this.errorResponse = errorResponse;
|
||||
}
|
||||
|
||||
public HttpStatus getStatusCode() {
|
||||
return this.statusCode;
|
||||
}
|
||||
|
||||
public MediaType getContentType() {
|
||||
return this.contentType;
|
||||
}
|
||||
|
||||
public ErrorResponse getErrorResponse() {
|
||||
return this.errorResponse;
|
||||
}
|
||||
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package org.mifosng.ui;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.mifosng.data.ErrorResponse;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
|
||||
import org.springframework.web.client.ResponseErrorHandler;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
|
||||
public class JaxRs311ErrorResponseHandler implements ResponseErrorHandler {
|
||||
|
||||
private final ResponseErrorHandler delegateResponseErrorHandler;
|
||||
|
||||
public JaxRs311ErrorResponseHandler(
|
||||
final ResponseErrorHandler delegateResponseErrorHandler) {
|
||||
this.delegateResponseErrorHandler = delegateResponseErrorHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasError(final ClientHttpResponse response) throws IOException {
|
||||
return this.delegateResponseErrorHandler.hasError(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleError(final ClientHttpResponse response) throws IOException {
|
||||
|
||||
HttpStatus statusCode = response.getStatusCode();
|
||||
MediaType contentType = response.getHeaders().getContentType();
|
||||
|
||||
Jaxb2RootElementHttpMessageConverter converter = new Jaxb2RootElementHttpMessageConverter();
|
||||
ErrorResponse errorResponse = (ErrorResponse) converter.read(
|
||||
ErrorResponse.class, response);
|
||||
|
||||
switch (statusCode.series()) {
|
||||
case CLIENT_ERROR:
|
||||
throw new Jax2bRestClientException(statusCode, contentType, errorResponse);
|
||||
case SERVER_ERROR:
|
||||
throw new Jax2bRestServerException(statusCode, contentType,
|
||||
errorResponse);
|
||||
default:
|
||||
throw new RestClientException("Unknown status code [" + statusCode
|
||||
+ "]");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
package org.mifosng.ui.admin;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.mifosng.data.AppUserData;
|
||||
import org.mifosng.data.EntityIdentifier;
|
||||
import org.mifosng.data.ErrorResponse;
|
||||
import org.mifosng.data.command.ChangePasswordCommand;
|
||||
import org.mifosng.data.command.UserCommand;
|
||||
import org.mifosng.ui.CommonRestOperations;
|
||||
import org.mifosng.ui.loanproduct.ClientValidationException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
/**
|
||||
* Controller for user and organisation administration functions.
|
||||
*/
|
||||
@Controller
|
||||
public class AdministrationController {
|
||||
|
||||
private final CommonRestOperations commonRestOperations;
|
||||
|
||||
@Autowired
|
||||
public AdministrationController(final CommonRestOperations commonRestOperations) {
|
||||
this.commonRestOperations = commonRestOperations;
|
||||
}
|
||||
|
||||
@ExceptionHandler(AccessDeniedException.class)
|
||||
public String accessDeniedException() {
|
||||
return "unAuthorizedAction";
|
||||
}
|
||||
|
||||
@ExceptionHandler(ClientValidationException.class)
|
||||
public @ResponseBody Collection<ErrorResponse> validationException(ClientValidationException ex, HttpServletResponse response) {
|
||||
|
||||
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||
response.setContentType("application/json");
|
||||
|
||||
return ex.getValidationErrors();
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/org/admin", method = RequestMethod.GET)
|
||||
public String organisationAdminScreen() {
|
||||
return "admin/orghome";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/org/admin/user", method = RequestMethod.GET)
|
||||
public String userAdminScreen() {
|
||||
return "admin/userhome";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/org/admin/settings", method = RequestMethod.GET)
|
||||
public String userSettingsScreen(Model model) {
|
||||
return "admin/accountsettings";
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "org/admin/settings/details", method = RequestMethod.GET)
|
||||
public @ResponseBody AppUserData viewUserDetails() {
|
||||
|
||||
return this.commonRestOperations.retrieveCurrentUser();
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "org/admin/settings/details", method = RequestMethod.POST)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public @ResponseBody EntityIdentifier updateUserDetails(HttpServletRequest request,
|
||||
@RequestParam(value="username", required=false) String username,
|
||||
@RequestParam(value="firstname", required=false) String firstname,
|
||||
@RequestParam(value="lastname", required=false) String lastname,
|
||||
@RequestParam(value="email", required=false) String email) {
|
||||
|
||||
UserCommand command = new UserCommand(username, firstname, lastname, email);
|
||||
|
||||
return this.commonRestOperations.updateCurrentUserDetails(command);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "org/admin/settings/password", method = RequestMethod.GET)
|
||||
public @ResponseBody ChangePasswordCommand viewChangePasswordDetails() {
|
||||
|
||||
return new ChangePasswordCommand();
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "org/admin/settings/password", method = RequestMethod.POST)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public @ResponseBody EntityIdentifier updateUserDetails(HttpServletRequest request,
|
||||
@RequestParam(value="password", required=false) String password,
|
||||
@RequestParam(value="passwordrepeat", required=false) String passwordrepeat) {
|
||||
|
||||
ChangePasswordCommand command = new ChangePasswordCommand();
|
||||
command.setPassword(password);
|
||||
command.setPasswordrepeat(passwordrepeat);
|
||||
|
||||
return this.commonRestOperations.updateCurrentUserPassword(command);
|
||||
}
|
||||
}
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
package org.mifosng.ui.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.mifosng.data.ClientData;
|
||||
import org.mifosng.data.ClientDataWithAccountsData;
|
||||
import org.mifosng.data.ClientList;
|
||||
import org.mifosng.data.EntityIdentifier;
|
||||
import org.mifosng.data.ErrorResponse;
|
||||
import org.mifosng.data.LoanAccountData;
|
||||
import org.mifosng.data.NoteData;
|
||||
import org.mifosng.data.command.EnrollClientCommand;
|
||||
import org.mifosng.data.command.NoteCommand;
|
||||
import org.mifosng.ui.CommonRestOperations;
|
||||
import org.mifosng.ui.loanproduct.ClientValidationException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@Controller
|
||||
public class ClientController {
|
||||
|
||||
private final CommonRestOperations commonRestOperations;
|
||||
|
||||
@Autowired
|
||||
public ClientController(final CommonRestOperations commonRestOperations) {
|
||||
this.commonRestOperations = commonRestOperations;
|
||||
}
|
||||
|
||||
@ExceptionHandler(AccessDeniedException.class)
|
||||
public String accessDeniedException() {
|
||||
return "unAuthorizedAction";
|
||||
}
|
||||
|
||||
@ExceptionHandler(ClientValidationException.class)
|
||||
public @ResponseBody Collection<ErrorResponse> validationException(ClientValidationException ex, HttpServletResponse response) {
|
||||
|
||||
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||
response.setContentType("application/json");
|
||||
|
||||
return ex.getValidationErrors();
|
||||
}
|
||||
|
||||
private LocalDate parseStringToLocalDate(String eventDate, String dateFieldIdentifier) {
|
||||
LocalDate eventLocalDate = null;
|
||||
if (StringUtils.isNotBlank(eventDate)) {
|
||||
try {
|
||||
Locale locale = LocaleContextHolder.getLocale();
|
||||
eventLocalDate = DateTimeFormat.forPattern("dd MMMM yyyy").withLocale(locale).parseLocalDate(eventDate.toLowerCase(locale));
|
||||
} catch (IllegalArgumentException e) {
|
||||
List<ErrorResponse> validationErrors = new ArrayList<ErrorResponse>();
|
||||
validationErrors.add(new ErrorResponse("validation.msg.invalid.date.format", dateFieldIdentifier, eventDate));
|
||||
throw new ClientValidationException(validationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
return eventLocalDate;
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "/portfolio/client/{clientId}/note/all", method = RequestMethod.GET)
|
||||
public @ResponseBody List<NoteData> retrieveClientNotes(@PathVariable("clientId") Long clientId) {
|
||||
|
||||
Collection<NoteData> clientNotes = this.commonRestOperations.retrieveClientNotes(clientId);
|
||||
|
||||
return new ArrayList<NoteData>(clientNotes);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "/portfolio/client/{clientId}/note/new", method = RequestMethod.GET)
|
||||
public @ResponseBody NoteData retrieveNewNoteDetails(@PathVariable("clientId") Long clientId) {
|
||||
|
||||
NoteData noteData = new NoteData();
|
||||
noteData.setClientId(clientId);
|
||||
|
||||
return noteData;
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/portfolio/client/{clientId}/note/new", method = RequestMethod.POST)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public @ResponseBody EntityIdentifier addClientNote(@PathVariable("clientId") Long clientId,
|
||||
@RequestParam(value="note", required=false) String note) {
|
||||
|
||||
NoteCommand command = new NoteCommand();
|
||||
command.setClientId(clientId);
|
||||
command.setNote(note);
|
||||
|
||||
return this.commonRestOperations.addNote(command);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "/portfolio/client/{clientId}/note/{noteId}", method = RequestMethod.GET)
|
||||
public @ResponseBody NoteData retrieveExistingNoteDetails(@PathVariable("clientId") Long clientId, @PathVariable("noteId") Long noteId) {
|
||||
|
||||
return this.commonRestOperations.retrieveClientNote(clientId, noteId);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/portfolio/client/{clientId}/note/{noteId}", method = RequestMethod.POST)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public @ResponseBody EntityIdentifier updateClientNote(@PathVariable("clientId") Long clientId, @PathVariable("noteId") Long noteId,
|
||||
@RequestParam(value="note", required=false) String note) {
|
||||
|
||||
NoteCommand command = new NoteCommand();
|
||||
command.setId(noteId);
|
||||
command.setClientId(clientId);
|
||||
command.setNote(note);
|
||||
|
||||
return this.commonRestOperations.updateNote(command);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "/portfolio/client/all", method = RequestMethod.GET)
|
||||
public @ResponseBody ClientList viewAllClients() {
|
||||
|
||||
return new ClientList(this.commonRestOperations.retrieveAllIndividualClients());
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "/portfolio/client/new", method = RequestMethod.GET)
|
||||
public @ResponseBody ClientData newIndividualClientDetails() {
|
||||
|
||||
ClientData clientData = this.commonRestOperations.retrieveNewIndividualClient();
|
||||
return clientData;
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/portfolio/client/new", method = RequestMethod.POST)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public @ResponseBody EntityIdentifier createClient(HttpServletRequest request,
|
||||
@RequestParam(value="office", required=false) Long officeId,
|
||||
@RequestParam(value="firstname", required=false) String firstname,
|
||||
@RequestParam(value="lastname", required=false) String lastname,
|
||||
@RequestParam(value="fullname", required=false) String fullname,
|
||||
@RequestParam(value="joiningDate", required=false) String joiningDate,
|
||||
@RequestParam(value="externalId", required=false) String externalId) {
|
||||
|
||||
|
||||
LocalDate joiningLocalDate = parseStringToLocalDate(joiningDate, "joiningDate");
|
||||
|
||||
EnrollClientCommand command = new EnrollClientCommand(firstname, lastname, fullname, officeId, joiningLocalDate);
|
||||
return this.commonRestOperations.enrollClient(command);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "/portfolio/client/{clientId}", method = RequestMethod.GET)
|
||||
public @ResponseBody ClientDataWithAccountsData viewClientAccountData(@PathVariable("clientId") Long clientId) {
|
||||
|
||||
return this.commonRestOperations.retrieveClientAccount(clientId);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "/portfolio/loan/{loanId}", method = RequestMethod.GET)
|
||||
public @ResponseBody LoanAccountData viewLoanAccountData(@PathVariable("loanId") Long loanId) {
|
||||
|
||||
return this.commonRestOperations.retrieveLoanAccount(loanId);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/portfolio/client/{clientId}", method = RequestMethod.GET)
|
||||
public String viewClientAccount(final Model model, @PathVariable("clientId") final Long clientId) {
|
||||
|
||||
ClientData clientData = this.commonRestOperations.retrieveClientDetails(clientId);
|
||||
|
||||
model.addAttribute("clientId", clientId);
|
||||
model.addAttribute("clientDisplayName", clientData.getDisplayName());
|
||||
|
||||
return "client/viewClientAccount";
|
||||
}
|
||||
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package org.mifosng.ui.client;
|
||||
|
||||
public class DropdownOption {
|
||||
|
||||
private String label;
|
||||
private String value;
|
||||
|
||||
public static DropdownOption of(String label, String value) {
|
||||
DropdownOption option = new DropdownOption();
|
||||
option.setLabel(label);
|
||||
option.setValue(value);
|
||||
return option;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public void setLabel(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package org.mifosng.ui.client;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
public class PayoffFormBean {
|
||||
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||
private DateTime payoffDate = new DateTime();
|
||||
|
||||
public DateTime getPayoffDate() {
|
||||
return this.payoffDate;
|
||||
}
|
||||
|
||||
public void setPayoffDate(final DateTime payoffDate) {
|
||||
this.payoffDate = payoffDate;
|
||||
}
|
||||
}
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
package org.mifosng.ui.configuration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.mifosng.configuration.ApplicationConfigurationService;
|
||||
import org.mifosng.configuration.OAuthProviderDetails;
|
||||
import org.mifosng.data.ConfigurationData;
|
||||
import org.mifosng.data.CurrencyData;
|
||||
import org.mifosng.data.EntityIdentifier;
|
||||
import org.mifosng.data.ErrorResponse;
|
||||
import org.mifosng.data.command.UpdateOrganisationCurrencyCommand;
|
||||
import org.mifosng.oauth.RefreshableProtectedResourceDetailsService;
|
||||
import org.mifosng.ui.CommonRestOperations;
|
||||
import org.mifosng.ui.loanproduct.ClientValidationException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.oauth.consumer.ProtectedResourceDetailsService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.SessionAttributes;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
@SessionAttributes({"oauthSettingsFormBean"})
|
||||
@Controller
|
||||
public class ConfigurationController {
|
||||
|
||||
private final ApplicationConfigurationService applicationConfigurationService;
|
||||
private final RefreshableProtectedResourceDetailsService refreshableProtectedResourceDetailsService;
|
||||
private final CommonRestOperations commonRestOperations;
|
||||
|
||||
@Autowired
|
||||
public ConfigurationController(
|
||||
final CommonRestOperations commonRestOperations, final ApplicationConfigurationService applicationConfigurationService,
|
||||
final RefreshableProtectedResourceDetailsService refreshableProtectedResourceDetailsService) {
|
||||
this.commonRestOperations = commonRestOperations;
|
||||
this.applicationConfigurationService = applicationConfigurationService;
|
||||
this.refreshableProtectedResourceDetailsService = refreshableProtectedResourceDetailsService;
|
||||
}
|
||||
|
||||
@ExceptionHandler(AccessDeniedException.class)
|
||||
public String accessDeniedException() {
|
||||
return "unAuthorizedAction";
|
||||
}
|
||||
|
||||
@ExceptionHandler(ClientValidationException.class)
|
||||
public @ResponseBody
|
||||
Collection<ErrorResponse> validationException(ClientValidationException ex,
|
||||
HttpServletResponse response) {
|
||||
|
||||
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||
response.setContentType("application/json");
|
||||
|
||||
return ex.getValidationErrors();
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "org/configuration/edit", method = RequestMethod.GET)
|
||||
public @ResponseBody ConfigurationData viewConfigurationDetails() {
|
||||
|
||||
List<CurrencyData> selectedCurrencyOptions = new ArrayList<CurrencyData>(this.commonRestOperations.retrieveAllowedCurrencies());
|
||||
List<CurrencyData> currencyOptions = new ArrayList<CurrencyData>(this.commonRestOperations.retrieveAllPlatformCurrencies());
|
||||
|
||||
// remove selected currency options
|
||||
currencyOptions.removeAll(selectedCurrencyOptions);
|
||||
|
||||
ConfigurationData configurationData = new ConfigurationData();
|
||||
configurationData.setCurrencyOptions(currencyOptions);
|
||||
configurationData.setSelectedCurrencyOptions(selectedCurrencyOptions);
|
||||
|
||||
return configurationData;
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "org/configuration/edit", method = RequestMethod.POST)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public @ResponseBody EntityIdentifier updateOrganisationCurrencies(@RequestParam(value="selectedItems", required=false) String[] selectedCurrencies) {
|
||||
|
||||
List<String> codes = new ArrayList<String>();
|
||||
if (selectedCurrencies != null) {
|
||||
codes = Arrays.asList(selectedCurrencies);
|
||||
}
|
||||
|
||||
UpdateOrganisationCurrencyCommand command = new UpdateOrganisationCurrencyCommand(codes);
|
||||
|
||||
this.commonRestOperations.updateOrganisationCurrencies(command);
|
||||
|
||||
return new EntityIdentifier(Long.valueOf(1));
|
||||
}
|
||||
|
||||
@ModelAttribute("oauthSettingsFormBean")
|
||||
@RequestMapping(value = "oauth/configuration/edit", method = RequestMethod.GET)
|
||||
public ModelAndView showOAuthConfiguration() {
|
||||
|
||||
OAuthProviderDetails details = this.applicationConfigurationService.retrieveOAuthProviderDetails();
|
||||
|
||||
OauthSettingsFormBean oauthSettingsFormBean = new OauthSettingsFormBean();
|
||||
oauthSettingsFormBean.setConsumerkey(details.getConsumerkey());
|
||||
oauthSettingsFormBean.setSharedSecret(details.getSharedSecret());
|
||||
oauthSettingsFormBean.setOauthProviderUrl(details.getProviderBaseUrl());
|
||||
|
||||
return new ModelAndView("configuration/oauthconfig",
|
||||
"oauthSettingsFormBean", oauthSettingsFormBean);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "oauth/configuration/edit", method = RequestMethod.POST)
|
||||
public ModelAndView updateOAuthConfiguration(
|
||||
@ModelAttribute final OauthSettingsFormBean oauthSettingsFormBean,
|
||||
final BindingResult result) {
|
||||
|
||||
ModelAndView mav = new ModelAndView("redirect:/");
|
||||
|
||||
OAuthProviderDetails newDetails = new OAuthProviderDetails(oauthSettingsFormBean.getOauthProviderUrl(), oauthSettingsFormBean.getConsumerkey(), oauthSettingsFormBean.getSharedSecret());
|
||||
|
||||
this.applicationConfigurationService.update(newDetails);
|
||||
|
||||
this.refreshableProtectedResourceDetailsService.refresh();
|
||||
|
||||
this.commonRestOperations.updateProtectedResource(((ProtectedResourceDetailsService)refreshableProtectedResourceDetailsService).loadProtectedResourceDetailsById("protectedMifosNgServices"));
|
||||
|
||||
return mav;
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package org.mifosng.ui.configuration;
|
||||
|
||||
public class OauthSettingsFormBean {
|
||||
|
||||
private String oauthProviderUrl;
|
||||
private String sharedSecret;
|
||||
private String consumerkey;
|
||||
|
||||
public String getOauthProviderUrl() {
|
||||
return oauthProviderUrl;
|
||||
}
|
||||
|
||||
public void setOauthProviderUrl(String oauthProviderUrl) {
|
||||
this.oauthProviderUrl = oauthProviderUrl;
|
||||
}
|
||||
|
||||
public String getSharedSecret() {
|
||||
return sharedSecret;
|
||||
}
|
||||
|
||||
public void setSharedSecret(String sharedSecret) {
|
||||
this.sharedSecret = sharedSecret;
|
||||
}
|
||||
|
||||
public String getConsumerkey() {
|
||||
return consumerkey;
|
||||
}
|
||||
|
||||
public void setConsumerkey(String consumerkey) {
|
||||
this.consumerkey = consumerkey;
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package org.mifosng.ui.extradata;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.mifosng.data.EntityIdentifier;
|
||||
import org.mifosng.data.ErrorResponse;
|
||||
import org.mifosng.data.ExtraDatasets;
|
||||
import org.mifosng.data.reports.GenericResultset;
|
||||
import org.mifosng.ui.CommonRestOperations;
|
||||
import org.mifosng.ui.loanproduct.ClientValidationException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@Controller
|
||||
public class ExtraDataController {
|
||||
|
||||
private final CommonRestOperations commonRestOperations;
|
||||
|
||||
@Autowired
|
||||
public ExtraDataController(final CommonRestOperations commonRestOperations) {
|
||||
this.commonRestOperations = commonRestOperations;
|
||||
}
|
||||
|
||||
@ExceptionHandler(AccessDeniedException.class)
|
||||
public String accessDeniedException() {
|
||||
return "unAuthorizedAction";
|
||||
}
|
||||
|
||||
@ExceptionHandler(ClientValidationException.class)
|
||||
public @ResponseBody Collection<ErrorResponse> validationException(ClientValidationException ex, HttpServletResponse response) {
|
||||
|
||||
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||
response.setContentType("application/json");
|
||||
|
||||
return ex.getValidationErrors();
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "/extradata/datasets/{datasetType}", method = RequestMethod.GET)
|
||||
public @ResponseBody ExtraDatasets retrieveExtraDatasets(@PathVariable("datasetType") String datasetType) {
|
||||
|
||||
return this.commonRestOperations.retrieveExtraDatasets(datasetType);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "/extradata/{datasetType}/{datasetName}/{datasetPKValue}", method = RequestMethod.GET)
|
||||
public @ResponseBody GenericResultset viewExtraData(@PathVariable("datasetType") String datasetType, @PathVariable("datasetName") String datasetName, @PathVariable("datasetPKValue") String datasetPKValue) {
|
||||
|
||||
return this.commonRestOperations.retrieveExtraData(datasetType, datasetName, datasetPKValue);
|
||||
}
|
||||
|
||||
@RequestMapping(produces="application/json", value = "/extradata/{datasetType}/{datasetName}/{datasetPKValue}", method = RequestMethod.POST)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public @ResponseBody EntityIdentifier saveExtraData(HttpServletRequest request, @PathVariable("datasetType") String datasetType,@PathVariable("datasetName") String datasetName, @PathVariable("datasetPKValue") String datasetPKValue) {
|
||||
return this.commonRestOperations.saveExtraData(datasetType, datasetName, datasetPKValue, request.getParameterMap());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.mifosng.ui.home;
|
||||
|
||||
import org.mifosng.ui.reporting.ReportingRestOperations;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
@Controller
|
||||
public class HomeController {
|
||||
|
||||
private final ReportingRestOperations reportingRestOperations;
|
||||
|
||||
@Autowired
|
||||
public HomeController(final ReportingRestOperations reportingRestOperations) {
|
||||
this.reportingRestOperations = reportingRestOperations;
|
||||
}
|
||||
|
||||
@RequestMapping(value="/forceOAuth", method = RequestMethod.GET)
|
||||
public String forceOAuth() {
|
||||
|
||||
this.reportingRestOperations.hackToForceAuthentication();
|
||||
|
||||
return "redirect:/home";
|
||||
}
|
||||
|
||||
@RequestMapping(value="/", method = RequestMethod.GET)
|
||||
public String redirectToIndexPage() {
|
||||
return "redirect:/home";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/home", method = RequestMethod.GET)
|
||||
public ModelAndView showIndividualClientsOnHomePage() {
|
||||
return new ModelAndView("/home");
|
||||
}
|
||||
|
||||
@RequestMapping(value="/switchToClient", method = RequestMethod.POST)
|
||||
public String switchToClientView(@RequestParam("client") final Long client) {
|
||||
return "redirect:/portfolio/client/" + client;
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package org.mifosng.ui.home;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.mifosng.configuration.ApplicationConfigurationService;
|
||||
import org.mifosng.ui.CommonRestOperations;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.oauth.consumer.OAuthConsumerToken;
|
||||
import org.springframework.security.oauth.consumer.OAuthSecurityContext;
|
||||
import org.springframework.security.oauth.consumer.OAuthSecurityContextHolder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
@Controller
|
||||
public class LogoutController {
|
||||
|
||||
private final CommonRestOperations commonRestOperations;
|
||||
// private final ApplicationConfigurationService applicationConfigurationService;
|
||||
|
||||
@Autowired
|
||||
public LogoutController(final CommonRestOperations commonRestOperations,
|
||||
ApplicationConfigurationService applicationConfigurationService) {
|
||||
this.commonRestOperations = commonRestOperations;
|
||||
// this.applicationConfigurationService = applicationConfigurationService;
|
||||
}
|
||||
|
||||
@RequestMapping(value="/logoutcontroller", method = RequestMethod.GET)
|
||||
public String forceOAuth() {
|
||||
|
||||
// OAuthProviderDetails oauthDetails = this.applicationConfigurationService
|
||||
// .retrieveOAuthProviderDetails();
|
||||
|
||||
String resourceId = "protectedMifosNgServices";
|
||||
OAuthSecurityContext context = OAuthSecurityContextHolder.getContext();
|
||||
if (context == null) {
|
||||
throw new IllegalStateException(
|
||||
"No OAuth security context has been established. Unable to access resource '"
|
||||
+ resourceId + "'.");
|
||||
}
|
||||
|
||||
Map<String, OAuthConsumerToken> accessTokens = context
|
||||
.getAccessTokens();
|
||||
OAuthConsumerToken accessToken = accessTokens == null ? null
|
||||
: accessTokens.get(resourceId);
|
||||
|
||||
// model.addAttribute("baseUrl", oauthDetails.getProviderBaseUrl());
|
||||
// model.addAttribute("consumerKey", oauthDetails.getConsumerkey());
|
||||
// model.addAttribute("consumerSecret", oauthDetails.getSharedSecret());
|
||||
// if (accessToken != null) {
|
||||
// model.addAttribute("accessToken", accessToken.getValue());
|
||||
// model.addAttribute("tokenSecret", accessToken.getSecret());
|
||||
// }
|
||||
|
||||
String oauthToken = "";
|
||||
if (accessToken != null) {
|
||||
oauthToken = accessToken.getValue();
|
||||
}
|
||||
|
||||
this.commonRestOperations.logout(oauthToken);
|
||||
|
||||
return "redirect:/j_spring_security_logout";
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
package org.mifosng.ui.loan;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.mifosng.data.CurrencyData;
|
||||
import org.mifosng.data.MoneyData;
|
||||
import org.mifosng.ui.CommonRestOperations;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
@Controller
|
||||
public class CashflowController {
|
||||
|
||||
// private final CommonRestOperations commonRestOperations;
|
||||
|
||||
@Autowired
|
||||
public CashflowController(final CommonRestOperations commonRestOperations) {
|
||||
// this.commonRestOperations = commonRestOperations;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/portfolio/client/{clientId}/cashflow/new", method = RequestMethod.GET)
|
||||
public String submitNewCashflowAnalysis(@PathVariable("clientId") final Long clientId) {
|
||||
return "redirect:/createCashflowAnalysis?loanId=0&clientId={clientId}";
|
||||
}
|
||||
|
||||
// called from webflow
|
||||
public void populateLoanDetailsForCashflow(final CashflowFormBean formBean, Long loanId, Long clientId) {
|
||||
|
||||
formBean.setBusinessName("Fixed Example Business (Sole Trader)");
|
||||
formBean.setClientName("Fixed Example Client");
|
||||
|
||||
CurrencyData currency = new CurrencyData("XOF", "", 0, "CFA", "currency.XOF");
|
||||
MoneyData amount = MoneyData.of(currency, BigDecimal.valueOf(0));
|
||||
|
||||
formBean.setExpectedLoanTerm(12);
|
||||
|
||||
List<MultiTermExpense> investments = new ArrayList<MultiTermExpense>();
|
||||
investments.add(new MultiTermExpense("equipment purchase", Integer.valueOf(0), amount.getAmount(), formBean.getExpectedLoanTerm()));
|
||||
investments.add(new MultiTermExpense("Option two", Integer.valueOf(0), amount.getAmount(), formBean.getExpectedLoanTerm()));
|
||||
investments.add(new MultiTermExpense("Option three", Integer.valueOf(0), amount.getAmount(), formBean.getExpectedLoanTerm()));
|
||||
|
||||
formBean.setInvestments(investments);
|
||||
|
||||
List<OneOffExpense> fixedExpenses = new ArrayList<OneOffExpense>();
|
||||
fixedExpenses.add(new OneOffExpense("Fixed one", amount.getAmount()));
|
||||
fixedExpenses.add(new OneOffExpense("Fixed two", amount.getAmount()));
|
||||
fixedExpenses.add(new OneOffExpense("Fixed three", amount.getAmount()));
|
||||
|
||||
formBean.setFixedExpenses(fixedExpenses);
|
||||
|
||||
List<UnitInformationOfProduct> products = new ArrayList<UnitInformationOfProduct>();
|
||||
products.add(new UnitInformationOfProduct("First Product", Integer.valueOf(10), BigDecimal.valueOf(Double.valueOf("12.00")), BigDecimal.valueOf(Double.valueOf("23.00"))));
|
||||
products.add(new UnitInformationOfProduct("Second Product", Integer.valueOf(500), BigDecimal.valueOf(Double.valueOf("10.00")), BigDecimal.valueOf(Double.valueOf("15.00"))));
|
||||
|
||||
formBean.setProducts(products);
|
||||
// List<ClientReadModel> individualClients = new ArrayList<ClientReadModel>(this.commonRestOperations.retrieveLoan);
|
||||
|
||||
// List<LoanProductReadModel> loanProducts = new ArrayList<LoanProductReadModel>(
|
||||
// this.commonRestOperations.retrieveAllLoanProducts());
|
||||
//
|
||||
// loanFormBean.setApplicantOptions(individualClients);
|
||||
// if (individualClients.size() == 1) {
|
||||
// loanFormBean.setSelectedApplicantOption(individualClients.get(0)
|
||||
// .getId());
|
||||
// }
|
||||
//
|
||||
// loanFormBean.setLoanProductOptions(loanProducts);
|
||||
// if (loanProducts.size() == 1) {
|
||||
// loanFormBean.setSelectedLoanProductOption(loanProducts.get(0)
|
||||
// .getId());
|
||||
// }
|
||||
}
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
package org.mifosng.ui.loan;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CashflowFormBean implements Serializable {
|
||||
|
||||
private String clientName;
|
||||
private String businessName;
|
||||
|
||||
private Integer expectedLoanTerm = Integer.valueOf(12);
|
||||
|
||||
private List<MultiTermExpense> investments = new ArrayList<MultiTermExpense>();
|
||||
private List<OneOffExpense> fixedExpenses = new ArrayList<OneOffExpense>();
|
||||
|
||||
private List<UnitInformationOfProduct> products = new ArrayList<UnitInformationOfProduct>();
|
||||
|
||||
private Number entrepreneurInput = Double.valueOf("0");
|
||||
|
||||
public String getClientName() {
|
||||
return clientName;
|
||||
}
|
||||
|
||||
public void setClientName(String clientName) {
|
||||
this.clientName = clientName;
|
||||
}
|
||||
|
||||
public String getBusinessName() {
|
||||
return businessName;
|
||||
}
|
||||
|
||||
public void setBusinessName(String businessName) {
|
||||
this.businessName = businessName;
|
||||
}
|
||||
|
||||
public List<OneOffExpense> getFixedExpenses() {
|
||||
return fixedExpenses;
|
||||
}
|
||||
|
||||
public void setFixedExpenses(List<OneOffExpense> fixedExpenses) {
|
||||
this.fixedExpenses = fixedExpenses;
|
||||
}
|
||||
|
||||
public List<UnitInformationOfProduct> getProducts() {
|
||||
return products;
|
||||
}
|
||||
|
||||
public void setProducts(List<UnitInformationOfProduct> products) {
|
||||
this.products = products;
|
||||
}
|
||||
|
||||
public Integer getExpectedLoanTerm() {
|
||||
return expectedLoanTerm;
|
||||
}
|
||||
|
||||
public void setExpectedLoanTerm(Integer expectedLoanTerm) {
|
||||
this.expectedLoanTerm = expectedLoanTerm;
|
||||
}
|
||||
|
||||
public List<MultiTermExpense> getInvestments() {
|
||||
return investments;
|
||||
}
|
||||
|
||||
public void setInvestments(List<MultiTermExpense> investments) {
|
||||
this.investments = investments;
|
||||
}
|
||||
|
||||
public Number getEntrepreneurInput() {
|
||||
return entrepreneurInput;
|
||||
}
|
||||
|
||||
public void setEntrepreneurInput(Number entrepreneurInput) {
|
||||
this.entrepreneurInput = entrepreneurInput;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
package org.mifosng.ui.loan;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.security.Principal;
|
||||
import java.text.NumberFormat;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.mifosng.data.EntityIdentifier;
|
||||
import org.mifosng.data.ErrorResponse;
|
||||
import org.mifosng.data.LoanSchedule;
|
||||
import org.mifosng.data.NewLoanWorkflowStepOneData;
|
||||
import org.mifosng.data.command.CalculateLoanScheduleCommand;
|
||||
import org.mifosng.data.command.SubmitLoanApplicationCommand;
|
||||
import org.mifosng.oauth.ConsumerUserDetails;
|
||||
import org.mifosng.ui.CommonRestOperations;
|
||||
import org.mifosng.ui.loanproduct.ClientValidationException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
public class LoanController {
|
||||
|
||||
private final CommonRestOperations commonRestOperations;
|
||||
|
||||
@Autowired
|
||||
public LoanController(final CommonRestOperations commonRestOperations) {
|
||||
this.commonRestOperations = commonRestOperations;
|
||||
}
|
||||
|
||||
@ExceptionHandler(AccessDeniedException.class)
|
||||
public String accessDeniedException() {
|
||||
return "unAuthorizedAction";
|
||||
}
|
||||
|
||||
@ExceptionHandler(ClientValidationException.class)
|
||||
public @ResponseBody Collection<ErrorResponse> validationException(ClientValidationException ex, HttpServletResponse response) {
|
||||
|
||||
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||
response.setContentType("application/json");
|
||||
|
||||
return ex.getValidationErrors();
|
||||
}
|
||||
|
||||
private LocalDate parseStringToLocalDate(String eventDate, String dateFieldIdentifier) {
|
||||
LocalDate eventLocalDate = null;
|
||||
if (StringUtils.isNotBlank(eventDate)) {
|
||||
try {
|
||||
Locale locale = LocaleContextHolder.getLocale();
|
||||
eventLocalDate = DateTimeFormat.forPattern("dd MMMM yyyy").withLocale(locale).parseLocalDate(eventDate.toLowerCase(locale));
|
||||
} catch (IllegalArgumentException e) {
|
||||
List<ErrorResponse> validationErrors = new ArrayList<ErrorResponse>();
|
||||
validationErrors.add(new ErrorResponse("validation.msg.invalid.date.format", dateFieldIdentifier, eventDate));
|
||||
throw new ClientValidationException(validationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
return eventLocalDate;
|
||||
}
|
||||
|
||||
private BigDecimal parseStringToBigDecimal(String source) {
|
||||
try {
|
||||
BigDecimal number = null;
|
||||
|
||||
if (StringUtils.isNotBlank(source)) {
|
||||
String sourceWithoutSpaces = source.replaceAll(" ", "");
|
||||
Locale locale = LocaleContextHolder.getLocale();
|
||||
NumberFormat format = NumberFormat.getNumberInstance(locale);
|
||||
Number parsedNumber = format.parse(sourceWithoutSpaces);
|
||||
number = BigDecimal.valueOf(Double.valueOf(parsedNumber
|
||||
.doubleValue()));
|
||||
}
|
||||
|
||||
return number;
|
||||
} catch (ParseException e) {
|
||||
List<ErrorResponse> validationErrors = new ArrayList<ErrorResponse>();
|
||||
validationErrors.add(new ErrorResponse("validation.msg.invalid.number.format", "amount", source));
|
||||
throw new ClientValidationException(validationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/portfolio/client/{clientId}/loan/new", method = RequestMethod.GET)
|
||||
public String loadLoanCreationWorkflow(final Model model, @PathVariable("clientId") final Long clientId, final Principal principal) {
|
||||
|
||||
UsernamePasswordAuthenticationToken authenticationToken = (UsernamePasswordAuthenticationToken) principal;
|
||||
ConsumerUserDetails user = (ConsumerUserDetails) authenticationToken.getPrincipal();
|
||||
if (user.hasNoAuthorityToSumitLoanApplication()) {
|
||||
throw new AccessDeniedException("");
|
||||
}
|
||||
|
||||
model.addAttribute("clientId", clientId);
|
||||
|
||||
return "newloanapplication";
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/portfolio/client/{clientId}/loan/new", method = RequestMethod.POST)
|
||||
public @ResponseBody EntityIdentifier submitNewLoanApplication(
|
||||
@RequestParam(value="clientId", required=false) Long applicantId,
|
||||
@RequestParam(value="productId", required=false) Long productId,
|
||||
@RequestParam(value="submittedOnDate", required=false) String submittedOnDateStr,
|
||||
@RequestParam(value="submittedOnNote", required=false) String submittedOnNote,
|
||||
@RequestParam(value="currencyCode", required=false) String currencyCode,
|
||||
@RequestParam(value="digitsAfterDecimal", required=false) Integer digitsAfterDecimal,
|
||||
@RequestParam(value="principalMoney", required=false) String principalMoney,
|
||||
@RequestParam(value="repaidEvery", required=false) Integer repaymentEvery,
|
||||
@RequestParam(value="selectedRepaymentFrequencyOption", required=false) Integer repaymentFrequency,
|
||||
@RequestParam(value="numberOfRepayments", required=false) Integer numberOfRepayments,
|
||||
@RequestParam(value="selectedAmortizationMethodOption", required=false) Integer amortizationMethod,
|
||||
@RequestParam(value="inArrearsTolerance", required=false) String inArrearsTolerance,
|
||||
@RequestParam(value="nominalInterestRate", required=false) String nominalInterestRate,
|
||||
@RequestParam(value="selectedInterestFrequencyOption", required=false) Integer interestRateFrequencyMethod,
|
||||
@RequestParam(value="selectedInterestMethodOption", required=false) Integer interestMethod,
|
||||
@RequestParam(value="expectedDisbursementDate", required=false) String expectedDisbursementDateStr,
|
||||
@RequestParam(value="repaymentsStartingFromDate", required=false) String repaymentsStartingFromDateStr,
|
||||
@RequestParam(value="interestCalculatedFromDate", required=false) String interestCalculatedFromDateStr
|
||||
) {
|
||||
|
||||
final LocalDate submittedOnDate = parseStringToLocalDate(submittedOnDateStr, "submittedOnDate");
|
||||
final Number toleranceAmount = parseStringToBigDecimal(inArrearsTolerance);
|
||||
|
||||
final Number principal = parseStringToBigDecimal(principalMoney);
|
||||
final Number interestRatePerPeriod = parseStringToBigDecimal(nominalInterestRate);
|
||||
final boolean flexibleRepaymentSchedule = false;
|
||||
final boolean interestRebateAllowed = false;
|
||||
|
||||
final LocalDate expectedDisbursementDate = parseStringToLocalDate(expectedDisbursementDateStr, "expectedDisbursementDate");
|
||||
final LocalDate repaymentsStartingFromDate = parseStringToLocalDate(repaymentsStartingFromDateStr, "repaymentsStartingFromDate");
|
||||
final LocalDate interestCalculatedFromDate = parseStringToLocalDate(interestCalculatedFromDateStr, "interestCalculatedFromDate");
|
||||
|
||||
CalculateLoanScheduleCommand calculateLoanScheduleCommand = new CalculateLoanScheduleCommand(currencyCode, digitsAfterDecimal, principal, interestRatePerPeriod,
|
||||
interestRateFrequencyMethod, interestMethod, repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod,
|
||||
flexibleRepaymentSchedule, interestRebateAllowed, expectedDisbursementDate, repaymentsStartingFromDate, interestCalculatedFromDate);
|
||||
|
||||
LoanSchedule loanSchedule = this.commonRestOperations.calculateLoanSchedule(calculateLoanScheduleCommand);
|
||||
|
||||
SubmitLoanApplicationCommand command = new SubmitLoanApplicationCommand(applicantId, productId,
|
||||
submittedOnDate, submittedOnNote, expectedDisbursementDate, repaymentsStartingFromDate, interestCalculatedFromDate,
|
||||
loanSchedule, currencyCode, digitsAfterDecimal, principal,
|
||||
interestRatePerPeriod, interestRateFrequencyMethod, interestMethod,
|
||||
repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod,
|
||||
toleranceAmount, flexibleRepaymentSchedule, interestRebateAllowed);
|
||||
|
||||
Long identifier = this.commonRestOperations.submitLoanApplication(command);
|
||||
|
||||
return new EntityIdentifier(identifier);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/portfolio/loanschedule/calculate", method = RequestMethod.POST)
|
||||
public @ResponseBody LoanSchedule calculateLoanSchedule(
|
||||
@RequestParam(value="currencyCode", required=false) String currencyCode,
|
||||
@RequestParam(value="digitsAfterDecimal", required=false) Integer digitsAfterDecimal,
|
||||
@RequestParam(value="principalMoney", required=false) String principalMoney,
|
||||
@RequestParam(value="repaidEvery", required=false) Integer repaymentEvery,
|
||||
@RequestParam(value="selectedRepaymentFrequencyOption", required=false) Integer repaymentFrequency,
|
||||
@RequestParam(value="numberOfRepayments", required=false) Integer numberOfRepayments,
|
||||
@RequestParam(value="selectedAmortizationMethodOption", required=false) Integer amortizationMethod,
|
||||
@RequestParam(value="nominalInterestRate", required=false) String nominalInterestRate,
|
||||
@RequestParam(value="selectedInterestFrequencyOption", required=false) Integer interestRateFrequencyMethod,
|
||||
@RequestParam(value="selectedInterestMethodOption", required=false) Integer interestMethod,
|
||||
@RequestParam(value="expectedDisbursementDate", required=false) String expectedDisbursementDateStr,
|
||||
@RequestParam(value="repaymentsStartingFromDate", required=false) String repaymentsStartingFromDateStr,
|
||||
@RequestParam(value="interestCalculatedFromDate", required=false) String interestCalculatedFromDateStr
|
||||
) {
|
||||
|
||||
final Number principal = parseStringToBigDecimal(principalMoney);
|
||||
final Number interestRatePerPeriod = parseStringToBigDecimal(nominalInterestRate);
|
||||
final boolean flexibleRepaymentSchedule = false;
|
||||
final boolean interestRebateAllowed = false;
|
||||
final LocalDate expectedDisbursementDate = parseStringToLocalDate(expectedDisbursementDateStr, "expectedDisbursementDate");
|
||||
final LocalDate repaymentsStartingFromDate = parseStringToLocalDate(repaymentsStartingFromDateStr, "repaymentsStartingFromDate");
|
||||
final LocalDate interestCalculatedFromDate = parseStringToLocalDate(interestCalculatedFromDateStr, "interestCalculatedFromDate");
|
||||
|
||||
CalculateLoanScheduleCommand command = new CalculateLoanScheduleCommand(currencyCode, digitsAfterDecimal, principal, interestRatePerPeriod,
|
||||
interestRateFrequencyMethod, interestMethod, repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod,
|
||||
flexibleRepaymentSchedule, interestRebateAllowed, expectedDisbursementDate, repaymentsStartingFromDate, interestCalculatedFromDate);
|
||||
|
||||
return this.commonRestOperations.calculateLoanSchedule(command);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "/portfolio/client/{clientId}/product/{productId}/new", method = RequestMethod.GET)
|
||||
public @ResponseBody NewLoanWorkflowStepOneData retrieveNewLoan(@PathVariable("clientId") Long clientId, @PathVariable("productId") Long productId) {
|
||||
|
||||
return this.commonRestOperations.retrieveNewLoanApplicationDetails(clientId, productId);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "/portfolio/client/{clientId}/loan/new/workflow/one", method = RequestMethod.GET)
|
||||
public @ResponseBody NewLoanWorkflowStepOneData retrieveNewLoan(@PathVariable("clientId") Long clientId) {
|
||||
|
||||
return this.commonRestOperations.retrieveNewLoanApplicationStepOneDetails(clientId);
|
||||
}
|
||||
}
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
package org.mifosng.ui.loan;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.NumberFormat;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.mifosng.data.EntityIdentifier;
|
||||
import org.mifosng.data.ErrorResponse;
|
||||
import org.mifosng.data.LoanRepaymentData;
|
||||
import org.mifosng.data.command.AdjustLoanTransactionCommand;
|
||||
import org.mifosng.data.command.LoanStateTransitionCommand;
|
||||
import org.mifosng.data.command.LoanTransactionCommand;
|
||||
import org.mifosng.data.command.UndoLoanApprovalCommand;
|
||||
import org.mifosng.data.command.UndoLoanDisbursalCommand;
|
||||
import org.mifosng.ui.CommonRestOperations;
|
||||
import org.mifosng.ui.loanproduct.ClientValidationException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@Controller
|
||||
public class LoanTransactionController {
|
||||
|
||||
private final CommonRestOperations commonRestOperations;
|
||||
|
||||
@Autowired
|
||||
public LoanTransactionController(final CommonRestOperations commonRestOperations) {
|
||||
this.commonRestOperations = commonRestOperations;
|
||||
}
|
||||
|
||||
@ExceptionHandler(AccessDeniedException.class)
|
||||
public String accessDeniedException() {
|
||||
return "unAuthorizedAction";
|
||||
}
|
||||
|
||||
@ExceptionHandler(ClientValidationException.class)
|
||||
public @ResponseBody Collection<ErrorResponse> validationException(ClientValidationException ex, HttpServletResponse response) {
|
||||
|
||||
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||
response.setContentType("application/json");
|
||||
|
||||
return ex.getValidationErrors();
|
||||
}
|
||||
|
||||
private LocalDate parseStringToLocalDate(String eventDate, String dateFieldIdentifier) {
|
||||
LocalDate eventLocalDate = null;
|
||||
if (StringUtils.isNotBlank(eventDate)) {
|
||||
try {
|
||||
Locale locale = LocaleContextHolder.getLocale();
|
||||
eventLocalDate = DateTimeFormat.forPattern("dd MMMM yyyy").withLocale(locale).parseLocalDate(eventDate.toLowerCase(locale));
|
||||
} catch (IllegalArgumentException e) {
|
||||
List<ErrorResponse> validationErrors = new ArrayList<ErrorResponse>();
|
||||
validationErrors.add(new ErrorResponse("validation.msg.invalid.date.format", dateFieldIdentifier, eventDate));
|
||||
throw new ClientValidationException(validationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
return eventLocalDate;
|
||||
}
|
||||
|
||||
private BigDecimal parseStringToBigDecimal(String source) {
|
||||
try {
|
||||
BigDecimal number = null;
|
||||
|
||||
if (StringUtils.isNotBlank(source)) {
|
||||
String sourceWithoutSpaces = source.replaceAll(" ", "");
|
||||
Locale locale = LocaleContextHolder.getLocale();
|
||||
NumberFormat format = NumberFormat.getNumberInstance(locale);
|
||||
Number parsedNumber = format.parse(sourceWithoutSpaces);
|
||||
number = BigDecimal.valueOf(Double.valueOf(parsedNumber
|
||||
.doubleValue()));
|
||||
}
|
||||
|
||||
return number;
|
||||
} catch (ParseException e) {
|
||||
List<ErrorResponse> validationErrors = new ArrayList<ErrorResponse>();
|
||||
validationErrors.add(new ErrorResponse("validation.msg.invalid.number.format", "amount", source));
|
||||
throw new ClientValidationException(validationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/portfolio/loan/{loanId}/delete", method = RequestMethod.POST)
|
||||
public @ResponseBody EntityIdentifier deleteLoan(@PathVariable("loanId") final Long loanId) {
|
||||
|
||||
return this.commonRestOperations.deleteLoan(loanId);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/portfolio/loan/{loanId}/approve", method = RequestMethod.POST)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public @ResponseBody EntityIdentifier approveLoan(
|
||||
@PathVariable("loanId") final Long loanId,
|
||||
@RequestParam(value="eventDate", required=false) String eventDate,
|
||||
@RequestParam(value="comment", required=false) String comment) {
|
||||
|
||||
LocalDate approvalDate = parseStringToLocalDate(eventDate, "eventDate");
|
||||
|
||||
LoanStateTransitionCommand command = new LoanStateTransitionCommand(loanId, approvalDate, comment);
|
||||
|
||||
return this.commonRestOperations.approveLoan(command);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/portfolio/loan/{loanId}/undoapproval", method = RequestMethod.POST)
|
||||
public String undoLoanApproval(@PathVariable("loanId") final Long loanId) {
|
||||
|
||||
UndoLoanApprovalCommand command = new UndoLoanApprovalCommand(loanId);
|
||||
|
||||
EntityIdentifier clientAccountId = this.commonRestOperations
|
||||
.undoLoanApproval(command);
|
||||
|
||||
return "redirect:/portfolio/client/" + clientAccountId.getEntityId();
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/portfolio/loan/{loanId}/reject", method = RequestMethod.POST)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public @ResponseBody EntityIdentifier rejectLoan(
|
||||
@PathVariable("loanId") final Long loanId,
|
||||
@RequestParam(value="eventDate", required=false) String eventDate,
|
||||
@RequestParam(value="comment", required=false) String comment) {
|
||||
|
||||
LocalDate rejectionDate = parseStringToLocalDate(eventDate, "eventDate");
|
||||
|
||||
LoanStateTransitionCommand command = new LoanStateTransitionCommand(loanId, rejectionDate, comment);
|
||||
|
||||
return this.commonRestOperations.rejectLoan(command);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/portfolio/loan/{loanId}/withdraw", method = RequestMethod.POST)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public @ResponseBody EntityIdentifier loanWithdrawnByClient(
|
||||
@PathVariable("loanId") final Long loanId,
|
||||
@RequestParam(value="eventDate", required=false) String eventDate,
|
||||
@RequestParam(value="comment", required=false) String comment) {
|
||||
|
||||
LocalDate withdrawnOnDate = parseStringToLocalDate(eventDate, "eventDate");
|
||||
|
||||
LoanStateTransitionCommand command = new LoanStateTransitionCommand(loanId, withdrawnOnDate, comment);
|
||||
|
||||
return this.commonRestOperations.withdrawLoan(command);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/portfolio/loan/{loanId}/disburse", method = RequestMethod.POST)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public @ResponseBody EntityIdentifier disburseLoan(
|
||||
@PathVariable("loanId") final Long loanId,
|
||||
@RequestParam(value="eventDate", required=false) String eventDate,
|
||||
@RequestParam(value="comment", required=false) String comment) {
|
||||
|
||||
LocalDate disbursalDate = parseStringToLocalDate(eventDate, "eventDate");
|
||||
|
||||
LoanStateTransitionCommand command = new LoanStateTransitionCommand(loanId, disbursalDate, comment);
|
||||
|
||||
return this.commonRestOperations.disburseLoan(command);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/portfolio/loan/{loanId}/undodisbursal", method = RequestMethod.POST)
|
||||
public String undoLoanDisbursal(@PathVariable final Long loanId) {
|
||||
|
||||
UndoLoanDisbursalCommand command = new UndoLoanDisbursalCommand(loanId);
|
||||
|
||||
EntityIdentifier clientAccountId = this.commonRestOperations
|
||||
.undloLoanDisbursal(command);
|
||||
|
||||
return "redirect:/portfolio/client/" + clientAccountId.getEntityId();
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value ="/portfolio/loan/{loanId}/repayment", method = RequestMethod.GET)
|
||||
public @ResponseBody LoanRepaymentData retrieveNewLoanRepaymentDetail(@PathVariable("loanId") final Long loanId) {
|
||||
|
||||
return this.commonRestOperations.retrieveNewLoanRepaymentDetails(loanId);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/portfolio/loan/{loanId}/repayment", method = RequestMethod.POST)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public @ResponseBody EntityIdentifier enterRepaymentOnLoan(
|
||||
@PathVariable("loanId") final Long loanId,
|
||||
@RequestParam(value="transactionDate", required=false) String transactionDate,
|
||||
@RequestParam(value="transactionComment", required=false) String transactionComment,
|
||||
@RequestParam(value="transactionAmount", required=false) String transactionAmount) {
|
||||
|
||||
LocalDate repaymentDate = parseStringToLocalDate(transactionDate, "transactionDate");
|
||||
BigDecimal repaymentAmount = parseStringToBigDecimal(transactionAmount);
|
||||
|
||||
LoanTransactionCommand command = new LoanTransactionCommand(loanId,
|
||||
repaymentDate, transactionComment, repaymentAmount);
|
||||
|
||||
return this.commonRestOperations.makeLoanRepayment(command);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "/portfolio/loan/{loanId}/repayment/{repaymentId}/adjust", method = RequestMethod.GET)
|
||||
public @ResponseBody LoanRepaymentData retrieveLoanRepayment(@PathVariable("loanId") final Long loanId, @PathVariable("repaymentId") final Long repaymentId) {
|
||||
return this.commonRestOperations.retrieveLoanRepaymentDetails(loanId, repaymentId);
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/portfolio/loan/{loanId}/repayment/{repaymentId}/adjust", method = RequestMethod.POST)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public @ResponseBody EntityIdentifier adjustPreviousRepaymentOnLoan(
|
||||
@PathVariable("loanId") final Long loanId, @PathVariable("repaymentId") final Long repaymentId,
|
||||
@RequestParam(value="transactionDate", required=false) String transactionDate,
|
||||
@RequestParam(value="transactionComment", required=false) String transactionComment,
|
||||
@RequestParam(value="transactionAmount", required=false) String transactionAmount) {
|
||||
|
||||
LocalDate repaymentDate = parseStringToLocalDate(transactionDate, "transactionDate");
|
||||
BigDecimal repaymentAmount = parseStringToBigDecimal(transactionAmount);
|
||||
|
||||
AdjustLoanTransactionCommand command = new AdjustLoanTransactionCommand(loanId, repaymentId, repaymentDate, transactionComment, repaymentAmount);
|
||||
|
||||
return this.commonRestOperations.adjustLoanRepayment(command);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "/portfolio/loan/{loanId}/waive", method = RequestMethod.GET)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public @ResponseBody LoanRepaymentData retrievePossibleWaiveDetails(@PathVariable("loanId") final Long loanId) {
|
||||
return this.commonRestOperations.retrieveNewLoanWaiverDetails(loanId);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/portfolio/loan/{loanId}/waive", method = RequestMethod.POST)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public @ResponseBody EntityIdentifier waiveLoanAmount(
|
||||
@PathVariable("loanId") final Long loanId,
|
||||
@RequestParam(value="transactionDate", required=false) String transactionDate,
|
||||
@RequestParam(value="transactionComment", required=false) String transactionComment,
|
||||
@RequestParam(value="transactionAmount", required=false) String transactionAmount) {
|
||||
|
||||
LocalDate waiveDate = parseStringToLocalDate(transactionDate, "transactionDate");
|
||||
BigDecimal waiveAmount = parseStringToBigDecimal(transactionAmount);
|
||||
|
||||
LoanTransactionCommand command = new LoanTransactionCommand(loanId,
|
||||
waiveDate, transactionComment, waiveAmount);
|
||||
|
||||
return this.commonRestOperations.waiveLoanAmount(command);
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
package org.mifosng.ui.loan;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
public class MultiTermExpense implements Serializable {
|
||||
|
||||
private String name;
|
||||
private String description;
|
||||
private Integer fullTermInMonths;
|
||||
private Number fullAmount;
|
||||
private Integer applicableTermInMonths;
|
||||
private Number applicableAmount;
|
||||
|
||||
public MultiTermExpense() {
|
||||
//
|
||||
}
|
||||
|
||||
public MultiTermExpense(String name, Integer fullTermInMonths, BigDecimal fullAmount, Integer applicableTermInMonths) {
|
||||
this.name = name;
|
||||
this.fullTermInMonths = fullTermInMonths;
|
||||
this.fullAmount = fullAmount;
|
||||
this.applicableTermInMonths = applicableTermInMonths;
|
||||
this.applicableAmount = fullAmount;
|
||||
BigDecimal fullAmountAsDecimal = BigDecimal.valueOf(this.fullAmount.longValue());
|
||||
if (!fullAmountAsDecimal.equals(BigDecimal.ZERO)) {
|
||||
this.applicableAmount = fullAmountAsDecimal.divide(BigDecimal.valueOf(applicableTermInMonths.longValue()), RoundingMode.HALF_EVEN);
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Integer getFullTermInMonths() {
|
||||
return fullTermInMonths;
|
||||
}
|
||||
|
||||
public void setFullTermInMonths(Integer fullTermInMonths) {
|
||||
this.fullTermInMonths = fullTermInMonths;
|
||||
}
|
||||
|
||||
public Number getFullAmount() {
|
||||
return fullAmount;
|
||||
}
|
||||
|
||||
public void setFullAmount(Number fullAmount) {
|
||||
this.fullAmount = fullAmount;
|
||||
}
|
||||
|
||||
public Integer getApplicableTermInMonths() {
|
||||
return applicableTermInMonths;
|
||||
}
|
||||
|
||||
public void setApplicableTermInMonths(Integer applicableTermInMonths) {
|
||||
this.applicableTermInMonths = applicableTermInMonths;
|
||||
}
|
||||
|
||||
public Number getApplicableAmount() {
|
||||
return applicableAmount;
|
||||
}
|
||||
|
||||
public void setApplicableAmount(Number applicableAmount) {
|
||||
this.applicableAmount = applicableAmount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package org.mifosng.ui.loan;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class OneOffExpense implements Serializable {
|
||||
|
||||
private String name;
|
||||
private String description;
|
||||
private Number amount;
|
||||
|
||||
public OneOffExpense() {
|
||||
//
|
||||
}
|
||||
|
||||
public OneOffExpense(String name, BigDecimal amount) {
|
||||
this.name = name;
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Number getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(Number amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package org.mifosng.ui.loan;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class UnitInformationOfProduct implements Serializable {
|
||||
|
||||
private String name;
|
||||
private Number unitsSold = Integer.valueOf(0);
|
||||
private Number costPerUnit = BigDecimal.ZERO;
|
||||
private Number pricePerUnit = BigDecimal.ZERO;
|
||||
|
||||
public UnitInformationOfProduct() {
|
||||
//
|
||||
}
|
||||
|
||||
public UnitInformationOfProduct(String name, Integer unitsSold,
|
||||
BigDecimal costPerUnit, BigDecimal pricePerUnit) {
|
||||
this.name = name;
|
||||
this.unitsSold = unitsSold;
|
||||
this.costPerUnit = costPerUnit;
|
||||
this.pricePerUnit = pricePerUnit;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Number getUnitsSold() {
|
||||
return unitsSold;
|
||||
}
|
||||
|
||||
public void setUnitsSold(Number unitsSold) {
|
||||
this.unitsSold = unitsSold;
|
||||
}
|
||||
|
||||
public Number getCostPerUnit() {
|
||||
return costPerUnit;
|
||||
}
|
||||
|
||||
public void setCostPerUnit(Number costPerUnit) {
|
||||
this.costPerUnit = costPerUnit;
|
||||
}
|
||||
|
||||
public Number getPricePerUnit() {
|
||||
return pricePerUnit;
|
||||
}
|
||||
|
||||
public void setPricePerUnit(Number pricePerUnit) {
|
||||
this.pricePerUnit = pricePerUnit;
|
||||
}
|
||||
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package org.mifosng.ui.loanproduct;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.mifosng.data.ErrorResponse;
|
||||
|
||||
public class ClientValidationException extends RuntimeException {
|
||||
|
||||
private final List<ErrorResponse> validationErrors;
|
||||
|
||||
public ClientValidationException(List<ErrorResponse> validationErrors) {
|
||||
super("Validation errors exist");
|
||||
this.validationErrors = validationErrors;
|
||||
}
|
||||
|
||||
public List<ErrorResponse> getValidationErrors() {
|
||||
return validationErrors;
|
||||
}
|
||||
}
|
||||
+193
@@ -0,0 +1,193 @@
|
||||
package org.mifosng.ui.loanproduct;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.NumberFormat;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.mifosng.data.EntityIdentifier;
|
||||
import org.mifosng.data.ErrorResponse;
|
||||
import org.mifosng.data.LoanProductData;
|
||||
import org.mifosng.data.command.CreateLoanProductCommand;
|
||||
import org.mifosng.data.command.UpdateLoanProductCommand;
|
||||
import org.mifosng.ui.CommonRestOperations;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@Controller
|
||||
public class LoanProductController {
|
||||
|
||||
private final CommonRestOperations commonRestOperations;
|
||||
|
||||
@Autowired
|
||||
public LoanProductController(final CommonRestOperations commonRestOperations) {
|
||||
this.commonRestOperations = commonRestOperations;
|
||||
}
|
||||
|
||||
@ExceptionHandler(AccessDeniedException.class)
|
||||
public String accessDeniedException() {
|
||||
return "unAuthorizedAction";
|
||||
}
|
||||
|
||||
@ExceptionHandler(ClientValidationException.class)
|
||||
public @ResponseBody Collection<ErrorResponse> validationException(ClientValidationException ex, HttpServletResponse response) {
|
||||
|
||||
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||
response.setContentType("application/json");
|
||||
|
||||
return ex.getValidationErrors();
|
||||
}
|
||||
|
||||
private BigDecimal parseStringToBigDecimal(String source) {
|
||||
try {
|
||||
BigDecimal number = null;
|
||||
|
||||
if (StringUtils.isNotBlank(source)) {
|
||||
String sourceWithoutSpaces = source.replaceAll(" ", "");
|
||||
Locale locale = LocaleContextHolder.getLocale();
|
||||
NumberFormat format = NumberFormat.getNumberInstance(locale);
|
||||
Number parsedNumber = format.parse(sourceWithoutSpaces);
|
||||
number = BigDecimal.valueOf(Double.valueOf(parsedNumber
|
||||
.doubleValue()));
|
||||
}
|
||||
|
||||
return number;
|
||||
} catch (ParseException e) {
|
||||
List<ErrorResponse> validationErrors = new ArrayList<ErrorResponse>();
|
||||
validationErrors.add(new ErrorResponse("validation.msg.invalid.number.format", "amount", source));
|
||||
throw new ClientValidationException(validationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "/portfolio/product/loan/all", method = RequestMethod.GET)
|
||||
public @ResponseBody Collection<LoanProductData> viewAllLoanProducts() {
|
||||
|
||||
return this.commonRestOperations.retrieveAllLoanProducts();
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "/portfolio/product/loan/new", method = RequestMethod.GET)
|
||||
public @ResponseBody LoanProductData viewNewLoanProductForm() {
|
||||
|
||||
return this.commonRestOperations.retrieveNewLoanProductDetails();
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/portfolio/product/loan/new", method = RequestMethod.POST)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public @ResponseBody EntityIdentifier createLoanProduct(HttpServletRequest request,
|
||||
@RequestParam("name") String name,
|
||||
@RequestParam("description") String description,
|
||||
@RequestParam("selectedCurrency") String currencyCode, @RequestParam("selectedDigitsAfterDecimal") Integer digitsAfterDecimal,
|
||||
@RequestParam("amount") String principalAsNumber,
|
||||
@RequestParam("repaidEvery") Integer repaymentEvery,
|
||||
@RequestParam("selectedRepaymentFrequencyOption") Integer repaymentFrequency,
|
||||
@RequestParam("numberOfRepayments") Integer numberOfRepayments,
|
||||
@RequestParam("selectedAmortizationMethodOption") Integer amortizationMethod,
|
||||
@RequestParam("inArrearsTolerance") String inArrearsToleranceAsNumber,
|
||||
@RequestParam("nominalInterestRate") String nominalInterestRatePerPeriodAsNumber,
|
||||
@RequestParam("selectedInterestFrequencyOption") Integer nominalInterestRatePerPeriodFrequency,
|
||||
@RequestParam("selectedInterestMethodOption") Integer interestMethod
|
||||
) {
|
||||
|
||||
CreateLoanProductCommand command = new CreateLoanProductCommand();
|
||||
command.setName(name);
|
||||
command.setDescription(description);
|
||||
command.setCurrencyCode(currencyCode);
|
||||
command.setDigitsAfterDecimal(digitsAfterDecimal);
|
||||
|
||||
if (StringUtils.isNotBlank(principalAsNumber)) {
|
||||
BigDecimal principal = parseStringToBigDecimal(principalAsNumber);
|
||||
command.setPrincipal(principal);
|
||||
}
|
||||
|
||||
command.setRepaymentEvery(repaymentEvery);
|
||||
command.setRepaymentFrequency(repaymentFrequency);
|
||||
command.setNumberOfRepayments(numberOfRepayments);
|
||||
command.setAmortizationMethod(amortizationMethod);
|
||||
|
||||
if (StringUtils.isNotBlank(inArrearsToleranceAsNumber)) {
|
||||
BigDecimal inArrearsToleranceAmount = parseStringToBigDecimal(inArrearsToleranceAsNumber);
|
||||
command.setInArrearsToleranceAmount(inArrearsToleranceAmount);
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(nominalInterestRatePerPeriodAsNumber)) {
|
||||
BigDecimal interestRatePerPeriod = parseStringToBigDecimal(nominalInterestRatePerPeriodAsNumber);
|
||||
command.setInterestRatePerPeriod(interestRatePerPeriod);
|
||||
}
|
||||
command.setInterestRateFrequencyMethod(nominalInterestRatePerPeriodFrequency);
|
||||
command.setInterestMethod(interestMethod);
|
||||
|
||||
return this.commonRestOperations.createLoanProduct(command);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "/portfolio/product/loan/{productId}", method = RequestMethod.GET)
|
||||
public @ResponseBody LoanProductData viewLoanProduct(@PathVariable("productId") final Long productId) {
|
||||
|
||||
return this.commonRestOperations.retrieveLoanProductDetails(productId);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/portfolio/product/loan/{productId}", method = RequestMethod.POST)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public @ResponseBody EntityIdentifier updateLoanProduct(@PathVariable("productId") final Long productId, HttpServletRequest request,
|
||||
@RequestParam("name") String name, @RequestParam("description") String description,
|
||||
@RequestParam("selectedCurrency") String currencyCode, @RequestParam("selectedDigitsAfterDecimal") Integer digitsAfterDecimal,
|
||||
@RequestParam("amount") String principalAsNumber,
|
||||
@RequestParam("repaidEvery") Integer repaymentEvery,
|
||||
@RequestParam("selectedRepaymentFrequencyOption") Integer repaymentFrequency,
|
||||
@RequestParam("numberOfRepayments") Integer numberOfRepayments,
|
||||
@RequestParam("selectedAmortizationMethodOption") Integer amortizationMethod,
|
||||
@RequestParam("inArrearsTolerance") String inArrearsToleranceAsNumber,
|
||||
@RequestParam("nominalInterestRate") String nominalInterestRatePerPeriodAsNumber,
|
||||
@RequestParam("selectedInterestFrequencyOption") Integer nominalInterestRatePerPeriodFrequency,
|
||||
@RequestParam("selectedInterestMethodOption") Integer interestMethod
|
||||
) {
|
||||
|
||||
UpdateLoanProductCommand command = new UpdateLoanProductCommand();
|
||||
command.setId(productId);
|
||||
command.setName(name);
|
||||
command.setDescription(description);
|
||||
command.setExternalId(null);
|
||||
command.setCurrencyCode(currencyCode);
|
||||
command.setDigitsAfterDecimal(digitsAfterDecimal);
|
||||
|
||||
if (StringUtils.isNotBlank(principalAsNumber)) {
|
||||
BigDecimal principal = parseStringToBigDecimal(principalAsNumber);
|
||||
command.setPrincipal(principal);
|
||||
}
|
||||
|
||||
command.setRepaymentEvery(repaymentEvery);
|
||||
command.setRepaymentFrequency(repaymentFrequency);
|
||||
command.setNumberOfRepayments(numberOfRepayments);
|
||||
command.setAmortizationMethod(amortizationMethod);
|
||||
|
||||
if (StringUtils.isNotBlank(inArrearsToleranceAsNumber)) {
|
||||
BigDecimal inArrearsToleranceAmount = parseStringToBigDecimal(inArrearsToleranceAsNumber);
|
||||
command.setInArrearsToleranceAmount(inArrearsToleranceAmount);
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(nominalInterestRatePerPeriodAsNumber)) {
|
||||
BigDecimal interestRatePerPeriod = parseStringToBigDecimal(nominalInterestRatePerPeriodAsNumber);
|
||||
command.setInterestRatePerPeriod(interestRatePerPeriod);
|
||||
}
|
||||
command.setInterestRateFrequencyMethod(nominalInterestRatePerPeriodFrequency);
|
||||
command.setInterestMethod(interestMethod);
|
||||
|
||||
return this.commonRestOperations.updateLoanProduct(command);
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package org.mifosng.ui.migration;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.mifosng.configuration.ApplicationConfigurationService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.oauth.consumer.client.OAuthRestTemplate;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
@Controller
|
||||
public class MigrationTriggerController {
|
||||
|
||||
private final OAuthRestTemplate oauthRestServiceTemplate;
|
||||
private final ApplicationConfigurationService applicationConfigurationService;
|
||||
|
||||
@Autowired
|
||||
public MigrationTriggerController(final OAuthRestTemplate oauthRestServiceTemplate, ApplicationConfigurationService applicationConfigurationService) {
|
||||
this.oauthRestServiceTemplate = oauthRestServiceTemplate;
|
||||
this.applicationConfigurationService = applicationConfigurationService;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/migration/trigger/clients/creocore", method = RequestMethod.GET)
|
||||
public String migrateClientInformation() {
|
||||
|
||||
URI restUri = URI
|
||||
.create(getBaseServerUrl().concat("api/protected/import/trigger/clients/creocore"));
|
||||
|
||||
this.oauthRestServiceTemplate.getForEntity(restUri, null);
|
||||
return "redirect:/home";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/migration/trigger/loans/creocore", method = RequestMethod.GET)
|
||||
public String migrateLoanInformation() {
|
||||
|
||||
URI restUri = URI
|
||||
.create(getBaseServerUrl().concat("api/protected/import/trigger/loans/creocore"));
|
||||
|
||||
this.oauthRestServiceTemplate.getForEntity(restUri, null);
|
||||
return "redirect:/home";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/migration/trigger/repayments/creocore", method = RequestMethod.GET)
|
||||
public String migrateLoanRepaymentsInformation() {
|
||||
|
||||
URI restUri = URI
|
||||
.create(getBaseServerUrl().concat("api/protected/import/trigger/repayments/creocore"));
|
||||
|
||||
this.oauthRestServiceTemplate.getForEntity(restUri, null);
|
||||
return "redirect:/home";
|
||||
}
|
||||
|
||||
private String getBaseServerUrl() {
|
||||
return this.applicationConfigurationService.retrieveOAuthProviderDetails().getProviderBaseUrl();
|
||||
}
|
||||
}
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
package org.mifosng.ui.office;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.mifosng.data.EntityIdentifier;
|
||||
import org.mifosng.data.ErrorResponse;
|
||||
import org.mifosng.data.OfficeData;
|
||||
import org.mifosng.data.command.OfficeCommand;
|
||||
import org.mifosng.ui.CommonRestOperations;
|
||||
import org.mifosng.ui.loanproduct.ClientValidationException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@Controller
|
||||
public class OfficeController {
|
||||
|
||||
private final CommonRestOperations commonRestOperations;
|
||||
|
||||
@Autowired
|
||||
public OfficeController(final CommonRestOperations commonRestOperations) {
|
||||
this.commonRestOperations = commonRestOperations;
|
||||
}
|
||||
|
||||
@ExceptionHandler(AccessDeniedException.class)
|
||||
public String accessDeniedException() {
|
||||
return "unAuthorizedAction";
|
||||
}
|
||||
|
||||
@ExceptionHandler(ClientValidationException.class)
|
||||
public @ResponseBody
|
||||
Collection<ErrorResponse> validationException(ClientValidationException ex,
|
||||
HttpServletResponse response) {
|
||||
|
||||
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||
response.setContentType("application/json");
|
||||
|
||||
return ex.getValidationErrors();
|
||||
}
|
||||
|
||||
private LocalDate parseStringToLocalDate(String eventDate, String dateFieldIdentifier) {
|
||||
LocalDate eventLocalDate = null;
|
||||
if (StringUtils.isNotBlank(eventDate)) {
|
||||
try {
|
||||
Locale locale = LocaleContextHolder.getLocale();
|
||||
eventLocalDate = DateTimeFormat.forPattern("dd MMMM yyyy").withLocale(locale).parseLocalDate(eventDate.toLowerCase(locale));
|
||||
} catch (IllegalArgumentException e) {
|
||||
List<ErrorResponse> validationErrors = new ArrayList<ErrorResponse>();
|
||||
validationErrors.add(new ErrorResponse("validation.msg.invalid.date.format", dateFieldIdentifier, eventDate));
|
||||
throw new ClientValidationException(validationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
return eventLocalDate;
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "/org/office/all", method = RequestMethod.GET)
|
||||
public @ResponseBody Collection<OfficeData> viewAllOffices() {
|
||||
|
||||
return this.commonRestOperations.retrieveAllOffices();
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "/org/office/new", method = RequestMethod.GET)
|
||||
public @ResponseBody OfficeData viewNewOfficeForm() {
|
||||
|
||||
OfficeData newOffice = new OfficeData();
|
||||
newOffice.setOpeningDate(new LocalDate());
|
||||
|
||||
Collection<OfficeData> allOffices = this.commonRestOperations.retrieveAllOffices();
|
||||
List<OfficeData> allowedParents = new ArrayList<OfficeData>(allOffices);
|
||||
|
||||
newOffice.setAllowedParents(allowedParents);
|
||||
|
||||
return newOffice;
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/org/office/new", method = RequestMethod.POST)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public @ResponseBody EntityIdentifier createOffice(HttpServletRequest request,
|
||||
@RequestParam("name") String name,
|
||||
@RequestParam(value="parentId", required=false) Long parentId,
|
||||
@RequestParam("openingDate") String openingDate,
|
||||
@RequestParam(value="externalId", required=false) String externalId) {
|
||||
|
||||
LocalDate openingLocalDate = parseStringToLocalDate(openingDate, "openingDate");
|
||||
|
||||
OfficeCommand command = new OfficeCommand(name, externalId, parentId, openingLocalDate);
|
||||
return this.commonRestOperations.createOffice(command);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "/org/office/{officeId}", method = RequestMethod.GET)
|
||||
public @ResponseBody OfficeData viewOffice(@PathVariable("officeId") final Long officeId) {
|
||||
|
||||
return this.commonRestOperations.retrieveOffice(officeId);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/org/office/{officeId}", method = RequestMethod.POST)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public @ResponseBody EntityIdentifier updateOffice(HttpServletRequest request, @PathVariable("officeId") final Long officeId,
|
||||
@RequestParam("name") String name,
|
||||
@RequestParam(value="parentId", required=false) Long parentId,
|
||||
@RequestParam("openingDate") String openingDate,
|
||||
@RequestParam(value="externalId", required=false) String externalId) {
|
||||
|
||||
LocalDate openingLocalDate = parseStringToLocalDate(openingDate, "openingDate");
|
||||
|
||||
OfficeCommand command = new OfficeCommand(officeId, name, externalId, parentId, openingLocalDate);
|
||||
return this.commonRestOperations.updateOffice(command);
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
package org.mifosng.ui.reporting;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Map;
|
||||
|
||||
import org.mifosng.configuration.ApplicationConfigurationService;
|
||||
import org.mifosng.configuration.OAuthProviderDetails;
|
||||
import org.mifosng.oauth.ConsumerUserDetails;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.oauth.consumer.OAuthConsumerToken;
|
||||
import org.springframework.security.oauth.consumer.OAuthSecurityContext;
|
||||
import org.springframework.security.oauth.consumer.OAuthSecurityContextHolder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/reporting")
|
||||
public class ReportingController {
|
||||
|
||||
private final ReportingRestOperations reportingRestOperations;
|
||||
private final ApplicationConfigurationService applicationConfigurationService;
|
||||
|
||||
@Autowired
|
||||
public ReportingController(final ReportingRestOperations reportingRestOperations,
|
||||
ApplicationConfigurationService applicationConfigurationService) {
|
||||
this.reportingRestOperations = reportingRestOperations;
|
||||
this.applicationConfigurationService = applicationConfigurationService;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/flexireport", method = RequestMethod.GET)
|
||||
public String viewFlexibleReportingPage(final Model model, final Principal principal) {
|
||||
|
||||
UsernamePasswordAuthenticationToken authenticationToken = (UsernamePasswordAuthenticationToken) principal;
|
||||
ConsumerUserDetails user = (ConsumerUserDetails) authenticationToken.getPrincipal();
|
||||
if (user.hasNoReportingAuthority()) {
|
||||
throw new AccessDeniedException("");
|
||||
}
|
||||
|
||||
this.reportingRestOperations.hackToForceAuthentication();
|
||||
|
||||
OAuthProviderDetails oauthDetails = this.applicationConfigurationService
|
||||
.retrieveOAuthProviderDetails();
|
||||
|
||||
String resourceId = "protectedMifosNgServices";
|
||||
OAuthSecurityContext context = OAuthSecurityContextHolder.getContext();
|
||||
if (context == null) {
|
||||
throw new IllegalStateException(
|
||||
"No OAuth security context has been established. Unable to access resource '"
|
||||
+ resourceId + "'.");
|
||||
}
|
||||
|
||||
Map<String, OAuthConsumerToken> accessTokens = context
|
||||
.getAccessTokens();
|
||||
OAuthConsumerToken accessToken = accessTokens == null ? null
|
||||
: accessTokens.get(resourceId);
|
||||
|
||||
model.addAttribute("baseUrl", oauthDetails.getProviderBaseUrl());
|
||||
model.addAttribute("consumerKey", oauthDetails.getConsumerkey());
|
||||
model.addAttribute("consumerSecret", oauthDetails.getSharedSecret());
|
||||
if (accessToken != null) {
|
||||
model.addAttribute("accessToken", accessToken.getValue());
|
||||
model.addAttribute("tokenSecret", accessToken.getSecret());
|
||||
}
|
||||
|
||||
return "reports/flexireport";
|
||||
}
|
||||
|
||||
@ExceptionHandler(AccessDeniedException.class)
|
||||
public String accessDeniedException() {
|
||||
return "unAuthorizedAction";
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package org.mifosng.ui.reporting;
|
||||
|
||||
public interface ReportingRestOperations {
|
||||
|
||||
void hackToForceAuthentication();
|
||||
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package org.mifosng.ui.reporting;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.mifosng.configuration.ApplicationConfigurationService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.oauth.consumer.client.OAuthRestTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
|
||||
@Service
|
||||
public class ReportingRestOperationsImpl implements ReportingRestOperations {
|
||||
|
||||
private final OAuthRestTemplate oauthRestServiceTemplate;
|
||||
private final ApplicationConfigurationService applicationConfigurationService;
|
||||
|
||||
@Autowired
|
||||
public ReportingRestOperationsImpl(
|
||||
final OAuthRestTemplate oauthRestServiceTemplate, final ApplicationConfigurationService applicationConfigurationService) {
|
||||
this.oauthRestServiceTemplate = oauthRestServiceTemplate;
|
||||
this.applicationConfigurationService = applicationConfigurationService;
|
||||
}
|
||||
|
||||
private HttpEntity<Object> emptyRequest() {
|
||||
HttpHeaders requestHeaders = new HttpHeaders();
|
||||
requestHeaders.set("Accept", "application/xml");
|
||||
requestHeaders.set("Content-Type", "application/xml");
|
||||
|
||||
HttpEntity<Object> requestEntity = new HttpEntity<Object>(
|
||||
requestHeaders);
|
||||
return requestEntity;
|
||||
}
|
||||
|
||||
private String getBaseServerUrl() {
|
||||
return this.applicationConfigurationService.retrieveOAuthProviderDetails().getProviderBaseUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hackToForceAuthentication() {
|
||||
try {
|
||||
URI restUri = URI
|
||||
.create(getBaseServerUrl().concat("api/protected/reporting/forceauth"));
|
||||
|
||||
this.oauthRestServiceTemplate.exchange(restUri, HttpMethod.GET, emptyRequest(), null);
|
||||
} catch (HttpStatusCodeException e) {
|
||||
System.err.println(e.getMessage());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
package org.mifosng.ui.user;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.mifosng.data.AppUserData;
|
||||
import org.mifosng.data.EntityIdentifier;
|
||||
import org.mifosng.data.ErrorResponse;
|
||||
import org.mifosng.data.PermissionData;
|
||||
import org.mifosng.data.RoleData;
|
||||
import org.mifosng.data.command.RoleCommand;
|
||||
import org.mifosng.data.command.UserCommand;
|
||||
import org.mifosng.ui.CommonRestOperations;
|
||||
import org.mifosng.ui.loanproduct.ClientValidationException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@Controller
|
||||
public class AppUserController {
|
||||
|
||||
private final CommonRestOperations commonRestOperations;
|
||||
|
||||
@Autowired
|
||||
public AppUserController(final CommonRestOperations commonRestOperations) {
|
||||
this.commonRestOperations = commonRestOperations;
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "/admin/permission/all", method = RequestMethod.GET)
|
||||
public @ResponseBody Collection<PermissionData> viewAllPermission() {
|
||||
|
||||
return this.commonRestOperations.retrieveAllPermissions();
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "/admin/role/all", method = RequestMethod.GET)
|
||||
public @ResponseBody Collection<RoleData> viewAllRoles() {
|
||||
|
||||
return this.commonRestOperations.retrieveAllRoles();
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "/admin/role/new", method = RequestMethod.GET)
|
||||
public @ResponseBody RoleData newRoleDetails() {
|
||||
|
||||
return this.commonRestOperations.retrieveNewRoleDetails();
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/admin/role/new", method = RequestMethod.POST)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public @ResponseBody EntityIdentifier createNewRole(@RequestParam(value="selectedItems", required=false) String[] selectedRoles,
|
||||
@RequestParam(value="name") String name,
|
||||
@RequestParam(value="description") String description) {
|
||||
|
||||
RoleCommand command = new RoleCommand(name, description, selectedRoles);
|
||||
|
||||
return this.commonRestOperations.createRole(command);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes = "application/json", produces = "application/json", value = "/admin/role/{roleId}", method = RequestMethod.GET)
|
||||
public @ResponseBody
|
||||
RoleData retrieveRoleDetails(@PathVariable("roleId") Long roleId) {
|
||||
|
||||
return this.commonRestOperations.retrieveRole(roleId);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/admin/role/{roleId}", method = RequestMethod.POST)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public @ResponseBody EntityIdentifier updateRole(@PathVariable("roleId") Long roleId,
|
||||
@RequestParam(value="selectedItems", required=false) String[] selectedRoles,
|
||||
@RequestParam(value="name") String name,
|
||||
@RequestParam(value="description") String description) {
|
||||
|
||||
RoleCommand command = new RoleCommand(name, description, selectedRoles);
|
||||
command.setId(roleId);
|
||||
|
||||
return this.commonRestOperations.updateRole(command);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "/admin/user/all", method = RequestMethod.GET)
|
||||
public @ResponseBody Collection<AppUserData> viewAllUsers() {
|
||||
|
||||
return this.commonRestOperations.retrieveAllUsers();
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "/admin/user/new", method = RequestMethod.GET)
|
||||
public @ResponseBody AppUserData viewUser() {
|
||||
|
||||
return this.commonRestOperations.retrieveNewUserDetails();
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/admin/user/new", method = RequestMethod.POST)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public @ResponseBody EntityIdentifier createNewUser(@RequestParam(value="selectedItems", required=false) String[] selectedRoles,
|
||||
@RequestParam(value="username") String username,
|
||||
@RequestParam(value="firstname") String firstname,
|
||||
@RequestParam(value="lastname") String lastname,
|
||||
@RequestParam(value="email") String email,
|
||||
@RequestParam(value="officeId") Long officeId) {
|
||||
|
||||
UserCommand command = new UserCommand(username, firstname, lastname, "", email, selectedRoles, officeId);
|
||||
|
||||
return this.commonRestOperations.createUser(command);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes = "application/json", produces = "application/json", value = "/admin/user/{userId}", method = RequestMethod.DELETE)
|
||||
public @ResponseBody
|
||||
EntityIdentifier attemptToDeleteUser(@PathVariable("userId") Long userId) {
|
||||
|
||||
this.commonRestOperations.deleteUser(userId);
|
||||
|
||||
return new EntityIdentifier(Long.valueOf(1));
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/json", produces="application/json", value = "/admin/user/{userId}", method = RequestMethod.GET)
|
||||
public @ResponseBody AppUserData viewUser(@PathVariable("userId") Long userId) {
|
||||
|
||||
return this.commonRestOperations.retrieveUser(userId);
|
||||
}
|
||||
|
||||
@RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/admin/user/{userId}", method = RequestMethod.POST)
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public @ResponseBody EntityIdentifier updateUser(@PathVariable("userId") Long userId,
|
||||
@RequestParam(value="selectedItems", required=false) String[] selectedRoles,
|
||||
@RequestParam(value="username") String username,
|
||||
@RequestParam(value="firstname") String firstname,
|
||||
@RequestParam(value="lastname") String lastname,
|
||||
@RequestParam(value="email") String email,
|
||||
@RequestParam(value="officeId") Long officeId) {
|
||||
|
||||
UserCommand command = new UserCommand(username, firstname, lastname, "", email, selectedRoles, officeId);
|
||||
command.setId(userId);
|
||||
|
||||
return this.commonRestOperations.updateUser(command);
|
||||
}
|
||||
|
||||
@ExceptionHandler(ClientValidationException.class)
|
||||
public @ResponseBody Collection<ErrorResponse> validationException(ClientValidationException ex, HttpServletResponse response) {
|
||||
|
||||
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||
response.setContentType("application/json");
|
||||
|
||||
return ex.getValidationErrors();
|
||||
}
|
||||
}
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
package org.mifosng.ui.user;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.mifosng.data.ErrorResponse;
|
||||
import org.mifosng.data.reports.GenericResultset;
|
||||
import org.mifosng.data.reports.ResultsetColumnHeader;
|
||||
import org.mifosng.data.reports.ResultsetDataRow;
|
||||
import org.mifosng.ui.CommonRestOperations;
|
||||
import org.mifosng.ui.loanproduct.ClientValidationException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
public class ExportCSVController {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(ExportCSVController.class);
|
||||
|
||||
private final CommonRestOperations commonRestOperations;
|
||||
|
||||
@Autowired
|
||||
public ExportCSVController(final CommonRestOperations commonRestOperations) {
|
||||
this.commonRestOperations = commonRestOperations;
|
||||
}
|
||||
|
||||
@ExceptionHandler(AccessDeniedException.class)
|
||||
public String accessDeniedException() {
|
||||
return "unAuthorizedAction";
|
||||
}
|
||||
|
||||
@ExceptionHandler(ClientValidationException.class)
|
||||
public @ResponseBody Collection<ErrorResponse> validationException(ClientValidationException ex, HttpServletResponse response) {
|
||||
|
||||
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||
response.setContentType("application/json");
|
||||
|
||||
return ex.getValidationErrors();
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/exportcsv*", method = RequestMethod.GET)
|
||||
public void handleExportCSV(final HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, String[]> queryParams = request.getParameterMap();
|
||||
|
||||
String rptDB = queryParams.get("MRP_rptDB")[0];
|
||||
String name = queryParams.get("MRP_Name")[0];
|
||||
String type = queryParams.get("MRP_Type")[0];
|
||||
|
||||
Set<String> keys = queryParams.keySet();
|
||||
Map<String, String> extractedQueryParams = new HashMap<String, String>();
|
||||
String pKey;
|
||||
String pValue;
|
||||
for (String k : keys) {
|
||||
|
||||
if (k.startsWith("MRP_")) {
|
||||
pKey = "${" + k.substring(4) + "}";
|
||||
pValue = queryParams.get(k)[0];
|
||||
// logger.info(name + ": " + pKey + ": " + pValue);
|
||||
extractedQueryParams.put(pKey, pValue);
|
||||
}
|
||||
}
|
||||
|
||||
// if (extractedQueryParams.size() > 3) {
|
||||
// throw new UnsupportedOperationException("Not able to support this report for export to CSV right now.");
|
||||
// }
|
||||
|
||||
GenericResultset result = this.commonRestOperations.retrieveReportingData(rptDB, name, type, extractedQueryParams);
|
||||
|
||||
// response.setContentType("application/octet-stream");
|
||||
response.setContentType("application/x-msdownload");
|
||||
|
||||
response.setHeader("Content-Disposition",
|
||||
"attachment;filename=" + name.replaceAll(" ", "") + ".csv");
|
||||
|
||||
ServletOutputStream out = response.getOutputStream();
|
||||
StringBuffer sb = generateCsvFileBuffer(result);
|
||||
|
||||
InputStream in = new ByteArrayInputStream(sb.toString().getBytes(
|
||||
"UTF-8"));
|
||||
|
||||
byte[] outputByte = new byte[4096];
|
||||
Integer readLen = in.read(outputByte, 0, 4096);
|
||||
|
||||
while (readLen != -1) {
|
||||
out.write(outputByte, 0, readLen);
|
||||
readLen = in.read(outputByte, 0, 4096);
|
||||
}
|
||||
in.close();
|
||||
out.flush();
|
||||
out.close();
|
||||
|
||||
}
|
||||
|
||||
private static StringBuffer generateCsvFileBuffer(GenericResultset result) {
|
||||
StringBuffer writer = new StringBuffer();
|
||||
|
||||
List<ResultsetColumnHeader> columnHeaders = result.getColumnHeaders();
|
||||
logger.info("NO. of Columns: " + columnHeaders.size());
|
||||
Integer chSize = columnHeaders.size();
|
||||
for (int i = 0; i < chSize; i++) {
|
||||
writer.append('"' + columnHeaders.get(i).getColumnName() + '"');
|
||||
if (i < (chSize - 1))
|
||||
writer.append(",");
|
||||
}
|
||||
writer.append('\n');
|
||||
|
||||
List<ResultsetDataRow> data = result.getData();
|
||||
List<String> row;
|
||||
Integer rSize;
|
||||
// String currCol;
|
||||
String currColType;
|
||||
String currVal;
|
||||
logger.info("NO. of Rows: " + data.size());
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
row = data.get(i).getRow();
|
||||
rSize = row.size();
|
||||
for (int j = 0; j < rSize; j++) {
|
||||
// currCol = columnHeaders.get(j).getColumnName();
|
||||
currColType = columnHeaders.get(j).getColumnType();
|
||||
currVal = row.get(j);
|
||||
if (currVal != null) {
|
||||
if (currColType.equals("DECIMAL")
|
||||
|| currColType.equals("DOUBLE")
|
||||
|| currColType.equals("BIGINT")
|
||||
|| currColType.equals("SMALLINT")
|
||||
|| currColType.equals("INT"))
|
||||
writer.append(currVal);
|
||||
else
|
||||
writer.append('"' + currVal + '"');
|
||||
}
|
||||
if (j < (rSize - 1))
|
||||
writer.append(",");
|
||||
}
|
||||
writer.append('\n');
|
||||
}
|
||||
|
||||
return writer;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user