MIFOSX-97: change detection on user admin areas.

This commit is contained in:
Keith Woodlock
2012-12-07 13:54:43 +00:00
parent f5c1225dfa
commit fb4dfe7996
13 changed files with 310 additions and 283 deletions
@@ -28,7 +28,8 @@ public class RoleCommandHandler implements CommandSourceHandler {
private final ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson toApiJsonSerializer; private final ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson toApiJsonSerializer;
@Autowired @Autowired
public RoleCommandHandler(final PlatformSecurityContext context, final FromJsonHelper fromApiJsonHelper, public RoleCommandHandler(final PlatformSecurityContext context,
final FromJsonHelper fromApiJsonHelper,
final ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson toApiJsonSerializer, final ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson toApiJsonSerializer,
final RoleWritePlatformService writePlatformService) { final RoleWritePlatformService writePlatformService) {
this.context = context; this.context = context;
@@ -45,11 +46,11 @@ public class RoleCommandHandler implements CommandSourceHandler {
CommandSource commandSourceResult = commandSource.copy(); CommandSource commandSourceResult = commandSource.copy();
final JsonElement parsedCommand = this.fromApiJsonHelper.parse(commandSource.json());
final JsonCommand command = JsonCommand.from(commandSource.json(), parsedCommand, this.fromApiJsonHelper);
final Long resourceId = commandSource.resourceId(); final Long resourceId = commandSource.resourceId();
if (commandSource.isCreate()) { if (commandSource.isCreate()) {
try { try {
final JsonElement parsedCommand = this.fromApiJsonHelper.parse(commandSource.json());
final JsonCommand command = JsonCommand.from(commandSource.json(), parsedCommand, this.fromApiJsonHelper);
final Long newResourceId = this.writePlatformService.createRole(command); final Long newResourceId = this.writePlatformService.createRole(command);
@@ -60,24 +61,16 @@ public class RoleCommandHandler implements CommandSourceHandler {
} }
} else if (commandSource.isUpdate()) { } else if (commandSource.isUpdate()) {
try { try {
final JsonElement parsedCommand = this.fromApiJsonHelper.parse(commandSource.json());
final JsonCommand command = JsonCommand.from(commandSource.json(), parsedCommand, this.fromApiJsonHelper);
final EntityIdentifier result = this.writePlatformService.updateRole(resourceId, command); final EntityIdentifier result = this.writePlatformService.updateRole(resourceId, command);
final String jsonOfChangesOnly = toApiJsonSerializer.serialize(result.getChanges()); final String jsonOfChangesOnly = toApiJsonSerializer.serialize(result.getChanges());
commandSourceResult.updateJsonTo(jsonOfChangesOnly); commandSourceResult.updateJsonTo(jsonOfChangesOnly);
commandSourceResult.markAsChecked(maker, asToday); commandSourceResult.markAsChecked(maker, asToday);
} catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) {
// swallow this rollback transaction by design // swallow this rollback transaction by design
} }
} else if (commandSource.isUpdateRolePermissions()) { } else if (commandSource.isUpdateRolePermissions()) {
try { try {
final JsonElement parsedCommand = this.fromApiJsonHelper.parse(commandSource.json());
final JsonCommand command = JsonCommand.from(commandSource.json(), parsedCommand, this.fromApiJsonHelper);
final EntityIdentifier result = this.writePlatformService.updateRolePermissions(resourceId, command); final EntityIdentifier result = this.writePlatformService.updateRolePermissions(resourceId, command);
final String jsonOfChangesOnly = toApiJsonSerializer.serialize(result.getChanges()); final String jsonOfChangesOnly = toApiJsonSerializer.serialize(result.getChanges());
@@ -5,27 +5,34 @@ import java.util.List;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosplatform.commands.domain.CommandSource; import org.mifosplatform.commands.domain.CommandSource;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
import org.mifosplatform.infrastructure.core.serialization.ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException;
import org.mifosplatform.useradministration.command.UserCommand;
import org.mifosplatform.useradministration.domain.AppUser; import org.mifosplatform.useradministration.domain.AppUser;
import org.mifosplatform.useradministration.serialization.UserCommandFromCommandJsonDeserializer;
import org.mifosplatform.useradministration.service.AppUserWritePlatformService; import org.mifosplatform.useradministration.service.AppUserWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.google.gson.JsonElement;
@Service @Service
public class UserCommandHandler implements CommandSourceHandler { public class UserCommandHandler implements CommandSourceHandler {
private final PlatformSecurityContext context; private final PlatformSecurityContext context;
private final UserCommandFromCommandJsonDeserializer fromCommandJsonDeserializer; private final FromJsonHelper fromApiJsonHelper;
private final ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson toApiJsonSerializer;
private final AppUserWritePlatformService writePlatformService; private final AppUserWritePlatformService writePlatformService;
@Autowired @Autowired
public UserCommandHandler(final PlatformSecurityContext context, public UserCommandHandler(final PlatformSecurityContext context, final FromJsonHelper fromApiJsonHelper,
final UserCommandFromCommandJsonDeserializer fromCommandJsonDeserializer, final AppUserWritePlatformService writePlatformService) { final ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson toApiJsonSerializer,
final AppUserWritePlatformService writePlatformService) {
this.context = context; this.context = context;
this.fromCommandJsonDeserializer = fromCommandJsonDeserializer; this.fromApiJsonHelper = fromApiJsonHelper;
this.toApiJsonSerializer = toApiJsonSerializer;
this.writePlatformService = writePlatformService; this.writePlatformService = writePlatformService;
} }
@@ -36,11 +43,13 @@ public class UserCommandHandler implements CommandSourceHandler {
final LocalDate asToday = new LocalDate(); final LocalDate asToday = new LocalDate();
final Long resourceId = commandSource.resourceId(); final Long resourceId = commandSource.resourceId();
final UserCommand command = this.fromCommandJsonDeserializer.commandFromCommandJson(resourceId, commandSource.json()); final JsonElement parsedCommand = this.fromApiJsonHelper.parse(commandSource.json());
final JsonCommand command = JsonCommand.from(commandSource.json(), parsedCommand, this.fromApiJsonHelper);
CommandSource commandSourceResult = commandSource.copy(); CommandSource commandSourceResult = commandSource.copy();
if (commandSource.isCreate()) { if (commandSource.isCreate()) {
try { try {
Long newResourceId = this.writePlatformService.createUser(command); final Long newResourceId = this.writePlatformService.createUser(command);
commandSourceResult.markAsChecked(maker, asToday); commandSourceResult.markAsChecked(maker, asToday);
commandSourceResult.updateResourceId(newResourceId); commandSourceResult.updateResourceId(newResourceId);
@@ -49,19 +58,22 @@ public class UserCommandHandler implements CommandSourceHandler {
} }
} else if (commandSource.isUpdate()) { } else if (commandSource.isUpdate()) {
try { try {
if (maker.hasIdOf(command.getId())) { EntityIdentifier result = null;
this.writePlatformService.updateUsersOwnAccountDetails(command); if (maker.hasIdOf(resourceId)) {
result = this.writePlatformService.updateUsersOwnAccountDetails(resourceId, command);
} else { } else {
this.writePlatformService.updateUser(command); result = this.writePlatformService.updateUser(resourceId, command);
} }
final String jsonOfChangesOnly = toApiJsonSerializer.serialize(result.getChanges());
commandSourceResult.updateJsonTo(jsonOfChangesOnly);
commandSourceResult.markAsChecked(maker, asToday); commandSourceResult.markAsChecked(maker, asToday);
} catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) {
// swallow this rollback transaction by design // swallow this rollback transaction by design
} }
} else if (commandSource.isDelete()) { } else if (commandSource.isDelete()) {
try { try {
this.writePlatformService.deleteUser(command); this.writePlatformService.deleteUser(resourceId, command);
commandSourceResult.markAsChecked(maker, asToday); commandSourceResult.markAsChecked(maker, asToday);
} catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) {
// swallow this rollback transaction by design // swallow this rollback transaction by design
@@ -76,35 +88,40 @@ public class UserCommandHandler implements CommandSourceHandler {
final AppUser checker = context.authenticatedUser(); final AppUser checker = context.authenticatedUser();
Long resourceId = commandSourceResult.resourceId(); final Long resourceId = commandSourceResult.resourceId();
final UserCommand command = this.fromCommandJsonDeserializer.commandFromCommandJson(resourceId, commandSourceResult.json(), true); final JsonElement parsedCommand = this.fromApiJsonHelper.parse(commandSourceResult.json());
final JsonCommand command = JsonCommand.withMakerCheckerApproval(commandSourceResult.json(), parsedCommand, this.fromApiJsonHelper);
if (commandSourceResult.isUserResource()) { if (commandSourceResult.isUserResource()) {
if (commandSourceResult.isCreate()) { if (commandSourceResult.isCreate()) {
final List<String> allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "USER_ADMINISTRATION_SUPER_USER", final List<String> allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "USER_ADMINISTRATION_SUPER_USER",
"CREATE_USER_MAKER"); "CREATE_USER_MAKER");
context.authenticatedUser().validateHasPermissionTo("CREATE_USER_MAKER", allowedPermissions); context.authenticatedUser().validateHasPermissionTo("CREATE_USER_MAKER", allowedPermissions);
resourceId = this.writePlatformService.createUser(command); final Long newResourceId = this.writePlatformService.createUser(command);
commandSourceResult.updateResourceId(resourceId); commandSourceResult.updateResourceId(newResourceId);
commandSourceResult.markAsChecked(checker, new LocalDate()); commandSourceResult.markAsChecked(checker, new LocalDate());
} else if (commandSourceResult.isUpdate()) { } else if (commandSourceResult.isUpdate()) {
if (checker.hasIdOf(command.getId())) { EntityIdentifier result = null;
this.writePlatformService.updateUsersOwnAccountDetails(command); if (checker.hasIdOf(resourceId)) {
result = this.writePlatformService.updateUsersOwnAccountDetails(resourceId, command);
} else { } else {
final List<String> allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "USER_ADMINISTRATION_SUPER_USER", final List<String> allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "USER_ADMINISTRATION_SUPER_USER",
"UPDATE_USER_MAKER"); "UPDATE_USER_MAKER");
context.authenticatedUser().validateHasPermissionTo("UPDATE_USER_MAKER", allowedPermissions); context.authenticatedUser().validateHasPermissionTo("UPDATE_USER_MAKER", allowedPermissions);
this.writePlatformService.updateUser(command); result = this.writePlatformService.updateUser(resourceId, command);
} }
final String jsonOfChangesOnly = toApiJsonSerializer.serialize(result.getChanges());
commandSourceResult.updateJsonTo(jsonOfChangesOnly);
commandSourceResult.markAsChecked(checker, new LocalDate()); commandSourceResult.markAsChecked(checker, new LocalDate());
} else if (commandSourceResult.isDelete()) { } else if (commandSourceResult.isDelete()) {
final List<String> allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "USER_ADMINISTRATION_SUPER_USER", final List<String> allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "USER_ADMINISTRATION_SUPER_USER",
"DELETE_USER_MAKER"); "DELETE_USER_MAKER");
context.authenticatedUser().validateHasPermissionTo("DELETE_USER_MAKER", allowedPermissions); context.authenticatedUser().validateHasPermissionTo("DELETE_USER_MAKER", allowedPermissions);
this.writePlatformService.deleteUser(command); this.writePlatformService.deleteUser(resourceId, command);
commandSourceResult.markAsChecked(checker, new LocalDate()); commandSourceResult.markAsChecked(checker, new LocalDate());
} }
} }
@@ -1,11 +1,15 @@
package org.mifosplatform.infrastructure.core.api; package org.mifosplatform.infrastructure.core.api;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Map; import java.util.Map;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.infrastructure.security.domain.BasicPasswordEncodablePlatformUser;
import org.mifosplatform.infrastructure.security.domain.PlatformUser;
import org.mifosplatform.infrastructure.security.service.PlatformPasswordEncoder;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
@@ -72,6 +76,12 @@ public final class JsonCommand {
return differenceExists; return differenceExists;
} }
private boolean differenceExists(final String[] baseValue, final String[] workingCopyValue) {
Arrays.sort(baseValue);
Arrays.sort(workingCopyValue);
return !Arrays.equals(baseValue, workingCopyValue);
}
private boolean differenceExists(final Long baseValue, final Long workingCopyValue) { private boolean differenceExists(final Long baseValue, final Long workingCopyValue) {
boolean differenceExists = false; boolean differenceExists = false;
@@ -87,6 +97,10 @@ public final class JsonCommand {
private boolean parameterExists(final String parameterName) { private boolean parameterExists(final String parameterName) {
return this.fromApiJsonHelper.parameterExists(parameterName, parsedCommand); return this.fromApiJsonHelper.parameterExists(parameterName, parsedCommand);
} }
public boolean hasParameter(final String parameterName) {
return parameterExists(parameterName);
}
public String dateFormat() { public String dateFormat() {
return stringValueOfParameterNamed("dateFormat"); return stringValueOfParameterNamed("dateFormat");
@@ -95,14 +109,14 @@ public final class JsonCommand {
public String locale() { public String locale() {
return stringValueOfParameterNamed("locale"); return stringValueOfParameterNamed("locale");
} }
public Map<String, Boolean> mapValueOfParameterNamed(final String parameterName) { public Map<String, Boolean> mapValueOfParameterNamed(final String parameterName) {
final Type typeOfMap = new TypeToken<Map<String, Boolean>>() {}.getType(); final Type typeOfMap = new TypeToken<Map<String, Boolean>>() {}.getType();
if (parsedCommand.getAsJsonObject().has(parameterName)) { if (parsedCommand.getAsJsonObject().has(parameterName)) {
parsedCommand.getAsJsonObject().get(parameterName); parsedCommand.getAsJsonObject().get(parameterName);
} }
return this.fromApiJsonHelper.extractMap(typeOfMap, jsonCommand); return this.fromApiJsonHelper.extractMap(typeOfMap, jsonCommand);
} }
@@ -145,4 +159,33 @@ public final class JsonCommand {
final String value = this.fromApiJsonHelper.extractStringNamed(parameterName, parsedCommand); final String value = this.fromApiJsonHelper.extractStringNamed(parameterName, parsedCommand);
return StringUtils.defaultIfEmpty(value, ""); return StringUtils.defaultIfEmpty(value, "");
} }
public boolean isChangeInArrayParameterNamed(final String parameterName, final String[] existingValue) {
boolean isChanged = false;
if (parameterExists(parameterName)) {
final String[] workingValue = arrayValueOfParameterNamed(parameterName);
isChanged = differenceExists(existingValue, workingValue);
}
return isChanged;
}
public String[] arrayValueOfParameterNamed(final String parameterName) {
return this.fromApiJsonHelper.extractArrayNamed(parameterName, parsedCommand);
}
public boolean isChangeInPasswordParameterNamed(final String parameterName, final String existingValue, final PlatformPasswordEncoder platformPasswordEncoder, final Long saltValue) {
boolean isChanged = false;
if (parameterExists(parameterName)) {
final String workingValue = passwordValueOfParameterNamed(parameterName, platformPasswordEncoder, saltValue);
isChanged = differenceExists(existingValue, workingValue);
}
return isChanged;
}
public String passwordValueOfParameterNamed(final String parameterName, final PlatformPasswordEncoder platformPasswordEncoder, final Long saltValue) {
final String passwordPlainText = stringValueOfParameterNamed(parameterName);
final PlatformUser dummyPlatformUser = new BasicPasswordEncodablePlatformUser(saltValue, "", passwordPlainText);
return platformPasswordEncoder.encode(dummyPlatformUser);
}
} }
@@ -27,6 +27,10 @@ public class EntityIdentifier {
public static EntityIdentifier withChanges(final Long resourceId, final Map<String, Object> changes) { public static EntityIdentifier withChanges(final Long resourceId, final Map<String, Object> changes) {
return new EntityIdentifier(resourceId, null, changes); return new EntityIdentifier(resourceId, null, changes);
} }
public static EntityIdentifier empty() {
return new EntityIdentifier(Long.valueOf(-1), null, null);
}
public EntityIdentifier() { public EntityIdentifier() {
// //
@@ -78,6 +78,10 @@ public class FromJsonHelper {
public Long extractLongNamed(final String parameterName, final JsonElement element, final Set<String> parametersPassedInRequest) { public Long extractLongNamed(final String parameterName, final JsonElement element, final Set<String> parametersPassedInRequest) {
return helperDelegator.extractLongNamed(parameterName, element, parametersPassedInRequest); return helperDelegator.extractLongNamed(parameterName, element, parametersPassedInRequest);
} }
public String[] extractArrayNamed(final String parameterName, final JsonElement element) {
return helperDelegator.extractArrayNamed(parameterName, element, new HashSet<String>());
}
public String[] extractArrayNamed(final String parameterName, final JsonElement element, final Set<String> parametersPassedInRequest) { public String[] extractArrayNamed(final String parameterName, final JsonElement element, final Set<String> parametersPassedInRequest) {
return helperDelegator.extractArrayNamed(parameterName, element, parametersPassedInRequest); return helperDelegator.extractArrayNamed(parameterName, element, parametersPassedInRequest);
@@ -145,6 +145,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
final Client clientForUpdate = this.clientRepository.findOne(clientId); final Client clientForUpdate = this.clientRepository.findOne(clientId);
if (clientForUpdate == null || clientForUpdate.isDeleted()) { throw new ClientNotFoundException(clientId); } if (clientForUpdate == null || clientForUpdate.isDeleted()) { throw new ClientNotFoundException(clientId); }
final Map<String, Object> changesOnly = clientForUpdate.update(command); final Map<String, Object> changesOnly = clientForUpdate.update(command);
if (changesOnly.containsKey("officeId")) { if (changesOnly.containsKey("officeId")) {
@@ -20,7 +20,6 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService; import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
import org.mifosplatform.infrastructure.codes.data.CodeData;
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper; import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
import org.mifosplatform.infrastructure.core.data.EntityIdentifier; import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
@@ -29,7 +28,6 @@ import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext
import org.mifosplatform.organisation.office.data.OfficeLookup; import org.mifosplatform.organisation.office.data.OfficeLookup;
import org.mifosplatform.organisation.office.service.OfficeReadPlatformService; import org.mifosplatform.organisation.office.service.OfficeReadPlatformService;
import org.mifosplatform.useradministration.data.AppUserData; import org.mifosplatform.useradministration.data.AppUserData;
import org.mifosplatform.useradministration.serialization.UserCommandFromApiJsonDeserializer;
import org.mifosplatform.useradministration.service.AppUserReadPlatformService; import org.mifosplatform.useradministration.service.AppUserReadPlatformService;
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;
@@ -41,7 +39,7 @@ import org.springframework.stereotype.Component;
public class UsersApiResource { public class UsersApiResource {
/** /**
* The set of parameters that are supported in response for {@link CodeData} * The set of parameters that are supported in response for {@link AppUserData}.
*/ */
private final Set<String> RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "officeId", "officeName", "username", private final Set<String> RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "officeId", "officeName", "username",
"firstname", "lastname", "email", "allowedOffices", "availableRoles", "selectedRoles")); "firstname", "lastname", "email", "allowedOffices", "availableRoles", "selectedRoles"));
@@ -51,20 +49,18 @@ public class UsersApiResource {
private final PlatformSecurityContext context; private final PlatformSecurityContext context;
private final AppUserReadPlatformService readPlatformService; private final AppUserReadPlatformService readPlatformService;
private final OfficeReadPlatformService officeReadPlatformService; private final OfficeReadPlatformService officeReadPlatformService;
private final UserCommandFromApiJsonDeserializer fromApiJsonDeserializer;
private final DefaultToApiJsonSerializer<AppUserData> toApiJsonSerializer; private final DefaultToApiJsonSerializer<AppUserData> toApiJsonSerializer;
private final ApiRequestParameterHelper apiRequestParameterHelper; private final ApiRequestParameterHelper apiRequestParameterHelper;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
@Autowired @Autowired
public UsersApiResource(final PlatformSecurityContext context, final AppUserReadPlatformService readPlatformService, public UsersApiResource(final PlatformSecurityContext context, final AppUserReadPlatformService readPlatformService,
final OfficeReadPlatformService officeReadPlatformService, final UserCommandFromApiJsonDeserializer fromApiJsonDeserializer, final OfficeReadPlatformService officeReadPlatformService,
final DefaultToApiJsonSerializer<AppUserData> toApiJsonSerializer, final ApiRequestParameterHelper apiRequestParameterHelper, final DefaultToApiJsonSerializer<AppUserData> toApiJsonSerializer, final ApiRequestParameterHelper apiRequestParameterHelper,
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) { final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) {
this.context = context; this.context = context;
this.readPlatformService = readPlatformService; this.readPlatformService = readPlatformService;
this.officeReadPlatformService = officeReadPlatformService; this.officeReadPlatformService = officeReadPlatformService;
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
this.toApiJsonSerializer = toApiJsonSerializer; this.toApiJsonSerializer = toApiJsonSerializer;
this.apiRequestParameterHelper = apiRequestParameterHelper; this.apiRequestParameterHelper = apiRequestParameterHelper;
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
@@ -124,10 +120,8 @@ public class UsersApiResource {
final List<String> allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "USER_ADMINISTRATION_SUPER_USER", "CREATE_USER"); final List<String> allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "USER_ADMINISTRATION_SUPER_USER", "CREATE_USER");
context.authenticatedUser().validateHasPermissionTo("CREATE_USER", allowedPermissions); context.authenticatedUser().validateHasPermissionTo("CREATE_USER", allowedPermissions);
final String commandSerializedAsJson = this.fromApiJsonDeserializer.serializedCommandJsonFromApiJson(apiRequestBodyAsJson);
final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE", "users", null, final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE", "users", null,
commandSerializedAsJson); apiRequestBodyAsJson);
return this.toApiJsonSerializer.serialize(result); return this.toApiJsonSerializer.serialize(result);
} }
@@ -141,10 +135,8 @@ public class UsersApiResource {
final List<String> allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "USER_ADMINISTRATION_SUPER_USER", "UPDATE_USER"); final List<String> allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "USER_ADMINISTRATION_SUPER_USER", "UPDATE_USER");
context.authenticatedUser().validateHasPermissionTo("UPDATE_USER", allowedPermissions); context.authenticatedUser().validateHasPermissionTo("UPDATE_USER", allowedPermissions);
final String commandSerializedAsJson = this.fromApiJsonDeserializer.serializedCommandJsonFromApiJson(apiRequestBodyAsJson);
final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", "users", userId, final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", "users", userId,
commandSerializedAsJson); apiRequestBodyAsJson);
return this.toApiJsonSerializer.serialize(result); return this.toApiJsonSerializer.serialize(result);
} }
@@ -2,7 +2,6 @@ package org.mifosplatform.useradministration.command;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set;
import org.mifosplatform.infrastructure.core.data.ApiParameterError; import org.mifosplatform.infrastructure.core.data.ApiParameterError;
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
@@ -18,37 +17,26 @@ public class UserCommand {
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 passwordEncoded;
private final String email; private final String email;
private final Long officeId; private final Long officeId;
private final String[] notSelectedRoles; private final String[] notSelectedRoles;
private final String[] roles; private final String[] roles;
private transient final boolean makerCheckerApproval; public UserCommand(final String username, final String firstname, final String lastname, final String password,
private transient final Long id; final String repeatPassword, final String passwordEncoded, final String email, final Long officeId, final String[] notSelectedRoles, final String[] roles) {
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.username = username;
this.firstname = firstname; this.firstname = firstname;
this.lastname = lastname; this.lastname = lastname;
this.password = password; this.password = password;
this.repeatPassword = repeatPassword; this.repeatPassword = repeatPassword;
this.passwordEncoded = passwordEncoded;
this.email = email; this.email = email;
this.officeId = officeId; this.officeId = officeId;
this.notSelectedRoles = notSelectedRoles; this.notSelectedRoles = notSelectedRoles;
this.roles = roles; this.roles = roles;
} }
public Long getId() {
return id;
}
public String getUsername() { public String getUsername() {
return username; return username;
} }
@@ -85,38 +73,6 @@ public class UserCommand {
return roles; 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;
}
public void validateForCreate() { public void validateForCreate() {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>(); List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
@@ -130,7 +86,7 @@ public class UserCommand {
baseDataValidator.reset().parameter("roles").value(this.roles).arrayNotEmpty(); baseDataValidator.reset().parameter("roles").value(this.roles).arrayNotEmpty();
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); } "Validation errors exist.", dataValidationErrors); }
} }
public void validateForUpdate() { public void validateForUpdate() {
@@ -138,7 +94,6 @@ public class UserCommand {
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("user"); DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("user");
baseDataValidator.reset().parameter("id").value(this.id).notNull();
baseDataValidator.reset().parameter("username").value(this.username).ignoreIfNull().notBlank(); baseDataValidator.reset().parameter("username").value(this.username).ignoreIfNull().notBlank();
baseDataValidator.reset().parameter("firstname").value(this.firstname).ignoreIfNull().notBlank(); baseDataValidator.reset().parameter("firstname").value(this.firstname).ignoreIfNull().notBlank();
baseDataValidator.reset().parameter("lastname").value(this.lastname).ignoreIfNull().notBlank(); baseDataValidator.reset().parameter("lastname").value(this.lastname).ignoreIfNull().notBlank();
@@ -151,8 +106,8 @@ public class UserCommand {
baseDataValidator.reset().parameter("password").value(this.password).ignoreIfNull() baseDataValidator.reset().parameter("password").value(this.password).ignoreIfNull()
.equalToParameter("repeatPassword", this.repeatPassword); .equalToParameter("repeatPassword", this.repeatPassword);
baseDataValidator.reset().anyOfNotNull(this.username, this.firstname, this.lastname, this.email, this.officeId, baseDataValidator.reset().anyOfNotNull(this.username, this.firstname, this.lastname, this.email, this.officeId, this.roles,
this.roles, this.password, this.repeatPassword); this.password, this.repeatPassword);
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); } "Validation errors exist.", dataValidationErrors); }
@@ -3,7 +3,9 @@ package org.mifosplatform.useradministration.domain;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.persistence.Column; import javax.persistence.Column;
@@ -16,11 +18,13 @@ import javax.persistence.ManyToOne;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.UniqueConstraint; import javax.persistence.UniqueConstraint;
import org.apache.commons.lang.StringUtils;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom; import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom;
import org.mifosplatform.infrastructure.security.domain.PlatformUser; import org.mifosplatform.infrastructure.security.domain.PlatformUser;
import org.mifosplatform.infrastructure.security.exception.NoAuthorizationException; import org.mifosplatform.infrastructure.security.exception.NoAuthorizationException;
import org.mifosplatform.infrastructure.security.service.PlatformPasswordEncoder;
import org.mifosplatform.organisation.office.domain.Office; import org.mifosplatform.organisation.office.domain.Office;
import org.mifosplatform.useradministration.command.UserCommand;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.User;
@@ -71,8 +75,13 @@ public class AppUser extends AbstractAuditableCustom<AppUser, Long> implements P
@JoinTable(name = "m_appuser_role", joinColumns = @JoinColumn(name = "appuser_id"), inverseJoinColumns = @JoinColumn(name = "role_id")) @JoinTable(name = "m_appuser_role", joinColumns = @JoinColumn(name = "appuser_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> roles; private Set<Role> roles;
public static AppUser createNew(final Office office, final Set<Role> allRoles, final String username, final String email, public static AppUser fromJson(final Office userOffice, final Set<Role> allRoles, final JsonCommand command) {
final String firstname, final String lastname, final String password) {
final String username = command.stringValueOfParameterNamed("username");
String password = command.stringValueOfParameterNamed("password");
if (StringUtils.isBlank(password)) {
password = "autogenerate";
}
boolean userEnabled = true; boolean userEnabled = true;
boolean userAccountNonExpired = true; boolean userAccountNonExpired = true;
@@ -84,20 +93,18 @@ public class AppUser extends AbstractAuditableCustom<AppUser, Long> implements P
User user = new User(username, password, userEnabled, userAccountNonExpired, userCredentialsNonExpired, userAccountNonLocked, User user = new User(username, password, userEnabled, userAccountNonExpired, userCredentialsNonExpired, userAccountNonLocked,
authorities); authorities);
return new AppUser(office, user, allRoles, email, firstname, lastname);
final String email = command.stringValueOfParameterNamed("email");
final String firstname = command.stringValueOfParameterNamed("firstname");
final String lastname = command.stringValueOfParameterNamed("lastname");
return new AppUser(userOffice, user, allRoles, email, firstname, lastname);
} }
protected AppUser() { protected AppUser() {
this.office = null;
this.email = null;
this.username = null;
this.password = null;
this.accountNonExpired = false;
this.accountNonLocked = false; this.accountNonLocked = false;
this.credentialsNonExpired = false; this.credentialsNonExpired = false;
this.enabled = false;
this.roles = new HashSet<Role>(); this.roles = new HashSet<Role>();
this.firstTimeLoginRemaining = true;
} }
public AppUser(final Office office, final User user, final Set<Role> roles, final String email, final String firstname, public AppUser(final Office office, final User user, final Set<Role> roles, final String email, final String firstname,
@@ -121,27 +128,92 @@ public class AppUser extends AbstractAuditableCustom<AppUser, Long> implements P
this.firstTimeLoginRemaining = false; this.firstTimeLoginRemaining = false;
} }
public void update(final Set<Role> allRoles, final Office office, final UserCommand userCommand) { public void changeOffice(final Office differentOffice) {
this.office = differentOffice;
}
if (userCommand.isRolesChanged() && !allRoles.isEmpty()) { public void updateRoles(final Set<Role> allRoles) {
if (!allRoles.isEmpty()) {
this.roles.clear(); this.roles.clear();
this.roles = allRoles; this.roles = allRoles;
} }
if (userCommand.isOfficeChanged()) { }
this.office = office;
public Map<String, Object> update(final JsonCommand command, final PlatformPasswordEncoder platformPasswordEncoder) {
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(7);
// unencoded password provided
final String passwordParamName = "password";
final String passwordEncodedParamName = "passwordEncoded";
if (command.hasParameter(passwordParamName)) {
if (command.isChangeInPasswordParameterNamed(passwordParamName, this.password, platformPasswordEncoder, this.getId())) {
final String passwordEncodedValue = command.passwordValueOfParameterNamed(passwordParamName, platformPasswordEncoder,
this.getId());
actualChanges.put(passwordEncodedParamName, passwordEncodedValue);
updatePassword(passwordEncodedValue);
}
} }
if (userCommand.isUsernameChanged()) {
this.username = userCommand.getUsername(); if (command.hasParameter(passwordEncodedParamName)) {
if (command.isChangeInStringParameterNamed(passwordEncodedParamName, this.password)) {
final String newValue = command.stringValueOfParameterNamed(passwordEncodedParamName);
actualChanges.put(passwordEncodedParamName, newValue);
updatePassword(newValue);
}
} }
if (userCommand.isFirstnameChanged()) {
this.firstname = userCommand.getFirstname(); final String officeIdParamName = "officeId";
if (command.isChangeInLongParameterNamed(officeIdParamName, this.office.getId())) {
final Long newValue = command.longValueOfParameterNamed(officeIdParamName);
actualChanges.put(officeIdParamName, newValue);
} }
if (userCommand.isLastnameChanged()) {
this.lastname = userCommand.getLastname(); final String rolesParamName = "roles";
if (command.isChangeInArrayParameterNamed(rolesParamName, getRolesAsIdStringArray())) {
final String[] newValue = command.arrayValueOfParameterNamed(rolesParamName);
actualChanges.put(rolesParamName, newValue);
} }
if (userCommand.isEmailChanged()) {
this.email = userCommand.getEmail(); final String usernameParamName = "username";
if (command.isChangeInStringParameterNamed(usernameParamName, this.username)) {
final String newValue = command.stringValueOfParameterNamed(usernameParamName);
actualChanges.put(usernameParamName, newValue);
this.username = newValue;
} }
final String firstnameParamName = "firstname";
if (command.isChangeInStringParameterNamed(firstnameParamName, this.firstname)) {
final String newValue = command.stringValueOfParameterNamed(firstnameParamName);
actualChanges.put(firstnameParamName, newValue);
this.firstname = newValue;
}
final String lastnameParamName = "lastname";
if (command.isChangeInStringParameterNamed(lastnameParamName, this.lastname)) {
final String newValue = command.stringValueOfParameterNamed(lastnameParamName);
actualChanges.put(lastnameParamName, newValue);
this.lastname = newValue;
}
final String emailParamName = "email";
if (command.isChangeInStringParameterNamed(emailParamName, this.email)) {
final String newValue = command.stringValueOfParameterNamed(emailParamName);
actualChanges.put(emailParamName, newValue);
this.email = newValue;
}
return actualChanges;
}
private String[] getRolesAsIdStringArray() {
List<String> roleIds = new ArrayList<String>();
for (Role role : this.roles) {
roleIds.add(role.getId().toString());
}
return roleIds.toArray(new String[roleIds.size()]);
} }
/** /**
@@ -352,7 +424,7 @@ public class AppUser extends AbstractAuditableCustom<AppUser, Long> implements P
} }
return match; return match;
} }
public boolean hasIdOf(final Long userId) { public boolean hasIdOf(final Long userId) {
return getId().equals(userId); return getId().equals(userId);
} }
@@ -360,7 +432,7 @@ public class AppUser extends AbstractAuditableCustom<AppUser, Long> implements P
private boolean hasNotAnyPermission(final List<String> permissions) { private boolean hasNotAnyPermission(final List<String> permissions) {
return !hasAnyPermission(permissions); return !hasAnyPermission(permissions);
} }
private boolean hasAnyPermission(final List<String> permissions) { private boolean hasAnyPermission(final List<String> permissions) {
boolean hasAtLeastOneOf = false; boolean hasAtLeastOneOf = false;
@@ -370,7 +442,7 @@ public class AppUser extends AbstractAuditableCustom<AppUser, Long> implements P
break; break;
} }
} }
return hasAtLeastOneOf; return hasAtLeastOneOf;
} }
@@ -6,6 +6,9 @@ import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
import org.mifosplatform.infrastructure.core.serialization.AbstractFromApiJsonDeserializer;
import org.mifosplatform.infrastructure.core.serialization.CommandSerializer; import org.mifosplatform.infrastructure.core.serialization.CommandSerializer;
import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer; import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
@@ -13,13 +16,14 @@ import org.mifosplatform.useradministration.command.UserCommand;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.google.gson.JsonElement;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
/** /**
* Implementation of {@link FromApiJsonDeserializer} for {@link UserCommand}'s. * Implementation of {@link FromApiJsonDeserializer} for {@link UserCommand}'s.
*/ */
@Component @Component
public final class UserCommandFromApiJsonDeserializer implements FromApiJsonDeserializer<UserCommand> { public final class UserCommandFromApiJsonDeserializer extends AbstractFromApiJsonDeserializer<UserCommand> {
/** /**
* The parameters supported for this command. * The parameters supported for this command.
@@ -28,41 +32,36 @@ public final class UserCommandFromApiJsonDeserializer implements FromApiJsonDese
"repeatPassword", "email", "officeId", "notSelectedRoles", "roles")); "repeatPassword", "email", "officeId", "notSelectedRoles", "roles"));
private final FromJsonHelper fromApiJsonHelper; private final FromJsonHelper fromApiJsonHelper;
private final UserCommandFromCommandJsonDeserializer fromCommandJsonDeserializer;
private final CommandSerializer commandSerializerService;
@Autowired @Autowired
public UserCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper, public UserCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper, final CommandSerializer commandSerializerService) {
final UserCommandFromCommandJsonDeserializer fromCommandJsonDeserializer, final CommandSerializer commandSerializerService) { super(commandSerializerService);
this.fromApiJsonHelper = fromApiJsonHelper; this.fromApiJsonHelper = fromApiJsonHelper;
this.fromCommandJsonDeserializer = fromCommandJsonDeserializer;
this.commandSerializerService = commandSerializerService;
} }
@Override @Override
public UserCommand commandFromApiJson(final String json) { public UserCommand commandFromApiJson(@SuppressWarnings("unused") final Long userId, final String json) {
return commandFromApiJson(null, json);
}
@Override if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
public UserCommand commandFromApiJson(final Long userId, final String json) {
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType(); final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters);
return this.fromCommandJsonDeserializer.commandFromCommandJson(userId, json); final JsonElement element = fromApiJsonHelper.parse(json);
}
@Override final String username = fromApiJsonHelper.extractStringNamed("username", element);
public String serializedCommandJsonFromApiJson(final String json) { final String firstname = fromApiJsonHelper.extractStringNamed("firstname", element);
final UserCommand command = commandFromApiJson(json); final String lastname = fromApiJsonHelper.extractStringNamed("lastname", element);
return this.commandSerializerService.serializeCommandToJson(command); final String password = fromApiJsonHelper.extractStringNamed("password", element);
} final String repeatPassword = fromApiJsonHelper.extractStringNamed("repeatPassword", element);
final String passwordEncoded = fromApiJsonHelper.extractStringNamed("passwordEncoded", element);
final String email = fromApiJsonHelper.extractStringNamed("email", element);
final Long officeId = fromApiJsonHelper.extractLongNamed("officeId", element);
@Override final String[] notSelectedRoles = fromApiJsonHelper.extractArrayNamed("notSelectedRoles", element);
public String serializedCommandJsonFromApiJson(final Long userId, final String json) { final String[] roles = fromApiJsonHelper.extractArrayNamed("roles", element);
final UserCommand command = commandFromApiJson(userId, json);
return this.commandSerializerService.serializeCommandToJson(command); return new UserCommand(username, firstname, lastname, password, repeatPassword, passwordEncoded, email, officeId, notSelectedRoles, roles);
} }
} }
@@ -1,61 +0,0 @@
package org.mifosplatform.useradministration.serialization;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
import org.mifosplatform.infrastructure.core.serialization.FromCommandJsonDeserializer;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.useradministration.command.UserCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.google.gson.JsonElement;
/**
*
*/
@Component
public final class UserCommandFromCommandJsonDeserializer implements FromCommandJsonDeserializer<UserCommand> {
private final FromJsonHelper fromJsonHelper;
@Autowired
public UserCommandFromCommandJsonDeserializer(final FromJsonHelper fromApiJsonHelper) {
this.fromJsonHelper = fromApiJsonHelper;
}
@Override
public UserCommand commandFromCommandJson(final String commandAsJson) {
return commandFromCommandJson(null, commandAsJson);
}
@Override
public UserCommand commandFromCommandJson(final Long userId, final String commandAsJson) {
return commandFromCommandJson(userId, commandAsJson, false);
}
@Override
public UserCommand commandFromCommandJson(final Long userId, final String commandAsJson, final boolean makerCheckerApproval) {
if (StringUtils.isBlank(commandAsJson)) { throw new InvalidJsonException(); }
final Set<String> parametersPassedInRequest = new HashSet<String>();
final JsonElement element = fromJsonHelper.parse(commandAsJson);
final String username = fromJsonHelper.extractStringNamed("username", element, parametersPassedInRequest);
final String firstname = fromJsonHelper.extractStringNamed("firstname", element, parametersPassedInRequest);
final String lastname = fromJsonHelper.extractStringNamed("lastname", element, parametersPassedInRequest);
final String password = fromJsonHelper.extractStringNamed("password", element, parametersPassedInRequest);
final String repeatPassword = fromJsonHelper.extractStringNamed("repeatPassword", element, parametersPassedInRequest);
final String email = fromJsonHelper.extractStringNamed("email", element, parametersPassedInRequest);
final Long officeId = fromJsonHelper.extractLongNamed("officeId", element, parametersPassedInRequest);
final String[] notSelectedRoles = fromJsonHelper.extractArrayNamed("notSelectedRoles", element, parametersPassedInRequest);
final String[] roles = fromJsonHelper.extractArrayNamed("roles", element, parametersPassedInRequest);
return new UserCommand(parametersPassedInRequest, makerCheckerApproval, userId, username, firstname, lastname, password,
repeatPassword, email, officeId, notSelectedRoles, roles);
}
}
@@ -1,16 +1,17 @@
package org.mifosplatform.useradministration.service; package org.mifosplatform.useradministration.service;
import org.mifosplatform.useradministration.command.UserCommand; import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
public interface AppUserWritePlatformService { public interface AppUserWritePlatformService {
Long createUser(UserCommand command); Long createUser(JsonCommand command);
Long updateUser(UserCommand command); EntityIdentifier updateUser(Long userId, JsonCommand command);
void deleteUser(UserCommand command); void deleteUser(Long userId, JsonCommand 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).
Long updateUsersOwnAccountDetails(UserCommand command); EntityIdentifier updateUsersOwnAccountDetails(Long userId, JsonCommand command);
} }
@@ -3,15 +3,15 @@ package org.mifosplatform.useradministration.service;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import org.apache.commons.lang.StringUtils; import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.ApiParameterError; import org.mifosplatform.infrastructure.core.data.ApiParameterError;
import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException; import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
import org.mifosplatform.infrastructure.core.service.PlatformEmailSendException; import org.mifosplatform.infrastructure.core.service.PlatformEmailSendException;
import org.mifosplatform.infrastructure.security.domain.BasicPasswordEncodablePlatformUser;
import org.mifosplatform.infrastructure.security.domain.PlatformUser;
import org.mifosplatform.infrastructure.security.service.PlatformPasswordEncoder; import org.mifosplatform.infrastructure.security.service.PlatformPasswordEncoder;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.organisation.monetary.service.ConfigurationDomainService; import org.mifosplatform.organisation.monetary.service.ConfigurationDomainService;
@@ -27,6 +27,7 @@ import org.mifosplatform.useradministration.domain.RoleRepository;
import org.mifosplatform.useradministration.domain.UserDomainService; import org.mifosplatform.useradministration.domain.UserDomainService;
import org.mifosplatform.useradministration.exception.RoleNotFoundException; import org.mifosplatform.useradministration.exception.RoleNotFoundException;
import org.mifosplatform.useradministration.exception.UserNotFoundException; import org.mifosplatform.useradministration.exception.UserNotFoundException;
import org.mifosplatform.useradministration.serialization.UserCommandFromApiJsonDeserializer;
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;
@@ -47,11 +48,13 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
private final OfficeRepository officeRepository; private final OfficeRepository officeRepository;
private final RoleRepository roleRepository; private final RoleRepository roleRepository;
private final ConfigurationDomainService configurationDomainService; private final ConfigurationDomainService configurationDomainService;
private final UserCommandFromApiJsonDeserializer fromApiJsonDeserializer;
@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 ConfigurationDomainService configurationDomainService) { final PlatformPasswordEncoder platformPasswordEncoder, final ConfigurationDomainService configurationDomainService,
final UserCommandFromApiJsonDeserializer fromApiJsonDeserializer) {
this.context = context; this.context = context;
this.appUserRepository = appUserRepository; this.appUserRepository = appUserRepository;
this.userDomainService = userDomainService; this.userDomainService = userDomainService;
@@ -59,29 +62,29 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
this.roleRepository = roleRepository; this.roleRepository = roleRepository;
this.platformPasswordEncoder = platformPasswordEncoder; this.platformPasswordEncoder = platformPasswordEncoder;
this.configurationDomainService = configurationDomainService; this.configurationDomainService = configurationDomainService;
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
} }
@Transactional @Transactional
@Override @Override
public Long createUser(final UserCommand command) { public Long createUser(final JsonCommand command) {
try { try {
context.authenticatedUser(); context.authenticatedUser();
command.validateForCreate();
final Set<Role> allRoles = assembleSetOfRoles(command); final UserCommand userCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json());
userCommand.validateForCreate();
final Office office = this.officeRepository.findOne(command.getOfficeId()); final String officeIdParamName = "officeId";
if (office == null) { throw new OfficeNotFoundException(command.getOfficeId()); } final Long officeId = command.longValueOfParameterNamed(officeIdParamName);
String password = command.getPassword(); final Office userOffice = this.officeRepository.findOne(officeId);
if (StringUtils.isBlank(password)) { if (userOffice == null) { throw new OfficeNotFoundException(officeId); }
password = "autogenerate";
}
final AppUser appUser = AppUser.createNew(office, allRoles, command.getUsername(), command.getEmail(), command.getFirstname(), final String[] roles = command.arrayValueOfParameterNamed("roles");
command.getLastname(), password); final Set<Role> allRoles = assembleSetOfRoles(roles);
final AppUser appUser = AppUser.fromJson(userOffice, allRoles, command);
this.userDomainService.create(appUser, command.isApprovedByChecker()); this.userDomainService.create(appUser, command.isApprovedByChecker());
return appUser.getId(); return appUser.getId();
@@ -90,8 +93,10 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
return Long.valueOf(-1); return Long.valueOf(-1);
} catch (PlatformEmailSendException e) { } catch (PlatformEmailSendException e) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>(); final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final String email = command.stringValueOfParameterNamed("email");
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", email);
dataValidationErrors.add(error); dataValidationErrors.add(error);
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
@@ -101,42 +106,44 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
@Transactional @Transactional
@Override @Override
public Long updateUser(final UserCommand command) { public EntityIdentifier updateUser(final Long userId, final JsonCommand command) {
try { try {
context.authenticatedUser(); context.authenticatedUser();
command.validateForUpdate();
final Set<Role> allRoles = assembleSetOfRoles(command); final UserCommand userCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json());
userCommand.validateForUpdate();
Office office = null; final AppUser userToUpdate = this.appUserRepository.findOne(userId);
if (command.isOfficeChanged()) { if (userToUpdate == null) { throw new UserNotFoundException(userId); }
office = this.officeRepository.findOne(command.getOfficeId());
if (office == null) { throw new OfficeNotFoundException(command.getOfficeId()); } final Map<String, Object> changes = userToUpdate.update(command, this.platformPasswordEncoder);
if (changes.containsKey("officeId")) {
final Long officeId = (Long) changes.get("officeId");
final Office office = this.officeRepository.findOne(officeId);
if (office == null) { throw new OfficeNotFoundException(officeId); }
userToUpdate.changeOffice(office);
} }
final AppUser userToUpdate = this.appUserRepository.findOne(command.getId()); if (changes.containsKey("roles")) {
if (userToUpdate == null) { throw new UserNotFoundException(command.getId()); } final String[] roleIds = (String[]) changes.get("roles");
final Set<Role> allRoles = assembleSetOfRoles(roleIds);
userToUpdate.update(allRoles, office, command); userToUpdate.updateRoles(allRoles);
this.appUserRepository.saveAndFlush(userToUpdate); }
if (command.isPasswordChanged()) { if (!changes.isEmpty()) {
PlatformUser dummyPlatformUser = new BasicPasswordEncodablePlatformUser(userToUpdate.getId(), userToUpdate.getUsername(), this.appUserRepository.save(userToUpdate);
command.getPassword());
String newPasswordEncoded = this.platformPasswordEncoder.encode(dummyPlatformUser);
userToUpdate.updatePassword(newPasswordEncoded);
this.appUserRepository.saveAndFlush(userToUpdate);
} }
if (this.configurationDomainService.isMakerCheckerEnabledForTask("UPDATE_USER") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } if (this.configurationDomainService.isMakerCheckerEnabledForTask("UPDATE_USER") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); }
return userToUpdate.getId(); return EntityIdentifier.withChanges(userId, changes);
} catch (DataIntegrityViolationException dve) { } catch (DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve); handleDataIntegrityIssues(command, dve);
return Long.valueOf(-1); return EntityIdentifier.empty();
} }
} }
@@ -147,52 +154,53 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
*/ */
@Transactional @Transactional
@Override @Override
public Long updateUsersOwnAccountDetails(final UserCommand command) { public EntityIdentifier updateUsersOwnAccountDetails(final Long userId, final JsonCommand command) {
try { try {
context.authenticatedUser(); context.authenticatedUser();
command.validateForUpdate();
final Set<Role> allRoles = assembleSetOfRoles(command); final UserCommand userCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json());
userCommand.validateForUpdate();
Office office = null; final AppUser userToUpdate = this.appUserRepository.findOne(userId);
if (command.isOfficeChanged()) { if (userToUpdate == null) { throw new UserNotFoundException(userId); }
office = this.officeRepository.findOne(command.getOfficeId());
if (office == null) { throw new OfficeNotFoundException(command.getOfficeId()); } final Map<String, Object> changes = userToUpdate.update(command, this.platformPasswordEncoder);
if (changes.containsKey("officeId")) {
final Long officeId = (Long) changes.get("officeId");
final Office office = this.officeRepository.findOne(officeId);
if (office == null) { throw new OfficeNotFoundException(officeId); }
userToUpdate.changeOffice(office);
} }
final AppUser userToUpdate = this.appUserRepository.findOne(command.getId()); if (changes.containsKey("roles")) {
if (userToUpdate == null) { throw new UserNotFoundException(command.getId()); } final String[] roleIds = (String[]) changes.get("roles");
final Set<Role> allRoles = assembleSetOfRoles(roleIds);
userToUpdate.update(allRoles, office, command); userToUpdate.updateRoles(allRoles);
this.appUserRepository.saveAndFlush(userToUpdate); }
if (command.isPasswordChanged()) { if (!changes.isEmpty()) {
PlatformUser dummyPlatformUser = new BasicPasswordEncodablePlatformUser(userToUpdate.getId(), userToUpdate.getUsername(),
command.getPassword());
String newPasswordEncoded = this.platformPasswordEncoder.encode(dummyPlatformUser);
userToUpdate.updatePassword(newPasswordEncoded);
this.appUserRepository.saveAndFlush(userToUpdate); this.appUserRepository.saveAndFlush(userToUpdate);
} }
return userToUpdate.getId(); return EntityIdentifier.withChanges(userId, changes);
} catch (DataIntegrityViolationException dve) { } catch (DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve); handleDataIntegrityIssues(command, dve);
return Long.valueOf(-1); return EntityIdentifier.empty();
} }
} }
private Set<Role> assembleSetOfRoles(final UserCommand command) { private Set<Role> assembleSetOfRoles(final String[] rolesArray) {
final Set<Role> allRoles = new HashSet<Role>(); final Set<Role> allRoles = new HashSet<Role>();
String[] rolesArray = command.getRoles(); if (!ObjectUtils.isEmpty(rolesArray)) {
if (command.isRolesChanged() && !ObjectUtils.isEmpty(rolesArray)) {
for (String roleId : rolesArray) { for (String roleId : rolesArray) {
Long id = Long.valueOf(roleId); final Long id = Long.valueOf(roleId);
Role role = this.roleRepository.findOne(id); final Role role = this.roleRepository.findOne(id);
if (role == null) { throw new RoleNotFoundException(id); } if (role == null) { throw new RoleNotFoundException(id); }
allRoles.add(role); allRoles.add(role);
} }
@@ -203,10 +211,9 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
@Transactional @Transactional
@Override @Override
public void deleteUser(final UserCommand command) { public void deleteUser(final Long userId, final JsonCommand command) {
final Long userId = command.getId(); final 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();
@@ -219,14 +226,14 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
* Guaranteed to throw an exception no matter what the data integrity issue * Guaranteed to throw an exception no matter what the data integrity issue
* is. * is.
*/ */
private void handleDataIntegrityIssues(final UserCommand command, final DataIntegrityViolationException dve) { private void handleDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) {
Throwable realCause = dve.getMostSpecificCause(); Throwable realCause = dve.getMostSpecificCause();
if (realCause.getMessage().contains("username_org")) { if (realCause.getMessage().contains("username_org")) {
StringBuilder defaultMessageBuilder = new StringBuilder("User with username ").append(command.getUsername()).append( final String username = command.stringValueOfParameterNamed("username");
" already exists."); StringBuilder defaultMessageBuilder = new StringBuilder("User with username ").append(username).append(" already exists.");
throw new PlatformDataIntegrityException("error.msg.user.duplicate.username", defaultMessageBuilder.toString(), "username", throw new PlatformDataIntegrityException("error.msg.user.duplicate.username", defaultMessageBuilder.toString(), "username",
command.getUsername()); username);
} }
logger.error(dve.getMessage(), dve); logger.error(dve.getMessage(), dve);