first commit
This commit is contained in:
66
backend/pom.xml
Normal file
66
backend/pom.xml
Normal file
@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.5.0</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>com.yandex.practicum.devops</groupId>
|
||||
<artifactId>sausage-store</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>sausage-store</name>
|
||||
<description>Backend for sausage-store</description>
|
||||
<properties>
|
||||
<java.version>16</java.version>
|
||||
<sonar.projectKey>test_manual</sonar.projectKey>
|
||||
<sonar.qualitygate.wait>true</sonar.qualitygate.wait>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.vintage</groupId>
|
||||
<artifactId>junit-vintage-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -0,0 +1,28 @@
|
||||
package com.yandex.practicum.devops;
|
||||
|
||||
import com.yandex.practicum.devops.model.Product;
|
||||
import com.yandex.practicum.devops.service.ProductService;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SausageApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SausageApplication.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
CommandLineRunner runner(ProductService productService) {
|
||||
return args -> {
|
||||
productService.save(new Product(1L, "Сливочная", 320.00, "https://res.cloudinary.com/sugrobov/image/upload/v1623323635/repos/sausages/6.jpg"));
|
||||
productService.save(new Product(2L, "Особая", 179.00, "https://res.cloudinary.com/sugrobov/image/upload/v1623323635/repos/sausages/5.jpg"));
|
||||
productService.save(new Product(3L, "Молочная", 225.00, "https://res.cloudinary.com/sugrobov/image/upload/v1623323635/repos/sausages/4.jpg"));
|
||||
productService.save(new Product(4L, "Нюренбергская", 315.00, "https://res.cloudinary.com/sugrobov/image/upload/v1623323635/repos/sausages/3.jpg"));
|
||||
productService.save(new Product(5L, "Мюнхенская", 330.00, "https://res.cloudinary.com/sugrobov/image/upload/v1623323635/repos/sausages/2.jpg"));
|
||||
productService.save(new Product(6L, "Русская", 189.00, "https://res.cloudinary.com/sugrobov/image/upload/v1623323635/repos/sausages/1.jpg"));
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
package com.yandex.practicum.devops.controller;
|
||||
|
||||
import com.yandex.practicum.devops.dto.OrderProductDto;
|
||||
import com.yandex.practicum.devops.exception.ResourceNotFoundException;
|
||||
import com.yandex.practicum.devops.model.Order;
|
||||
import com.yandex.practicum.devops.model.OrderProduct;
|
||||
import com.yandex.practicum.devops.model.OrderStatus;
|
||||
import com.yandex.practicum.devops.service.OrderProductService;
|
||||
import com.yandex.practicum.devops.service.OrderService;
|
||||
import com.yandex.practicum.devops.service.ProductService;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/orders")
|
||||
public class OrderController {
|
||||
|
||||
ProductService productService;
|
||||
OrderService orderService;
|
||||
OrderProductService orderProductService;
|
||||
|
||||
public OrderController(ProductService productService, OrderService orderService, OrderProductService orderProductService) {
|
||||
this.productService = productService;
|
||||
this.orderService = orderService;
|
||||
this.orderProductService = orderProductService;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public @NotNull Iterable<Order> list() {
|
||||
return this.orderService.getAllOrders();
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<Order> create(@RequestBody OrderForm form) {
|
||||
List<OrderProductDto> formDtos = form.getProductOrders();
|
||||
validateProductsExistence(formDtos);
|
||||
Order order = new Order();
|
||||
order.setStatus(OrderStatus.PAID.name());
|
||||
order = this.orderService.create(order);
|
||||
|
||||
List<OrderProduct> orderProducts = new ArrayList<>();
|
||||
for (OrderProductDto dto : formDtos) {
|
||||
orderProducts.add(orderProductService.create(new OrderProduct(order, productService.getProduct(dto
|
||||
.getProduct()
|
||||
.getId()), dto.getQuantity())));
|
||||
}
|
||||
|
||||
order.setOrderProducts(orderProducts);
|
||||
|
||||
this.orderService.update(order);
|
||||
|
||||
String uri = ServletUriComponentsBuilder
|
||||
.fromCurrentServletMapping()
|
||||
.path("/orders/{id}")
|
||||
.buildAndExpand(order.getId())
|
||||
.toString();
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("Location", uri);
|
||||
|
||||
return new ResponseEntity<>(order, headers, HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
private void validateProductsExistence(List<OrderProductDto> orderProducts) {
|
||||
List<OrderProductDto> list = orderProducts
|
||||
.stream()
|
||||
.filter(op -> Objects.isNull(productService.getProduct(op
|
||||
.getProduct()
|
||||
.getId())))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!CollectionUtils.isEmpty(list)) {
|
||||
new ResourceNotFoundException("Product not found");
|
||||
}
|
||||
}
|
||||
|
||||
public static class OrderForm {
|
||||
|
||||
private List<OrderProductDto> productOrders;
|
||||
|
||||
public List<OrderProductDto> getProductOrders() {
|
||||
return productOrders;
|
||||
}
|
||||
|
||||
public void setProductOrders(List<OrderProductDto> productOrders) {
|
||||
this.productOrders = productOrders;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.yandex.practicum.devops.controller;
|
||||
|
||||
import com.yandex.practicum.devops.model.Product;
|
||||
import com.yandex.practicum.devops.service.ProductService;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/products")
|
||||
public class ProductController {
|
||||
|
||||
private ProductService productService;
|
||||
|
||||
public ProductController(ProductService productService) {
|
||||
this.productService = productService;
|
||||
}
|
||||
|
||||
@GetMapping(value = { "", "/" })
|
||||
public @NotNull Iterable<Product> getProducts() {
|
||||
return productService.getAllProducts();
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.yandex.practicum.devops.dto;
|
||||
|
||||
import com.yandex.practicum.devops.model.Product;
|
||||
|
||||
public class OrderProductDto {
|
||||
|
||||
private Product product;
|
||||
private Integer quantity;
|
||||
|
||||
public Product getProduct() {
|
||||
return product;
|
||||
}
|
||||
|
||||
public void setProduct(Product product) {
|
||||
this.product = product;
|
||||
}
|
||||
|
||||
public Integer getQuantity() {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
public void setQuantity(Integer quantity) {
|
||||
this.quantity = quantity;
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package com.yandex.practicum.devops.exception;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.ConstraintViolationException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RestControllerAdvice
|
||||
public class ApiExceptionHandler {
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@ExceptionHandler(ConstraintViolationException.class)
|
||||
public ResponseEntity<ErrorResponse> handle(ConstraintViolationException e) {
|
||||
ErrorResponse errors = new ErrorResponse();
|
||||
for (ConstraintViolation violation : e.getConstraintViolations()) {
|
||||
ErrorItem error = new ErrorItem();
|
||||
error.setCode(violation.getMessageTemplate());
|
||||
error.setMessage(violation.getMessage());
|
||||
errors.addError(error);
|
||||
}
|
||||
|
||||
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@ExceptionHandler(ResourceNotFoundException.class)
|
||||
public ResponseEntity<ErrorItem> handle(ResourceNotFoundException e) {
|
||||
ErrorItem error = new ErrorItem();
|
||||
error.setMessage(e.getMessage());
|
||||
|
||||
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
public static class ErrorItem {
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL) private String code;
|
||||
|
||||
private String message;
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class ErrorResponse {
|
||||
|
||||
private List<ErrorItem> errors = new ArrayList<>();
|
||||
|
||||
public List<ErrorItem> getErrors() {
|
||||
return errors;
|
||||
}
|
||||
|
||||
public void setErrors(List<ErrorItem> errors) {
|
||||
this.errors = errors;
|
||||
}
|
||||
|
||||
public void addError(ErrorItem error) {
|
||||
this.errors.add(error);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.yandex.practicum.devops.exception;
|
||||
|
||||
public class ResourceNotFoundException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 5861310537366287163L;
|
||||
|
||||
public ResourceNotFoundException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ResourceNotFoundException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public ResourceNotFoundException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ResourceNotFoundException(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package com.yandex.practicum.devops.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
|
||||
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.Valid;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Table(name = "orders")
|
||||
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="orderProducts")
|
||||
public class Order {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@JsonFormat(pattern = "dd/MM/yyyy") private LocalDate dateCreated;
|
||||
|
||||
private String status;
|
||||
|
||||
@OneToMany(mappedBy = "pk.order")
|
||||
@Valid
|
||||
private List<OrderProduct> orderProducts = new ArrayList<>();
|
||||
|
||||
@Transient
|
||||
public Double getTotalOrderPrice() {
|
||||
double sum = 0D;
|
||||
List<OrderProduct> orderProducts = getOrderProducts();
|
||||
for (OrderProduct op : orderProducts) {
|
||||
sum += op.getTotalPrice();
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public LocalDate getDateCreated() {
|
||||
return dateCreated;
|
||||
}
|
||||
|
||||
public void setDateCreated(LocalDate dateCreated) {
|
||||
this.dateCreated = dateCreated;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public List<OrderProduct> getOrderProducts() {
|
||||
return orderProducts;
|
||||
}
|
||||
|
||||
public void setOrderProducts(List<OrderProduct> orderProducts) {
|
||||
this.orderProducts = orderProducts;
|
||||
}
|
||||
|
||||
@Transient
|
||||
public int getNumberOfProducts() {
|
||||
return this.orderProducts.size();
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
package com.yandex.practicum.devops.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.EmbeddedId;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
@Entity
|
||||
public class OrderProduct {
|
||||
|
||||
@EmbeddedId
|
||||
@JsonIgnore
|
||||
private OrderProductPK pk;
|
||||
|
||||
@Column(nullable = false) private Integer quantity;
|
||||
|
||||
public OrderProduct() {
|
||||
super();
|
||||
}
|
||||
|
||||
public OrderProduct(Order order, Product product, Integer quantity) {
|
||||
pk = new OrderProductPK();
|
||||
pk.setOrder(order);
|
||||
pk.setProduct(product);
|
||||
this.quantity = quantity;
|
||||
}
|
||||
|
||||
@Transient
|
||||
public Product getProduct() {
|
||||
return this.pk.getProduct();
|
||||
}
|
||||
|
||||
@Transient
|
||||
public Double getTotalPrice() {
|
||||
return getProduct().getPrice() * getQuantity();
|
||||
}
|
||||
|
||||
public OrderProductPK getPk() {
|
||||
return pk;
|
||||
}
|
||||
|
||||
public void setPk(OrderProductPK pk) {
|
||||
this.pk = pk;
|
||||
}
|
||||
|
||||
public Integer getQuantity() {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
public void setQuantity(Integer quantity) {
|
||||
this.quantity = quantity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((pk == null) ? 0 : pk.hashCode());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
OrderProduct other = (OrderProduct) obj;
|
||||
if (pk == null) {
|
||||
if (other.pk != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!pk.equals(other.pk)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package com.yandex.practicum.devops.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
|
||||
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
|
||||
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Embeddable
|
||||
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "order")
|
||||
public class OrderProductPK implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 476151177562655457L;
|
||||
|
||||
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "order_id")
|
||||
private Order order;
|
||||
|
||||
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "product_id")
|
||||
private Product product;
|
||||
|
||||
public Order getOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
public void setOrder(Order order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
public Product getProduct() {
|
||||
return product;
|
||||
}
|
||||
|
||||
public void setProduct(Product product) {
|
||||
this.product = product;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
|
||||
result = prime * result + ((order.getId() == null)
|
||||
? 0
|
||||
: order
|
||||
.getId()
|
||||
.hashCode());
|
||||
result = prime * result + ((product.getId() == null)
|
||||
? 0
|
||||
: product
|
||||
.getId()
|
||||
.hashCode());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
OrderProductPK other = (OrderProductPK) obj;
|
||||
if (order == null) {
|
||||
if (other.order != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!order.equals(other.order)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (product == null) {
|
||||
if (other.product != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!product.equals(other.product)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package com.yandex.practicum.devops.model;
|
||||
|
||||
public enum OrderStatus {
|
||||
PAID
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package com.yandex.practicum.devops.model;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Entity
|
||||
public class Product {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@NotNull(message = "Product name is required.")
|
||||
@Basic(optional = false)
|
||||
private String name;
|
||||
|
||||
private Double price;
|
||||
|
||||
private String pictureUrl;
|
||||
|
||||
public Product(Long id, @NotNull(message = "Product name is required.") String name, Double price, String pictureUrl) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.price = price;
|
||||
this.pictureUrl = pictureUrl;
|
||||
}
|
||||
|
||||
public Product() {
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Double getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
public void setPrice(Double price) {
|
||||
this.price = price;
|
||||
}
|
||||
|
||||
public String getPictureUrl() {
|
||||
return pictureUrl;
|
||||
}
|
||||
|
||||
public void setPictureUrl(String pictureUrl) {
|
||||
this.pictureUrl = pictureUrl;
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package com.yandex.practicum.devops.repository;
|
||||
|
||||
import com.yandex.practicum.devops.model.OrderProduct;
|
||||
import com.yandex.practicum.devops.model.OrderProductPK;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
public interface OrderProductRepository extends CrudRepository<OrderProduct, OrderProductPK> {
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.yandex.practicum.devops.repository;
|
||||
|
||||
import com.yandex.practicum.devops.model.Order;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
public interface OrderRepository extends CrudRepository<Order, Long> {
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.yandex.practicum.devops.repository;
|
||||
|
||||
import com.yandex.practicum.devops.model.Product;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
public interface ProductRepository extends CrudRepository<Product, Long> {
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.yandex.practicum.devops.service;
|
||||
|
||||
import com.yandex.practicum.devops.model.OrderProduct;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Validated
|
||||
public interface OrderProductService {
|
||||
|
||||
OrderProduct create(@NotNull(message = "The products for order cannot be null.") @Valid OrderProduct orderProduct);
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.yandex.practicum.devops.service;
|
||||
|
||||
import com.yandex.practicum.devops.model.OrderProduct;
|
||||
import com.yandex.practicum.devops.repository.OrderProductRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
public class OrderProductServiceImpl implements OrderProductService {
|
||||
|
||||
private OrderProductRepository orderProductRepository;
|
||||
|
||||
public OrderProductServiceImpl(OrderProductRepository orderProductRepository) {
|
||||
this.orderProductRepository = orderProductRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrderProduct create(OrderProduct orderProduct) {
|
||||
return this.orderProductRepository.save(orderProduct);
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.yandex.practicum.devops.service;
|
||||
|
||||
import com.yandex.practicum.devops.model.Order;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Validated
|
||||
public interface OrderService {
|
||||
|
||||
@NotNull Iterable<Order> getAllOrders();
|
||||
|
||||
Order create(@NotNull(message = "The order cannot be null.") @Valid Order order);
|
||||
|
||||
void update(@NotNull(message = "The order cannot be null.") @Valid Order order);
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package com.yandex.practicum.devops.service;
|
||||
|
||||
import com.yandex.practicum.devops.model.Order;
|
||||
import com.yandex.practicum.devops.repository.OrderRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
public class OrderServiceImpl implements OrderService {
|
||||
|
||||
private OrderRepository orderRepository;
|
||||
|
||||
public OrderServiceImpl(OrderRepository orderRepository) {
|
||||
this.orderRepository = orderRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Order> getAllOrders() {
|
||||
return this.orderRepository.findAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Order create(Order order) {
|
||||
order.setDateCreated(LocalDate.now());
|
||||
|
||||
return this.orderRepository.save(order);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Order order) {
|
||||
this.orderRepository.save(order);
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.yandex.practicum.devops.service;
|
||||
|
||||
import com.yandex.practicum.devops.model.Product;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Validated
|
||||
public interface ProductService {
|
||||
|
||||
@NotNull Iterable<Product> getAllProducts();
|
||||
|
||||
Product getProduct(@Min(value = 1L, message = "Invalid product ID.") long id);
|
||||
|
||||
Product save(Product product);
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.yandex.practicum.devops.service;
|
||||
|
||||
import com.yandex.practicum.devops.exception.ResourceNotFoundException;
|
||||
import com.yandex.practicum.devops.model.Product;
|
||||
import com.yandex.practicum.devops.repository.ProductRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
public class ProductServiceImpl implements ProductService {
|
||||
|
||||
private ProductRepository productRepository;
|
||||
|
||||
public ProductServiceImpl(ProductRepository productRepository) {
|
||||
this.productRepository = productRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Product> getAllProducts() {
|
||||
return productRepository.findAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Product getProduct(long id) {
|
||||
return productRepository
|
||||
.findById(id)
|
||||
.orElseThrow(() -> new ResourceNotFoundException("Product not found"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Product save(Product product) {
|
||||
return productRepository.save(product);
|
||||
}
|
||||
}
|
8
backend/src/main/resources/application.properties
Normal file
8
backend/src/main/resources/application.properties
Normal file
@ -0,0 +1,8 @@
|
||||
management.security.enabled=false
|
||||
|
||||
spring.datasource.name=ecommercedb
|
||||
spring.jpa.show-sql=false
|
||||
|
||||
#H2 settings
|
||||
spring.h2.console.enabled=true
|
||||
spring.h2.console.path=/h2-console
|
13
backend/src/main/resources/logback.xml
Normal file
13
backend/src/main/resources/logback.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
@ -0,0 +1,99 @@
|
||||
package com.yandex.practicum.devops;
|
||||
|
||||
import com.yandex.practicum.devops.controller.OrderController;
|
||||
import com.yandex.practicum.devops.controller.ProductController;
|
||||
import com.yandex.practicum.devops.dto.OrderProductDto;
|
||||
import com.yandex.practicum.devops.model.Order;
|
||||
import com.yandex.practicum.devops.model.Product;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.hasProperty;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = { SausageApplication.class }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
public class SausageApplicationIntegrationTest {
|
||||
|
||||
@Autowired private TestRestTemplate restTemplate;
|
||||
|
||||
@LocalServerPort private int port;
|
||||
|
||||
@Autowired private ProductController productController;
|
||||
|
||||
@Autowired private OrderController orderController;
|
||||
|
||||
@Test
|
||||
public void contextLoads() {
|
||||
Assertions
|
||||
.assertThat(productController)
|
||||
.isNotNull();
|
||||
Assertions
|
||||
.assertThat(orderController)
|
||||
.isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenGetProductsApiCall_whenProductListRetrieved_thenSizeMatchAndListContainsProductNames() {
|
||||
ResponseEntity<Iterable<Product>> responseEntity = restTemplate.exchange("http://localhost:" + port + "/api/products", HttpMethod.GET, null, new ParameterizedTypeReference<Iterable<Product>>() {
|
||||
});
|
||||
Iterable<Product> products = responseEntity.getBody();
|
||||
Assertions
|
||||
.assertThat(products)
|
||||
.hasSize(6);
|
||||
|
||||
assertThat(products, hasItem(hasProperty("name", is("Сливочная"))));
|
||||
assertThat(products, hasItem(hasProperty("name", is("Особая"))));
|
||||
assertThat(products, hasItem(hasProperty("name", is("Молочная"))));
|
||||
assertThat(products, hasItem(hasProperty("name", is("Нюренбергская"))));
|
||||
assertThat(products, hasItem(hasProperty("name", is("Мюнхенская"))));
|
||||
assertThat(products, hasItem(hasProperty("name", is("Русская"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenGetOrdersApiCall_whenProductListRetrieved_thenSizeMatchAndListContainsProductNames() {
|
||||
ResponseEntity<Iterable<Order>> responseEntity = restTemplate.exchange("http://localhost:" + port + "/api/orders", HttpMethod.GET, null, new ParameterizedTypeReference<Iterable<Order>>() {
|
||||
});
|
||||
|
||||
Iterable<Order> orders = responseEntity.getBody();
|
||||
Assertions
|
||||
.assertThat(orders)
|
||||
.hasSize(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenPostOrder_whenBodyRequestMatcherJson_thenResponseContainsEqualObjectProperties() {
|
||||
final ResponseEntity<Order> postResponse = restTemplate.postForEntity("http://localhost:" + port + "/api/orders", prepareOrderForm(), Order.class);
|
||||
Order order = postResponse.getBody();
|
||||
Assertions
|
||||
.assertThat(postResponse.getStatusCode())
|
||||
.isEqualByComparingTo(HttpStatus.CREATED);
|
||||
|
||||
assertThat(order, hasProperty("status", is("PAID")));
|
||||
assertThat(order.getOrderProducts(), hasItem(hasProperty("quantity", is(2))));
|
||||
}
|
||||
|
||||
private OrderController.OrderForm prepareOrderForm() {
|
||||
OrderController.OrderForm orderForm = new OrderController.OrderForm();
|
||||
OrderProductDto productDto = new OrderProductDto();
|
||||
productDto.setProduct(new Product(1L, "Русская", 300.00, "http://placehold.it/200x100"));
|
||||
productDto.setQuantity(2);
|
||||
orderForm.setProductOrders(Collections.singletonList(productDto));
|
||||
|
||||
return orderForm;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user