Skip to content

Commit

Permalink
Improve error logging for failed user creation (FINERACT-1070)
Browse files Browse the repository at this point in the history
  • Loading branch information
vorburger committed Dec 13, 2020
1 parent 7e1d6da commit 2b4ee62
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
Expand Down Expand Up @@ -107,11 +106,10 @@ public AppUserWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContex
this.topicDomainService = topicDomainService;
}

@Transactional
@Override
@Transactional
@Caching(evict = { @CacheEvict(value = "users", allEntries = true), @CacheEvict(value = "usersByUsername", allEntries = true) })
public CommandProcessingResult createUser(final JsonCommand command) {

try {
this.context.authenticatedUser();

Expand All @@ -125,17 +123,17 @@ public CommandProcessingResult createUser(final JsonCommand command) {
final String[] roles = command.arrayValueOfParameterNamed("roles");
final Set<Role> allRoles = assembleSetOfRoles(roles);

AppUser appUser;

final String staffIdParamName = "staffId";
final Long staffId = command.longValueOfParameterNamed(staffIdParamName);

Staff linkedStaff = null;
Staff linkedStaff;
if (staffId != null) {
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)
&& command.booleanPrimitiveValueOfParameterNamed(AppUserConstants.IS_SELF_SERVICE_USER)
&& command.hasParameter(AppUserConstants.CLIENTS)) {
Expand All @@ -145,9 +143,11 @@ public CommandProcessingResult createUser(final JsonCommand command) {
clientIds.add(clientElement.getAsLong());
}
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");
this.userDomainService.create(appUser, sendPasswordToEmail);
Expand All @@ -160,34 +160,29 @@ public CommandProcessingResult createUser(final JsonCommand command) {
.withOfficeId(userOffice.getId()) //
.build();
} catch (final DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty();
throw handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
} catch (final JpaSystemException | PersistenceException | AuthenticationServiceException dve) {
LOG.error("createUser: JpaSystemException | PersistenceException | AuthenticationServiceException", dve);
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
handleDataIntegrityIssues(command, throwable, dve);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.build();
throw handleDataIntegrityIssues(command, throwable, dve);
} catch (final PlatformEmailSendException e) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
LOG.error("createUser: PlatformEmailSendException", e);

final String email = command.stringValueOfParameterNamed("email");
final ApiParameterError error = ApiParameterError.parameterError("error.msg.user.email.invalid",
"The parameter email is invalid.", "email", email);
dataValidationErrors.add(error);
"Sending email failed; is parameter email is invalid? More details available in server log: " + e.getMessage(), "email",
email);

throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors, e);
List.of(error), e);
}
}

@Transactional
@Override
@Transactional
@Caching(evict = { @CacheEvict(value = "users", allEntries = true), @CacheEvict(value = "usersByUsername", allEntries = true) })
public CommandProcessingResult updateUser(final Long userId, final JsonCommand command) {

try {

this.context.authenticatedUser(new CommandWrapperBuilder().updateUser(null).build());

this.fromApiJsonDeserializer.validateForUpdate(command.json());
Expand Down Expand Up @@ -251,57 +246,40 @@ public CommandProcessingResult updateUser(final Long userId, final JsonCommand c
.with(changes) //
.build();
} catch (final DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty();
throw handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
} catch (final JpaSystemException | PersistenceException | AuthenticationServiceException dve) {
LOG.error("updateUser: JpaSystemException | PersistenceException | AuthenticationServiceException", dve);
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
handleDataIntegrityIssues(command, throwable, dve);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.build();
throw handleDataIntegrityIssues(command, throwable, dve);
}
}

/**
* encode the new submitted password retrieve the last n used password check if the current submitted password,
* match with one of them
*
* @param user
* @param command
* @return
* Encode the new submitted password and retrieve the last N used passwords to check if the current submitted
* password matches with one of them.
*/
private AppUserPreviousPassword getCurrentPasswordToSaveAsPreview(final AppUser user, final JsonCommand command) {

final String passWordEncodedValue = user.getEncodedPassword(command, this.platformPasswordEncoder);

AppUserPreviousPassword currentPasswordToSaveAsPreview = null;

if (passWordEncodedValue != null) {

PageRequest pageRequest = PageRequest.of(0, AppUserApiConstant.numberOfPreviousPasswords, Sort.Direction.DESC, "removalDate");

final List<AppUserPreviousPassword> nLastUsedPasswords = this.appUserPreviewPasswordRepository.findByUserId(user.getId(),
pageRequest);

for (AppUserPreviousPassword aPreviewPassword : nLastUsedPasswords) {

if (aPreviewPassword.getPassword().equals(passWordEncodedValue)) {

throw new PasswordPreviouslyUsedException();

}
}

currentPasswordToSaveAsPreview = new AppUserPreviousPassword(user);

}

return currentPasswordToSaveAsPreview;

}

private Set<Role> assembleSetOfRoles(final String[] rolesArray) {

final Set<Role> allRoles = new HashSet<>();

if (!ObjectUtils.isEmpty(rolesArray)) {
Expand All @@ -315,11 +293,10 @@ private Set<Role> assembleSetOfRoles(final String[] rolesArray) {
return allRoles;
}

@Transactional
@Override
@Transactional
@Caching(evict = { @CacheEvict(value = "users", allEntries = true), @CacheEvict(value = "usersByUsername", allEntries = true) })
public CommandProcessingResult deleteUser(final Long userId) {

final AppUser user = this.appUserRepository.findById(userId).orElseThrow(() -> new UserNotFoundException(userId));
if (user.isDeleted()) {
throw new UserNotFoundException(userId);
Expand All @@ -333,23 +310,24 @@ public CommandProcessingResult deleteUser(final Long userId) {
}

/*
* 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'")) {
final String username = command.stringValueOfParameterNamed("username");
final StringBuilder defaultMessageBuilder = new StringBuilder("User with username ").append(username)
.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);
}

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.");
}

LOG.error("Error occured.", dve);
throw new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue", "Unknown data integrity issue with resource.");
LOG.error("handleDataIntegrityIssues: Neither duplicate username nor existing user; unknown error occured", dve);
return new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue", "Unknown data integrity issue with resource.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import org.junit.jupiter.api.Test;

/**
* Integration Test for /staff API.
* Integration Test for /runreports/ API.
*
* @author Michael Vorburger.ch
*/
Expand Down

0 comments on commit 2b4ee62

Please sign in to comment.