Customer Self Service API Phase 1
This commit is contained in:
+2034
-1
File diff suppressed because it is too large
Load Diff
@@ -192,7 +192,7 @@ body {
|
||||
.flybar-nav {
|
||||
display: block;
|
||||
float: left;
|
||||
min-width: 90px;
|
||||
min-width: 80px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
+31
-13
@@ -34,21 +34,23 @@ public final class SearchParameters {
|
||||
private final Long provisioningEntryId ;
|
||||
private final Long productId ;
|
||||
private final Long categoryId ;
|
||||
private final boolean isSelfUser;
|
||||
|
||||
public static SearchParameters from(final String sqlSearch, final Long officeId, final String externalId, final String name,
|
||||
public static SearchParameters from(final String sqlSearch, final Long officeId, final String externalId, final String name,
|
||||
final String hierarchy) {
|
||||
final Long staffId = null;
|
||||
final String accountNo = null;
|
||||
final Long loanId = null;
|
||||
final Long savingsId = null;
|
||||
final Boolean orphansOnly = false;
|
||||
final boolean isSelfUser = false;
|
||||
return new SearchParameters(sqlSearch, officeId, externalId, name, hierarchy, null, null, null, null, null, null, staffId,
|
||||
accountNo, loanId, savingsId, orphansOnly);
|
||||
accountNo, loanId, savingsId, orphansOnly, isSelfUser);
|
||||
}
|
||||
|
||||
public static SearchParameters forClients(final String sqlSearch, final Long officeId, final String externalId,
|
||||
final String displayName, final String firstname, final String lastname, final String hierarchy, final Integer offset,
|
||||
final Integer limit, final String orderBy, final String sortOrder, final Boolean orphansOnly) {
|
||||
final Integer limit, final String orderBy, final String sortOrder, final Boolean orphansOnly, final boolean isSelfUser) {
|
||||
|
||||
final Integer maxLimitAllowed = getCheckedLimit(limit);
|
||||
final Long staffId = null;
|
||||
@@ -57,7 +59,7 @@ public final class SearchParameters {
|
||||
final Long savingsId = null;
|
||||
|
||||
return new SearchParameters(sqlSearch, officeId, externalId, displayName, hierarchy, firstname, lastname, offset, maxLimitAllowed,
|
||||
orderBy, sortOrder, staffId, accountNo, loanId, savingsId, orphansOnly);
|
||||
orderBy, sortOrder, staffId, accountNo, loanId, savingsId, orphansOnly, isSelfUser);
|
||||
}
|
||||
|
||||
public static SearchParameters forGroups(final String sqlSearch, final Long officeId, final Long staffId, final String externalId,
|
||||
@@ -68,15 +70,17 @@ public final class SearchParameters {
|
||||
final String accountNo = null;
|
||||
final Long loanId = null;
|
||||
final Long savingsId = null;
|
||||
final boolean isSelfUser = false;
|
||||
|
||||
return new SearchParameters(sqlSearch, officeId, externalId, name, hierarchy, null, null, offset, maxLimitAllowed, orderBy,
|
||||
sortOrder, staffId, accountNo, loanId, savingsId, orphansOnly);
|
||||
sortOrder, staffId, accountNo, loanId, savingsId, orphansOnly, isSelfUser);
|
||||
}
|
||||
|
||||
public static SearchParameters forOffices(final String orderBy, final String sortOrder) {
|
||||
final Boolean orphansOnly = false;
|
||||
final boolean isSelfUser = false;
|
||||
return new SearchParameters(null, null, null, null, null, null, null, null, null, orderBy, sortOrder, null, null, null, null,
|
||||
orphansOnly);
|
||||
orphansOnly, isSelfUser);
|
||||
}
|
||||
|
||||
public static SearchParameters forLoans(final String sqlSearch, final String externalId, final Integer offset, final Integer limit,
|
||||
@@ -87,9 +91,10 @@ public final class SearchParameters {
|
||||
final Long loanId = null;
|
||||
final Long savingsId = null;
|
||||
final Boolean orphansOnly = false;
|
||||
final boolean isSelfUser = false;
|
||||
|
||||
return new SearchParameters(sqlSearch, null, externalId, null, null, null, null, offset, maxLimitAllowed, orderBy, sortOrder,
|
||||
staffId, accountNo, loanId, savingsId, orphansOnly);
|
||||
staffId, accountNo, loanId, savingsId, orphansOnly, isSelfUser);
|
||||
}
|
||||
|
||||
public static SearchParameters forJournalEntries(final Long officeId, final Integer offset, final Integer limit, final String orderBy,
|
||||
@@ -98,9 +103,10 @@ public final class SearchParameters {
|
||||
final Integer maxLimitAllowed = getCheckedLimit(limit);
|
||||
final Long staffId = null;
|
||||
final Boolean orphansOnly = false;
|
||||
final boolean isSelfUser = false;
|
||||
|
||||
return new SearchParameters(null, officeId, null, null, null, null, null, offset, maxLimitAllowed, orderBy, sortOrder, staffId,
|
||||
null, loanId, savingsId, orphansOnly);
|
||||
null, loanId, savingsId, orphansOnly, isSelfUser);
|
||||
}
|
||||
|
||||
public static SearchParameters forJournalEntries(final Long officeId, final Integer offset, final Integer limit, final String orderBy,
|
||||
@@ -120,9 +126,10 @@ public final class SearchParameters {
|
||||
final Long loanId = null;
|
||||
final Long savingsId = null;
|
||||
final Boolean orphansOnly = false;
|
||||
final boolean isSelfUser = false;
|
||||
|
||||
return new SearchParameters(null, null, null, null, null, null, null, offset, maxLimitAllowed, orderBy, sortOrder, staffId, null,
|
||||
loanId, savingsId, orphansOnly);
|
||||
loanId, savingsId, orphansOnly, isSelfUser);
|
||||
}
|
||||
|
||||
public static SearchParameters forPagination(final Integer offset, final Integer limit) {
|
||||
@@ -134,9 +141,10 @@ public final class SearchParameters {
|
||||
final Boolean orphansOnly = false;
|
||||
final String orderBy = null;
|
||||
final String sortOrder = null;
|
||||
final boolean isSelfUser = false;
|
||||
|
||||
return new SearchParameters(null, null, null, null, null, null, null, offset, maxLimitAllowed, orderBy, sortOrder, staffId, null,
|
||||
loanId, savingsId, orphansOnly);
|
||||
loanId, savingsId, orphansOnly, isSelfUser);
|
||||
}
|
||||
|
||||
public final static SearchParameters forProvisioningEntries(final Long provisioningEntryId, final Long officeId, final Long productId,
|
||||
@@ -153,9 +161,10 @@ public final class SearchParameters {
|
||||
final Long loanId = null;
|
||||
final Long savingsId = null;
|
||||
final Boolean orphansOnly = false;
|
||||
final boolean isSelfUser = false;
|
||||
|
||||
return new SearchParameters(sqlSearch, null, externalId, null, null, null, null, offset, maxLimitAllowed, orderBy, sortOrder,
|
||||
staffId, accountNo, loanId, savingsId, orphansOnly);
|
||||
staffId, accountNo, loanId, savingsId, orphansOnly, isSelfUser);
|
||||
}
|
||||
|
||||
public static SearchParameters forAccountTransfer(final String sqlSearch, final String externalId, final Integer offset,
|
||||
@@ -167,15 +176,16 @@ public final class SearchParameters {
|
||||
final Long loanId = null;
|
||||
final Long savingsId = null;
|
||||
final Boolean orphansOnly = false;
|
||||
final boolean isSelfUser = false;
|
||||
|
||||
return new SearchParameters(sqlSearch, null, externalId, null, null, null, null, offset, maxLimitAllowed, orderBy, sortOrder,
|
||||
staffId, accountNo, loanId, savingsId, orphansOnly);
|
||||
staffId, accountNo, loanId, savingsId, orphansOnly, isSelfUser);
|
||||
}
|
||||
|
||||
private SearchParameters(final String sqlSearch, final Long officeId, final String externalId, final String name,
|
||||
final String hierarchy, final String firstname, final String lastname, final Integer offset, final Integer limit,
|
||||
final String orderBy, final String sortOrder, final Long staffId, final String accountNo, final Long loanId,
|
||||
final Long savingsId, final Boolean orphansOnly) {
|
||||
final Long savingsId, final Boolean orphansOnly, boolean isSelfUser) {
|
||||
this.sqlSearch = sqlSearch;
|
||||
this.officeId = officeId;
|
||||
this.externalId = externalId;
|
||||
@@ -196,6 +206,7 @@ public final class SearchParameters {
|
||||
this.provisioningEntryId = null ;
|
||||
this.productId = null ;
|
||||
this.categoryId = null ;
|
||||
this.isSelfUser = isSelfUser;
|
||||
|
||||
}
|
||||
|
||||
@@ -221,6 +232,7 @@ public final class SearchParameters {
|
||||
this.provisioningEntryId = provisioningEntryId ;
|
||||
this.productId = productId ;
|
||||
this.categoryId = categoryId ;
|
||||
this.isSelfUser = false;
|
||||
|
||||
}
|
||||
|
||||
@@ -248,6 +260,7 @@ public final class SearchParameters {
|
||||
this.provisioningEntryId = null ;
|
||||
this.productId = null ;
|
||||
this.categoryId = null ;
|
||||
this.isSelfUser = false;
|
||||
}
|
||||
|
||||
public boolean isOrderByRequested() {
|
||||
@@ -397,4 +410,9 @@ public final class SearchParameters {
|
||||
public boolean isCategoryIdPassed() {
|
||||
return this.categoryId != null && this.categoryId != 0 ;
|
||||
}
|
||||
|
||||
public boolean isSelfUser() {
|
||||
return this.isSelfUser;
|
||||
}
|
||||
|
||||
}
|
||||
+22
@@ -24,11 +24,15 @@ import org.mifosplatform.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.mifosplatform.infrastructure.security.data.PlatformRequestLog;
|
||||
import org.mifosplatform.infrastructure.security.exception.InvalidTenantIdentiferException;
|
||||
import org.mifosplatform.infrastructure.security.service.BasicAuthTenantDetailsService;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
@@ -143,4 +147,22 @@ public class TenantAwareBasicAuthenticationFilter extends BasicAuthenticationFil
|
||||
logger.info(this.toApiJsonSerializer.serialize(log));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSuccessfulAuthentication(HttpServletRequest request,
|
||||
HttpServletResponse response, Authentication authResult)
|
||||
throws IOException {
|
||||
super.onSuccessfulAuthentication(request, response, authResult);
|
||||
AppUser user = (AppUser) authResult.getPrincipal();
|
||||
|
||||
String pathURL = request.getRequestURI();
|
||||
boolean isSelfServiceRequest = (pathURL != null && pathURL.contains("/self/"));
|
||||
|
||||
boolean notAllowed = ((isSelfServiceRequest && !user.isSelfServiceUser())
|
||||
||(!isSelfServiceRequest && user.isSelfServiceUser()));
|
||||
|
||||
if(notAllowed){
|
||||
throw new BadCredentialsException("User not authorised to use the requested resource.");
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -88,7 +88,7 @@ public class TenantAwareTenantIdentifierFilter extends GenericFilterBean {
|
||||
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
|
||||
final String reqHead = request.getHeader("Access-Control-Request-Headers");
|
||||
|
||||
if (null != reqHead && !reqHead.equals(null)) {
|
||||
if (null != reqHead && !reqHead.isEmpty()) {
|
||||
response.setHeader("Access-Control-Allow-Headers", reqHead);
|
||||
}
|
||||
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.infrastructure.security.vote;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.springframework.security.access.AccessDecisionVoter;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.FilterInvocation;
|
||||
|
||||
public class SelfServiceUserAccessVote implements AccessDecisionVoter<FilterInvocation> {
|
||||
|
||||
@Override
|
||||
public boolean supports(@SuppressWarnings("unused") ConfigAttribute attribute) {
|
||||
// This implementation supports any attribute, because it does not rely on it.
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<?> clazz) {
|
||||
return FilterInvocation.class.isAssignableFrom(clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int vote(final Authentication authentication, final FilterInvocation fi,
|
||||
@SuppressWarnings("unused") final Collection<ConfigAttribute> attributes) {
|
||||
if(!"OPTIONS".equalsIgnoreCase(fi.getHttpRequest().getMethod())){
|
||||
AppUser user = (AppUser) authentication.getPrincipal();
|
||||
|
||||
String pathURL = fi.getRequestUrl();
|
||||
boolean isSelfServiceRequest = (pathURL != null && pathURL.contains("/self/"));
|
||||
|
||||
boolean notAllowed = ((isSelfServiceRequest && !user.isSelfServiceUser())
|
||||
||(!isSelfServiceRequest && user.isSelfServiceUser()));
|
||||
|
||||
if(notAllowed){
|
||||
return ACCESS_DENIED;
|
||||
}
|
||||
}
|
||||
return ACCESS_GRANTED;
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -75,7 +75,7 @@ public class AccountTransfersReadPlatformServiceImpl implements AccountTransfers
|
||||
final Integer mostRelevantFromAccountType = fromAccountType;
|
||||
final Collection<EnumOptionData> fromAccountTypeOptions = Arrays.asList(savingsAccountType, loanAccountType);
|
||||
final Collection<EnumOptionData> toAccountTypeOptions;
|
||||
if (mostRelevantFromAccountType == 1) {
|
||||
if (mostRelevantFromAccountType != null && mostRelevantFromAccountType == 1) {
|
||||
// overpaid loan amt transfer to savings account
|
||||
toAccountTypeOptions = Arrays.asList(savingsAccountType);
|
||||
} else {
|
||||
|
||||
+13
-1
@@ -117,10 +117,22 @@ public class ClientsApiResource {
|
||||
@QueryParam("orderBy") final String orderBy, @QueryParam("sortOrder") final String sortOrder,
|
||||
@QueryParam("orphansOnly") final Boolean orphansOnly) {
|
||||
|
||||
return this.retrieveAll(uriInfo, sqlSearch, officeId, externalId, displayName, firstname,
|
||||
lastname, hierarchy, offset, limit, orderBy, sortOrder, orphansOnly, false);
|
||||
}
|
||||
|
||||
public String retrieveAll(final UriInfo uriInfo, final String sqlSearch,
|
||||
final Long officeId, final String externalId,
|
||||
final String displayName, final String firstname,
|
||||
final String lastname, final String hierarchy,
|
||||
final Integer offset, final Integer limit,
|
||||
final String orderBy, final String sortOrder,
|
||||
final Boolean orphansOnly, final boolean isSelfUser) {
|
||||
|
||||
this.context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_RESOURCE_NAME);
|
||||
|
||||
final SearchParameters searchParameters = SearchParameters.forClients(sqlSearch, officeId, externalId, displayName, firstname,
|
||||
lastname, hierarchy, offset, limit, orderBy, sortOrder, orphansOnly);
|
||||
lastname, hierarchy, offset, limit, orderBy, sortOrder, orphansOnly, isSelfUser);
|
||||
|
||||
final Page<ClientData> clientData = this.clientReadPlatformService.retrieveAll(searchParameters);
|
||||
|
||||
|
||||
+10
-2
@@ -113,6 +113,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
|
||||
|
||||
final String userOfficeHierarchy = this.context.officeHierarchy();
|
||||
final String underHierarchySearchString = userOfficeHierarchy + "%";
|
||||
final String appUserID = String.valueOf(context.authenticatedUser().getId());
|
||||
|
||||
// if (searchParameters.isScopedByOfficeHierarchy()) {
|
||||
// this.context.validateAccessRights(searchParameters.getHierarchy());
|
||||
@@ -123,6 +124,10 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
|
||||
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
|
||||
sqlBuilder.append(this.clientMapper.schema());
|
||||
sqlBuilder.append(" where (o.hierarchy like ? or transferToOffice.hierarchy like ?) ");
|
||||
|
||||
if(searchParameters.isSelfUser()){
|
||||
sqlBuilder.append(" and c.id in (select umap.client_id from m_selfservice_user_client_mapping as umap where umap.appuser_id = ? ) ");
|
||||
}
|
||||
|
||||
final String extraCriteria = buildSqlStringFromClientCriteria(searchParameters);
|
||||
|
||||
@@ -146,8 +151,11 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
|
||||
}
|
||||
|
||||
final String sqlCountRows = "SELECT FOUND_ROWS()";
|
||||
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), new Object[] {
|
||||
underHierarchySearchString, underHierarchySearchString }, this.clientMapper);
|
||||
Object[] params = new Object[] {underHierarchySearchString, underHierarchySearchString };
|
||||
if(searchParameters.isSelfUser()){
|
||||
params = new Object[] {underHierarchySearchString, underHierarchySearchString, appUserID };
|
||||
}
|
||||
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), params, this.clientMapper);
|
||||
}
|
||||
|
||||
private String buildSqlStringFromClientCriteria(final SearchParameters searchParameters) {
|
||||
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.self.account.api;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
|
||||
import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
|
||||
import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.portfolio.account.api.AccountTransfersApiResource;
|
||||
import org.mifosplatform.portfolio.self.account.data.SelfAccountTemplateData;
|
||||
import org.mifosplatform.portfolio.self.account.data.SelfAccountTransferData;
|
||||
import org.mifosplatform.portfolio.self.account.data.SelfAccountTransferDataValidator;
|
||||
import org.mifosplatform.portfolio.self.account.service.SelfAccountTransferReadService;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Path("/self/accounttransfers")
|
||||
@Component
|
||||
@Scope("singleton")
|
||||
public class SelfAccountTransferApiResource {
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final DefaultToApiJsonSerializer<SelfAccountTransferData> toApiJsonSerializer;
|
||||
private final AccountTransfersApiResource accountTransfersApiResource;
|
||||
private final SelfAccountTransferReadService selfAccountTransferReadService;
|
||||
private final ApiRequestParameterHelper apiRequestParameterHelper;
|
||||
private final SelfAccountTransferDataValidator dataValidator;
|
||||
|
||||
@Autowired
|
||||
public SelfAccountTransferApiResource(
|
||||
final PlatformSecurityContext context,
|
||||
final DefaultToApiJsonSerializer<SelfAccountTransferData> toApiJsonSerializer,
|
||||
final AccountTransfersApiResource accountTransfersApiResource,
|
||||
final SelfAccountTransferReadService selfAccountTransferReadService,
|
||||
final ApiRequestParameterHelper apiRequestParameterHelper,
|
||||
final SelfAccountTransferDataValidator dataValidator) {
|
||||
this.context = context;
|
||||
this.toApiJsonSerializer = toApiJsonSerializer;
|
||||
this.accountTransfersApiResource = accountTransfersApiResource;
|
||||
this.selfAccountTransferReadService = selfAccountTransferReadService;
|
||||
this.apiRequestParameterHelper = apiRequestParameterHelper;
|
||||
this.dataValidator = dataValidator;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("template")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String template(@Context final UriInfo uriInfo) {
|
||||
|
||||
AppUser user = this.context.authenticatedUser();
|
||||
Collection<SelfAccountTemplateData> templateData = this.selfAccountTransferReadService
|
||||
.retrieveSelfAccountTemplateData(user);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper
|
||||
.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings,
|
||||
new SelfAccountTransferData(templateData));
|
||||
}
|
||||
|
||||
@POST
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String create(final String apiRequestBodyAsJson) {
|
||||
this.dataValidator.validateCreate(apiRequestBodyAsJson);
|
||||
return this.accountTransfersApiResource.create(apiRequestBodyAsJson);
|
||||
}
|
||||
|
||||
}
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.self.account.data;
|
||||
|
||||
import org.apache.commons.lang.builder.CompareToBuilder;
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.portfolio.account.service.AccountTransferEnumerations;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class SelfAccountTemplateData implements
|
||||
Comparable<SelfAccountTemplateData> {
|
||||
|
||||
private final Long accountId;
|
||||
private final String accountNo;
|
||||
private final EnumOptionData accountType;
|
||||
private final Long clientId;
|
||||
private final String clientName;
|
||||
private final Long officeId;
|
||||
private final String officeName;
|
||||
|
||||
public SelfAccountTemplateData(final Long accountId,
|
||||
final String accountNo, final Integer accountType,
|
||||
final Long clientId, final String clientName, final Long officeId,
|
||||
final String officeName) {
|
||||
this.accountId = accountId;
|
||||
this.accountNo = accountNo;
|
||||
this.accountType = AccountTransferEnumerations.accountType(accountType);
|
||||
this.clientId = clientId;
|
||||
this.clientName = clientName;
|
||||
this.officeId = officeId;
|
||||
this.officeName = officeName;
|
||||
}
|
||||
|
||||
public SelfAccountTemplateData(final Long accountId,
|
||||
final Integer accountType, final Long clientId, final Long officeId) {
|
||||
this.accountId = accountId;
|
||||
this.accountNo = null;
|
||||
this.accountType = AccountTransferEnumerations.accountType(accountType);
|
||||
this.clientId = clientId;
|
||||
this.clientName = null;
|
||||
this.officeId = officeId;
|
||||
this.officeName = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(final SelfAccountTemplateData obj) {
|
||||
if (obj == null) {
|
||||
return -1;
|
||||
}
|
||||
return new CompareToBuilder() //
|
||||
.append(this.accountId, obj.accountId) //
|
||||
.append(this.accountType.getValue(), obj.accountType.getValue()) //
|
||||
.append(this.clientId, obj.clientId) //
|
||||
.append(this.officeId, obj.officeId) //
|
||||
.toComparison();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (obj.getClass() != getClass()) {
|
||||
return false;
|
||||
}
|
||||
final SelfAccountTemplateData rhs = (SelfAccountTemplateData) obj;
|
||||
return new EqualsBuilder() //
|
||||
.append(this.accountId, rhs.accountId) //
|
||||
.append(this.accountType.getValue(), rhs.accountType.getValue()) //
|
||||
.append(this.clientId, rhs.clientId) //
|
||||
.append(this.officeId, rhs.officeId) //
|
||||
.isEquals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(17, 37) //
|
||||
.append(this.accountId) //
|
||||
.append(this.accountType.getValue()) //
|
||||
.append(this.clientId) //
|
||||
.append(this.officeId) //
|
||||
.toHashCode();
|
||||
}
|
||||
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.self.account.data;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class SelfAccountTransferData {
|
||||
|
||||
private final Collection<SelfAccountTemplateData> accountOptions;
|
||||
|
||||
public SelfAccountTransferData(
|
||||
final Collection<SelfAccountTemplateData> accountOptions) {
|
||||
this.accountOptions = accountOptions;
|
||||
}
|
||||
|
||||
}
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.self.account.data;
|
||||
|
||||
import static org.mifosplatform.portfolio.account.AccountDetailConstants.fromAccountIdParamName;
|
||||
import static org.mifosplatform.portfolio.account.AccountDetailConstants.fromAccountTypeParamName;
|
||||
import static org.mifosplatform.portfolio.account.AccountDetailConstants.fromClientIdParamName;
|
||||
import static org.mifosplatform.portfolio.account.AccountDetailConstants.fromOfficeIdParamName;
|
||||
import static org.mifosplatform.portfolio.account.AccountDetailConstants.toAccountIdParamName;
|
||||
import static org.mifosplatform.portfolio.account.AccountDetailConstants.toAccountTypeParamName;
|
||||
import static org.mifosplatform.portfolio.account.AccountDetailConstants.toClientIdParamName;
|
||||
import static org.mifosplatform.portfolio.account.AccountDetailConstants.toOfficeIdParamName;
|
||||
import static org.mifosplatform.portfolio.account.api.AccountTransfersApiConstants.ACCOUNT_TRANSFER_RESOURCE_NAME;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.portfolio.self.account.service.SelfAccountTransferReadService;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
@Component
|
||||
public class SelfAccountTransferDataValidator {
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final SelfAccountTransferReadService selfAccountTransferReadService;
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
@Autowired
|
||||
public SelfAccountTransferDataValidator(
|
||||
final PlatformSecurityContext context,
|
||||
final SelfAccountTransferReadService selfAccountTransferReadService,
|
||||
final FromJsonHelper fromApiJsonHelper) {
|
||||
this.context = context;
|
||||
this.selfAccountTransferReadService = selfAccountTransferReadService;
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
}
|
||||
|
||||
public void validateCreate(String apiRequestBodyAsJson) {
|
||||
if (StringUtils.isBlank(apiRequestBodyAsJson)) {
|
||||
throw new InvalidJsonException();
|
||||
}
|
||||
|
||||
JsonElement element = this.fromApiJsonHelper
|
||||
.parse(apiRequestBodyAsJson);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(
|
||||
dataValidationErrors).resource(ACCOUNT_TRANSFER_RESOURCE_NAME);
|
||||
|
||||
final Long fromOfficeId = this.fromApiJsonHelper.extractLongNamed(
|
||||
fromOfficeIdParamName, element);
|
||||
baseDataValidator.reset().parameter(fromOfficeIdParamName)
|
||||
.value(fromOfficeId).notNull().integerGreaterThanZero();
|
||||
|
||||
final Long fromClientId = this.fromApiJsonHelper.extractLongNamed(
|
||||
fromClientIdParamName, element);
|
||||
baseDataValidator.reset().parameter(fromClientIdParamName)
|
||||
.value(fromClientId).notNull().integerGreaterThanZero();
|
||||
|
||||
final Long fromAccountId = this.fromApiJsonHelper.extractLongNamed(
|
||||
fromAccountIdParamName, element);
|
||||
baseDataValidator.reset().parameter(fromAccountIdParamName)
|
||||
.value(fromAccountId).notNull().integerGreaterThanZero();
|
||||
|
||||
final Integer fromAccountType = this.fromApiJsonHelper
|
||||
.extractIntegerSansLocaleNamed(fromAccountTypeParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(fromAccountTypeParamName)
|
||||
.value(fromAccountType).notNull()
|
||||
.isOneOfTheseValues(Integer.valueOf(1), Integer.valueOf(2));
|
||||
|
||||
final Long toOfficeId = this.fromApiJsonHelper.extractLongNamed(
|
||||
toOfficeIdParamName, element);
|
||||
baseDataValidator.reset().parameter(toOfficeIdParamName)
|
||||
.value(toOfficeId).notNull().integerGreaterThanZero();
|
||||
|
||||
final Long toClientId = this.fromApiJsonHelper.extractLongNamed(
|
||||
toClientIdParamName, element);
|
||||
baseDataValidator.reset().parameter(toClientIdParamName)
|
||||
.value(toClientId).notNull().integerGreaterThanZero();
|
||||
|
||||
final Long toAccountId = this.fromApiJsonHelper.extractLongNamed(
|
||||
toAccountIdParamName, element);
|
||||
baseDataValidator.reset().parameter(toAccountIdParamName)
|
||||
.value(toAccountId).notNull().integerGreaterThanZero();
|
||||
|
||||
final Integer toAccountType = this.fromApiJsonHelper
|
||||
.extractIntegerSansLocaleNamed(toAccountTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(toAccountTypeParamName)
|
||||
.value(toAccountType).notNull()
|
||||
.isOneOfTheseValues(Integer.valueOf(1), Integer.valueOf(2));
|
||||
|
||||
if (fromAccountType != null && fromAccountType == 1
|
||||
&& toAccountType != null && toAccountType == 1) {
|
||||
baseDataValidator
|
||||
.reset()
|
||||
.failWithCode("loan.to.loan.transfer.not.allowed",
|
||||
"Cannot transfer from Loan account to another Loan account.");
|
||||
}
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
|
||||
SelfAccountTemplateData fromAccount = new SelfAccountTemplateData(
|
||||
fromAccountId, fromAccountType, fromClientId, fromOfficeId);
|
||||
SelfAccountTemplateData toAccount = new SelfAccountTemplateData(
|
||||
toAccountId, toAccountType, toClientId, toOfficeId);
|
||||
|
||||
validateSelfUserAccounts(fromAccount, toAccount, baseDataValidator);
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
|
||||
}
|
||||
|
||||
private void validateSelfUserAccounts(
|
||||
final SelfAccountTemplateData fromAccount,
|
||||
final SelfAccountTemplateData toAccount,
|
||||
final DataValidatorBuilder baseDataValidator) {
|
||||
AppUser user = this.context.authenticatedUser();
|
||||
Collection<SelfAccountTemplateData> userValidAccounts = this.selfAccountTransferReadService
|
||||
.retrieveSelfAccountTemplateData(user);
|
||||
|
||||
boolean validFromAccount = false;
|
||||
for (SelfAccountTemplateData validAccount : userValidAccounts) {
|
||||
if (validAccount.equals(fromAccount)) {
|
||||
validFromAccount = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
boolean validToAccount = false;
|
||||
for (SelfAccountTemplateData validAccount : userValidAccounts) {
|
||||
if (validAccount.equals(toAccount)) {
|
||||
validToAccount = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!validFromAccount) {
|
||||
baseDataValidator
|
||||
.reset()
|
||||
.failWithCode("invalid.from.account.details",
|
||||
"Source account details doesn't match with valid user account details.");
|
||||
}
|
||||
|
||||
if (!validToAccount) {
|
||||
baseDataValidator
|
||||
.reset()
|
||||
.failWithCode("invalid.to.account.details",
|
||||
"Destination account details doesn't match with valid user account details.");
|
||||
}
|
||||
|
||||
if (fromAccount.equals(toAccount)) {
|
||||
baseDataValidator.reset().failWithCode(
|
||||
"same.from.to.account.details",
|
||||
"Source and Destination account details are same.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(
|
||||
final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.self.account.service;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mifosplatform.portfolio.self.account.data.SelfAccountTemplateData;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
|
||||
public interface SelfAccountTransferReadService {
|
||||
|
||||
Collection<SelfAccountTemplateData> retrieveSelfAccountTemplateData(
|
||||
AppUser user);
|
||||
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.self.account.service;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
||||
import org.mifosplatform.portfolio.self.account.data.SelfAccountTemplateData;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class SelfAccountTransferReadServiceImpl implements
|
||||
SelfAccountTransferReadService {
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
@Autowired
|
||||
public SelfAccountTransferReadServiceImpl(final RoutingDataSource dataSource) {
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SelfAccountTemplateData> retrieveSelfAccountTemplateData(
|
||||
AppUser user) {
|
||||
SelfAccountTemplateMapper mapper = new SelfAccountTemplateMapper();
|
||||
StringBuffer sql = new StringBuffer()
|
||||
.append("select s.id as accountId, ")
|
||||
.append("s.account_no as accountNo, ")
|
||||
.append("2 as accountType, ")
|
||||
.append("c.id as clientId, ")
|
||||
.append("c.display_name as clientName, ")
|
||||
.append("o.id as officeId, ")
|
||||
.append("o.name as officeName ")
|
||||
.append("from m_appuser as u ")
|
||||
.append("inner join m_selfservice_user_client_mapping as map on u.id = map.appuser_id ")
|
||||
.append("inner join m_client as c on map.client_id = c.id ")
|
||||
.append("inner join m_office as o on c.office_id = o.id ")
|
||||
.append("inner join m_savings_account as s on s.client_id = c.id ")
|
||||
.append("where u.id = ? ")
|
||||
.append("and s.status_enum = 300 ")
|
||||
.append("union ")
|
||||
.append("select l.id as accountId, ")
|
||||
.append("l.account_no as accountNo, ")
|
||||
.append("1 as accountType, ")
|
||||
.append("c.id as clientId, ")
|
||||
.append("c.display_name as clientName, ")
|
||||
.append("o.id as officeId, ")
|
||||
.append("o.name as officeName ")
|
||||
.append("from m_appuser as u ")
|
||||
.append("inner join m_selfservice_user_client_mapping as map on u.id = map.appuser_id ")
|
||||
.append("inner join m_client as c on map.client_id = c.id ")
|
||||
.append("inner join m_office as o on c.office_id = o.id ")
|
||||
.append("inner join m_loan as l on l.client_id = c.id ")
|
||||
.append("where u.id = ? ")
|
||||
.append("and l.loan_status_id = 300 ");
|
||||
return this.jdbcTemplate.query(sql.toString(), mapper, new Object[] {
|
||||
user.getId(), user.getId() });
|
||||
}
|
||||
|
||||
private final class SelfAccountTemplateMapper implements
|
||||
RowMapper<SelfAccountTemplateData> {
|
||||
|
||||
@Override
|
||||
public SelfAccountTemplateData mapRow(final ResultSet rs,
|
||||
@SuppressWarnings("unused") final int rowNum)
|
||||
throws SQLException {
|
||||
final Long accountId = rs.getLong("accountId");
|
||||
final String accountNo = rs.getString("accountNo");
|
||||
final Integer accountType = rs.getInt("accountType");
|
||||
final Long clientId = rs.getLong("clientId");
|
||||
final String clientName = rs.getString("clientName");
|
||||
final Long officeId = rs.getLong("officeId");
|
||||
final String officeName = rs.getString("officeName");
|
||||
|
||||
return new SelfAccountTemplateData(accountId, accountNo,
|
||||
accountType, clientId, clientName, officeId, officeName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+208
@@ -0,0 +1,208 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.self.client.api;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DefaultValue;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.mifosplatform.infrastructure.documentmanagement.api.ImagesApiResource;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.portfolio.client.api.ClientApiConstants;
|
||||
import org.mifosplatform.portfolio.client.api.ClientChargesApiResource;
|
||||
import org.mifosplatform.portfolio.client.api.ClientTransactionsApiResource;
|
||||
import org.mifosplatform.portfolio.client.api.ClientsApiResource;
|
||||
import org.mifosplatform.portfolio.client.exception.ClientNotFoundException;
|
||||
import org.mifosplatform.portfolio.self.client.data.SelfClientDataValidator;
|
||||
import org.mifosplatform.portfolio.self.client.service.AppuserClientMapperReadService;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Path("/self/clients")
|
||||
@Component
|
||||
@Scope("singleton")
|
||||
public class SelfClientsApiResource {
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final ClientsApiResource clientApiResource;
|
||||
private final ImagesApiResource imagesApiResource;
|
||||
private final ClientChargesApiResource clientChargesApiResource;
|
||||
private final ClientTransactionsApiResource clientTransactionsApiResource;
|
||||
private final AppuserClientMapperReadService appUserClientMapperReadService;
|
||||
private final SelfClientDataValidator dataValidator;
|
||||
|
||||
@Autowired
|
||||
public SelfClientsApiResource(
|
||||
final PlatformSecurityContext context,
|
||||
final ClientsApiResource clientApiResource,
|
||||
final ImagesApiResource imagesApiResource,
|
||||
final ClientChargesApiResource clientChargesApiResource,
|
||||
final ClientTransactionsApiResource clientTransactionsApiResource,
|
||||
final AppuserClientMapperReadService appUserClientMapperReadService,
|
||||
final SelfClientDataValidator dataValidator) {
|
||||
this.context = context;
|
||||
this.clientApiResource = clientApiResource;
|
||||
this.imagesApiResource = imagesApiResource;
|
||||
this.clientChargesApiResource = clientChargesApiResource;
|
||||
this.clientTransactionsApiResource = clientTransactionsApiResource;
|
||||
this.appUserClientMapperReadService = appUserClientMapperReadService;
|
||||
this.dataValidator = dataValidator;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveAll(@Context final UriInfo uriInfo,
|
||||
@QueryParam("displayName") final String displayName,
|
||||
@QueryParam("firstName") final String firstname,
|
||||
@QueryParam("lastName") final String lastname,
|
||||
@QueryParam("offset") final Integer offset,
|
||||
@QueryParam("limit") final Integer limit,
|
||||
@QueryParam("orderBy") final String orderBy,
|
||||
@QueryParam("sortOrder") final String sortOrder) {
|
||||
|
||||
final String sqlSearch = null;
|
||||
final Long officeId = null;
|
||||
final String externalId = null;
|
||||
final String hierarchy = null;
|
||||
final Boolean orphansOnly = null;
|
||||
return this.clientApiResource.retrieveAll(uriInfo, sqlSearch, officeId,
|
||||
externalId, displayName, firstname, lastname, hierarchy,
|
||||
offset, limit, orderBy, sortOrder, orphansOnly, true);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{clientId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveOne(@PathParam("clientId") final Long clientId,
|
||||
@Context final UriInfo uriInfo) {
|
||||
|
||||
this.dataValidator.validateRetrieveOne(uriInfo);
|
||||
|
||||
validateAppuserClientsMapping(clientId);
|
||||
|
||||
final boolean staffInSelectedOfficeOnly = false;
|
||||
return this.clientApiResource.retrieveOne(clientId, uriInfo,
|
||||
staffInSelectedOfficeOnly);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{clientId}/accounts")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveAssociatedAccounts(
|
||||
@PathParam("clientId") final Long clientId,
|
||||
@Context final UriInfo uriInfo) {
|
||||
|
||||
validateAppuserClientsMapping(clientId);
|
||||
|
||||
return this.clientApiResource.retrieveAssociatedAccounts(clientId,
|
||||
uriInfo);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{clientId}/images")
|
||||
@Consumes({ MediaType.TEXT_PLAIN, MediaType.TEXT_HTML,
|
||||
MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.TEXT_PLAIN })
|
||||
public Response retrieveImage(@PathParam("clientId") final Long clientId,
|
||||
@QueryParam("maxWidth") final Integer maxWidth,
|
||||
@QueryParam("maxHeight") final Integer maxHeight,
|
||||
@QueryParam("output") final String output) {
|
||||
|
||||
validateAppuserClientsMapping(clientId);
|
||||
|
||||
return this.imagesApiResource.retrieveImage("clients", clientId,
|
||||
maxWidth, maxHeight, output);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{clientId}/charges")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveAllClientCharges(
|
||||
@PathParam("clientId") final Long clientId,
|
||||
@DefaultValue(ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_ALL) @QueryParam(ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS) final String chargeStatus,
|
||||
@QueryParam("pendingPayment") final Boolean pendingPayment,
|
||||
@Context final UriInfo uriInfo,
|
||||
@QueryParam("limit") final Integer limit,
|
||||
@QueryParam("offset") final Integer offset) {
|
||||
|
||||
validateAppuserClientsMapping(clientId);
|
||||
|
||||
return this.clientChargesApiResource.retrieveAllClientCharges(clientId,
|
||||
chargeStatus, pendingPayment, uriInfo, limit, offset);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{clientId}/charges/{chargeId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveClientCharge(
|
||||
@PathParam("clientId") final Long clientId,
|
||||
@PathParam("chargeId") final Long chargeId,
|
||||
@Context final UriInfo uriInfo) {
|
||||
|
||||
this.dataValidator.validateClientCharges(uriInfo);
|
||||
|
||||
validateAppuserClientsMapping(clientId);
|
||||
|
||||
return this.clientChargesApiResource.retrieveClientCharge(clientId,
|
||||
chargeId, uriInfo);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{clientId}/transactions")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveAllClientTransactions(
|
||||
@PathParam("clientId") final Long clientId,
|
||||
@Context final UriInfo uriInfo,
|
||||
@QueryParam("offset") final Integer offset,
|
||||
@QueryParam("limit") final Integer limit) {
|
||||
|
||||
validateAppuserClientsMapping(clientId);
|
||||
|
||||
return this.clientTransactionsApiResource
|
||||
.retrieveAllClientTransactions(clientId, uriInfo, offset, limit);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{clientId}/transactions/{transactionId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveClientTransaction(
|
||||
@PathParam("clientId") final Long clientId,
|
||||
@PathParam("transactionId") final Long transactionId,
|
||||
@Context final UriInfo uriInfo) {
|
||||
|
||||
validateAppuserClientsMapping(clientId);
|
||||
|
||||
return this.clientTransactionsApiResource.retrieveClientTransaction(
|
||||
clientId, transactionId, uriInfo);
|
||||
}
|
||||
|
||||
private void validateAppuserClientsMapping(final Long clientId) {
|
||||
AppUser user = this.context.authenticatedUser();
|
||||
final boolean mappedClientId = this.appUserClientMapperReadService
|
||||
.isClientMappedToUser(clientId, user.getId());
|
||||
if (!mappedClientId) {
|
||||
throw new ClientNotFoundException(clientId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.self.client.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.api.ApiParameterHelper;
|
||||
import org.mifosplatform.infrastructure.core.exception.UnsupportedParameterException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class SelfClientDataValidator {
|
||||
|
||||
private static final Set<String> allowedChargesAssociationParameters = new HashSet<>(
|
||||
Arrays.asList("transactions"));
|
||||
|
||||
public void validateClientCharges(final UriInfo uriInfo) {
|
||||
List<String> unsupportedParams = new ArrayList<>();
|
||||
|
||||
Set<String> associationParameters = ApiParameterHelper
|
||||
.extractAssociationsForResponseIfProvided(uriInfo
|
||||
.getQueryParameters());
|
||||
if (!associationParameters.isEmpty()) {
|
||||
associationParameters
|
||||
.removeAll(allowedChargesAssociationParameters);
|
||||
if (!associationParameters.isEmpty()) {
|
||||
unsupportedParams.addAll(associationParameters);
|
||||
}
|
||||
}
|
||||
|
||||
if (uriInfo.getQueryParameters().getFirst("exclude") != null) {
|
||||
unsupportedParams.add("exclude");
|
||||
}
|
||||
|
||||
if (unsupportedParams.size() > 0) {
|
||||
throw new UnsupportedParameterException(unsupportedParams);
|
||||
}
|
||||
}
|
||||
|
||||
public void validateRetrieveOne(final UriInfo uriInfo) {
|
||||
List<String> unsupportedParams = new ArrayList<>();
|
||||
|
||||
final boolean templateRequest = ApiParameterHelper.template(uriInfo
|
||||
.getQueryParameters());
|
||||
if (templateRequest) {
|
||||
unsupportedParams.add("template");
|
||||
}
|
||||
|
||||
if (unsupportedParams.size() > 0) {
|
||||
throw new UnsupportedParameterException(unsupportedParams);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.self.client.service;
|
||||
|
||||
public interface AppuserClientMapperReadService {
|
||||
|
||||
public Boolean isClientMappedToUser(Long clientId, Long appUserId);
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.self.client.service;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class AppuserClientMapperReadServiceImpl implements
|
||||
AppuserClientMapperReadService {
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
@Autowired
|
||||
public AppuserClientMapperReadServiceImpl(final RoutingDataSource dataSource) {
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isClientMappedToUser(Long clientId, Long appUserId) {
|
||||
return this.jdbcTemplate
|
||||
.queryForObject(
|
||||
"select case when (count(*) > 0) then true else false end "
|
||||
+ " from m_selfservice_user_client_mapping where client_id = ? and appuser_id = ?",
|
||||
new Object[] { clientId, appUserId }, Boolean.class);
|
||||
}
|
||||
|
||||
}
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.self.loanaccount.api;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.portfolio.loanaccount.api.LoanChargesApiResource;
|
||||
import org.mifosplatform.portfolio.loanaccount.api.LoanTransactionsApiResource;
|
||||
import org.mifosplatform.portfolio.loanaccount.api.LoansApiResource;
|
||||
import org.mifosplatform.portfolio.loanaccount.exception.LoanNotFoundException;
|
||||
import org.mifosplatform.portfolio.self.loanaccount.data.SelfLoansDataValidator;
|
||||
import org.mifosplatform.portfolio.self.loanaccount.service.AppuserLoansMapperReadService;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Path("/self/loans")
|
||||
@Component
|
||||
@Scope("singleton")
|
||||
public class SelfLoansApiResource {
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final LoansApiResource loansApiResource;
|
||||
private final LoanTransactionsApiResource loanTransactionsApiResource;
|
||||
private final LoanChargesApiResource loanChargesApiResource;
|
||||
private final AppuserLoansMapperReadService appuserLoansMapperReadService;
|
||||
private final SelfLoansDataValidator dataValidator;
|
||||
|
||||
@Autowired
|
||||
public SelfLoansApiResource(final PlatformSecurityContext context,
|
||||
final LoansApiResource loansApiResource,
|
||||
final LoanTransactionsApiResource loanTransactionsApiResource,
|
||||
final LoanChargesApiResource loanChargesApiResource,
|
||||
final AppuserLoansMapperReadService appuserLoansMapperReadService,
|
||||
final SelfLoansDataValidator dataValidator) {
|
||||
this.context = context;
|
||||
this.loansApiResource = loansApiResource;
|
||||
this.loanTransactionsApiResource = loanTransactionsApiResource;
|
||||
this.loanChargesApiResource = loanChargesApiResource;
|
||||
this.appuserLoansMapperReadService = appuserLoansMapperReadService;
|
||||
this.dataValidator = dataValidator;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{loanId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveLoan(@PathParam("loanId") final Long loanId,
|
||||
@Context final UriInfo uriInfo) {
|
||||
|
||||
this.dataValidator.validateRetrieveLoan(uriInfo);
|
||||
|
||||
validateAppuserLoanMapping(loanId);
|
||||
|
||||
final boolean staffInSelectedOfficeOnly = false;
|
||||
return this.loansApiResource.retrieveLoan(loanId,
|
||||
staffInSelectedOfficeOnly, uriInfo);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{loanId}/transactions/{transactionId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveTransaction(@PathParam("loanId") final Long loanId,
|
||||
@PathParam("transactionId") final Long transactionId,
|
||||
@Context final UriInfo uriInfo) {
|
||||
|
||||
this.dataValidator.validateRetrieveTransaction(uriInfo);
|
||||
|
||||
validateAppuserLoanMapping(loanId);
|
||||
|
||||
return this.loanTransactionsApiResource.retrieveTransaction(loanId,
|
||||
transactionId, uriInfo);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{loanId}/charges")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveAllLoanCharges(
|
||||
@PathParam("loanId") final Long loanId,
|
||||
@Context final UriInfo uriInfo) {
|
||||
|
||||
validateAppuserLoanMapping(loanId);
|
||||
|
||||
return this.loanChargesApiResource.retrieveAllLoanCharges(loanId,
|
||||
uriInfo);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{loanId}/charges/{chargeId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveLoanCharge(@PathParam("loanId") final Long loanId,
|
||||
@PathParam("chargeId") final Long loanChargeId,
|
||||
@Context final UriInfo uriInfo) {
|
||||
|
||||
validateAppuserLoanMapping(loanId);
|
||||
|
||||
return this.retrieveLoanCharge(loanId, loanChargeId, uriInfo);
|
||||
}
|
||||
|
||||
private void validateAppuserLoanMapping(final Long loanId) {
|
||||
AppUser user = this.context.authenticatedUser();
|
||||
final boolean isLoanMappedToUser = this.appuserLoansMapperReadService
|
||||
.isLoanMappedToUser(loanId, user.getId());
|
||||
if (!isLoanMappedToUser) {
|
||||
throw new LoanNotFoundException(loanId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.self.loanaccount.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.api.ApiParameterHelper;
|
||||
import org.mifosplatform.infrastructure.core.exception.UnsupportedParameterException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class SelfLoansDataValidator {
|
||||
private static final Set<String> allowedAssociationParameters = new HashSet<>(
|
||||
Arrays.asList("repaymentSchedule", "futureSchedule",
|
||||
"originalSchedule", "transactions", "charges",
|
||||
"guarantors", "collateral", "linkedAccount",
|
||||
"multiDisburseDetails"));
|
||||
|
||||
public void validateRetrieveLoan(final UriInfo uriInfo) {
|
||||
List<String> unsupportedParams = new ArrayList<>();
|
||||
|
||||
validateTemplate(uriInfo, unsupportedParams);
|
||||
|
||||
Set<String> associationParameters = ApiParameterHelper
|
||||
.extractAssociationsForResponseIfProvided(uriInfo
|
||||
.getQueryParameters());
|
||||
if (!associationParameters.isEmpty()) {
|
||||
associationParameters.removeAll(allowedAssociationParameters);
|
||||
if (!associationParameters.isEmpty()) {
|
||||
unsupportedParams.addAll(associationParameters);
|
||||
}
|
||||
}
|
||||
|
||||
if (uriInfo.getQueryParameters().getFirst("exclude") != null) {
|
||||
unsupportedParams.add("exclude");
|
||||
}
|
||||
|
||||
throwExceptionIfReqd(unsupportedParams);
|
||||
}
|
||||
|
||||
public void validateRetrieveTransaction(UriInfo uriInfo) {
|
||||
List<String> unsupportedParams = new ArrayList<>();
|
||||
|
||||
validateTemplate(uriInfo, unsupportedParams);
|
||||
|
||||
throwExceptionIfReqd(unsupportedParams);
|
||||
|
||||
}
|
||||
|
||||
private void throwExceptionIfReqd(List<String> unsupportedParams) {
|
||||
if (unsupportedParams.size() > 0) {
|
||||
throw new UnsupportedParameterException(unsupportedParams);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateTemplate(final UriInfo uriInfo,
|
||||
List<String> unsupportedParams) {
|
||||
final boolean templateRequest = ApiParameterHelper.template(uriInfo
|
||||
.getQueryParameters());
|
||||
if (templateRequest) {
|
||||
unsupportedParams.add("template");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.self.loanaccount.service;
|
||||
|
||||
public interface AppuserLoansMapperReadService {
|
||||
|
||||
public Boolean isLoanMappedToUser(Long loanId, Long appUserId);
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.self.loanaccount.service;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class AppuserLoansMapperReadServiceImpl implements
|
||||
AppuserLoansMapperReadService {
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
@Autowired
|
||||
public AppuserLoansMapperReadServiceImpl(final RoutingDataSource dataSource) {
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isLoanMappedToUser(Long loanId, Long appUserId) {
|
||||
return this.jdbcTemplate
|
||||
.queryForObject(
|
||||
"select case when (count(*) > 0) then true else false end "
|
||||
+ " from m_selfservice_user_client_mapping as m "
|
||||
+ " left join m_loan as l on l.client_id = m.client_id "
|
||||
+ " where l.id = ? and m.appuser_id = ? ",
|
||||
new Object[] { loanId, appUserId }, Boolean.class);
|
||||
}
|
||||
|
||||
}
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.self.savings.api;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DefaultValue;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.portfolio.savings.api.SavingsAccountChargesApiResource;
|
||||
import org.mifosplatform.portfolio.savings.api.SavingsAccountTransactionsApiResource;
|
||||
import org.mifosplatform.portfolio.savings.api.SavingsAccountsApiResource;
|
||||
import org.mifosplatform.portfolio.savings.exception.SavingsAccountNotFoundException;
|
||||
import org.mifosplatform.portfolio.self.savings.data.SelfSavingsDataValidator;
|
||||
import org.mifosplatform.portfolio.self.savings.service.AppuserSavingsMapperReadService;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Path("/self/savingsaccounts")
|
||||
@Component
|
||||
@Scope("singleton")
|
||||
public class SelfSavingsApiResource {
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final SavingsAccountsApiResource savingsAccountsApiResource;
|
||||
private final SavingsAccountChargesApiResource savingsAccountChargesApiResource;
|
||||
private final SavingsAccountTransactionsApiResource savingsAccountTransactionsApiResource;
|
||||
private final AppuserSavingsMapperReadService appuserSavingsMapperReadService;
|
||||
private final SelfSavingsDataValidator dataValidator;
|
||||
|
||||
@Autowired
|
||||
public SelfSavingsApiResource(
|
||||
final PlatformSecurityContext context,
|
||||
final SavingsAccountsApiResource savingsAccountsApiResource,
|
||||
final SavingsAccountChargesApiResource savingsAccountChargesApiResource,
|
||||
final SavingsAccountTransactionsApiResource savingsAccountTransactionsApiResource,
|
||||
final AppuserSavingsMapperReadService appuserSavingsMapperReadService,
|
||||
final SelfSavingsDataValidator dataValidator) {
|
||||
this.context = context;
|
||||
this.savingsAccountsApiResource = savingsAccountsApiResource;
|
||||
this.savingsAccountChargesApiResource = savingsAccountChargesApiResource;
|
||||
this.savingsAccountTransactionsApiResource = savingsAccountTransactionsApiResource;
|
||||
this.appuserSavingsMapperReadService = appuserSavingsMapperReadService;
|
||||
this.dataValidator = dataValidator;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{accountId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveSavings(
|
||||
@PathParam("accountId") final Long accountId,
|
||||
@DefaultValue("all") @QueryParam("chargeStatus") final String chargeStatus,
|
||||
@Context final UriInfo uriInfo) {
|
||||
|
||||
this.dataValidator.validateRetrieveSavings(uriInfo);
|
||||
|
||||
validateAppuserSavingsAccountMapping(accountId);
|
||||
|
||||
final boolean staffInSelectedOfficeOnly = false;
|
||||
return this.savingsAccountsApiResource.retrieveOne(accountId,
|
||||
staffInSelectedOfficeOnly, chargeStatus, uriInfo);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{accountId}/transactions/{transactionId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveSavingsTransaction(
|
||||
@PathParam("savingsId") final Long accountId,
|
||||
@PathParam("transactionId") final Long transactionId,
|
||||
@Context final UriInfo uriInfo) {
|
||||
|
||||
this.dataValidator.validateRetrieveSavingsTransaction(uriInfo);
|
||||
|
||||
validateAppuserSavingsAccountMapping(accountId);
|
||||
|
||||
return this.savingsAccountTransactionsApiResource.retrieveOne(
|
||||
accountId, transactionId, uriInfo);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{accountId}/charges")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveAllSavingsAccountCharges(
|
||||
@PathParam("savingsAccountId") final Long accountId,
|
||||
@DefaultValue("all") @QueryParam("chargeStatus") final String chargeStatus,
|
||||
@Context final UriInfo uriInfo) {
|
||||
|
||||
validateAppuserSavingsAccountMapping(accountId);
|
||||
|
||||
return this.savingsAccountChargesApiResource
|
||||
.retrieveAllSavingsAccountCharges(accountId, chargeStatus,
|
||||
uriInfo);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{accountId}/charges/{savingsAccountChargeId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveSavingsAccountCharge(
|
||||
@PathParam("savingsAccountId") final Long accountId,
|
||||
@PathParam("savingsAccountChargeId") final Long savingsAccountChargeId,
|
||||
@Context final UriInfo uriInfo) {
|
||||
|
||||
validateAppuserSavingsAccountMapping(accountId);
|
||||
|
||||
return this.savingsAccountChargesApiResource
|
||||
.retrieveSavingsAccountCharge(accountId,
|
||||
savingsAccountChargeId, uriInfo);
|
||||
}
|
||||
|
||||
private void validateAppuserSavingsAccountMapping(final Long accountId) {
|
||||
AppUser user = this.context.authenticatedUser();
|
||||
final boolean isMappedSavings = this.appuserSavingsMapperReadService
|
||||
.isSavingsMappedToUser(accountId, user.getId());
|
||||
if (!isMappedSavings) {
|
||||
throw new SavingsAccountNotFoundException(accountId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.self.savings.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.api.ApiParameterHelper;
|
||||
import org.mifosplatform.infrastructure.core.exception.UnsupportedParameterException;
|
||||
import org.mifosplatform.portfolio.savings.SavingsApiConstants;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class SelfSavingsDataValidator {
|
||||
|
||||
private static final Set<String> allowedAssociationParameters = new HashSet<>(
|
||||
Arrays.asList(SavingsApiConstants.transactions,
|
||||
SavingsApiConstants.charges));
|
||||
|
||||
public void validateRetrieveSavings(final UriInfo uriInfo) {
|
||||
List<String> unsupportedParams = new ArrayList<>();
|
||||
|
||||
validateTemplate(uriInfo, unsupportedParams);
|
||||
|
||||
Set<String> associationParameters = ApiParameterHelper
|
||||
.extractAssociationsForResponseIfProvided(uriInfo
|
||||
.getQueryParameters());
|
||||
if (!associationParameters.isEmpty()) {
|
||||
associationParameters.removeAll(allowedAssociationParameters);
|
||||
if (!associationParameters.isEmpty()) {
|
||||
unsupportedParams.addAll(associationParameters);
|
||||
}
|
||||
}
|
||||
|
||||
if (uriInfo.getQueryParameters().getFirst("exclude") != null) {
|
||||
unsupportedParams.add("exclude");
|
||||
}
|
||||
|
||||
throwExceptionIfReqd(unsupportedParams);
|
||||
}
|
||||
|
||||
public void validateRetrieveSavingsTransaction(final UriInfo uriInfo) {
|
||||
List<String> unsupportedParams = new ArrayList<>();
|
||||
|
||||
validateTemplate(uriInfo, unsupportedParams);
|
||||
|
||||
throwExceptionIfReqd(unsupportedParams);
|
||||
}
|
||||
|
||||
private void throwExceptionIfReqd(final List<String> unsupportedParams) {
|
||||
if (unsupportedParams.size() > 0) {
|
||||
throw new UnsupportedParameterException(unsupportedParams);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateTemplate(final UriInfo uriInfo,
|
||||
List<String> unsupportedParams) {
|
||||
final boolean templateRequest = ApiParameterHelper.template(uriInfo
|
||||
.getQueryParameters());
|
||||
if (templateRequest) {
|
||||
unsupportedParams.add("template");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.self.savings.service;
|
||||
|
||||
public interface AppuserSavingsMapperReadService {
|
||||
|
||||
public Boolean isSavingsMappedToUser(Long savingsId, Long appUserId);
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.self.savings.service;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class AppuserSavingsMapperReadServiceImpl implements
|
||||
AppuserSavingsMapperReadService {
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
@Autowired
|
||||
public AppuserSavingsMapperReadServiceImpl(
|
||||
final RoutingDataSource dataSource) {
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isSavingsMappedToUser(Long savingsId, Long appUserId) {
|
||||
return this.jdbcTemplate
|
||||
.queryForObject(
|
||||
"select case when (count(*) > 0) then true else false end "
|
||||
+ " from m_selfservice_user_client_mapping as m "
|
||||
+ " left join m_savings_account as s on s.client_id = m.client_id "
|
||||
+ " where s.id = ? and m.appuser_id = ? ",
|
||||
new Object[] { savingsId, appUserId }, Boolean.class);
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.self.security.api;
|
||||
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.mifosplatform.infrastructure.security.api.AuthenticationApiResource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Path("/self/authentication")
|
||||
@Component
|
||||
@Profile("basicauth")
|
||||
@Scope("singleton")
|
||||
public class SelfAuthenticationApiResource {
|
||||
|
||||
private final AuthenticationApiResource authenticationApiResource;
|
||||
|
||||
@Autowired
|
||||
public SelfAuthenticationApiResource(
|
||||
final AuthenticationApiResource authenticationApiResource) {
|
||||
this.authenticationApiResource = authenticationApiResource;
|
||||
}
|
||||
|
||||
@POST
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String authenticate(@QueryParam("username") final String username,
|
||||
@QueryParam("password") final String password) {
|
||||
return this.authenticationApiResource.authenticate(username, password);
|
||||
}
|
||||
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.self.security.api;
|
||||
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.mifosplatform.infrastructure.security.api.UserDetailsApiResource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Path("/self/userdetails")
|
||||
@Component
|
||||
@Profile("oauth")
|
||||
@Scope("singleton")
|
||||
public class SelfUserDetailsApiResource {
|
||||
|
||||
private final UserDetailsApiResource userDetailsApiResource;
|
||||
|
||||
@Autowired
|
||||
public SelfUserDetailsApiResource(
|
||||
final UserDetailsApiResource userDetailsApiResource) {
|
||||
this.userDetailsApiResource = userDetailsApiResource;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String fetchAuthenticatedUserData(
|
||||
@QueryParam("access_token") final String accessToken) {
|
||||
return this.userDetailsApiResource
|
||||
.fetchAuthenticatedUserData(accessToken);
|
||||
}
|
||||
}
|
||||
+22
-6
@@ -6,9 +6,11 @@
|
||||
package org.mifosplatform.useradministration.data;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mifosplatform.organisation.office.data.OfficeData;
|
||||
import org.mifosplatform.organisation.staff.data.StaffData;
|
||||
import org.mifosplatform.portfolio.client.data.ClientData;
|
||||
|
||||
/**
|
||||
* Immutable data object for application user data.
|
||||
@@ -29,31 +31,35 @@ public class AppUserData {
|
||||
private final Collection<RoleData> availableRoles;
|
||||
private final Collection<RoleData> selectedRoles;
|
||||
private final StaffData staff;
|
||||
private final Boolean isSelfServiceUser;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private Set<ClientData> clients;
|
||||
|
||||
public static AppUserData template(final AppUserData user, final Collection<OfficeData> officesForDropdown) {
|
||||
return new AppUserData(user.id, user.username, user.email, user.officeId, user.officeName, user.firstname, user.lastname,
|
||||
user.availableRoles, user.selectedRoles, officesForDropdown, user.staff, user.passwordNeverExpires);
|
||||
user.availableRoles, user.selectedRoles, officesForDropdown, user.staff, user.passwordNeverExpires, user.isSelfServiceUser);
|
||||
}
|
||||
|
||||
public static AppUserData template(final Collection<OfficeData> offices, final Collection<RoleData> availableRoles) {
|
||||
return new AppUserData(null, null, null, null, null, null, null, availableRoles, null, offices, null, null);
|
||||
return new AppUserData(null, null, null, null, null, null, null, availableRoles, null, offices, null, null, null);
|
||||
}
|
||||
|
||||
public static AppUserData dropdown(final Long id, final String username) {
|
||||
return new AppUserData(id, username, null, null, null, null, null, null, null, null, null, null);
|
||||
return new AppUserData(id, username, null, null, null, null, null, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
public static AppUserData instance(final Long id, final String username, final String email, final Long officeId,
|
||||
final String officeName, final String firstname, final String lastname, final Collection<RoleData> availableRoles,
|
||||
final Collection<RoleData> selectedRoles, final StaffData staff, final Boolean passwordNeverExpire) {
|
||||
final Collection<RoleData> selectedRoles, final StaffData staff, final Boolean passwordNeverExpire, final Boolean isSelfServiceUser) {
|
||||
return new AppUserData(id, username, email, officeId, officeName, firstname, lastname, availableRoles, selectedRoles, null, staff,
|
||||
passwordNeverExpire);
|
||||
passwordNeverExpire, isSelfServiceUser);
|
||||
}
|
||||
|
||||
private AppUserData(final Long id, final String username, final String email, final Long officeId, final String officeName,
|
||||
final String firstname, final String lastname, final Collection<RoleData> availableRoles,
|
||||
final Collection<RoleData> selectedRoles, final Collection<OfficeData> allowedOffices, final StaffData staff,
|
||||
final Boolean passwordNeverExpire) {
|
||||
final Boolean passwordNeverExpire, final Boolean isSelfServiceUser) {
|
||||
this.id = id;
|
||||
this.username = username;
|
||||
this.officeId = officeId;
|
||||
@@ -66,6 +72,7 @@ public class AppUserData {
|
||||
this.selectedRoles = selectedRoles;
|
||||
this.staff = staff;
|
||||
this.passwordNeverExpires = passwordNeverExpire;
|
||||
this.isSelfServiceUser = isSelfServiceUser;
|
||||
}
|
||||
|
||||
public boolean hasIdentifyOf(final Long createdById) {
|
||||
@@ -92,4 +99,13 @@ public class AppUserData {
|
||||
public int hashCode() {
|
||||
return id != null ? id.hashCode() : 0;
|
||||
}
|
||||
|
||||
public void setClients(Set<ClientData> clients){
|
||||
this.clients = clients;
|
||||
}
|
||||
|
||||
public boolean isSelfServiceUser() {
|
||||
return this.isSelfServiceUser==null?false:this.isSelfServiceUser;
|
||||
}
|
||||
|
||||
}
|
||||
+69
-4
@@ -14,6 +14,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
@@ -21,11 +22,14 @@ import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
import org.hibernate.annotations.LazyCollection;
|
||||
import org.hibernate.annotations.LazyCollectionOption;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
@@ -35,6 +39,7 @@ import org.mifosplatform.infrastructure.security.service.PlatformPasswordEncoder
|
||||
import org.mifosplatform.infrastructure.security.service.RandomPasswordGenerator;
|
||||
import org.mifosplatform.organisation.office.domain.Office;
|
||||
import org.mifosplatform.organisation.staff.domain.Staff;
|
||||
import org.mifosplatform.portfolio.client.domain.Client;
|
||||
import org.mifosplatform.useradministration.service.AppUserConstants;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -101,7 +106,16 @@ public class AppUser extends AbstractPersistable<Long> implements PlatformUser {
|
||||
@Column(name = "password_never_expires", nullable = false)
|
||||
private boolean passwordNeverExpires;
|
||||
|
||||
public static AppUser fromJson(final Office userOffice, final Staff linkedStaff, final Set<Role> allRoles, final JsonCommand command) {
|
||||
@Column(name = "is_self_service_user", nullable = false)
|
||||
private boolean isSelfServiceUser;
|
||||
|
||||
@LazyCollection(LazyCollectionOption.FALSE)
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
@JoinColumn(name = "appuser_id", referencedColumnName= "id", nullable = false)
|
||||
private Set<AppUserClientMapping> appUserClientMappings = new HashSet<>();
|
||||
|
||||
public static AppUser fromJson(final Office userOffice, final Staff linkedStaff, final Set<Role> allRoles,
|
||||
final Collection<Client> clients, final JsonCommand command) {
|
||||
|
||||
final String username = command.stringValueOfParameterNamed("username");
|
||||
String password = command.stringValueOfParameterNamed("password");
|
||||
@@ -131,8 +145,11 @@ public class AppUser extends AbstractPersistable<Long> implements PlatformUser {
|
||||
final String email = command.stringValueOfParameterNamed("email");
|
||||
final String firstname = command.stringValueOfParameterNamed("firstname");
|
||||
final String lastname = command.stringValueOfParameterNamed("lastname");
|
||||
|
||||
final boolean isSelfServiceUser = command.booleanPrimitiveValueOfParameterNamed(AppUserConstants.IS_SELF_SERVICE_USER);
|
||||
|
||||
return new AppUser(userOffice, user, allRoles, email, firstname, lastname, linkedStaff, passwordNeverExpire);
|
||||
return new AppUser(userOffice, user, allRoles, email, firstname, lastname, linkedStaff, passwordNeverExpire,
|
||||
isSelfServiceUser, clients);
|
||||
}
|
||||
|
||||
protected AppUser() {
|
||||
@@ -142,7 +159,8 @@ public class AppUser extends AbstractPersistable<Long> implements PlatformUser {
|
||||
}
|
||||
|
||||
public AppUser(final Office office, final User user, final Set<Role> roles, final String email, final String firstname,
|
||||
final String lastname, final Staff staff, final boolean passwordNeverExpire) {
|
||||
final String lastname, final Staff staff, final boolean passwordNeverExpire,
|
||||
final boolean isSelfServiceUser, final Collection<Client> clients) {
|
||||
this.office = office;
|
||||
this.email = email.trim();
|
||||
this.username = user.getUsername().trim();
|
||||
@@ -158,6 +176,8 @@ public class AppUser extends AbstractPersistable<Long> implements PlatformUser {
|
||||
this.lastTimePasswordUpdated = DateUtils.getDateOfTenant();
|
||||
this.staff = staff;
|
||||
this.passwordNeverExpires = passwordNeverExpire;
|
||||
this.isSelfServiceUser = isSelfServiceUser;
|
||||
this.appUserClientMappings = createAppUserClientMappings(clients);
|
||||
}
|
||||
|
||||
public EnumOptionData organisationalRoleData() {
|
||||
@@ -190,7 +210,8 @@ public class AppUser extends AbstractPersistable<Long> implements PlatformUser {
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Object> update(final JsonCommand command, final PlatformPasswordEncoder platformPasswordEncoder) {
|
||||
public Map<String, Object> update(final JsonCommand command, final PlatformPasswordEncoder platformPasswordEncoder,
|
||||
final Collection<Client> clients) {
|
||||
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<>(7);
|
||||
|
||||
@@ -270,6 +291,30 @@ public class AppUser extends AbstractPersistable<Long> implements PlatformUser {
|
||||
this.passwordNeverExpires = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
if(command.hasParameter(AppUserConstants.IS_SELF_SERVICE_USER)){
|
||||
if (command.isChangeInBooleanParameterNamed(AppUserConstants.IS_SELF_SERVICE_USER, this.isSelfServiceUser)){
|
||||
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(AppUserConstants.IS_SELF_SERVICE_USER);
|
||||
actualChanges.put(AppUserConstants.IS_SELF_SERVICE_USER, newValue);
|
||||
this.isSelfServiceUser = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
if(this.isSelfServiceUser && command.hasParameter(AppUserConstants.CLIENTS)){
|
||||
actualChanges.put(AppUserConstants.CLIENTS, command.arrayValueOfParameterNamed(AppUserConstants.CLIENTS));
|
||||
Set<AppUserClientMapping> newClients = createAppUserClientMappings(clients);
|
||||
if(this.appUserClientMappings == null){
|
||||
this.appUserClientMappings = new HashSet<>();
|
||||
}else{
|
||||
this.appUserClientMappings.retainAll(newClients);
|
||||
}
|
||||
this.appUserClientMappings.addAll(newClients);
|
||||
}else if(!this.isSelfServiceUser && actualChanges.containsKey(AppUserConstants.IS_SELF_SERVICE_USER)){
|
||||
actualChanges.put(AppUserConstants.CLIENTS, new ArrayList<>());
|
||||
if(this.appUserClientMappings != null){
|
||||
this.appUserClientMappings = null;
|
||||
}
|
||||
}
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
@@ -573,4 +618,24 @@ public class AppUser extends AbstractPersistable<Long> implements PlatformUser {
|
||||
public boolean isNotEnabled() {
|
||||
return !isEnabled();
|
||||
}
|
||||
|
||||
public boolean isSelfServiceUser() {
|
||||
return this.isSelfServiceUser;
|
||||
}
|
||||
|
||||
public Set<AppUserClientMapping> getAppUserClientMappings() {
|
||||
return this.appUserClientMappings;
|
||||
}
|
||||
|
||||
private Set<AppUserClientMapping> createAppUserClientMappings(Collection<Client> clients) {
|
||||
Set<AppUserClientMapping> newAppUserClientMappings = null;
|
||||
if(clients != null && clients.size() > 0){
|
||||
newAppUserClientMappings = new HashSet<>();
|
||||
for(Client client : clients){
|
||||
newAppUserClientMappings.add(new AppUserClientMapping(client));
|
||||
}
|
||||
}
|
||||
return newAppUserClientMappings;
|
||||
}
|
||||
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.useradministration.domain;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.mifosplatform.portfolio.client.domain.Client;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_selfservice_user_client_mapping")
|
||||
public class AppUserClientMapping extends AbstractPersistable<Long> {
|
||||
|
||||
@ManyToOne(optional = false, cascade = CascadeType.PERSIST)
|
||||
@JoinColumn(name = "client_id", nullable = false)
|
||||
private Client client;
|
||||
|
||||
public AppUserClientMapping(){
|
||||
|
||||
}
|
||||
|
||||
public AppUserClientMapping(Client client){
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public Client getClient() {
|
||||
return this.client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (null == obj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!getClass().equals(obj.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AppUserClientMapping that = (AppUserClientMapping) obj;
|
||||
|
||||
return null == this.client.getId() ? false : this.client.getId().equals(that.client.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int hashCode = 17;
|
||||
|
||||
hashCode += null == this.client ? 0 : this.client.getId().hashCode() * 31;
|
||||
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
}
|
||||
+2
@@ -8,5 +8,7 @@ package org.mifosplatform.useradministration.service;
|
||||
public class AppUserConstants {
|
||||
|
||||
public static final String PASSWORD_NEVER_EXPIRES = "passwordNeverExpires";
|
||||
public static final String IS_SELF_SERVICE_USER = "isSelfServiceUser";
|
||||
public static final String CLIENTS = "clients";
|
||||
|
||||
}
|
||||
|
||||
+21
-4
@@ -9,6 +9,7 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
||||
@@ -18,9 +19,12 @@ import org.mifosplatform.organisation.office.data.OfficeData;
|
||||
import org.mifosplatform.organisation.office.service.OfficeReadPlatformService;
|
||||
import org.mifosplatform.organisation.staff.data.StaffData;
|
||||
import org.mifosplatform.organisation.staff.service.StaffReadPlatformService;
|
||||
import org.mifosplatform.portfolio.client.data.ClientData;
|
||||
import org.mifosplatform.portfolio.client.domain.Client;
|
||||
import org.mifosplatform.useradministration.data.AppUserData;
|
||||
import org.mifosplatform.useradministration.data.RoleData;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.mifosplatform.useradministration.domain.AppUserClientMapping;
|
||||
import org.mifosplatform.useradministration.domain.AppUserRepository;
|
||||
import org.mifosplatform.useradministration.domain.Role;
|
||||
import org.mifosplatform.useradministration.exception.UserNotFoundException;
|
||||
@@ -119,9 +123,21 @@ public class AppUserReadPlatformServiceImpl implements AppUserReadPlatformServic
|
||||
linkedStaff = null;
|
||||
}
|
||||
|
||||
return AppUserData.instance(user.getId(), user.getUsername(), user.getEmail(), user.getOffice().getId(),
|
||||
AppUserData retUser = AppUserData.instance(user.getId(), user.getUsername(), user.getEmail(), user.getOffice().getId(),
|
||||
user.getOffice().getName(), user.getFirstname(), user.getLastname(), availableRoles, selectedUserRoles, linkedStaff,
|
||||
user.getPasswordNeverExpires());
|
||||
user.getPasswordNeverExpires(), user.isSelfServiceUser());
|
||||
|
||||
if(retUser.isSelfServiceUser()){
|
||||
Set<ClientData> clients = new HashSet<>();
|
||||
for(AppUserClientMapping clientMap : user.getAppUserClientMappings()){
|
||||
Client client = clientMap.getClient();
|
||||
clients.add(ClientData.lookup(client.getId(), client.getDisplayName(),
|
||||
client.getOffice().getId(), client.getOffice().getName()));
|
||||
}
|
||||
retUser.setClients(clients);
|
||||
}
|
||||
|
||||
return retUser;
|
||||
}
|
||||
|
||||
private static final class AppUserMapper implements RowMapper<AppUserData> {
|
||||
@@ -146,6 +162,7 @@ public class AppUserReadPlatformServiceImpl implements AppUserReadPlatformServic
|
||||
final String officeName = rs.getString("officeName");
|
||||
final Long staffId = JdbcSupport.getLong(rs, "staffId");
|
||||
final Boolean passwordNeverExpire = rs.getBoolean("passwordNeverExpires");
|
||||
final Boolean isSelfServiceUser = rs.getBoolean("isSelfServiceUser");
|
||||
final Collection<RoleData> selectedRoles = this.roleReadPlatformService.retrieveAppUserRoles(id);
|
||||
|
||||
final StaffData linkedStaff;
|
||||
@@ -155,12 +172,12 @@ public class AppUserReadPlatformServiceImpl implements AppUserReadPlatformServic
|
||||
linkedStaff = null;
|
||||
}
|
||||
return AppUserData.instance(id, username, email, officeId, officeName, firstname, lastname, null, selectedRoles, linkedStaff,
|
||||
passwordNeverExpire);
|
||||
passwordNeverExpire, isSelfServiceUser);
|
||||
}
|
||||
|
||||
public String schema() {
|
||||
return " u.id as id, u.username as username, u.firstname as firstname, u.lastname as lastname, u.email as email, u.password_never_expires as passwordNeverExpires, "
|
||||
+ " u.office_id as officeId, o.name as officeName, u.staff_id as staffId from m_appuser u "
|
||||
+ " u.office_id as officeId, o.name as officeName, u.staff_id as staffId, u.is_self_service_user as isSelfServiceUser from m_appuser u "
|
||||
+ " join m_office o on o.id = u.office_id where o.hierarchy like ? and u.is_deleted=0 order by u.username";
|
||||
}
|
||||
|
||||
|
||||
+40
-3
@@ -6,6 +6,7 @@
|
||||
package org.mifosplatform.useradministration.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -26,6 +27,8 @@ import org.mifosplatform.organisation.office.domain.OfficeRepository;
|
||||
import org.mifosplatform.organisation.office.exception.OfficeNotFoundException;
|
||||
import org.mifosplatform.organisation.staff.domain.Staff;
|
||||
import org.mifosplatform.organisation.staff.domain.StaffRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.client.domain.Client;
|
||||
import org.mifosplatform.portfolio.client.domain.ClientRepository;
|
||||
import org.mifosplatform.useradministration.api.AppUserApiConstant;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.mifosplatform.useradministration.domain.AppUserPreviousPassword;
|
||||
@@ -49,6 +52,9 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
@Service
|
||||
public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWritePlatformService {
|
||||
|
||||
@@ -63,12 +69,14 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
|
||||
private final UserDataValidator fromApiJsonDeserializer;
|
||||
private final AppUserPreviousPasswordRepository appUserPreviewPasswordRepository;
|
||||
private final StaffRepositoryWrapper staffRepositoryWrapper;
|
||||
private final ClientRepository clientRepository;
|
||||
|
||||
@Autowired
|
||||
public AppUserWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final AppUserRepository appUserRepository,
|
||||
final UserDomainService userDomainService, final OfficeRepository officeRepository, final RoleRepository roleRepository,
|
||||
final PlatformPasswordEncoder platformPasswordEncoder, final UserDataValidator fromApiJsonDeserializer,
|
||||
final AppUserPreviousPasswordRepository appUserPreviewPasswordRepository, final StaffRepositoryWrapper staffRepositoryWrapper) {
|
||||
final AppUserPreviousPasswordRepository appUserPreviewPasswordRepository, final StaffRepositoryWrapper staffRepositoryWrapper,
|
||||
final ClientRepository clientRepository) {
|
||||
this.context = context;
|
||||
this.appUserRepository = appUserRepository;
|
||||
this.userDomainService = userDomainService;
|
||||
@@ -78,6 +86,7 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
|
||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||
this.appUserPreviewPasswordRepository = appUserPreviewPasswordRepository;
|
||||
this.staffRepositoryWrapper = staffRepositoryWrapper;
|
||||
this.clientRepository = clientRepository;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -108,8 +117,20 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
|
||||
if (staffId != null) {
|
||||
linkedStaff = this.staffRepositoryWrapper.findByOfficeWithNotFoundDetection(staffId, userOffice.getId());
|
||||
}
|
||||
|
||||
Collection<Client> clients = null;
|
||||
if(command.hasParameter(AppUserConstants.IS_SELF_SERVICE_USER)
|
||||
&& command.booleanPrimitiveValueOfParameterNamed(AppUserConstants.IS_SELF_SERVICE_USER)
|
||||
&& command.hasParameter(AppUserConstants.CLIENTS)){
|
||||
JsonArray clientsArray = command.arrayOfParameterNamed(AppUserConstants.CLIENTS);
|
||||
Collection<Long> clientIds = new HashSet<>();
|
||||
for(JsonElement clientElement : clientsArray){
|
||||
clientIds.add(clientElement.getAsLong());
|
||||
}
|
||||
clients = this.clientRepository.findAll(clientIds);
|
||||
}
|
||||
|
||||
appUser = AppUser.fromJson(userOffice, linkedStaff, allRoles, command);
|
||||
appUser = AppUser.fromJson(userOffice, linkedStaff, allRoles, clients, command);
|
||||
|
||||
final Boolean sendPasswordToEmail = command.booleanObjectValueOfParameterNamed("sendPasswordToEmail");
|
||||
this.userDomainService.create(appUser, sendPasswordToEmail);
|
||||
@@ -151,8 +172,24 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
|
||||
if (userToUpdate == null) { throw new UserNotFoundException(userId); }
|
||||
|
||||
final AppUserPreviousPassword currentPasswordToSaveAsPreview = getCurrentPasswordToSaveAsPreview(userToUpdate, command);
|
||||
|
||||
Collection<Client> clients = null;
|
||||
boolean isSelfServiceUser = userToUpdate.isSelfServiceUser();
|
||||
if(command.hasParameter(AppUserConstants.IS_SELF_SERVICE_USER)){
|
||||
isSelfServiceUser = command.booleanPrimitiveValueOfParameterNamed(AppUserConstants.IS_SELF_SERVICE_USER);
|
||||
}
|
||||
|
||||
if(isSelfServiceUser
|
||||
&& command.hasParameter(AppUserConstants.CLIENTS)){
|
||||
JsonArray clientsArray = command.arrayOfParameterNamed(AppUserConstants.CLIENTS);
|
||||
Collection<Long> clientIds = new HashSet<>();
|
||||
for(JsonElement clientElement : clientsArray){
|
||||
clientIds.add(clientElement.getAsLong());
|
||||
}
|
||||
clients = this.clientRepository.findAll(clientIds);
|
||||
}
|
||||
|
||||
final Map<String, Object> changes = userToUpdate.update(command, this.platformPasswordEncoder);
|
||||
final Map<String, Object> changes = userToUpdate.update(command, this.platformPasswordEncoder, clients);
|
||||
|
||||
if (changes.containsKey("officeId")) {
|
||||
final Long officeId = (Long) changes.get("officeId");
|
||||
|
||||
+49
-1
@@ -24,6 +24,7 @@ import org.mifosplatform.useradministration.domain.PasswordValidationPolicyRepos
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
@@ -34,7 +35,8 @@ public final class UserDataValidator {
|
||||
* The parameters supported for this command.
|
||||
*/
|
||||
private final Set<String> supportedParameters = new HashSet<>(Arrays.asList("username", "firstname", "lastname", "password",
|
||||
"repeatPassword", "email", "officeId", "notSelectedRoles", "roles", "sendPasswordToEmail", "staffId", "passwordNeverExpires"));
|
||||
"repeatPassword", "email", "officeId", "notSelectedRoles", "roles", "sendPasswordToEmail", "staffId", "passwordNeverExpires",
|
||||
AppUserConstants.IS_SELF_SERVICE_USER, AppUserConstants.CLIENTS));
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
@@ -100,6 +102,29 @@ public final class UserDataValidator {
|
||||
.extractBooleanNamed(AppUserConstants.PASSWORD_NEVER_EXPIRES, element);
|
||||
baseDataValidator.reset().parameter("passwordNeverExpire").value(passwordNeverExpire).validateForBooleanValue();
|
||||
}
|
||||
|
||||
Boolean isSelfServiceUser = null;
|
||||
if(this.fromApiJsonHelper.parameterExists(AppUserConstants.IS_SELF_SERVICE_USER, element)){
|
||||
isSelfServiceUser = this.fromApiJsonHelper.extractBooleanNamed(AppUserConstants.IS_SELF_SERVICE_USER, element);
|
||||
if(isSelfServiceUser == null){
|
||||
baseDataValidator.reset().parameter(AppUserConstants.IS_SELF_SERVICE_USER).trueOrFalseRequired(false);
|
||||
}
|
||||
}
|
||||
|
||||
if(this.fromApiJsonHelper.parameterExists(AppUserConstants.CLIENTS, element)){
|
||||
if(isSelfServiceUser == null || !isSelfServiceUser){
|
||||
baseDataValidator.reset().parameter(AppUserConstants.CLIENTS).failWithCode("not.supported.when.isSelfServiceUser.is.false",
|
||||
"clients parameter is not supported when isSelfServiceUser parameter is false");
|
||||
}else{
|
||||
final JsonArray clientsArray = this.fromApiJsonHelper.extractJsonArrayNamed(AppUserConstants.CLIENTS, element);
|
||||
baseDataValidator.reset().parameter(AppUserConstants.CLIENTS).value(clientsArray).jsonArrayNotEmpty();
|
||||
|
||||
for(JsonElement client : clientsArray){
|
||||
Long clientId = client.getAsLong();
|
||||
baseDataValidator.reset().parameter(AppUserConstants.CLIENTS).value(clientId).longGreaterThanZero();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final String[] roles = this.fromApiJsonHelper.extractArrayNamed("roles", element);
|
||||
baseDataValidator.reset().parameter("roles").value(roles).arrayNotEmpty();
|
||||
@@ -175,6 +200,29 @@ public final class UserDataValidator {
|
||||
final boolean passwordNeverExpire = this.fromApiJsonHelper.extractBooleanNamed("passwordNeverExpire", element);
|
||||
baseDataValidator.reset().parameter("passwordNeverExpire").value(passwordNeverExpire).validateForBooleanValue();
|
||||
}
|
||||
|
||||
Boolean isSelfServiceUser = null;
|
||||
if(this.fromApiJsonHelper.parameterExists(AppUserConstants.IS_SELF_SERVICE_USER, element)){
|
||||
isSelfServiceUser = this.fromApiJsonHelper.extractBooleanNamed(AppUserConstants.IS_SELF_SERVICE_USER, element);
|
||||
if(isSelfServiceUser == null){
|
||||
baseDataValidator.reset().parameter(AppUserConstants.IS_SELF_SERVICE_USER).trueOrFalseRequired(false);
|
||||
}
|
||||
}
|
||||
|
||||
if(this.fromApiJsonHelper.parameterExists(AppUserConstants.CLIENTS, element)){
|
||||
if(isSelfServiceUser != null && !isSelfServiceUser){
|
||||
baseDataValidator.reset().parameter(AppUserConstants.CLIENTS).failWithCode("not.supported.when.isSelfServiceUser.is.false",
|
||||
"clients parameter is not supported when isSelfServiceUser parameter is false");
|
||||
}else{
|
||||
final JsonArray clientsArray = this.fromApiJsonHelper.extractJsonArrayNamed(AppUserConstants.CLIENTS, element);
|
||||
baseDataValidator.reset().parameter(AppUserConstants.CLIENTS).value(clientsArray).jsonArrayNotEmpty();
|
||||
|
||||
for(JsonElement client : clientsArray){
|
||||
Long clientId = client.getAsLong();
|
||||
baseDataValidator.reset().parameter(AppUserConstants.CLIENTS).value(clientId).longGreaterThanZero();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
entry-point-ref="basicAuthenticationEntryPoint">
|
||||
<intercept-url pattern="/api/*/authentication" access="permitAll"
|
||||
method="POST" requires-channel="https" />
|
||||
<intercept-url pattern="/api/*/self/authentication" access="permitAll"
|
||||
method="POST" requires-channel="https" />
|
||||
<intercept-url pattern="/api/**" access="isFullyAuthenticated()"
|
||||
method="GET" requires-channel="https" />
|
||||
<intercept-url pattern="/api/**" access="isFullyAuthenticated()"
|
||||
@@ -132,6 +134,8 @@
|
||||
class="org.springframework.security.access.vote.AuthenticatedVoter" />
|
||||
<beans:bean
|
||||
class="org.springframework.security.web.access.expression.WebExpressionVoter" />
|
||||
<beans:bean
|
||||
class="org.mifosplatform.infrastructure.security.vote.SelfServiceUserAccessVote" />
|
||||
</beans:list>
|
||||
</beans:constructor-arg>
|
||||
</beans:bean>
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
ALTER TABLE `m_appuser`
|
||||
ADD COLUMN `is_self_service_user` BIT(1) NOT NULL DEFAULT 0;
|
||||
|
||||
CREATE TABLE `m_selfservice_user_client_mapping` (
|
||||
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
`appuser_id` BIGINT(20) NOT NULL,
|
||||
`client_id` BIGINT(20) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE INDEX `appuser_id_client_id` (`appuser_id`, `client_id`),
|
||||
CONSTRAINT `m_selfservice_appuser_id` FOREIGN KEY (`appuser_id`) REFERENCES `m_appuser` (`id`),
|
||||
CONSTRAINT `m_selfservice_client_id` FOREIGN KEY (`client_id`) REFERENCES `m_client` (`id`)
|
||||
)
|
||||
COLLATE='utf8_general_ci'
|
||||
ENGINE=InnoDB
|
||||
AUTO_INCREMENT=1;
|
||||
Reference in New Issue
Block a user