diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/CommandsApiResource.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/CommandsApiResource.java index 40f4abeba..361713fe6 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/CommandsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/CommandsApiResource.java @@ -33,66 +33,63 @@ import org.springframework.stereotype.Component; @Scope("singleton") public class CommandsApiResource { - @Autowired - private PortfolioCommandsReadPlatformService readPlatformService; - - @Autowired - private PortfolioCommandSourceWritePlatformService writePlatformService; + @Autowired + private PortfolioCommandsReadPlatformService readPlatformService; - @Autowired - private PortfolioApiJsonSerializerService apiJsonSerializerService; + @Autowired + private PortfolioCommandSourceWritePlatformService writePlatformService; - private final String entityType = "MAKERCHECKER"; + @Autowired + private PortfolioApiJsonSerializerService apiJsonSerializerService; + + private final String entityType = "MAKERCHECKER"; @Autowired private PlatformSecurityContext context; - - @GET - @Consumes({MediaType.APPLICATION_JSON}) - @Produces({MediaType.APPLICATION_JSON}) - public String retrieveCodes(@Context final UriInfo uriInfo) { - context.authenticatedUser().validateHasReadPermission(entityType); - - final Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); - final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); - - final Collection 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) { + @GET + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveCodes(@Context final UriInfo uriInfo) { - EntityIdentifier result = null; - if (is(commandParam, "approve")) { - result = this.writePlatformService.approveEntry(makerCheckerId); - } else { - throw new UnrecognizedQueryParamException("command", commandParam); - } + context.authenticatedUser().validateHasReadPermission(entityType); - return this.apiJsonSerializerService.serializeEntityIdentifier(result); - } + final Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); + final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); - 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 Collection entries = this.readPlatformService.retrieveAllEntriesToBeChecked(); - 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)); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/ConfigurationApiResource.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/ConfigurationApiResource.java index 61d03879a..7eaa40f54 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/ConfigurationApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/ConfigurationApiResource.java @@ -31,53 +31,52 @@ import org.springframework.stereotype.Component; @Scope("singleton") public class ConfigurationApiResource { - @Autowired - private ConfigurationReadPlatformService configurationReadPlatformService; + @Autowired + private ConfigurationReadPlatformService configurationReadPlatformService; - @Autowired - private ConfigurationWritePlatformService configurationWritePlatformService; + @Autowired + private ConfigurationWritePlatformService configurationWritePlatformService; - @Autowired - private PortfolioApiDataConversionService apiDataConversionService; - - @Autowired - private PortfolioApiJsonSerializerService apiJsonSerializerService; + @Autowired + private PortfolioApiDataConversionService apiDataConversionService; + + @Autowired + private PortfolioApiJsonSerializerService apiJsonSerializerService; @Autowired 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"); - - Set typicalResponseParameters = new HashSet( - Arrays.asList("selectedCurrencyOptions", "currencyOptions")); - - Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); - if (responseParameters.isEmpty()) { - responseParameters.addAll(typicalResponseParameters); - } - boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); + @GET + @Path("currency") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveCurrencyDataForConfiguration(@Context final UriInfo uriInfo) { - ConfigurationData configurationData = this.configurationReadPlatformService.retrieveCurrencyConfiguration(); - - return this.apiJsonSerializerService.serializeConfigurationDataToJson(prettyPrint, responseParameters, configurationData); - } + context.authenticatedUser().validateHasReadPermission("CURRENCY"); - @PUT - @Path("currency") - @Consumes({MediaType.APPLICATION_JSON}) - @Produces({MediaType.APPLICATION_JSON}) - public Response updateAllowedCurrenciesForOrganisation(final String jsonRequestBody) { + Set typicalResponseParameters = new HashSet(Arrays.asList("selectedCurrencyOptions", "currencyOptions")); - OrganisationCurrencyCommand command = this.apiDataConversionService.convertJsonToOrganisationCurrencyCommand(jsonRequestBody); - - this.configurationWritePlatformService.updateOrganisationCurrencies(command); + Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); + if (responseParameters.isEmpty()) { + 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(); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/UsersApiResource.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/UsersApiResource.java index 70d08522d..51d1ab5f6 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/UsersApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/UsersApiResource.java @@ -15,21 +15,17 @@ 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.Response; 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.EntityIdentifier; 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.infrastructure.api.ApiParameterHelper; +import org.mifosng.platform.makerchecker.service.PortfolioCommandSourceWritePlatformService; import org.mifosng.platform.organisation.service.OfficeReadPlatformService; 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.AppUserWritePlatformService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @@ -45,14 +41,11 @@ public class UsersApiResource { @Autowired private OfficeReadPlatformService officeReadPlatformService; - @Autowired - private AppUserWritePlatformService appUserWritePlatformService; - - @Autowired - private PortfolioApiDataConversionService apiDataConversionService; - @Autowired private PortfolioApiJsonSerializerService apiJsonSerializerService; + + @Autowired + private PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; @Autowired private PlatformSecurityContext context; @@ -114,41 +107,32 @@ public class UsersApiResource { @POST @Consumes({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 Response.ok().entity(new EntityIdentifier(userId)).build(); + return this.apiJsonSerializerService.serializeEntityIdentifier(result); } @DELETE @Path("{userId}") @Consumes({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 Response.ok(new EntityIdentifier(userId)).build(); + return this.apiJsonSerializerService.serializeEntityIdentifier(result); } @PUT @Path("{userId}") @Consumes({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(); - - if (loggedInUser.hasIdOf(userId)) { - this.appUserWritePlatformService.updateUsersOwnAccountDetails(command); - } else { - this.appUserWritePlatformService.updateUser(command); - } - - return Response.ok().entity(new EntityIdentifier(userId)).build(); + return this.apiJsonSerializerService.serializeEntityIdentifier(result); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/UserCommand.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/UserCommand.java index b7b1792bd..d4b6ec313 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/UserCommand.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/UserCommand.java @@ -1,113 +1,114 @@ package org.mifosng.platform.api.commands; -import java.io.Serializable; import java.util.Set; /** * 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 firstname; - private final String lastname; - private final String password; - private final String repeatPassword; - private final String email; - private final Long officeId; - - private final String[] notSelectedRoles; - private final String[] roles; - - private final Set modifiedParameters; + private final String username; + private final String firstname; + private final String lastname; + private final String password; + private final String repeatPassword; + private final String email; + private final Long officeId; - public UserCommand(final Set modifiedParameters, 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.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(); - } + private final String[] notSelectedRoles; + private final String[] roles; - public Long getId() { - return id; - } + private transient final boolean makerCheckerApproval; + private transient final Long id; + private transient final Set modifiedParameters; + + public UserCommand(final Set 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() { - return username; - } + public Long getId() { + return id; + } - public String getFirstname() { - return firstname; - } + public String getUsername() { + return username; + } - public String getLastname() { - return lastname; - } + public String getFirstname() { + return firstname; + } - public String getPassword() { - return password; - } + public String getLastname() { + return lastname; + } - public String getRepeatPassword() { - return repeatPassword; - } + public String getPassword() { + return password; + } - public String getEmail() { - return email; - } + public String getRepeatPassword() { + return repeatPassword; + } - public Long getOfficeId() { - return officeId; - } + public String getEmail() { + return email; + } - public String[] getNotSelectedRoles() { - return notSelectedRoles; - } + public Long getOfficeId() { + return officeId; + } - public String[] getRoles() { - return roles; - } + public String[] getNotSelectedRoles() { + return notSelectedRoles; + } - public boolean isUsernameChanged() { - return this.modifiedParameters.contains("username"); - } - - public boolean isFirstnameChanged() { - return this.modifiedParameters.contains("firstname"); - } - - public boolean isLastnameChanged() { - return this.modifiedParameters.contains("lastname"); - } - - public boolean isEmailChanged() { - return this.modifiedParameters.contains("email"); - } - - public boolean isPasswordChanged() { - return this.modifiedParameters.contains("password") && this.modifiedParameters.contains("repeatPassword"); - } - - public boolean isOfficeChanged() { - return this.modifiedParameters.contains("officeId"); - } - - public boolean isRolesChanged() { - return this.modifiedParameters.contains("roles"); - } + public String[] getRoles() { + return roles; + } + + public boolean isUsernameChanged() { + return this.modifiedParameters.contains("username"); + } + + public boolean isFirstnameChanged() { + return this.modifiedParameters.contains("firstname"); + } + + public boolean isLastnameChanged() { + return this.modifiedParameters.contains("lastname"); + } + + public boolean isEmailChanged() { + return this.modifiedParameters.contains("email"); + } + + public boolean isPasswordChanged() { + return this.modifiedParameters.contains("password") && this.modifiedParameters.contains("repeatPassword"); + } + + public boolean isOfficeChanged() { + return this.modifiedParameters.contains("officeId"); + } + + public boolean isRolesChanged() { + return this.modifiedParameters.contains("roles"); + } + + public boolean isApprovedByChecker() { + return this.makerCheckerApproval; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioApiDataConversionService.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioApiDataConversionService.java index 826a324cb..56e4b9751 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioApiDataConversionService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioApiDataConversionService.java @@ -44,7 +44,7 @@ public interface PortfolioApiDataConversionService { RolePermissionCommand convertApiRequestJsonToRolePermissionCommand(Long roleId, String jsonRequestBody); - UserCommand convertJsonToUserCommand(Long resourceIdentifier, String json); + UserCommand convertApiRequestJsonToUserCommand(Long resourceIdentifier, String json); BranchMoneyTransferCommand convertJsonToBranchMoneyTransferCommand(String json); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioApiDataConversionServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioApiDataConversionServiceImpl.java index 6dd458781..8d98ac04c 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioApiDataConversionServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioApiDataConversionServiceImpl.java @@ -269,58 +269,22 @@ public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataCo } @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(); } - Type typeOfMap = new TypeToken>() {}.getType(); - Map requestMap = gsonConverter.fromJson(json, typeOfMap); + final Type typeOfMap = new TypeToken>() {}.getType(); + final Map requestMap = gsonConverter.fromJson(json, typeOfMap); - Set supportedParams = new HashSet(Arrays.asList("username", "firstname", "lastname", "password", "repeatPassword", + final Set supportedParams = new HashSet(Arrays.asList("username", "firstname", "lastname", "password", "repeatPassword", "email", "officeId", "notSelectedRoles", "roles")); checkForUnsupportedParameters(requestMap, supportedParams); - Set modifiedParameters = new HashSet(); - - String username = extractStringParameter("username", requestMap, modifiedParameters); - String firstname = extractStringParameter("firstname", requestMap, modifiedParameters); - 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); + // no difference between the api json and internal command + // representation of json so reuse this code to de-serialize into + // command object + return this.portfolioCommandDeserializerService.deserializeUserCommand(resourceIdentifier, json, false); } @Override @@ -576,8 +540,6 @@ public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataCo final Type typeOfMap = new TypeToken>() {}.getType(); final Map requestMap = gsonConverter.fromJson(json, typeOfMap); - // FIXME - A - LoanProduct - KW - Do we add support for - // "overpaidTolerance" parameter? final Set supportedParams = new HashSet(Arrays.asList("name", "description", "fundId", "transactionProcessingStrategyId", "currencyCode", "digitsAfterDecimal", "principal", "inArrearsTolerance", "interestRatePerPeriod", "repaymentEvery", "numberOfRepayments", "repaymentFrequencyType", "interestRateFrequencyType", @@ -621,10 +583,6 @@ public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataCo final Integer interestCalculationPeriodType = helper.extractIntegerNamed("interestCalculationPeriodType", element, 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; if (element.isJsonObject()) { JsonObject object = element.getAsJsonObject(); @@ -739,7 +697,6 @@ public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataCo loanTermFrequency, loanTermFrequencyType, inArrearsToleranceValue, charges, loanOfficerId); } - // FIXME - KW - charges @Override public LoanChargeCommand convertJsonToLoanChargeCommand(final Long loanChargeId, final Long loanId, final String json) { if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } @@ -1594,7 +1551,6 @@ public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataCo @Override public CodeCommand convertJsonToCodeCommand(Long resourceIdentifier, String json) { - // TODO Auto-generated method stub if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } Type typeOfMap = new TypeToken>() {}.getType(); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandDeerializerServiceGoogleGson.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandDeerializerServiceGoogleGson.java index b2b8b838f..6d0ead906 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandDeerializerServiceGoogleGson.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandDeerializerServiceGoogleGson.java @@ -6,12 +6,15 @@ import java.util.Set; import org.apache.commons.lang.StringUtils; import org.mifosng.platform.accounting.api.commands.RolePermissionCommand; 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.errorhandling.InvalidJsonException; import org.springframework.stereotype.Service; import com.google.gson.Gson; +import com.google.gson.JsonArray; import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.google.gson.JsonParser; /** @@ -53,4 +56,50 @@ public class PortfolioCommandDeerializerServiceGoogleGson implements PortfolioCo 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 parametersPassedInRequest = new HashSet(); + + 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); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandDeserializerService.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandDeserializerService.java index c50ade9aa..3b39862b9 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandDeserializerService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandDeserializerService.java @@ -2,6 +2,7 @@ package org.mifosng.platform.api.infrastructure; import org.mifosng.platform.accounting.api.commands.RolePermissionCommand; 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 @@ -18,4 +19,6 @@ public interface PortfolioCommandDeserializerService { RoleCommand deserializeRoleCommand(Long roleId, String commandAsJson, boolean makerCheckerApproval); RolePermissionCommand deserializeRolePermissionCommand(Long roleId, String commandAsJson, boolean makerCheckerApproval); + + UserCommand deserializeUserCommand(Long resourceId, String jsonOfChangesOnly, boolean makerCheckerApproval); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandSerializerService.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandSerializerService.java index 578efe740..2c1cf4f0b 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandSerializerService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandSerializerService.java @@ -2,6 +2,7 @@ package org.mifosng.platform.api.infrastructure; import org.mifosng.platform.accounting.api.commands.RolePermissionCommand; import org.mifosng.platform.api.commands.RoleCommand; +import org.mifosng.platform.api.commands.UserCommand; /** * Service for serializing commands into another format. @@ -14,4 +15,6 @@ public interface PortfolioCommandSerializerService { String serializeRoleCommandToJson(RoleCommand command); String serializeRolePermissionCommandToJson(RolePermissionCommand command); + + String serializeUserCommandToJson(UserCommand command); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandSerializerServiceJson.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandSerializerServiceJson.java index 2e11f691a..dcfe5f5aa 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandSerializerServiceJson.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioCommandSerializerServiceJson.java @@ -4,6 +4,7 @@ import java.util.HashSet; import org.mifosng.platform.accounting.api.commands.RolePermissionCommand; import org.mifosng.platform.api.commands.RoleCommand; +import org.mifosng.platform.api.commands.UserCommand; import org.mifosng.platform.infrastructure.api.GoogleGsonSerializerHelper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -36,4 +37,10 @@ public class PortfolioCommandSerializerServiceJson implements PortfolioCommandSe final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(new HashSet(), false, new HashSet()); return helper.serializedJsonFrom(gsonDeserializer, command); } + + @Override + public String serializeUserCommandToJson(final UserCommand command) { + final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(new HashSet(), false, new HashSet()); + return helper.serializedJsonFrom(gsonDeserializer, command); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java index 76530006f..ae1ae8bf6 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java @@ -30,6 +30,8 @@ import org.mifosng.platform.organisation.domain.CodeValueRepository; import org.mifosng.platform.organisation.domain.Office; import org.mifosng.platform.organisation.domain.OfficeRepository; 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.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -48,21 +50,19 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP private final OfficeRepository officeRepository; private final NoteRepository noteRepository; private final CodeValueRepository codeValueRepository; - - // FIXME - kw - this value is hardcoded for now but will be retrieved from - // configuration - private boolean makerCheckerEnabledForTask = false; + private final PermissionRepository permissionRepository; @Autowired public ClientWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final ClientRepository clientRepository, final ClientIdentifierRepository clientIdentifierRepository, final OfficeRepository officeRepository, - NoteRepository noteRepository, final CodeValueRepository codeValueRepository) { + NoteRepository noteRepository, final CodeValueRepository codeValueRepository, final PermissionRepository permissionRepository) { this.context = context; this.clientRepository = clientRepository; this.clientIdentifierRepository = clientIdentifierRepository; this.officeRepository = officeRepository; this.noteRepository = noteRepository; this.codeValueRepository = codeValueRepository; + this.permissionRepository = permissionRepository; } @Transactional @@ -76,8 +76,9 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP client.delete(); 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()); } @@ -92,7 +93,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP "error.msg.client.duplicate.externalId", "Client with externalId `" + command.getExternalId() + "` already exists", "externalId", command.getExternalId()); } - logger.error(dve.getMessage(), dve); + logAsErrorUnexpectedDataIntegrityException(dve); throw new PlatformDataIntegrityException("error.msg.client.unknown.data.integrity.issue", "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()); 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(); } catch (DataIntegrityViolationException dve) { @@ -153,8 +155,9 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP 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()); } catch (DataIntegrityViolationException 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( documentTypeId, documentTypeLabel, documentKey); } - // only log as error if unexpected data integrity violation. - logger.error(dve.getMessage(), dve); + logAsErrorUnexpectedDataIntegrityException(dve); throw new PlatformDataIntegrityException("error.msg.clientIdentifier.unknown.data.integrity.issue", "Unknown data integrity issue with resource."); } + private void logAsErrorUnexpectedDataIntegrityException(final DataIntegrityViolationException dve) { + logger.error(dve.getMessage(), dve); + } + @Transactional @Override public EntityIdentifier deleteClientIdentifier(final Long clientIdentifierId) { diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/configuration/service/ConfigurationReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosng/platform/configuration/service/ConfigurationReadPlatformService.java index 2f29e6c02..7b5ef49e0 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/configuration/service/ConfigurationReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/configuration/service/ConfigurationReadPlatformService.java @@ -4,6 +4,6 @@ import org.mifosng.platform.api.data.ConfigurationData; public interface ConfigurationReadPlatformService { - ConfigurationData retrieveCurrencyConfiguration(); - + ConfigurationData retrieveCurrencyConfiguration(); + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/configuration/service/ConfigurationReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/configuration/service/ConfigurationReadPlatformServiceImpl.java index c12be07cc..c867a7472 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/configuration/service/ConfigurationReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/configuration/service/ConfigurationReadPlatformServiceImpl.java @@ -12,24 +12,25 @@ import org.springframework.stereotype.Service; @Service public class ConfigurationReadPlatformServiceImpl implements ConfigurationReadPlatformService { - private final CurrencyReadPlatformService currencyReadPlatformService; + private final CurrencyReadPlatformService currencyReadPlatformService; - @Autowired - public ConfigurationReadPlatformServiceImpl(final CurrencyReadPlatformService currencyReadPlatformService) { - this.currencyReadPlatformService = currencyReadPlatformService; - } + @Autowired + public ConfigurationReadPlatformServiceImpl(final CurrencyReadPlatformService currencyReadPlatformService) { + this.currencyReadPlatformService = currencyReadPlatformService; + } - @Override - public ConfigurationData retrieveCurrencyConfiguration() { - - List selectedCurrencyOptions = new ArrayList(this.currencyReadPlatformService.retrieveAllowedCurrencies()); - List currencyOptions = new ArrayList(this.currencyReadPlatformService.retrieveAllPlatformCurrencies()); + @Override + public ConfigurationData retrieveCurrencyConfiguration() { - // remove selected currency options - currencyOptions.removeAll(selectedCurrencyOptions); - - ConfigurationData configurationData = new ConfigurationData(currencyOptions, selectedCurrencyOptions); - - return configurationData; - } + List selectedCurrencyOptions = new ArrayList( + this.currencyReadPlatformService.retrieveAllowedCurrencies()); + List currencyOptions = new ArrayList(this.currencyReadPlatformService.retrieveAllPlatformCurrencies()); + + // remove selected currency options + currencyOptions.removeAll(selectedCurrencyOptions); + + ConfigurationData configurationData = new ConfigurationData(currencyOptions, selectedCurrencyOptions); + + return configurationData; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/configuration/service/ConfigurationWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosng/platform/configuration/service/ConfigurationWritePlatformService.java index fce25ad8a..d318570c8 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/configuration/service/ConfigurationWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/configuration/service/ConfigurationWritePlatformService.java @@ -5,7 +5,7 @@ import org.springframework.security.access.prepost.PreAuthorize; public interface ConfigurationWritePlatformService { - @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'ORGANISATION_ADMINISTRATION_SUPER_USER', 'UPDATE_CURRENCY')") - void updateOrganisationCurrencies(OrganisationCurrencyCommand command); - + @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'ORGANISATION_ADMINISTRATION_SUPER_USER', 'UPDATE_CURRENCY')") + void updateOrganisationCurrencies(OrganisationCurrencyCommand command); + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/configuration/service/ConfigurationWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/configuration/service/ConfigurationWritePlatformServiceJpaRepositoryImpl.java index d6af2398c..cb539a00b 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/configuration/service/ConfigurationWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/configuration/service/ConfigurationWritePlatformServiceJpaRepositoryImpl.java @@ -21,54 +21,53 @@ import org.springframework.transaction.annotation.Transactional; @Service public class ConfigurationWritePlatformServiceJpaRepositoryImpl implements ConfigurationWritePlatformService { - private final PlatformSecurityContext context; - private final ApplicationCurrencyRepository applicationCurrencyRepository; - private final OrganisationCurrencyRepository organisationCurrencyRepository; + private final PlatformSecurityContext context; + private final ApplicationCurrencyRepository applicationCurrencyRepository; + private final OrganisationCurrencyRepository organisationCurrencyRepository; - @Autowired - public ConfigurationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, - final ApplicationCurrencyRepository applicationCurrencyRepository, final OrganisationCurrencyRepository organisationCurrencyRepository) { - this.context = context; - this.applicationCurrencyRepository = applicationCurrencyRepository; - this.organisationCurrencyRepository = organisationCurrencyRepository; - } - - @Transactional - @Override - public void updateOrganisationCurrencies(final OrganisationCurrencyCommand command) { - - context.authenticatedUser(); - - List dataValidationErrors = new ArrayList(); - 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 allowedCurrencies = new HashSet(); + @Autowired + public ConfigurationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, + final ApplicationCurrencyRepository applicationCurrencyRepository, + final OrganisationCurrencyRepository organisationCurrencyRepository) { + this.context = context; + this.applicationCurrencyRepository = applicationCurrencyRepository; + this.organisationCurrencyRepository = organisationCurrencyRepository; + } - for (String currencyCode : command.getCurrencies()) { + @Transactional + @Override + public void updateOrganisationCurrencies(final OrganisationCurrencyCommand command) { - 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()); + context.authenticatedUser(); - 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); - } - } + List dataValidationErrors = new ArrayList(); + 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 allowedCurrencies = new HashSet(); + + 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); } + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/domain/CommandSource.java b/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/domain/CommandSource.java index a51428ed3..87a994034 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/domain/CommandSource.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/domain/CommandSource.java @@ -131,4 +131,8 @@ public class CommandSource extends AbstractPersistable { public boolean isRoleResource() { return this.resource.equalsIgnoreCase("ROLES"); } + + public boolean isUserResource() { + return this.resource.equalsIgnoreCase("USERS"); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/ClientCommandHandler.java b/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/ClientCommandHandler.java index d912c38da..70d2de444 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/ClientCommandHandler.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/ClientCommandHandler.java @@ -85,6 +85,8 @@ public class ClientCommandHandler implements CommandSourceHandler { public CommandSource handle(final CommandSource commandSourceResult) { + final AppUser checker = context.authenticatedUser(); + Long resourceId = null; if (commandSourceResult.isClientResource()) { final ClientCommand command = this.apiDataConversionService.convertInternalJsonFormatToClientCommand( @@ -92,16 +94,15 @@ public class ClientCommandHandler implements CommandSourceHandler { if (commandSourceResult.isCreate()) { resourceId = this.clientWritePlatformService.createClient(command); + commandSourceResult.markAsChecked(checker, new LocalDate()); } else if (commandSourceResult.isUpdate()) { - - // TODO - is there a case for doing change detection at this - // point also? - EntityIdentifier result = this.clientWritePlatformService.updateClientDetails(command); resourceId = result.getEntityId(); + commandSourceResult.markAsChecked(checker, new LocalDate()); } else if (commandSourceResult.isDelete()) { EntityIdentifier result = this.clientWritePlatformService.deleteClient(command); resourceId = result.getEntityId(); + commandSourceResult.markAsChecked(checker, new LocalDate()); } } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/CommandSourceHandlerDelegator.java b/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/CommandSourceHandlerDelegator.java index 04be4bc54..1e5c772fd 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/CommandSourceHandlerDelegator.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/CommandSourceHandlerDelegator.java @@ -15,14 +15,17 @@ public class CommandSourceHandlerDelegator { private final PlatformSecurityContext context; private final ClientCommandHandler clientCommandHandler; private final RoleCommandHandler roleCommandHandler; + private final UserCommandHandler userCommandHandler; @Autowired public CommandSourceHandlerDelegator(final PlatformSecurityContext context, final ClientCommandHandler clientCommandHandler, - final RoleCommandHandler roleCommandHandler) { + final RoleCommandHandler roleCommandHandler, + final UserCommandHandler userCommandHandler) { this.context = context; this.clientCommandHandler = clientCommandHandler; this.roleCommandHandler = roleCommandHandler; + this.userCommandHandler = userCommandHandler; } public CommandSource handle(final CommandSource commandSource, final String apiRequestBodyInJson) { @@ -33,13 +36,15 @@ public class CommandSourceHandlerDelegator { commandSourceResult = clientCommandHandler.handle(commandSource, apiRequestBodyInJson); } else if (commandSource.isRoleResource()) { commandSourceResult = roleCommandHandler.handle(commandSource, apiRequestBodyInJson); + } else if (commandSource.isUserResource()) { + commandSourceResult = userCommandHandler.handle(commandSource, apiRequestBodyInJson); } else { throw new UnsupportedCommandException(commandSource.commandName()); } return commandSourceResult; } - + public CommandSource handleExistingCommand(final CommandSource commandSource) { CommandSource commandSourceResult = null; @@ -47,6 +52,8 @@ public class CommandSourceHandlerDelegator { commandSourceResult = clientCommandHandler.handle(commandSource); } else if (commandSource.isRoleResource()) { commandSourceResult = roleCommandHandler.handle(commandSource); + } else if (commandSource.isUserResource()) { + commandSourceResult = userCommandHandler.handle(commandSource); } else { throw new UnsupportedCommandException(commandSource.commandName()); } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/PortfolioCommandSourceWriteServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/PortfolioCommandSourceWriteServiceImpl.java index 6d357196c..3cbc4fc20 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/PortfolioCommandSourceWriteServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/PortfolioCommandSourceWriteServiceImpl.java @@ -44,13 +44,10 @@ public class PortfolioCommandSourceWriteServiceImpl implements PortfolioCommandS @Override public EntityIdentifier approveEntry(final Long id) { - final AppUser checker = context.authenticatedUser(); + context.authenticatedUser(); final CommandSource commandSourceInput = this.commandSourceRepository.findOne(id); - commandSourceInput.markAsChecked(checker, new LocalDate()); - final CommandSource commandSourceResult = this.commandSourceHandlerDelegator.handleExistingCommand(commandSourceInput); - commandSourceRepository.save(commandSourceResult); return EntityIdentifier.makerChecker(commandSourceResult.resourceId(), commandSourceResult.getId()); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/RoleCommandHandler.java b/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/RoleCommandHandler.java index 02284d6c0..5e1e6f783 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/RoleCommandHandler.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/RoleCommandHandler.java @@ -112,17 +112,22 @@ public class RoleCommandHandler implements CommandSourceHandler { */ public CommandSource handle(final CommandSource commandSourceResult) { + final AppUser checker = context.authenticatedUser(); + Long resourceId = commandSourceResult.resourceId(); if (commandSourceResult.isRoleResource()) { if (commandSourceResult.isCreate()) { final RoleCommand command = this.commandDeserializerService.deserializeRoleCommand(resourceId, commandSourceResult.json(), true); resourceId = this.writePlatformService.createRole(command); + commandSourceResult.markAsChecked(checker, new LocalDate()); } else if (commandSourceResult.isUpdate()) { final RoleCommand command = this.commandDeserializerService.deserializeRoleCommand(resourceId, commandSourceResult.json(), true); resourceId = this.writePlatformService.updateRole(command); + commandSourceResult.markAsChecked(checker, new LocalDate()); } else if (commandSourceResult.isUpdateRolePermissions()) { final RolePermissionCommand command = this.commandDeserializerService.deserializeRolePermissionCommand(resourceId, commandSourceResult.json(), true); resourceId =this.writePlatformService.updateRolePermissions(command); + commandSourceResult.markAsChecked(checker, new LocalDate()); } else if (commandSourceResult.isDelete()) { throw new UnsupportedCommandException(commandSourceResult.commandName()); } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/UserCommandHandler.java b/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/UserCommandHandler.java new file mode 100644 index 000000000..443e800d6 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/makerchecker/service/UserCommandHandler.java @@ -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; + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/JpaUserDomainService.java b/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/JpaUserDomainService.java index a99c5d81f..de04b80ff 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/JpaUserDomainService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/JpaUserDomainService.java @@ -1,5 +1,6 @@ package org.mifosng.platform.user.domain; +import org.mifosng.platform.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; import org.mifosng.platform.infrastructure.EmailDetail; import org.mifosng.platform.infrastructure.PlatformEmailService; import org.mifosng.platform.infrastructure.PlatformPasswordEncoder; @@ -11,37 +12,46 @@ import org.springframework.transaction.annotation.Transactional; @Service public class JpaUserDomainService implements UserDomainService { + private final AppUserRepository userRepository; + private final PlatformPasswordEncoder applicationPasswordEncoder; + private final PlatformEmailService emailService; + private final PermissionRepository permissionRepository; + @Autowired - private AppUserRepository userRepository; - - @Autowired - private PlatformPasswordEncoder applicationPasswordEncoder; - - @Autowired - private PlatformEmailService emailService; - + public JpaUserDomainService(final AppUserRepository userRepository, final PlatformPasswordEncoder applicationPasswordEncoder, + final PlatformEmailService emailService, final PermissionRepository permissionRepository) { + this.userRepository = userRepository; + this.applicationPasswordEncoder = applicationPasswordEncoder; + this.emailService = emailService; + this.permissionRepository = permissionRepository; + } + @Transactional @Override - public void create(final AppUser appUser) { + public void create(final AppUser appUser, final boolean isApprovedByChecker) { + generateKeyUsedForPasswordSalting(appUser); String unencodedPassword = appUser.getPassword(); if (org.apache.commons.lang.StringUtils.isBlank(unencodedPassword) || "autogenerate".equalsIgnoreCase(unencodedPassword)) { - unencodedPassword = new RandomPasswordGenerator(13).generate(); - appUser.updatePassword(unencodedPassword); + unencodedPassword = new RandomPasswordGenerator(13).generate(); + 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); } - private void generateKeyUsedForPasswordSalting(final AppUser appUser) { - this.userRepository.save(appUser); - } + private void generateKeyUsedForPasswordSalting(final AppUser appUser) { + this.userRepository.save(appUser); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/Permission.java b/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/Permission.java index 41c5288dd..004396c84 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/Permission.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/Permission.java @@ -25,15 +25,15 @@ public class Permission extends AbstractPersistable { @Column(name = "action_name", nullable = true, length = 100) private final String actionName; - @SuppressWarnings("unused") @Column(name = "can_maker_checker", nullable = false) - private Boolean canMakerChecker; + private final boolean canMakerChecker; protected Permission() { this.grouping = null; this.code = null; this.entityName = null; this.actionName = null; + this.canMakerChecker = false; } public boolean hasCode(final String checkCode) { @@ -43,4 +43,8 @@ public class Permission extends AbstractPersistable { public String code() { return this.code; } + + public boolean hasMakerCheckerEnabled() { + return this.canMakerChecker; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/PermissionRepository.java b/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/PermissionRepository.java index e236b5bb8..9a5c04d61 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/PermissionRepository.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/PermissionRepository.java @@ -3,5 +3,6 @@ package org.mifosng.platform.user.domain; import org.springframework.data.jpa.repository.JpaRepository; public interface PermissionRepository extends JpaRepository { - // no added behaviour + + Permission findOneByCode(String code); } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/UserDomainService.java b/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/UserDomainService.java index 8f11ef4c8..05160b028 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/UserDomainService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/user/domain/UserDomainService.java @@ -2,5 +2,5 @@ package org.mifosng.platform.user.domain; public interface UserDomainService { - void create(AppUser appUser); + void create(AppUser appUser, boolean isApprovedByChecker); } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/user/service/AppUserWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosng/platform/user/service/AppUserWritePlatformService.java index e03eec39f..5f01ba735 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/user/service/AppUserWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/user/service/AppUserWritePlatformService.java @@ -6,15 +6,15 @@ import org.springframework.security.access.prepost.PreAuthorize; public interface AppUserWritePlatformService { @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')") - Long updateUser(final UserCommand command); + Long updateUser(UserCommand command); @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 // change their own details (email, username, password etc). - void updateUsersOwnAccountDetails(UserCommand command); + Long updateUsersOwnAccountDetails(UserCommand command); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/user/service/AppUserWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/user/service/AppUserWritePlatformServiceJpaRepositoryImpl.java index f0825c44c..f5a42ffc3 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/user/service/AppUserWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/user/service/AppUserWritePlatformServiceJpaRepositoryImpl.java @@ -8,6 +8,7 @@ import java.util.Set; import org.apache.commons.lang.StringUtils; import org.mifosng.platform.api.commands.UserCommand; 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.PlatformApiDataValidationException; 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.user.domain.AppUser; 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.RoleRepository; import org.mifosng.platform.user.domain.UserDomainService; @@ -44,17 +47,19 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit private final AppUserRepository appUserRepository; private final OfficeRepository officeRepository; private final RoleRepository roleRepository; - + private final PermissionRepository permissionRepository; + @Autowired public AppUserWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final AppUserRepository appUserRepository, final UserDomainService userDomainService, final OfficeRepository officeRepository, final RoleRepository roleRepository, - final PlatformPasswordEncoder platformPasswordEncoder) { + final PlatformPasswordEncoder platformPasswordEncoder, final PermissionRepository permissionRepository) { this.context = context; this.appUserRepository = appUserRepository; this.userDomainService = userDomainService; this.officeRepository = officeRepository; this.roleRepository = roleRepository; this.platformPasswordEncoder = platformPasswordEncoder; + this.permissionRepository = permissionRepository; } @Transactional @@ -64,12 +69,12 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit try { context.authenticatedUser(); - UserCommandValidator validator = new UserCommandValidator(command); + final UserCommandValidator validator = new UserCommandValidator(command); validator.validateForCreate(); final Set 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()); } String password = command.getPassword(); @@ -77,17 +82,17 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit 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); - this.userDomainService.create(appUser); - + this.userDomainService.create(appUser, command.isApprovedByChecker()); + return appUser.getId(); } catch (DataIntegrityViolationException dve) { handleDataIntegrityIssues(command, dve); return Long.valueOf(-1); } catch (PlatformEmailSendException e) { - List dataValidationErrors = new ArrayList(); + final List dataValidationErrors = new ArrayList(); ApiParameterError error = ApiParameterError.parameterError("error.msg.user.email.invalid", "The parameter email is invalid.", "email", command.getEmail()); dataValidationErrors.add(error); @@ -103,10 +108,10 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit try { context.authenticatedUser(); - + UserCommandValidator validator = new UserCommandValidator(command); validator.validateForUpdate(); - + final Set allRoles = assembleSetOfRoles(command); Office office = null; @@ -115,7 +120,7 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit 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()); } userToUpdate.update(allRoles, office, command); @@ -131,6 +136,9 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit this.appUserRepository.saveAndFlush(userToUpdate); } + final Permission thisTask = this.permissionRepository.findOneByCode("UPDATE_USER"); + if (thisTask.hasMakerCheckerEnabled() && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } + return userToUpdate.getId(); } catch (DataIntegrityViolationException dve) { handleDataIntegrityIssues(command, dve); @@ -138,10 +146,50 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit } } + /** + * Different between this and updateUser is that we dont do + * maker-checker flow or require that user have particular permission to + * change their own details. + */ @Transactional @Override - public void updateUsersOwnAccountDetails(final UserCommand command) { - updateUser(command); + public Long updateUsersOwnAccountDetails(final UserCommand command) { + + try { + context.authenticatedUser(); + + UserCommandValidator validator = new UserCommandValidator(command); + validator.validateForUpdate(); + + final Set 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 assembleSetOfRoles(final UserCommand command) { @@ -163,13 +211,18 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit @Transactional @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); if (user == null || user.isDeleted()) { throw new UserNotFoundException(userId); } user.delete(); this.appUserRepository.save(user); + + if (permissionForThisTask.hasMakerCheckerEnabled() && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } } /* diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/user/service/RoleWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/user/service/RoleWritePlatformServiceJpaRepositoryImpl.java index 57ffc1b90..dd3ce8281 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/user/service/RoleWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/user/service/RoleWritePlatformServiceJpaRepositoryImpl.java @@ -24,10 +24,6 @@ public class RoleWritePlatformServiceJpaRepositoryImpl implements RoleWritePlatf private final RoleRepository roleRepository; private final PermissionRepository permissionRepository; - // FIXME - kw - this value is hardcoded for now but will be retrieved from - // configuration - private boolean makerCheckerEnabledForTask = true; - @Autowired public RoleWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final RoleRepository roleRepository, final PermissionRepository permissionRepository) { @@ -42,15 +38,16 @@ public class RoleWritePlatformServiceJpaRepositoryImpl implements RoleWritePlatf context.authenticatedUser(); - RoleCommandValidator validator = new RoleCommandValidator(command); + final RoleCommandValidator validator = new RoleCommandValidator(command); validator.validateForCreate(); - - Role entity = new Role(command.getName(), command.getDescription()); + + final Role entity = new Role(command.getName(), command.getDescription()); 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(); } @@ -60,16 +57,17 @@ public class RoleWritePlatformServiceJpaRepositoryImpl implements RoleWritePlatf context.authenticatedUser(); - RoleCommandValidator validator = new RoleCommandValidator(command); + final RoleCommandValidator validator = new RoleCommandValidator(command); 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()); } role.update(command); 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(); } @@ -98,8 +96,9 @@ public class RoleWritePlatformServiceJpaRepositoryImpl implements RoleWritePlatf 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(); } diff --git a/mifosng-provider/src/main/resources/logback.xml b/mifosng-provider/src/main/resources/logback.xml index e3e0c3473..fb801bbf9 100644 --- a/mifosng-provider/src/main/resources/logback.xml +++ b/mifosng-provider/src/main/resources/logback.xml @@ -18,10 +18,8 @@ - + - -