MIFOSX-97: initial integration of maker-checker capability on permissions with actual api services.

This commit is contained in:
Keith Woodlock
2012-11-26 18:17:53 +00:00
parent 092eabc0a0
commit 19fea3ed00
29 changed files with 636 additions and 417 deletions
@@ -33,66 +33,63 @@ import org.springframework.stereotype.Component;
@Scope("singleton") @Scope("singleton")
public class CommandsApiResource { public class CommandsApiResource {
@Autowired @Autowired
private PortfolioCommandsReadPlatformService readPlatformService; private PortfolioCommandsReadPlatformService readPlatformService;
@Autowired
private PortfolioCommandSourceWritePlatformService writePlatformService;
@Autowired @Autowired
private PortfolioApiJsonSerializerService apiJsonSerializerService; private PortfolioCommandSourceWritePlatformService writePlatformService;
private final String entityType = "MAKERCHECKER"; @Autowired
private PortfolioApiJsonSerializerService apiJsonSerializerService;
private final String entityType = "MAKERCHECKER";
@Autowired @Autowired
private PlatformSecurityContext context; private PlatformSecurityContext context;
@GET
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public String retrieveCodes(@Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(entityType); @GET
@Consumes({ MediaType.APPLICATION_JSON })
final Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); @Produces({ MediaType.APPLICATION_JSON })
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); public String retrieveCodes(@Context final UriInfo uriInfo) {
final Collection<CommandSourceData> entries = this.readPlatformService.retrieveAllEntriesToBeChecked();
return this.apiJsonSerializerService.serializeMakerCheckerDataToJson(prettyPrint, responseParameters, entries);
}
@POST
@Path("{makerCheckerId}")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public String approveMakerCheckerEntry(
@PathParam("makerCheckerId") final Long makerCheckerId,
@QueryParam("command") final String commandParam) {
EntityIdentifier result = null; context.authenticatedUser().validateHasReadPermission(entityType);
if (is(commandParam, "approve")) {
result = this.writePlatformService.approveEntry(makerCheckerId);
} else {
throw new UnrecognizedQueryParamException("command", commandParam);
}
return this.apiJsonSerializerService.serializeEntityIdentifier(result); final Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
} final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
private boolean is(final String commandParam, final String commandValue) { final Collection<CommandSourceData> entries = this.readPlatformService.retrieveAllEntriesToBeChecked();
return StringUtils.isNotBlank(commandParam)
&& commandParam.trim().equalsIgnoreCase(commandValue);
}
@DELETE
@Path("{makerCheckerId}")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public String deleteMakerCheckerEntry(
@PathParam("makerCheckerId") final Long makerCheckerId) {
final Long id = this.writePlatformService.deleteEntry(makerCheckerId); return this.apiJsonSerializerService.serializeMakerCheckerDataToJson(prettyPrint, responseParameters, entries);
}
return this.apiJsonSerializerService.serializeEntityIdentifier(EntityIdentifier.makerChecker(id)); @POST
} @Path("{makerCheckerId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String approveMakerCheckerEntry(@PathParam("makerCheckerId") final Long makerCheckerId,
@QueryParam("command") final String commandParam) {
EntityIdentifier result = null;
if (is(commandParam, "approve")) {
result = this.writePlatformService.approveEntry(makerCheckerId);
} else {
throw new UnrecognizedQueryParamException("command", commandParam);
}
return this.apiJsonSerializerService.serializeEntityIdentifier(result);
}
private boolean is(final String commandParam, final String commandValue) {
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
}
@DELETE
@Path("{makerCheckerId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String deleteMakerCheckerEntry(@PathParam("makerCheckerId") final Long makerCheckerId) {
final Long id = this.writePlatformService.deleteEntry(makerCheckerId);
return this.apiJsonSerializerService.serializeEntityIdentifier(EntityIdentifier.makerChecker(id));
}
} }
@@ -31,53 +31,52 @@ import org.springframework.stereotype.Component;
@Scope("singleton") @Scope("singleton")
public class ConfigurationApiResource { public class ConfigurationApiResource {
@Autowired @Autowired
private ConfigurationReadPlatformService configurationReadPlatformService; private ConfigurationReadPlatformService configurationReadPlatformService;
@Autowired @Autowired
private ConfigurationWritePlatformService configurationWritePlatformService; private ConfigurationWritePlatformService configurationWritePlatformService;
@Autowired @Autowired
private PortfolioApiDataConversionService apiDataConversionService; private PortfolioApiDataConversionService apiDataConversionService;
@Autowired @Autowired
private PortfolioApiJsonSerializerService apiJsonSerializerService; private PortfolioApiJsonSerializerService apiJsonSerializerService;
@Autowired @Autowired
private PlatformSecurityContext context; private PlatformSecurityContext context;
@GET
@Path("currency")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public String retrieveCurrencyDataForConfiguration(@Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission("CURRENCY"); @GET
@Path("currency")
Set<String> typicalResponseParameters = new HashSet<String>( @Consumes({ MediaType.APPLICATION_JSON })
Arrays.asList("selectedCurrencyOptions", "currencyOptions")); @Produces({ MediaType.APPLICATION_JSON })
public String retrieveCurrencyDataForConfiguration(@Context final UriInfo uriInfo) {
Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
if (responseParameters.isEmpty()) {
responseParameters.addAll(typicalResponseParameters);
}
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
ConfigurationData configurationData = this.configurationReadPlatformService.retrieveCurrencyConfiguration(); context.authenticatedUser().validateHasReadPermission("CURRENCY");
return this.apiJsonSerializerService.serializeConfigurationDataToJson(prettyPrint, responseParameters, configurationData);
}
@PUT Set<String> typicalResponseParameters = new HashSet<String>(Arrays.asList("selectedCurrencyOptions", "currencyOptions"));
@Path("currency")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public Response updateAllowedCurrenciesForOrganisation(final String jsonRequestBody) {
OrganisationCurrencyCommand command = this.apiDataConversionService.convertJsonToOrganisationCurrencyCommand(jsonRequestBody); Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
if (responseParameters.isEmpty()) {
this.configurationWritePlatformService.updateOrganisationCurrencies(command); responseParameters.addAll(typicalResponseParameters);
}
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
return Response.ok().entity(command).build(); ConfigurationData configurationData = this.configurationReadPlatformService.retrieveCurrencyConfiguration();
}
return this.apiJsonSerializerService.serializeConfigurationDataToJson(prettyPrint, responseParameters, configurationData);
}
@PUT
@Path("currency")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response updateAllowedCurrenciesForOrganisation(final String jsonRequestBody) {
OrganisationCurrencyCommand command = this.apiDataConversionService.convertJsonToOrganisationCurrencyCommand(jsonRequestBody);
this.configurationWritePlatformService.updateOrganisationCurrencies(command);
return Response.ok().entity(command).build();
}
} }
@@ -15,21 +15,17 @@ import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.Context; import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
import org.mifosng.platform.api.commands.UserCommand;
import org.mifosng.platform.api.data.AppUserData; import org.mifosng.platform.api.data.AppUserData;
import org.mifosng.platform.api.data.EntityIdentifier; import org.mifosng.platform.api.data.EntityIdentifier;
import org.mifosng.platform.api.data.OfficeLookup; import org.mifosng.platform.api.data.OfficeLookup;
import org.mifosng.platform.api.infrastructure.PortfolioApiDataConversionService;
import org.mifosng.platform.api.infrastructure.PortfolioApiJsonSerializerService; import org.mifosng.platform.api.infrastructure.PortfolioApiJsonSerializerService;
import org.mifosng.platform.infrastructure.api.ApiParameterHelper; import org.mifosng.platform.infrastructure.api.ApiParameterHelper;
import org.mifosng.platform.makerchecker.service.PortfolioCommandSourceWritePlatformService;
import org.mifosng.platform.organisation.service.OfficeReadPlatformService; import org.mifosng.platform.organisation.service.OfficeReadPlatformService;
import org.mifosng.platform.security.PlatformSecurityContext; import org.mifosng.platform.security.PlatformSecurityContext;
import org.mifosng.platform.user.domain.AppUser;
import org.mifosng.platform.user.service.AppUserReadPlatformService; import org.mifosng.platform.user.service.AppUserReadPlatformService;
import org.mifosng.platform.user.service.AppUserWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -45,14 +41,11 @@ public class UsersApiResource {
@Autowired @Autowired
private OfficeReadPlatformService officeReadPlatformService; private OfficeReadPlatformService officeReadPlatformService;
@Autowired
private AppUserWritePlatformService appUserWritePlatformService;
@Autowired
private PortfolioApiDataConversionService apiDataConversionService;
@Autowired @Autowired
private PortfolioApiJsonSerializerService apiJsonSerializerService; private PortfolioApiJsonSerializerService apiJsonSerializerService;
@Autowired
private PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
@Autowired @Autowired
private PlatformSecurityContext context; private PlatformSecurityContext context;
@@ -114,41 +107,32 @@ public class UsersApiResource {
@POST @POST
@Consumes({MediaType.APPLICATION_JSON}) @Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON}) @Produces({MediaType.APPLICATION_JSON})
public Response createUser(final String jsonRequestBody) { public String createUser(final String apiRequestBodyAsJson) {
final UserCommand command = this.apiDataConversionService.convertJsonToUserCommand(null, jsonRequestBody); final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE", "users", null, apiRequestBodyAsJson);
final Long userId = this.appUserWritePlatformService.createUser(command); return this.apiJsonSerializerService.serializeEntityIdentifier(result);
return Response.ok().entity(new EntityIdentifier(userId)).build();
} }
@DELETE @DELETE
@Path("{userId}") @Path("{userId}")
@Consumes({MediaType.APPLICATION_JSON}) @Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON}) @Produces({MediaType.APPLICATION_JSON})
public Response deleteUser(@PathParam("userId") final Long userId) { public String deleteUser(@PathParam("userId") final Long userId) {
final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("DELETE", "users", userId, "{}");
this.appUserWritePlatformService.deleteUser(userId); return this.apiJsonSerializerService.serializeEntityIdentifier(result);
return Response.ok(new EntityIdentifier(userId)).build();
} }
@PUT @PUT
@Path("{userId}") @Path("{userId}")
@Consumes({MediaType.APPLICATION_JSON}) @Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON}) @Produces({MediaType.APPLICATION_JSON})
public Response updateUser(@PathParam("userId") final Long userId, final String jsonRequestBody) { public String updateUser(@PathParam("userId") final Long userId, final String apiRequestBodyAsJson) {
final UserCommand command = this.apiDataConversionService.convertJsonToUserCommand(userId, jsonRequestBody); final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", "users", userId, apiRequestBodyAsJson);
final AppUser loggedInUser = context.authenticatedUser(); return this.apiJsonSerializerService.serializeEntityIdentifier(result);
if (loggedInUser.hasIdOf(userId)) {
this.appUserWritePlatformService.updateUsersOwnAccountDetails(command);
} else {
this.appUserWritePlatformService.updateUser(command);
}
return Response.ok().entity(new EntityIdentifier(userId)).build();
} }
} }
@@ -1,113 +1,114 @@
package org.mifosng.platform.api.commands; package org.mifosng.platform.api.commands;
import java.io.Serializable;
import java.util.Set; import java.util.Set;
/** /**
* Immutable command for creating or updating details of a User. * Immutable command for creating or updating details of a User.
*/ */
public class UserCommand implements Serializable { public class UserCommand {
private final Long id; private final String username;
private final String username; private final String firstname;
private final String firstname; private final String lastname;
private final String lastname; private final String password;
private final String password; private final String repeatPassword;
private final String repeatPassword; private final String email;
private final String email; private final Long officeId;
private final Long officeId;
private final String[] notSelectedRoles;
private final String[] roles;
private final Set<String> modifiedParameters;
public UserCommand(final Set<String> modifiedParameters, final Long id, private final String[] notSelectedRoles;
final String username, final String firstname, final String lastname, private final String[] roles;
final String password, final String repeatPassword, final String email,
final Long officeId, final String[] notSelectedRoles, final String[] roles) {
this.modifiedParameters = modifiedParameters;
this.id = id;
this.username = username;
this.firstname = firstname;
this.lastname = lastname;
this.password = password;
this.repeatPassword = repeatPassword;
this.email = email;
this.officeId = officeId;
this.notSelectedRoles = notSelectedRoles;
this.roles = roles;
}
public String getDisplayName() {
return new StringBuilder(this.lastname).append(", ").append(this.firstname).toString();
}
public Long getId() { private transient final boolean makerCheckerApproval;
return id; private transient final Long id;
} private transient final Set<String> modifiedParameters;
public UserCommand(final Set<String> modifiedParameters, final boolean makerCheckerApproval,
final Long id, final String username, final String firstname,
final String lastname, final String password, final String repeatPassword, final String email, final Long officeId,
final String[] notSelectedRoles, final String[] roles) {
this.modifiedParameters = modifiedParameters;
this.makerCheckerApproval = makerCheckerApproval;
this.id = id;
this.username = username;
this.firstname = firstname;
this.lastname = lastname;
this.password = password;
this.repeatPassword = repeatPassword;
this.email = email;
this.officeId = officeId;
this.notSelectedRoles = notSelectedRoles;
this.roles = roles;
}
public String getUsername() { public Long getId() {
return username; return id;
} }
public String getFirstname() { public String getUsername() {
return firstname; return username;
} }
public String getLastname() { public String getFirstname() {
return lastname; return firstname;
} }
public String getPassword() { public String getLastname() {
return password; return lastname;
} }
public String getRepeatPassword() { public String getPassword() {
return repeatPassword; return password;
} }
public String getEmail() { public String getRepeatPassword() {
return email; return repeatPassword;
} }
public Long getOfficeId() { public String getEmail() {
return officeId; return email;
} }
public String[] getNotSelectedRoles() { public Long getOfficeId() {
return notSelectedRoles; return officeId;
} }
public String[] getRoles() { public String[] getNotSelectedRoles() {
return roles; return notSelectedRoles;
} }
public boolean isUsernameChanged() { public String[] getRoles() {
return this.modifiedParameters.contains("username"); return roles;
} }
public boolean isFirstnameChanged() { public boolean isUsernameChanged() {
return this.modifiedParameters.contains("firstname"); return this.modifiedParameters.contains("username");
} }
public boolean isLastnameChanged() { public boolean isFirstnameChanged() {
return this.modifiedParameters.contains("lastname"); return this.modifiedParameters.contains("firstname");
} }
public boolean isEmailChanged() { public boolean isLastnameChanged() {
return this.modifiedParameters.contains("email"); return this.modifiedParameters.contains("lastname");
} }
public boolean isPasswordChanged() { public boolean isEmailChanged() {
return this.modifiedParameters.contains("password") && this.modifiedParameters.contains("repeatPassword"); return this.modifiedParameters.contains("email");
} }
public boolean isOfficeChanged() { public boolean isPasswordChanged() {
return this.modifiedParameters.contains("officeId"); return this.modifiedParameters.contains("password") && this.modifiedParameters.contains("repeatPassword");
} }
public boolean isRolesChanged() { public boolean isOfficeChanged() {
return this.modifiedParameters.contains("roles"); return this.modifiedParameters.contains("officeId");
} }
public boolean isRolesChanged() {
return this.modifiedParameters.contains("roles");
}
public boolean isApprovedByChecker() {
return this.makerCheckerApproval;
}
} }
@@ -44,7 +44,7 @@ public interface PortfolioApiDataConversionService {
RolePermissionCommand convertApiRequestJsonToRolePermissionCommand(Long roleId, String jsonRequestBody); RolePermissionCommand convertApiRequestJsonToRolePermissionCommand(Long roleId, String jsonRequestBody);
UserCommand convertJsonToUserCommand(Long resourceIdentifier, String json); UserCommand convertApiRequestJsonToUserCommand(Long resourceIdentifier, String json);
BranchMoneyTransferCommand convertJsonToBranchMoneyTransferCommand(String json); BranchMoneyTransferCommand convertJsonToBranchMoneyTransferCommand(String json);
@@ -269,58 +269,22 @@ public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataCo
} }
@Override @Override
public UserCommand convertJsonToUserCommand(final Long resourceIdentifier, final String json) { public UserCommand convertApiRequestJsonToUserCommand(final Long resourceIdentifier, final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType(); final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
Map<String, Object> requestMap = gsonConverter.fromJson(json, typeOfMap); final Map<String, Object> requestMap = gsonConverter.fromJson(json, typeOfMap);
Set<String> supportedParams = new HashSet<String>(Arrays.asList("username", "firstname", "lastname", "password", "repeatPassword", final Set<String> supportedParams = new HashSet<String>(Arrays.asList("username", "firstname", "lastname", "password", "repeatPassword",
"email", "officeId", "notSelectedRoles", "roles")); "email", "officeId", "notSelectedRoles", "roles"));
checkForUnsupportedParameters(requestMap, supportedParams); checkForUnsupportedParameters(requestMap, supportedParams);
Set<String> modifiedParameters = new HashSet<String>(); // no difference between the api json and internal command
// representation of json so reuse this code to de-serialize into
String username = extractStringParameter("username", requestMap, modifiedParameters); // command object
String firstname = extractStringParameter("firstname", requestMap, modifiedParameters); return this.portfolioCommandDeserializerService.deserializeUserCommand(resourceIdentifier, json, false);
String lastname = extractStringParameter("lastname", requestMap, modifiedParameters);
String password = extractStringParameter("password", requestMap, modifiedParameters);
String repeatPassword = extractStringParameter("repeatPassword", requestMap, modifiedParameters);
String email = extractStringParameter("email", requestMap, modifiedParameters);
Long officeId = extractLongParameter("officeId", requestMap, modifiedParameters);
// check array
JsonParser parser = new JsonParser();
String[] notSelectedRoles = null;
String[] roles = null;
JsonElement element = parser.parse(json);
if (element.isJsonObject()) {
JsonObject object = element.getAsJsonObject();
if (object.has("notSelectedRoles")) {
modifiedParameters.add("notSelectedRoles");
JsonArray array = object.get("notSelectedRoles").getAsJsonArray();
notSelectedRoles = new String[array.size()];
for (int i = 0; i < array.size(); i++) {
notSelectedRoles[i] = array.get(i).getAsString();
}
}
if (object.has("roles")) {
modifiedParameters.add("roles");
JsonArray array = object.get("roles").getAsJsonArray();
roles = new String[array.size()];
for (int i = 0; i < array.size(); i++) {
roles[i] = array.get(i).getAsString();
}
}
}
//
return new UserCommand(modifiedParameters, resourceIdentifier, username, firstname, lastname, password, repeatPassword, email,
officeId, notSelectedRoles, roles);
} }
@Override @Override
@@ -576,8 +540,6 @@ public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataCo
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType(); final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
final Map<String, Object> requestMap = gsonConverter.fromJson(json, typeOfMap); final Map<String, Object> requestMap = gsonConverter.fromJson(json, typeOfMap);
// FIXME - A - LoanProduct - KW - Do we add support for
// "overpaidTolerance" parameter?
final Set<String> supportedParams = new HashSet<String>(Arrays.asList("name", "description", "fundId", final Set<String> supportedParams = new HashSet<String>(Arrays.asList("name", "description", "fundId",
"transactionProcessingStrategyId", "currencyCode", "digitsAfterDecimal", "principal", "inArrearsTolerance", "transactionProcessingStrategyId", "currencyCode", "digitsAfterDecimal", "principal", "inArrearsTolerance",
"interestRatePerPeriod", "repaymentEvery", "numberOfRepayments", "repaymentFrequencyType", "interestRateFrequencyType", "interestRatePerPeriod", "repaymentEvery", "numberOfRepayments", "repaymentFrequencyType", "interestRateFrequencyType",
@@ -621,10 +583,6 @@ public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataCo
final Integer interestCalculationPeriodType = helper.extractIntegerNamed("interestCalculationPeriodType", element, final Integer interestCalculationPeriodType = helper.extractIntegerNamed("interestCalculationPeriodType", element,
modifiedParameters); modifiedParameters);
// FIXME - A - LoanProduct - KW - product charges at present dont allow
// for adding 'charge' to loan product and setting its 'amount', might
// this be needed?
// loan product charges
String[] charges = null; String[] charges = null;
if (element.isJsonObject()) { if (element.isJsonObject()) {
JsonObject object = element.getAsJsonObject(); JsonObject object = element.getAsJsonObject();
@@ -739,7 +697,6 @@ public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataCo
loanTermFrequency, loanTermFrequencyType, inArrearsToleranceValue, charges, loanOfficerId); loanTermFrequency, loanTermFrequencyType, inArrearsToleranceValue, charges, loanOfficerId);
} }
// FIXME - KW - charges
@Override @Override
public LoanChargeCommand convertJsonToLoanChargeCommand(final Long loanChargeId, final Long loanId, final String json) { public LoanChargeCommand convertJsonToLoanChargeCommand(final Long loanChargeId, final Long loanId, final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
@@ -1594,7 +1551,6 @@ public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataCo
@Override @Override
public CodeCommand convertJsonToCodeCommand(Long resourceIdentifier, String json) { public CodeCommand convertJsonToCodeCommand(Long resourceIdentifier, String json) {
// TODO Auto-generated method stub
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
Type typeOfMap = new TypeToken<Map<String, String>>() {}.getType(); Type typeOfMap = new TypeToken<Map<String, String>>() {}.getType();
@@ -6,12 +6,15 @@ import java.util.Set;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.mifosng.platform.accounting.api.commands.RolePermissionCommand; import org.mifosng.platform.accounting.api.commands.RolePermissionCommand;
import org.mifosng.platform.api.commands.RoleCommand; import org.mifosng.platform.api.commands.RoleCommand;
import org.mifosng.platform.api.commands.UserCommand;
import org.mifosng.platform.infrastructure.api.JsonParserHelper; import org.mifosng.platform.infrastructure.api.JsonParserHelper;
import org.mifosng.platform.infrastructure.errorhandling.InvalidJsonException; import org.mifosng.platform.infrastructure.errorhandling.InvalidJsonException;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
/** /**
@@ -53,4 +56,50 @@ public class PortfolioCommandDeerializerServiceGoogleGson implements PortfolioCo
return new RolePermissionCommand(roleId, command.getPermissions(), makerCheckerApproval); return new RolePermissionCommand(roleId, command.getPermissions(), makerCheckerApproval);
} }
@Override
public UserCommand deserializeUserCommand(final Long userId, final String commandAsJson, final boolean makerCheckerApproval) {
if (StringUtils.isBlank(commandAsJson)) { throw new InvalidJsonException(); }
final JsonParserHelper helper = new JsonParserHelper();
final JsonElement element = parser.parse(commandAsJson);
final Set<String> parametersPassedInRequest = new HashSet<String>();
final String username = helper.extractStringNamed("username", element, parametersPassedInRequest);
final String firstname = helper.extractStringNamed("firstname", element, parametersPassedInRequest);
final String lastname = helper.extractStringNamed("lastname", element, parametersPassedInRequest);
final String password = helper.extractStringNamed("password", element, parametersPassedInRequest);
final String repeatPassword = helper.extractStringNamed("repeatPassword", element, parametersPassedInRequest);
final String email = helper.extractStringNamed("email", element, parametersPassedInRequest);
final Long officeId = helper.extractLongNamed("officeId", element, parametersPassedInRequest);
// check array
String[] notSelectedRoles = null;
String[] roles = null;
if (element.isJsonObject()) {
JsonObject object = element.getAsJsonObject();
if (object.has("notSelectedRoles")) {
parametersPassedInRequest.add("notSelectedRoles");
JsonArray array = object.get("notSelectedRoles").getAsJsonArray();
notSelectedRoles = new String[array.size()];
for (int i = 0; i < array.size(); i++) {
notSelectedRoles[i] = array.get(i).getAsString();
}
}
if (object.has("roles")) {
parametersPassedInRequest.add("roles");
JsonArray array = object.get("roles").getAsJsonArray();
roles = new String[array.size()];
for (int i = 0; i < array.size(); i++) {
roles[i] = array.get(i).getAsString();
}
}
}
return new UserCommand(parametersPassedInRequest, makerCheckerApproval, userId, username, firstname, lastname,
password, repeatPassword, email, officeId, notSelectedRoles, roles);
}
} }
@@ -2,6 +2,7 @@ package org.mifosng.platform.api.infrastructure;
import org.mifosng.platform.accounting.api.commands.RolePermissionCommand; import org.mifosng.platform.accounting.api.commands.RolePermissionCommand;
import org.mifosng.platform.api.commands.RoleCommand; import org.mifosng.platform.api.commands.RoleCommand;
import org.mifosng.platform.api.commands.UserCommand;
/** /**
* Service for de-serializing JSON for a command into the platforms internal * Service for de-serializing JSON for a command into the platforms internal
@@ -18,4 +19,6 @@ public interface PortfolioCommandDeserializerService {
RoleCommand deserializeRoleCommand(Long roleId, String commandAsJson, boolean makerCheckerApproval); RoleCommand deserializeRoleCommand(Long roleId, String commandAsJson, boolean makerCheckerApproval);
RolePermissionCommand deserializeRolePermissionCommand(Long roleId, String commandAsJson, boolean makerCheckerApproval); RolePermissionCommand deserializeRolePermissionCommand(Long roleId, String commandAsJson, boolean makerCheckerApproval);
UserCommand deserializeUserCommand(Long resourceId, String jsonOfChangesOnly, boolean makerCheckerApproval);
} }
@@ -2,6 +2,7 @@ package org.mifosng.platform.api.infrastructure;
import org.mifosng.platform.accounting.api.commands.RolePermissionCommand; import org.mifosng.platform.accounting.api.commands.RolePermissionCommand;
import org.mifosng.platform.api.commands.RoleCommand; import org.mifosng.platform.api.commands.RoleCommand;
import org.mifosng.platform.api.commands.UserCommand;
/** /**
* Service for serializing commands into another format. * Service for serializing commands into another format.
@@ -14,4 +15,6 @@ public interface PortfolioCommandSerializerService {
String serializeRoleCommandToJson(RoleCommand command); String serializeRoleCommandToJson(RoleCommand command);
String serializeRolePermissionCommandToJson(RolePermissionCommand command); String serializeRolePermissionCommandToJson(RolePermissionCommand command);
String serializeUserCommandToJson(UserCommand command);
} }
@@ -4,6 +4,7 @@ import java.util.HashSet;
import org.mifosng.platform.accounting.api.commands.RolePermissionCommand; import org.mifosng.platform.accounting.api.commands.RolePermissionCommand;
import org.mifosng.platform.api.commands.RoleCommand; import org.mifosng.platform.api.commands.RoleCommand;
import org.mifosng.platform.api.commands.UserCommand;
import org.mifosng.platform.infrastructure.api.GoogleGsonSerializerHelper; import org.mifosng.platform.infrastructure.api.GoogleGsonSerializerHelper;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -36,4 +37,10 @@ public class PortfolioCommandSerializerServiceJson implements PortfolioCommandSe
final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(new HashSet<String>(), false, new HashSet<String>()); final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(new HashSet<String>(), false, new HashSet<String>());
return helper.serializedJsonFrom(gsonDeserializer, command); return helper.serializedJsonFrom(gsonDeserializer, command);
} }
@Override
public String serializeUserCommandToJson(final UserCommand command) {
final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(new HashSet<String>(), false, new HashSet<String>());
return helper.serializedJsonFrom(gsonDeserializer, command);
}
} }
@@ -30,6 +30,8 @@ import org.mifosng.platform.organisation.domain.CodeValueRepository;
import org.mifosng.platform.organisation.domain.Office; import org.mifosng.platform.organisation.domain.Office;
import org.mifosng.platform.organisation.domain.OfficeRepository; import org.mifosng.platform.organisation.domain.OfficeRepository;
import org.mifosng.platform.security.PlatformSecurityContext; import org.mifosng.platform.security.PlatformSecurityContext;
import org.mifosng.platform.user.domain.Permission;
import org.mifosng.platform.user.domain.PermissionRepository;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -48,21 +50,19 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
private final OfficeRepository officeRepository; private final OfficeRepository officeRepository;
private final NoteRepository noteRepository; private final NoteRepository noteRepository;
private final CodeValueRepository codeValueRepository; private final CodeValueRepository codeValueRepository;
private final PermissionRepository permissionRepository;
// FIXME - kw - this value is hardcoded for now but will be retrieved from
// configuration
private boolean makerCheckerEnabledForTask = false;
@Autowired @Autowired
public ClientWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final ClientRepository clientRepository, public ClientWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final ClientRepository clientRepository,
final ClientIdentifierRepository clientIdentifierRepository, final OfficeRepository officeRepository, final ClientIdentifierRepository clientIdentifierRepository, final OfficeRepository officeRepository,
NoteRepository noteRepository, final CodeValueRepository codeValueRepository) { NoteRepository noteRepository, final CodeValueRepository codeValueRepository, final PermissionRepository permissionRepository) {
this.context = context; this.context = context;
this.clientRepository = clientRepository; this.clientRepository = clientRepository;
this.clientIdentifierRepository = clientIdentifierRepository; this.clientIdentifierRepository = clientIdentifierRepository;
this.officeRepository = officeRepository; this.officeRepository = officeRepository;
this.noteRepository = noteRepository; this.noteRepository = noteRepository;
this.codeValueRepository = codeValueRepository; this.codeValueRepository = codeValueRepository;
this.permissionRepository = permissionRepository;
} }
@Transactional @Transactional
@@ -76,8 +76,9 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
client.delete(); client.delete();
this.clientRepository.save(client); this.clientRepository.save(client);
if (this.makerCheckerEnabledForTask && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } final Permission thisTask = this.permissionRepository.findOneByCode("DELETE_CLIENT");
if (thisTask.hasMakerCheckerEnabled() && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); }
return new EntityIdentifier(client.getId()); return new EntityIdentifier(client.getId());
} }
@@ -92,7 +93,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
"error.msg.client.duplicate.externalId", "Client with externalId `" + command.getExternalId() + "` already exists", "error.msg.client.duplicate.externalId", "Client with externalId `" + command.getExternalId() + "` already exists",
"externalId", command.getExternalId()); } "externalId", command.getExternalId()); }
logger.error(dve.getMessage(), dve); logAsErrorUnexpectedDataIntegrityException(dve);
throw new PlatformDataIntegrityException("error.msg.client.unknown.data.integrity.issue", throw new PlatformDataIntegrityException("error.msg.client.unknown.data.integrity.issue",
"Unknown data integrity issue with resource."); "Unknown data integrity issue with resource.");
} }
@@ -120,8 +121,9 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
final Client newClient = Client.newClient(clientOffice, firstname, lastname, command.getJoiningDate(), command.getExternalId()); final Client newClient = Client.newClient(clientOffice, firstname, lastname, command.getJoiningDate(), command.getExternalId());
this.clientRepository.save(newClient); this.clientRepository.save(newClient);
if (this.makerCheckerEnabledForTask && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } final Permission thisTask = this.permissionRepository.findOneByCode("CREATE_CLIENT");
if (thisTask.hasMakerCheckerEnabled() && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); }
return newClient.getId(); return newClient.getId();
} catch (DataIntegrityViolationException dve) { } catch (DataIntegrityViolationException dve) {
@@ -153,8 +155,9 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
this.clientRepository.saveAndFlush(clientForUpdate); this.clientRepository.saveAndFlush(clientForUpdate);
if (this.makerCheckerEnabledForTask && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } final Permission thisTask = this.permissionRepository.findOneByCode("UPDATE_CLIENT");
if (thisTask.hasMakerCheckerEnabled() && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); }
return new EntityIdentifier(clientForUpdate.getId()); return new EntityIdentifier(clientForUpdate.getId());
} catch (DataIntegrityViolationException dve) { } catch (DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve); handleDataIntegrityIssues(command, dve);
@@ -285,12 +288,15 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
} else if (dve.getMostSpecificCause().getMessage().contains("unique_identifier_key")) { throw new DuplicateClientIdentifierException( } else if (dve.getMostSpecificCause().getMessage().contains("unique_identifier_key")) { throw new DuplicateClientIdentifierException(
documentTypeId, documentTypeLabel, documentKey); } documentTypeId, documentTypeLabel, documentKey); }
// only log as error if unexpected data integrity violation. logAsErrorUnexpectedDataIntegrityException(dve);
logger.error(dve.getMessage(), dve);
throw new PlatformDataIntegrityException("error.msg.clientIdentifier.unknown.data.integrity.issue", throw new PlatformDataIntegrityException("error.msg.clientIdentifier.unknown.data.integrity.issue",
"Unknown data integrity issue with resource."); "Unknown data integrity issue with resource.");
} }
private void logAsErrorUnexpectedDataIntegrityException(final DataIntegrityViolationException dve) {
logger.error(dve.getMessage(), dve);
}
@Transactional @Transactional
@Override @Override
public EntityIdentifier deleteClientIdentifier(final Long clientIdentifierId) { public EntityIdentifier deleteClientIdentifier(final Long clientIdentifierId) {
@@ -4,6 +4,6 @@ import org.mifosng.platform.api.data.ConfigurationData;
public interface ConfigurationReadPlatformService { public interface ConfigurationReadPlatformService {
ConfigurationData retrieveCurrencyConfiguration(); ConfigurationData retrieveCurrencyConfiguration();
} }
@@ -12,24 +12,25 @@ import org.springframework.stereotype.Service;
@Service @Service
public class ConfigurationReadPlatformServiceImpl implements ConfigurationReadPlatformService { public class ConfigurationReadPlatformServiceImpl implements ConfigurationReadPlatformService {
private final CurrencyReadPlatformService currencyReadPlatformService; private final CurrencyReadPlatformService currencyReadPlatformService;
@Autowired @Autowired
public ConfigurationReadPlatformServiceImpl(final CurrencyReadPlatformService currencyReadPlatformService) { public ConfigurationReadPlatformServiceImpl(final CurrencyReadPlatformService currencyReadPlatformService) {
this.currencyReadPlatformService = currencyReadPlatformService; this.currencyReadPlatformService = currencyReadPlatformService;
} }
@Override @Override
public ConfigurationData retrieveCurrencyConfiguration() { public ConfigurationData retrieveCurrencyConfiguration() {
List<CurrencyData> selectedCurrencyOptions = new ArrayList<CurrencyData>(this.currencyReadPlatformService.retrieveAllowedCurrencies());
List<CurrencyData> currencyOptions = new ArrayList<CurrencyData>(this.currencyReadPlatformService.retrieveAllPlatformCurrencies());
// remove selected currency options List<CurrencyData> selectedCurrencyOptions = new ArrayList<CurrencyData>(
currencyOptions.removeAll(selectedCurrencyOptions); this.currencyReadPlatformService.retrieveAllowedCurrencies());
List<CurrencyData> currencyOptions = new ArrayList<CurrencyData>(this.currencyReadPlatformService.retrieveAllPlatformCurrencies());
ConfigurationData configurationData = new ConfigurationData(currencyOptions, selectedCurrencyOptions);
// remove selected currency options
return configurationData; currencyOptions.removeAll(selectedCurrencyOptions);
}
ConfigurationData configurationData = new ConfigurationData(currencyOptions, selectedCurrencyOptions);
return configurationData;
}
} }
@@ -5,7 +5,7 @@ import org.springframework.security.access.prepost.PreAuthorize;
public interface ConfigurationWritePlatformService { public interface ConfigurationWritePlatformService {
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'ORGANISATION_ADMINISTRATION_SUPER_USER', 'UPDATE_CURRENCY')") @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'ORGANISATION_ADMINISTRATION_SUPER_USER', 'UPDATE_CURRENCY')")
void updateOrganisationCurrencies(OrganisationCurrencyCommand command); void updateOrganisationCurrencies(OrganisationCurrencyCommand command);
} }
@@ -21,54 +21,53 @@ import org.springframework.transaction.annotation.Transactional;
@Service @Service
public class ConfigurationWritePlatformServiceJpaRepositoryImpl implements ConfigurationWritePlatformService { public class ConfigurationWritePlatformServiceJpaRepositoryImpl implements ConfigurationWritePlatformService {
private final PlatformSecurityContext context; private final PlatformSecurityContext context;
private final ApplicationCurrencyRepository applicationCurrencyRepository; private final ApplicationCurrencyRepository applicationCurrencyRepository;
private final OrganisationCurrencyRepository organisationCurrencyRepository; private final OrganisationCurrencyRepository organisationCurrencyRepository;
@Autowired @Autowired
public ConfigurationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, public ConfigurationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
final ApplicationCurrencyRepository applicationCurrencyRepository, final OrganisationCurrencyRepository organisationCurrencyRepository) { final ApplicationCurrencyRepository applicationCurrencyRepository,
this.context = context; final OrganisationCurrencyRepository organisationCurrencyRepository) {
this.applicationCurrencyRepository = applicationCurrencyRepository; this.context = context;
this.organisationCurrencyRepository = organisationCurrencyRepository; this.applicationCurrencyRepository = applicationCurrencyRepository;
} this.organisationCurrencyRepository = organisationCurrencyRepository;
}
@Transactional
@Override
public void updateOrganisationCurrencies(final OrganisationCurrencyCommand command) {
context.authenticatedUser();
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("configuration");
baseDataValidator.reset().parameter("currencies").value(command.getCurrencies()).arrayNotEmpty();
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors);
}
Set<OrganisationCurrency> allowedCurrencies = new HashSet<OrganisationCurrency>();
for (String currencyCode : command.getCurrencies()) { @Transactional
@Override
public void updateOrganisationCurrencies(final OrganisationCurrencyCommand command) {
ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(currencyCode); context.authenticatedUser();
if (currency == null) {
baseDataValidator.reset().parameter("currencies").value(command.getCurrencies()).inValidValue("currency.code", currencyCode);
} else {
OrganisationCurrency allowedCurrency = new OrganisationCurrency(
currency.getCode(), currency.getName(),
currency.getDecimalPlaces(), currency.getNameCode(), currency.getDisplaySymbol());
allowedCurrencies.add(allowedCurrency); List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
} DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("configuration");
}
baseDataValidator.reset().parameter("currencies").value(command.getCurrencies()).arrayNotEmpty();
this.organisationCurrencyRepository.deleteAll();
this.organisationCurrencyRepository.save(allowedCurrencies); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors); Set<OrganisationCurrency> allowedCurrencies = new HashSet<OrganisationCurrency>();
}
} for (String currencyCode : command.getCurrencies()) {
ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(currencyCode);
if (currency == null) {
baseDataValidator.reset().parameter("currencies").value(command.getCurrencies())
.inValidValue("currency.code", currencyCode);
} else {
OrganisationCurrency allowedCurrency = new OrganisationCurrency(currency.getCode(), currency.getName(),
currency.getDecimalPlaces(), currency.getNameCode(), currency.getDisplaySymbol());
allowedCurrencies.add(allowedCurrency);
}
}
this.organisationCurrencyRepository.deleteAll();
this.organisationCurrencyRepository.save(allowedCurrencies);
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
}
} }
@@ -131,4 +131,8 @@ public class CommandSource extends AbstractPersistable<Long> {
public boolean isRoleResource() { public boolean isRoleResource() {
return this.resource.equalsIgnoreCase("ROLES"); return this.resource.equalsIgnoreCase("ROLES");
} }
public boolean isUserResource() {
return this.resource.equalsIgnoreCase("USERS");
}
} }
@@ -85,6 +85,8 @@ public class ClientCommandHandler implements CommandSourceHandler {
public CommandSource handle(final CommandSource commandSourceResult) { public CommandSource handle(final CommandSource commandSourceResult) {
final AppUser checker = context.authenticatedUser();
Long resourceId = null; Long resourceId = null;
if (commandSourceResult.isClientResource()) { if (commandSourceResult.isClientResource()) {
final ClientCommand command = this.apiDataConversionService.convertInternalJsonFormatToClientCommand( final ClientCommand command = this.apiDataConversionService.convertInternalJsonFormatToClientCommand(
@@ -92,16 +94,15 @@ public class ClientCommandHandler implements CommandSourceHandler {
if (commandSourceResult.isCreate()) { if (commandSourceResult.isCreate()) {
resourceId = this.clientWritePlatformService.createClient(command); resourceId = this.clientWritePlatformService.createClient(command);
commandSourceResult.markAsChecked(checker, new LocalDate());
} else if (commandSourceResult.isUpdate()) { } else if (commandSourceResult.isUpdate()) {
// TODO - is there a case for doing change detection at this
// point also?
EntityIdentifier result = this.clientWritePlatformService.updateClientDetails(command); EntityIdentifier result = this.clientWritePlatformService.updateClientDetails(command);
resourceId = result.getEntityId(); resourceId = result.getEntityId();
commandSourceResult.markAsChecked(checker, new LocalDate());
} else if (commandSourceResult.isDelete()) { } else if (commandSourceResult.isDelete()) {
EntityIdentifier result = this.clientWritePlatformService.deleteClient(command); EntityIdentifier result = this.clientWritePlatformService.deleteClient(command);
resourceId = result.getEntityId(); resourceId = result.getEntityId();
commandSourceResult.markAsChecked(checker, new LocalDate());
} }
} }
@@ -15,14 +15,17 @@ public class CommandSourceHandlerDelegator {
private final PlatformSecurityContext context; private final PlatformSecurityContext context;
private final ClientCommandHandler clientCommandHandler; private final ClientCommandHandler clientCommandHandler;
private final RoleCommandHandler roleCommandHandler; private final RoleCommandHandler roleCommandHandler;
private final UserCommandHandler userCommandHandler;
@Autowired @Autowired
public CommandSourceHandlerDelegator(final PlatformSecurityContext context, public CommandSourceHandlerDelegator(final PlatformSecurityContext context,
final ClientCommandHandler clientCommandHandler, final ClientCommandHandler clientCommandHandler,
final RoleCommandHandler roleCommandHandler) { final RoleCommandHandler roleCommandHandler,
final UserCommandHandler userCommandHandler) {
this.context = context; this.context = context;
this.clientCommandHandler = clientCommandHandler; this.clientCommandHandler = clientCommandHandler;
this.roleCommandHandler = roleCommandHandler; this.roleCommandHandler = roleCommandHandler;
this.userCommandHandler = userCommandHandler;
} }
public CommandSource handle(final CommandSource commandSource, final String apiRequestBodyInJson) { public CommandSource handle(final CommandSource commandSource, final String apiRequestBodyInJson) {
@@ -33,13 +36,15 @@ public class CommandSourceHandlerDelegator {
commandSourceResult = clientCommandHandler.handle(commandSource, apiRequestBodyInJson); commandSourceResult = clientCommandHandler.handle(commandSource, apiRequestBodyInJson);
} else if (commandSource.isRoleResource()) { } else if (commandSource.isRoleResource()) {
commandSourceResult = roleCommandHandler.handle(commandSource, apiRequestBodyInJson); commandSourceResult = roleCommandHandler.handle(commandSource, apiRequestBodyInJson);
} else if (commandSource.isUserResource()) {
commandSourceResult = userCommandHandler.handle(commandSource, apiRequestBodyInJson);
} else { } else {
throw new UnsupportedCommandException(commandSource.commandName()); throw new UnsupportedCommandException(commandSource.commandName());
} }
return commandSourceResult; return commandSourceResult;
} }
public CommandSource handleExistingCommand(final CommandSource commandSource) { public CommandSource handleExistingCommand(final CommandSource commandSource) {
CommandSource commandSourceResult = null; CommandSource commandSourceResult = null;
@@ -47,6 +52,8 @@ public class CommandSourceHandlerDelegator {
commandSourceResult = clientCommandHandler.handle(commandSource); commandSourceResult = clientCommandHandler.handle(commandSource);
} else if (commandSource.isRoleResource()) { } else if (commandSource.isRoleResource()) {
commandSourceResult = roleCommandHandler.handle(commandSource); commandSourceResult = roleCommandHandler.handle(commandSource);
} else if (commandSource.isUserResource()) {
commandSourceResult = userCommandHandler.handle(commandSource);
} else { } else {
throw new UnsupportedCommandException(commandSource.commandName()); throw new UnsupportedCommandException(commandSource.commandName());
} }
@@ -44,13 +44,10 @@ public class PortfolioCommandSourceWriteServiceImpl implements PortfolioCommandS
@Override @Override
public EntityIdentifier approveEntry(final Long id) { public EntityIdentifier approveEntry(final Long id) {
final AppUser checker = context.authenticatedUser(); context.authenticatedUser();
final CommandSource commandSourceInput = this.commandSourceRepository.findOne(id); final CommandSource commandSourceInput = this.commandSourceRepository.findOne(id);
commandSourceInput.markAsChecked(checker, new LocalDate());
final CommandSource commandSourceResult = this.commandSourceHandlerDelegator.handleExistingCommand(commandSourceInput); final CommandSource commandSourceResult = this.commandSourceHandlerDelegator.handleExistingCommand(commandSourceInput);
commandSourceRepository.save(commandSourceResult); commandSourceRepository.save(commandSourceResult);
return EntityIdentifier.makerChecker(commandSourceResult.resourceId(), commandSourceResult.getId()); return EntityIdentifier.makerChecker(commandSourceResult.resourceId(), commandSourceResult.getId());
@@ -112,17 +112,22 @@ public class RoleCommandHandler implements CommandSourceHandler {
*/ */
public CommandSource handle(final CommandSource commandSourceResult) { public CommandSource handle(final CommandSource commandSourceResult) {
final AppUser checker = context.authenticatedUser();
Long resourceId = commandSourceResult.resourceId(); Long resourceId = commandSourceResult.resourceId();
if (commandSourceResult.isRoleResource()) { if (commandSourceResult.isRoleResource()) {
if (commandSourceResult.isCreate()) { if (commandSourceResult.isCreate()) {
final RoleCommand command = this.commandDeserializerService.deserializeRoleCommand(resourceId, commandSourceResult.json(), true); final RoleCommand command = this.commandDeserializerService.deserializeRoleCommand(resourceId, commandSourceResult.json(), true);
resourceId = this.writePlatformService.createRole(command); resourceId = this.writePlatformService.createRole(command);
commandSourceResult.markAsChecked(checker, new LocalDate());
} else if (commandSourceResult.isUpdate()) { } else if (commandSourceResult.isUpdate()) {
final RoleCommand command = this.commandDeserializerService.deserializeRoleCommand(resourceId, commandSourceResult.json(), true); final RoleCommand command = this.commandDeserializerService.deserializeRoleCommand(resourceId, commandSourceResult.json(), true);
resourceId = this.writePlatformService.updateRole(command); resourceId = this.writePlatformService.updateRole(command);
commandSourceResult.markAsChecked(checker, new LocalDate());
} else if (commandSourceResult.isUpdateRolePermissions()) { } else if (commandSourceResult.isUpdateRolePermissions()) {
final RolePermissionCommand command = this.commandDeserializerService.deserializeRolePermissionCommand(resourceId, commandSourceResult.json(), true); final RolePermissionCommand command = this.commandDeserializerService.deserializeRolePermissionCommand(resourceId, commandSourceResult.json(), true);
resourceId =this.writePlatformService.updateRolePermissions(command); resourceId =this.writePlatformService.updateRolePermissions(command);
commandSourceResult.markAsChecked(checker, new LocalDate());
} else if (commandSourceResult.isDelete()) { } else if (commandSourceResult.isDelete()) {
throw new UnsupportedCommandException(commandSourceResult.commandName()); throw new UnsupportedCommandException(commandSourceResult.commandName());
} }
@@ -0,0 +1,135 @@
package org.mifosng.platform.makerchecker.service;
import org.joda.time.LocalDate;
import org.mifosng.platform.api.commands.UserCommand;
import org.mifosng.platform.api.infrastructure.PortfolioApiDataConversionService;
import org.mifosng.platform.api.infrastructure.PortfolioCommandDeserializerService;
import org.mifosng.platform.api.infrastructure.PortfolioCommandSerializerService;
import org.mifosng.platform.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException;
import org.mifosng.platform.makerchecker.domain.CommandSource;
import org.mifosng.platform.security.PlatformSecurityContext;
import org.mifosng.platform.user.domain.AppUser;
import org.mifosng.platform.user.service.AppUserWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserCommandHandler implements CommandSourceHandler {
private final PlatformSecurityContext context;
private final ChangeDetectionService changeDetectionService;
private final PortfolioApiDataConversionService apiDataConversionService;
private final PortfolioCommandSerializerService commandSerializerService;
private final PortfolioCommandDeserializerService commandDeserializerService;
private final AppUserWritePlatformService writePlatformService;
@Autowired
public UserCommandHandler(final PlatformSecurityContext context, final ChangeDetectionService changeDetectionService,
final PortfolioApiDataConversionService apiDataConversionService,
final PortfolioCommandSerializerService commandSerializerService,
final PortfolioCommandDeserializerService commandDeserializerService,
final AppUserWritePlatformService writePlatformService) {
this.context = context;
this.changeDetectionService = changeDetectionService;
this.apiDataConversionService = apiDataConversionService;
this.commandSerializerService = commandSerializerService;
this.commandDeserializerService = commandDeserializerService;
this.writePlatformService = writePlatformService;
}
/*
* Used when users with 'create' capability create a command. If 'maker-checker' is not
* enabled for this specific command then the 'creator' is also marked 'as the checker' and command
* automatically is processed and changes state of system.
*/
public CommandSource handle(final CommandSource commandSource, final String apiRequestBodyInJson) {
final AppUser maker = context.authenticatedUser();
final LocalDate asToday = new LocalDate();
CommandSource commandSourceResult = commandSource.copy();
final Long resourceId = commandSource.resourceId();
if (commandSource.isCreate()) {
try {
final UserCommand command = this.apiDataConversionService.convertApiRequestJsonToUserCommand(null, apiRequestBodyInJson);
final String commandSerializedAsJson = this.commandSerializerService.serializeUserCommandToJson(command);
commandSourceResult.updateJsonTo(commandSerializedAsJson);
Long newResourceId = this.writePlatformService.createUser(command);
commandSourceResult.markAsChecked(maker, asToday);
commandSourceResult.updateResourceId(newResourceId);
} catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) {
// swallow this rollback transaction by design
}
} else if (commandSource.isUpdate()) {
try {
final UserCommand command = this.apiDataConversionService.convertApiRequestJsonToUserCommand(resourceId, apiRequestBodyInJson);
final String commandSerializedAsJson = this.commandSerializerService.serializeUserCommandToJson(command);
commandSourceResult.updateJsonTo(commandSerializedAsJson);
final String jsonOfChangesOnly = this.changeDetectionService.detectChangesOnUpdate(commandSource.resourceName(), commandSource.resourceId(), commandSerializedAsJson);
commandSourceResult.updateJsonTo(jsonOfChangesOnly);
final UserCommand changesOnly = this.commandDeserializerService.deserializeUserCommand(resourceId, jsonOfChangesOnly, false);
if (maker.hasIdOf(command.getId())) {
this.writePlatformService.updateUsersOwnAccountDetails(changesOnly);
} else {
this.writePlatformService.updateUser(changesOnly);
}
commandSourceResult.markAsChecked(maker, asToday);
} catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) {
// swallow this rollback transaction by design
}
} else if (commandSource.isDelete()) {
try {
final UserCommand command = this.apiDataConversionService.convertApiRequestJsonToUserCommand(resourceId, apiRequestBodyInJson);
final String commandSerializedAsJson = this.commandSerializerService.serializeUserCommandToJson(command);
commandSourceResult.updateJsonTo(commandSerializedAsJson);
this.writePlatformService.deleteUser(command);
commandSourceResult.markAsChecked(maker, asToday);
} catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) {
// swallow this rollback transaction by design
}
}
return commandSourceResult;
}
/*
* Used when users with 'checker' capability approve a command.
*/
public CommandSource handle(final CommandSource commandSourceResult) {
final AppUser checker = context.authenticatedUser();
Long resourceId = commandSourceResult.resourceId();
if (commandSourceResult.isUserResource()) {
if (commandSourceResult.isCreate()) {
final UserCommand command = this.commandDeserializerService.deserializeUserCommand(resourceId, commandSourceResult.json(), true);
resourceId = this.writePlatformService.createUser(command);
commandSourceResult.updateResourceId(resourceId);
commandSourceResult.markAsChecked(checker, new LocalDate());
} else if (commandSourceResult.isUpdate()) {
final UserCommand command = this.commandDeserializerService.deserializeUserCommand(resourceId, commandSourceResult.json(), true);
if (checker.hasIdOf(command.getId())) {
this.writePlatformService.updateUsersOwnAccountDetails(command);
} else {
this.writePlatformService.updateUser(command);
}
commandSourceResult.markAsChecked(checker, new LocalDate());
} else if (commandSourceResult.isDelete()) {
final UserCommand command = this.commandDeserializerService.deserializeUserCommand(resourceId, commandSourceResult.json(), true);
this.writePlatformService.deleteUser(command);
commandSourceResult.markAsChecked(checker, new LocalDate());
}
}
return commandSourceResult;
}
}
@@ -1,5 +1,6 @@
package org.mifosng.platform.user.domain; package org.mifosng.platform.user.domain;
import org.mifosng.platform.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException;
import org.mifosng.platform.infrastructure.EmailDetail; import org.mifosng.platform.infrastructure.EmailDetail;
import org.mifosng.platform.infrastructure.PlatformEmailService; import org.mifosng.platform.infrastructure.PlatformEmailService;
import org.mifosng.platform.infrastructure.PlatformPasswordEncoder; import org.mifosng.platform.infrastructure.PlatformPasswordEncoder;
@@ -11,37 +12,46 @@ import org.springframework.transaction.annotation.Transactional;
@Service @Service
public class JpaUserDomainService implements UserDomainService { public class JpaUserDomainService implements UserDomainService {
private final AppUserRepository userRepository;
private final PlatformPasswordEncoder applicationPasswordEncoder;
private final PlatformEmailService emailService;
private final PermissionRepository permissionRepository;
@Autowired @Autowired
private AppUserRepository userRepository; public JpaUserDomainService(final AppUserRepository userRepository, final PlatformPasswordEncoder applicationPasswordEncoder,
final PlatformEmailService emailService, final PermissionRepository permissionRepository) {
@Autowired this.userRepository = userRepository;
private PlatformPasswordEncoder applicationPasswordEncoder; this.applicationPasswordEncoder = applicationPasswordEncoder;
this.emailService = emailService;
@Autowired this.permissionRepository = permissionRepository;
private PlatformEmailService emailService; }
@Transactional @Transactional
@Override @Override
public void create(final AppUser appUser) { public void create(final AppUser appUser, final boolean isApprovedByChecker) {
generateKeyUsedForPasswordSalting(appUser); generateKeyUsedForPasswordSalting(appUser);
String unencodedPassword = appUser.getPassword(); String unencodedPassword = appUser.getPassword();
if (org.apache.commons.lang.StringUtils.isBlank(unencodedPassword) || "autogenerate".equalsIgnoreCase(unencodedPassword)) { if (org.apache.commons.lang.StringUtils.isBlank(unencodedPassword) || "autogenerate".equalsIgnoreCase(unencodedPassword)) {
unencodedPassword = new RandomPasswordGenerator(13).generate(); unencodedPassword = new RandomPasswordGenerator(13).generate();
appUser.updatePassword(unencodedPassword); appUser.updatePassword(unencodedPassword);
} }
String encodePassword = this.applicationPasswordEncoder.encode(appUser);
appUser.updatePassword(encodePassword);
this.userRepository.save(appUser); final String encodePassword = this.applicationPasswordEncoder.encode(appUser);
appUser.updatePassword(encodePassword);
this.userRepository.save(appUser);
EmailDetail emailDetail = new EmailDetail(appUser.getFirstname(), appUser.getFirstname(), appUser.getEmail(), appUser.getUsername()); final Permission thisTask = this.permissionRepository.findOneByCode("CREATE_USER");
if (thisTask.hasMakerCheckerEnabled() && !isApprovedByChecker) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); }
final EmailDetail emailDetail = new EmailDetail(appUser.getFirstname(), appUser.getFirstname(), appUser.getEmail(), appUser.getUsername());
this.emailService.sendToUserAccount(emailDetail, unencodedPassword); this.emailService.sendToUserAccount(emailDetail, unencodedPassword);
} }
private void generateKeyUsedForPasswordSalting(final AppUser appUser) { private void generateKeyUsedForPasswordSalting(final AppUser appUser) {
this.userRepository.save(appUser); this.userRepository.save(appUser);
} }
} }
@@ -25,15 +25,15 @@ public class Permission extends AbstractPersistable<Long> {
@Column(name = "action_name", nullable = true, length = 100) @Column(name = "action_name", nullable = true, length = 100)
private final String actionName; private final String actionName;
@SuppressWarnings("unused")
@Column(name = "can_maker_checker", nullable = false) @Column(name = "can_maker_checker", nullable = false)
private Boolean canMakerChecker; private final boolean canMakerChecker;
protected Permission() { protected Permission() {
this.grouping = null; this.grouping = null;
this.code = null; this.code = null;
this.entityName = null; this.entityName = null;
this.actionName = null; this.actionName = null;
this.canMakerChecker = false;
} }
public boolean hasCode(final String checkCode) { public boolean hasCode(final String checkCode) {
@@ -43,4 +43,8 @@ public class Permission extends AbstractPersistable<Long> {
public String code() { public String code() {
return this.code; return this.code;
} }
public boolean hasMakerCheckerEnabled() {
return this.canMakerChecker;
}
} }
@@ -3,5 +3,6 @@ package org.mifosng.platform.user.domain;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
public interface PermissionRepository extends JpaRepository<Permission, Long> { public interface PermissionRepository extends JpaRepository<Permission, Long> {
// no added behaviour
Permission findOneByCode(String code);
} }
@@ -2,5 +2,5 @@ package org.mifosng.platform.user.domain;
public interface UserDomainService { public interface UserDomainService {
void create(AppUser appUser); void create(AppUser appUser, boolean isApprovedByChecker);
} }
@@ -6,15 +6,15 @@ import org.springframework.security.access.prepost.PreAuthorize;
public interface AppUserWritePlatformService { public interface AppUserWritePlatformService {
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'USER_ADMINISTRATION_SUPER_USER', 'CREATE_USER')") @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'USER_ADMINISTRATION_SUPER_USER', 'CREATE_USER')")
Long createUser(final UserCommand command); Long createUser(UserCommand command);
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'USER_ADMINISTRATION_SUPER_USER', 'UPDATE_USER')") @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'USER_ADMINISTRATION_SUPER_USER', 'UPDATE_USER')")
Long updateUser(final UserCommand command); Long updateUser(UserCommand command);
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'USER_ADMINISTRATION_SUPER_USER', 'DELETE_USER')") @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'USER_ADMINISTRATION_SUPER_USER', 'DELETE_USER')")
void deleteUser(final Long userId); void deleteUser(UserCommand command);
// we dont put any permissions on this e.g. a user with no admin rights can // we dont put any permissions on this e.g. a user with no admin rights can
// change their own details (email, username, password etc). // change their own details (email, username, password etc).
void updateUsersOwnAccountDetails(UserCommand command); Long updateUsersOwnAccountDetails(UserCommand command);
} }
@@ -8,6 +8,7 @@ import java.util.Set;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.mifosng.platform.api.commands.UserCommand; import org.mifosng.platform.api.commands.UserCommand;
import org.mifosng.platform.api.data.ApiParameterError; import org.mifosng.platform.api.data.ApiParameterError;
import org.mifosng.platform.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException;
import org.mifosng.platform.exceptions.OfficeNotFoundException; import org.mifosng.platform.exceptions.OfficeNotFoundException;
import org.mifosng.platform.exceptions.PlatformApiDataValidationException; import org.mifosng.platform.exceptions.PlatformApiDataValidationException;
import org.mifosng.platform.exceptions.PlatformDataIntegrityException; import org.mifosng.platform.exceptions.PlatformDataIntegrityException;
@@ -22,6 +23,8 @@ import org.mifosng.platform.organisation.domain.OfficeRepository;
import org.mifosng.platform.security.PlatformSecurityContext; import org.mifosng.platform.security.PlatformSecurityContext;
import org.mifosng.platform.user.domain.AppUser; import org.mifosng.platform.user.domain.AppUser;
import org.mifosng.platform.user.domain.AppUserRepository; import org.mifosng.platform.user.domain.AppUserRepository;
import org.mifosng.platform.user.domain.Permission;
import org.mifosng.platform.user.domain.PermissionRepository;
import org.mifosng.platform.user.domain.Role; import org.mifosng.platform.user.domain.Role;
import org.mifosng.platform.user.domain.RoleRepository; import org.mifosng.platform.user.domain.RoleRepository;
import org.mifosng.platform.user.domain.UserDomainService; import org.mifosng.platform.user.domain.UserDomainService;
@@ -44,17 +47,19 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
private final AppUserRepository appUserRepository; private final AppUserRepository appUserRepository;
private final OfficeRepository officeRepository; private final OfficeRepository officeRepository;
private final RoleRepository roleRepository; private final RoleRepository roleRepository;
private final PermissionRepository permissionRepository;
@Autowired @Autowired
public AppUserWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final AppUserRepository appUserRepository, public AppUserWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final AppUserRepository appUserRepository,
final UserDomainService userDomainService, final OfficeRepository officeRepository, final RoleRepository roleRepository, final UserDomainService userDomainService, final OfficeRepository officeRepository, final RoleRepository roleRepository,
final PlatformPasswordEncoder platformPasswordEncoder) { final PlatformPasswordEncoder platformPasswordEncoder, final PermissionRepository permissionRepository) {
this.context = context; this.context = context;
this.appUserRepository = appUserRepository; this.appUserRepository = appUserRepository;
this.userDomainService = userDomainService; this.userDomainService = userDomainService;
this.officeRepository = officeRepository; this.officeRepository = officeRepository;
this.roleRepository = roleRepository; this.roleRepository = roleRepository;
this.platformPasswordEncoder = platformPasswordEncoder; this.platformPasswordEncoder = platformPasswordEncoder;
this.permissionRepository = permissionRepository;
} }
@Transactional @Transactional
@@ -64,12 +69,12 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
try { try {
context.authenticatedUser(); context.authenticatedUser();
UserCommandValidator validator = new UserCommandValidator(command); final UserCommandValidator validator = new UserCommandValidator(command);
validator.validateForCreate(); validator.validateForCreate();
final Set<Role> allRoles = assembleSetOfRoles(command); final Set<Role> allRoles = assembleSetOfRoles(command);
Office office = this.officeRepository.findOne(command.getOfficeId()); final Office office = this.officeRepository.findOne(command.getOfficeId());
if (office == null) { throw new OfficeNotFoundException(command.getOfficeId()); } if (office == null) { throw new OfficeNotFoundException(command.getOfficeId()); }
String password = command.getPassword(); String password = command.getPassword();
@@ -77,17 +82,17 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
password = "autogenerate"; password = "autogenerate";
} }
AppUser appUser = AppUser.createNew(office, allRoles, command.getUsername(), command.getEmail(), command.getFirstname(), final AppUser appUser = AppUser.createNew(office, allRoles, command.getUsername(), command.getEmail(), command.getFirstname(),
command.getLastname(), password); command.getLastname(), password);
this.userDomainService.create(appUser); this.userDomainService.create(appUser, command.isApprovedByChecker());
return appUser.getId(); return appUser.getId();
} catch (DataIntegrityViolationException dve) { } catch (DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve); handleDataIntegrityIssues(command, dve);
return Long.valueOf(-1); return Long.valueOf(-1);
} catch (PlatformEmailSendException e) { } catch (PlatformEmailSendException e) {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>(); final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
ApiParameterError error = ApiParameterError.parameterError("error.msg.user.email.invalid", "The parameter email is invalid.", ApiParameterError error = ApiParameterError.parameterError("error.msg.user.email.invalid", "The parameter email is invalid.",
"email", command.getEmail()); "email", command.getEmail());
dataValidationErrors.add(error); dataValidationErrors.add(error);
@@ -103,10 +108,10 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
try { try {
context.authenticatedUser(); context.authenticatedUser();
UserCommandValidator validator = new UserCommandValidator(command); UserCommandValidator validator = new UserCommandValidator(command);
validator.validateForUpdate(); validator.validateForUpdate();
final Set<Role> allRoles = assembleSetOfRoles(command); final Set<Role> allRoles = assembleSetOfRoles(command);
Office office = null; Office office = null;
@@ -115,7 +120,7 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
if (office == null) { throw new OfficeNotFoundException(command.getOfficeId()); } if (office == null) { throw new OfficeNotFoundException(command.getOfficeId()); }
} }
AppUser userToUpdate = this.appUserRepository.findOne(command.getId()); final AppUser userToUpdate = this.appUserRepository.findOne(command.getId());
if (userToUpdate == null) { throw new UserNotFoundException(command.getId()); } if (userToUpdate == null) { throw new UserNotFoundException(command.getId()); }
userToUpdate.update(allRoles, office, command); userToUpdate.update(allRoles, office, command);
@@ -131,6 +136,9 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
this.appUserRepository.saveAndFlush(userToUpdate); this.appUserRepository.saveAndFlush(userToUpdate);
} }
final Permission thisTask = this.permissionRepository.findOneByCode("UPDATE_USER");
if (thisTask.hasMakerCheckerEnabled() && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); }
return userToUpdate.getId(); return userToUpdate.getId();
} catch (DataIntegrityViolationException dve) { } catch (DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve); handleDataIntegrityIssues(command, dve);
@@ -138,10 +146,50 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
} }
} }
/**
* Different between this and <code>updateUser</code> is that we dont do
* maker-checker flow or require that user have particular permission to
* change their own details.
*/
@Transactional @Transactional
@Override @Override
public void updateUsersOwnAccountDetails(final UserCommand command) { public Long updateUsersOwnAccountDetails(final UserCommand command) {
updateUser(command);
try {
context.authenticatedUser();
UserCommandValidator validator = new UserCommandValidator(command);
validator.validateForUpdate();
final Set<Role> allRoles = assembleSetOfRoles(command);
Office office = null;
if (command.isOfficeChanged()) {
office = this.officeRepository.findOne(command.getOfficeId());
if (office == null) { throw new OfficeNotFoundException(command.getOfficeId()); }
}
final AppUser userToUpdate = this.appUserRepository.findOne(command.getId());
if (userToUpdate == null) { throw new UserNotFoundException(command.getId()); }
userToUpdate.update(allRoles, office, command);
this.appUserRepository.saveAndFlush(userToUpdate);
if (command.isPasswordChanged()) {
PlatformUser dummyPlatformUser = new BasicPasswordEncodablePlatformUser(userToUpdate.getId(), userToUpdate.getUsername(),
command.getPassword());
String newPasswordEncoded = this.platformPasswordEncoder.encode(dummyPlatformUser);
userToUpdate.updatePassword(newPasswordEncoded);
this.appUserRepository.saveAndFlush(userToUpdate);
}
return userToUpdate.getId();
} catch (DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve);
return Long.valueOf(-1);
}
} }
private Set<Role> assembleSetOfRoles(final UserCommand command) { private Set<Role> assembleSetOfRoles(final UserCommand command) {
@@ -163,13 +211,18 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
@Transactional @Transactional
@Override @Override
public void deleteUser(final Long userId) { public void deleteUser(final UserCommand command) {
final Permission permissionForThisTask = this.permissionRepository.findOneByCode("UPDATE_USER");
final Long userId = command.getId();
AppUser user = this.appUserRepository.findOne(userId); AppUser user = this.appUserRepository.findOne(userId);
if (user == null || user.isDeleted()) { throw new UserNotFoundException(userId); } if (user == null || user.isDeleted()) { throw new UserNotFoundException(userId); }
user.delete(); user.delete();
this.appUserRepository.save(user); this.appUserRepository.save(user);
if (permissionForThisTask.hasMakerCheckerEnabled() && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); }
} }
/* /*
@@ -24,10 +24,6 @@ public class RoleWritePlatformServiceJpaRepositoryImpl implements RoleWritePlatf
private final RoleRepository roleRepository; private final RoleRepository roleRepository;
private final PermissionRepository permissionRepository; private final PermissionRepository permissionRepository;
// FIXME - kw - this value is hardcoded for now but will be retrieved from
// configuration
private boolean makerCheckerEnabledForTask = true;
@Autowired @Autowired
public RoleWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final RoleRepository roleRepository, public RoleWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final RoleRepository roleRepository,
final PermissionRepository permissionRepository) { final PermissionRepository permissionRepository) {
@@ -42,15 +38,16 @@ public class RoleWritePlatformServiceJpaRepositoryImpl implements RoleWritePlatf
context.authenticatedUser(); context.authenticatedUser();
RoleCommandValidator validator = new RoleCommandValidator(command); final RoleCommandValidator validator = new RoleCommandValidator(command);
validator.validateForCreate(); validator.validateForCreate();
Role entity = new Role(command.getName(), command.getDescription()); final Role entity = new Role(command.getName(), command.getDescription());
this.roleRepository.save(entity); this.roleRepository.save(entity);
if (this.makerCheckerEnabledForTask && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } final Permission thisTask = this.permissionRepository.findOneByCode("CREATE_ROLE");
if (thisTask.hasMakerCheckerEnabled() && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); }
return entity.getId(); return entity.getId();
} }
@@ -60,16 +57,17 @@ public class RoleWritePlatformServiceJpaRepositoryImpl implements RoleWritePlatf
context.authenticatedUser(); context.authenticatedUser();
RoleCommandValidator validator = new RoleCommandValidator(command); final RoleCommandValidator validator = new RoleCommandValidator(command);
validator.validateForUpdate(); validator.validateForUpdate();
Role role = this.roleRepository.findOne(command.getId()); final Role role = this.roleRepository.findOne(command.getId());
if (role == null) { throw new RoleNotFoundException(command.getId()); } if (role == null) { throw new RoleNotFoundException(command.getId()); }
role.update(command); role.update(command);
this.roleRepository.save(role); this.roleRepository.save(role);
if (this.makerCheckerEnabledForTask && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } final Permission thisTask = this.permissionRepository.findOneByCode("UPDATE_ROLE");
if (thisTask.hasMakerCheckerEnabled() && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); }
return role.getId(); return role.getId();
} }
@@ -98,8 +96,9 @@ public class RoleWritePlatformServiceJpaRepositoryImpl implements RoleWritePlatf
this.roleRepository.save(role); this.roleRepository.save(role);
if (this.makerCheckerEnabledForTask && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } final Permission thisTask = this.permissionRepository.findOneByCode("PERMISSIONS_ROLE");
if (thisTask.hasMakerCheckerEnabled() && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); }
return role.getId(); return role.getId();
} }
@@ -18,10 +18,8 @@
<logger name="org.mifosng.platform" level="debug" /> <logger name="org.mifosng.platform" level="debug" />
<logger name="org.springframework.web" level="debug" /> <logger name="org.springframework.web" level="info" />
<logger name="org.springframework.beans" level="debug" /> <logger name="org.springframework.beans" level="debug" />
<logger name="org.springframework.orm" level="debug" />
<logger name="org.springframework.web" level="debug" />
<logger name="net.sf.ehcache" level="error" /> <logger name="net.sf.ehcache" level="error" />
<logger name="org.hibernate.cache" level="error" /> <logger name="org.hibernate.cache" level="error" />