Compare commits
No commits in common. "main" and "lab-3" have entirely different histories.
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
SpringApp/data.mv.db
|
SpringApp/data.mv.db
|
||||||
SpringApp/library/data.mv.db
|
SpringApp/library/data.mv.db
|
||||||
|
SpringApp/library/data.trace.db
|
||||||
|
@ -7,10 +7,22 @@
|
|||||||
"role": "admin"
|
"role": "admin"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "user",
|
"name": "testUser",
|
||||||
"password": "123",
|
"password": "123",
|
||||||
"role": "user",
|
"role": "user",
|
||||||
"id": 2
|
"id": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "testUser2",
|
||||||
|
"password": "123",
|
||||||
|
"role": "user",
|
||||||
|
"id": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "testUser3",
|
||||||
|
"password": "123",
|
||||||
|
"role": "user",
|
||||||
|
"id": 4
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"types": [
|
"types": [
|
||||||
|
@ -1,15 +1,8 @@
|
|||||||
import { Button, Table } from 'react-bootstrap';
|
import { Button, Table } from 'react-bootstrap';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import AuthorizationForm from '../components/users/authorization/form/AuthorizationForm.jsx';
|
|
||||||
|
|
||||||
const UserFavorities = () => {
|
const UserFavorities = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
if (!parseInt(localStorage.getItem('userId'), 10)) {
|
|
||||||
return (
|
|
||||||
<AuthorizationForm/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h1 className='mt-2 text-md-start text-center'>
|
<h1 className='mt-2 text-md-start text-center'>
|
||||||
|
@ -1,14 +1,8 @@
|
|||||||
import { Button, Table } from 'react-bootstrap';
|
import { Button, Table } from 'react-bootstrap';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import AuthorizationForm from '../components/users/authorization/form/AuthorizationForm.jsx';
|
|
||||||
|
|
||||||
const UserHistory = () => {
|
const UserHistory = () => {
|
||||||
if (!parseInt(localStorage.getItem('userId'), 10)) {
|
// const navigate = useNavigate();
|
||||||
return (
|
|
||||||
<AuthorizationForm/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h1 className='mt-2 text-md-start text-center'>
|
<h1 className='mt-2 text-md-start text-center'>
|
||||||
|
@ -2,7 +2,8 @@ import AuthorizationForm from '../components/users/authorization/form/Authorizat
|
|||||||
import UserPageInfo from '../components/users/userPage/UserPageInfo.jsx';
|
import UserPageInfo from '../components/users/userPage/UserPageInfo.jsx';
|
||||||
|
|
||||||
const UserPage = () => {
|
const UserPage = () => {
|
||||||
if (!parseInt(localStorage.getItem('userId'), 10)) {
|
const id = parseInt(localStorage.getItem('userId'), 10);
|
||||||
|
if (!id) {
|
||||||
return (
|
return (
|
||||||
<AuthorizationForm/>
|
<AuthorizationForm/>
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'java'
|
id 'java'
|
||||||
id 'org.springframework.boot' version '3.3.0'
|
id 'org.springframework.boot' version '3.2.4'
|
||||||
id 'io.spring.dependency-management' version '1.1.4'
|
id 'io.spring.dependency-management' version '1.1.4'
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,11 +34,6 @@ dependencies {
|
|||||||
|
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||||
implementation 'com.h2database:h2:2.2.224'
|
implementation 'com.h2database:h2:2.2.224'
|
||||||
|
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-security'
|
|
||||||
implementation 'com.auth0:java-jwt:4.4.0'
|
|
||||||
|
|
||||||
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
|
|
||||||
|
|
||||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||||
}
|
}
|
||||||
|
@ -12,14 +12,14 @@ import org.springframework.boot.CommandLineRunner;
|
|||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
import com.ip.library.controllers.authors.AuthorEntity;
|
import com.ip.library.authors.model.AuthorEntity;
|
||||||
import com.ip.library.controllers.authors.AuthorService;
|
import com.ip.library.authors.service.AuthorService;
|
||||||
import com.ip.library.controllers.books.BookEntity;
|
import com.ip.library.books.model.BookEntity;
|
||||||
import com.ip.library.controllers.books.BookService;
|
import com.ip.library.books.service.BookService;
|
||||||
import com.ip.library.controllers.types.TypeEntity;
|
import com.ip.library.types.model.TypeEntity;
|
||||||
import com.ip.library.controllers.types.TypeService;
|
import com.ip.library.types.service.TypeService;
|
||||||
import com.ip.library.controllers.users.UserEntity;
|
import com.ip.library.users.model.UserEntity;
|
||||||
import com.ip.library.controllers.users.UserService;
|
import com.ip.library.users.service.UserService;
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
package com.ip.library.controllers.authors;
|
package com.ip.library.authors.api;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.modelmapper.ModelMapper;
|
import org.modelmapper.ModelMapper;
|
||||||
import org.springframework.security.access.annotation.Secured;
|
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
@ -13,14 +12,14 @@ import org.springframework.web.bind.annotation.RequestBody;
|
|||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import com.ip.library.controllers.users.UserRole;
|
|
||||||
import com.ip.library.core.configuration.Constants;
|
import com.ip.library.core.configuration.Constants;
|
||||||
|
import com.ip.library.authors.model.AuthorEntity;
|
||||||
|
import com.ip.library.authors.service.AuthorService;
|
||||||
|
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@Secured(value = UserRole.Secured.ADMIN)
|
|
||||||
@RequestMapping(Constants.API_URL + "/author")
|
@RequestMapping(Constants.API_URL + "/author")
|
||||||
public class AuthorController {
|
public class AuthorController {
|
||||||
private final AuthorService authorService;
|
private final AuthorService authorService;
|
@ -1,4 +1,4 @@
|
|||||||
package com.ip.library.controllers.authors;
|
package com.ip.library.authors.api;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
@ -1,11 +1,11 @@
|
|||||||
package com.ip.library.controllers.authors;
|
package com.ip.library.authors.model;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import com.ip.library.controllers.authors_books.AuthorsBooksEntity;
|
import com.ip.library.authors_books.model.AuthorsBooksEntity;
|
||||||
import com.ip.library.controllers.books.BookEntity;
|
import com.ip.library.books.model.BookEntity;
|
||||||
import com.ip.library.core.model.BaseEntity;
|
import com.ip.library.core.model.BaseEntity;
|
||||||
|
|
||||||
import jakarta.persistence.CascadeType;
|
import jakarta.persistence.CascadeType;
|
@ -1,10 +1,12 @@
|
|||||||
package com.ip.library.controllers.authors;
|
package com.ip.library.authors.repository;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.springframework.data.repository.CrudRepository;
|
import org.springframework.data.repository.CrudRepository;
|
||||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||||
|
|
||||||
|
import com.ip.library.authors.model.AuthorEntity;
|
||||||
|
|
||||||
public interface AuthorRepository extends
|
public interface AuthorRepository extends
|
||||||
CrudRepository<AuthorEntity, Long>,
|
CrudRepository<AuthorEntity, Long>,
|
||||||
PagingAndSortingRepository<AuthorEntity, Long> {
|
PagingAndSortingRepository<AuthorEntity, Long> {
|
@ -1,4 +1,4 @@
|
|||||||
package com.ip.library.controllers.authors;
|
package com.ip.library.authors.service;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.StreamSupport;
|
import java.util.stream.StreamSupport;
|
||||||
@ -7,6 +7,8 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import com.ip.library.core.error.NotFoundException;
|
import com.ip.library.core.error.NotFoundException;
|
||||||
|
import com.ip.library.authors.model.AuthorEntity;
|
||||||
|
import com.ip.library.authors.repository.AuthorRepository;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class AuthorService {
|
public class AuthorService {
|
@ -1,9 +1,9 @@
|
|||||||
package com.ip.library.controllers.authors_books;
|
package com.ip.library.authors_books.model;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import com.ip.library.controllers.authors.AuthorEntity;
|
import com.ip.library.authors.model.AuthorEntity;
|
||||||
import com.ip.library.controllers.books.BookEntity;
|
import com.ip.library.books.model.BookEntity;
|
||||||
|
|
||||||
import jakarta.persistence.EmbeddedId;
|
import jakarta.persistence.EmbeddedId;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
@ -1,4 +1,4 @@
|
|||||||
package com.ip.library.controllers.authors_books;
|
package com.ip.library.authors_books.model;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
@ -1,9 +1,8 @@
|
|||||||
package com.ip.library.controllers.books;
|
package com.ip.library.books.api;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.modelmapper.ModelMapper;
|
import org.modelmapper.ModelMapper;
|
||||||
import org.springframework.security.access.annotation.Secured;
|
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
@ -14,14 +13,14 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import com.ip.library.controllers.types.TypeService;
|
import com.ip.library.books.model.BookEntity;
|
||||||
import com.ip.library.controllers.users.UserRole;
|
import com.ip.library.books.service.BookService;
|
||||||
import com.ip.library.core.configuration.Constants;
|
import com.ip.library.core.configuration.Constants;
|
||||||
|
import com.ip.library.types.service.TypeService;
|
||||||
|
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@Secured(value = UserRole.Secured.ADMIN)
|
|
||||||
@RequestMapping(Constants.API_URL + "/book")
|
@RequestMapping(Constants.API_URL + "/book")
|
||||||
public class BookController {
|
public class BookController {
|
||||||
private final BookService bookService;
|
private final BookService bookService;
|
||||||
@ -36,7 +35,7 @@ public class BookController {
|
|||||||
|
|
||||||
private BookDto toBookDto (BookEntity entity) {
|
private BookDto toBookDto (BookEntity entity) {
|
||||||
BookDto bookDto = modelMapper.map(entity, BookDto.class);
|
BookDto bookDto = modelMapper.map(entity, BookDto.class);
|
||||||
bookDto.setAuthorIds(entity.getAuthorsBooks().stream().map(x -> x.getAuthor().getId()).toList());
|
bookDto.setAuthorId(entity.getAuthorsBooks().stream().map(x -> x.getAuthor().getId()).toList());
|
||||||
return bookDto;
|
return bookDto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,16 +74,15 @@ public class BookController {
|
|||||||
return toBookDto(bookService.delete(id));
|
return toBookDto(bookService.delete(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{bookId}/users/number")
|
||||||
|
public int getBookSubscribersNumber(@PathVariable(name = "bookId") Long bookId) {
|
||||||
|
return bookService.getBookSubscribersNumber(bookId);
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/{bookId}/author/{authorId}")
|
@GetMapping("/{bookId}/author/{authorId}")
|
||||||
public boolean addAuthor(
|
public boolean addAuthor(
|
||||||
@PathVariable(name = "bookId") Long bookId,
|
@PathVariable(name = "bookId") Long bookId,
|
||||||
@PathVariable(name = "authorId") Long authorId) {
|
@PathVariable(name = "authorId") Long authorId) {
|
||||||
return bookService.addAuthor(authorId, bookId);
|
return bookService.addAuthor(authorId, bookId);
|
||||||
}
|
|
||||||
|
|
||||||
@Secured(value = { UserRole.Secured.USER, UserRole.Secured.ADMIN })
|
|
||||||
@GetMapping("/{bookId}/number")
|
|
||||||
public int getBookSubscribersNumber(@PathVariable(name = "bookId") Long bookId) {
|
|
||||||
return bookService.getBookSubscribersNumber(bookId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package com.ip.library.controllers.books;
|
package com.ip.library.books.api;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ public class BookDto {
|
|||||||
@Min(1)
|
@Min(1)
|
||||||
private Long typeId;
|
private Long typeId;
|
||||||
@NotNull
|
@NotNull
|
||||||
private List<Long> authorIds;
|
private List<Long> authorsId;
|
||||||
|
|
||||||
public Long getId() {
|
public Long getId() {
|
||||||
return id;
|
return id;
|
||||||
@ -43,11 +43,11 @@ public class BookDto {
|
|||||||
this.typeId = typeId;
|
this.typeId = typeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Long> getAuthorIds() {
|
public List<Long> getAuthorsId() {
|
||||||
return authorIds;
|
return authorsId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAuthorIds(List<Long> authorIds) {
|
public void setAuthorId(List<Long> authorsId) {
|
||||||
this.authorIds = authorIds;
|
this.authorsId = authorsId;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,10 +1,11 @@
|
|||||||
package com.ip.library.controllers.books;
|
package com.ip.library.books.model;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import com.ip.library.core.model.BaseEntity;
|
import com.ip.library.core.model.BaseEntity;
|
||||||
|
import com.ip.library.types.model.TypeEntity;
|
||||||
|
|
||||||
import jakarta.persistence.CascadeType;
|
import jakarta.persistence.CascadeType;
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
@ -16,9 +17,8 @@ import jakarta.persistence.OneToMany;
|
|||||||
import jakarta.persistence.OrderBy;
|
import jakarta.persistence.OrderBy;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
import com.ip.library.controllers.authors.AuthorEntity;
|
import com.ip.library.authors.model.AuthorEntity;
|
||||||
import com.ip.library.controllers.authors_books.AuthorsBooksEntity;
|
import com.ip.library.authors_books.model.AuthorsBooksEntity;
|
||||||
import com.ip.library.controllers.types.TypeEntity;
|
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "books")
|
@Table(name = "books")
|
@ -1,4 +1,4 @@
|
|||||||
package com.ip.library.controllers.books;
|
package com.ip.library.books.repository;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -9,6 +9,8 @@ import org.springframework.data.jpa.repository.Query;
|
|||||||
import org.springframework.data.repository.CrudRepository;
|
import org.springframework.data.repository.CrudRepository;
|
||||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||||
|
|
||||||
|
import com.ip.library.books.model.BookEntity;
|
||||||
|
|
||||||
public interface BookRepository extends
|
public interface BookRepository extends
|
||||||
CrudRepository<BookEntity, Long>,
|
CrudRepository<BookEntity, Long>,
|
||||||
PagingAndSortingRepository<BookEntity, Long> {
|
PagingAndSortingRepository<BookEntity, Long> {
|
@ -1,4 +1,4 @@
|
|||||||
package com.ip.library.controllers.books;
|
package com.ip.library.books.service;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.StreamSupport;
|
import java.util.stream.StreamSupport;
|
||||||
@ -8,8 +8,10 @@ import org.springframework.data.domain.PageRequest;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import com.ip.library.controllers.authors.AuthorEntity;
|
import com.ip.library.authors.model.AuthorEntity;
|
||||||
import com.ip.library.controllers.authors.AuthorService;
|
import com.ip.library.authors.service.AuthorService;
|
||||||
|
import com.ip.library.books.model.BookEntity;
|
||||||
|
import com.ip.library.books.repository.BookRepository;
|
||||||
import com.ip.library.core.error.NotFoundException;
|
import com.ip.library.core.error.NotFoundException;
|
||||||
|
|
||||||
@Service
|
@Service
|
@ -1,45 +0,0 @@
|
|||||||
package com.ip.library.controllers.users;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import com.ip.library.core.configuration.Constants;
|
|
||||||
|
|
||||||
@RestController
|
|
||||||
public class LoginController {
|
|
||||||
private final UserService userService;
|
|
||||||
|
|
||||||
public LoginController(UserService userService) {
|
|
||||||
this.userService = userService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping(Constants.LOGIN_URL)
|
|
||||||
public String login(
|
|
||||||
@RequestParam(name = "login") String login,
|
|
||||||
@RequestParam(name = "password") String password) {
|
|
||||||
return userService.login(login, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping(Constants.SIGNUP_URL)
|
|
||||||
public boolean signup(
|
|
||||||
@RequestParam(name = "login") String login,
|
|
||||||
@RequestParam(name = "password") String password,
|
|
||||||
@RequestParam(name = "password2") String password2) {
|
|
||||||
if (!StringUtils.hasText(login)) {
|
|
||||||
throw new IllegalArgumentException("Invalid login");
|
|
||||||
}
|
|
||||||
if (!StringUtils.hasText(password)) {
|
|
||||||
throw new IllegalArgumentException("Invalid password");
|
|
||||||
}
|
|
||||||
if (!Objects.equals(password, password2)) {
|
|
||||||
throw new IllegalArgumentException("Passwords are not equals");
|
|
||||||
}
|
|
||||||
final UserEntity user = new UserEntity(login, password);
|
|
||||||
userService.create(user);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
package com.ip.library.controllers.users;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.modelmapper.ModelMapper;
|
|
||||||
import org.springframework.security.access.annotation.Secured;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import com.ip.library.controllers.books.BookDto;
|
|
||||||
import com.ip.library.controllers.books.BookEntity;
|
|
||||||
import com.ip.library.core.configuration.Constants;
|
|
||||||
|
|
||||||
@RestController
|
|
||||||
@Secured(value = { UserRole.Secured.USER, UserRole.Secured.ADMIN })
|
|
||||||
@RequestMapping(Constants.API_URL + "/user/{userId}/book")
|
|
||||||
public class UserBookController {
|
|
||||||
private final UserService userService;
|
|
||||||
private final ModelMapper modelMapper;
|
|
||||||
|
|
||||||
public UserBookController(
|
|
||||||
UserService userService,
|
|
||||||
ModelMapper modelMapper) {
|
|
||||||
this.userService = userService;
|
|
||||||
this.modelMapper = modelMapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
private BookDto toBookDto (BookEntity entity) {
|
|
||||||
BookDto bookDto = modelMapper.map(entity, BookDto.class);
|
|
||||||
bookDto.setAuthorIds(entity.getAuthorsBooks().stream().map(x -> x.getAuthor().getId()).toList());
|
|
||||||
return bookDto;
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{bookId}")
|
|
||||||
public boolean addFavorite(
|
|
||||||
@PathVariable(name = "userId") Long userId,
|
|
||||||
@PathVariable(name = "bookId") Long bookId) {
|
|
||||||
return userService.addFavorite(userId, bookId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/all-books")
|
|
||||||
public List<BookDto> getUserFavorites(
|
|
||||||
@PathVariable(name = "userId") Long userId,
|
|
||||||
@RequestParam(name = "page", defaultValue = "0") int page,
|
|
||||||
@RequestParam(name = "size", defaultValue = Constants.DEFAULT_PAGE_SIZE) int size) {
|
|
||||||
return userService.getUserFavorities(userId, page, size).stream().map(this::toBookDto).toList();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
package com.ip.library.controllers.users;
|
|
||||||
|
|
||||||
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 Secured {
|
|
||||||
private Secured() {}
|
|
||||||
|
|
||||||
public static final String ADMIN = PREFIX + "ADMIN";
|
|
||||||
public static final String USER = PREFIX + "USER";
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,10 +7,5 @@ public class Constants {
|
|||||||
|
|
||||||
public static final String DEFAULT_PAGE_SIZE = "5";
|
public static final String DEFAULT_PAGE_SIZE = "5";
|
||||||
|
|
||||||
public static final String LOGIN_URL = "/login";
|
|
||||||
public static final String SIGNUP_URL = "/signup";
|
|
||||||
|
|
||||||
public static final String DEFAULT_PASSWORD = "123456";
|
|
||||||
|
|
||||||
private Constants() {}
|
private Constants() {}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.ip.library.core.configuration;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class WebConfiguration implements WebMvcConfigurer {
|
||||||
|
@Override
|
||||||
|
public void addCorsMappings(@NonNull CorsRegistry registry) {
|
||||||
|
registry.addMapping("/**")
|
||||||
|
.allowedMethods("GET", "POST", "PUT", "DELETE");
|
||||||
|
}
|
||||||
|
}
|
@ -1,83 +0,0 @@
|
|||||||
package com.ip.library.core.error;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.http.HttpStatusCode;
|
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.security.access.AccessDeniedException;
|
|
||||||
import org.springframework.security.core.AuthenticationException;
|
|
||||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
|
||||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
|
||||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
|
||||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
|
|
||||||
import jakarta.servlet.ServletException;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
@RestControllerAdvice
|
|
||||||
public class AdviceController implements AuthenticationEntryPoint {
|
|
||||||
private final Logger log = LoggerFactory.getLogger(AdviceController.class);
|
|
||||||
|
|
||||||
public static ErrorCauseDto getRootCause(Throwable throwable) {
|
|
||||||
Throwable rootCause = throwable;
|
|
||||||
while (rootCause.getCause() != null && rootCause.getCause() != rootCause) {
|
|
||||||
rootCause = rootCause.getCause();
|
|
||||||
}
|
|
||||||
final StackTraceElement firstError = rootCause.getStackTrace()[0];
|
|
||||||
return new ErrorCauseDto(
|
|
||||||
rootCause.getClass().getName(),
|
|
||||||
firstError.getMethodName(),
|
|
||||||
firstError.getFileName(),
|
|
||||||
firstError.getLineNumber());
|
|
||||||
}
|
|
||||||
|
|
||||||
private ResponseEntity<ErrorDto> handleException(Throwable throwable, HttpStatusCode httpCode) {
|
|
||||||
log.error("{}", throwable.getMessage());
|
|
||||||
throwable.printStackTrace();
|
|
||||||
final ErrorDto errorDto = new ErrorDto(throwable.getMessage(), AdviceController.getRootCause(throwable));
|
|
||||||
return new ResponseEntity<>(errorDto, httpCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void commence(
|
|
||||||
HttpServletRequest request,
|
|
||||||
HttpServletResponse response,
|
|
||||||
AuthenticationException authException) throws IOException, ServletException {
|
|
||||||
final ResponseEntity<ErrorDto> body = handleException(authException, HttpStatus.UNAUTHORIZED);
|
|
||||||
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
|
||||||
response.setStatus(body.getStatusCode().value());
|
|
||||||
response.getWriter().write(new ObjectMapper().writeValueAsString(body.getBody()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@ExceptionHandler(AccessDeniedException.class)
|
|
||||||
@ResponseStatus(HttpStatus.FORBIDDEN)
|
|
||||||
public ResponseEntity<ErrorDto> handleAccessDeniedException(Throwable throwable) {
|
|
||||||
return handleException(throwable, HttpStatus.FORBIDDEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ExceptionHandler(NotFoundException.class)
|
|
||||||
@ResponseStatus(HttpStatus.NOT_FOUND)
|
|
||||||
public ResponseEntity<ErrorDto> handleNotFoundException(Throwable throwable) {
|
|
||||||
return handleException(throwable, HttpStatus.NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
|
||||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
|
||||||
public ResponseEntity<ErrorDto> handleDataIntegrityViolationException(Throwable throwable) {
|
|
||||||
return handleException(throwable, HttpStatus.BAD_REQUEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ExceptionHandler(Exception.class)
|
|
||||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
|
||||||
public ResponseEntity<ErrorDto> handleAnyException(Throwable throwable) {
|
|
||||||
return handleException(throwable, HttpStatus.INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
package com.ip.library.core.error;
|
|
||||||
|
|
||||||
class ErrorCauseDto {
|
|
||||||
private String exception;
|
|
||||||
private String methodName;
|
|
||||||
private String fineName;
|
|
||||||
private int lineNumber;
|
|
||||||
|
|
||||||
ErrorCauseDto(String exception, String methodName, String fineName, int lineNumber) {
|
|
||||||
this.exception = exception;
|
|
||||||
this.methodName = methodName;
|
|
||||||
this.fineName = fineName;
|
|
||||||
this.lineNumber = lineNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getException() {
|
|
||||||
return exception;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMethodName() {
|
|
||||||
return methodName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFineName() {
|
|
||||||
return fineName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getLineNumber() {
|
|
||||||
return lineNumber;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
package com.ip.library.core.error;
|
|
||||||
|
|
||||||
public class ErrorDto {
|
|
||||||
private String error;
|
|
||||||
private ErrorCauseDto rootCause;
|
|
||||||
|
|
||||||
public ErrorDto(String error, ErrorCauseDto rootCause) {
|
|
||||||
this.error = error;
|
|
||||||
this.rootCause = rootCause;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getError() {
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ErrorCauseDto getRootCause() {
|
|
||||||
return rootCause;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
package com.ip.library.core.jwt;
|
|
||||||
|
|
||||||
public class JwtException extends RuntimeException {
|
|
||||||
public JwtException(Throwable throwable) {
|
|
||||||
super(throwable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public JwtException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
package com.ip.library.core.jwt;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.springframework.lang.NonNull;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.security.core.context.SecurityContext;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
|
||||||
|
|
||||||
import com.ip.library.controllers.users.UserService;
|
|
||||||
|
|
||||||
import jakarta.servlet.FilterChain;
|
|
||||||
import jakarta.servlet.ServletException;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
public class JwtFilter extends OncePerRequestFilter {
|
|
||||||
private static final String AUTHORIZATION = "Authorization";
|
|
||||||
public static final String TOKEN_BEGIN_STR = "Bearer ";
|
|
||||||
|
|
||||||
private final UserService userService;
|
|
||||||
|
|
||||||
public JwtFilter(UserService userService) {
|
|
||||||
this.userService = userService;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getTokenFromRequest(HttpServletRequest request) {
|
|
||||||
String bearer = request.getHeader(AUTHORIZATION);
|
|
||||||
if (StringUtils.hasText(bearer) && StringUtils.startsWithIgnoreCase(bearer, TOKEN_BEGIN_STR)) {
|
|
||||||
return bearer.substring(TOKEN_BEGIN_STR.length());
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doFilterInternal(
|
|
||||||
@NonNull HttpServletRequest request,
|
|
||||||
@NonNull HttpServletResponse response,
|
|
||||||
@NonNull FilterChain filterChain) throws ServletException, IOException {
|
|
||||||
final String token = getTokenFromRequest(request);
|
|
||||||
if (!StringUtils.hasText(token)) {
|
|
||||||
filterChain.doFilter(request, response);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final UserDetails user = userService.getByToken(token);
|
|
||||||
final UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
|
|
||||||
user,
|
|
||||||
null,
|
|
||||||
user.getAuthorities());
|
|
||||||
final SecurityContext context = SecurityContextHolder.createEmptyContext();
|
|
||||||
context.setAuthentication(auth);
|
|
||||||
SecurityContextHolder.setContext(context);
|
|
||||||
filterChain.doFilter(request, response);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
package com.ip.library.core.jwt;
|
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@ConfigurationProperties(prefix = "jwt", ignoreInvalidFields = true)
|
|
||||||
public class JwtProperties {
|
|
||||||
private String key = "";
|
|
||||||
|
|
||||||
public String getKey() {
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setKey(String key) {
|
|
||||||
this.key = key;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,110 +0,0 @@
|
|||||||
package com.ip.library.core.jwt;
|
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.time.ZoneId;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import com.auth0.jwt.JWT;
|
|
||||||
import com.auth0.jwt.algorithms.Algorithm;
|
|
||||||
import com.auth0.jwt.exceptions.JWTVerificationException;
|
|
||||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
|
||||||
import com.auth0.jwt.interfaces.JWTVerifier;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
public class JwtProvider {
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(JwtProvider.class);
|
|
||||||
|
|
||||||
private static final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII);
|
|
||||||
private static final String ISSUER = "auth0";
|
|
||||||
|
|
||||||
private final Algorithm algorithm;
|
|
||||||
private final JWTVerifier verifier;
|
|
||||||
|
|
||||||
public JwtProvider(JwtProperties jwtProperties) {
|
|
||||||
final String key = jwtProperties.getKey();
|
|
||||||
if (!StringUtils.hasText(key)) {
|
|
||||||
log.info("Generate new JWT key");
|
|
||||||
try {
|
|
||||||
final MessageDigest salt = MessageDigest.getInstance("SHA-256");
|
|
||||||
salt.update(UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8));
|
|
||||||
final String hex = bytesToHex(salt.digest());
|
|
||||||
log.info("Use generated JWT key for prod \n{}", hex);
|
|
||||||
algorithm = Algorithm.HMAC256(hex);
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
throw new JwtException(e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.info("Use JWT key from config \n{}", key);
|
|
||||||
algorithm = Algorithm.HMAC256(key);
|
|
||||||
}
|
|
||||||
verifier = JWT.require(algorithm)
|
|
||||||
.withIssuer(ISSUER)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String bytesToHex(byte[] bytes) {
|
|
||||||
byte[] hexChars = new byte[bytes.length * 2];
|
|
||||||
for (int j = 0; j < bytes.length; j++) {
|
|
||||||
int v = bytes[j] & 0xFF;
|
|
||||||
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
|
|
||||||
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
|
|
||||||
}
|
|
||||||
return new String(hexChars, StandardCharsets.UTF_8);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String generateToken(String login) {
|
|
||||||
final Date issueDate = Date.from(LocalDate.now()
|
|
||||||
.atStartOfDay(ZoneId.systemDefault())
|
|
||||||
.toInstant());
|
|
||||||
final Date expireDate = Date.from(LocalDate.now()
|
|
||||||
.plusDays(15)
|
|
||||||
.atStartOfDay(ZoneId.systemDefault())
|
|
||||||
.toInstant());
|
|
||||||
return JWT.create()
|
|
||||||
.withIssuer(ISSUER)
|
|
||||||
.withIssuedAt(issueDate)
|
|
||||||
.withExpiresAt(expireDate)
|
|
||||||
.withSubject(login)
|
|
||||||
.sign(algorithm);
|
|
||||||
}
|
|
||||||
|
|
||||||
private DecodedJWT validateToken(String token) {
|
|
||||||
try {
|
|
||||||
return verifier.verify(token);
|
|
||||||
} catch (JWTVerificationException e) {
|
|
||||||
throw new JwtException(String.format("Token verification error: %s", e.getMessage()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isTokenValid(String token) {
|
|
||||||
if (!StringUtils.hasText(token)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
validateToken(token);
|
|
||||||
return true;
|
|
||||||
} catch (JwtException e) {
|
|
||||||
log.error(e.getMessage());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Optional<String> getLoginFromToken(String token) {
|
|
||||||
try {
|
|
||||||
return Optional.ofNullable(validateToken(token).getSubject());
|
|
||||||
} catch (JwtException e) {
|
|
||||||
log.error(e.getMessage());
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,89 +0,0 @@
|
|||||||
package com.ip.library.core.security;
|
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.http.HttpMethod;
|
|
||||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
|
||||||
import org.springframework.security.config.Customizer;
|
|
||||||
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.configurers.AbstractHttpConfigurer;
|
|
||||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer.FrameOptionsConfig;
|
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
import org.springframework.web.cors.CorsConfiguration;
|
|
||||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
|
||||||
import org.springframework.web.filter.CorsFilter;
|
|
||||||
|
|
||||||
import com.ip.library.controllers.users.UserRole;
|
|
||||||
import com.ip.library.controllers.users.UserService;
|
|
||||||
import com.ip.library.core.configuration.Constants;
|
|
||||||
import com.ip.library.core.error.AdviceController;
|
|
||||||
import com.ip.library.core.jwt.JwtFilter;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@EnableWebSecurity
|
|
||||||
@EnableMethodSecurity(securedEnabled = true)
|
|
||||||
public class SecurityConfiguration {
|
|
||||||
@Bean
|
|
||||||
SecurityFilterChain filterChain(
|
|
||||||
HttpSecurity httpSecurity,
|
|
||||||
UserService userService,
|
|
||||||
AdviceController adviceController) throws Exception {
|
|
||||||
httpSecurity.headers(headers -> headers.frameOptions(FrameOptionsConfig::sameOrigin));
|
|
||||||
httpSecurity.csrf(AbstractHttpConfigurer::disable);
|
|
||||||
httpSecurity.cors(Customizer.withDefaults());
|
|
||||||
httpSecurity.sessionManagement(sessionManagement -> sessionManagement
|
|
||||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
|
|
||||||
|
|
||||||
httpSecurity.authorizeHttpRequests(requests -> requests
|
|
||||||
.requestMatchers("/swagger-ui/**", "/v3/api-docs/**", "/swagger-ui.html")
|
|
||||||
.permitAll());
|
|
||||||
|
|
||||||
httpSecurity.authorizeHttpRequests(requests -> requests
|
|
||||||
.requestMatchers("/h2-console/**").hasRole(UserRole.ADMIN.name())
|
|
||||||
.requestMatchers(HttpMethod.POST, Constants.SIGNUP_URL).anonymous()
|
|
||||||
.requestMatchers(HttpMethod.POST, Constants.LOGIN_URL).anonymous()
|
|
||||||
.anyRequest().authenticated());
|
|
||||||
|
|
||||||
httpSecurity.exceptionHandling(exceptionHandling -> exceptionHandling
|
|
||||||
.authenticationEntryPoint(adviceController));
|
|
||||||
|
|
||||||
httpSecurity.addFilterBefore(new JwtFilter(userService), UsernamePasswordAuthenticationFilter.class);
|
|
||||||
|
|
||||||
return httpSecurity.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
DaoAuthenticationProvider authenticationProvider(UserDetailsService userDetailsService) {
|
|
||||||
final DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
|
|
||||||
authProvider.setUserDetailsService(userDetailsService);
|
|
||||||
authProvider.setPasswordEncoder(passwordEncoder());
|
|
||||||
return authProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
PasswordEncoder passwordEncoder() {
|
|
||||||
return new BCryptPasswordEncoder();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
CorsFilter corsFilter() {
|
|
||||||
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
|
||||||
final CorsConfiguration config = new CorsConfiguration();
|
|
||||||
if (!CollectionUtils.isEmpty(config.getAllowedOrigins())
|
|
||||||
|| !CollectionUtils.isEmpty(config.getAllowedOriginPatterns())) {
|
|
||||||
source.registerCorsConfiguration(Constants.API_URL + "/**", config);
|
|
||||||
source.registerCorsConfiguration("/v3/api-docs", config);
|
|
||||||
source.registerCorsConfiguration("/swagger-ui/**", config);
|
|
||||||
}
|
|
||||||
return new CorsFilter(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
package com.ip.library.core.security;
|
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
|
|
||||||
import io.swagger.v3.oas.models.Components;
|
|
||||||
import io.swagger.v3.oas.models.OpenAPI;
|
|
||||||
import io.swagger.v3.oas.models.security.SecurityRequirement;
|
|
||||||
import io.swagger.v3.oas.models.security.SecurityScheme;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@OpenAPIDefinition
|
|
||||||
public class SwaggerConfiguration {
|
|
||||||
private static final String SCHEME_NAME = "JWT";
|
|
||||||
private static final String SCHEME = "bearer";
|
|
||||||
|
|
||||||
private SecurityScheme createBearerScheme() {
|
|
||||||
return new SecurityScheme()
|
|
||||||
.type(SecurityScheme.Type.HTTP)
|
|
||||||
.scheme(SCHEME);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
OpenAPI customOpenApi() {
|
|
||||||
return new OpenAPI()
|
|
||||||
.components(new Components()
|
|
||||||
.addSecuritySchemes(SCHEME_NAME, createBearerScheme()))
|
|
||||||
.addSecurityItem(new SecurityRequirement().addList(SCHEME_NAME));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
package com.ip.library.core.security;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
|
||||||
|
|
||||||
import com.ip.library.controllers.users.UserEntity;
|
|
||||||
|
|
||||||
public class UserPrincipal implements UserDetails {
|
|
||||||
private final long id;
|
|
||||||
private final String username;
|
|
||||||
private final String password;
|
|
||||||
private final Set<? extends GrantedAuthority> roles;
|
|
||||||
private final boolean active;
|
|
||||||
|
|
||||||
public UserPrincipal(UserEntity user) {
|
|
||||||
this.id = user.getId();
|
|
||||||
this.username = user.getLogin();
|
|
||||||
this.password = user.getPassword();
|
|
||||||
this.roles = Set.of(user.getRole());
|
|
||||||
this.active = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUsername() {
|
|
||||||
return username;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getPassword() {
|
|
||||||
return password;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
|
||||||
return roles;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled() {
|
|
||||||
return active;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAccountNonExpired() {
|
|
||||||
return isEnabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAccountNonLocked() {
|
|
||||||
return isEnabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCredentialsNonExpired() {
|
|
||||||
return isEnabled();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +1,9 @@
|
|||||||
package com.ip.library.controllers.favorites;
|
package com.ip.library.favorites.model;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import com.ip.library.controllers.books.BookEntity;
|
import com.ip.library.books.model.BookEntity;
|
||||||
import com.ip.library.controllers.users.UserEntity;
|
import com.ip.library.users.model.UserEntity;
|
||||||
|
|
||||||
import jakarta.persistence.EmbeddedId;
|
import jakarta.persistence.EmbeddedId;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
@ -1,4 +1,4 @@
|
|||||||
package com.ip.library.controllers.favorites;
|
package com.ip.library.favorites.model;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
@ -1,9 +1,8 @@
|
|||||||
package com.ip.library.controllers.types;
|
package com.ip.library.types.api;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.modelmapper.ModelMapper;
|
import org.modelmapper.ModelMapper;
|
||||||
import org.springframework.security.access.annotation.Secured;
|
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
@ -13,13 +12,13 @@ import org.springframework.web.bind.annotation.RequestBody;
|
|||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import com.ip.library.controllers.users.UserRole;
|
|
||||||
import com.ip.library.core.configuration.Constants;
|
import com.ip.library.core.configuration.Constants;
|
||||||
|
import com.ip.library.types.model.TypeEntity;
|
||||||
|
import com.ip.library.types.service.TypeService;
|
||||||
|
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@Secured(value = UserRole.Secured.ADMIN)
|
|
||||||
@RequestMapping(Constants.API_URL + "/type")
|
@RequestMapping(Constants.API_URL + "/type")
|
||||||
public class TypeController {
|
public class TypeController {
|
||||||
private final TypeService typeService;
|
private final TypeService typeService;
|
@ -1,4 +1,4 @@
|
|||||||
package com.ip.library.controllers.types;
|
package com.ip.library.types.api;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package com.ip.library.controllers.types;
|
package com.ip.library.types.model;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
@ -1,9 +1,11 @@
|
|||||||
package com.ip.library.controllers.types;
|
package com.ip.library.types.repository;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.springframework.data.repository.CrudRepository;
|
import org.springframework.data.repository.CrudRepository;
|
||||||
|
|
||||||
|
import com.ip.library.types.model.TypeEntity;
|
||||||
|
|
||||||
public interface TypeRepository extends CrudRepository<TypeEntity, Long> {
|
public interface TypeRepository extends CrudRepository<TypeEntity, Long> {
|
||||||
Optional<TypeEntity> findByNameIgnoreCase(String name);
|
Optional<TypeEntity> findByNameIgnoreCase(String name);
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package com.ip.library.controllers.types;
|
package com.ip.library.types.service;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.StreamSupport;
|
import java.util.stream.StreamSupport;
|
||||||
@ -7,6 +7,8 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import com.ip.library.core.error.NotFoundException;
|
import com.ip.library.core.error.NotFoundException;
|
||||||
|
import com.ip.library.types.model.TypeEntity;
|
||||||
|
import com.ip.library.types.repository.TypeRepository;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class TypeService {
|
public class TypeService {
|
@ -1,7 +1,8 @@
|
|||||||
package com.ip.library.controllers.users;
|
package com.ip.library.users.api;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.modelmapper.ModelMapper;
|
import org.modelmapper.ModelMapper;
|
||||||
import org.springframework.security.access.annotation.Secured;
|
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
@ -12,25 +13,32 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import com.ip.library.books.api.BookDto;
|
||||||
|
import com.ip.library.books.model.BookEntity;
|
||||||
import com.ip.library.core.api.PageDto;
|
import com.ip.library.core.api.PageDto;
|
||||||
import com.ip.library.core.api.PageDtoMapper;
|
import com.ip.library.core.api.PageDtoMapper;
|
||||||
import com.ip.library.core.configuration.Constants;
|
import com.ip.library.core.configuration.Constants;
|
||||||
|
import com.ip.library.users.model.UserEntity;
|
||||||
|
import com.ip.library.users.service.UserService;
|
||||||
|
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@Secured(value = UserRole.Secured.ADMIN)
|
|
||||||
@RequestMapping(Constants.API_URL + "/user")
|
@RequestMapping(Constants.API_URL + "/user")
|
||||||
public class UserController {
|
public class UserController {
|
||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
private final ModelMapper modelMapper;
|
private final ModelMapper modelMapper;
|
||||||
|
|
||||||
public UserController(
|
public UserController(UserService userService, ModelMapper modelMapper) {
|
||||||
UserService userService,
|
|
||||||
ModelMapper modelMapper) {
|
|
||||||
this.userService = userService;
|
this.userService = userService;
|
||||||
this.modelMapper = modelMapper;
|
this.modelMapper = modelMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BookDto toBookDto (BookEntity entity) {
|
||||||
|
BookDto bookDto = modelMapper.map(entity, BookDto.class);
|
||||||
|
bookDto.setAuthorId(entity.getAuthorsBooks().stream().map(x -> x.getAuthor().getId()).toList());
|
||||||
|
return bookDto;
|
||||||
|
}
|
||||||
|
|
||||||
private UserDto toUserDto(UserEntity entity) {
|
private UserDto toUserDto(UserEntity entity) {
|
||||||
return modelMapper.map(entity, UserDto.class);
|
return modelMapper.map(entity, UserDto.class);
|
||||||
@ -42,8 +50,8 @@ public class UserController {
|
|||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public PageDto<UserDto> getAll(
|
public PageDto<UserDto> getAll(
|
||||||
@RequestParam(name = "page", defaultValue = "0") int page,
|
@RequestParam(name = "page", defaultValue = "0") int page,
|
||||||
@RequestParam(name = "size", defaultValue = Constants.DEFAULT_PAGE_SIZE) int size) {
|
@RequestParam(name = "size", defaultValue = Constants.DEFAULT_PAGE_SIZE) int size) {
|
||||||
return PageDtoMapper.toDto(userService.getAll(page, size), this::toUserDto);
|
return PageDtoMapper.toDto(userService.getAll(page, size), this::toUserDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,4 +79,26 @@ public class UserController {
|
|||||||
public UserDto changePassword(@PathVariable(name = "id") Long id, @RequestBody String newPassword) {
|
public UserDto changePassword(@PathVariable(name = "id") Long id, @RequestBody String newPassword) {
|
||||||
return toUserDto(userService.changePassword(id, newPassword));
|
return toUserDto(userService.changePassword(id, newPassword));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{userId}/books/{bookId}")
|
||||||
|
public boolean removeFavorite(
|
||||||
|
@PathVariable(name = "userId") Long userId,
|
||||||
|
@PathVariable(name = "bookId") Long bookId) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{userId}/books/{bookId}")
|
||||||
|
public boolean addFavorite(
|
||||||
|
@PathVariable(name = "userId") Long userId,
|
||||||
|
@PathVariable(name = "bookId") Long bookId) {
|
||||||
|
return userService.addFavorite(userId, bookId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{userId}/books")
|
||||||
|
public List<BookDto> getUserFavorites(
|
||||||
|
@PathVariable(name = "userId") Long userId,
|
||||||
|
@RequestParam(name = "page", defaultValue = "0") int page,
|
||||||
|
@RequestParam(name = "size", defaultValue = Constants.DEFAULT_PAGE_SIZE) int size) {
|
||||||
|
return userService.getUserFavorities(userId, page, size).stream().map(this::toBookDto).toList();
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package com.ip.library.controllers.users;
|
package com.ip.library.users.api;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
@ -11,6 +11,14 @@ public class UserDto {
|
|||||||
@NotBlank
|
@NotBlank
|
||||||
@Size(min = 5, max = 20)
|
@Size(min = 5, max = 20)
|
||||||
private String login;
|
private String login;
|
||||||
|
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||||
|
@NotBlank
|
||||||
|
@Size(min = 5, max = 20)
|
||||||
|
private String password;
|
||||||
|
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||||
|
@NotBlank
|
||||||
|
@Size(min = 4, max = 20)
|
||||||
|
private String role;
|
||||||
|
|
||||||
public Long getId() {
|
public Long getId() {
|
||||||
return id;
|
return id;
|
||||||
@ -27,4 +35,20 @@ public class UserDto {
|
|||||||
public void setLogin(String name) {
|
public void setLogin(String name) {
|
||||||
this.login = name;
|
this.login = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRole() {
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRole(String role) {
|
||||||
|
this.role = role;
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,12 +1,12 @@
|
|||||||
package com.ip.library.controllers.users;
|
package com.ip.library.users.model;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import com.ip.library.controllers.books.BookEntity;
|
import com.ip.library.books.model.BookEntity;
|
||||||
import com.ip.library.controllers.favorites.FavoriteEntity;
|
|
||||||
import com.ip.library.core.model.BaseEntity;
|
import com.ip.library.core.model.BaseEntity;
|
||||||
|
import com.ip.library.favorites.model.FavoriteEntity;
|
||||||
|
|
||||||
import jakarta.persistence.CascadeType;
|
import jakarta.persistence.CascadeType;
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
@ -20,9 +20,10 @@ import jakarta.persistence.Table;
|
|||||||
public class UserEntity extends BaseEntity {
|
public class UserEntity extends BaseEntity {
|
||||||
@Column(nullable = false, unique = true, length = 20)
|
@Column(nullable = false, unique = true, length = 20)
|
||||||
private String login;
|
private String login;
|
||||||
@Column(nullable = false, unique = false)
|
@Column(nullable = false, unique = false, length = 20)
|
||||||
private String password;
|
private String password;
|
||||||
private UserRole role = UserRole.USER;
|
@Column(nullable = false, unique = false, length = 20)
|
||||||
|
private String role = "user";
|
||||||
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
|
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||||
@OrderBy("id ASC")
|
@OrderBy("id ASC")
|
||||||
private Set<FavoriteEntity> favorites = new HashSet<>();
|
private Set<FavoriteEntity> favorites = new HashSet<>();
|
||||||
@ -56,11 +57,11 @@ public class UserEntity extends BaseEntity {
|
|||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserRole getRole() {
|
public String getRole() {
|
||||||
return role;
|
return role;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRole(UserRole role) {
|
public void setRole(String role) {
|
||||||
this.role = role;
|
this.role = role;
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package com.ip.library.controllers.users;
|
package com.ip.library.users.repository;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -9,7 +9,8 @@ import org.springframework.data.jpa.repository.Query;
|
|||||||
import org.springframework.data.repository.CrudRepository;
|
import org.springframework.data.repository.CrudRepository;
|
||||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||||
|
|
||||||
import com.ip.library.controllers.books.BookEntity;
|
import com.ip.library.books.model.BookEntity;
|
||||||
|
import com.ip.library.users.model.UserEntity;
|
||||||
|
|
||||||
public interface UserRepository extends
|
public interface UserRepository extends
|
||||||
CrudRepository<UserEntity, Long>,
|
CrudRepository<UserEntity, Long>,
|
@ -1,43 +1,27 @@
|
|||||||
package com.ip.library.controllers.users;
|
package com.ip.library.users.service;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.stream.StreamSupport;
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
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.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import com.ip.library.controllers.books.BookEntity;
|
import com.ip.library.books.model.BookEntity;
|
||||||
import com.ip.library.controllers.books.BookService;
|
import com.ip.library.books.service.BookService;
|
||||||
import com.ip.library.core.configuration.Constants;
|
|
||||||
import com.ip.library.core.error.NotFoundException;
|
import com.ip.library.core.error.NotFoundException;
|
||||||
import com.ip.library.core.jwt.JwtException;
|
import com.ip.library.users.model.UserEntity;
|
||||||
import com.ip.library.core.jwt.JwtProvider;
|
import com.ip.library.users.repository.UserRepository;
|
||||||
import com.ip.library.core.security.UserPrincipal;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class UserService implements UserDetailsService{
|
public class UserService {
|
||||||
private final UserRepository repository;
|
private final UserRepository repository;
|
||||||
private final BookService bookService;
|
private final BookService bookService;
|
||||||
private final PasswordEncoder passwordEncoder;
|
|
||||||
private final JwtProvider jwtProvider;
|
|
||||||
|
|
||||||
public UserService(
|
public UserService(UserRepository repository, BookService bookService) {
|
||||||
UserRepository repository,
|
|
||||||
BookService bookService,
|
|
||||||
PasswordEncoder passwordEncoder,
|
|
||||||
JwtProvider jwtProvider) {
|
|
||||||
this.repository = repository;
|
this.repository = repository;
|
||||||
this.bookService = bookService;
|
this.bookService = bookService;
|
||||||
this.jwtProvider = jwtProvider;
|
|
||||||
this.passwordEncoder = passwordEncoder;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkLoginUniqueness(String name){
|
private void checkLoginUniqueness(String name){
|
||||||
@ -64,24 +48,9 @@ public class UserService implements UserDetailsService{
|
|||||||
.orElseThrow(() -> new NotFoundException(UserEntity.class, id));
|
.orElseThrow(() -> new NotFoundException(UserEntity.class, id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(readOnly = true)
|
|
||||||
public UserEntity getByLogin(String login) {
|
|
||||||
return repository.findByLoginIgnoreCase(login)
|
|
||||||
.orElseThrow(() -> new IllegalArgumentException("Invalid login"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public UserEntity create(UserEntity entity) {
|
public UserEntity create(UserEntity entity) {
|
||||||
if (entity == null)
|
|
||||||
throw new IllegalArgumentException("Entity is null");
|
|
||||||
if (entity.getPassword() == null)
|
|
||||||
throw new IllegalArgumentException("Entity.GetPassword is null");
|
|
||||||
checkLoginUniqueness(entity.getLogin());
|
checkLoginUniqueness(entity.getLogin());
|
||||||
final String password = Optional.ofNullable(entity.getPassword()).orElse("");
|
|
||||||
entity.setPassword(
|
|
||||||
passwordEncoder.encode(
|
|
||||||
StringUtils.hasText(password.strip()) ? password : Constants.DEFAULT_PASSWORD));
|
|
||||||
entity.setRole(Optional.ofNullable(entity.getRole()).orElse(UserRole.USER));
|
|
||||||
return repository.save(entity);
|
return repository.save(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,14 +72,14 @@ public class UserService implements UserDetailsService{
|
|||||||
@Transactional
|
@Transactional
|
||||||
public UserEntity giveAdminRole(long id) {
|
public UserEntity giveAdminRole(long id) {
|
||||||
final UserEntity existsEntity = get(id);
|
final UserEntity existsEntity = get(id);
|
||||||
existsEntity.setRole(UserRole.ADMIN);
|
existsEntity.setRole("admin");
|
||||||
return repository.save(existsEntity);
|
return repository.save(existsEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public UserEntity giveUserRole(long id) {
|
public UserEntity giveUserRole(long id) {
|
||||||
final UserEntity existsEntity = get(id);
|
final UserEntity existsEntity = get(id);
|
||||||
existsEntity.setRole(UserRole.USER);
|
existsEntity.setRole("user");
|
||||||
return repository.save(existsEntity);
|
return repository.save(existsEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,29 +106,4 @@ public class UserService implements UserDetailsService{
|
|||||||
public Page<BookEntity> getUserFavorities (long userId, int page, int size) {
|
public Page<BookEntity> getUserFavorities (long userId, int page, int size) {
|
||||||
return repository.getUserFavorities(userId, PageRequest.of(page, size));
|
return repository.getUserFavorities(userId, PageRequest.of(page, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(readOnly = true)
|
|
||||||
public UserDetails getByToken(String token) {
|
|
||||||
if (!jwtProvider.isTokenValid(token))
|
|
||||||
throw new JwtException("Bad token");
|
|
||||||
final String userLogin = jwtProvider.getLoginFromToken(token)
|
|
||||||
.orElseThrow(() -> new JwtException("Token is not contain Login"));
|
|
||||||
return loadUserByUsername(userLogin);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Transactional(readOnly = true)
|
|
||||||
public String login(String login, String password) {
|
|
||||||
final UserEntity existsUser = getByLogin(login);
|
|
||||||
if (!passwordEncoder.matches(password, existsUser.getPassword()))
|
|
||||||
throw new IllegalArgumentException("Invalid login");
|
|
||||||
return jwtProvider.generateToken(existsUser.getLogin());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(readOnly = true)
|
|
||||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
|
||||||
final UserEntity existsUser = getByLogin(username);
|
|
||||||
return new UserPrincipal(existsUser);
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -8,9 +8,9 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.dao.DataIntegrityViolationException;
|
import org.springframework.dao.DataIntegrityViolationException;
|
||||||
|
|
||||||
import com.ip.library.controllers.authors.AuthorEntity;
|
|
||||||
import com.ip.library.controllers.authors.AuthorService;
|
|
||||||
import com.ip.library.core.error.NotFoundException;
|
import com.ip.library.core.error.NotFoundException;
|
||||||
|
import com.ip.library.authors.model.AuthorEntity;
|
||||||
|
import com.ip.library.authors.service.AuthorService;
|
||||||
|
|
||||||
@SpringBootTest
|
@SpringBootTest
|
||||||
class AuthorsTests {
|
class AuthorsTests {
|
||||||
|
@ -11,12 +11,12 @@ import org.springframework.boot.test.context.SpringBootTest;
|
|||||||
import org.springframework.dao.DataIntegrityViolationException;
|
import org.springframework.dao.DataIntegrityViolationException;
|
||||||
|
|
||||||
import com.ip.library.core.error.NotFoundException;
|
import com.ip.library.core.error.NotFoundException;
|
||||||
import com.ip.library.controllers.authors.AuthorEntity;
|
import com.ip.library.types.model.TypeEntity;
|
||||||
import com.ip.library.controllers.authors.AuthorService;
|
import com.ip.library.types.service.TypeService;
|
||||||
import com.ip.library.controllers.books.BookEntity;
|
import com.ip.library.authors.model.AuthorEntity;
|
||||||
import com.ip.library.controllers.books.BookService;
|
import com.ip.library.authors.service.AuthorService;
|
||||||
import com.ip.library.controllers.types.TypeEntity;
|
import com.ip.library.books.model.BookEntity;
|
||||||
import com.ip.library.controllers.types.TypeService;
|
import com.ip.library.books.service.BookService;
|
||||||
|
|
||||||
@SpringBootTest
|
@SpringBootTest
|
||||||
class BooksTests {
|
class BooksTests {
|
||||||
|
@ -9,12 +9,12 @@ import org.junit.jupiter.api.Test;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
import com.ip.library.controllers.books.BookEntity;
|
import com.ip.library.books.model.BookEntity;
|
||||||
import com.ip.library.controllers.books.BookService;
|
import com.ip.library.books.service.BookService;
|
||||||
import com.ip.library.controllers.types.TypeEntity;
|
import com.ip.library.types.model.TypeEntity;
|
||||||
import com.ip.library.controllers.types.TypeService;
|
import com.ip.library.types.service.TypeService;
|
||||||
import com.ip.library.controllers.users.UserEntity;
|
import com.ip.library.users.model.UserEntity;
|
||||||
import com.ip.library.controllers.users.UserService;
|
import com.ip.library.users.service.UserService;
|
||||||
|
|
||||||
@SpringBootTest
|
@SpringBootTest
|
||||||
class FavoritesTests {
|
class FavoritesTests {
|
||||||
|
@ -8,9 +8,9 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.dao.DataIntegrityViolationException;
|
import org.springframework.dao.DataIntegrityViolationException;
|
||||||
|
|
||||||
import com.ip.library.controllers.types.TypeEntity;
|
|
||||||
import com.ip.library.controllers.types.TypeService;
|
|
||||||
import com.ip.library.core.error.NotFoundException;
|
import com.ip.library.core.error.NotFoundException;
|
||||||
|
import com.ip.library.types.model.TypeEntity;
|
||||||
|
import com.ip.library.types.service.TypeService;
|
||||||
|
|
||||||
@SpringBootTest
|
@SpringBootTest
|
||||||
class TypesTests {
|
class TypesTests {
|
||||||
|
@ -7,19 +7,15 @@ import org.junit.jupiter.api.Test;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.dao.DataIntegrityViolationException;
|
import org.springframework.dao.DataIntegrityViolationException;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
||||||
|
|
||||||
import com.ip.library.controllers.users.UserEntity;
|
|
||||||
import com.ip.library.controllers.users.UserRole;
|
|
||||||
import com.ip.library.controllers.users.UserService;
|
|
||||||
import com.ip.library.core.error.NotFoundException;
|
import com.ip.library.core.error.NotFoundException;
|
||||||
|
import com.ip.library.users.model.UserEntity;
|
||||||
|
import com.ip.library.users.service.UserService;
|
||||||
|
|
||||||
@SpringBootTest
|
@SpringBootTest
|
||||||
class UsersTests {
|
class UsersTests {
|
||||||
@Autowired
|
@Autowired
|
||||||
private UserService userService;
|
private UserService userService;
|
||||||
@Autowired
|
|
||||||
private PasswordEncoder passwordEncoder;
|
|
||||||
private UserEntity user;
|
private UserEntity user;
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
@ -39,8 +35,8 @@ class UsersTests {
|
|||||||
void createTest() {
|
void createTest() {
|
||||||
Assertions.assertEquals(3, userService.getAll().size());
|
Assertions.assertEquals(3, userService.getAll().size());
|
||||||
Assertions.assertEquals("user3", user.getLogin());
|
Assertions.assertEquals("user3", user.getLogin());
|
||||||
Assertions.assertTrue(passwordEncoder.matches("aqw2sed45", user.getPassword()));
|
Assertions.assertEquals("aqw2sed45", user.getPassword());
|
||||||
Assertions.assertEquals(UserRole.USER, user.getRole());
|
Assertions.assertEquals("user", user.getRole());
|
||||||
Assertions.assertEquals(0, user.getFavorites().size());
|
Assertions.assertEquals(0, user.getFavorites().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,11 +79,11 @@ class UsersTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void changeRoleTest() {
|
void changeRoleTest() {
|
||||||
Assertions.assertEquals(UserRole.USER, user.getRole());
|
Assertions.assertEquals("user", user.getRole());
|
||||||
user = userService.giveAdminRole(user.getId());
|
user = userService.giveAdminRole(user.getId());
|
||||||
Assertions.assertEquals(UserRole.ADMIN, user.getRole());
|
Assertions.assertEquals("admin", user.getRole());
|
||||||
user = userService.giveUserRole(user.getId());
|
user = userService.giveUserRole(user.getId());
|
||||||
Assertions.assertEquals(UserRole.USER, user.getRole());
|
Assertions.assertEquals("user", user.getRole());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -105,7 +101,7 @@ class UsersTests {
|
|||||||
@Test
|
@Test
|
||||||
void nullPasswordTest() {
|
void nullPasswordTest() {
|
||||||
Assertions.assertThrows(
|
Assertions.assertThrows(
|
||||||
IllegalArgumentException.class,
|
DataIntegrityViolationException.class,
|
||||||
() -> userService.create(new UserEntity(user.getLogin() + "TEST", null))
|
() -> userService.create(new UserEntity(user.getLogin() + "TEST", null))
|
||||||
);
|
);
|
||||||
Assertions.assertThrows(
|
Assertions.assertThrows(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user