Compare commits

...

17 Commits

Author SHA1 Message Date
ec7e6812d6 Добавлен отчёт №6 2023-06-18 13:13:49 +04:00
abazov73
74766fecab Шестая лабораторная работа. Фикс вывода forbidden. 2023-05-16 10:19:24 +04:00
abazov73
1f69a7929e Шестая лабораторная работа. Фикс Post и Put запросов. 2023-05-16 01:32:23 +04:00
abazov73
02bc284ff1 Шестая лабораторная работа. Готово. 2023-05-16 01:25:06 +04:00
abazov73
4a6f146039 Шестая лабораторная работа. Аунтефикация в MVC + обработка токенов через JWT. 2023-05-15 22:32:53 +04:00
abazov73
f4e33caffe Пятая лабораторная работа. Готово. 2023-05-02 17:01:30 +04:00
abazov73
20af7ec707 Пятая лабораторная работа. Фикс ссылки на главную 2023-05-02 08:40:50 +04:00
abazov73
4a27990626 Пятая лабораторная работа. Начала работы с MVC + CustomerMVCController. 2023-05-02 01:29:14 +04:00
abazov73
d29a9a5e25 Четвёртая лабораторная работа. Фикс отбора товаров по признаку привязки к магазину. 2023-04-30 21:07:58 +04:00
abazov73
d652956ae9 Четвёртая лабораторная работа. Frontend. 2023-04-25 14:55:16 +04:00
abazov73
c6b23e8d96 Четвёртая лабораторная работа. Frontend без страниц для Order, Product, Store. 2023-04-25 11:52:45 +04:00
abazov73
5568a57217 Четвёртая лабораторная работа. Backend 2023-04-25 00:35:21 +04:00
abazov73
61813642af Третья лабораторная работа. Доп. задание 2023-04-11 14:42:54 +04:00
abazov73
c6dff060b0 Третья лабораторная работа. Фикс сервиса продукта + фикс установки связей OneToMany 2023-04-11 12:51:22 +04:00
abazov73
49195ca6b4 Третья лабораторная работа. Тесты. 2023-04-10 21:49:50 +04:00
abazov73
0f2260935c Третья лабораторная работа. 2023-04-10 19:39:05 +04:00
abazov73
4a7874a0a7 Вторая лабораторная работа. 2023-03-14 09:47:00 +04:00
117 changed files with 15171 additions and 162 deletions

View File

@ -1,6 +1,6 @@
plugins { plugins {
id 'java' id 'java'
id 'org.springframework.boot' version '3.0.2' id 'org.springframework.boot' version '3.0.1'
id 'io.spring.dependency-management' version '1.1.0' id 'io.spring.dependency-management' version '1.1.0'
} }
@ -14,7 +14,28 @@ repositories {
dependencies { dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'com.h2database:h2:2.1.210'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.6.5'
testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.hibernate.validator:hibernate-validator'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-devtools'
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'
implementation 'org.webjars:bootstrap:5.1.3'
implementation 'org.webjars:jquery:3.6.0'
implementation 'org.webjars:font-awesome:6.1.0'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
implementation 'com.auth0:java-jwt:4.4.0'
implementation group: 'io.jsonwebtoken', name: 'jjwt', version: '0.9.1'
implementation 'javax.xml.bind:jaxb-api:2.3.1'
} }
tasks.named('test') { tasks.named('test') {

BIN
backend/ipLab/data.mv.db Normal file

Binary file not shown.

5708
backend/ipLab/data.trace.db Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
package com.example.ipLab.StoreDataBase.Configurations;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class PasswordEncoderConfiguration {
@Bean
public PasswordEncoder createPasswordEncoder(){
return new BCryptPasswordEncoder();
}
}

View File

@ -0,0 +1,91 @@
package com.example.ipLab.StoreDataBase.Configurations;
import com.example.ipLab.StoreDataBase.Configurations.jwt.JwtFilter;
import com.example.ipLab.StoreDataBase.Controllers.UserController;
import com.example.ipLab.StoreDataBase.MVC.UserLoginMVCController;
import com.example.ipLab.StoreDataBase.Model.UserRole;
import com.example.ipLab.StoreDataBase.Service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(securedEnabled = true)
public class SecurityConfiguration {
private final Logger log = LoggerFactory.getLogger(SecurityConfiguration.class);
private static final String LOGIN_URL = "/login";
public static final String SPA_URL_MASK = "/{path:[^\\.]*}";
private UserService userService;
private JwtFilter jwtFilter;
public SecurityConfiguration(UserService userService) {
this.userService = userService;
this.jwtFilter = new JwtFilter(userService);
createAdminOnStartup();
createTestUsersOnStartup();
}
private void createAdminOnStartup() {
final String admin = "admin";
if (userService.getUserByLogin(admin) == null) {
log.info("Admin user successfully created");
userService.addUser(admin, admin, admin, UserRole.ADMIN, 2L);
}
}
private void createTestUsersOnStartup() {
final String[] userNames = {"user1", "user2", "user3"};
final Long[] userId = {19052L, 19053L, 20652L};
int cnt = 0;
for (String user : userNames) {
if (userService.getUserByLogin(user) == null) {
userService.addUser(user, user, user, UserRole.USER, userId[cnt]);
}
cnt++;
}
}
@Bean
public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
http.cors()
.and()
.csrf().disable()
.authorizeHttpRequests((a) -> a
.requestMatchers(HttpMethod.DELETE, "/api/**").hasRole("ADMIN")
.requestMatchers(HttpMethod.PUT, "/api/**").hasRole("ADMIN")
.requestMatchers(HttpMethod.POST, "/api/**").hasRole("ADMIN")
.requestMatchers(HttpMethod.GET, "/api/customer/**").hasRole("ADMIN")
.requestMatchers(HttpMethod.GET, "/api/store/addStore/**").hasRole("ADMIN")
.requestMatchers(HttpMethod.GET, "/customer/**").hasRole("ADMIN")
.requestMatchers(HttpMethod.GET, "/store/addToStore/**").hasRole("ADMIN")
.requestMatchers("/api/**").authenticated()
.requestMatchers(HttpMethod.POST, UserController.URL_LOGIN).permitAll()
.requestMatchers(HttpMethod.GET, "/img/**").permitAll())
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
.anonymous().and().authorizeHttpRequests((a) ->
a.requestMatchers(LOGIN_URL, UserLoginMVCController.SIGNUP_URL, "/h2-console/**")
.permitAll().requestMatchers("/users").hasRole("ADMIN").anyRequest().authenticated())
.formLogin()
.loginPage(LOGIN_URL).permitAll()
.defaultSuccessUrl("/", true)
.and()
.logout().permitAll()
.logoutSuccessUrl("/login")
.and()
.userDetailsService(userService);
return http.build();
}
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().requestMatchers("/css/**", "/js/**", "/templates/**", "/webjars/**", "/styles/**");
}
}

View File

@ -0,0 +1,11 @@
package com.example.ipLab.StoreDataBase.Configurations.jwt;
public class JwtException extends RuntimeException{
public JwtException(Throwable throwable) {
super(throwable);
}
public JwtException(String message) {
super(message);
}
}

View File

@ -0,0 +1,92 @@
package com.example.ipLab.StoreDataBase.Configurations.jwt;
import com.example.ipLab.StoreDataBase.Service.UserService;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
import org.springframework.util.StringUtils;
import java.io.IOException;
public class JwtFilter extends AbstractPreAuthenticatedProcessingFilter {
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) && bearer.startsWith(TOKEN_BEGIN_STR)) {
return bearer.substring(TOKEN_BEGIN_STR.length());
}
return null;
}
private void raiseException(ServletResponse response, int status, String message) throws IOException {
if (response instanceof final HttpServletResponse httpResponse) {
httpResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
httpResponse.setStatus(status);
final byte[] body = new ObjectMapper().writeValueAsBytes(message);
response.getOutputStream().write(body);
}
}
@Override
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if (request instanceof final HttpServletRequest httpRequest) {
final String token = getTokenFromRequest(httpRequest);
if (StringUtils.hasText(token)) {
try {
final UserDetails user = userService.loadUserByToken(token);
final UsernamePasswordAuthenticationToken auth =
new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(auth);
} catch (JwtException e) {
raiseException(response, HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());
return;
} catch (Exception e) {
e.printStackTrace();
raiseException(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
String.format("Internal error: %s", e.getMessage()));
return;
}
}
}
HttpServletRequest httpRequest = (HttpServletRequest) request;
if (httpRequest.getRequestURI().startsWith("/api/")) {
// Для URL, начинающихся с /api/, выполняем проверку наличия токена
super.doFilter(request, response, chain);
} else {
// Для остальных URL выполняем авторизацию
chain.doFilter(request, response);
}
}
@Override
protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
String token = getTokenFromRequest(request);
// Возвращаем токен как принципала
return token;
}
@Override
protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
return new WebAuthenticationDetailsSource().buildDetails(request);
}
}

View File

@ -0,0 +1,27 @@
package com.example.ipLab.StoreDataBase.Configurations.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 devToken = "";
private Boolean isDev = true;
public String getDevToken() {
return devToken;
}
public void setDevToken(String devToken) {
this.devToken = devToken;
}
public Boolean isDev() {
return isDev;
}
public void setDev(Boolean dev) {
isDev = dev;
}
}

View File

@ -0,0 +1,47 @@
package com.example.ipLab.StoreDataBase.Configurations.jwt;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;
@Component
public class JwtsProvider {
@Value("jwt.secret")
private String secret;
public String generateToken(String login, String role) {
Date date = Date.from(LocalDate.now().plusDays(15).atStartOfDay(ZoneId.systemDefault()).toInstant());
JwtBuilder builder = Jwts.builder()
.setSubject(login)
.setExpiration(date)
.signWith(SignatureAlgorithm.HS512, secret);
Claims claims = Jwts.claims();
claims.put("role", role);
builder.addClaims(claims);
return builder.compact();
}
public boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(secret).parseClaimsJws(token);
return true;
} catch (Exception e) {
return false;
}
}
public String getLogin(String token) {
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody()
.getSubject();
}
}

View File

@ -0,0 +1,58 @@
package com.example.ipLab.StoreDataBase.Controllers;
import com.example.ipLab.StoreDataBase.DTO.CustomerDTO;
import com.example.ipLab.StoreDataBase.Exceptions.ForbiddenException;
import com.example.ipLab.StoreDataBase.Model.CustomUser;
import com.example.ipLab.StoreDataBase.Model.Customer;
import com.example.ipLab.StoreDataBase.Model.UserRole;
import com.example.ipLab.StoreDataBase.Service.CustomerService;
import com.example.ipLab.WebConfiguration;
import jakarta.validation.Valid;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping(WebConfiguration.REST_API + "/customer")
public class CustomerController {
private final CustomerService customerService;
public CustomerController(CustomerService customerService){
this.customerService = customerService;
}
@GetMapping("/{id}")
public CustomerDTO getCustomer(@PathVariable Long id){
return new CustomerDTO(customerService.getCustomer(id));
}
@GetMapping
public List<CustomerDTO> getCustomers(@AuthenticationPrincipal CustomUser user){
return customerService.getAllCustomers().stream()
.map(CustomerDTO::new)
.toList();
}
@PostMapping
public CustomerDTO createCustomer(@RequestBody @Valid CustomerDTO customerDTO){
final Customer customer = customerService.addCustomer(customerDTO.getlastName(), customerDTO.getfirstName(), customerDTO.getmiddleName());
return new CustomerDTO(customer);
}
@PutMapping("/{id}")
public CustomerDTO updateCustomer(@RequestBody @Valid CustomerDTO customerDTO,
@PathVariable Long id){
return new CustomerDTO(customerService.updateCustomer(id, customerDTO.getlastName(), customerDTO.getfirstName(), customerDTO.getmiddleName()));
}
@DeleteMapping("/{id}")
public CustomerDTO deleteCustomer(@PathVariable Long id){
return new CustomerDTO(customerService.deleteCustomer(id));
}
@DeleteMapping()
public void deleteAllCustomers(){
customerService.deleteAllCustomers();
}
}

View File

@ -0,0 +1,71 @@
package com.example.ipLab.StoreDataBase.Controllers;
import com.example.ipLab.StoreDataBase.DTO.OrderedDTO;
import com.example.ipLab.StoreDataBase.Model.CustomUser;
import com.example.ipLab.StoreDataBase.Model.Ordered;
import com.example.ipLab.StoreDataBase.Model.UserRole;
import com.example.ipLab.StoreDataBase.Service.CustomerService;
import com.example.ipLab.StoreDataBase.Service.OrderService;
import com.example.ipLab.StoreDataBase.Service.ProductService;
import com.example.ipLab.WebConfiguration;
import jakarta.validation.Valid;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping(WebConfiguration.REST_API + "/order")
public class OrderedController {
private final OrderService orderedService;
private final ProductService productService;
private final CustomerService customerService;
public OrderedController(OrderService orderedService, ProductService productService, CustomerService customerService){
this.productService = productService;
this.customerService = customerService;
this.orderedService = orderedService;
}
@GetMapping("/{id}")
public OrderedDTO getOrdered(@PathVariable Long id){
return new OrderedDTO(orderedService.getOrder(id));
}
@GetMapping
public List<OrderedDTO> getOrdereds(@AuthenticationPrincipal CustomUser user){
if (user.getRole() == UserRole.USER){
return orderedService.getOrdersByCustomerId(user.getUserID()).stream()
.map(OrderedDTO::new)
.toList();
}
else{
return orderedService.getAllOrders().stream()
.map(OrderedDTO::new)
.toList();
}
}
@PostMapping
public OrderedDTO createOrdered(@RequestBody @Valid OrderedDTO orderedDTO){
final Ordered ordered = orderedService.addOrder(productService.getProduct(orderedDTO.getProductId()), customerService.getCustomer(orderedDTO.getCustomerId()), orderedDTO.quantity);
return new OrderedDTO(ordered);
}
@PutMapping("/{id}")
public OrderedDTO updateOrdered(@RequestBody @Valid OrderedDTO orderedDTO,
@PathVariable Long id){
return new OrderedDTO(orderedService.updateOrder(id, orderedDTO.quantity));
}
@DeleteMapping("/{id}")
public OrderedDTO deleteOrdered(@PathVariable Long id){
return new OrderedDTO(orderedService.deleteOrder(id));
}
@DeleteMapping()
public void deleteAllOrdereds(){
orderedService.deleteAllOrders();
}
}

View File

@ -0,0 +1,79 @@
package com.example.ipLab.StoreDataBase.Controllers;
import com.example.ipLab.StoreDataBase.DTO.ProductDTO;
import com.example.ipLab.StoreDataBase.Model.CustomUser;
import com.example.ipLab.StoreDataBase.Model.Product;
import com.example.ipLab.StoreDataBase.Model.UserRole;
import com.example.ipLab.StoreDataBase.Service.ProductService;
import com.example.ipLab.WebConfiguration;
import jakarta.validation.Valid;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping(WebConfiguration.REST_API + "/product")
public class ProductController {
private final ProductService productService;
public ProductController(ProductService productService){
this.productService = productService;
}
@GetMapping("/{id}")
public ProductDTO getProduct(@PathVariable Long id){
return new ProductDTO(productService.getProduct(id));
}
@GetMapping
public List<ProductDTO> getProducts(@AuthenticationPrincipal CustomUser user){
if (user.getRole() == UserRole.USER){
return productService.getAllProductsWithStores().stream()
.map(ProductDTO::new)
.toList();
}
else{
return productService.getAllProducts().stream()
.map(ProductDTO::new)
.toList();
}
}
@GetMapping("/getWithStores")
public List<ProductDTO> getProductsWithStores(){
return productService.getAllProductsWithStores().stream()
.map(ProductDTO::new)
.toList();
}
@GetMapping("/getWithoutStores")
public List<ProductDTO> getProductsWithoutStores(){
return productService.getAllProductsWithoutStores().stream()
.map(ProductDTO::new)
.toList();
}
@PostMapping
public ProductDTO createProduct(@RequestBody @Valid ProductDTO productDTO){
final Product product = productService.addProduct(productDTO.getproductName());
return new ProductDTO(product);
}
@PutMapping("/{id}")
public ProductDTO updateProduct(@RequestBody @Valid ProductDTO productDTO,
@PathVariable Long id){
return new ProductDTO(productService.updateProduct(id, productDTO.getproductName()));
}
@DeleteMapping("/{id}")
public ProductDTO deleteProduct(@PathVariable Long id){
return new ProductDTO(productService.deleteProduct(id));
}
@DeleteMapping()
public void deleteAllProducts(){
productService.deleteAllProducts();
}
}

View File

@ -0,0 +1,62 @@
package com.example.ipLab.StoreDataBase.Controllers;
import com.example.ipLab.StoreDataBase.DTO.CustomerDTO;
import com.example.ipLab.StoreDataBase.DTO.ProductDTO;
import com.example.ipLab.StoreDataBase.DTO.StoreDTO;
import com.example.ipLab.StoreDataBase.Model.Store;
import com.example.ipLab.StoreDataBase.Service.StoreService;
import com.example.ipLab.WebConfiguration;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping(WebConfiguration.REST_API + "/store")
public class StoreController {
private final StoreService storeService;
public StoreController(StoreService storeService){
this.storeService = storeService;
}
@GetMapping("/{id}")
public StoreDTO getStore(@PathVariable Long id){
return new StoreDTO(storeService.getStore(id));
}
@GetMapping
public List<StoreDTO> getStores(){
return storeService.getAllStores().stream()
.map(StoreDTO::new)
.toList();
}
@PostMapping
public StoreDTO createStore(@RequestBody @Valid StoreDTO storeDTO){
final Store store = storeService.addStore(storeDTO.getstoreName());
return new StoreDTO(store);
}
@PutMapping("/{id}")
public StoreDTO updateStore(@RequestBody @Valid StoreDTO storeDTO,
@PathVariable Long id){
return new StoreDTO(storeService.updateStore(id, storeDTO.getstoreName()));
}
@PutMapping("{id}/add")
public ProductDTO addProduct(@PathVariable Long id,
@RequestBody @Valid CustomerDTO customerDTO){
return new ProductDTO(storeService.addProduct(id, customerDTO.getId()));
}
@DeleteMapping("/{id}")
public StoreDTO deleteStore(@PathVariable Long id){
return new StoreDTO(storeService.deleteStore(id));
}
@DeleteMapping()
public void deleteAllStores(){
storeService.deleteAllStores();
}
}

View File

@ -0,0 +1,24 @@
package com.example.ipLab.StoreDataBase.Controllers;
import com.example.ipLab.StoreDataBase.DTO.UserDTO;
import com.example.ipLab.StoreDataBase.Service.UserService;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
public static final String URL_LOGIN = "/jwt/login";
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@PostMapping(URL_LOGIN)
public String login(@RequestBody @Valid UserDTO userDto) {
return userService.loginAndGetToken(userDto);
}
}

View File

@ -0,0 +1,60 @@
package com.example.ipLab.StoreDataBase.DTO;
import com.example.ipLab.StoreDataBase.Model.Customer;
import jakarta.validation.constraints.NotBlank;
public class CustomerDTO {
public Long id;
@NotBlank(message = "lastName can't be null or empty")
public String lastName;
@NotBlank(message = "firstName can't be null or empty")
public String firstName;
@NotBlank(message = "middleName can't be null or empty")
public String middleName;
public String customerFIO;
public CustomerDTO(){
}
public CustomerDTO(Customer customer){
this.id = customer.getId();
this.lastName = customer.getLastName();
this.firstName = customer.getFirstName();
this.middleName = customer.getMiddleName();
this.customerFIO = lastName + " " + firstName + " " + middleName;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getlastName() {
return lastName;
}
public void setlastName(String lastName) {
this.lastName = lastName;
}
public String getfirstName() {
return firstName;
}
public void setfirstName(String firstName) {
this.firstName = firstName;
}
public String getmiddleName() {
return middleName;
}
public void setmiddleName(String middleName) {
this.middleName = middleName;
}
public String getcustomerFIO() {
return customerFIO;
}
public void setcustomerFIO(String customerFIO) {
this.customerFIO = customerFIO;
}
}

View File

@ -0,0 +1,36 @@
package com.example.ipLab.StoreDataBase.DTO;
import jakarta.validation.constraints.NotBlank;
public class LoginDTO {
@NotBlank
private String login;
@NotBlank
private String password;
@NotBlank
private String passwordConfirm;
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPasswordConfirm() {
return passwordConfirm;
}
public void setPasswordConfirm(String passwordConfirm) {
this.passwordConfirm = passwordConfirm;
}
}

View File

@ -0,0 +1,69 @@
package com.example.ipLab.StoreDataBase.DTO;
import com.example.ipLab.StoreDataBase.Model.Customer;
import com.example.ipLab.StoreDataBase.Model.Ordered;
import com.example.ipLab.StoreDataBase.Model.Product;
public class OrderedDTO {
public Long id;
public int quantity;
public String productName;
public String customerFIO;
public String storeName;
public Long customerId;
public Long productId;
public OrderedDTO(){
}
public OrderedDTO(Ordered ordered){
this.id = ordered.getId();
this.quantity = ordered.getQuantity();
this.productName = ordered.getProduct().getName();
this.storeName = ordered.getProduct().getStore().getStoreName();
this.customerFIO = ordered.getCustomer().getLastName() + " " + ordered.getCustomer().getFirstName() + " " + ordered.getCustomer().getMiddleName();
this.customerId = ordered.getProduct().getId();
this.productId = ordered.getProduct().getId();
}
public Long getId() {
return id;
}
public int getQuantity() {
return quantity;
}
public String getproductName() {
return productName;
}
public void setproductName(String productName) {
this.productName = productName;
}
public String getcustomerFIO() {
return customerFIO;
}
public void setcustomerFIO(String customerFIO) {
this.customerFIO = customerFIO;
}
public String getstoreName() {
return storeName;
}
public void setstoreName(String storeName) {
this.storeName = storeName;
}
public Long getCustomerId() {
return customerId;
}
public Long getProductId() {
return productId;
}
}

View File

@ -0,0 +1,34 @@
package com.example.ipLab.StoreDataBase.DTO;
import com.example.ipLab.StoreDataBase.Model.Product;
public class ProductDTO {
public Long id;
public String productName;
public String storeName;
public ProductDTO(){
}
public ProductDTO(Product product){
this.id = product.getId();
this.productName = product.getName();
this.storeName = product.getStore() == null ? null : product.getStore().getStoreName();
}
public Long getId() {
return id;
}
public String getproductName() {
return productName;
}
public void setproductName(String productName) {
this.productName = productName;
}
public String getStoreName() {
return storeName;
}
}

View File

@ -0,0 +1,37 @@
package com.example.ipLab.StoreDataBase.DTO;
import com.example.ipLab.StoreDataBase.Model.Store;
import java.util.List;
public class StoreDTO {
public Long id;
public String storeName;
public List<ProductDTO> products;
public StoreDTO(){
}
public StoreDTO(Store store){
this.id = store.getId();
this.storeName = store.getStoreName();
this.products = store.getProducts().stream().map(ProductDTO::new).toList();
}
public Long getId() {
return id;
}
public String getstoreName() {
return storeName;
}
public void setstoreName(String storeName) {
this.storeName = storeName;
}
public List<ProductDTO> getProducts() {
return products;
}
}

View File

@ -0,0 +1,49 @@
package com.example.ipLab.StoreDataBase.DTO;
import com.example.ipLab.StoreDataBase.Model.User;
import com.example.ipLab.StoreDataBase.Model.UserRole;
public class UserDTO {
private long id;
private String login;
private UserRole role;
private String password;
public UserDTO() {
}
public UserDTO(User user) {
this.id = user.getId();
this.login = user.getLogin();
this.role = user.getRole();
this.password = user.getPassword();
}
public long getId() {
return id;
}
public String getLogin() {
return login;
}
public UserRole getRole() {
return role;
}
public String getPassword() {
return password;
}
public void setLogin(String login) {
this.login = login;
}
public void setRole(UserRole role) {
this.role = role;
}
public void setPassword(String password) {
this.password = password;
}
}

View File

@ -0,0 +1,7 @@
package com.example.ipLab.StoreDataBase.Exceptions;
public class CustomerNotFoundException extends RuntimeException{
public CustomerNotFoundException(Long id){
super(String.format("Customer with id: %s hasn't been found", id));
}
}

View File

@ -0,0 +1,8 @@
package com.example.ipLab.StoreDataBase.Exceptions;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(HttpStatus.FORBIDDEN)
public class ForbiddenException extends RuntimeException {
}

View File

@ -0,0 +1,7 @@
package com.example.ipLab.StoreDataBase.Exceptions;
public class OrderedNotFoundException extends RuntimeException{
public OrderedNotFoundException(Long id){
super(String.format("Order with id: %s hasn't been found", id));
}
}

View File

@ -0,0 +1,7 @@
package com.example.ipLab.StoreDataBase.Exceptions;
public class ProductNotFoundException extends RuntimeException{
public ProductNotFoundException(Long id){
super(String.format("Product with id: %s hasn't been found", id));
}
}

View File

@ -0,0 +1,7 @@
package com.example.ipLab.StoreDataBase.Exceptions;
public class StoreNotFoundException extends RuntimeException{
public StoreNotFoundException(Long id){
super(String.format("Store with id: %s hasn't been found", id));
}
}

View File

@ -0,0 +1,7 @@
package com.example.ipLab.StoreDataBase.Exceptions;
public class UserNotFoundException extends RuntimeException{
public UserNotFoundException(String login){
super(String.format("User with login: %s hasn't been found", login));
}
}

View File

@ -0,0 +1,63 @@
package com.example.ipLab.StoreDataBase.MVC;
import com.example.ipLab.StoreDataBase.DTO.CustomerDTO;
import com.example.ipLab.StoreDataBase.Service.CustomerService;
import jakarta.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
@Controller
@RequestMapping("/customer")
public class CustomerMVCController {
private final CustomerService customerService;
public CustomerMVCController(CustomerService customerService) {
this.customerService = customerService;
}
@GetMapping
public String getCustomers(Model model) {
model.addAttribute("customers",
customerService.getAllCustomers().stream()
.map(CustomerDTO::new)
.toList());
return "customer";
}
@GetMapping(value = {"/edit/", "/edit/{id}"})
public String editCustomer(@PathVariable(required = false) Long id,
Model model) {
if (id == null || id <= 0) {
model.addAttribute("customerDTO", new CustomerDTO());
} else {
model.addAttribute("customerId", id);
model.addAttribute("customerDTO", new CustomerDTO(customerService.getCustomer(id)));
}
return "customer-edit";
}
@PostMapping(value = {"/", "/{id}"})
public String saveCustomer(@PathVariable(required = false) Long id,
@ModelAttribute @Valid CustomerDTO customerDto,
BindingResult bindingResult,
Model model) {
if (bindingResult.hasErrors()) {
model.addAttribute("errors", bindingResult.getAllErrors());
return "customer-edit";
}
if (id == null || id <= 0) {
customerService.addCustomer(customerDto.getlastName(), customerDto.getfirstName(), customerDto.getmiddleName());
} else {
customerService.updateCustomer(id, customerDto.getlastName(), customerDto.getfirstName(), customerDto.getmiddleName());
}
return "redirect:/customer";
}
@PostMapping("/delete/{id}")
public String deleteCustomer(@PathVariable Long id) {
customerService.deleteCustomer(id);
return "redirect:/customer";
}
}

View File

@ -0,0 +1,76 @@
package com.example.ipLab.StoreDataBase.MVC;
import com.example.ipLab.StoreDataBase.DTO.CustomerDTO;
import com.example.ipLab.StoreDataBase.DTO.OrderedDTO;
import com.example.ipLab.StoreDataBase.DTO.ProductDTO;
import com.example.ipLab.StoreDataBase.Model.CustomUser;
import com.example.ipLab.StoreDataBase.Model.UserRole;
import com.example.ipLab.StoreDataBase.Service.CustomerService;
import com.example.ipLab.StoreDataBase.Service.OrderService;
import com.example.ipLab.StoreDataBase.Service.ProductService;
import jakarta.validation.Valid;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
@Controller
@RequestMapping("/order")
public class OrderedMVCController {
private final OrderService orderedService;
private final ProductService productService;
private final CustomerService customerService;
public OrderedMVCController(OrderService orderedService, ProductService productService, CustomerService customerService){
this.productService = productService;
this.customerService = customerService;
this.orderedService = orderedService;
}
@GetMapping
public String getOrdereds(Model model, @AuthenticationPrincipal CustomUser user) {
if (user.getRole() == UserRole.USER){
model.addAttribute("orders",
orderedService.getOrdersByCustomerId(user.getUserID()).stream()
.map(OrderedDTO::new)
.toList());
}
else {
model.addAttribute("orders",
orderedService.getAllOrders().stream()
.map(OrderedDTO::new)
.toList());
}
return "order";
}
@GetMapping(value = {"/edit/", "/edit/{id}"})
public String editOrdered(@PathVariable(required = false) Long id,
Model model) {
model.addAttribute("orderDTO", new OrderedDTO());
model.addAttribute("customers", customerService.getAllCustomers().stream().map(CustomerDTO::new).toList());
model.addAttribute("products", productService.getAllProductsWithStores().stream().map(ProductDTO::new).toList());
return "order-edit";
}
@PostMapping(value = {"/", "/{id}"})
public String saveOrdered(@RequestParam(value = "productId") Long productId,
@RequestParam(value = "customerId") Long customerId,
@ModelAttribute @Valid OrderedDTO orderedDto,
BindingResult bindingResult,
Model model) {
if (bindingResult.hasErrors()) {
model.addAttribute("errors", bindingResult.getAllErrors());
return "ordered-edit";
}
orderedService.addOrder(productService.getProduct(productId), customerService.getCustomer(customerId), orderedDto.getQuantity());
return "redirect:/order";
}
@PostMapping("/delete/{id}")
public String deleteOrdered(@PathVariable Long id) {
orderedService.deleteOrder(id);
return "redirect:/order";
}
}

View File

@ -0,0 +1,84 @@
package com.example.ipLab.StoreDataBase.MVC;
import com.example.ipLab.StoreDataBase.Configurations.SecurityConfiguration;
import com.example.ipLab.StoreDataBase.DTO.ProductDTO;
import com.example.ipLab.StoreDataBase.Model.CustomUser;
import com.example.ipLab.StoreDataBase.Model.User;
import com.example.ipLab.StoreDataBase.Model.UserRole;
import com.example.ipLab.StoreDataBase.Service.ProductService;
import com.example.ipLab.StoreDataBase.Service.UserService;
import jakarta.validation.Valid;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import java.security.Principal;
@Controller
@RequestMapping("/product")
public class ProductMVCController {
private final ProductService productService;
public ProductMVCController(ProductService productService) {
this.productService = productService;
}
@GetMapping
public String getProducts(Model model, @AuthenticationPrincipal CustomUser user) {
if (user.getRole() == UserRole.USER){
model.addAttribute("products",
productService.getAllProductsWithStores().stream()
.map(ProductDTO::new)
.toList());
}
else{
model.addAttribute("products",
productService.getAllProducts().stream()
.map(ProductDTO::new)
.toList());
}
return "product";
}
@GetMapping(value = {"/edit/", "/edit/{id}"})
public String editProduct(@PathVariable(required = false) Long id,
Model model) {
if (id == null || id <= 0) {
model.addAttribute("productDTO", new ProductDTO());
} else {
model.addAttribute("productId", id);
model.addAttribute("productDTO", new ProductDTO(productService.getProduct(id)));
}
return "product-edit";
}
@PostMapping(value = {"/", "/{id}"})
public String saveProduct(@PathVariable(required = false) Long id,
@ModelAttribute @Valid ProductDTO productDto,
BindingResult bindingResult,
Model model) {
if (bindingResult.hasErrors()) {
model.addAttribute("errors", bindingResult.getAllErrors());
return "product-edit";
}
if (id == null || id <= 0) {
productService.addProduct(productDto.getproductName());
} else {
productService.updateProduct(id, productDto.getproductName());
}
return "redirect:/product";
}
@PostMapping("/delete/{id}")
public String deleteProduct(@PathVariable Long id) {
productService.deleteProduct(id);
return "redirect:/product";
}
}

View File

@ -0,0 +1,84 @@
package com.example.ipLab.StoreDataBase.MVC;
import com.example.ipLab.StoreDataBase.DTO.CustomerDTO;
import com.example.ipLab.StoreDataBase.DTO.ProductDTO;
import com.example.ipLab.StoreDataBase.DTO.StoreDTO;
import com.example.ipLab.StoreDataBase.Service.ProductService;
import com.example.ipLab.StoreDataBase.Service.StoreService;
import jakarta.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
@Controller
@RequestMapping("/store")
public class StoreMVCController {
private final StoreService storeService;
private final ProductService productService;
public StoreMVCController(StoreService storeService, ProductService productService) {
this.storeService = storeService;
this.productService = productService;
}
@GetMapping
public String getStores(Model model) {
model.addAttribute("stores",
storeService.getAllStores().stream()
.map(StoreDTO::new)
.toList());
return "store";
}
@GetMapping(value = {"/edit/", "/edit/{id}"})
public String editStore(@PathVariable(required = false) Long id,
Model model) {
if (id == null || id <= 0) {
model.addAttribute("storeDTO", new StoreDTO());
} else {
model.addAttribute("storeId", id);
model.addAttribute("storeDTO", new StoreDTO(storeService.getStore(id)));
}
return "store-edit";
}
@GetMapping(value = "/addToStore")
public String addToStore(@PathVariable(required = false) Long id,
Model model) {
model.addAttribute("stores", storeService.getAllStores().stream().map(StoreDTO::new).toList());
model.addAttribute("products", productService.getAllProductsWithoutStores().stream().map(ProductDTO::new).toList());
return "addToStore";
}
@PostMapping(value = {"/", "/{id}"})
public String saveStore(@PathVariable(required = false) Long id,
@ModelAttribute @Valid StoreDTO storeDto,
BindingResult bindingResult,
Model model) {
if (bindingResult.hasErrors()) {
model.addAttribute("errors", bindingResult.getAllErrors());
return "store-edit";
}
if (id == null || id <= 0) {
storeService.addStore(storeDto.getstoreName());
} else {
storeService.updateStore(id, storeDto.getstoreName());
}
return "redirect:/store";
}
@PostMapping("/add")
public String addProduct(@RequestParam(value = "storeId") Long storeId,
@RequestParam(value = "productId") Long productId
){
storeService.addProduct(storeId, productId);
return "redirect:/product";
}
@PostMapping("/delete/{id}")
public String deleteStore(@PathVariable Long id) {
storeService.deleteStore(id);
return "redirect:/store";
}
}

View File

@ -0,0 +1,51 @@
package com.example.ipLab.StoreDataBase.MVC;
import com.example.ipLab.StoreDataBase.DTO.LoginDTO;
import com.example.ipLab.StoreDataBase.Model.User;
import com.example.ipLab.StoreDataBase.Model.UserRole;
import com.example.ipLab.StoreDataBase.Service.UserService;
import com.example.ipLab.StoreDataBase.util.validation.ValidationException;
import jakarta.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(UserLoginMVCController.SIGNUP_URL)
public class UserLoginMVCController {
public static final String SIGNUP_URL = "/signup";
private final UserService userService;
public UserLoginMVCController(UserService userService) {
this.userService = userService;
}
@GetMapping
public String showSignupForm(Model model) {
model.addAttribute("userDto", new LoginDTO());
return "signup";
}
@PostMapping
public String signup(@ModelAttribute("userDto") @Valid LoginDTO userSignupDto,
BindingResult bindingResult,
Model model) {
if (bindingResult.hasErrors()) {
model.addAttribute("errors", bindingResult.getAllErrors());
return "signup";
}
try {
final User user = userService.addUser(
userSignupDto.getLogin(), userSignupDto.getPassword(), userSignupDto.getPasswordConfirm(), UserRole.USER, Long.parseLong("1"));
return "redirect:/login?created=" + user.getLogin();
} catch (ValidationException e) {
model.addAttribute("errors", e.getMessage());
return "signup";
}
}
}

View File

@ -0,0 +1,33 @@
package com.example.ipLab.StoreDataBase.MVC;
import com.example.ipLab.StoreDataBase.DTO.ProductDTO;
import com.example.ipLab.StoreDataBase.DTO.UserDTO;
import com.example.ipLab.StoreDataBase.Model.UserRole;
import com.example.ipLab.StoreDataBase.Service.UserService;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/user")
public class UserMVCController {
private final UserService userService;
public UserMVCController(UserService userService) {
this.userService = userService;
}
@GetMapping
@Secured({UserRole.AsString.ADMIN})
public String getUsers(Model model){
model.addAttribute("users",
userService.getAllUsers().stream()
.map(UserDTO::new)
.toList());
return "users";
}
}

View File

@ -0,0 +1,26 @@
package com.example.ipLab.StoreDataBase.Model;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import java.util.Collection;
public class CustomUser extends User {
private final Long userID;
private final UserRole role;
public CustomUser(String username, String password,
Collection<? extends GrantedAuthority> authorities, Long userID, UserRole role) {
super(username, password, authorities);
this.userID = userID;
this.role = role;
}
public Long getUserID() {
return userID;
}
public UserRole getRole() {
return role;
}
}

View File

@ -0,0 +1,95 @@
package com.example.ipLab.StoreDataBase.Model;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotBlank;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@Entity
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column
@NotBlank(message = "Customer's last name can't be empty")
private String lastName;
@Column
@NotBlank(message = "Customer's first name can't be empty")
private String firstName;
@Column
@NotBlank(message = "Customer's middle name can't be empty")
private String middleName;
@OneToMany(fetch = FetchType.EAGER, mappedBy = "customer", cascade = CascadeType.ALL)
private List<Ordered> orders;
public void AddOrdered(Ordered ordered){
this.orders.add(ordered);
if (ordered.getCustomer() != this){
ordered.setCustomer(this);
}
}
@PreRemove
public void removeOrders(){
for (var order:
orders) {
order.removeCustomer();
}
orders = null;
}
public Customer(){
this.orders = new ArrayList<>();
}
public Customer(String lastName, String firstName, String middleName){
this.lastName = lastName;
this.firstName = firstName;
this.middleName = middleName;
this.orders = new ArrayList<Ordered>();
}
public Long getId() {
return id;
}
public String getLastName() {
return lastName;
}
public String getMiddleName() {
return middleName;
}
public String getFirstName() {
return firstName;
}
public List<Ordered> getOrders() {
return orders;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public void setMiddleName(String middleName) {
this.middleName = middleName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Customer customer = (Customer) obj;
return Objects.equals(id, customer.id);
}
@Override
public int hashCode(){
return Objects.hashCode(id);
}
}

View File

@ -0,0 +1,82 @@
package com.example.ipLab.StoreDataBase.Model;
import jakarta.persistence.*;
import java.util.Objects;
@Entity
public class Ordered {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name="customer_fk")
private Customer customer;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name="product_fk")
private Product product;
@Column
private int quantity;
public Ordered(){}
public Ordered(int quantity){
this.quantity = quantity;
}
public Long getId() {
return id;
}
public Customer getCustomer() {
return customer;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
if (!product.getOrders().contains(this)){
product.AddOrdered(this);
}
}
@PreRemove
public void removeProduct(){
this.product.getOrders().remove(this);
this.product = null;
removeCustomer();
}
public void removeCustomer(){
this.customer.getOrders().remove(this);
this.customer = null;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public void setCustomer(Customer customer) {
this.customer = customer;
if (!customer.getOrders().contains(this)){
customer.AddOrdered(this);
}
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Ordered order = (Ordered) obj;
return Objects.equals(id, order.id);
}
@Override
public int hashCode(){
return Objects.hashCode(id);
}
}

View File

@ -0,0 +1,94 @@
package com.example.ipLab.StoreDataBase.Model;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotBlank;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@Entity
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column
@NotBlank(message = "Product's name can't be empty")
private String name;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "store_fk")
private Store store;
@OneToMany(fetch = FetchType.EAGER, mappedBy = "product", cascade = CascadeType.ALL)
private List<Ordered> orders;
public Product(){}
public Product(String name){
this.name = name;
this.orders = new ArrayList<Ordered>();
}
public Product(Store store, String name){
this.store = store;
this.name = name;
this.orders = new ArrayList<Ordered>();
}
public void AddOrdered(Ordered ordered){
this.orders.add(ordered);
if (ordered.getProduct() != this){
ordered.setProduct(this);
}
}
@PreRemove
public void removeStore(){
if (this.store != null) {
this.store.getProducts().remove(this);
this.store = null;
}
removeOrders();
}
public void removeOrders(){
for (var order:
orders) {
order.removeProduct();
}
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public Store getStore() {
return store;
}
public List<Ordered> getOrders() {
return orders;
}
public void setName(String name) {
this.name = name;
}
public void setStore(Store store) {
this.store = store;
if (!store.getProducts().contains(this)){
store.AddProduct(this);
}
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Product product = (Product) obj;
return Objects.equals(id, product.id);
}
@Override
public int hashCode(){
return Objects.hashCode(id);
}
}

View File

@ -0,0 +1,70 @@
package com.example.ipLab.StoreDataBase.Model;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotBlank;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@Entity
public class Store {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column
@NotBlank(message = "Store's name can't be empty")
private String storeName;
@OneToMany(fetch = FetchType.EAGER, mappedBy = "store", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Product> products;
public Store(){
this.products = new ArrayList<>();
}
public Store(String storeName){
this.storeName = storeName;
this.products = new ArrayList<>();
}
public Long getId() {
return id;
}
public String getStoreName() {
return storeName;
}
public List<Product> getProducts() {
return products;
}
public void AddProduct(Product product){
this.products.add(product);
if (product.getStore() != this){
product.setStore(this);
}
}
@PreRemove
public void removeProducts(){
for (var product:
products) {
product.removeStore();
}
products = new ArrayList<>();
}
public void setStoreName(String storeName) {
this.storeName = storeName;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Store store = (Store) obj;
return Objects.equals(id, store.id);
}
@Override
public int hashCode(){
return Objects.hashCode(id);
}
}

View File

@ -0,0 +1,79 @@
package com.example.ipLab.StoreDataBase.Model;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotBlank;
import java.util.Objects;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column
@NotBlank
private String login;
@Column
@NotBlank
private String password;
@Column
private Long userId;
private UserRole role;
public User() {
}
public User(String login, String password, Long userId) {
this(login, password, UserRole.USER, userId);
}
public User(String login, String password, UserRole role, Long userId) {
this.login = login;
this.password = password;
this.role = role;
this.userId = userId;
}
public Long getId() {
return id;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public UserRole getRole() {
return role;
}
public Long getUserId() {
return userId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(id, user.id) && Objects.equals(login, user.login);
}
@Override
public int hashCode() {
return Objects.hash(id, login);
}
}

View File

@ -0,0 +1,20 @@
package com.example.ipLab.StoreDataBase.Model;
import org.springframework.security.core.GrantedAuthority;
public enum UserRole implements GrantedAuthority {
ADMIN,
USER;
private static final String PREFIX = "ROLE_";
@Override
public String getAuthority() {
return PREFIX + this.name();
}
public static final class AsString {
public static final String ADMIN = PREFIX + "ADMIN";
public static final String USER = PREFIX + "USER";
}
}

View File

@ -0,0 +1,7 @@
package com.example.ipLab.StoreDataBase.Repositories;
import com.example.ipLab.StoreDataBase.Model.Customer;
import org.springframework.data.jpa.repository.JpaRepository;
public interface CustomerRepository extends JpaRepository<Customer, Long> {
}

View File

@ -0,0 +1,13 @@
package com.example.ipLab.StoreDataBase.Repositories;
import com.example.ipLab.StoreDataBase.Model.Ordered;
import com.example.ipLab.StoreDataBase.Model.Product;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.Collection;
public interface OrderedRepository extends JpaRepository<Ordered, Long> {
@Query("SELECT o FROM Ordered o WHERE o.customer.id = ?1")
Collection<Ordered> findOrdersByCustomerId(Long clientId);
}

View File

@ -0,0 +1,14 @@
package com.example.ipLab.StoreDataBase.Repositories;
import com.example.ipLab.StoreDataBase.Model.Product;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.Collection;
public interface ProductRepository extends JpaRepository<Product, Long> {
@Query("SELECT p FROM Product p WHERE p.store <> null")
Collection<Product> findAllProductsWithStores();
@Query("SELECT p FROM Product p WHERE p.store = null")
Collection<Product> findAllProductsWithoutStores();
}

View File

@ -0,0 +1,7 @@
package com.example.ipLab.StoreDataBase.Repositories;
import com.example.ipLab.StoreDataBase.Model.Store;
import org.springframework.data.jpa.repository.JpaRepository;
public interface StoreRepository extends JpaRepository<Store, Long> {
}

View File

@ -0,0 +1,8 @@
package com.example.ipLab.StoreDataBase.Repositories;
import com.example.ipLab.StoreDataBase.Model.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
User findOneByLogin(String login);
}

View File

@ -0,0 +1,68 @@
package com.example.ipLab.StoreDataBase.Service;
import com.example.ipLab.StoreDataBase.Exceptions.CustomerNotFoundException;
import com.example.ipLab.StoreDataBase.Model.Customer;
import com.example.ipLab.StoreDataBase.Repositories.CustomerRepository;
import com.example.ipLab.StoreDataBase.util.validation.ValidatorUtil;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityNotFoundException;
import jakarta.persistence.PersistenceContext;
import jakarta.transaction.Transactional;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.List;
@Service
public class CustomerService {
private final CustomerRepository customerRepository;
private final ValidatorUtil validatorUtil;
public CustomerService(CustomerRepository customerRepository,
ValidatorUtil validatorUtil){
this.customerRepository = customerRepository;
this.validatorUtil = validatorUtil;
}
@Transactional
public Customer addCustomer(String customerLastName, String customerFirstName, String customerMiddleName){
Customer customer = new Customer(customerLastName, customerFirstName, customerMiddleName);
validatorUtil.validate(customer);
return customerRepository.save(customer);
}
@Transactional()
public Customer getCustomer(Long id){
return customerRepository.findById(id).orElseThrow(() -> new CustomerNotFoundException(id));
}
@Transactional
public List<Customer> getAllCustomers(){
return customerRepository.findAll();
}
@Transactional
public Customer updateCustomer(Long id, String customerLastName, String customerFirstName, String customerMiddleName){
Customer customer = getCustomer(id);
customer.setLastName(customerLastName);
customer.setFirstName(customerFirstName);
customer.setMiddleName(customerMiddleName);
validatorUtil.validate(customer);
return customerRepository.save(customer);
}
@Transactional
public Customer deleteCustomer(Long id){
Customer customer = getCustomer(id);
customerRepository.delete(customer);
return customer;
}
@Transactional
public void deleteAllCustomers(){
//for (var customer:
// getAllCustomers()) {
// customer.removeOrders();
//}
customerRepository.deleteAll();
}
}

View File

@ -0,0 +1,91 @@
package com.example.ipLab.StoreDataBase.Service;
import com.example.ipLab.StoreDataBase.Exceptions.OrderedNotFoundException;
import com.example.ipLab.StoreDataBase.Model.Customer;
import com.example.ipLab.StoreDataBase.Model.Ordered;
import com.example.ipLab.StoreDataBase.Model.Product;
import com.example.ipLab.StoreDataBase.Model.Store;
import com.example.ipLab.StoreDataBase.Repositories.OrderedRepository;
import com.example.ipLab.StoreDataBase.util.validation.ValidatorUtil;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityNotFoundException;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.criteria.Order;
import jakarta.transaction.Transactional;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.List;
@Service
public class OrderService {
private final OrderedRepository orderedRepository;
private final ValidatorUtil validatorUtil;
public OrderService(OrderedRepository orderedRepository,
ValidatorUtil validatorUtil,
ProductService productService){
this.productService = productService;
this.orderedRepository = orderedRepository;
this.validatorUtil = validatorUtil;
}
private ProductService productService;
@Transactional
public Ordered addOrder(Product product, Customer customer, int quantity){
final Ordered order = new Ordered(quantity);
validatorUtil.validate(order);
product.AddOrdered(order);
customer.AddOrdered(order);
orderedRepository.save(order);
return order;
}
@Transactional()
public Ordered getOrder(Long id){
return orderedRepository.findById(id).orElseThrow(() -> new OrderedNotFoundException(id));
}
@Transactional
public List<Ordered> getAllOrders(){
return orderedRepository.findAll();
}
@Transactional
public List<Ordered> getOrdersByCustomerId(Long customerId){
return orderedRepository.findOrdersByCustomerId(customerId).stream().toList();
}
@Transactional
public Ordered updateOrder(Long id, int quantity){
final Ordered order = getOrder(id);
order.setQuantity(quantity);
validatorUtil.validate(order);
return orderedRepository.save(order);
}
@Transactional
public Ordered deleteOrder(Long id){
final Ordered order = getOrder(id);
order.getCustomer().getOrders().remove(order);
orderedRepository.delete(order);
return order;
}
@Transactional
public void deleteAllOrders(){
//for (var order:
// getAllOrders()) {
// order.removeProduct();
// order.removeCustomer();
//}
orderedRepository.deleteAll();
}
//product section
@Transactional()
public Product getProduct(Long orderId){
Ordered order = getOrder(orderId);
return order.getProduct();
}
}

View File

@ -0,0 +1,77 @@
package com.example.ipLab.StoreDataBase.Service;
import com.example.ipLab.StoreDataBase.Exceptions.ProductNotFoundException;
import com.example.ipLab.StoreDataBase.Model.Customer;
import com.example.ipLab.StoreDataBase.Model.Ordered;
import com.example.ipLab.StoreDataBase.Model.Product;
import com.example.ipLab.StoreDataBase.Model.Store;
import com.example.ipLab.StoreDataBase.Repositories.ProductRepository;
import com.example.ipLab.StoreDataBase.util.validation.ValidatorUtil;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityNotFoundException;
import jakarta.persistence.PersistenceContext;
import jakarta.transaction.Transactional;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.List;
@Service
public class ProductService {
private final ProductRepository productRepository;
private final ValidatorUtil validatorUtil;
public ProductService(ProductRepository productRepository, ValidatorUtil validatorUtil){
this.productRepository = productRepository;
this.validatorUtil = validatorUtil;
}
@Transactional
public Product addProduct(String productName){
final Product product = new Product(productName);
validatorUtil.validate(product);
productRepository.save(product);
return product;
}
@Transactional()
public Product getProduct(Long id){
return productRepository.findById(id).orElseThrow(() -> new ProductNotFoundException(id));
}
@Transactional
public List<Product> getAllProducts(){
return productRepository.findAll();
}
@Transactional
public List<Product> getAllProductsWithStores(){
return productRepository.findAllProductsWithStores().stream().toList();
}
@Transactional
public List<Product> getAllProductsWithoutStores(){
return productRepository.findAllProductsWithoutStores().stream().toList();
}
@Transactional
public Product updateProduct(Long id, String productName){
final Product product = getProduct(id);
product.setName(productName);
validatorUtil.validate(product);
return productRepository.save(product);
}
@Transactional
public Product deleteProduct(Long id){
final Product product = getProduct(id);
Store store = product.getStore();
if (store != null) store.getProducts().remove(product);
productRepository.delete(product);
return product;
}
@Transactional
public void deleteAllProducts(){
//for (var product:
// getAllProducts()) {
// product.removeStore();
// product.removeOrders();
//}
productRepository.deleteAll();
}
}

View File

@ -0,0 +1,115 @@
package com.example.ipLab.StoreDataBase.Service;
import com.example.ipLab.StoreDataBase.Exceptions.StoreNotFoundException;
import com.example.ipLab.StoreDataBase.Model.Product;
import com.example.ipLab.StoreDataBase.Model.Store;
import com.example.ipLab.StoreDataBase.Repositories.StoreRepository;
import com.example.ipLab.StoreDataBase.util.validation.ValidatorUtil;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityNotFoundException;
import jakarta.persistence.PersistenceContext;
import jakarta.transaction.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class StoreService {
private final StoreRepository storeRepository;
private final ValidatorUtil validatorUtil;
private ProductService productService;
public StoreService(StoreRepository storeRepository, ValidatorUtil validatorUtil, ProductService productService){
this.storeRepository = storeRepository;
this.validatorUtil = validatorUtil;
this.productService = productService;
}
@Transactional
public Store addStore(String storeName){
final Store store = new Store(storeName);
validatorUtil.validate(store);
storeRepository.save(store);
return store;
}
@Transactional()
public Store getStore(Long id){
return storeRepository.findById(id).orElseThrow(() -> new StoreNotFoundException(id));
}
@Transactional
public List<Store> getAllStores(){
return storeRepository.findAll();
}
@Transactional
public Store updateStore(Long id, String storeName){
final Store store = getStore(id);
store.setStoreName(storeName);
validatorUtil.validate(store);
return storeRepository.save(store);
}
@Transactional
public Store deleteStore(Long id){
final Store store = getStore(id);
storeRepository.delete(store);
return store;
}
@Transactional
public void deleteAllStores(){
//for (var store:
// getAllStores()) {
// store.removeProducts();
//}
storeRepository.deleteAll();
}
//product section
@Transactional
public Product addProduct(Long storeId, Long productId){
Store store = getStore(storeId);
Product product = productService.getProduct(productId);
store.AddProduct(product);
storeRepository.save(store);
return product;
}
@Transactional()
public Product getProductFromStore(Long productId, Long storeId){
Store store = getStore(storeId);
var prFind = store.getProducts().stream().filter(pr -> pr.getId().equals(productId)).findFirst();
if (prFind.isPresent()) {
return prFind.get();
}
else throw new EntityNotFoundException(String.format("Product with id = %s isn't found in store with id = %s", productId, storeId));
}
@Transactional
public List<Product> getAllProductsFromStore(Long storeId) {
Store store = getStore(storeId);
return store.getProducts();
}
// @Transactional
// public Product deleteProductFromStore(Long storeId, Long productId){
// Store store = getStore(storeId);
// Product product = getProductFromStore(productId, storeId);
// store.getProducts().remove(product);
// product.setStore(null);
// return product;
// }
// @Transactional
// public void deleteAllProducts(Long storeId){
// Store store = getStore(storeId);
// List<Product> storeProducts = store.getProducts();
// for (Product pr:
// storeProducts) {
// pr.setStore(null);
// store.getProducts().remove(pr);
// }
// }
}

View File

@ -0,0 +1,97 @@
package com.example.ipLab.StoreDataBase.Service;
import com.example.ipLab.StoreDataBase.Configurations.jwt.JwtException;
import com.example.ipLab.StoreDataBase.Configurations.jwt.JwtsProvider;
import com.example.ipLab.StoreDataBase.DTO.UserDTO;
import com.example.ipLab.StoreDataBase.Exceptions.CustomerNotFoundException;
import com.example.ipLab.StoreDataBase.Exceptions.UserNotFoundException;
import com.example.ipLab.StoreDataBase.Model.CustomUser;
import com.example.ipLab.StoreDataBase.Model.Customer;
import com.example.ipLab.StoreDataBase.Model.User;
import com.example.ipLab.StoreDataBase.Model.UserRole;
import com.example.ipLab.StoreDataBase.Repositories.UserRepository;
import com.example.ipLab.StoreDataBase.util.validation.ValidationException;
import com.example.ipLab.StoreDataBase.util.validation.ValidatorUtil;
import jakarta.transaction.Transactional;
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 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;
private final ValidatorUtil validatorUtil;
private final JwtsProvider jwtProvider;
public UserService(UserRepository userRepository,
PasswordEncoder passwordEncoder,
ValidatorUtil validatorUtil,
JwtsProvider jwtProvider) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
this.validatorUtil = validatorUtil;
this.jwtProvider = jwtProvider;
}
@Transactional
public User addUser(String login, String password, String passwordConfirm, UserRole role, Long userId){
if (getUserByLogin(login) != null){
throw new ValidationException(String.format("User with login %s already exists", login));
}
if (!Objects.equals(password, passwordConfirm)) {
throw new ValidationException("Passwords not equals");
}
final User user = new User(login, passwordEncoder.encode(password), role, userId);
validatorUtil.validate(user);
return userRepository.save(user);
}
@Transactional
public User getUserByLogin(String login){
return userRepository.findOneByLogin(login);
}
@Transactional
public List<User> getAllUsers(){
return userRepository.findAll();
}
public UserDetails loadUserByToken(String token) throws UsernameNotFoundException {
if (!jwtProvider.validateToken(token)) {
throw new JwtException("Bad token");
}
final String userLogin = jwtProvider.getLogin(token);
if (userLogin.isEmpty()) {
throw new JwtException("Token is not contain Login");
}
return loadUserByUsername(userLogin);
}
public String loginAndGetToken(UserDTO userDto) {
final User user = getUserByLogin(userDto.getLogin());
if (user == null) {
throw new UserNotFoundException(userDto.getLogin());
}
if (!passwordEncoder.matches(userDto.getPassword(), user.getPassword())) {
throw new UserNotFoundException(user.getLogin());
}
return jwtProvider.generateToken(user.getLogin(), user.getRole().name());
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
final User userEntity = getUserByLogin(username);
if (userEntity == null) {
throw new UsernameNotFoundException(username);
}
return new CustomUser(
userEntity.getLogin(), userEntity.getPassword(), Collections.singleton(userEntity.getRole()), userEntity.getUserId(), userEntity.getRole());
}
}

View File

@ -0,0 +1,52 @@
package com.example.ipLab.StoreDataBase.util.error;
import com.example.ipLab.StoreDataBase.Exceptions.CustomerNotFoundException;
import com.example.ipLab.StoreDataBase.Exceptions.OrderedNotFoundException;
import com.example.ipLab.StoreDataBase.Exceptions.ProductNotFoundException;
import com.example.ipLab.StoreDataBase.Exceptions.StoreNotFoundException;
import com.example.ipLab.StoreDataBase.util.validation.ValidationException;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
import java.nio.file.AccessDeniedException;
import java.util.stream.Collectors;
@ControllerAdvice(annotations = RestController.class)
public class AdviceController {
@ExceptionHandler({
CustomerNotFoundException.class,
OrderedNotFoundException.class,
ProductNotFoundException.class,
StoreNotFoundException.class
})
public ResponseEntity<Object> handleException(Throwable e){
return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Object> handleBindException(MethodArgumentNotValidException e) {
final ValidationException validationException = new ValidationException(
e.getBindingResult().getAllErrors().stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage)
.collect(Collectors.toSet()));
return handleException(validationException);
}
@ExceptionHandler({
AccessDeniedException.class
})
public ResponseEntity<Object> handleAccessDeniedException(Throwable e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.FORBIDDEN);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<Object> handleUnknownException(Throwable e) {
e.printStackTrace();
return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}

View File

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

View File

@ -0,0 +1,30 @@
package com.example.ipLab.StoreDataBase.util.validation;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;
import org.springframework.stereotype.Component;
import java.util.Set;
import java.util.stream.Collectors;
@Component
public class ValidatorUtil {
private final Validator validator;
public ValidatorUtil(){
try (ValidatorFactory factory = Validation.buildDefaultValidatorFactory()){
this.validator = factory.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

@ -2,10 +2,18 @@ package com.example.ipLab;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration @Configuration
public class WebConfiguration implements WebMvcConfigurer { public class WebConfiguration implements WebMvcConfigurer {
public static final String REST_API = "/api";
@Override
public void addViewControllers(ViewControllerRegistry registry) {
WebMvcConfigurer.super.addViewControllers(registry);
registry.addViewController("login");
}
@Override @Override
public void addCorsMappings(CorsRegistry registry){ public void addCorsMappings(CorsRegistry registry){
registry.addMapping("/**").allowedMethods("*"); registry.addMapping("/**").allowedMethods("*");

View File

@ -1,39 +0,0 @@
package com.example.ipLab.controllers;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CalcController {
@GetMapping("/second")
public int second(@RequestParam(value = "num") int num){
return num*num;
}
@GetMapping("/root")
public double root(@RequestParam(value = "num") int num){
return Math.sqrt(num);
}
@GetMapping("/fact")
public int fact(@RequestParam(value = "num") int num){
int res = 1;
for (int i = 2; i <= num; i++) {
res *= i;
}
return res;
}
@GetMapping("/digit")
public int digit(@RequestParam(value = "num") int num){
if (num < 0) num *= -1;
int sum = 0;
while (num > 0) {
sum += num % 10;
num /= 10;
}
return sum;
}
}

View File

@ -1 +1,14 @@
spring.main.banner-mode=off
#server.port=8080
spring.datasource.url=jdbc:h2:file:./data
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=update
spring.h2.console.enabled=true
spring.h2.console.settings.trace=false
spring.h2.console.settings.web-allow-others=false
jwt.dev-token=my-secret-jwt
jwt.dev=true
jwt.secret = my-secret-jwt

View File

@ -0,0 +1,284 @@
header{
background-color: #9094c1;
flex-direction: row;
}
header nav{
font-family: Segoe UI;
font-weight: bold;
font-size: 42px;
}
header nav a{
color: inherit;
}
header nav a:hover{
text-decoration: underline;
}
.navigationCaption{
font-family: Segoe UI;
font-weight: bold;
font-size: 42px;
}
.headNav{
color: inherit;
}
a{
color: inherit;
text-decoration: none;
}
td, th{
border: 1px solid black;
font-family: Segoe UI;
text-align: center;
font-size: 28px;
}
table tbody td a:hover{
text-decoration: underline;
color: inherit;
}
footer{
background-color: #707be5;
max-height: 110px;
}
.mainPage a:hover{
text-decoration: underline;
color: inherit;
}
.popularCaption{
font-family: Segoe UI;
font-size: 24px;
}
.discountsCaption{
font-family: Segoe UI;
font-size: 24px;
}
.item{
font-family: Segoe UI;
font-size: 18px;
}
.item img{
width: 200px;
height: 200px;
}
.tableMy table caption{
font-family: Segoe UI;
font-weight: bold;
font-size: 45px;
}
.tableMy table tbody td a:hover{
text-decoration: underline;
color: inherit !important;
}
.tableCart table caption{
font-family: Segoe UI;
font-weight: bold;
font-size: 32px;
}
.cartInfo{
margin-top: 320px;
margin-right: 400px;
font-family: Segoe UI;
font-size: 45px;
}
.buttonOrder{
background-color: #4d89d9;
}
.itemCaption{
font-family: Segoe UI;
font-size: 32px;
}
#itemPhoto{
margin-left: 50px;
}
.itemInfo{
font-family: Segoe UI;
font-size: 45px;
margin-left: 85px;
}
.itemInfo li{
list-style-type: none;
}
.buttonAdd{
font-family: Segoe UI;
font-size: 45px;
background-color: #4d89d9;
margin-left: 35px;
}
.companyName{
font-family: Segoe UI;
font-size: 45px;
}
.longText{
font-family: Segoe UI;
font-size: 25px;
}
#logoName{
font-family: Rockwell Condensed;
font-size: 64px;
font-weight: bold;
font-stretch: condensed;
text-decoration: none;
}
#logoName a:hover{
text-decoration: none;
color: inherit;
}
.footerLeft{
margin-bottom: 10px;
font-family: Segoe UI;
font-size: 16px;
}
.footerBottom{
font-family: Segoe UI;
font-size: 28px;
}
.hide{
display: none;
}
.active{
display: block;
}
.active img{
width: 200px;
height: 100px;
}
@media (max-width: 1080px){
header{
flex-direction: column;
}
header nav{
text-align: center;
}
.headerContainer{
flex-direction: column !important;
}
.itemContent{
flex-direction: column !important;
justify-content: center !important;
}
#itemPhoto{
margin-left: auto !important;
margin-right: auto ;
}
.itemInfo{
margin-bottom: 10px !important;
margin-left: 10px!important;
}
#cartContainer{
flex-direction: column !important;
}
.cartInfo{
margin-top: 0px !important;
margin-left: 5px;
margin-right: auto;
margin-bottom: 10px;
}
#tableCart{
width: auto;
}
.mainPage{
flex-direction: column !important;
justify-content: center;
}
.tablePopular{
margin-left: auto !important;
margin-right: auto !important;
}
.tableDiscounts{
margin-top: 30px;
margin-left: auto !important;
margin-right: auto !important;
}
}
@media (max-width: 767px){
.tableMy table thead th{
font-size: 12px !important;
}
.tableMy table tr td{
font-size: 12px !important;
}
.tableCart table thead th{
font-size: 18px !important;
}
.tableCart table tr td{
font-size: 18px !important;
}
.cartInfo{
font-size: 18px !important;
}
.itemInfo{
font-size: 18px !important;
}
.buttonAdd{
font-size: 18px !important
}
.footerLeft{
font-size: 12px !important;
}
.footerBottom{
font-size: 16px !important;
}
.footerRight img{
width: 55px;
height: 27px;
}
.mainPage img{
width: 100px !important;
height: 100px !important;
}
.popularCaption{
font-size: 18px !important;
}
.discountsCaption{
font-size: 18px !important;
}
#itemIcon{
width: 250px !important;
height: 250px !important;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

View File

@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
</head>
<body>
<div sec:authorize="hasRole('ROLE_ADMIN')" layout:fragment="content">
<div th:text="${errors}" class="margin-bottom alert-danger"></div>
<form action="#" th:action="@{/store/add}" method="post">
<div class="mb-3">
<label for="store" class="form-label">Покупатель</label>
<select id="store" class="form-select" th:name="storeId">
<option th:each="value: ${stores}" th:value="${value.id}" th:selected="${storeId} == ${value}">
<span th:text="${value.storeName}"></span>
</option>
</select>
</div>
<div class="mb-3">
<label for="product" class="form-label">Продукт</label>
<select id="product" class="form-select" th:name="productId">
<option th:each="value: ${products}" th:value="${value.id}" th:selected="${productId} == ${value}">
<span th:text="${value.productName}"></span>
</option>
</select>
</div>
<div class="mb-3">
<button type="submit" class="btn btn-primary button-fixed">
<span>Добавить</span>
</button>
</div>
</form>
</div>
</body>
</html>

View File

@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<div th:text="${errors}" class="margin-bottom alert-danger"></div>
<form action="#" th:action="@{/customer/{id}(id=${id})}" th:object="${customerDTO}" method="post">
<div class="mb-3">
<label for="lastName" class="form-label">Фамилия</label>
<input type="text" class="form-control" id="lastName" th:field="${customerDTO.lastName}" required="true">
</div>
<div class="mb-3">
<label for="firstName" class="form-label">Имя</label>
<input type="text" class="form-control" id="firstName" th:field="${customerDTO.firstName}" required="true">
</div>
<div class="mb-3">
<label for="middleName" class="form-label">Отчество</label>
<input type="text" class="form-control" id="middleName" th:field="${customerDTO.middleName}" required="true">
</div>
<div class="mb-3">
<button type="submit" class="btn btn-primary button-fixed">
<span th:if="${id == null}">Добавить</span>
<span th:if="${id != null}">Обновить</span>
</button>
<a class="btn btn-secondary button-fixed" th:href="@{/customer}">
Назад
</a>
</div>
</form>
</div>
</body>
</html>

View File

@ -0,0 +1,65 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<div sec:authorize="hasRole('ROLE_ADMIN')">
<div>
<a class="btn btn-success button-fixed"
th:href="@{/customer/edit/}">
<i class="fa-solid fa-plus"></i> Добавить
</a>
</div>
<div class="table-responsive">
<table class="table table-success table-hover">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">ID</th>
<th scope="col">Фамилия</th>
<th scope="col">Имя</th>
<th scope="col">Отчество</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr th:each="customer, iterator: ${customers}">
<th scope="row" th:text="${iterator.index} + 1"/>
<td th:text="${customer.Id}"/>
<td th:text="${customer.lastName}"/>
<td th:text="${customer.firstName}"/>
<td th:text="${customer.middleName}"/>
<td style="width: 10%">
<div class="btn-group" role="group" aria-label="Basic example">
<a class="btn btn-warning button-fixed button-sm"
th:href="@{/customer/edit/{id}(id=${customer.id})}">
<i class="fa fa-pencil" aria-hidden="true"></i> Изменить
</a>
<button type="button" class="btn btn-danger button-fixed button-sm"
th:attr="onclick=|confirm('Удалить запись?') && document.getElementById('remove-${customer.id}').click()|">
<i class="fa fa-trash" aria-hidden="true"></i> Удалить
</button>
</div>
<form th:action="@{/customer/delete/{id}(id=${customer.id})}" method="post">
<button th:id="'remove-' + ${customer.id}" type="submit" style="display: none">
Удалить
</button>
</form>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div sec:authorize="hasRole('ROLE_USER')">
<div>
<h2>Forbidden</h2>
<a href="/">На главную</a>
</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,59 @@
<!DOCTYPE html>
<html lang="ru"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<meta charset="UTF-8"/>
<title>IP Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="icon" href="/favicon.ico">
<script type="text/javascript" src="/webjars/bootstrap/5.1.3/js/bootstrap.bundle.min.js"></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/styleSite.css"/>
</head>
<body>
<header>
<div class="d-flex flex-row headerContainer">
<nav class="navbar navbar-expand-md">
<div class="container-fluid" id="navigationMenu">
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="d-flex flex-row ml-3 ms-3 mt-auto mb-auto align-items-center">
<a>
<img src="/img/logo.png" alt="*" width="60" height="60" class="align-text-top"/>
</a>
<div id="logoName">
<a href="/">boxStore</a>
</div>
</div>
<div class="navbar-collapse collapse justify-content-end" id="navbarNav">
<ul class="navbar-nav" id="headerNavigation">
<a sec:authorize="hasRole('ROLE_ADMIN')" class="nav-link headNav" href="/customer"
th:classappend="${#strings.equals(activeLink, '/customer')} ? 'active' : ''">Клиенты</a>
<a class="nav-link headNav" href="/store"
th:classappend="${#strings.equals(activeLink, '/store')} ? 'active' : ''">Магазины</a>
<a class="nav-link headNav" href="/product"
th:classappend="${#strings.equals(activeLink, '/product')} ? 'active' : ''">Товары</a>
<a class="nav-link headNav" href="/order"
th:classappend="${#strings.equals(activeLink, '/order')} ? 'active' : ''">Заказы</a>
<a sec:authorize="hasRole('ROLE_ADMIN')" class="nav-link headNav" href="/store/addToStore"
th:classappend="${#strings.equals(activeLink, '/order')} ? 'active' : ''">Доставка</a>
<a sec:authorize="!isAuthenticated()" class="nav-link headNav" href="/login">Войти</a>
<a sec:authorize="isAuthenticated()" class="nav-link headNav" href="/logout">Выйти</a>
</ul>
</div>
</div>
</nav>
</div>
</header>
<div class="container-fluid">
<div class="container container-padding" layout:fragment="content">
</div>
</div>
</body>
<th:block layout:fragment="scripts">
</th:block>
</html>

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<div><span th:text="${error}"></span></div>
<a href="/">На главную</a>
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<h2>Добро пожаловать, <span sec:authentication="name"></span>!</h2>
</div>
</body>
</html>

View File

@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
</head>
<body>
<div class="container-fluid" 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>
<div class="row justify-content-center align-items-center vh-100">
<div class="col-sm-6 col-md-4">
<div class="card">
<div class="card-body">
<h5 class="card-title">Авторизация</h5>
<form th:action="@{/login}" method="post">
<div class="mb-3">
<label htmlFor="login">Логин</label>
<input type="text" name="username" id="username" class="form-control"
placeholder="Логин" required="true" autofocus="true"/>
</div>
<div class="mb-3">
<label htmlFor="login">Пароль</label>
<input type="password" name="password" id="password" class="form-control"
placeholder="Пароль" required="true"/>
</div>
<button type="submit" class="btn btn-primary button-fixed">Войти</button>
</form>
</div>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,42 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<div th:text="${errors}" class="margin-bottom alert-danger"></div>
<form action="#" th:action="@{/order/}" th:object="${orderDTO}" method="post">
<div class="mb-3">
<label for="customer" class="form-label">Покупатель</label>
<select id="customer" class="form-select" th:name="customerId">
<option th:each="value: ${customers}" th:value="${value.id}" th:selected="${customerId} == ${value}">
<span th:text="${value.customerFIO}"></span>
</option>
</select>
</div>
<div class="mb-3">
<label for="product" class="form-label">Продукт</label>
<select id="product" class="form-select" th:name="productId">
<option th:each="value: ${products}" th:value="${value.id}" th:selected="${productId} == ${value}">
<span th:text="${value.productName}"></span>
</option>
</select>
</div>
<div class="mb-3">
<label for="quantity" class="form-label">Количество</label>
<input type="text" class="form-control" id="quantity" th:field="${orderDTO.quantity}" required="true">
</div>
<div class="mb-3">
<button type="submit" class="btn btn-primary button-fixed">
<span>Добавить</span>
</button>
<a class="btn btn-secondary button-fixed" th:href="@{/order}">
Назад
</a>
</div>
</form>
</div>
</body>
</html>

View File

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<div sec:authorize="hasRole('ROLE_ADMIN')">
<a class="btn btn-success button-fixed"
th:href="@{/order/edit/}">
<i class="fa-solid fa-plus"></i> Добавить
</a>
</div>
<div class="table-responsive">
<table class="table table-success table-hover">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">ФИО покупателя</th>
<th scope="col">Магазин</th>
<th scope="col">Товар</th>
</tr>
</thead>
<tbody>
<tr th:each="order, iterator: ${orders}">
<th scope="row" th:text="${iterator.index} + 1"/>
<td th:text="${order.customerFIO}"/>
<td th:text="${order.storeName}"/>
<td th:text="${order.productName}"/>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<div th:text="${errors}" class="margin-bottom alert-danger"></div>
<form action="#" th:action="@{/product/{id}(id=${id})}" th:object="${productDTO}" method="post">
<div class="mb-3">
<label for="productName" class="form-label">Название товара</label>
<input type="text" class="form-control" id="productName" th:field="${productDTO.productName}" required="true">
</div>
<div class="mb-3">
<button type="submit" class="btn btn-primary button-fixed">
<span th:if="${id == null}">Добавить</span>
<span th:if="${id != null}">Обновить</span>
</button>
<a class="btn btn-secondary button-fixed" th:href="@{/product}">
Назад
</a>
</div>
</form>
</div>
</body>
</html>

View File

@ -0,0 +1,53 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<div sec:authorize="hasRole('ROLE_ADMIN')">
<a class="btn btn-success button-fixed "
th:href="@{/product/edit/}">
<i class="fa-solid fa-plus"></i> Добавить
</a>
</div>
<div class="table-responsive">
<table class="table table-success table-hover">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Название товара</th>
<th scope="col">Название магазина</th>
<th sec:authorize="hasRole('ROLE_ADMIN')" scope="col"></th>
</tr>
</thead>
<tbody>
<tr th:each="product, iterator: ${products}">
<th scope="row" th:text="${iterator.index} + 1"/>
<td th:text="${product.productName}"/>
<td th:text="${product.storeName}"/>
<td sec:authorize="hasRole('ROLE_ADMIN')" style="width: 10%">
<div class="btn-group" role="group" aria-label="Basic example">
<a class="btn btn-warning button-fixed button-sm"
th:href="@{/product/edit/{id}(id=${product.id})}">
<i class="fa fa-pencil" aria-hidden="true"></i> Изменить
</a>
<button type="button" class="btn btn-danger button-fixed button-sm"
th:attr="onclick=|confirm('Удалить запись?') && document.getElementById('remove-${product.id}').click()|">
<i class="fa fa-trash" aria-hidden="true"></i> Удалить
</button>
</div>
<form th:action="@{/product/delete/{id}(id=${product.id})}" method="post">
<button th:id="'remove-' + ${product.id}" type="submit" style="display: none">
Удалить
</button>
</form>
</td>
</tr>
</tbody>
</table>
</div>
</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="${LoginDTO}" method="post">
<div class="mb-3">
<input type="text" class="form-control" th:field="${LoginDTO.login}"
placeholder="Логин" required="true" autofocus="true" maxlength="64"/>
</div>
<div class="mb-3">
<input type="password" class="form-control" th:field="${LoginDTO.password}"
placeholder="Пароль" required="true" minlength="6" maxlength="64"/>
</div>
<div class="mb-3">
<input type="password" class="form-control" th:field="${LoginDTO.passwordConfirm}"
placeholder="Пароль (подтверждение)" required="true" minlength="6" 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>

View File

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<div th:text="${errors}" class="margin-bottom alert-danger"></div>
<form action="#" th:action="@{/store/{id}(id=${id})}" th:object="${storeDTO}" method="post">
<div class="mb-3">
<label for="storeName" class="form-label">Название магазина</label>
<input type="text" class="form-control" id="storeName" th:field="${storeDTO.storeName}" required="true">
</div>
<div class="mb-3">
<button type="submit" class="btn btn-primary button-fixed">
<span th:if="${id == null}">Добавить</span>
<span th:if="${id != null}">Обновить</span>
</button>
<a class="btn btn-secondary button-fixed" th:href="@{/store}">
Назад
</a>
</div>
</form>
</div>
</body>
</html>

View File

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<div sec:authorize="hasRole('ROLE_ADMIN')">
<a class="btn btn-success button-fixed"
th:href="@{/store/edit/}">
<i class="fa-solid fa-plus"></i> Добавить
</a>
</div>
<div class="table-responsive">
<table class="table table-success table-hover">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Название магазина</th>
<th sec:authorize="hasRole('ROLE_ADMIN')" scope="col"></th>
</tr>
</thead>
<tbody>
<tr th:each="store, iterator: ${stores}">
<th scope="row" th:text="${iterator.index} + 1"/>
<td th:text="${store.storeName}"/>
<td sec:authorize="hasRole('ROLE_ADMIN')" style="width: 10%">
<div class="btn-group" role="group" aria-label="Basic example">
<a class="btn btn-warning button-fixed button-sm"
th:href="@{/store/edit/{id}(id=${store.id})}">
<i class="fa fa-pencil" aria-hidden="true"></i> Изменить
</a>
<button type="button" class="btn btn-danger button-fixed button-sm"
th:attr="onclick=|confirm('Удалить запись?') && document.getElementById('remove-${store.id}').click()|">
<i class="fa fa-trash" aria-hidden="true"></i> Удалить
</button>
</div>
<form th:action="@{/store/delete/{id}(id=${store.id})}" method="post">
<button th:id="'remove-' + ${store.id}" type="submit" style="display: none">
Удалить
</button>
</form>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="table-responsive">
<table class="table table-success table-hover">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Логин</th>
<th scope="col">Роль</th>
</tr>
</thead>
<tbody>
<tr th:each="user, iterator: ${users}">
<th scope="row" th:text="${iterator.index} + 1"/>
<td th:text="${user.login}"/>
<td th:text="${user.role}"/>
</tr>
</tbody>
</table>
</div>
</body>
</html>

View File

@ -1,13 +0,0 @@
package com.example.ipLab;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class IpLabApplicationTests {
@Test
void contextLoads() {
}
}

View File

@ -0,0 +1,158 @@
package com.example.ipLab;
import com.example.ipLab.StoreDataBase.Model.Customer;
import com.example.ipLab.StoreDataBase.Model.Ordered;
import com.example.ipLab.StoreDataBase.Model.Product;
import com.example.ipLab.StoreDataBase.Model.Store;
import com.example.ipLab.StoreDataBase.Service.CustomerService;
import com.example.ipLab.StoreDataBase.Service.OrderService;
import com.example.ipLab.StoreDataBase.Service.ProductService;
import com.example.ipLab.StoreDataBase.Service.StoreService;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.ArrayList;
import java.util.List;
@SpringBootTest
public class JpaTests {
@Autowired
OrderService orderService;
@Autowired
CustomerService customerService;
@Autowired
StoreService storeService;
@Autowired
ProductService productService;
@Test
void testStore(){
orderService.deleteAllOrders();
customerService.deleteAllCustomers();
productService.deleteAllProducts();
storeService.deleteAllStores();
Store store = storeService.addStore("example");
Assertions.assertEquals("example", store.getStoreName());
Assertions.assertEquals("example", storeService.getStore(store.getId()).getStoreName());
storeService.updateStore(store.getId(), "newName");
Assertions.assertEquals("newName", storeService.getStore(store.getId()).getStoreName());
Assertions.assertEquals("newName", storeService.deleteStore(store.getId()).getStoreName());
orderService.deleteAllOrders();
customerService.deleteAllCustomers();
productService.deleteAllProducts();
storeService.deleteAllStores();
}
@Test
void testCustomer(){
orderService.deleteAllOrders();
var list = orderService.getAllOrders();
customerService.deleteAllCustomers();
productService.deleteAllProducts();
storeService.deleteAllStores();
Customer c = customerService.addCustomer("1", "2", "3");
Assertions.assertEquals("2", c.getFirstName());
Assertions.assertEquals("2", customerService.getCustomer(c.getId()).getFirstName());
Assertions.assertEquals("1", customerService.updateCustomer(c.getId(), c.getLastName(), "1", c.getMiddleName()).getFirstName());
Assertions.assertEquals("1", customerService.deleteCustomer(c.getId()).getFirstName());
orderService.deleteAllOrders();
customerService.deleteAllCustomers();
productService.deleteAllProducts();
storeService.deleteAllStores();
}
@Test
void testProduct(){
orderService.deleteAllOrders();
customerService.deleteAllCustomers();
productService.deleteAllProducts();
storeService.deleteAllStores();
Store store = storeService.addStore("example");
Assertions.assertEquals("example", store.getStoreName());
Product p = productService.addProduct("product");
Assertions.assertEquals("product", p.getName());
Assertions.assertEquals("product", storeService.addProduct(store.getId(), p.getId()).getName());
Assertions.assertEquals("product", storeService.getProductFromStore(p.getId(), store.getId()).getName());
orderService.deleteAllOrders();
customerService.deleteAllCustomers();
productService.deleteAllProducts();
storeService.deleteAllStores();
}
@Test
void testOrder(){
orderService.deleteAllOrders();
customerService.deleteAllCustomers();
productService.deleteAllProducts();
storeService.deleteAllStores();
Store store = storeService.addStore("example");
Assertions.assertEquals("example", store.getStoreName());
Product p = productService.addProduct("product");
storeService.addProduct(store.getId(), p.getId());
Assertions.assertEquals("product", p.getName());
Customer c = customerService.addCustomer("1", "2", "3");
Assertions.assertEquals("2", c.getFirstName());
Ordered order = orderService.addOrder(p, c, 5);
Assertions.assertEquals("5", Integer.toString(order.getQuantity()));
Assertions.assertEquals("5", Integer.toString(orderService.getOrder(order.getId()).getQuantity()));
Assertions.assertEquals("6", Integer.toString(orderService.updateOrder(order.getId(), 6).getQuantity()));
Assertions.assertEquals("6", Integer.toString(orderService.deleteOrder(order.getId()).getQuantity()));
orderService.deleteAllOrders();
customerService.deleteAllCustomers();
productService.deleteAllProducts();
storeService.deleteAllStores();
}
@Test
void FilterOrderTest(){
orderService.deleteAllOrders();
customerService.deleteAllCustomers();
productService.deleteAllProducts();
storeService.deleteAllStores();
Store store = storeService.addStore("example");
Assertions.assertEquals("example", store.getStoreName());
Product p1 = productService.addProduct("product");
Product p2 = productService.addProduct("product2");
storeService.addProduct(store.getId(), p1.getId());
Assertions.assertEquals("product", p1.getName());
storeService.addProduct(store.getId(), p2.getId());
Assertions.assertEquals("product2", p2.getName());
Customer c = customerService.addCustomer("1", "2", "3");
Assertions.assertEquals("2", c.getFirstName());
Ordered order1 = orderService.addOrder(p1, c, 0);
Ordered order2 = orderService.addOrder(p2, c, 6);
Ordered order3 = orderService.addOrder(p1, c, 2);
Ordered order4 = orderService.addOrder(p2, c, 2);
Ordered order5 = orderService.addOrder(p1, c, 3);
//List<Ordered> expectedResult = new ArrayList<>();
//expectedResult.add(order3);
//expectedResult.add(order5);
//orderService.getAllOrders();
//Assertions.assertEquals(expectedResult, orderService.getOrdersWithProduct(p1.getId(), 1, 5));
orderService.deleteAllOrders();
customerService.deleteAllCustomers();
productService.deleteAllProducts();
storeService.deleteAllStores();
}
}

View File

@ -0,0 +1,6 @@
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=create-drop

BIN
frontend/AppStore.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
frontend/GooglePlay.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
frontend/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,25 +1,17 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="ru" class="h-100"> <html lang="ru" class="h-100">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<script src ="node_modules/bootstrap/dist/js/bootstrap.min.js"></script> <script src="/node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
<script src ="scripts/calc.js"></script> <link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.min.css">
<link href="node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" /> <link rel="stylesheet" href="/node_modules/@fortawesome/fontawesome-free/css/all.min.css">
<link href="node_modules/@fortawesome/fontawesome-free/css/all.min.css" rel="stylesheet" /> <title>IP lab</title>
<title>Calc</title> </head>
<link rel="stylesheet" type="text/css" href="style.css"> <body class="h-100 bg-light m-0">
</head> <article class="h-100">
<body class="h-100"> <div id="app" class="h-100"></div>
<div class="d-flex flex-column align-content-center flex-wrap"> <script type="module" src="/src/main.jsx"></script>
<div class="input-group p-3"> </article>
<input id="numberInput" type="number" class="form-control" placeholder="Введите число..." required> </body>
<button class="btn btn-outline-secondary" onclick="calcSecond()" type="button">^2</button>
<button class="btn btn-outline-secondary" onclick="calcRoot()" type="button"></button>
<button class="btn btn-outline-secondary" onclick="calcFact()" type="button">!</button>
<button class="btn btn-outline-secondary" onclick="calcDigit()" type="button">Сумма цифр</button>
</div>
<a id="responseField" class="m-3"></a>
</div>
</body>
</html> </html>

BIN
frontend/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

4391
frontend/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,19 +1,26 @@
{ {
"name": "ip_lab", "name": "test",
"version": "1.0.0", "version": "1.0.0",
"description": "My project for IP lab", "type": "module",
"main": "index.html",
"scripts": { "scripts": {
"start": "http-server -p 3000 ./", "dev": "vite",
"test": "echo \"Error: no test specified\" && exit 1" "start": "npm-run-all --parallel dev",
"build": "vite build",
"preview": "vite preview"
}, },
"author": "Abazov Andrey",
"license": "ISC",
"dependencies": { "dependencies": {
"bootstrap": "5.2.1", "react": "^18.2.0",
"@fortawesome/fontawesome-free": "6.2.0" "react-dom": "^18.2.0",
"react-router-dom": "^6.4.4",
"axios": "^1.1.3",
"bootstrap": "^5.2.2",
"@fortawesome/fontawesome-free": "^6.2.1"
}, },
"devDependencies": { "devDependencies": {
"http-server": "14.1.1" "@types/react": "^18.0.24",
"@types/react-dom": "^18.0.8",
"vite": "^3.2.3",
"@vitejs/plugin-react": "^2.2.0",
"npm-run-all": "^4.1.5"
} }
} }

View File

@ -1,70 +0,0 @@
function calcSecond(){
var num = document.getElementById("numberInput").value;
fetch("http://127.0.0.1:8080/second?num=" + num)
.then(function(response) {
if (response.status != 200){
return response.text().then(text => {throw new Error(text)});
}
return response.text();
})
.then((response) => {
document.getElementById("responseField").innerHTML = "Результат: " + response;
})
.catch(err => {document.getElementById("responseField").innerHTML = "Ошибка: " + err;})
}
function calcRoot(){
var num = document.getElementById("numberInput").value;
if (num < 0) {
document.getElementById("responseField").innerHTML = "Результат: введите НЕОТРИЦАТЕЛЬНОЕ число";
return;
}
fetch("http://127.0.0.1:8080/root?num=" + num)
.then((response) => {
if (response.status != 200){
return response.text().then(text => {throw new Error(text)});
}
return response.text();
})
.then((response) => {
console.log(response);
document.getElementById("responseField").innerHTML = "Результат: " + response;
})
.catch(err => {document.getElementById("responseField").innerHTML = "Ошибка: " + err;})
}
function calcFact(){
var num = document.getElementById("numberInput").value;
if (num < 0) {
document.getElementById("responseField").innerHTML = "Результат: введите НЕОТРИЦАТЕЛЬНОЕ число";
return;
}
fetch("http://127.0.0.1:8080/fact?num=" + num)
.then((response) => {
if (response.status != 200){
return response.text().then(text => {throw new Error(text)});
}
return response.text();
})
.then((response) => {
console.log(response);
document.getElementById("responseField").innerHTML = "Результат: " + response;
})
.catch(err => {document.getElementById("responseField").innerHTML = "Ошибка: " + err;})
}
function calcDigit(){
var num = document.getElementById("numberInput").value;
fetch("http://127.0.0.1:8080/digit?num=" + num)
.then((response) => {
if (response.status != 200){
return response.text().then(text => {throw new Error(text)});
}
return response.text();
})
.then((response) => {
console.log(response);
document.getElementById("responseField").innerHTML = "Результат: " + response;
})
.catch(err => {document.getElementById("responseField").innerHTML = "Ошибка: " + err;})
}

69
frontend/src/App.jsx Normal file
View File

@ -0,0 +1,69 @@
import { useRoutes, Outlet, BrowserRouter } from 'react-router-dom';
import { useState, useEffect } from 'react';
import Header from './components/common/Header';
import CustomerPage from './components/pages/customerPage';
import StorePage from './components/pages/storePage';
import ProductPage from './components/pages/productPage';
import OrderPage from './components/pages/orderPage';
import AddToStorePage from './components/pages/addToStorePage';
import LoginPage from './components/pages/loginPage';
import Logout from './components/pages/logout';
import ForbiddenPage from './components/pages/forbiddenPage'
import './styleSite.css';
function Router(props) {
return useRoutes(props.rootRoute);
}
export default function App() {
const routes = [
{ index: true, element: <StorePage/> },
localStorage.getItem("role") === "ADMIN" && { path: 'customer', element: <CustomerPage/>, label:'Покупатели'},
localStorage.getItem("role") !== "ADMIN" && { path: 'customer', element: <ForbiddenPage/>},
{ path: 'store', element: <StorePage/>, label: 'Магазины' },
{ path: 'product', element: <ProductPage/>, label: 'Товары' },
{ path: 'order', element: <OrderPage/>, label: 'Заказы'},
localStorage.getItem("role") === "ADMIN" && { path: 'addToStore', element: <AddToStorePage/>, label: 'Доставка'},
localStorage.getItem("role") !== "ADMIN" && { path: 'addToStore', element: <ForbiddenPage/>},
{ path: '/login', element: <LoginPage/>},
{ path: '/logout', element: <Logout/>}
];
const links = routes.filter(route => route.hasOwnProperty('label'));
const [token, setToken] = useState(localStorage.getItem('token'));
useEffect(() => {
function handleStorageChange() {
setToken(localStorage.getItem('token'));
}
window.addEventListener('storage', handleStorageChange);
return () => {
window.removeEventListener('storage', handleStorageChange);
};
}, []);
const rootRoute = [
{ path: '/', element: render(links), children: routes }
];
function render(links) {
console.info('render links');
return (
<>
<Header token={token} links={links} />
<div className="container-fluid">
<Outlet />
</div>
</>
);
}
return (
<BrowserRouter>
<Router rootRoute={ rootRoute } />
</BrowserRouter>
);
}

View File

@ -0,0 +1,24 @@
import React from 'react'
import { useNavigate} from "react-router-dom";
import { useEffect } from 'react';
const checkLogin = (Component) => {
const AuthenticatedComponent = (props) => {
const navigate = useNavigate();
const token = localStorage.getItem('token');
useEffect(() => {
if (!token || token === 'undefined') {
navigate('/login');
}
}, [navigate, token]);
if (token && token !== 'undefined') {
return <Component {...props} />
}
return null;
}
return AuthenticatedComponent;
}
export default checkLogin;

View File

@ -0,0 +1,21 @@
import React from "react";
export default function Footer(){
return(
<div className="ml-0 mr-0 h-25 d-flex flex-column justify-content-end">
<footer className="footer d-flex container-fluid">
<div className="text-left text-nowrap ml-0 footerLeft fw-bold">
Контакты<br/>
+7(***)***-**-**<br/>
+7(***)***-**-**<br/>
</div>
<div className="text-bottom text-center mx-auto mt-auto mb-0 fw-bold footerBottom">
boxStore. inc, 2022
</div>
<div className="footerRight me-0 ms-auto my-0 d-flex flex-column">
<a href="https://www.apple.com/ru/app-store/"><img src="AppStore.png" width="110" height="55"/></a>
<img src="GooglePlay.png" width="110" height="55"/>
</div>
</footer>
</div>
);
}

View File

@ -0,0 +1,50 @@
import { NavLink } from "react-router-dom";
import React from 'react'
export default function Header(props){
return(
<header>
<div className="d-flex flex-row headerContainer">
<div className="d-flex flex-row ml-3 ms-3 mt-auto mb-auto align-items-center">
<a>
<img src="logo.png" alt="*" width="60" height="60" className="align-text-top"></img>
</a>
<div id="logoName">
<a href="store">boxStore</a>
</div>
</div>
<nav className="navbar navbar-expand-md">
<div className="container-fluid" id="navigationMenu">
<button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="navbar-collapse collapse justify-content-end" id="navbarNav">
<ul className="navbar-nav" id="headerNavigation">
{
props.links.map(route =>
<li key={route.path}
className="nav-item">
<NavLink className="nav-link navigationCaption" to={route.path}>
{route.label}
</NavLink>
</li>
)
}
{props.token && props.token !== undefined ?
<NavLink className="nav-link navigationCaption" to="/logout">
<div>Выход</div>
</NavLink>
:
<NavLink className="nav-link navigationCaption" to="/login">
<div>Вход</div>
</NavLink>
}
</ul>
</div>
</div>
</nav>
</div>
</header>
);
}

View File

@ -0,0 +1,46 @@
import React from "react";
export default function Modal(props) {
const formRef = React.createRef();
function hide() {
props.onHide();
}
function done(e) {
e.preventDefault();
if (formRef.current.checkValidity()) {
props.onDone();
hide();
} else {
formRef.current.reportValidity();
}
}
return (
<div className="modal fade show" tabIndex="-1" aria-hidden="true"
style={{ display: props.visible ? 'block' : 'none' }}>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<h1 className="modal-title fs-5" id="exampleModalLabel">{props.header}</h1>
<button className="btn-close" type="button" aria-label="Close"
onClick={hide}></button>
</div>
<div className="modal-body">
<form ref={formRef} onSubmit={done}>
{props.children}
</form>
</div>
<div className="modal-footer">
<button className="btn btn-secondary" type="button" onClick={hide}>Закрыть</button>
<button className="btn btn-primary" type="button" onClick={done}>
{props.confirm}
</button>
</div>
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,73 @@
import { useState } from 'react';
import styles from './Table.module.css';
export default function Table(props) {
const [tableUpdate, setTableUpdate] = useState(false);
const [selectedItems, setSelectedItems] = useState([]);
function isSelected(id) {
if (!props.selectable) {
return false;
}
return selectedItems.includes(id);
}
function click(id) {
if (!props.selectable) {
return;
}
if (isSelected(id)) {
var index = selectedItems.indexOf(id);
if (index !== -1) {
selectedItems.splice(index, 1);
setSelectedItems(selectedItems);
setTableUpdate(!tableUpdate);
}
} else {
selectedItems.push(id);
setSelectedItems(selectedItems);
setTableUpdate(!tableUpdate);
}
props.onClick(selectedItems);
}
function dblClick(id) {
if (!props.selectable) {
return;
}
props.onDblClick(id);
}
return (
<table className={`table table-success table-hover ${styles.table} ${props.selectable ? styles.selectable : '' } `}>
<thead>
<tr>
<th scope="col">#</th>
{
props.headers.map(header =>
<th key={header.name} scope="col">
{header.label}
</th>
)
}
</tr>
</thead>
<tbody>
{
props.items.map((item, index) =>
<tr key={item.id}
className={isSelected(item.id) ? styles.selected : ''}
onClick={(e) => click(item.id, e)} onDoubleClick={(e) => dblClick(item.id, e)}>
<th scope="row">{index + 1}</th>
{
props.headers.map(header =>
<td key={item.id + header.name}>{item[header.name]}</td>
)
}
</tr>
)
}
</tbody >
</table >
);
}

View File

@ -0,0 +1,12 @@
.table tbody tr {
user-select: none;
}
.selectable tbody tr:hover {
cursor: pointer;
}
.selected {
background-color: #0d6efd;
opacity: 80%;
}

View File

@ -0,0 +1,29 @@
import styles from './Toolbar.module.css';
export default function Toolbar(props) {
function add() {
props.onAdd();
}
function edit() {
props.onEdit();
}
function remove() {
props.onRemove();
}
return (
<div className="btn-group my-2 mx-4" role="group">
{localStorage.getItem("role") === "ADMIN" && <button type="button" className={`btn btn-success ${styles.btn}`} onClick={add}>
Добавить
</button>}
{localStorage.getItem("role") === "ADMIN" && <button type="button" className={`btn btn-warning ${styles.btn}`} onClick={edit} >
Изменить
</button >}
{localStorage.getItem("role") === "ADMIN" && <button type="button" className={`btn btn-danger ${styles.btn}`} onClick={remove}>
Удалить
</button >}
</div >
);
}

View File

@ -0,0 +1,3 @@
.btn {
min-width: 140px;
}

View File

@ -0,0 +1,15 @@
import styles from './Toolbar.module.css';
export default function ToolbarOrder(props) {
function add() {
props.onAdd();
}
return (
<div className="btn-group my-2 mx-4" role="group">
{localStorage.getItem("role") === "ADMIN" && <button type="button" className={`btn btn-success ${styles.btn}`} onClick={add}>
Добавить
</button>}
</div >
);
}

View File

@ -0,0 +1,118 @@
import { useState, useEffect } from "react";
import Modal from './Modal';
import DataService from '../../services/DataService';
import Toolbar from './Toolbar';
import Table from './Table';
export default function CustomerTable(props){
const [items, setItems] = useState([]);
const [modalHeader, setModalHeader] = useState('');
const [modalConfirm, setModalConfirm] = useState('');
const [modalVisible, setModalVisible] = useState(false);
const [isEdit, setEdit] = useState(false);
let selectedItems = [];
useEffect(() => {
loadItems();
}, []);
function loadItems() {
DataService.readAll(props.getAllUrl, props.transformer)
.then(data => setItems(data));
}
function saveItem() {
let customer = {
lastName: props.data.lastName,
firstName: props.data.firstName,
middleName: props.data.middleName
}
if (!isEdit) {
DataService.create(props.url, customer).then(() => loadItems());
} else {
DataService.update(props.getUrl + props.data.id, customer).then(() => loadItems());
}
}
function handleAdd() {
setEdit(false);
setModalHeader('Регистрация');
setModalConfirm('Зарегестрироваться');
setModalVisible(true);
props.onAdd();
}
function handleEdit() {
if (selectedItems.length === 0) {
return;
}
edit(selectedItems[0]);
}
function edit(editedId) {
DataService.read(props.getUrl + editedId, props.transformer)
.then(data => {
setEdit(true);
setModalHeader('Редактирование пользователя');
setModalConfirm('Сохранить');
setModalVisible(true);
props.onEdit(data);
});
}
function handleRemove() {
if (selectedItems.length === 0) {
return;
}
if (confirm('Удалить выбранные элементы?')) {
const promises = [];
selectedItems.forEach(item => {
promises.push(DataService.delete(props.getUrl + item));
});
Promise.all(promises).then((results) => {
selectedItems.length = 0;
loadItems();
});
}
}
function handleTableClick(tableSelectedItems) {
selectedItems = tableSelectedItems;
}
function handleTableDblClick(tableSelectedItem) {
edit(tableSelectedItem);
}
function handleModalHide() {
setModalVisible(false);
}
function handleModalDone() {
saveItem();
}
return(
<>
<Toolbar
onAdd={handleAdd}
onEdit={handleEdit}
onRemove={handleRemove}/>
<Table
headers={props.headers}
items={items}
selectable={true}
onClick={handleTableClick}
onDblClick={handleTableDblClick}/>
<Modal
header={modalHeader}
confirm={modalConfirm}
visible={modalVisible}
onHide={handleModalHide}
onDone={handleModalDone}>
{props.children}
</Modal>
</>
)
}

View File

@ -0,0 +1,121 @@
import { useState, useEffect } from "react";
import Modal from './Modal';
import DataService from '../../services/DataService';
import OrderToolbar from './ToolbarOrder';
import Table from './Table';
export default function CustomerTable(props){
const [items, setItems] = useState([]);
const [modalHeader, setModalHeader] = useState('');
const [modalConfirm, setModalConfirm] = useState('');
const [modalVisible, setModalVisible] = useState(false);
const [isEdit, setEdit] = useState(false);
let selectedItems = [];
useEffect(() => {
loadItems();
loadOptions();
}, []);
function loadItems() {
DataService.readAll(props.getAllUrl, props.transformer)
.then(data => setItems(data));
}
async function loadOptions(){
props.loadOptions(await DataService.readAll(props.getCustomerUrl, props.transformerCustomer), await DataService.readAll(props.getProductUrl, props.transformerProduct));
}
function saveItem() {
let ordered = {
productId: props.data.productId,
customerId: props.data.customerId,
quantity: props.data.quantity
}
if (!isEdit) {
DataService.create(props.url, ordered).then(() => loadItems());
} else {
DataService.update(props.getUrl + props.data.id, ordered).then(() => loadItems());
}
}
function handleAdd() {
setEdit(false);
setModalHeader('Заказ');
setModalConfirm('Заказать');
setModalVisible(true);
props.onAdd();
}
function handleEdit() {
if (selectedItems.length === 0) {
return;
}
edit(selectedItems[0]);
}
function edit(editedId) {
DataService.read(props.getUrl + editedId, props.transformer)
.then(data => {
setEdit(true);
setModalHeader('Редактирование заказа');
setModalConfirm('Сохранить');
setModalVisible(true);
props.onEdit(data);
});
}
function handleRemove() {
if (selectedItems.length === 0) {
return;
}
if (confirm('Удалить выбранные элементы?')) {
const promises = [];
selectedItems.forEach(item => {
promises.push(DataService.delete(props.getUrl + item));
});
Promise.all(promises).then((results) => {
selectedItems.length = 0;
loadItems();
});
}
}
function handleTableClick(tableSelectedItems) {
selectedItems = tableSelectedItems;
}
function handleTableDblClick(tableSelectedItem) {
edit(tableSelectedItem);
}
function handleModalHide() {
setModalVisible(false);
}
function handleModalDone() {
saveItem();
}
return(
<>
<OrderToolbar
onAdd={handleAdd}/>
<Table
headers={props.headers}
items={items}
selectable={true}
onClick={handleTableClick}
onDblClick={handleTableDblClick}/>
<Modal
header={modalHeader}
confirm={modalConfirm}
visible={modalVisible}
onHide={handleModalHide}
onDone={handleModalDone}>
{props.children}
</Modal>
</>
)
}

View File

@ -0,0 +1,116 @@
import { useState, useEffect } from "react";
import Modal from './Modal';
import DataService from '../../services/DataService';
import Toolbar from './Toolbar';
import Table from './Table';
export default function CustomerTable(props){
const [items, setItems] = useState([]);
const [modalHeader, setModalHeader] = useState('');
const [modalConfirm, setModalConfirm] = useState('');
const [modalVisible, setModalVisible] = useState(false);
const [isEdit, setEdit] = useState(false);
let selectedItems = [];
useEffect(() => {
loadItems();
}, []);
function loadItems() {
DataService.readAll(props.getAllUrl, props.transformer)
.then(data => setItems(data));
}
function saveItem() {
let product = {
productName: props.data.productName
}
if (!isEdit) {
DataService.create(props.url, product).then(() => loadItems());
} else {
DataService.update(props.getUrl + props.data.id, product).then(() => loadItems());
}
}
function handleAdd() {
setEdit(false);
setModalHeader('Добавления товара');
setModalConfirm('Добавить');
setModalVisible(true);
props.onAdd();
}
function handleEdit() {
if (selectedItems.length === 0) {
return;
}
edit(selectedItems[0]);
}
function edit(editedId) {
DataService.read(props.getUrl + editedId, props.transformer)
.then(data => {
setEdit(true);
setModalHeader('Редактирование пользователя');
setModalConfirm('Сохранить');
setModalVisible(true);
props.onEdit(data);
});
}
function handleRemove() {
if (selectedItems.length === 0) {
return;
}
if (confirm('Удалить выбранные элементы?')) {
const promises = [];
selectedItems.forEach(item => {
promises.push(DataService.delete(props.getUrl + item));
});
Promise.all(promises).then((results) => {
selectedItems.length = 0;
loadItems();
});
}
}
function handleTableClick(tableSelectedItems) {
selectedItems = tableSelectedItems;
}
function handleTableDblClick(tableSelectedItem) {
edit(tableSelectedItem);
}
function handleModalHide() {
setModalVisible(false);
}
function handleModalDone() {
saveItem();
}
return(
<>
<Toolbar
onAdd={handleAdd}
onEdit={handleEdit}
onRemove={handleRemove}/>
<Table
headers={props.headers}
items={items}
selectable={true}
onClick={handleTableClick}
onDblClick={handleTableDblClick}/>
<Modal
header={modalHeader}
confirm={modalConfirm}
visible={modalVisible}
onHide={handleModalHide}
onDone={handleModalDone}>
{props.children}
</Modal>
</>
)
}

View File

@ -0,0 +1,116 @@
import { useState, useEffect } from "react";
import Modal from './Modal';
import DataService from '../../services/DataService';
import Toolbar from './Toolbar';
import Table from './Table';
export default function CustomerTable(props){
const [items, setItems] = useState([]);
const [modalHeader, setModalHeader] = useState('');
const [modalConfirm, setModalConfirm] = useState('');
const [modalVisible, setModalVisible] = useState(false);
const [isEdit, setEdit] = useState(false);
let selectedItems = [];
useEffect(() => {
loadItems();
}, []);
function loadItems() {
DataService.readAll(props.getAllUrl, props.transformer)
.then(data => setItems(data));
}
function saveItem() {
let store = {
storeName: props.data.storeName
}
if (!isEdit) {
DataService.create(props.url, store).then(() => loadItems());
} else {
DataService.update(props.getUrl + props.data.id, store).then(() => loadItems());
}
}
function handleAdd() {
setEdit(false);
setModalHeader('Регистрация магазина');
setModalConfirm('Зарегестрировать');
setModalVisible(true);
props.onAdd();
}
function handleEdit() {
if (selectedItems.length === 0) {
return;
}
edit(selectedItems[0]);
}
function edit(editedId) {
DataService.read(props.getUrl + editedId, props.transformer)
.then(data => {
setEdit(true);
setModalHeader('Редактирование пользователя');
setModalConfirm('Сохранить');
setModalVisible(true);
props.onEdit(data);
});
}
function handleRemove() {
if (selectedItems.length === 0) {
return;
}
if (confirm('Удалить выбранные элементы?')) {
const promises = [];
selectedItems.forEach(item => {
promises.push(DataService.delete(props.getUrl + item));
});
Promise.all(promises).then((results) => {
selectedItems.length = 0;
loadItems();
});
}
}
function handleTableClick(tableSelectedItems) {
selectedItems = tableSelectedItems;
}
function handleTableDblClick(tableSelectedItem) {
edit(tableSelectedItem);
}
function handleModalHide() {
setModalVisible(false);
}
function handleModalDone() {
saveItem();
}
return(
<>
<Toolbar
onAdd={handleAdd}
onEdit={handleEdit}
onRemove={handleRemove}/>
<Table
headers={props.headers}
items={items}
selectable={true}
onClick={handleTableClick}
onDblClick={handleTableDblClick}/>
<Modal
header={modalHeader}
confirm={modalConfirm}
visible={modalVisible}
onHide={handleModalHide}
onDone={handleModalDone}>
{props.children}
</Modal>
</>
)
}

View File

@ -0,0 +1,92 @@
import Product from "../../models/product"
import Store from "../../models/store"
import DataService from '../../services/DataService';
import { useState, useEffect} from "react";
import checkLogin from '../../checkLogin';
function AddToStorePage(){
const getStoreUrl = 'store';
const getProductUrl = 'product/getWithoutStores'
const url = 'store/'
const [storeOptions, setStoreOptions] = useState([])
const [productOptions, setProductOptions] = useState([])
const transformerProduct = (data) => new Product(data);
const transformerStore = (data) => new Store(data);
useEffect(() => {
loadOptions();
}, []);
async function loadOptions(){
loadSelOptions(await DataService.readAll(getStoreUrl, transformerStore), await DataService.readAll(getProductUrl, transformerProduct));
}
function loadSelOptions(dataStore, dataProduct){
const results1 = [];
//console.log(dataProduct);
dataStore.forEach((value) => {
results1.push({
key: value.storeName,
value: value.id,
})
})
console.log(results1);
setStoreOptions(results1);
const results2 = [];
console.log(dataProduct);
dataProduct.forEach((value) => {
results2.push({
key: value.productName,
value: value.id,
})
})
setProductOptions(results2);
}
function add(){
var storeId = document.getElementById("storeId").value;
var productId = document.getElementById("productId").value;
let product = {
id: productId
}
DataService.update(url + storeId + "/add", product);
window.location.replace("/product");
}
return(
<>
<div className="col-md-4">
<label className="form-label" forhtml="storeId">Магазин</label>
<select className="form-select" id="storeId" required>
{
storeOptions.map((option) => {
return(
<option key={option.value} value={option.value}>
{option.key}
</option>
)
}
)
}
</select>
<label className="form-label" forhtml="productId">Товар</label>
<select className="form-select" id="productId" required>
{
productOptions.map((option) => {
return(
<option key={option.value} value={option.value}>
{option.key}
</option>
)
}
)
}
</select>
<button className={`btn btn-success`} onClick={add}>
Добавить в магазин
</button>
</div>
</>
);
}
export default checkLogin(AddToStorePage);

Some files were not shown because too many files have changed in this diff Show More