This commit is contained in:
1yuee 2023-06-19 20:32:05 +04:00
parent 4a64a94660
commit fcf22c2a4d
15 changed files with 590 additions and 3872 deletions

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,8 @@
package com.webproglabs.lab1;
import com.webproglabs.lab1.lab34.model.enums.UserRole;
import com.webproglabs.lab1.lab34.mvc.UserSignUpMvcController;
import com.webproglabs.lab1.lab34.services.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
@ -29,47 +32,47 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final Logger log = LoggerFactory.getLogger(SecurityConfiguration.class);
private static final String LOGIN_URL = "/login";
public static final String SPA_URL_MASK = "/{path:[^\\.]*}";
// private final ProfileService userService;
//
// public SecurityConfiguration(ProfileService userService) {
// this.userService = userService;
// createAdminOnStartup();
// }
private final UserService userService;
// private void createAdminOnStartup() {
// final String admin = "admin";
// if (userService.findByLogin(admin) == null) {
// log.info("Admin user successfully created");
// try {
// userService.createUser(admin, admin, admin, UserRole.ADMIN);
// } catch (Exception e) {
// throw new RuntimeException(e);
// }
// }
// }
public SecurityConfiguration(UserService userService) {
this.userService = userService;
createAdminOnStartup();
}
// @Override
// protected void configure(HttpSecurity http) throws Exception {
//
// http.exceptionHandling().authenticationEntryPoint(delegatingEntryPoint());
// http.headers().frameOptions().sameOrigin().and()
// .cors().and()
// .csrf().disable()
// .authorizeRequests()
// .antMatchers(UserSignupMvcController.SIGNUP_URL).permitAll()
// .antMatchers(HttpMethod.GET, LOGIN_URL).permitAll()
// .anyRequest().authenticated()
// .and()
// .formLogin()
// .loginPage(LOGIN_URL).permitAll()
// .and()
// .logout().permitAll();
// }
private void createAdminOnStartup() {
final String admin = "admin";
if (userService.findUserByLogin(admin) == null) {
log.info("Admin user successfully created");
try {
userService.createUser(admin, admin, admin, UserRole.ADMIN);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
// @Override
// protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// auth.userDetailsService(userService);
// }
@Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling().authenticationEntryPoint(delegatingEntryPoint());
http.headers().frameOptions().sameOrigin().and()
.cors().and()
.csrf().disable()
.authorizeRequests()
.antMatchers(UserSignUpMvcController.SIGNUP_URL).permitAll()
.antMatchers(HttpMethod.GET, LOGIN_URL).permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage(LOGIN_URL).permitAll()
.and()
.logout().permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
}
@Override
public void configure(WebSecurity web) {

View File

@ -8,10 +8,10 @@ public class UserSignUpDto {
@Size(min = 3, max = 64)
private String login;
@NotBlank
@Size(min = 6, max = 64)
@Size(min = 4, max = 64)
private String password;
@NotBlank
@Size(min = 6, max = 64)
@Size(min = 4, max = 64)
private String passwordConfirm;
public String getLogin() {

View File

@ -16,14 +16,14 @@ public class User {
@GeneratedValue(strategy = GenerationType.AUTO)
private Long Id;
@Column(nullable = false, unique = true, length = 64)
@Column(nullable = false, unique = true, length = 1024)
@NotBlank
@Size(min = 3, max = 32)
@Size(min = 4, max = 64)
private String login;
@Column(nullable = false, length = 64)
@Column(nullable = false, length = 1024)
@NotBlank
@Size(min = 6, max = 32)
@Size(min = 4, max = 64)
private String Password;
@ManyToMany(mappedBy = "Users")

View File

@ -0,0 +1,48 @@
package com.webproglabs.lab1.lab34.mvc;
import com.webproglabs.lab1.lab34.dto.UserSignUpDto;
import com.webproglabs.lab1.lab34.model.User;
import com.webproglabs.lab1.lab34.services.UserService;
import javax.validation.Valid;
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;
@Controller
@RequestMapping(UserSignUpMvcController.SIGNUP_URL)
public class UserSignUpMvcController {
public static final String SIGNUP_URL = "/signup";
private final UserService UserService;
public UserSignUpMvcController(UserService userService) {
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 NewUser = UserService.createUser(userSignupDto.getLogin(), userSignupDto.getPassword(), userSignupDto.getPasswordConfirm());
return "redirect:/login?created=" + NewUser.getLogin();
} catch (Exception e) {
model.addAttribute("errors", e.getMessage());
return "signup";
}
}
}

View File

@ -0,0 +1,86 @@
package com.webproglabs.lab1.lab34.services;
import javax.persistence.EntityNotFoundException;
import javax.transaction.Transactional;
import com.webproglabs.lab1.lab34.model.Category;
import com.webproglabs.lab1.lab34.model.Product;
import com.webproglabs.lab1.lab34.repository.CategoryRepository;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.List;
@Service
public class CategoryService {
private final CategoryRepository CategoryRepository;
public CategoryService(CategoryRepository CategoryRepository) {
this.CategoryRepository = CategoryRepository;
}
@Transactional
public Category addCategory(String Name) {
if (!StringUtils.hasText(Name)) {
throw new IllegalArgumentException("Name is null or empty");
}
final Category Category = new Category(Name);
CategoryRepository.save(Category);
return Category;
}
@Transactional
public Category findCategoryById(Long Id) {
final Category Category = CategoryRepository.findById(Id).orElse(null);
if (Category == null) {
throw new EntityNotFoundException(String.format(" Category with id [%s] is not found", Id));
}
return Category;
}
@Transactional
public List<Category> findAllCategories(){
return CategoryRepository.findAll();
}
@Transactional
public Category updateCategory(Long Id, String Name) {
if (!StringUtils.hasText(Name)) {
throw new IllegalArgumentException("Name is null or empty");
}
final Category CurrentCategory = findCategoryById(Id);
CurrentCategory.setName(Name);
return CategoryRepository.save(CurrentCategory);
}
@Transactional
public Category deleteCategory(Long Id) {
final Category CurrentCategory = findCategoryById(Id);
CategoryRepository.delete(CurrentCategory);
return CurrentCategory;
}
@Transactional
public void deleteAllCategories() {
CategoryRepository.deleteAll();
}
@Transactional
public Product addProductToCategory(Long Id, Product Product) {
// TODO возможно придется подключать репозиторий продуктов и там тоже сохранять
final Category CurrentCategory = findCategoryById(Id);
CurrentCategory.addProduct(Product);
CategoryRepository.save(CurrentCategory);
return Product;
}
@Transactional
public void removeProductFromCategory(Long Id, Product Product) {
// TODO возможно придется подключать репозиторий продуктов и там тоже сохранять
final Category CurrentCategory = findCategoryById(Id);
CurrentCategory.removeProduct(Product);
CategoryRepository.save(CurrentCategory);
}
}

View File

@ -0,0 +1,72 @@
package com.webproglabs.lab1.lab34.services;
import javax.persistence.EntityNotFoundException;
import javax.transaction.Transactional;
import com.webproglabs.lab1.lab34.model.Category;
import com.webproglabs.lab1.lab34.model.Product;
import com.webproglabs.lab1.lab34.model.Shop;
import com.webproglabs.lab1.lab34.repository.ProductRepository;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.List;
@Service
public class ProductService {
private final ProductRepository ProductRepository;
public ProductService(ProductRepository productRepository) {
ProductRepository = productRepository;
}
@Transactional
public Product addProduct(String Name, Double Cost, Shop Shop, Category Category) {
if (!StringUtils.hasText(Name) || Cost == null || Cost < 0 || Shop == null || Category == null) {
throw new IllegalArgumentException();
}
final Product NewProduct = new Product(Name, Cost, Shop, Category);
return ProductRepository.save(NewProduct);
}
@Transactional
public Product findProductById(Long Id) {
final Product CurrentProduct = ProductRepository.findById(Id).orElse(null);
if (CurrentProduct == null) {
throw new EntityNotFoundException(String.format(" Product with id [%s] is not found", Id));
}
return CurrentProduct;
}
@Transactional
public List<Product> findAllProducts() {
return ProductRepository.findAll();
}
@Transactional
public Product updateProduct(Long Id, String Name, Double Cost, Shop Shop, Category Category) {
final Product CurrentProduct = findProductById(Id);
if (!StringUtils.hasText(Name) || Cost == null || Cost < 0 || Shop == null || Category == null) {
throw new IllegalArgumentException();
}
CurrentProduct.setName(Name);
CurrentProduct.setCost(Cost);
CurrentProduct.setShop(Shop);
CurrentProduct.setCategory(Category);
return ProductRepository.save(CurrentProduct);
}
@Transactional
public Product deleteProduct(Long Id) {
final Product CurrentProduct = findProductById(Id);
ProductRepository.delete(CurrentProduct);
return CurrentProduct;
}
@Transactional
public void deleteAllProducts() {
ProductRepository.deleteAll();
}
}

View File

@ -0,0 +1,85 @@
package com.webproglabs.lab1.lab34.services;
import com.webproglabs.lab1.lab34.model.Product;
import com.webproglabs.lab1.lab34.model.Shop;
import com.webproglabs.lab1.lab34.repository.ShopRepository;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.persistence.EntityNotFoundException;
import javax.transaction.Transactional;
import java.util.List;
@Service
public class ShopService {
private final ShopRepository ShopRepository;
public ShopService(ShopRepository ShopRepository) {
this.ShopRepository = ShopRepository;
}
@Transactional
public Shop addShop(String Name) {
if (!StringUtils.hasText(Name)) {
throw new IllegalArgumentException("Name is null or empty");
}
final Shop Shop = new Shop(Name);
ShopRepository.save(Shop);
return Shop;
}
@Transactional
public Shop findShopById(Long Id) {
final Shop Shop = ShopRepository.findById(Id).orElse(null);
if (Shop == null) {
throw new EntityNotFoundException(String.format(" Shop with id [%s] is not found", Id));
}
return Shop;
}
@Transactional
public List<Shop> findAllShops(){
return ShopRepository.findAll();
}
@Transactional
public Shop updateShop(Long Id, String Name) {
if (!StringUtils.hasText(Name)) {
throw new IllegalArgumentException("Name is null or empty");
}
final Shop CurrentShop = findShopById(Id);
CurrentShop.setName(Name);
return ShopRepository.save(CurrentShop);
}
@Transactional
public Shop deleteShop(Long Id) {
final Shop CurrentShop = findShopById(Id);
ShopRepository.delete(CurrentShop);
return CurrentShop;
}
@Transactional
public void deleteAllShops() {
ShopRepository.deleteAll();
}
@Transactional
public Product addProductToShop(Long Id, Product Product) {
// TODO возможно придется подключать репозиторий продуктов и там тоже сохранять
final Shop CurrentShop = findShopById(Id);
CurrentShop.addProduct(Product);
ShopRepository.save(CurrentShop);
return Product;
}
@Transactional
public void removeProductFromShop(Long Id, Product Product) {
// TODO возможно придется подключать репозиторий продуктов и там тоже сохранять
final Shop CurrentShop = findShopById(Id);
CurrentShop.removeProduct(Product);
ShopRepository.save(CurrentShop);
}
}

View File

@ -0,0 +1,117 @@
package com.webproglabs.lab1.lab34.services;
import com.webproglabs.lab1.lab34.model.Product;
import com.webproglabs.lab1.lab34.model.User;
import com.webproglabs.lab1.lab34.model.enums.UserRole;
import com.webproglabs.lab1.lab34.repository.UserRepository;
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.util.StringUtils;
import javax.persistence.EntityNotFoundException;
import javax.transaction.Transactional;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@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;
}
@Transactional
public User findUserById(Long Id) {
User CurrentUser = UserRepository.findById(Id).orElse(null);
if (CurrentUser == null) {
throw new EntityNotFoundException(String.format(" User with id [%s] is not found", Id));
}
return CurrentUser;
}
@Transactional
public User findUserByLogin(String Login) {
if (!StringUtils.hasText(Login)) {
throw new IllegalArgumentException("Login is null or empty");
}
User CurrentUser = UserRepository.findOneByLoginIgnoreCase(Login).orElse(null);
return CurrentUser;
}
@Transactional
public List<User> findAllUsers() {
return UserRepository.findAll();
}
@Transactional
public User createUser(String Login, String Password, String PasswordConfirm) {
return createUser(Login, Password, PasswordConfirm, UserRole.USER);
}
@Transactional
public User createUser(String Login, String Password, String PasswordConfirm, UserRole Role) {
if (findUserByLogin(Login) != null) {
throw new IllegalArgumentException("User " + Login + " already exists");
}
if (!Objects.equals(Password, PasswordConfirm)) {
throw new IllegalArgumentException("Passwords not equals");
}
final User NewUser = new User(Login, PasswordEncoder.encode(Password), Role);
return UserRepository.save(NewUser);
}
@Transactional
public User updateUser(Long Id, String Login, String Password, UserRole Role) {
if (!StringUtils.hasText(Login) || !StringUtils.hasText(Password)) {
throw new IllegalArgumentException("User data is null or empty");
}
final User CurrentUser = findUserById(Id);
CurrentUser.setLogin(Login);
CurrentUser.setPassword(Password);
CurrentUser.setRole(Role);
return UserRepository.save(CurrentUser);
}
@Transactional
public User deleteUser(Long Id) {
final User CurrentUser = findUserById(Id);
UserRepository.delete(CurrentUser);
return CurrentUser;
}
@Transactional
public void deleteAllUsers(){
UserRepository.deleteAll();
}
@Transactional
public void addProductToUser(Long Id, Product Product) {
// TODO возможно придется подключать репозиторий продуктов и там тоже сохранять
final User CurrentUser = findUserById(Id);
CurrentUser.addProduct(Product);
UserRepository.save(CurrentUser);
}
@Transactional
public void removeProductFromUser(Long Id, Product Product) {
// TODO возможно придется подключать репозиторий продуктов и там тоже сохранять
final User CurrentUser = findUserById(Id);
CurrentUser.removeProduct(Product);
UserRepository.save(CurrentUser);
}
@Override
public UserDetails loadUserByUsername(String Login) throws UsernameNotFoundException {
final User UserEntity = findUserByLogin(Login);
return new org.springframework.security.core.userdetails.User(UserEntity.getLogin(), UserEntity.getPassword(), Collections.singleton(UserEntity.getRole()));
}
}

View File

@ -0,0 +1,13 @@
package com.webproglabs.lab1.lab34.validation;
import java.util.Set;
public class ValidationException extends RuntimeException {
public <T> ValidationException(Set<String> errors) {
super(String.join("\n", errors));
}
public <T> ValidationException(String error) {
super(error);
}
}

View File

@ -0,0 +1,27 @@
package com.webproglabs.lab1.lab34.validation;
import org.springframework.stereotype.Component;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.util.Set;
import java.util.stream.Collectors;
@Component
public class ValidatorUtil {
private final Validator validator;
public ValidatorUtil() {
this.validator = Validation.buildDefaultValidatorFactory().getValidator();
}
public <T> void validate(T object) {
final Set<ConstraintViolation<T>> errors = validator.validate(object);
if (!errors.isEmpty()) {
throw new ValidationException(errors.stream()
.map(ConstraintViolation::getMessage)
.collect(Collectors.toSet()));
}
}
}

View File

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html lang="ru"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
<meta charset="UTF-8"/>
<title>Магазин</title>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="icon" href="/favicon.svg">
<script type="text/javascript" src="/webjars/bootstrap/5.1.3/js/bootstrap.bundle.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<link rel="stylesheet" href="/webjars/bootstrap/5.1.3/css/bootstrap.min.css"/>
<link rel="stylesheet" href="/webjars/font-awesome/6.1.0/css/all.min.css"/>
<link rel="stylesheet" href="/css/style.css"/>
</head>
<body>
<div>
<p class='text-center m-3 h3'>Магазин</p>
</div>
<div>
<p class='h4 text-center'>
<a sec:authorize="hasRole('ROLE_ADMIN')" href="/profiles" class="text-decoration-none m-3">Профили</a>
<a sec:authorize="isAuthenticated()" href="/feed/" class="text-decoration-none m-3">Лента</a>
<a sec:authorize="isAuthenticated()" href="/logout" class="text-decoration-none m-3">
Выход
</a>
</p>
</div>
<div >
<div layout:fragment="content"></div>
</div>
</body>

View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<body>
<div class="container" layout:fragment="content">
<div th:if="${param.error}" class="alert alert-danger margin-bottom">
Пользователь не найден или пароль указан не верно
</div>
<div th:if="${param.logout}" class="alert alert-success margin-bottom">
Выход успешно произведен
</div>
<div th:if="${param.created}" class="alert alert-success margin-bottom">
Пользователь '<span th:text="${param.created}"></span>' успешно создан
</div>
<form th:action="@{/login}" method="post" class="container-padding">
<div class="mb-3">
<input type="text" name="username" id="username" class="form-control"
placeholder="Логин" required="true" autofocus="true"/>
</div>
<div class="mb-3">
<input type="password" name="password" id="password" class="form-control"
placeholder="Пароль" required="true"/>
</div>
<button type="submit" class="btn btn-success button-fixed">Войти</button>
<a class="btn btn-primary button-fixed" href="/signup">Регистрация</a>
</form>
</div>
</body>
</html>

View File

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<body>
<div class="container container-padding" layout:fragment="content">
<div th:if="${errors}" th:text="${errors}" class="margin-bottom alert alert-danger"></div>
<form action="#" th:action="@{/signup}" th:object="${userDto}" method="post">
<div class="mb-3">
<input type="text" class="form-control" th:field="${userDto.login}"
placeholder="Логин" required="true" autofocus="true" maxlength="64"/>
</div>
<div class="mb-3">
<input type="password" class="form-control" th:field="${userDto.password}"
placeholder="Пароль" required="true" minlength="4" maxlength="64"/>
</div>
<div class="mb-3">
<input type="password" class="form-control" th:field="${userDto.passwordConfirm}"
placeholder="Пароль (подтверждение)" required="true" minlength="4" maxlength="64"/>
</div>
<div class="mb-3">
<button type="submit" class="btn btn-success button-fixed">Создать</button>
<a class="btn btn-primary button-fixed" href="/login">Назад</a>
</div>
</form>
</div>
</body>
</html>