diff --git a/build.gradle b/build.gradle index 43bcafb..9fc7191 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.7.8' + id 'org.springframework.boot' version '3.0.2' id 'io.spring.dependency-management' version '1.0.15.RELEASE' } @@ -13,17 +13,24 @@ repositories { } dependencies { + annotationProcessor "org.springframework.boot:spring-boot-configuration-processor" implementation 'org.springframework.boot:spring-boot-starter-web' - developmentOnly 'org.springframework.boot:spring-boot-devtools' - implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' - implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect' - implementation 'org.webjars:bootstrap:5.1.3' - implementation 'org.webjars:jquery:3.6.0' - implementation 'org.webjars:font-awesome:6.1.0' - implementation 'com.h2database:h2:2.1.210' - implementation 'org.hibernate.validator:hibernate-validator:6.0.17.Final' - implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.6.5' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' + implementation 'org.springframework.boot:spring-boot-starter-security' + implementation 'com.auth0:java-jwt:4.4.0' + implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6' + implementation 'org.springframework.boot:spring-boot-devtools' + implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect' + + implementation 'org.webjars:bootstrap:5.1.3' + implementation 'org.webjars:font-awesome:6.1.0' + + implementation 'org.webjars:jquery:3.6.0' + implementation 'com.h2database:h2:2.1.210' + implementation 'jakarta.validation:jakarta.validation-api:3.0.0' + implementation 'org.hibernate.validator:hibernate-validator:7.0.1.Final' + implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.6.5' testImplementation 'org.springframework.boot:spring-boot-starter-test' } diff --git a/data.mv.db b/data.mv.db index 8fa6ada..c9a8a86 100644 Binary files a/data.mv.db and b/data.mv.db differ diff --git a/src/main/java/ru/ip/labworks/labworks/bookshop/controller/AuthorController.java b/src/main/java/ru/ip/labworks/labworks/bookshop/controller/AuthorController.java index 9bd7c19..2238588 100644 --- a/src/main/java/ru/ip/labworks/labworks/bookshop/controller/AuthorController.java +++ b/src/main/java/ru/ip/labworks/labworks/bookshop/controller/AuthorController.java @@ -1,9 +1,9 @@ -package ru.ip.labworks.labworks.bookshop.controller; +/*package ru.ip.labworks.labworks.bookshop.controller; import org.springframework.web.bind.annotation.*; import ru.ip.labworks.labworks.bookshop.service.AuthorService; import ru.ip.labworks.labworks.configuration.WebConfiguration; -import javax.validation.Valid; +import jakarta.validation.Valid; import java.io.IOException; import java.util.List; import java.util.Map; @@ -62,4 +62,4 @@ public class AuthorController { public Map> getAuthorsBooks(){ return authorService.AllAuthorsAndBooks(); } -} +}*/ diff --git a/src/main/java/ru/ip/labworks/labworks/bookshop/controller/AuthorMvcController.java b/src/main/java/ru/ip/labworks/labworks/bookshop/controller/AuthorMvcController.java index 374ee73..109a2e2 100644 --- a/src/main/java/ru/ip/labworks/labworks/bookshop/controller/AuthorMvcController.java +++ b/src/main/java/ru/ip/labworks/labworks/bookshop/controller/AuthorMvcController.java @@ -1,4 +1,5 @@ package ru.ip.labworks.labworks.bookshop.controller; +import org.springframework.security.core.Authentication; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; @@ -6,8 +7,10 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import ru.ip.labworks.labworks.bookshop.service.AuthorService; import ru.ip.labworks.labworks.bookshop.service.BookService; +import ru.ip.labworks.labworks.bookshop.service.UserService; import java.io.IOException; +import java.security.Principal; import java.util.Base64; @Controller @@ -15,14 +18,17 @@ import java.util.Base64; public class AuthorMvcController { private final AuthorService authorService; private final BookService bookService; - public AuthorMvcController(AuthorService authorService, BookService bookService) + private final UserService userService; + public AuthorMvcController(UserService userService, AuthorService authorService, BookService bookService) { this.authorService = authorService; this.bookService = bookService; + this.userService = userService; } @GetMapping - public String getAuthors(Model model) { + public String getAuthors(Model model, Authentication authentication) { + model.addAttribute("user", userService.findByLogin(authentication.getName())); model.addAttribute("authors", authorService.findAllAuthors().stream() .map(AuthorDto::new) @@ -32,8 +38,10 @@ public class AuthorMvcController { @GetMapping(value = {"/update", "/update/{id}"}) public String updateAuthor(@PathVariable(required = false) Long id, - Model model) { + Model model, Principal principal) { if (id == null || id <= 0) { + Long userId = userService.findByLogin(principal.getName()).getId(); + model.addAttribute("userId",userId); model.addAttribute("authorDto", new AuthorDto()); } else { model.addAttribute("authorDto", id); @@ -47,15 +55,17 @@ public class AuthorMvcController { @RequestParam(value = "multipartFile") MultipartFile multipartFile, @ModelAttribute("authorDto") AuthorDto authorDto, BindingResult bindingResult, - Model model) throws IOException { + Model model, Principal principal) throws IOException { if (bindingResult.hasErrors()) { model.addAttribute("errors", bindingResult.getAllErrors()); return "author-update"; } + Long userId = userService.findByLogin(principal.getName()).getId(); + model.addAttribute("userId", userId); authorDto.setPhoto("data:" + multipartFile.getContentType() + ";base64," + Base64.getEncoder().encodeToString(multipartFile.getBytes())); if (id == null || id <= 0) { - return "redirect:/author/" + authorService.addAuthor(authorDto).getId().toString() + "/books"; + return "redirect:/author/" + authorService.addAuthor(authorDto, userId).getId().toString() + "/books"; } else { authorService.updateAuthor(id, authorDto); } diff --git a/src/main/java/ru/ip/labworks/labworks/bookshop/controller/BookController.java b/src/main/java/ru/ip/labworks/labworks/bookshop/controller/BookController.java index b60e01c..bd599a5 100644 --- a/src/main/java/ru/ip/labworks/labworks/bookshop/controller/BookController.java +++ b/src/main/java/ru/ip/labworks/labworks/bookshop/controller/BookController.java @@ -3,7 +3,7 @@ import org.springframework.web.bind.annotation.*; import ru.ip.labworks.labworks.bookshop.service.BookService; import ru.ip.labworks.labworks.configuration.WebConfiguration; -import javax.validation.Valid; +import jakarta.validation.Valid; import java.io.IOException; import java.util.List; diff --git a/src/main/java/ru/ip/labworks/labworks/bookshop/controller/GenreController.java b/src/main/java/ru/ip/labworks/labworks/bookshop/controller/GenreController.java index 8912319..e449824 100644 --- a/src/main/java/ru/ip/labworks/labworks/bookshop/controller/GenreController.java +++ b/src/main/java/ru/ip/labworks/labworks/bookshop/controller/GenreController.java @@ -3,7 +3,7 @@ import org.springframework.web.bind.annotation.*; import ru.ip.labworks.labworks.bookshop.service.GenreService; import ru.ip.labworks.labworks.configuration.WebConfiguration; -import javax.validation.Valid; +import jakarta.validation.Valid; import java.io.IOException; import java.util.List; diff --git a/src/main/java/ru/ip/labworks/labworks/bookshop/controller/GenreMvcController.java b/src/main/java/ru/ip/labworks/labworks/bookshop/controller/GenreMvcController.java index c303858..d5a239d 100644 --- a/src/main/java/ru/ip/labworks/labworks/bookshop/controller/GenreMvcController.java +++ b/src/main/java/ru/ip/labworks/labworks/bookshop/controller/GenreMvcController.java @@ -3,7 +3,6 @@ import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.*; -import ru.ip.labworks.labworks.bookshop.service.BookService; import ru.ip.labworks.labworks.bookshop.service.GenreService; import java.io.IOException; diff --git a/src/main/java/ru/ip/labworks/labworks/bookshop/controller/UserDto.java b/src/main/java/ru/ip/labworks/labworks/bookshop/controller/UserDto.java new file mode 100644 index 0000000..6e899bc --- /dev/null +++ b/src/main/java/ru/ip/labworks/labworks/bookshop/controller/UserDto.java @@ -0,0 +1,28 @@ +package ru.ip.labworks.labworks.bookshop.controller; + +import ru.ip.labworks.labworks.bookshop.model.User; +import ru.ip.labworks.labworks.bookshop.model.UserRole; + +public class UserDto { + private final long id; + private final String login; + private final UserRole role; + + public UserDto(User user) { + this.id = user.getId(); + this.login = user.getLogin(); + this.role = user.getRole(); + } + + public long getId() { + return id; + } + + public String getLogin() { + return login; + } + + public UserRole getRole() { + return role; + } +} diff --git a/src/main/java/ru/ip/labworks/labworks/bookshop/controller/UserMvcController.java b/src/main/java/ru/ip/labworks/labworks/bookshop/controller/UserMvcController.java new file mode 100644 index 0000000..7a26f30 --- /dev/null +++ b/src/main/java/ru/ip/labworks/labworks/bookshop/controller/UserMvcController.java @@ -0,0 +1,41 @@ +package ru.ip.labworks.labworks.bookshop.controller; + +import org.springframework.data.domain.Page; +import org.springframework.security.access.annotation.Secured; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import ru.ip.labworks.labworks.bookshop.model.UserRole; +import ru.ip.labworks.labworks.bookshop.service.UserService; + +import java.util.List; +import java.util.stream.IntStream; + +@Controller +@RequestMapping("/users") +public class UserMvcController { + private final UserService userService; + + public UserMvcController(UserService userService) { + this.userService = userService; + } + + @GetMapping + @Secured({UserRole.AsString.ADMIN}) + public String getUsers(@RequestParam(defaultValue = "1") int page, + @RequestParam(defaultValue = "5") int size, + 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"; + } +} diff --git a/src/main/java/ru/ip/labworks/labworks/bookshop/controller/UserSignUpDTO.java b/src/main/java/ru/ip/labworks/labworks/bookshop/controller/UserSignUpDTO.java new file mode 100644 index 0000000..86ce3eb --- /dev/null +++ b/src/main/java/ru/ip/labworks/labworks/bookshop/controller/UserSignUpDTO.java @@ -0,0 +1,40 @@ +package ru.ip.labworks.labworks.bookshop.controller; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +public class UserSignUpDTO { + @NotBlank + @Size(min = 3, max = 64) + private String login; + @NotBlank + @Size(min = 6, max = 64) + private String password; + @NotBlank + @Size(min = 6, max = 64) + private String passwordConfirm; + + public String getLogin() { + return login; + } + + public void setLogin(String login) { + this.login = login; + } + + 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/ip/labworks/labworks/bookshop/controller/UserSignUpMvcController.java b/src/main/java/ru/ip/labworks/labworks/bookshop/controller/UserSignUpMvcController.java new file mode 100644 index 0000000..feb94aa --- /dev/null +++ b/src/main/java/ru/ip/labworks/labworks/bookshop/controller/UserSignUpMvcController.java @@ -0,0 +1,48 @@ +package ru.ip.labworks.labworks.bookshop.controller; + +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.ip.labworks.labworks.bookshop.model.User; +import ru.ip.labworks.labworks.bookshop.service.UserService; + +import jakarta.validation.Valid; +import jakarta.validation.ValidationException; + +@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.createUser(userSignupDto.getLogin(), userSignupDto.getPassword(), userSignupDto.getPasswordConfirm()); + return "redirect:/login?created=" + user.getLogin(); + } catch (ValidationException e) { + model.addAttribute("errors", e.getMessage()); + return "signup"; + } + } +} diff --git a/src/main/java/ru/ip/labworks/labworks/bookshop/model/Author.java b/src/main/java/ru/ip/labworks/labworks/bookshop/model/Author.java index 5c02aa4..99424e0 100644 --- a/src/main/java/ru/ip/labworks/labworks/bookshop/model/Author.java +++ b/src/main/java/ru/ip/labworks/labworks/bookshop/model/Author.java @@ -1,8 +1,8 @@ package ru.ip.labworks.labworks.bookshop.model; +import jakarta.persistence.*; import ru.ip.labworks.labworks.bookshop.controller.AuthorDto; -import javax.persistence.*; import java.util.*; @Entity @@ -20,6 +20,10 @@ public class Author { inverseJoinColumns = @JoinColumn(name = "book_fk")) private List books; + @ManyToOne + @JoinColumn(name= "user_id", nullable = false) + private User user; + public Author(){} public Author(String firstname, String lastname, byte[] photo){ this.firstname = firstname; @@ -74,4 +78,11 @@ public class Author { public void removeBook(Book book) { books.remove(book); } + + public User getUser() { + return user; + } + public void setUser(User user) { + this.user = user; + } } diff --git a/src/main/java/ru/ip/labworks/labworks/bookshop/model/Book.java b/src/main/java/ru/ip/labworks/labworks/bookshop/model/Book.java index 69d6859..9a39c8f 100644 --- a/src/main/java/ru/ip/labworks/labworks/bookshop/model/Book.java +++ b/src/main/java/ru/ip/labworks/labworks/bookshop/model/Book.java @@ -1,10 +1,10 @@ package ru.ip.labworks.labworks.bookshop.model; +import jakarta.persistence.*; import org.hibernate.annotations.LazyCollection; import org.hibernate.annotations.LazyCollectionOption; import ru.ip.labworks.labworks.bookshop.controller.BookDto; -import javax.persistence.*; import java.util.*; @Entity @@ -26,6 +26,10 @@ public class Book { @ManyToMany(fetch = FetchType.EAGER, mappedBy = "books") private List authors; + @ManyToOne + @JoinColumn(name= "user_id", nullable = false) + private User user; + public Book(){} public Book(String name,Date release, byte[] cover){ this.name = name; @@ -80,4 +84,11 @@ public class Book { public void removeGenre(Genre genre) { genres.remove(genre); } + + public User getUser() { + return user; + } + public void setUser(User user) { + this.user = user; + } } diff --git a/src/main/java/ru/ip/labworks/labworks/bookshop/model/Genre.java b/src/main/java/ru/ip/labworks/labworks/bookshop/model/Genre.java index 86c94bc..fae1da9 100644 --- a/src/main/java/ru/ip/labworks/labworks/bookshop/model/Genre.java +++ b/src/main/java/ru/ip/labworks/labworks/bookshop/model/Genre.java @@ -1,8 +1,8 @@ package ru.ip.labworks.labworks.bookshop.model; +import jakarta.persistence.*; import ru.ip.labworks.labworks.bookshop.controller.GenreDto; -import javax.persistence.*; import java.util.*; @Entity @@ -12,6 +12,10 @@ public class Genre { private Long id; private String name; + @ManyToOne + @JoinColumn(name= "user_id", nullable = false) + private User user; + public Genre(){} public Genre(String name){ this.name = name; @@ -45,4 +49,11 @@ public class Genre { ", name='" + name + '\'' + '}'; } + + public User getUser() { + return user; + } + public void setUser(User user) { + this.user = user; + } } diff --git a/src/main/java/ru/ip/labworks/labworks/bookshop/model/User.java b/src/main/java/ru/ip/labworks/labworks/bookshop/model/User.java new file mode 100644 index 0000000..e1d4f0f --- /dev/null +++ b/src/main/java/ru/ip/labworks/labworks/bookshop/model/User.java @@ -0,0 +1,83 @@ +package ru.ip.labworks.labworks.bookshop.model; + +import jakarta.persistence.*; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import java.util.Objects; + +@Entity +@Table(name = "users") +public class User { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + @Column(nullable = false, unique = true, length = 64) + @NotBlank + @Size(min = 3, max = 64) + private String login; + @Column(nullable = false, length = 64) + @NotBlank + @Size(min = 6, max = 64) + private String password; + private UserRole role; + + public User() { + } + + public User(String login, String password) { + this(login, password, UserRole.USER); + } + + public User(String login, String password, UserRole role) { + this.login = login; + this.password = password; + this.role = role; + } + + public Long getId() { + return id; + } + + public String getLogin() { + return login; + } + + public void setLogin(String login) { + this.login = login; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public UserRole getRole() { + return role; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + User user = (User) o; + return Objects.equals(id, user.id) && Objects.equals(login, user.login); + } + + @Override + public int hashCode() { + return Objects.hash(id, login); + } + @Override + public String toString() { + return "User{" + + "id=" + id + + ", login='" + login + '\'' + + ", password='" + password + '\'' + + ", role='" + role + '\'' + + '}'; + } +} diff --git a/src/main/java/ru/ip/labworks/labworks/bookshop/model/UserRole.java b/src/main/java/ru/ip/labworks/labworks/bookshop/model/UserRole.java new file mode 100644 index 0000000..f442c65 --- /dev/null +++ b/src/main/java/ru/ip/labworks/labworks/bookshop/model/UserRole.java @@ -0,0 +1,20 @@ +package ru.ip.labworks.labworks.bookshop.model; + +import org.springframework.security.core.GrantedAuthority; + +public enum UserRole implements GrantedAuthority { + ADMIN, + USER; + + private static final String PREFIX = "ROLE_"; + + @Override + public String getAuthority() { + return PREFIX + this.name(); + } + + public static final class AsString { + public static final String ADMIN = PREFIX + "ADMIN"; + public static final String USER = PREFIX + "USER"; + } +} diff --git a/src/main/java/ru/ip/labworks/labworks/bookshop/repository/UserRepository.java b/src/main/java/ru/ip/labworks/labworks/bookshop/repository/UserRepository.java new file mode 100644 index 0000000..1acfa4a --- /dev/null +++ b/src/main/java/ru/ip/labworks/labworks/bookshop/repository/UserRepository.java @@ -0,0 +1,8 @@ +package ru.ip.labworks.labworks.bookshop.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import ru.ip.labworks.labworks.bookshop.model.User; + +public interface UserRepository extends JpaRepository { + User findOneByLoginIgnoreCase(String login); +} diff --git a/src/main/java/ru/ip/labworks/labworks/bookshop/service/AuthorService.java b/src/main/java/ru/ip/labworks/labworks/bookshop/service/AuthorService.java index 7551009..5627291 100644 --- a/src/main/java/ru/ip/labworks/labworks/bookshop/service/AuthorService.java +++ b/src/main/java/ru/ip/labworks/labworks/bookshop/service/AuthorService.java @@ -24,11 +24,14 @@ public class AuthorService { private final BookService bookService; @Autowired private final ValidatorUtil validatorUtil; + @Autowired + private final UserService userService; - public AuthorService(AuthorRepository authorRepository, BookService bookService, ValidatorUtil validatorUtil){ + public AuthorService(AuthorRepository authorRepository, BookService bookService, ValidatorUtil validatorUtil, UserService userService){ this.authorRepository = authorRepository; this.bookService = bookService; this.validatorUtil = validatorUtil; + this.userService = userService; } @Transactional @@ -42,8 +45,10 @@ public class AuthorService { } @Transactional - public Author addAuthor(AuthorDto authorDto) throws IOException { + public Author addAuthor(AuthorDto authorDto, Long userId) throws IOException { + User currentUser = userService.findUser(userId); final Author author = new Author(authorDto); + author.setUser(currentUser); validatorUtil.validate(author); return authorRepository.save(author); } diff --git a/src/main/java/ru/ip/labworks/labworks/bookshop/service/ImageHelper.java b/src/main/java/ru/ip/labworks/labworks/bookshop/service/ImageHelper.java index 9a76ac8..1e17379 100644 --- a/src/main/java/ru/ip/labworks/labworks/bookshop/service/ImageHelper.java +++ b/src/main/java/ru/ip/labworks/labworks/bookshop/service/ImageHelper.java @@ -1,6 +1,6 @@ package ru.ip.labworks.labworks.bookshop.service; -import javax.imageio.ImageIO; +//import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.File; @@ -8,13 +8,14 @@ import java.io.File; public class ImageHelper { public static byte[] ImageToByte(File image){ try { - BufferedImage bufferedImage = ImageIO.read(image); + /*BufferedImage bufferedImage = ImageIO.read(image); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ImageIO.write(bufferedImage, "jpg", byteArrayOutputStream); - return byteArrayOutputStream.toByteArray(); + return byteArrayOutputStream.toByteArray();*/ } catch (Exception ex) { return null; } + return null; } } diff --git a/src/main/java/ru/ip/labworks/labworks/bookshop/service/UserNotFoundException.java b/src/main/java/ru/ip/labworks/labworks/bookshop/service/UserNotFoundException.java new file mode 100644 index 0000000..f21e1a6 --- /dev/null +++ b/src/main/java/ru/ip/labworks/labworks/bookshop/service/UserNotFoundException.java @@ -0,0 +1,7 @@ +package ru.ip.labworks.labworks.bookshop.service; + +public class UserNotFoundException extends RuntimeException{ + public UserNotFoundException(Long id) { + super(String.format("User with id [%s] is not found", id)); + } +} diff --git a/src/main/java/ru/ip/labworks/labworks/bookshop/service/UserService.java b/src/main/java/ru/ip/labworks/labworks/bookshop/service/UserService.java new file mode 100644 index 0000000..9324570 --- /dev/null +++ b/src/main/java/ru/ip/labworks/labworks/bookshop/service/UserService.java @@ -0,0 +1,66 @@ +package ru.ip.labworks.labworks.bookshop.service; + +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.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.ip.labworks.labworks.bookshop.model.User; +import ru.ip.labworks.labworks.bookshop.model.UserRole; +import ru.ip.labworks.labworks.bookshop.repository.UserRepository; + +import jakarta.validation.ValidationException; +import java.util.Collections; +import java.util.Objects; +import java.util.Optional; + +@Service +public class UserService implements UserDetailsService { + private final UserRepository userRepository; + private final PasswordEncoder passwordEncoder; + + public UserService(UserRepository userRepository, + PasswordEncoder passwordEncoder) { + this.userRepository = userRepository; + this.passwordEncoder = passwordEncoder; + } + public Page findAllPages(int page, int size) { + return userRepository.findAll(PageRequest.of(page - 1, size, Sort.by("id").ascending())); + } + public User findByLogin(String login) { + return userRepository.findOneByLoginIgnoreCase(login); + } + public User createUser(String login, String password, String passwordConfirm) { + return createUser(login, password, passwordConfirm, UserRole.USER); + } + public User createUser(String login, String password, String passwordConfirm, UserRole role) { + if (findByLogin(login) != null) { + throw new ValidationException(String.format("User '%s' already exists", login)); + } + final User user = new User(login, passwordEncoder.encode(password), role); + if (!Objects.equals(password, passwordConfirm)) { + throw new ValidationException("Passwords not equals"); + } + return userRepository.save(user); + } + + @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())); + } + + @Transactional(readOnly = true) + public User findUser(Long id) { + final Optional user = userRepository.findById(id); + return user.orElseThrow(() -> new UserNotFoundException(id)); + } +} diff --git a/src/main/java/ru/ip/labworks/labworks/configuration/PasswordEncoderConfiguration.java b/src/main/java/ru/ip/labworks/labworks/configuration/PasswordEncoderConfiguration.java new file mode 100644 index 0000000..544463b --- /dev/null +++ b/src/main/java/ru/ip/labworks/labworks/configuration/PasswordEncoderConfiguration.java @@ -0,0 +1,14 @@ +package ru.ip.labworks.labworks.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(); + } +} \ No newline at end of file diff --git a/src/main/java/ru/ip/labworks/labworks/configuration/SecurityConfiguration.java b/src/main/java/ru/ip/labworks/labworks/configuration/SecurityConfiguration.java new file mode 100644 index 0000000..1e0c6e6 --- /dev/null +++ b/src/main/java/ru/ip/labworks/labworks/configuration/SecurityConfiguration.java @@ -0,0 +1,68 @@ +package ru.ip.labworks.labworks.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.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.ip.labworks.labworks.bookshop.controller.UserSignUpMvcController; +import ru.ip.labworks.labworks.bookshop.model.UserRole; +import ru.ip.labworks.labworks.bookshop.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.createUser(admin, 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() + .defaultSuccessUrl("/author", true) + .and() + .logout().permitAll(); + return http.userDetailsService(userService).build(); + } + + + @Bean + public WebSecurityCustomizer webSecurityCustomizer() { + return (web) -> web.ignoring() + .requestMatchers("/css/**") + .requestMatchers("/js/**") + .requestMatchers("/templates/**") + .requestMatchers("/webjars/**"); + } +} \ No newline at end of file diff --git a/src/main/java/ru/ip/labworks/labworks/configuration/WebConfiguration.java b/src/main/java/ru/ip/labworks/labworks/configuration/WebConfiguration.java index 065df0f..54ba1c6 100644 --- a/src/main/java/ru/ip/labworks/labworks/configuration/WebConfiguration.java +++ b/src/main/java/ru/ip/labworks/labworks/configuration/WebConfiguration.java @@ -11,7 +11,7 @@ public class WebConfiguration implements WebMvcConfigurer { @Override public void addViewControllers(ViewControllerRegistry registry) { WebMvcConfigurer.super.addViewControllers(registry); - registry.addViewController("author"); + registry.addViewController("login"); } @Override diff --git a/src/main/java/ru/ip/labworks/labworks/util/validation/ValidatorUtil.java b/src/main/java/ru/ip/labworks/labworks/util/validation/ValidatorUtil.java index e86c779..46bbf1f 100644 --- a/src/main/java/ru/ip/labworks/labworks/util/validation/ValidatorUtil.java +++ b/src/main/java/ru/ip/labworks/labworks/util/validation/ValidatorUtil.java @@ -2,10 +2,10 @@ package ru.ip.labworks.labworks.util.validation; import org.springframework.stereotype.Component; -import javax.validation.ConstraintViolation; -import javax.validation.Validation; -import javax.validation.Validator; -import javax.validation.ValidatorFactory; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; import java.util.Set; import java.util.stream.Collectors; diff --git a/src/main/resources/templates/all-authors-books.html b/src/main/resources/templates/all-authors-books.html index 52bc7e7..95e7d24 100644 --- a/src/main/resources/templates/all-authors-books.html +++ b/src/main/resources/templates/all-authors-books.html @@ -1,7 +1,7 @@ + layout:decorate="~{default}" xmlns:th="http://www.w3.org/1999/xhtml"> diff --git a/src/main/resources/templates/author-mtm.html b/src/main/resources/templates/author-mtm.html index 18af5d6..402a0d2 100644 --- a/src/main/resources/templates/author-mtm.html +++ b/src/main/resources/templates/author-mtm.html @@ -1,7 +1,7 @@ + layout:decorate="~{default}" xmlns:th="http://www.w3.org/1999/xhtml"> diff --git a/src/main/resources/templates/author-update.html b/src/main/resources/templates/author-update.html index 268327a..b073034 100644 --- a/src/main/resources/templates/author-update.html +++ b/src/main/resources/templates/author-update.html @@ -1,7 +1,7 @@ + layout:decorate="~{default}" xmlns:th="http://www.w3.org/1999/xhtml"> diff --git a/src/main/resources/templates/authors.html b/src/main/resources/templates/authors.html index 2acd0e1..dff0e15 100644 --- a/src/main/resources/templates/authors.html +++ b/src/main/resources/templates/authors.html @@ -1,14 +1,14 @@ + layout:decorate="~{default}" xmlns:th="http://www.w3.org/1999/xhtml">
+ th:href="@{/author/update}"> Добавить + layout:decorate="~{default}" xmlns:th="http://www.w3.org/1999/xhtml"> diff --git a/src/main/resources/templates/book-update.html b/src/main/resources/templates/book-update.html index ae3016c..262b49e 100644 --- a/src/main/resources/templates/book-update.html +++ b/src/main/resources/templates/book-update.html @@ -1,7 +1,7 @@ + layout:decorate="~{default}" xmlns:th="http://www.w3.org/1999/xhtml"> diff --git a/src/main/resources/templates/books.html b/src/main/resources/templates/books.html index 27b0e31..d8035ab 100644 --- a/src/main/resources/templates/books.html +++ b/src/main/resources/templates/books.html @@ -1,14 +1,14 @@ + layout:decorate="~{default}" xmlns:th="http://www.w3.org/1999/xhtml">
diff --git a/src/main/resources/templates/default.html b/src/main/resources/templates/default.html index 843e863..6e15801 100644 --- a/src/main/resources/templates/default.html +++ b/src/main/resources/templates/default.html @@ -22,10 +22,12 @@ diff --git a/src/main/resources/templates/error.html b/src/main/resources/templates/error.html index 566549b..a2f317f 100644 --- a/src/main/resources/templates/error.html +++ b/src/main/resources/templates/error.html @@ -1,10 +1,13 @@ - - - - Title - + - + \ No newline at end of file diff --git a/src/main/resources/templates/genre-update.html b/src/main/resources/templates/genre-update.html index 4e5b7f2..b4a683a 100644 --- a/src/main/resources/templates/genre-update.html +++ b/src/main/resources/templates/genre-update.html @@ -1,7 +1,7 @@ + layout:decorate="~{default}" xmlns:th="http://www.w3.org/1999/xhtml"> diff --git a/src/main/resources/templates/genres.html b/src/main/resources/templates/genres.html index ed3f680..0dd2593 100644 --- a/src/main/resources/templates/genres.html +++ b/src/main/resources/templates/genres.html @@ -1,14 +1,14 @@ + layout:decorate="~{default}" xmlns:th="http://www.w3.org/1999/xhtml">
diff --git a/src/main/resources/templates/login.html b/src/main/resources/templates/login.html new file mode 100644 index 0000000..e8b17ca --- /dev/null +++ b/src/main/resources/templates/login.html @@ -0,0 +1,42 @@ + + + +
+
+ User not found +
+
+ Logout success +
+
+ User '' was successfully created +
+
+
+

Login

+ +
+
+

Password

+ +
+
+ +
+
+

+ Not a member yet? + Sign Up here +

+
+
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/signup.html b/src/main/resources/templates/signup.html new file mode 100644 index 0000000..9f4e0e6 --- /dev/null +++ b/src/main/resources/templates/signup.html @@ -0,0 +1,29 @@ + + + +
+
+
+
+ +
+
+ +
+
+ +
+
+ + Назад +
+
+
+ + \ 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..34c6cfa --- /dev/null +++ b/src/main/resources/templates/users.html @@ -0,0 +1,38 @@ + + + +
+
+ + + + + + + + + + + + + + + + + +
#IDЛогинРоль
+
+ +
+ + \ No newline at end of file diff --git a/src/test/java/ru/ip/labworks/labworks/JpaAuthorTests.java b/src/test/java/ru/ip/labworks/labworks/JpaAuthorTests.java index 90402b1..62335a0 100644 --- a/src/test/java/ru/ip/labworks/labworks/JpaAuthorTests.java +++ b/src/test/java/ru/ip/labworks/labworks/JpaAuthorTests.java @@ -8,7 +8,6 @@ import ru.ip.labworks.labworks.bookshop.model.Author; import ru.ip.labworks.labworks.bookshop.model.Book; import ru.ip.labworks.labworks.bookshop.service.AuthorService; import ru.ip.labworks.labworks.bookshop.service.BookService; -import javax.persistence.EntityNotFoundException; import java.io.File; import java.util.ArrayList; import java.util.HashMap; diff --git a/src/test/java/ru/ip/labworks/labworks/JpaBookTests.java b/src/test/java/ru/ip/labworks/labworks/JpaBookTests.java index 494ff80..3daae8f 100644 --- a/src/test/java/ru/ip/labworks/labworks/JpaBookTests.java +++ b/src/test/java/ru/ip/labworks/labworks/JpaBookTests.java @@ -10,7 +10,6 @@ import ru.ip.labworks.labworks.bookshop.service.BookService; import ru.ip.labworks.labworks.bookshop.service.GenreService; import javax.imageio.ImageIO; -import javax.persistence.EntityNotFoundException; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.File; diff --git a/src/test/java/ru/ip/labworks/labworks/JpaGenreTests.java b/src/test/java/ru/ip/labworks/labworks/JpaGenreTests.java index 5f1b29d..6c5f2b7 100644 --- a/src/test/java/ru/ip/labworks/labworks/JpaGenreTests.java +++ b/src/test/java/ru/ip/labworks/labworks/JpaGenreTests.java @@ -7,7 +7,6 @@ import org.springframework.boot.test.context.SpringBootTest; import ru.ip.labworks.labworks.bookshop.model.Genre; import ru.ip.labworks.labworks.bookshop.service.GenreService; -import javax.persistence.EntityNotFoundException; import java.util.List; @SpringBootTest diff --git a/src/test/java/ru/ip/labworks/labworks/LabworksApplicationTests.java b/src/test/java/ru/ip/labworks/labworks/LabworksApplicationTests.java index 2775abb..d128458 100644 --- a/src/test/java/ru/ip/labworks/labworks/LabworksApplicationTests.java +++ b/src/test/java/ru/ip/labworks/labworks/LabworksApplicationTests.java @@ -5,11 +5,10 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import ru.ip.labworks.labworks.calculator.service.CalculatorService; @SpringBootTest class LabworksApplicationTests { - @Autowired + /*@Autowired CalculatorService calculatorService; @Test @@ -87,5 +86,5 @@ class LabworksApplicationTests { @Test void testErrorErrorWired() { Assertions.assertThrows(NoSuchBeanDefinitionException.class, () -> calculatorService.Plus("date", 1, 2)); - } + }*/ }