Improve error logging for failed user creation (FINERACT-1070)
This commit is contained in:
+29
-51
@@ -20,7 +20,6 @@ package org.apache.fineract.useradministration.service;
|
|||||||
|
|
||||||
import com.google.gson.JsonArray;
|
import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -107,11 +106,10 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
|
|||||||
this.topicDomainService = topicDomainService;
|
this.topicDomainService = topicDomainService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional
|
||||||
@Caching(evict = { @CacheEvict(value = "users", allEntries = true), @CacheEvict(value = "usersByUsername", allEntries = true) })
|
@Caching(evict = { @CacheEvict(value = "users", allEntries = true), @CacheEvict(value = "usersByUsername", allEntries = true) })
|
||||||
public CommandProcessingResult createUser(final JsonCommand command) {
|
public CommandProcessingResult createUser(final JsonCommand command) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.context.authenticatedUser();
|
this.context.authenticatedUser();
|
||||||
|
|
||||||
@@ -125,17 +123,17 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
|
|||||||
final String[] roles = command.arrayValueOfParameterNamed("roles");
|
final String[] roles = command.arrayValueOfParameterNamed("roles");
|
||||||
final Set<Role> allRoles = assembleSetOfRoles(roles);
|
final Set<Role> allRoles = assembleSetOfRoles(roles);
|
||||||
|
|
||||||
AppUser appUser;
|
|
||||||
|
|
||||||
final String staffIdParamName = "staffId";
|
final String staffIdParamName = "staffId";
|
||||||
final Long staffId = command.longValueOfParameterNamed(staffIdParamName);
|
final Long staffId = command.longValueOfParameterNamed(staffIdParamName);
|
||||||
|
|
||||||
Staff linkedStaff = null;
|
Staff linkedStaff;
|
||||||
if (staffId != null) {
|
if (staffId != null) {
|
||||||
linkedStaff = this.staffRepositoryWrapper.findByOfficeWithNotFoundDetection(staffId, userOffice.getId());
|
linkedStaff = this.staffRepositoryWrapper.findByOfficeWithNotFoundDetection(staffId, userOffice.getId());
|
||||||
|
} else {
|
||||||
|
linkedStaff = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection<Client> clients = null;
|
Collection<Client> clients;
|
||||||
if (command.hasParameter(AppUserConstants.IS_SELF_SERVICE_USER)
|
if (command.hasParameter(AppUserConstants.IS_SELF_SERVICE_USER)
|
||||||
&& command.booleanPrimitiveValueOfParameterNamed(AppUserConstants.IS_SELF_SERVICE_USER)
|
&& command.booleanPrimitiveValueOfParameterNamed(AppUserConstants.IS_SELF_SERVICE_USER)
|
||||||
&& command.hasParameter(AppUserConstants.CLIENTS)) {
|
&& command.hasParameter(AppUserConstants.CLIENTS)) {
|
||||||
@@ -145,9 +143,11 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
|
|||||||
clientIds.add(clientElement.getAsLong());
|
clientIds.add(clientElement.getAsLong());
|
||||||
}
|
}
|
||||||
clients = this.clientRepositoryWrapper.findAll(clientIds);
|
clients = this.clientRepositoryWrapper.findAll(clientIds);
|
||||||
|
} else {
|
||||||
|
clients = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
appUser = AppUser.fromJson(userOffice, linkedStaff, allRoles, clients, command);
|
AppUser appUser = AppUser.fromJson(userOffice, linkedStaff, allRoles, clients, command);
|
||||||
|
|
||||||
final Boolean sendPasswordToEmail = command.booleanObjectValueOfParameterNamed("sendPasswordToEmail");
|
final Boolean sendPasswordToEmail = command.booleanObjectValueOfParameterNamed("sendPasswordToEmail");
|
||||||
this.userDomainService.create(appUser, sendPasswordToEmail);
|
this.userDomainService.create(appUser, sendPasswordToEmail);
|
||||||
@@ -160,34 +160,29 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
|
|||||||
.withOfficeId(userOffice.getId()) //
|
.withOfficeId(userOffice.getId()) //
|
||||||
.build();
|
.build();
|
||||||
} catch (final DataIntegrityViolationException dve) {
|
} catch (final DataIntegrityViolationException dve) {
|
||||||
handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
|
throw handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
|
||||||
return CommandProcessingResult.empty();
|
|
||||||
} catch (final JpaSystemException | PersistenceException | AuthenticationServiceException dve) {
|
} catch (final JpaSystemException | PersistenceException | AuthenticationServiceException dve) {
|
||||||
|
LOG.error("createUser: JpaSystemException | PersistenceException | AuthenticationServiceException", dve);
|
||||||
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
|
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
|
||||||
handleDataIntegrityIssues(command, throwable, dve);
|
throw handleDataIntegrityIssues(command, throwable, dve);
|
||||||
return new CommandProcessingResultBuilder() //
|
|
||||||
.withCommandId(command.commandId()) //
|
|
||||||
.build();
|
|
||||||
} catch (final PlatformEmailSendException e) {
|
} catch (final PlatformEmailSendException e) {
|
||||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
LOG.error("createUser: PlatformEmailSendException", e);
|
||||||
|
|
||||||
final String email = command.stringValueOfParameterNamed("email");
|
final String email = command.stringValueOfParameterNamed("email");
|
||||||
final ApiParameterError error = ApiParameterError.parameterError("error.msg.user.email.invalid",
|
final ApiParameterError error = ApiParameterError.parameterError("error.msg.user.email.invalid",
|
||||||
"The parameter email is invalid.", "email", email);
|
"Sending email failed; is parameter email is invalid? More details available in server log: " + e.getMessage(), "email",
|
||||||
dataValidationErrors.add(error);
|
email);
|
||||||
|
|
||||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
|
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
|
||||||
dataValidationErrors, e);
|
List.of(error), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional
|
||||||
@Caching(evict = { @CacheEvict(value = "users", allEntries = true), @CacheEvict(value = "usersByUsername", allEntries = true) })
|
@Caching(evict = { @CacheEvict(value = "users", allEntries = true), @CacheEvict(value = "usersByUsername", allEntries = true) })
|
||||||
public CommandProcessingResult updateUser(final Long userId, final JsonCommand command) {
|
public CommandProcessingResult updateUser(final Long userId, final JsonCommand command) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
this.context.authenticatedUser(new CommandWrapperBuilder().updateUser(null).build());
|
this.context.authenticatedUser(new CommandWrapperBuilder().updateUser(null).build());
|
||||||
|
|
||||||
this.fromApiJsonDeserializer.validateForUpdate(command.json());
|
this.fromApiJsonDeserializer.validateForUpdate(command.json());
|
||||||
@@ -251,57 +246,40 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
|
|||||||
.with(changes) //
|
.with(changes) //
|
||||||
.build();
|
.build();
|
||||||
} catch (final DataIntegrityViolationException dve) {
|
} catch (final DataIntegrityViolationException dve) {
|
||||||
handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
|
throw handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
|
||||||
return CommandProcessingResult.empty();
|
|
||||||
} catch (final JpaSystemException | PersistenceException | AuthenticationServiceException dve) {
|
} catch (final JpaSystemException | PersistenceException | AuthenticationServiceException dve) {
|
||||||
|
LOG.error("updateUser: JpaSystemException | PersistenceException | AuthenticationServiceException", dve);
|
||||||
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
|
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
|
||||||
handleDataIntegrityIssues(command, throwable, dve);
|
throw handleDataIntegrityIssues(command, throwable, dve);
|
||||||
return new CommandProcessingResultBuilder() //
|
|
||||||
.withCommandId(command.commandId()) //
|
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* encode the new submitted password retrieve the last n used password check if the current submitted password,
|
* Encode the new submitted password and retrieve the last N used passwords to check if the current submitted
|
||||||
* match with one of them
|
* password matches with one of them.
|
||||||
*
|
|
||||||
* @param user
|
|
||||||
* @param command
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
private AppUserPreviousPassword getCurrentPasswordToSaveAsPreview(final AppUser user, final JsonCommand command) {
|
private AppUserPreviousPassword getCurrentPasswordToSaveAsPreview(final AppUser user, final JsonCommand command) {
|
||||||
|
|
||||||
final String passWordEncodedValue = user.getEncodedPassword(command, this.platformPasswordEncoder);
|
final String passWordEncodedValue = user.getEncodedPassword(command, this.platformPasswordEncoder);
|
||||||
|
|
||||||
AppUserPreviousPassword currentPasswordToSaveAsPreview = null;
|
AppUserPreviousPassword currentPasswordToSaveAsPreview = null;
|
||||||
|
|
||||||
if (passWordEncodedValue != null) {
|
if (passWordEncodedValue != null) {
|
||||||
|
|
||||||
PageRequest pageRequest = PageRequest.of(0, AppUserApiConstant.numberOfPreviousPasswords, Sort.Direction.DESC, "removalDate");
|
PageRequest pageRequest = PageRequest.of(0, AppUserApiConstant.numberOfPreviousPasswords, Sort.Direction.DESC, "removalDate");
|
||||||
|
|
||||||
final List<AppUserPreviousPassword> nLastUsedPasswords = this.appUserPreviewPasswordRepository.findByUserId(user.getId(),
|
final List<AppUserPreviousPassword> nLastUsedPasswords = this.appUserPreviewPasswordRepository.findByUserId(user.getId(),
|
||||||
pageRequest);
|
pageRequest);
|
||||||
|
|
||||||
for (AppUserPreviousPassword aPreviewPassword : nLastUsedPasswords) {
|
for (AppUserPreviousPassword aPreviewPassword : nLastUsedPasswords) {
|
||||||
|
|
||||||
if (aPreviewPassword.getPassword().equals(passWordEncodedValue)) {
|
if (aPreviewPassword.getPassword().equals(passWordEncodedValue)) {
|
||||||
|
|
||||||
throw new PasswordPreviouslyUsedException();
|
throw new PasswordPreviouslyUsedException();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentPasswordToSaveAsPreview = new AppUserPreviousPassword(user);
|
currentPasswordToSaveAsPreview = new AppUserPreviousPassword(user);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return currentPasswordToSaveAsPreview;
|
return currentPasswordToSaveAsPreview;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<Role> assembleSetOfRoles(final String[] rolesArray) {
|
private Set<Role> assembleSetOfRoles(final String[] rolesArray) {
|
||||||
|
|
||||||
final Set<Role> allRoles = new HashSet<>();
|
final Set<Role> allRoles = new HashSet<>();
|
||||||
|
|
||||||
if (!ObjectUtils.isEmpty(rolesArray)) {
|
if (!ObjectUtils.isEmpty(rolesArray)) {
|
||||||
@@ -315,11 +293,10 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
|
|||||||
return allRoles;
|
return allRoles;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional
|
||||||
@Caching(evict = { @CacheEvict(value = "users", allEntries = true), @CacheEvict(value = "usersByUsername", allEntries = true) })
|
@Caching(evict = { @CacheEvict(value = "users", allEntries = true), @CacheEvict(value = "usersByUsername", allEntries = true) })
|
||||||
public CommandProcessingResult deleteUser(final Long userId) {
|
public CommandProcessingResult deleteUser(final Long userId) {
|
||||||
|
|
||||||
final AppUser user = this.appUserRepository.findById(userId).orElseThrow(() -> new UserNotFoundException(userId));
|
final AppUser user = this.appUserRepository.findById(userId).orElseThrow(() -> new UserNotFoundException(userId));
|
||||||
if (user.isDeleted()) {
|
if (user.isDeleted()) {
|
||||||
throw new UserNotFoundException(userId);
|
throw new UserNotFoundException(userId);
|
||||||
@@ -333,23 +310,24 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Guaranteed to throw an exception no matter what the data integrity issue is.
|
* Return an exception to throw, no matter what the data integrity issue is.
|
||||||
*/
|
*/
|
||||||
private void handleDataIntegrityIssues(final JsonCommand command, final Throwable realCause, final Exception dve) {
|
private PlatformDataIntegrityException handleDataIntegrityIssues(final JsonCommand command, final Throwable realCause,
|
||||||
|
final Exception dve) {
|
||||||
if (realCause.getMessage().contains("'username_org'")) {
|
if (realCause.getMessage().contains("'username_org'")) {
|
||||||
final String username = command.stringValueOfParameterNamed("username");
|
final String username = command.stringValueOfParameterNamed("username");
|
||||||
final StringBuilder defaultMessageBuilder = new StringBuilder("User with username ").append(username)
|
final StringBuilder defaultMessageBuilder = new StringBuilder("User with username ").append(username)
|
||||||
.append(" already exists.");
|
.append(" already exists.");
|
||||||
throw new PlatformDataIntegrityException("error.msg.user.duplicate.username", defaultMessageBuilder.toString(), "username",
|
return new PlatformDataIntegrityException("error.msg.user.duplicate.username", defaultMessageBuilder.toString(), "username",
|
||||||
username);
|
username);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (realCause.getMessage().contains("'unique_self_client'")) {
|
if (realCause.getMessage().contains("'unique_self_client'")) {
|
||||||
throw new PlatformDataIntegrityException("error.msg.user.self.service.user.already.exist",
|
return new PlatformDataIntegrityException("error.msg.user.self.service.user.already.exist",
|
||||||
"Self Service User Id is already created. Go to Admin->Users to edit or delete the self-service user.");
|
"Self Service User Id is already created. Go to Admin->Users to edit or delete the self-service user.");
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG.error("Error occured.", dve);
|
LOG.error("handleDataIntegrityIssues: Neither duplicate username nor existing user; unknown error occured", dve);
|
||||||
throw new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue", "Unknown data integrity issue with resource.");
|
return new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue", "Unknown data integrity issue with resource.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -25,7 +25,7 @@ import org.junit.jupiter.api.Disabled;
|
|||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Integration Test for /staff API.
|
* Integration Test for /runreports/ API.
|
||||||
*
|
*
|
||||||
* @author Michael Vorburger.ch
|
* @author Michael Vorburger.ch
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user