Use form for editing customer profile

This commit is contained in:
Denis Natusch 2024-01-06 20:34:15 +01:00
parent 6297f3c073
commit 13641bc6a2
No known key found for this signature in database
GPG key ID: 5E57BD8EDACFA985
4 changed files with 106 additions and 69 deletions

View file

@ -7,6 +7,8 @@ import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import catering.users.UserForm.UserFormWithPassword;
@Component
public class FormValidator<F extends UserForm> implements Validator {
@ -22,6 +24,8 @@ public class FormValidator<F extends UserForm> implements Validator {
ValidationUtils.rejectIfEmptyOrWhitespace(e, "username", "username must not be empty");
ValidationUtils.rejectIfEmptyOrWhitespace(e, "address", "address must not be empty");
ValidationUtils.rejectIfEmptyOrWhitespace(e, "fullName", "fullName must not be empty");
form.validatePassword(e);
if (form instanceof UserFormWithPassword formWithPassword){
formWithPassword.validatePassword(e);
}
}
}

View file

@ -2,8 +2,9 @@
// SPDX-FileCopyrightText: 2023 swt23w23
package catering.users;
import static catering.users.UserForm.RegistrationForm;
import static catering.users.UserForm.ProfileForm;
import static catering.users.UserForm.UserFormWithPassword.RegistrationForm;
import static catering.users.UserForm.UserFormWithPassword.ProfileForm;
import static catering.users.UserForm.AdminForm;
import org.springframework.ui.Model;
import org.salespointframework.useraccount.Role;
import org.salespointframework.useraccount.UserAccount;
@ -41,6 +42,11 @@ public class UserController {
binder.setValidator(new FormValidator<RegistrationForm>());
}
@InitBinder("adminForm")
private void initAdminBinder(WebDataBinder binder) {
binder.setValidator(new FormValidator<AdminForm>());
}
@GetMapping("/unauthorized")
String unauthorized(){
return "unauthorized";
@ -124,16 +130,20 @@ public class UserController {
@GetMapping("/customers/edit/{id}")
@PreAuthorize("hasRole('ADMIN')")
public String editCustomer(@PathVariable("id") User user, Model model) {
model.addAttribute("customer", user);
model.addAttribute("id", user.getId());
model.addAttribute("adminForm", new AdminForm(user.getUsername(), user.getAddress(), user.getFullName()));
return "edit-customer";
}
@PostMapping("/customers/edit/{id}")
@PreAuthorize("hasRole('ADMIN')")
public String updateCustomer(@PathVariable("id") User user, @RequestParam String fullName, @RequestParam String username, @RequestParam String address) {
user.setUsername(username);
user.setAddress(address);
user.setFullName(fullName);
public String updateCustomer(@PathVariable("id") User user, @Valid AdminForm form, Errors result) {
if (result.hasErrors()){
return "edit-customer";
}
user.setUsername(form.getUsername());
user.setAddress(form.getAddress());
user.setFullName(form.getFullName());
userManagement.save(user);
return "redirect:/customers";
}

View file

@ -15,13 +15,12 @@ import org.springframework.validation.Errors;
*/
public abstract class UserForm {
private final String username, address, fullName, password;
private final String username, address, fullName;
public UserForm(String username, String address, String fullName, String password) {
public UserForm(String username, String address, String fullName) {
this.username = username;
this.address = address;
this.fullName = fullName;
this.password = password;
}
public String getUsername() {
@ -36,64 +35,85 @@ public abstract class UserForm {
return fullName;
}
public String getPassword() {
return password;
}
/**
* Template Method for validating the password.
*
* @param e {@link Errors} from {@link FormValidator}
* An extension of {@link UserForm} with a password attribute.
*/
public void validatePassword(Errors e) {
validatePasswordGeneric(e);
Optional.ofNullable(e.getFieldValue("password")).map(s -> (String) s).ifPresent(s -> {
if (s.chars().anyMatch(Character::isISOControl)) {
e.rejectValue("password", "password must only contain printable characters");
public abstract static class UserFormWithPassword extends UserForm {
private final String password;
public UserFormWithPassword(String username, String address, String fullName, String password) {
super(username, address, fullName);
this.password = password;
}
public String getPassword() {
return password;
}
/**
* Template Method for validating the password.
*
* @param e {@link Errors} from {@link FormValidator}
*/
public void validatePassword(Errors e) {
validatePasswordGeneric(e);
Optional.ofNullable(e.getFieldValue("password")).map(s -> (String) s).ifPresent(s -> {
if (s.chars().anyMatch(Character::isISOControl)) {
e.rejectValue("password", "password must only contain printable characters");
}
});
}
/**
* Primitive Operation for validating the password depending on the subclass.
*
* @param e {@link Errors} from {@link FormValidator}
*/
public abstract void validatePasswordGeneric(Errors e);
/**
* An extension of {@link UserFormWithPassword} to validate input during registration.
*
* It requires the password to be not empty.
*/
public static class RegistrationForm extends UserFormWithPassword {
RegistrationForm(String username, String address, String fullName, String password) {
super(username, address, fullName, password);
}
});
}
/**
* Primitive Operation for validating the password depending on the subclass.
*
* @param e {@link Errors} from {@link FormValidator}
*/
public abstract void validatePasswordGeneric(Errors e);
/**
* An extension of {@link UserForm} to validate input during registration.
*
* It requires the password to be not empty.
*/
public static class RegistrationForm extends UserForm {
RegistrationForm(String username, String address, String fullName, String password) {
super(username, address, fullName, password);
}
public static RegistrationForm empty() {
return new UserForm.RegistrationForm("", "", "", "");
}
public void validatePasswordGeneric(Errors e) {
ValidationUtils.rejectIfEmptyOrWhitespace(e, "password", "password must not be empty");
}
}
/**
* An extension of {@link UserForm} to validate input during profile editing.
*
* The password can be empty.
*/
public static class ProfileForm extends UserForm {
ProfileForm(String username, String address, String fullName, String password) {
super(username, address, fullName, password);
}
public void validatePasswordGeneric(Errors e) {
if (e.getFieldValue("password") == null) {
e.rejectValue("password", "password must not be null");
public static RegistrationForm empty() {
return new UserFormWithPassword.RegistrationForm("", "", "", "");
}
public void validatePasswordGeneric(Errors e) {
ValidationUtils.rejectIfEmptyOrWhitespace(e, "password", "password must not be empty");
}
}
/**
* An extension of {@link UserFormWithPassword} to validate input during profile editing.
*
* The password can be empty.
*/
public static class ProfileForm extends UserFormWithPassword {
ProfileForm(String username, String address, String fullName, String password) {
super(username, address, fullName, password);
}
public void validatePasswordGeneric(Errors e) {
if (e.getFieldValue("password") == null) {
e.rejectValue("password", "password must not be null");
}
}
}
}
/**
* An extension of {@link UserForm} to validate input during customer profile editing.
*/
public static class AdminForm extends UserForm {
AdminForm(String username, String address, String fullName) {
super(username, address, fullName);
}
}
}

View file

@ -11,20 +11,23 @@ SPDX-FileCopyrightText: 2023 swt23w23
</head>
<body>
<div layout:fragment="content">
<form method="post">
<form th:object="${adminForm}" th:action="@{/customers/edit/{id}(id=${id})}" method="post">
<div class="mb-3">
<label class="form-label" for="username">Nutzername</label>
<input class="form-control" type="text" name="username" th:value="${customer.username}"/>
<input class="form-control" th:field="*{username}" th:errorclass="is-invalid" type="text" required>
<div th:if="${#fields.hasErrors('username')}" class="invalid-feedback">Ungültiger Nutzername</div>
</div>
<div class="mb-3">
<label class="form-label" for="fullName">Name</label>
<input class="form-control" type="fullName" name="fullName" th:value="${customer.fullName}"/>
<input class="form-control" th:field="*{fullName}" th:errorclass="is-invalid" type="text" required>
<div th:if="${#fields.hasErrors('fullName')}" class="invalid-feedback">Ungültiger Name</div>
</div>
<div class="mb-3">
<label class="form-label" for="address">Adresse</label>
<textarea class="form-control" name="address" th:text="${customer.address}" rows="3" required></textarea>
<textarea class="form-control" th:field="*{address}" th:errorclass="is-invalid" th:placeholder="*{address}" rows="3" required></textarea>
<div th:if="${#fields.hasErrors('address')}" class="invalid-feedback">Ungültige Addresse</div>
</div>
<button class="btn btn-primary" type="submit">Speichern</button>
<button class="btn btn-primary" type="submit">Bearbeiten</button>
</form>
</div>
</body>