From c30e8182f9ce265e439eaa405d8268209f4b116a Mon Sep 17 00:00:00 2001 From: Pavel_Sorokin Date: Fri, 5 May 2023 16:43:38 +0400 Subject: [PATCH] =?UTF-8?q?=D0=92=D1=80=D0=BE=D0=B4=D0=B5=20MVC=20=D0=B3?= =?UTF-8?q?=D0=BE=D1=82=D0=BE=D0=B2=20(=D0=B5=D0=B4=D0=B8=D0=BD=D1=81?= =?UTF-8?q?=D1=82=D0=B2=D0=B5=D0=BD=D0=BD=D0=BE=D0=B5=20=D0=BF=D0=BE=D1=81?= =?UTF-8?q?=D0=BB=D0=B5=20=D0=B2=D1=85=D0=BE=D0=B4=D0=B0=20=D0=B2=20=D0=B0?= =?UTF-8?q?=D0=BA=D0=BA=D0=B0=D1=83=D0=BD=D1=82=20=D0=BF=D0=BD=D0=B3=20?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=B2=D1=81=D1=8E=20=D1=81=D1=82=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D1=86=D1=83=20=D0=BE=D1=82=D0=BE=D0=B1=D1=80=D0=B0?= =?UTF-8?q?=D0=B6=D0=B0=D0=B5=D1=82=20=D0=BF=D0=BE=D1=87=D0=B5=D0=BC=D1=83?= =?UTF-8?q?=20=D1=82=D0=BE=20(=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=BD=D0=BE?= =?UTF-8?q?=20:)=20))?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../is/sbapp/Comment/model/CommentDto.java | 2 +- .../PasswordEncoderConfiguration.java | 14 ++ .../Configuration/SecurityConfiguration.java | 76 ++++++++++ .../{ => Configuration}/WebConfiguration.java | 3 +- .../sbapp/Post/controller/PostController.java | 2 +- .../Post/controller/PostMvcController.java | 119 +++++++-------- .../sbapp/User/controller/UserController.java | 7 +- .../User/controller/UserMvcController.java | 111 ++++++++++---- .../controller/UserSignupMvcController.java | 51 +++++++ .../ru/ulstu/is/sbapp/User/model/User.java | 53 ++++--- .../ru/ulstu/is/sbapp/User/model/UserDto.java | 22 +-- .../is/sbapp/User/model/UserSignupDto.java | 40 ++++++ .../sbapp/User/repository/UserRepository.java | 2 + .../is/sbapp/User/service/UserService.java | 79 ++++++++-- src/main/resources/public/{ => css}/style.css | 0 .../resources/templates/comment-create.html | 12 +- .../resources/templates/comment-edit.html | 2 +- src/main/resources/templates/default.html | 17 ++- src/main/resources/templates/error.html | 2 +- .../templates/{post.html => index.html} | 28 +--- src/main/resources/templates/login.html | 41 ++++++ src/main/resources/templates/post-create.html | 10 +- src/main/resources/templates/post-edit.html | 2 +- src/main/resources/templates/post-page.html | 6 +- src/main/resources/templates/signup.html | 43 ++++++ src/main/resources/templates/user-edit.html | 39 ----- src/main/resources/templates/user.html | 135 ++++++++++++------ src/main/resources/templates/users.html | 54 +++++++ 28 files changed, 692 insertions(+), 280 deletions(-) create mode 100644 src/main/java/ru/ulstu/is/sbapp/Configuration/PasswordEncoderConfiguration.java create mode 100644 src/main/java/ru/ulstu/is/sbapp/Configuration/SecurityConfiguration.java rename src/main/java/ru/ulstu/is/sbapp/{ => Configuration}/WebConfiguration.java (89%) create mode 100644 src/main/java/ru/ulstu/is/sbapp/User/controller/UserSignupMvcController.java create mode 100644 src/main/java/ru/ulstu/is/sbapp/User/model/UserSignupDto.java rename src/main/resources/public/{ => css}/style.css (100%) rename src/main/resources/templates/{post.html => index.html} (66%) create mode 100644 src/main/resources/templates/login.html create mode 100644 src/main/resources/templates/signup.html delete mode 100644 src/main/resources/templates/user-edit.html create mode 100644 src/main/resources/templates/users.html diff --git a/src/main/java/ru/ulstu/is/sbapp/Comment/model/CommentDto.java b/src/main/java/ru/ulstu/is/sbapp/Comment/model/CommentDto.java index fae2f11..fe916fa 100644 --- a/src/main/java/ru/ulstu/is/sbapp/Comment/model/CommentDto.java +++ b/src/main/java/ru/ulstu/is/sbapp/Comment/model/CommentDto.java @@ -12,7 +12,7 @@ public class CommentDto { { this.id= comment.getId(); this.Text=comment.getText(); - this.userName=comment.getUser().getFirstName() + " " + comment.getUser().getLastName(); + this.userName=comment.getUser().getLogin(); this.postId=comment.getPost().getId(); } public Long getId() diff --git a/src/main/java/ru/ulstu/is/sbapp/Configuration/PasswordEncoderConfiguration.java b/src/main/java/ru/ulstu/is/sbapp/Configuration/PasswordEncoderConfiguration.java new file mode 100644 index 0000000..0ef5610 --- /dev/null +++ b/src/main/java/ru/ulstu/is/sbapp/Configuration/PasswordEncoderConfiguration.java @@ -0,0 +1,14 @@ +package ru.ulstu.is.sbapp.Configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +public class PasswordEncoderConfiguration { + @Bean + public PasswordEncoder createPasswordEncoder() { + return new BCryptPasswordEncoder(); + } +} diff --git a/src/main/java/ru/ulstu/is/sbapp/Configuration/SecurityConfiguration.java b/src/main/java/ru/ulstu/is/sbapp/Configuration/SecurityConfiguration.java new file mode 100644 index 0000000..bad4e96 --- /dev/null +++ b/src/main/java/ru/ulstu/is/sbapp/Configuration/SecurityConfiguration.java @@ -0,0 +1,76 @@ +package ru.ulstu.is.sbapp.Configuration; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; +import org.springframework.security.web.SecurityFilterChain; +import ru.ulstu.is.sbapp.User.controller.UserSignupMvcController; +import ru.ulstu.is.sbapp.User.model.UserRole; +import ru.ulstu.is.sbapp.User.service.UserService; + +@Configuration +@EnableWebSecurity +@EnableMethodSecurity( + securedEnabled = true +) +public class SecurityConfiguration { + private final Logger log = LoggerFactory.getLogger(SecurityConfiguration.class); + private static final String LOGIN_URL = "/login"; + private final UserService userService; + + public SecurityConfiguration(UserService userService) { + this.userService = userService; + createAdminOnStartup(); + } + + private void createAdminOnStartup() { + final String admin = "admin"; + if (userService.findByLogin(admin) == null) { + log.info("Admin user successfully created"); + userService.addUser(admin, "adminemail@gmail.com", admin, admin, UserRole.ADMIN); + } + } + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http.headers().frameOptions().sameOrigin().and() + .cors().and() + .csrf().disable() + .authorizeHttpRequests() + .requestMatchers(UserSignupMvcController.SIGNUP_URL).permitAll() + .requestMatchers(HttpMethod.GET, LOGIN_URL).permitAll() + .anyRequest().authenticated() + .and() + .formLogin() + .loginPage(LOGIN_URL).permitAll() + .and() + .logout().permitAll(); + return http.build(); + } + + @Bean + public AuthenticationManager authenticationManagerBean(HttpSecurity http) throws Exception { + AuthenticationManagerBuilder authenticationManagerBuilder = http + .getSharedObject(AuthenticationManagerBuilder.class); + authenticationManagerBuilder.userDetailsService(userService); + return authenticationManagerBuilder.build(); + } + + @Bean + public WebSecurityCustomizer webSecurityCustomizer() { + return (web) -> web.ignoring() + .requestMatchers("/css/**") + .requestMatchers("/js/**") + .requestMatchers("/templates/**") + .requestMatchers("/webjars/**"); + } +} diff --git a/src/main/java/ru/ulstu/is/sbapp/WebConfiguration.java b/src/main/java/ru/ulstu/is/sbapp/Configuration/WebConfiguration.java similarity index 89% rename from src/main/java/ru/ulstu/is/sbapp/WebConfiguration.java rename to src/main/java/ru/ulstu/is/sbapp/Configuration/WebConfiguration.java index fa9fd8d..061f014 100644 --- a/src/main/java/ru/ulstu/is/sbapp/WebConfiguration.java +++ b/src/main/java/ru/ulstu/is/sbapp/Configuration/WebConfiguration.java @@ -1,4 +1,4 @@ -package ru.ulstu.is.sbapp; +package ru.ulstu.is.sbapp.Configuration; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; @@ -11,6 +11,7 @@ public class WebConfiguration implements WebMvcConfigurer { @Override public void addViewControllers(ViewControllerRegistry registry) { WebMvcConfigurer.super.addViewControllers(registry); + registry.addViewController("login"); } @Override diff --git a/src/main/java/ru/ulstu/is/sbapp/Post/controller/PostController.java b/src/main/java/ru/ulstu/is/sbapp/Post/controller/PostController.java index 189e3b2..c31f4a2 100644 --- a/src/main/java/ru/ulstu/is/sbapp/Post/controller/PostController.java +++ b/src/main/java/ru/ulstu/is/sbapp/Post/controller/PostController.java @@ -5,7 +5,7 @@ import org.springframework.web.bind.annotation.*; import ru.ulstu.is.sbapp.Comment.model.CommentDto; import ru.ulstu.is.sbapp.Post.model.PostDto; import ru.ulstu.is.sbapp.Post.service.PostService; -import ru.ulstu.is.sbapp.WebConfiguration; +import ru.ulstu.is.sbapp.Configuration.WebConfiguration; import java.util.List; diff --git a/src/main/java/ru/ulstu/is/sbapp/Post/controller/PostMvcController.java b/src/main/java/ru/ulstu/is/sbapp/Post/controller/PostMvcController.java index 6ecf776..abcc514 100644 --- a/src/main/java/ru/ulstu/is/sbapp/Post/controller/PostMvcController.java +++ b/src/main/java/ru/ulstu/is/sbapp/Post/controller/PostMvcController.java @@ -7,6 +7,7 @@ import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; +import ru.ulstu.is.sbapp.Comment.model.Comment; import ru.ulstu.is.sbapp.Comment.model.CommentDto; import ru.ulstu.is.sbapp.Comment.service.CommentService; import ru.ulstu.is.sbapp.Post.model.PostDto; @@ -15,10 +16,11 @@ import ru.ulstu.is.sbapp.User.model.UserDto; import ru.ulstu.is.sbapp.User.service.UserService; import java.io.IOException; +import java.security.Principal; import java.util.Base64; @Controller -@RequestMapping("/post") +@RequestMapping("/index") public class PostMvcController { private final PostService postService; private final UserService userService; @@ -54,7 +56,7 @@ public class PostMvcController { userService.findAllUsers().stream() .map(UserDto::new) .toList()); - return "post"; + return "index"; } @GetMapping("/filter") public String getFileteredPosts(@RequestParam(value = "searchValue") String searchValue,Model model) @@ -67,29 +69,18 @@ public class PostMvcController { userService.findAllUsers().stream() .map(UserDto::new) .toList()); - return "post"; + return "index"; } - @GetMapping(value = {"/edit", "/edit/{id}"}) + @GetMapping(value = {"/edit/{id}"}) public String editPost(@PathVariable(required = false) Long id, Model model) { - if (id == null || id <= 0) { - model.addAttribute("postDto", new PostDto()); - model.addAttribute("users", - userService.findAllUsers().stream() - .map(UserDto::new) - .toList()); - return "post-create"; - } else { model.addAttribute("postId", id); model.addAttribute("postDto", new PostDto(postService.findPost(id))); return "post-edit"; - } - } - @PostMapping(value = {"/user/", "/{id}"}) + @PostMapping(value = {"/{id}"}) public String savePost(@PathVariable(required = false) Long id, - @RequestParam(value = "userId",required = false) Long userId, @RequestParam(value = "multipartFile") MultipartFile multipartFile, @ModelAttribute @Valid PostDto postDto, BindingResult bindingResult, @@ -98,27 +89,28 @@ public class PostMvcController { model.addAttribute("errors", bindingResult.getAllErrors()); return "post-edit"; } - if (id == null || id <= 0 && userId!=null) { - postDto.setImage("data:" + multipartFile.getContentType() + ";base64," + Base64.getEncoder().encodeToString(multipartFile.getBytes())); - userService.addNewPost(userId,postDto); - } else { postDto.setImage("data:" + multipartFile.getContentType() + ";base64," + Base64.getEncoder().encodeToString(multipartFile.getBytes())); postService.updatePost(id, postDto); - } - return "redirect:/post"; + return "redirect:/user"; } @PostMapping("/delete/{postId}") public String deletePost( @PathVariable Long postId) { postService.deletePost(postId); - return "redirect:/post"; + return "redirect:/user"; } @PostMapping("/deleteComment/{postId}/{commentId}") public String deleteComment(@PathVariable Long postId, - @PathVariable Long commentId) { + @PathVariable Long commentId, + Principal principal,Model model) { + Comment comment = commentService.findComment(commentId); + if(!comment.getUser().getLogin().equals(principal.getName())){ + model.addAttribute("error", new Exception("Вы не можете удалить не ваш комментарий")); + return "error"; + } postService.removeCommentFromPost(postId,commentId); - return "redirect:/post/{postId}"; + return "redirect:/index/{postId}"; } @GetMapping("/userPosts") @@ -132,48 +124,61 @@ public class PostMvcController { userService.findAllUsers().stream() .map(UserDto::new) .toList()); - return "post"; + return "index"; } - @GetMapping(value = {"/addComment/{postId}", "/editComment/{id}"}) - public String editComment(@PathVariable(required = false) Long id, - @PathVariable(required = false) Long postId, - Model model) { - if (id == null || id <= 0) { - model.addAttribute("postId", postId); - model.addAttribute("users", - userService.findAllUsers().stream() - .map(UserDto::new) - .toList()); - model.addAttribute("commentDto", new CommentDto()); - return "comment-create.html"; - } else { - model.addAttribute("id", id); - model.addAttribute("commentDto", new CommentDto(commentService.findComment(id))); + @GetMapping("/addComment/{postId}") + public String showCreateCommentInfo(@PathVariable(value = "postId") Long postId, Model model) { + model.addAttribute("postId", postId); + model.addAttribute("commentDto", new CommentDto()); + return "comment-create.html"; + } + @PostMapping("/createComment/{postId}") + public String createPost(@PathVariable(value = "postId") Long postId, + @ModelAttribute @Valid CommentDto commentDto, + BindingResult bindingResult, + Principal principal, + Model model) throws IOException + { + Long userId = userService.findByLogin(principal.getName()).getId(); + if (bindingResult.hasErrors()) { + model.addAttribute("errors", bindingResult.getAllErrors()); + return "post-create"; + } + postService.addCommentToPost(postId,userId,commentDto.getText()); + return "redirect:/index"; + } + + @GetMapping("/editComment/{Id}") + public String showEditCommentInfo(@PathVariable(value = "Id") Long Id, Model model,Principal principal) throws Exception { + model.addAttribute("Id", Id); + CommentDto commentDto = new CommentDto(commentService.findComment(Id)); + model.addAttribute("commentDto",commentDto); + if(!commentDto.getUser().equals(principal.getName())){ + model.addAttribute("error", new Exception("Вы не можете изменить не ваш комментарий")); + return "error"; + } + else + { return "comment-edit"; } } - @PostMapping(value = {"/comment/{postId}/user", "/comment/{id}"}) - public String saveComment(@PathVariable(required = false) Long id, - @RequestParam(value = "userId",required = false) Long userId, - @PathVariable(required = false) Long postId, - @ModelAttribute @Valid CommentDto commentDto, - BindingResult bindingResult, - Model model, - HttpServletRequest request) { + + @PostMapping("/updateComment/{Id}") + public String updateComment(@PathVariable(value = "Id") Long Id, + @ModelAttribute @Valid CommentDto commentDto, + BindingResult bindingResult, + Principal principal, + Model model) throws IOException + { + Long userId = userService.findByLogin(principal.getName()).getId(); if (bindingResult.hasErrors()) { model.addAttribute("errors", bindingResult.getAllErrors()); return "comment-edit"; } - if (id == null || id <= 0 && userId!=null) { - postService.addCommentToPost(postId,userId,commentDto.getText()); - return "redirect:/post/"+ postId; - } else { - commentService.updateComment(id, commentDto.getText()); - return "redirect:/post"; - } - + commentService.updateComment(Id,commentDto.getText()); + return "redirect:/user"; } } diff --git a/src/main/java/ru/ulstu/is/sbapp/User/controller/UserController.java b/src/main/java/ru/ulstu/is/sbapp/User/controller/UserController.java index 1d8ee98..165fd5e 100644 --- a/src/main/java/ru/ulstu/is/sbapp/User/controller/UserController.java +++ b/src/main/java/ru/ulstu/is/sbapp/User/controller/UserController.java @@ -5,7 +5,7 @@ import org.springframework.web.bind.annotation.*; import ru.ulstu.is.sbapp.Post.model.PostDto; import ru.ulstu.is.sbapp.User.model.UserDto; import ru.ulstu.is.sbapp.User.service.UserService; -import ru.ulstu.is.sbapp.WebConfiguration; +import ru.ulstu.is.sbapp.Configuration.WebConfiguration; import java.util.List; @@ -42,11 +42,10 @@ public class UserController { @PutMapping("/{id}") public UserDto updateClient(@PathVariable Long id, - @RequestParam("firstName") String firstName, - @RequestParam("lastName") String lastname, + @RequestParam("firstName") String login, @RequestParam("email") String email, @RequestParam("password") String password){ - return new UserDto(userService.updateUser(id, firstName, lastname,email,password)); + return new UserDto(userService.updateUser(id, login,email,password)); } @PostMapping("/{id}/Post") public void addPost(@PathVariable Long id, diff --git a/src/main/java/ru/ulstu/is/sbapp/User/controller/UserMvcController.java b/src/main/java/ru/ulstu/is/sbapp/User/controller/UserMvcController.java index 511570f..e16d07e 100644 --- a/src/main/java/ru/ulstu/is/sbapp/User/controller/UserMvcController.java +++ b/src/main/java/ru/ulstu/is/sbapp/User/controller/UserMvcController.java @@ -1,13 +1,31 @@ package ru.ulstu.is.sbapp.User.controller; import jakarta.validation.Valid; +import jakarta.validation.ValidationException; +import org.springframework.data.domain.Page; +import org.springframework.security.access.annotation.Secured; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import ru.ulstu.is.sbapp.Comment.model.CommentDto; +import ru.ulstu.is.sbapp.Post.model.PostDto; +import ru.ulstu.is.sbapp.User.model.User; import ru.ulstu.is.sbapp.User.model.UserDto; +import ru.ulstu.is.sbapp.User.model.UserRole; import ru.ulstu.is.sbapp.User.service.UserService; +import java.io.IOException; +import java.security.Principal; +import java.util.Base64; +import java.util.Collection; +import java.util.List; +import java.util.stream.IntStream; + @Controller @RequestMapping("/user") public class UserMvcController { @@ -16,45 +34,82 @@ public class UserMvcController { { this.userService=userService; } + @GetMapping(value = "/all") + @Secured({UserRole.AsString.ADMIN}) + public String getUsers(@RequestParam(defaultValue = "1") int page, + @RequestParam(defaultValue = "5") int size, + Principal principal, Model model) { + final Page users = userService.findAllPages(page, size) + .map(UserDto::new); + model.addAttribute("users", users); + final int totalPages = users.getTotalPages(); + final List pageNumbers = IntStream.rangeClosed(1, totalPages) + .boxed() + .toList(); + model.addAttribute("pages", pageNumbers); + model.addAttribute("totalPages", totalPages); + return "users"; + } @GetMapping - public String getUsers(Model model) { - model.addAttribute("users", - userService.findAllUsers().stream() - .map(UserDto::new) - .toList()); + public String showUpdateUserForm(Principal principal, Model model) { + UserDto userDto = new UserDto(userService.findByLogin(principal.getName())); + Long id = userService.findByLogin(principal.getName()).getId(); + model.addAttribute("userId",id); + model.addAttribute("userDto", userDto); + model.addAttribute("posts",userService.GetUserPosts(id).stream() + .map(PostDto::new) + .toList()); return "user"; } - @GetMapping(value = {"/edit", "/edit/{id}"}) - public String editUser(@PathVariable(required = false) Long id, - Model model) { - if (id == null || id <= 0) { - model.addAttribute("userDto", new UserDto()); - } else { - model.addAttribute("userId", id); - model.addAttribute("userDto", new UserDto(userService.findUser(id))); - } - return "user-edit"; - } - - @PostMapping(value = {"/", "/{id}"}) - public String saveUser(@PathVariable(required = false) Long id, - @ModelAttribute @Valid UserDto userDto, - BindingResult bindingResult, - Model model) { + @PostMapping + public String updateUser(@ModelAttribute @Valid UserDto userDto, + BindingResult bindingResult, + Model model) { if (bindingResult.hasErrors()) { model.addAttribute("errors", bindingResult.getAllErrors()); - return "user-edit"; + return "user"; } - if (id == null || id <= 0) { - userService.addUser(userDto.getFirstName(), userDto.getLastName(),userDto.getEmail(),userDto.getPassword()); - } else { - userService.updateUser(id, userDto.getFirstName(), userDto.getLastName(),userDto.getEmail(),userDto.getPassword()); + try { + userService.updateUser(userDto); + @SuppressWarnings("unchecked") + Collection nowAuthorities = + (Collection)SecurityContextHolder.getContext() + .getAuthentication() + .getAuthorities(); + UsernamePasswordAuthenticationToken authentication = + new UsernamePasswordAuthenticationToken(userDto.getLogin(), userDto.getPassword(), nowAuthorities); + SecurityContextHolder.getContext().setAuthentication(authentication); + } catch (ValidationException e) { + model.addAttribute("errors", e.getMessage()); } - return "redirect:/user"; + return "user"; } + @GetMapping("/post") + public String showCreatePostInfo(Principal principal, Model model) { + Long id = userService.findByLogin(principal.getName()).getId(); + model.addAttribute("userId",id); + model.addAttribute("postDto", new PostDto()); + return "post-create"; + } + @PostMapping("/createPost/{userId}") + public String createPost(@PathVariable(value = "userId") Long id, + @ModelAttribute @Valid PostDto postDto, + @RequestParam(value = "multipartFile") MultipartFile multipartFile, + BindingResult bindingResult, + Model model) throws IOException + { + if (bindingResult.hasErrors()) { + model.addAttribute("errors", bindingResult.getAllErrors()); + return "post-create"; + } + postDto.setImage("data:" + multipartFile.getContentType() + ";base64," + Base64.getEncoder().encodeToString(multipartFile.getBytes())); + userService.addNewPost(id,postDto); + return "redirect:/user"; + } @PostMapping("/delete/{id}") + @Secured({UserRole.AsString.ADMIN}) public String deleteUser(@PathVariable Long id) { userService.deleteUser(id); return "redirect:/user"; diff --git a/src/main/java/ru/ulstu/is/sbapp/User/controller/UserSignupMvcController.java b/src/main/java/ru/ulstu/is/sbapp/User/controller/UserSignupMvcController.java new file mode 100644 index 0000000..8b1f2c6 --- /dev/null +++ b/src/main/java/ru/ulstu/is/sbapp/User/controller/UserSignupMvcController.java @@ -0,0 +1,51 @@ +package ru.ulstu.is.sbapp.User.controller; + +import jakarta.validation.Valid; +import jakarta.validation.ValidationException; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +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 ru.ulstu.is.sbapp.User.model.User; +import ru.ulstu.is.sbapp.User.model.UserRole; +import ru.ulstu.is.sbapp.User.model.UserSignupDto; +import ru.ulstu.is.sbapp.User.service.UserService; + +@Controller +@RequestMapping(UserSignupMvcController.SIGNUP_URL) +public class UserSignupMvcController +{ + public static final String SIGNUP_URL = "/signup"; + private final UserService userService; + + public UserSignupMvcController(UserService userService) { + this.userService = userService; + } + + @GetMapping + public String showSignupForm(Model model) { + model.addAttribute("userDto", new UserSignupDto()); + return "signup"; + } + + @PostMapping + public String signup(@ModelAttribute("userDto") @Valid UserSignupDto userSignupDto, + BindingResult bindingResult, + Model model) { + if (bindingResult.hasErrors()) { + model.addAttribute("errors", bindingResult.getAllErrors()); + return "signup"; + } + try { + final User user = userService.addUser(userSignupDto.getLogin(),userSignupDto.getEmail(), + userSignupDto.getPassword(), userSignupDto.getPasswordConfirm(), UserRole.USER); + return "redirect:/login?created=" + user.getLogin(); + } catch (ValidationException e) { + model.addAttribute("errors", e.getMessage()); + return "signup"; + } + } +} diff --git a/src/main/java/ru/ulstu/is/sbapp/User/model/User.java b/src/main/java/ru/ulstu/is/sbapp/User/model/User.java index a74f26b..1918d96 100644 --- a/src/main/java/ru/ulstu/is/sbapp/User/model/User.java +++ b/src/main/java/ru/ulstu/is/sbapp/User/model/User.java @@ -2,6 +2,7 @@ package ru.ulstu.is.sbapp.User.model; import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Size; import ru.ulstu.is.sbapp.Comment.model.Comment; import ru.ulstu.is.sbapp.Post.model.Post; @@ -16,14 +17,12 @@ public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; - @Column() - @NotBlank(message = "firstName cannot be null") - private String firstName; - @NotBlank(message = "lastName cannot be null") - private String lastName; + @NotBlank(message = "Login can't be null or empty") + @Size(min = 3, max = 64, message = "Incorrect login length") + private String login; - @Column(nullable = false, unique = true, length = 64) @NotBlank(message = "email cannot be null") + @Pattern(regexp = "^(.+)@(\\S+)$", message = "Incorrect email value") private String email; @Column(nullable = false, length = 64) @@ -41,37 +40,26 @@ public class User { public User() { } - public User(String firstName,String lastName,String email, String password) { - this(firstName,lastName,email, password, UserRole.USER); + public User(String login,String email, String password) { + this(login,email, password, UserRole.USER); } - public User(String firstName, String lastName, String email,String password,UserRole role) { - this.firstName = firstName; - this.lastName = lastName; + public User(String login,String email,String password,UserRole role) { + this.login=login; this.email=email; this.password=password; this.role=role; } - + public User(UserSignupDto userSignupDto) { + this.login = userSignupDto.getLogin(); + this.email = userSignupDto.getEmail(); + this.password = userSignupDto.getPassword(); + this.role = UserRole.USER; + } public Long getId() { return id; } - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } public List getPosts() { return posts; @@ -112,6 +100,14 @@ public class User { return Objects.equals(id, user.id); } + public String getLogin() { + return login; + } + + public void setLogin(String login) { + this.login = login; + } + @Override public int hashCode() { return Objects.hash(id); @@ -121,8 +117,7 @@ public class User { public String toString() { return "Client{" + "id=" + id + - ", firstName='" + firstName + '\'' + - ", lastName='" + lastName + '\'' + + ", login='" + login + '\'' + ", email='" + email + '\'' + ", password='" + password + '\'' + ", posts=" + posts +'\''+ diff --git a/src/main/java/ru/ulstu/is/sbapp/User/model/UserDto.java b/src/main/java/ru/ulstu/is/sbapp/User/model/UserDto.java index d9c256a..faf2e59 100644 --- a/src/main/java/ru/ulstu/is/sbapp/User/model/UserDto.java +++ b/src/main/java/ru/ulstu/is/sbapp/User/model/UserDto.java @@ -10,9 +10,7 @@ import java.util.List; public class UserDto { private Long id; - private String firstName; - - private String lastName; + private String login; private String email; @@ -27,8 +25,7 @@ public class UserDto { public UserDto(){} public UserDto(User user) { this.id=user.getId(); - this.firstName = user.getFirstName(); - this.lastName = user.getLastName(); + this.login = user.getLogin(); this.email= user.getEmail(); this.role=user.getRole(); this.password=user.getPassword(); @@ -37,12 +34,8 @@ public class UserDto { return id; } - public String getFirstName() { - return firstName; - } - - public String getLastName() { - return lastName; + public String getLogin() { + return login; } public String getPassword(){ @@ -78,13 +71,10 @@ public class UserDto { this.id = id; } - public void setFirstName(String firstName) { - this.firstName = firstName; + public void setLogin(String login) { + this.login = login; } - public void setLastName(String lastName) { - this.lastName = lastName; - } public void setComments(List comments) { this.comments = comments; diff --git a/src/main/java/ru/ulstu/is/sbapp/User/model/UserSignupDto.java b/src/main/java/ru/ulstu/is/sbapp/User/model/UserSignupDto.java new file mode 100644 index 0000000..3ccd5ed --- /dev/null +++ b/src/main/java/ru/ulstu/is/sbapp/User/model/UserSignupDto.java @@ -0,0 +1,40 @@ +package ru.ulstu.is.sbapp.User.model; + +public class UserSignupDto { + private String login; + private String email; + private String password; + private String passwordConfirm; + + public String getLogin() { + return login; + } + + public void setLogin(String login) { + this.login = login; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getPasswordConfirm() { + return passwordConfirm; + } + + public void setPasswordConfirm(String passwordConfirm) { + this.passwordConfirm = passwordConfirm; + } +} diff --git a/src/main/java/ru/ulstu/is/sbapp/User/repository/UserRepository.java b/src/main/java/ru/ulstu/is/sbapp/User/repository/UserRepository.java index 9b3e9c8..4ba79e7 100644 --- a/src/main/java/ru/ulstu/is/sbapp/User/repository/UserRepository.java +++ b/src/main/java/ru/ulstu/is/sbapp/User/repository/UserRepository.java @@ -12,4 +12,6 @@ public interface UserRepository extends JpaRepository { @Query("Select p from Post p where user.id = :id") List getUsersPosts(Long id); + User findOneByLoginIgnoreCase(String login); + } diff --git a/src/main/java/ru/ulstu/is/sbapp/User/service/UserService.java b/src/main/java/ru/ulstu/is/sbapp/User/service/UserService.java index 98e3284..a4c94dd 100644 --- a/src/main/java/ru/ulstu/is/sbapp/User/service/UserService.java +++ b/src/main/java/ru/ulstu/is/sbapp/User/service/UserService.java @@ -1,5 +1,12 @@ package ru.ulstu.is.sbapp.User.service; +import jakarta.validation.ValidationException; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import ru.ulstu.is.sbapp.Comment.service.CommentService; @@ -7,40 +14,72 @@ import ru.ulstu.is.sbapp.Post.model.PostDto; import ru.ulstu.is.sbapp.Post.model.Post; import ru.ulstu.is.sbapp.Post.repository.PostRepository; import ru.ulstu.is.sbapp.User.model.User; - +import org.springframework.security.crypto.password.PasswordEncoder; +import ru.ulstu.is.sbapp.User.model.UserDto; import ru.ulstu.is.sbapp.User.model.UserRole; +import ru.ulstu.is.sbapp.User.model.UserSignupDto; import ru.ulstu.is.sbapp.User.repository.UserRepository; import ru.ulstu.is.sbapp.Util.validation.ValidatorUtil; +import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.Optional; @Service -public class UserService { +public class UserService implements UserDetailsService { private final UserRepository userRepository; private final PostRepository postRepository; private final CommentService commentService; + + private final PasswordEncoder passwordEncoder; private final ValidatorUtil validatorUtil; - public UserService(UserRepository userRepository, ValidatorUtil validatorUtil, PostRepository postRepository, CommentService commentService) + public UserService(UserRepository userRepository, ValidatorUtil validatorUtil, PostRepository postRepository, CommentService commentService,PasswordEncoder passwordEncoder) { this.userRepository=userRepository; this.validatorUtil=validatorUtil; this.postRepository = postRepository; this.commentService = commentService; + this.passwordEncoder=passwordEncoder; + } + public User findByLogin(String login) { + return userRepository.findOneByLoginIgnoreCase(login); + } + public Page findAllPages(int page, int size) { + return userRepository.findAll(PageRequest.of(page - 1, size, Sort.by("id").ascending())); } public User addUser(String firstName, String lastName, String email, String password) { return addUser(firstName,lastName, email, password, UserRole.USER); } @Transactional - public User addUser(String firstName, String lastName, String email, String password, UserRole role) { - final User user = new User(firstName, lastName, email,password,role); + public User addUser(String login, String email, String password,String passwordConfirm, UserRole role) { + if (findByLogin(login) != null) { + throw new ValidationException(String.format("User '%s' already exists", login)); + } + if (!Objects.equals(password, passwordConfirm)) { + throw new ValidationException("Passwords not equals"); + } + final User user = new User(login,email,passwordEncoder.encode(password),role); validatorUtil.validate(user); return userRepository.save(user); } + @Transactional + public User addUser(UserSignupDto userSignupDto) { + if (findByLogin(userSignupDto.getLogin()) != null) { + throw new ValidationException(String.format("User '%s' already exists", userSignupDto.getLogin())); + } + if (!Objects.equals(userSignupDto.getPassword(), userSignupDto.getPasswordConfirm())) { + throw new ValidationException("Passwords not equals"); + } + final User user = new User(userSignupDto); + validatorUtil.validate(user); + return userRepository.save(user); + } + @Transactional public User findUser(Long id) { @@ -54,15 +93,29 @@ public class UserService { } @Transactional - public User updateUser(Long id, String firstName, String lastName, String email,String password) { + public User updateUser(Long id, String firstName, String email,String password) { final User currentUser = findUser(id); - currentUser.setFirstName(firstName); - currentUser.setLastName(lastName); + currentUser.setLogin(firstName); currentUser.setEmail(email); currentUser.setPassword(password); validatorUtil.validate(currentUser); return userRepository.save(currentUser); } + @Transactional + public User updateUser(UserDto userDto) { + final User currentUser = findUser(userDto.getId()); + final User sameUser = findByLogin(userDto.getLogin()); + if (sameUser != null && !Objects.equals(sameUser.getId(), currentUser.getId())) { + throw new ValidationException(String.format("User '%s' already exists", userDto.getLogin())); + } + if (!passwordEncoder.matches(userDto.getPassword(), currentUser.getPassword())) { + throw new ValidationException("Incorrect password"); + } + currentUser.setLogin(userDto.getLogin()); + currentUser.setEmail(userDto.getEmail()); + validatorUtil.validate(currentUser); + return userRepository.save(currentUser); + } @Transactional public void deleteUser(Long id) { @@ -98,4 +151,14 @@ public class UserService { public void deletePost(Long id, Long postId) { postRepository.deleteById(postId); } + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + final User userEntity = findByLogin(username); + if (userEntity == null) { + throw new UsernameNotFoundException(username); + } + return new org.springframework.security.core.userdetails.User( + userEntity.getLogin(), userEntity.getPassword(), Collections.singleton(userEntity.getRole())); + } } diff --git a/src/main/resources/public/style.css b/src/main/resources/public/css/style.css similarity index 100% rename from src/main/resources/public/style.css rename to src/main/resources/public/css/style.css diff --git a/src/main/resources/templates/comment-create.html b/src/main/resources/templates/comment-create.html index 6e75758..5cdc70f 100644 --- a/src/main/resources/templates/comment-create.html +++ b/src/main/resources/templates/comment-create.html @@ -8,18 +8,10 @@
-
-
- - -
+
- +
diff --git a/src/main/resources/templates/error.html b/src/main/resources/templates/error.html index f960e68..32f1bbc 100644 --- a/src/main/resources/templates/error.html +++ b/src/main/resources/templates/error.html @@ -7,7 +7,7 @@ \ No newline at end of file diff --git a/src/main/resources/templates/post.html b/src/main/resources/templates/index.html similarity index 66% rename from src/main/resources/templates/post.html rename to src/main/resources/templates/index.html index 0a34ff9..208dcda 100644 --- a/src/main/resources/templates/post.html +++ b/src/main/resources/templates/index.html @@ -9,28 +9,21 @@
- +
-
+
-
@@ -66,20 +59,7 @@
- - Изменить - - -
- -
- +
diff --git a/src/main/resources/templates/login.html b/src/main/resources/templates/login.html new file mode 100644 index 0000000..64ff282 --- /dev/null +++ b/src/main/resources/templates/login.html @@ -0,0 +1,41 @@ + + + +
+
+ User not found +
+
+ Logout success +
+
+ User '' was successfully created +
+
+
+

Login

+ +
+
+

Password

+ +
+
+ +
+
+

+ Not a member yet? + Sing Up here +

+
+
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/post-create.html b/src/main/resources/templates/post-create.html index 9e9cd80..1322b46 100644 --- a/src/main/resources/templates/post-create.html +++ b/src/main/resources/templates/post-create.html @@ -7,15 +7,7 @@
-
-
- - -
+
diff --git a/src/main/resources/templates/post-edit.html b/src/main/resources/templates/post-edit.html index 357b6a5..cf994cd 100644 --- a/src/main/resources/templates/post-edit.html +++ b/src/main/resources/templates/post-edit.html @@ -7,7 +7,7 @@
- +
diff --git a/src/main/resources/templates/post-page.html b/src/main/resources/templates/post-page.html index 90aba5e..938b594 100644 --- a/src/main/resources/templates/post-page.html +++ b/src/main/resources/templates/post-page.html @@ -16,7 +16,7 @@
+ th:href="@{/index/addComment/{postId}(postId=${post.id})}"> +
@@ -38,7 +38,7 @@
- + Изменить
- + diff --git a/src/main/resources/templates/signup.html b/src/main/resources/templates/signup.html new file mode 100644 index 0000000..fefdb26 --- /dev/null +++ b/src/main/resources/templates/signup.html @@ -0,0 +1,43 @@ + + + +
+
+ +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+

+ Already have an account? + Sing In here +

+
+ +
+ + diff --git a/src/main/resources/templates/user-edit.html b/src/main/resources/templates/user-edit.html deleted file mode 100644 index 2a4e4b8..0000000 --- a/src/main/resources/templates/user-edit.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - -
-
-
-
- - -
-
- - -
-
- - -
-
- - -
-
- - - Назад - -
-
-
- - \ No newline at end of file diff --git a/src/main/resources/templates/user.html b/src/main/resources/templates/user.html index 8cfe226..5a0cf41 100644 --- a/src/main/resources/templates/user.html +++ b/src/main/resources/templates/user.html @@ -1,57 +1,108 @@ - + + +
-
- - + -
- - - - - - - - - - - - - - - - -
#IDИмяПочтаПароль
- - - - - -
- +

Данные профиля

+
+
+ +
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+
+ +
+
+
+ +
+
+
+ +
+
+

+
+
+ + + + + + + + + + + + + +
#ПользовательТекст
+ + +
+
+
+ Изменить - +
+ +
+
-
- -
-
+
+
+
- \ No newline at end of file + + + + + + diff --git a/src/main/resources/templates/users.html b/src/main/resources/templates/users.html new file mode 100644 index 0000000..4f064b5 --- /dev/null +++ b/src/main/resources/templates/users.html @@ -0,0 +1,54 @@ + + + + + +
+
+ + + + + + + + + + + + + + + + +
#IDЛогинПочтаПароль
+ + + + +
+ +
+
+ +
+
+ +
+
+ + \ No newline at end of file