Add form for creating users to ManageUsers page. Fix delete users bug, add login-in-use validations

master
Dmitry Isaenko 2023-12-30 22:27:48 +03:00
parent 38ebab2ff0
commit aec02f027a
6 changed files with 112 additions and 18 deletions

View File

@ -0,0 +1,35 @@
package ru.redrise.marinesco;
import org.springframework.security.crypto.password.PasswordEncoder;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import ru.redrise.marinesco.data.RolesRepository;
import ru.redrise.marinesco.security.UserRole;
//TODO: refactor along with RegistrationForm.java
@Data
public class AdministatorAddUserForm {
@NotNull
@Size(min=3, max=32, message="Username must be at least 3 characters long. Should not exceed 32 characters.")
private String username;
@NotNull
@Size(min=8, max = 32, message="Password must be at least 8 characters long. Should not exceed 32 characters.")
private String password;
@NotNull
@NotEmpty(message = "Display name could not be blank")
private String displayname;
public User toUser(PasswordEncoder passwordEncoder, RolesRepository rolesRepo){
return new User(
username,
passwordEncoder.encode(password),
displayname,
rolesRepo.findByType(UserRole.Type.USER));
}
}

View File

@ -2,21 +2,19 @@ package ru.redrise.marinesco;
import java.util.List;
import org.hibernate.annotations.ManyToAny;
import org.springframework.security.core.userdetails.UserDetails;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.Table;
import lombok.AccessLevel;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.val;
import ru.redrise.marinesco.security.UserRole;
@Data
@ -37,7 +35,7 @@ public class User implements UserDetails{
private String password;
private String displayname;
@ManyToMany(cascade = CascadeType.REMOVE, fetch = FetchType.EAGER)
@ManyToAny(fetch = FetchType.EAGER)
private final List<UserRole> authorities;
public User(String username, String password, String displayname, List<UserRole> authorities){

View File

@ -4,19 +4,23 @@ import java.util.ArrayList;
import java.util.List;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import ru.redrise.marinesco.AdministatorAddUserForm;
import ru.redrise.marinesco.User;
import ru.redrise.marinesco.UserGenerified;
import ru.redrise.marinesco.data.RolesRepository;
import ru.redrise.marinesco.data.UserRepository;
//TODO
@Slf4j
@Controller
@ -24,10 +28,16 @@ import ru.redrise.marinesco.data.UserRepository;
@PreAuthorize("hasRole('ADMIN')")
public class ManageUsersController {
private UserRepository userRepository;
private final UserRepository userRepository;
private final RolesRepository rolesRepository;
private final PasswordEncoder passwordEncoder;
public ManageUsersController(UserRepository userRepository){
public ManageUsersController(UserRepository userRepository,
RolesRepository rolesRepository,
PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.rolesRepository = rolesRepository;
this.passwordEncoder = passwordEncoder;
}
@ModelAttribute(name = "userGenerified")
@ -36,18 +46,19 @@ public class ManageUsersController {
}
@ModelAttribute
public void addTitle(Model model){
public void addTitle(Model model) {
model.addAttribute("header_text", "Manage users");
model.addAttribute("administatorAddUserForm", new AdministatorAddUserForm());
}
@ModelAttribute
public void addUsers(Model model){
public void addUsers(Model model) {
Iterable<User> users = userRepository.findAll();
List<UserGenerified> usersGen = new ArrayList<>();
for (User user : users){
usersGen.add(new UserGenerified(user)); // TODO: ADD ARRAY INSTEAD OF ONE!
for (User user : users) {
usersGen.add(new UserGenerified(user));
}
model.addAttribute("USR", usersGen); // TODO: ADD ARRAY INSTEAD OF ONE!
model.addAttribute("USR", usersGen);
}
@GetMapping
@ -56,11 +67,28 @@ public class ManageUsersController {
}
@PostMapping("/delete")
public String processDelete(UserGenerified userGenerified){
public String processDelete(UserGenerified userGenerified) {
log.info(userGenerified.toString());
userRepository.deleteById(userGenerified.getId());
return "redirect:/manage_users";
}
@PostMapping
public String processNewUser(@Valid AdministatorAddUserForm form, Errors errors, Model model) {
if (userRepository.findByUsername(form.getUsername()) != null) {
model.addAttribute("loginOccupied", "Login already in use. Please choose another one");
return "manage_users";
}
if (errors.hasErrors()) {
log.info(errors.getAllErrors().toString());
return "manage_users";
}
User user = userRepository.save(form.toUser(passwordEncoder, rolesRepository));
log.info("Added user {} {} {}", user.getId(), user.getUsername(), user.getDisplayname());
// Reloads page therefore new records appears
return "redirect:/manage_users";
}
}

View File

@ -46,19 +46,23 @@ public class RegistrationController {
}
@PostMapping
public String postMethodName(@Valid RegistrationForm registerForm, Errors errors, Model model) {
if (registerForm.isPasswordsNotEqual()) {
public String postMethodName(@Valid RegistrationForm form, Errors errors, Model model) {
if (form.isPasswordsNotEqual()) {
model.addAttribute("passwordsMismatch", "Passwords must be the same.");
return "registration";
}
if (userRepo.findByUsername(form.getUsername()) != null){
model.addAttribute("loginOccupied", "Login already in use. Please choose another one");
return "registration";
}
if (errors.hasErrors()) {
return "registration";
}
User user = userRepo.save(registerForm.toUser(passwordEncoder, rolesRepo));
User user = userRepo.save(form.toUser(passwordEncoder, rolesRepo));
log.info("Added user {} {} {}", user.getId(), user.getUsername(), user.getDisplayname());
if (registerForm.auth(request))
if (form.auth(request))
return "redirect:/";
return "redirect:/login";
}

View File

@ -26,10 +26,37 @@
<input type="hidden" th:value="${role.id}" th:attr="name='role'" />
</span>
<button>DELETE</button>
<button>Delete</button>
</form>
<br />
</div>
<hr>
<b>Add user</b>
<form method="POST" th:action="@{/manage_users}" th:object="${administatorAddUserForm}">
<span class="validationError" th:if="${loginOccupied} != null" th:text="${loginOccupied}">pew</span>
<span class="validationError" th:if="${#fields.hasErrors('username')}"
th:errors="*{username}">Error</span>
<br />
<label for="username">Username: </label>
<input type="text" name="username" id="username" size="50%" /><br />
<span class="validationError" th:if="${#fields.hasErrors('password')}"
th:errors="*{password}">Error</span>
<br />
<label for="password">Password: </label>
<input type="password" name="password" id="password" size="50%" /><br />
<span class="validationError" th:if="${#fields.hasErrors('displayname')}"
th:errors="*{displayname}">Error</span>
<br />
<label for="displayname">Displayed name: </label>
<input type="text" name="displayname" id="displayname" size="50%" /><br />
<p>
<button class="sign" type="submit">Add user</button>
</p>
</form>
</div>
</div>
<div th:replace="~{fragments/footer :: 'footer'}"></div>

View File

@ -14,6 +14,8 @@
<div class="container base">
<h1>Register</h1>
<form class="regForm" method="POST" th:action="@{/register}" th:object="${registrationForm}">
<span class="validationError" th:if="${loginOccupied} != null"
th:text="${loginOccupied}">pew</span>
<span class="validationError" th:if="${#fields.hasErrors('username')}"
th:errors="*{username}">Error</span>