From 9a41c4caae7660014c70ab518ab9097d60323682 Mon Sep 17 00:00:00 2001 From: Leonid Date: Sun, 16 Feb 2025 14:46:28 +0300 Subject: [PATCH] =?UTF-8?q?-=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB?= =?UTF-8?q?=20=D0=BC=D0=B8=D0=B3=D1=80=D0=B0=D1=86=D0=B8=D0=B8=20Flyway.?= =?UTF-8?q?=20-=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D1=84=D0=B8=D0=BB=D1=8C=20=D0=BF=D0=BE=D0=BB=D1=8C?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D1=8F=20=D0=B8=20?= =?UTF-8?q?=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D1=8C=20=D0=B5=D0=B3=D0=BE=20=D1=80=D0=B5=D0=B4=D0=B0=D0=BA?= =?UTF-8?q?=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F.=20https?= =?UTF-8?q?://www.youtube.com/watch=3Fv=3DArM7nCys4hY&list=3DPLU2ftbIeotGp?= =?UTF-8?q?AYRP9Iv2KLIwK36-o=5FqYk&index=3D12?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 8 +++ .../sweater/controller/UserController.java | 48 ++++++++++------- .../sytes/kashey/sweater/domain/Message.java | 6 +-- .../sweater/security/CustomUserDetails.java | 4 ++ .../service/CustomUserDetailsService.java | 53 +++++++++++++++++-- src/main/resources/application.properties | 3 +- .../resources/db/migration/V1__Init_DB.sql | 48 +++++++++++++++++ .../resources/db/migration/V2__Add_admin.sql | 5 ++ src/main/resources/templates/parts/navbar.ftl | 5 ++ src/main/resources/templates/profile.ftl | 24 +++++++++ 10 files changed, 179 insertions(+), 25 deletions(-) create mode 100644 src/main/resources/db/migration/V1__Init_DB.sql create mode 100644 src/main/resources/db/migration/V2__Add_admin.sql create mode 100644 src/main/resources/templates/profile.ftl diff --git a/pom.xml b/pom.xml index 46299bd..81738c6 100644 --- a/pom.xml +++ b/pom.xml @@ -69,6 +69,14 @@ org.springframework.boot spring-boot-starter-mail + + org.flywaydb + flyway-core + + + org.flywaydb + flyway-mysql + diff --git a/src/main/java/net/sytes/kashey/sweater/controller/UserController.java b/src/main/java/net/sytes/kashey/sweater/controller/UserController.java index 6b9adf6..b721c19 100644 --- a/src/main/java/net/sytes/kashey/sweater/controller/UserController.java +++ b/src/main/java/net/sytes/kashey/sweater/controller/UserController.java @@ -2,36 +2,37 @@ package net.sytes.kashey.sweater.controller; import net.sytes.kashey.sweater.domain.Role; import net.sytes.kashey.sweater.domain.User; -import net.sytes.kashey.sweater.repository.UserRepository; +import net.sytes.kashey.sweater.security.CustomUserDetails; +import net.sytes.kashey.sweater.service.CustomUserDetailsService; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; -import java.util.Arrays; import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; @Controller @RequestMapping("/users") -@PreAuthorize("hasAuthority('ADMIN')") + public class UserController { - private final UserRepository userRepository; + private final CustomUserDetailsService customUserDetailsService; - public UserController(UserRepository userRepository) { + public UserController(CustomUserDetailsService customUserDetailsService) { - this.userRepository = userRepository; + this.customUserDetailsService = customUserDetailsService; } + @PreAuthorize("hasAuthority('ADMIN')") @GetMapping public String getAllUsers(Model model) { - model.addAttribute("users", userRepository.findAll()); + model.addAttribute("users", customUserDetailsService.findAll()); return "userList"; } + @PreAuthorize("hasAuthority('ADMIN')") @GetMapping("/{user}") public String editUser(@PathVariable User user, Model model) { @@ -40,20 +41,31 @@ public class UserController { return "userEdit"; } + @PreAuthorize("hasAuthority('ADMIN')") @PostMapping public String updateUser(@RequestParam String username, @RequestParam Map form, @RequestParam("userId") User user) { - user.setUsername(username); - user.getRoles().clear(); - Set roles = Arrays.stream(Role.values()).map(Enum::name).collect(Collectors.toSet()); - for (String role : form.keySet()) { - if (roles.contains(role)) { - user.getRoles().add(Role.valueOf(role)); - } - } - userRepository.save(user); + customUserDetailsService.updateUser(username, form, user); return "redirect:/users"; } + + @GetMapping("/profile") + public String getProfile(Model model, @AuthenticationPrincipal CustomUserDetails customUserDetails) { + model.addAttribute("username", customUserDetails.getUsername()); + model.addAttribute("email", customUserDetails.getEmail()); + model.addAttribute("password", customUserDetails.getPassword()); + customUserDetails.getPassword(); + return "profile"; + } + + @PostMapping("/profile") + public String updateProfile(@AuthenticationPrincipal CustomUserDetails customUserDetails, + @RequestParam String password, + @RequestParam String email) { + + customUserDetailsService.updateProfile(customUserDetails.getUser(), password, email); + return "redirect:/users/profile"; + } } \ No newline at end of file diff --git a/src/main/java/net/sytes/kashey/sweater/domain/Message.java b/src/main/java/net/sytes/kashey/sweater/domain/Message.java index 2bff318..4048587 100644 --- a/src/main/java/net/sytes/kashey/sweater/domain/Message.java +++ b/src/main/java/net/sytes/kashey/sweater/domain/Message.java @@ -6,7 +6,7 @@ import jakarta.persistence.*; public class Message { @Id @GeneratedValue(strategy = GenerationType.AUTO) - private Integer id; + private Long id; private String text; private String tag; @@ -25,11 +25,11 @@ public class Message { this.author = author; } - public Integer getId() { + public Long getId() { return id; } - public void setId(Integer id) { + public void setId(Long id) { this.id = id; } diff --git a/src/main/java/net/sytes/kashey/sweater/security/CustomUserDetails.java b/src/main/java/net/sytes/kashey/sweater/security/CustomUserDetails.java index 8413b67..c2d4c82 100644 --- a/src/main/java/net/sytes/kashey/sweater/security/CustomUserDetails.java +++ b/src/main/java/net/sytes/kashey/sweater/security/CustomUserDetails.java @@ -61,4 +61,8 @@ public class CustomUserDetails implements UserDetails { public boolean isAdmin() { return user.getRoles().contains(Role.ADMIN); } + + public String getEmail() { + return user.getEmail(); + } } \ No newline at end of file diff --git a/src/main/java/net/sytes/kashey/sweater/service/CustomUserDetailsService.java b/src/main/java/net/sytes/kashey/sweater/service/CustomUserDetailsService.java index 7d5cff3..398662d 100644 --- a/src/main/java/net/sytes/kashey/sweater/service/CustomUserDetailsService.java +++ b/src/main/java/net/sytes/kashey/sweater/service/CustomUserDetailsService.java @@ -11,8 +11,8 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import org.springframework.util.ObjectUtils; -import java.util.Collections; -import java.util.UUID; +import java.util.*; +import java.util.stream.Collectors; @Service public class CustomUserDetailsService implements UserDetailsService { @@ -53,6 +53,11 @@ public class CustomUserDetailsService implements UserDetailsService { user.setPassword("{noop}" + user.getPassword()); //пока не введено шифрование паролей userRepository.save(user); + sendMessage(user); + return ""; + } + + private void sendMessage(User user) { if (!ObjectUtils.isEmpty(user.getEmail())) { String message = String.format( @@ -65,7 +70,6 @@ public class CustomUserDetailsService implements UserDetailsService { emailService.send(user.getEmail(), "Activation code", message); } - return ""; } public boolean activateUser(String activationCode) { @@ -80,4 +84,47 @@ public class CustomUserDetailsService implements UserDetailsService { userRepository.save(user); return true; } + + public void updateUser(String username, Map form, User user) { + + user.setUsername(username); + user.getRoles().clear(); + Set roles = Arrays.stream(Role.values()).map(Enum::name).collect(Collectors.toSet()); + for (String role : form.keySet()) { + if (roles.contains(role)) { + user.getRoles().add(Role.valueOf(role)); + } + } + userRepository.save(user); + } + + public void updateProfile(User user, String password, String email) { + + String userEmail = user.getEmail(); + + boolean isEmailChanged = (email != null && !email.equals(userEmail)) || + (userEmail != null && !userEmail.equals(email)); + + if (isEmailChanged) { + user.setEmail(email); + + if (!ObjectUtils.isEmpty(email)) { + user.setActivationCode(UUID.randomUUID().toString()); + } + } + + if (!ObjectUtils.isEmpty(password)) { + user.setPassword("{noop}" + password); + } + + userRepository.save(user); + + if (isEmailChanged) { + sendMessage(user); + } + } + + public List findAll() { + return userRepository.findAll(); + } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 3050627..35ede6f 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,4 +1,5 @@ -spring.jpa.hibernate.ddl-auto=update +spring.jpa.hibernate.ddl-auto=validate +spring.jpa.show-sql=true spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/sweater_db spring.datasource.username=user spring.datasource.password=123456 diff --git a/src/main/resources/db/migration/V1__Init_DB.sql b/src/main/resources/db/migration/V1__Init_DB.sql new file mode 100644 index 0000000..ce9f7ca --- /dev/null +++ b/src/main/resources/db/migration/V1__Init_DB.sql @@ -0,0 +1,48 @@ +create table message +( + id bigint not null, + user_id bigint, + filename varchar(255), + tag varchar(255), + text varchar(2048) not null, + primary key (id) +) engine = InnoDB; + +create table message_seq +( + next_val bigint +) engine = InnoDB; + +insert into message_seq +values (1); + +create table user_role +( + user_id bigint not null, + roles enum ('ADMIN','USER') +) engine = InnoDB; + +create table usr +( + enabled bit not null, + id bigint not null, + activation_code varchar(255), + email varchar(255), + password varchar(255) not null, + username varchar(255) not null, + primary key (id) +) engine = InnoDB; + +create table usr_seq +( + next_val bigint +) engine = InnoDB; + +insert into usr_seq +values (1); + +alter table message + add constraint message_user_fk foreign key (user_id) references usr (id); + +alter table user_role + add constraint user_role_user_fk foreign key (user_id) references usr (id); diff --git a/src/main/resources/db/migration/V2__Add_admin.sql b/src/main/resources/db/migration/V2__Add_admin.sql new file mode 100644 index 0000000..a2ac870 --- /dev/null +++ b/src/main/resources/db/migration/V2__Add_admin.sql @@ -0,0 +1,5 @@ +insert into usr (id, username, password, enabled) +values (1, 'admin', '{noop}admin', true); + +insert into user_role (user_id, roles) +values (1, 'USER'), (1, 'ADMIN'); \ No newline at end of file diff --git a/src/main/resources/templates/parts/navbar.ftl b/src/main/resources/templates/parts/navbar.ftl index 22cd2df..5371439 100644 --- a/src/main/resources/templates/parts/navbar.ftl +++ b/src/main/resources/templates/parts/navbar.ftl @@ -22,6 +22,11 @@ Users + <#if user??> + + diff --git a/src/main/resources/templates/profile.ftl b/src/main/resources/templates/profile.ftl new file mode 100644 index 0000000..2a50586 --- /dev/null +++ b/src/main/resources/templates/profile.ftl @@ -0,0 +1,24 @@ +<#import "parts/common.ftl" as com> + +<@com.page> +
${username}
+ <#if message??> +
${message}
+ +
+
+ +
+ +
+
+
+ +
+ +
+
+ + +
+ \ No newline at end of file