that's all, folks?
This commit is contained in:
parent
263182db1d
commit
71dd9b4fde
@ -1,11 +1,19 @@
|
|||||||
package com.webproglabs.lab1.mvc;
|
package com.webproglabs.lab1.mvc;
|
||||||
|
|
||||||
import com.webproglabs.lab1.dto.UserDto;
|
import com.webproglabs.lab1.dto.UserDto;
|
||||||
|
import com.webproglabs.lab1.dto.UserSignupDto;
|
||||||
|
import com.webproglabs.lab1.models.User;
|
||||||
|
import com.webproglabs.lab1.models.UserRole;
|
||||||
import com.webproglabs.lab1.services.UserService;
|
import com.webproglabs.lab1.services.UserService;
|
||||||
|
import org.springframework.security.access.annotation.Secured;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.validation.BindingResult;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@RequestMapping("/users")
|
@RequestMapping("/users")
|
||||||
@ -17,8 +25,55 @@ public class UserMvcController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
|
@Secured({UserRole.AsString.ADMIN})
|
||||||
public String getUsersPage(Model model){
|
public String getUsersPage(Model model){
|
||||||
model.addAttribute("users", userService.findAllUsers().stream().map(UserDto::new).toList());
|
model.addAttribute("profiles", userService.findAllUsers().stream().map(UserDto::new).toList());
|
||||||
return "users";
|
return "users";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = {"/{id}"})
|
||||||
|
@Secured({UserRole.AsString.ADMIN})
|
||||||
|
public String deleteUser(@PathVariable Long id) {
|
||||||
|
userService.deleteUser(id);
|
||||||
|
return "redirect:/users";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(value = {"/{login}"})
|
||||||
|
public String getUserPage(@PathVariable String login, Model model) {
|
||||||
|
model.addAttribute("user", new UserDto(userService.findUserByLogin(login)));
|
||||||
|
return "userPage";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(value = {"/settings"})
|
||||||
|
public String getUserEditPage(Model model) {
|
||||||
|
UserDetails principal = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
var currentUser = userService.findUserByLogin(principal.getUsername());
|
||||||
|
model.addAttribute("user", new UserDto(userService.findUserById(currentUser.getId())));
|
||||||
|
model.addAttribute("userDto", new UserSignupDto());
|
||||||
|
|
||||||
|
return "userEditPage";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = {"/edit/{id}"})
|
||||||
|
public String editUserData(@PathVariable Long id, @ModelAttribute("userDto") @Valid UserSignupDto userSignupDto,
|
||||||
|
BindingResult bindingResult,
|
||||||
|
Model model) {
|
||||||
|
UserDetails principal = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
var currentUser = userService.findUserByLogin(principal.getUsername());
|
||||||
|
model.addAttribute("user", new UserDto(userService.findUserById(currentUser.getId())));
|
||||||
|
model.addAttribute("userDto", new UserSignupDto());
|
||||||
|
|
||||||
|
if (bindingResult.hasErrors()) {
|
||||||
|
model.addAttribute("errors", bindingResult.getAllErrors());
|
||||||
|
return "userEditPage";
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final User user = userService.updateUser(id, userSignupDto.getLogin(), userSignupDto.getPassword(), userSignupDto.getPasswordConfirm());
|
||||||
|
model.addAttribute("success", "Данные успешно изменены");
|
||||||
|
return "userEditPage";
|
||||||
|
} catch (Exception e) {
|
||||||
|
model.addAttribute("errors", e.getMessage());
|
||||||
|
return "userEditPage";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,13 +62,23 @@ public class UserService implements UserDetailsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public User updateUser(Long id, String login, String password) {
|
public User updateUser(Long id, String login, String password, String passwordConfirm) {
|
||||||
if (!StringUtils.hasText(login) || !StringUtils.hasText(password)) {
|
if (!StringUtils.hasText(login) || !StringUtils.hasText(password)) {
|
||||||
throw new IllegalArgumentException("User data is null or empty");
|
throw new IllegalArgumentException("User data is null or empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
final User currentUser = findUserById(id);
|
final User currentUser = findUserById(id);
|
||||||
|
|
||||||
|
if (Objects.equals(password, currentUser.getPassword())) {
|
||||||
|
throw new IllegalArgumentException("New password is the same as old");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Objects.equals(password, passwordConfirm)) {
|
||||||
|
throw new IllegalArgumentException("Password mismatch");
|
||||||
|
}
|
||||||
|
|
||||||
currentUser.setLogin(login);
|
currentUser.setLogin(login);
|
||||||
currentUser.setPassword(password);
|
currentUser.setPassword(passwordEncoder.encode(password));
|
||||||
return userRepository.save(currentUser);
|
return userRepository.save(currentUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,13 +20,14 @@
|
|||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p class='text-center m-3 h3'> СоцСеточка</p>
|
<p class='text-center mt-3 h3'> СоцСеточка</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class='h4 text-center'>
|
<p class='h4 text-center'>
|
||||||
<a sec:authorize="hasRole('ROLE_ADMIN')" href="/topic" class="text-decoration-none m-3 text-secondary">Топики</a>
|
<a sec:authorize="hasRole('ROLE_ADMIN')" href="/topic" class="text-decoration-none m-3 text-secondary">Топики</a>
|
||||||
<a sec:authorize="hasRole('ROLE_ADMIN')" href="/users" class="text-decoration-none m-3 text-secondary">Пользователи</a>
|
<a sec:authorize="hasRole('ROLE_ADMIN')" href="/users" class="text-decoration-none m-3 text-secondary">Пользователи</a>
|
||||||
<a sec:authorize="isAuthenticated()" href="/feed" class="text-decoration-none m-3 text-secondary">Лента</a>
|
<a sec:authorize="isAuthenticated()" href="/feed" class="text-decoration-none m-3 text-secondary">Лента</a>
|
||||||
|
<a sec:authorize="isAuthenticated()" href="/users/settings" class="text-decoration-none m-3 text-secondary">Настройки</a>
|
||||||
<a sec:authorize="isAuthenticated()" href="/logout" class="text-decoration-none m-3 text-secondary">
|
<a sec:authorize="isAuthenticated()" href="/logout" class="text-decoration-none m-3 text-secondary">
|
||||||
Выход
|
Выход
|
||||||
</a>
|
</a>
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<div class="dropdown text-center mx-auto w-75">
|
<div class="dropdown text-center mx-auto w-75">
|
||||||
<div class="text-center mt-3">
|
<div class="text-center mt-3">
|
||||||
<button class="btn btn-secondary dropdown-toggle ms-3 mb-3 w-50" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
<button class="btn btn-secondary dropdown-toggle ms-3 mb-3 w-50" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
Выбор топика
|
Выбор темы
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu w-50" >
|
<ul class="dropdown-menu w-50" >
|
||||||
<li th:each="topic: ${topics}">
|
<li th:each="topic: ${topics}">
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
<div class="d-flex justify-content-between fst-italic">
|
<div class="d-flex justify-content-between fst-italic">
|
||||||
<div>
|
<div>
|
||||||
Автор:
|
Автор:
|
||||||
<a th:text="${post.getAuthor()}" class="text-start fst-italic" th:href="@{/profile/{login}(login=${post.getAuthor()})}"></a>
|
<a th:text="${post.getAuthor()}" class="text-start fst-italic" th:href="@{/users/{login}(login=${post.getAuthor()})}"></a>
|
||||||
</div>
|
</div>
|
||||||
<div th:if="${selectedProfile.getLogin() == post.getAuthor()}" class="d-flex justify-content-between fst-italic">
|
<div th:if="${selectedProfile.getLogin() == post.getAuthor()}" class="d-flex justify-content-between fst-italic">
|
||||||
<form th:action="@{/feed/deletePost/{id}/{topicId} (id=${post.id}, topicId=${selectedTopic.id})}" method="post" >
|
<form th:action="@{/feed/deletePost/{id}/{topicId} (id=${post.id}, topicId=${selectedTopic.id})}" method="post" >
|
||||||
|
31
src/main/resources/templates/userEditPage.html
Normal file
31
src/main/resources/templates/userEditPage.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en"
|
||||||
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
|
layout:decorate="~{default}">
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div layout:fragment="content">
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
<div th:if="${errors}" th:text="${errors}" class="margin-bottom alert alert-danger"></div>
|
||||||
|
<div th:if="${success}" th:text="${success}" class="margin-bottom text-success"></div>
|
||||||
|
<div class="text-start mx-auto w-50 border p-5">
|
||||||
|
<p class='h5'>Изменение данных пользователя</p>
|
||||||
|
<p th:text="${'Логин: ' + user.login}"></p>
|
||||||
|
|
||||||
|
<form action="#" th:action="@{/users/edit/{id} (id=${user.id})}" th:object="${userDto}" method="post">
|
||||||
|
<p>Новый логин:</p>
|
||||||
|
<input th:field="${userDto.login}" type="text" class="mb-2 form-control" required="true" autofocus="true" maxlength="64"/>
|
||||||
|
<p>Новый пароль:</p>
|
||||||
|
<input th:field="${userDto.password}" type="password" class="mb-2 form-control" required="true" minlength="4" maxlength="64"/>
|
||||||
|
<p>Повторите пароль:</p>
|
||||||
|
<input th:field="${userDto.passwordConfirm}" type="password" class="mb-2 form-control" required="true" minlength="4" maxlength="64"/>
|
||||||
|
<button type="submit" class="btn btn-success" >Сохранить изменения</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
29
src/main/resources/templates/userPage.html
Normal file
29
src/main/resources/templates/userPage.html
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en"
|
||||||
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
|
layout:decorate="~{default}">
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div layout:fragment="content">
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="text-start mx-auto w-50 border p-5">
|
||||||
|
<p class='h5'>Профиль</p>
|
||||||
|
<p th:text="${'Логин: ' + user.login}"></p>
|
||||||
|
<p class='h6 '>Список постов пользователя: </p>
|
||||||
|
|
||||||
|
<div th:if="${user.posts.size()>0}">
|
||||||
|
<div th:each="post: ${user.posts}">
|
||||||
|
<p th:text="${post.text}" class="mb-3 ms-2 border p-2"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p th:unless="${user.posts.size()>0}">
|
||||||
|
Нет постов
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
36
src/main/resources/templates/users.html
Normal file
36
src/main/resources/templates/users.html
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en"
|
||||||
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
|
layout:decorate="~{default}" xmlns:th="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div layout:fragment="content" class="text-center">
|
||||||
|
|
||||||
|
<div th:each="profile: ${profiles}" class="mb-2">
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="text-start mx-auto w-50 border shadow p-3">
|
||||||
|
<p class='h5'>Профиль</p>
|
||||||
|
<p th:text="${'Логин: ' + profile.login}"></p>
|
||||||
|
<p class='h6 '>Список постов пользователя: </p>
|
||||||
|
|
||||||
|
<div th:if="${profile.posts.size()>0}">
|
||||||
|
<div th:each="post: ${profile.posts}">
|
||||||
|
<p th:text="${post.text}" class="mb-3 ms-2 border p-2"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p th:unless="${profile.posts.size()>0}">
|
||||||
|
Нет постов
|
||||||
|
</p>
|
||||||
|
<div class="text-end" th:if="${profile.login!='admin'}">
|
||||||
|
<form action="#" th:action="@{/users/{id} (id=${profile.id})}" method="post" >
|
||||||
|
<button type="submit" class="btn btn-danger">Удалить</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user