use of com.sanctionco.thunder.models.User in project thunder by RohanNagar.
the class DynamoDbUsersDao method findByEmail.
@Override
public CompletableFuture<User> findByEmail(String email) {
Objects.requireNonNull(email);
GetItemRequest request = GetItemRequest.builder().tableName(tableName).key(Collections.singletonMap("email", AttributeValue.builder().s(email).build())).build();
return dynamoDbClient.getItem(request).thenApply(response -> {
if (response.item().size() <= 0) {
LOG.warn("The email {} was not found in the database.", email);
throw new DatabaseException("User not found in the database.", DatabaseException.Error.USER_NOT_FOUND);
}
return UsersDao.fromJson(mapper, response.item().get("document").s()).withTime(Long.parseLong(response.item().get("creation_time").n()), Long.parseLong(response.item().get("update_time").n()));
}).exceptionally(throwable -> {
throw convertToDatabaseException(throwable.getCause(), email);
});
}
use of com.sanctionco.thunder.models.User in project thunder by RohanNagar.
the class DynamoDbUsersDao method update.
@Override
public CompletableFuture<User> update(@Nullable String existingEmail, User user) {
Objects.requireNonNull(user);
// Different email (primary key) means we need to delete and insert
if (existingEmail != null && !existingEmail.equals(user.getEmail().getAddress())) {
LOG.info("User to update has new email. The user will be deleted and then reinserted.");
return updateEmail(existingEmail, user);
}
long now = Instant.now().toEpochMilli();
// Get the old version
GetItemRequest request = GetItemRequest.builder().tableName(tableName).key(Collections.singletonMap("email", AttributeValue.builder().s(user.getEmail().getAddress()).build())).build();
return dynamoDbClient.getItem(request).thenApply(response -> {
if (response.item().size() <= 0) {
LOG.warn("The email {} was not found in the database.", user.getEmail().getAddress());
throw new DatabaseException("User not found in the database.", DatabaseException.Error.USER_NOT_FOUND);
}
// Compute the new data
String newVersion = UUID.randomUUID().toString();
String document = UsersDao.toJson(mapper, user);
// Build the new item
Map<String, AttributeValue> newItem = new HashMap<>();
// Fields that don't change
newItem.put("email", response.item().get("email"));
newItem.put("id", response.item().get("id"));
newItem.put("creation_time", response.item().get("creation_time"));
// Fields that do change
newItem.put("version", AttributeValue.builder().s(newVersion).build());
newItem.put("update_time", AttributeValue.builder().n(String.valueOf(now)).build());
newItem.put("document", AttributeValue.builder().s(document).build());
return PutItemRequest.builder().tableName(tableName).item(newItem).expected(Collections.singletonMap("version", ExpectedAttributeValue.builder().comparisonOperator(ComparisonOperator.EQ).value(response.item().get("version")).build())).returnValues(ReturnValue.ALL_OLD).build();
}).thenCompose(dynamoDbClient::putItem).thenApply(response -> user.withTime(Long.parseLong(response.attributes().get("creation_time").n()), now)).exceptionally(throwable -> {
throw convertToDatabaseException(throwable.getCause(), user.getEmail().getAddress());
});
}
use of com.sanctionco.thunder.models.User in project thunder by RohanNagar.
the class DynamoDbUsersDao method delete.
@Override
public CompletableFuture<User> delete(String email) {
Objects.requireNonNull(email);
DeleteItemRequest deleteItemRequest = DeleteItemRequest.builder().tableName(tableName).key(Collections.singletonMap("email", AttributeValue.builder().s(email).build())).expected(Collections.singletonMap("email", ExpectedAttributeValue.builder().value(AttributeValue.builder().s(email).build()).exists(true).build())).returnValues(ReturnValue.ALL_OLD).build();
return dynamoDbClient.deleteItem(deleteItemRequest).thenApply(response -> UsersDao.fromJson(mapper, response.attributes().get("document").s()).withTime(Long.parseLong(response.attributes().get("creation_time").n()), Long.parseLong(response.attributes().get("update_time").n()))).exceptionally(throwable -> {
// result than convertToDatabaseException() supplies
if (throwable.getCause() instanceof ConditionalCheckFailedException) {
LOG.warn("The email {} was not found in the database.", email, throwable);
throw new DatabaseException("User not found in the database.", DatabaseException.Error.USER_NOT_FOUND);
}
throw convertToDatabaseException(throwable.getCause(), email);
});
}
use of com.sanctionco.thunder.models.User in project thunder by RohanNagar.
the class UserResource method updateUser.
/**
* Updates the user in the database.
*
* @param response the async response object used to notify that the operation has completed
* @param auth the auth principal required to access the resource
* @param password the user's password. This should be the existing password prior to any updates.
* @param existingEmail the user's existing email. This can be {@code null} if the user's email
* will stay the same. It must be present if the email is to be changed.
* @param user the user with updated properties
*/
@PUT
@Metered(name = "update-requests")
@SwaggerAnnotations.Methods.Update
public void updateUser(@Suspended AsyncResponse response, @Parameter(hidden = true) @Auth Principal auth, @Parameter(hidden = true) @HeaderParam("password") String password, @Parameter(hidden = true) @QueryParam("email") String existingEmail, User user) {
requestOptions.setTimeout(response, updateTimeoutCounter);
try {
requestValidator.validate(password, existingEmail, user);
} catch (RequestValidationException e) {
response.resume(e.response(Optional.ofNullable(existingEmail).orElseGet(() -> Optional.ofNullable(user).map(User::getEmail).map(Email::getAddress).orElse("null"))));
return;
}
// Get the current email address for the user
String email = Optional.ofNullable(existingEmail).orElse(user.getEmail().getAddress());
LOG.info("Attempting to update user with existing email address {}.", email);
usersDao.findByEmail(email).thenApply(foundUser -> {
// Check that the password is correct for the user to update
requestValidator.verifyPasswordHeader(password, foundUser.getPassword());
// Determine what verification information to use for the updated user object.
// If it's a new email address, reset verification status.
// If it's the same, keep the existing verification status.
boolean verified = email.equals(user.getEmail().getAddress()) && foundUser.getEmail().isVerified();
String verificationToken = email.equals(user.getEmail().getAddress()) ? foundUser.getEmail().getVerificationToken() : null;
// Hash the password if it is a new password
String finalPassword = foundUser.getPassword();
if (!hashService.isMatch(user.getPassword(), foundUser.getPassword())) {
finalPassword = hashService.hash(user.getPassword());
}
LOG.info("Using verified status: {} and token: {} for the updated user.", verified, verificationToken);
return new User(new Email(user.getEmail().getAddress(), verified, verificationToken), finalPassword, user.getProperties());
}).thenCompose(updatedUser -> usersDao.update(existingEmail, updatedUser)).whenComplete((result, throwable) -> {
if (Objects.isNull(throwable)) {
LOG.info("Successfully updated user {}.", email);
response.resume(Response.ok(result).build());
} else {
LOG.error("Error updating user {}. Caused by: {}", email, throwable.getMessage());
response.resume(ThunderException.responseFromThrowable(throwable, email));
}
});
}
use of com.sanctionco.thunder.models.User in project thunder by RohanNagar.
the class UserResource method postUser.
/**
* Creates a new user in the database.
*
* @param response the async response object used to notify that the operation has completed
* @param auth the auth principal required to access the resource
* @param user the user to create in the database
*/
@POST
@Metered(name = "post-requests")
@SwaggerAnnotations.Methods.Create
public void postUser(@Suspended AsyncResponse response, @Parameter(hidden = true) @Auth Principal auth, User user) {
requestOptions.setTimeout(response, createTimeoutCounter);
try {
requestValidator.validate(user);
} catch (RequestValidationException exception) {
response.resume(exception.response(Optional.ofNullable(user).map(User::getEmail).map(Email::getAddress).orElse("null")));
return;
}
String email = user.getEmail().getAddress();
LOG.info("Attempting to create new user {}.", email);
// Hash the user's password
String finalPassword = hashService.hash(user.getPassword());
// Make sure the user is not verified, as this is a new user
User userToInsert = new User(Email.unverified(email), finalPassword, user.getProperties());
usersDao.insert(userToInsert).whenComplete((result, throwable) -> {
if (Objects.isNull(throwable)) {
LOG.info("Successfully created new user {}.", result.getEmail().getAddress());
response.resume(Response.status(Response.Status.CREATED).entity(result).build());
} else {
LOG.error("Error creating new user {}. Caused by {}", email, throwable.getMessage());
response.resume(ThunderException.responseFromThrowable(throwable, email));
}
});
}
Aggregations