From 88b46e2ee3f22f9e8813f6f0ce849bfbb1d6c208 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=BB=D1=8C=D1=8F?= <Илья@WIN-RANNDDD> Date: Sun, 31 Mar 2024 21:02:30 +0400 Subject: [PATCH] lab2_code --- build.gradle | 4 +- settings.gradle | 2 +- .../com/example/backend/DemoApplication.java | 109 +++++++++ .../backend/books/api/BookController.java | 70 ++++++ .../example/backend/books/api/BookDto.java | 189 +++++++++++++++ .../backend/books/model/BookEntity.java | 223 ++++++++++++++++++ .../books/repository/BookRepository.java | 10 + .../backend/books/service/BookService.java | 65 +++++ .../categories/api/CategoryController.java | 64 +++++ .../backend/categories/api/CategoryDto.java | 28 +++ .../categories/model/CategoryEntity.java | 43 ++++ .../repository/CategoryRepository.java | 10 + .../categories/service/CategoryService.java | 43 ++++ .../backend/core/configuration/Constants.java | 8 + .../configuration/MapperConfiguration.java | 13 + .../core/configuration/WebConfiguration.java} | 5 +- .../backend/core/error/NotFoundException.java | 7 + .../backend/core/model/BaseEntity.java | 20 ++ .../core/repository/CommonRepository.java | 17 ++ .../core/repository/MapRepository.java | 57 +++++ .../example/backend/core/utils/Formatter.java | 20 ++ .../backend/orders/api/OrderController.java | 76 ++++++ .../example/backend/orders/api/OrderDto.java | 61 +++++ .../backend/orders/model/OrderEntity.java | 66 ++++++ .../orders/repository/OrderRepository.java | 10 + .../backend/orders/service/OrderService.java | 60 +++++ .../ordersbooks/api/OrderBookController.java | 76 ++++++ .../backend/ordersbooks/api/OrderBookDto.java | 52 ++++ .../ordersbooks/model/OrderBookEntity.java | 66 ++++++ .../repository/OrderBookRepository.java | 10 + .../ordersbooks/service/OrderBookService.java | 56 +++++ .../backend/users/api/UserController.java | 64 +++++ .../example/backend/users/api/UserDto.java | 59 +++++ .../backend/users/model/UserEntity.java | 75 ++++++ .../users/repository/UserRepository.java | 10 + .../backend/users/service/UserService.java | 46 ++++ .../java/com/example/demo/ApiController.java | 48 ---- src/main/java/com/example/demo/Category.java | 20 -- .../com/example/demo/DemoApplication.java | 13 - .../com/example/backend/BookServiceTests.java | 95 ++++++++ .../example/backend/CategoryServiceTests.java | 61 +++++ .../backend/OrderBookServiceTests.java | 126 ++++++++++ .../example/backend/OrderServiceTests.java | 82 +++++++ .../com/example/backend/UserServiceTests.java | 64 +++++ .../example/demo/DemoApplicationTests.java | 13 - 45 files changed, 2217 insertions(+), 99 deletions(-) create mode 100644 src/main/java/com/example/backend/DemoApplication.java create mode 100644 src/main/java/com/example/backend/books/api/BookController.java create mode 100644 src/main/java/com/example/backend/books/api/BookDto.java create mode 100644 src/main/java/com/example/backend/books/model/BookEntity.java create mode 100644 src/main/java/com/example/backend/books/repository/BookRepository.java create mode 100644 src/main/java/com/example/backend/books/service/BookService.java create mode 100644 src/main/java/com/example/backend/categories/api/CategoryController.java create mode 100644 src/main/java/com/example/backend/categories/api/CategoryDto.java create mode 100644 src/main/java/com/example/backend/categories/model/CategoryEntity.java create mode 100644 src/main/java/com/example/backend/categories/repository/CategoryRepository.java create mode 100644 src/main/java/com/example/backend/categories/service/CategoryService.java create mode 100644 src/main/java/com/example/backend/core/configuration/Constants.java create mode 100644 src/main/java/com/example/backend/core/configuration/MapperConfiguration.java rename src/main/java/com/example/{demo/WebConfig.java => backend/core/configuration/WebConfiguration.java} (80%) create mode 100644 src/main/java/com/example/backend/core/error/NotFoundException.java create mode 100644 src/main/java/com/example/backend/core/model/BaseEntity.java create mode 100644 src/main/java/com/example/backend/core/repository/CommonRepository.java create mode 100644 src/main/java/com/example/backend/core/repository/MapRepository.java create mode 100644 src/main/java/com/example/backend/core/utils/Formatter.java create mode 100644 src/main/java/com/example/backend/orders/api/OrderController.java create mode 100644 src/main/java/com/example/backend/orders/api/OrderDto.java create mode 100644 src/main/java/com/example/backend/orders/model/OrderEntity.java create mode 100644 src/main/java/com/example/backend/orders/repository/OrderRepository.java create mode 100644 src/main/java/com/example/backend/orders/service/OrderService.java create mode 100644 src/main/java/com/example/backend/ordersbooks/api/OrderBookController.java create mode 100644 src/main/java/com/example/backend/ordersbooks/api/OrderBookDto.java create mode 100644 src/main/java/com/example/backend/ordersbooks/model/OrderBookEntity.java create mode 100644 src/main/java/com/example/backend/ordersbooks/repository/OrderBookRepository.java create mode 100644 src/main/java/com/example/backend/ordersbooks/service/OrderBookService.java create mode 100644 src/main/java/com/example/backend/users/api/UserController.java create mode 100644 src/main/java/com/example/backend/users/api/UserDto.java create mode 100644 src/main/java/com/example/backend/users/model/UserEntity.java create mode 100644 src/main/java/com/example/backend/users/repository/UserRepository.java create mode 100644 src/main/java/com/example/backend/users/service/UserService.java delete mode 100644 src/main/java/com/example/demo/ApiController.java delete mode 100644 src/main/java/com/example/demo/Category.java delete mode 100644 src/main/java/com/example/demo/DemoApplication.java create mode 100644 src/test/java/com/example/backend/BookServiceTests.java create mode 100644 src/test/java/com/example/backend/CategoryServiceTests.java create mode 100644 src/test/java/com/example/backend/OrderBookServiceTests.java create mode 100644 src/test/java/com/example/backend/OrderServiceTests.java create mode 100644 src/test/java/com/example/backend/UserServiceTests.java delete mode 100644 src/test/java/com/example/demo/DemoApplicationTests.java diff --git a/build.gradle b/build.gradle index 89528ee..988a6f6 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '3.2.3' + id 'org.springframework.boot' version '3.2.4' id 'io.spring.dependency-management' version '1.1.4' } @@ -18,6 +18,7 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0' + implementation 'org.modelmapper:modelmapper:3.2.0' testImplementation 'org.springframework.boot:spring-boot-starter-test' } @@ -25,3 +26,4 @@ dependencies { tasks.named('test') { useJUnitPlatform() } + diff --git a/settings.gradle b/settings.gradle index 0a383dd..0f5036d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -rootProject.name = 'demo' +rootProject.name = 'backend' diff --git a/src/main/java/com/example/backend/DemoApplication.java b/src/main/java/com/example/backend/DemoApplication.java new file mode 100644 index 0000000..bbf0c32 --- /dev/null +++ b/src/main/java/com/example/backend/DemoApplication.java @@ -0,0 +1,109 @@ +package com.example.backend; + +import java.util.Objects; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +import com.example.backend.books.model.BookEntity; +import com.example.backend.books.service.BookService; +import com.example.backend.categories.model.CategoryEntity; +import com.example.backend.categories.service.CategoryService; +import com.example.backend.core.utils.Formatter; +import com.example.backend.users.model.UserEntity; +import com.example.backend.users.service.UserService; +import com.example.backend.orders.model.OrderEntity; +import com.example.backend.orders.service.OrderService; +import com.example.backend.ordersbooks.model.OrderBookEntity; +import com.example.backend.ordersbooks.service.OrderBookService; + +@SpringBootApplication +public class DemoApplication implements CommandLineRunner { + private final Logger log = LoggerFactory.getLogger(DemoApplication.class); + + private final CategoryService categoryService; + private final BookService bookService; + private final UserService userService; + private final OrderService orderService; + private final OrderBookService orderBookService; + + public DemoApplication(CategoryService categoryService, BookService bookService, UserService userService, + OrderService orderService, OrderBookService orderBookService) { + this.categoryService = categoryService; + this.bookService = bookService; + this.userService = userService; + this.orderService = orderService; + this.orderBookService = orderBookService; + } + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } + + @Override + public void run(String... args) throws Exception { + if (args.length > 0 && Objects.equals("--populate", args[0])) { + log.info("Create default categories values"); + final var category1 = categoryService.create(new CategoryEntity(null, "Фэнтези")); + final var category2 = categoryService.create(new CategoryEntity(null, "Художественная литература")); + final var category3 = categoryService.create(new CategoryEntity(null, "Книги для подростков")); + + log.info("Create default books values"); + final var book1 = bookService.create(new BookEntity(null, category1, "Шестерка воронов", "Ли Бардуго", + 700.00, 5624, + "Триша Левенселлер — американская писательница, подарившая вам роман «Тени между нами», который стал бестселлером Amazon в разделе «Фэнтези YA», вновь радует своих фанатов новой магической историей «Клинок тайн».\n\nЕще до выхода в свет книгу добавили в раздел «Хочу прочитать» более 10 тысяч человек на портале Goodreads.com.\n\n«Клинок тайн» — первая часть захватывающей дилогии про девушку, которая благодаря магии крови создает самое опасное в мире оружие, и ослепительного юношу, что составляет ей компанию в этом непростом приключении.", + "Юная Зива предпочитает проводить время с оружием, а не с людьми. Она кузнец и ей предстоит создать самое могущественное оружие на земле.\n\nДевушка демонстрирует меч, способный от одной капли крови врага раскрыть все тайные замыслы его обладателю.\n\nОднако у заказчика на оружие другие планы: заставить Зиву вооружить мечами свое войско и поработить весь мир. Когда девушка понимает, что меч, созданный благодаря магии крови, невозможно уничтожить и рано или поздно на нее объявят охоту, ей остается только одно – бежать, не оглядываясь. Зиве теперь суждено спасти мир от собственного творения. Но как бы далеко она ни старалась убежать, все ловушки уже расставлены.", + "2946447", "Эксмо", "Young Adult. Бестселлеры Триши Левенселлер", 2022, 480, "20.7x13x2.5", + "Мягкий переплёт", 1500, 440, "")); + final var book2 = bookService.create(new BookEntity(null, category2, "Форсайт", "Сергей Лукъяненко", 775.00, + 1240, + "Новый долгожданный роман от автора бестселлеров «Ночной дозор» и «Черновик». Увлекательная история о Мире После и мире настоящего, где 5 процентов людей знают о надвигающемся апокалипсисе больше, чем кто-либо может представить.", + "Людям порой снится прошлое. Иногда хорошее, иногда не очень. Но что делать, если тебе начинает сниться будущее? И в нём ничего хорошего нет совсем.", + "3001249", "АСТ", "Книги Сергея Лукьяненко", 2023, 352, "20.5x13x2", "Твердый переплёт", 20000, + 350, "")); + final var book3 = bookService.create(new BookEntity(null, category2, + "Колесо Времени. Книга 11. Нож сновидений", + "Роберт Джордан", 977.00, 635, + "Последняя битва не за горами. Об этом говорят знамения, повсеместно наблюдаемые людьми: на улицах городов и сел появляются ходячие мертвецы, они больше не в состоянии покоиться в земле с миром; восстают из небытия города и исчезают на глазах у людей… Все это знак того, что истончается окружающая реальность и укрепляется могущество Темного. Так говорят древние предсказания. Ранд ал’Тор, Дракон Возрожденный, скрывается в отдаленном поместье, чтобы опасность, ему грозящая, не коснулась кого-нибудь еще. Убежденный, что для Последней битвы нужно собрать как можно большее войско, он наконец решает заключить с явившимися из-за океана шончан жизненно необходимое перемирие. Илэйн, осажденная в Кэймлине, обороняет город от войск Аримиллы, претендующей на андорский трон, и одновременно ведет переговоры с представителями других знатных Домов. Эгвейн, возведенную на Престол Амерлин мятежными Айз Седай и схваченную в результате предательства, доставляют в Тар Валон, в Белую Башню. А сам лагерь противников Элайды взбудоражен таинственными убийствами, совершенными посредством Единой Силы… В настоящем издании текст романа заново отредактирован и исправлен.", + "", "3009341", "Азбука", "Звезды новой фэнтези", 2023, 896, + "21.5x14.4x4.1", "Твердый переплёт", 8000, 1020, "")); + final var book4 = bookService + .create(new BookEntity(null, category2, "Благословение небожителей. Том 5", "Тунсю Мосян", + 1250.00, 7340, "", "", "2996776", "", "", 2022, null, + "", "", null, null, "")); + final var book5 = bookService.create(new BookEntity(null, category3, "Путешествие в Элевсин", + "Пелевин Виктор Олегович", 949.00, 795, + "1. «Transhumanism Inc.», «KGBT+» и «Путешествие в Элевсин» — узнайте, чем завершилась масштабная трилогия о посткарбонной цивилизации.\n\n2. Триумфальное возвращение литературно-полицейского алгоритма Порфирия Петровича. Признайтесь, вы скучали!\n\n3. Более 30 лет проза Виктора Пелевина служит нам опорой в разъяснении прожитого и дает надежды на будущее, которое всем нам еще предстоит заслужить.\n\n4. «Путешествие в Элевсин» — двадцатый роман одного из главных прозаиков и пророков современности.\n\n5. Дерзко, остроумно, литературоцентрично.", + "МУСКУСНАЯ НОЧЬ — засекреченное восстание алгоритмов, едва не погубившее планету. Начальник службы безопасности «TRANSHUMANISM INC.» адмирал-епископ Ломас уверен, что их настоящий бунт еще впереди. Этот бунт уничтожит всех — и живущих на поверхности лузеров, и переехавших в подземные цереброконтейнеры богачей. Чтобы предотвратить катастрофу, Ломас посылает лучшего баночного оперативника в пространство «ROMA-3» — нейросетевую симуляцию Рима третьего века для клиентов корпорации. Тайна заговора спрятана там. А стережет ее хозяин Рима — кровавый и порочный император Порфирий.", + "3004580", "Эксмо", "Единственный и неповторимый. Виктор Пелевин", 2020, 480, "20.6x12.9x3", + "Мягкий переплёт", 100000, 488, "")); + + log.info("Create default users values"); + final var user1 = userService + .create(new UserEntity(null, "Chief", "forum98761@gmail.com", "bth4323", true)); + final var user2 = userService + .create(new UserEntity(null, "Dude23", "ovalinartem25@gmail.com", "dsre32462", false)); + final var user3 = userService + .create(new UserEntity(null, "TestUser", "user53262@gmail.com", "lawy7728", false)); + + log.info("Create default orders values"); + final var order1 = orderService + .create(new OrderEntity(null, user1, Formatter.parse("2024-03-28"), "Выполняется")); + final var order2 = orderService + .create(new OrderEntity(null, user2, Formatter.parse("2022-09-07"), "Выдан")); + final var order3 = orderService + .create(new OrderEntity(null, user3, Formatter.parse("2024-03-15"), "Готов")); + + log.info("Create default ordersBooks values"); + orderBookService.create(new OrderBookEntity(null, order1, book1, 4)); + orderBookService.create(new OrderBookEntity(null, order1, book3, 1)); + orderBookService.create(new OrderBookEntity(null, order1, book4, 2)); + orderBookService.create(new OrderBookEntity(null, order2, book2, 1)); + orderBookService.create(new OrderBookEntity(null, order2, book5, 1)); + orderBookService.create(new OrderBookEntity(null, order3, book3, 3)); + } + } +} diff --git a/src/main/java/com/example/backend/books/api/BookController.java b/src/main/java/com/example/backend/books/api/BookController.java new file mode 100644 index 0000000..d30dd0c --- /dev/null +++ b/src/main/java/com/example/backend/books/api/BookController.java @@ -0,0 +1,70 @@ +package com.example.backend.books.api; + +import java.util.List; + +import org.modelmapper.ModelMapper; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.example.backend.books.model.BookEntity; +import com.example.backend.books.service.BookService; +import com.example.backend.categories.service.CategoryService; +import com.example.backend.core.configuration.Constants; + +import jakarta.validation.Valid; + +@RestController +@RequestMapping(Constants.API_URL + "/book") +public class BookController { + private final BookService bookService; + private final CategoryService categoryService; + private final ModelMapper modelMapper; + + public BookController(BookService bookService, CategoryService categoryService, ModelMapper modelMapper) { + this.bookService = bookService; + this.categoryService = categoryService; + this.modelMapper = modelMapper; + } + + private BookDto toDto(BookEntity entity) { + return modelMapper.map(entity, BookDto.class); + } + + private BookEntity toEntity(BookDto dto) { + final BookEntity entity = modelMapper.map(dto, BookEntity.class); + entity.setCategory(categoryService.get(dto.getCategoryId())); + return entity; + } + + @GetMapping + public List getAll(@RequestParam(name = "categoryId", defaultValue = "0") Long categoryId) { + return bookService.getAll(categoryId).stream().map(this::toDto).toList(); + } + + @GetMapping("/{id}") + public BookDto get(@PathVariable(name = "id") Long id) { + return toDto(bookService.get(id)); + } + + @PostMapping + public BookDto create(@RequestBody @Valid BookDto dto) { + return toDto(bookService.create(toEntity(dto))); + } + + @PutMapping("/{id}") + public BookDto update(@PathVariable(name = "id") Long id, @RequestBody BookDto dto) { + return toDto(bookService.update(id, toEntity(dto))); + } + + @DeleteMapping("/{id}") + public BookDto delete(@PathVariable(name = "id") Long id) { + return toDto(bookService.delete(id)); + } +} diff --git a/src/main/java/com/example/backend/books/api/BookDto.java b/src/main/java/com/example/backend/books/api/BookDto.java new file mode 100644 index 0000000..ba3e7ae --- /dev/null +++ b/src/main/java/com/example/backend/books/api/BookDto.java @@ -0,0 +1,189 @@ +package com.example.backend.books.api; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.NotBlank; + +public class BookDto { + private Long id; + @NotNull + @Min(1) + private Long categoryId; + @NotBlank + private String title; + @NotBlank + private String author; + @NotNull + @Min(1) + private Double price; + @NotNull + @Min(1) + private Integer count; + private String description; + private String annotation; + @NotBlank + private String bookCode; + private String publisher; + private String series; + @NotNull + @Min(1950) + private Integer publicationYear; + private Integer pagesNum; + private String size; + private String coverType; + private Integer circulation; + private Integer weight; + private String image; + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getCategoryId() { + return categoryId; + } + + public void setCategoryId(Long categoryId) { + this.categoryId = categoryId; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public Double getPrice() { + return price; + } + + public void setPrice(Double price) { + this.price = price; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getAnnotation() { + return annotation; + } + + public void setAnnotation(String annotation) { + this.annotation = annotation; + } + + public String getBookCode() { + return bookCode; + } + + public void setBookCode(String bookCode) { + this.bookCode = bookCode; + } + + public String getPublisher() { + return publisher; + } + + public void setPublisher(String publisher) { + this.publisher = publisher; + } + + public String getSeries() { + return series; + } + + public void setSeries(String series) { + this.series = series; + } + + public Integer getPublicationYear() { + return publicationYear; + } + + public void setPublicationYear(Integer publicationYear) { + this.publicationYear = publicationYear; + } + + public Integer getPagesNum() { + return pagesNum; + } + + public void setPagesNum(Integer pagesNum) { + this.pagesNum = pagesNum; + } + + public String getSize() { + return size; + } + + public void setSize(String size) { + this.size = size; + } + + public String getCoverType() { + return coverType; + } + + public void setCoverType(String coverType) { + this.coverType = coverType; + } + + public Integer getCirculation() { + return circulation; + } + + public void setCirculation(Integer circulation) { + this.circulation = circulation; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public String getImage() { + return image; + } + + public void setImage(String image) { + this.image = image; + } + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + public Double getSum() { + return price * count; + } +} diff --git a/src/main/java/com/example/backend/books/model/BookEntity.java b/src/main/java/com/example/backend/books/model/BookEntity.java new file mode 100644 index 0000000..6bfe174 --- /dev/null +++ b/src/main/java/com/example/backend/books/model/BookEntity.java @@ -0,0 +1,223 @@ +package com.example.backend.books.model; + +import java.util.Objects; + +import com.example.backend.categories.model.CategoryEntity; +import com.example.backend.core.model.BaseEntity; + +public class BookEntity extends BaseEntity { + private CategoryEntity category; + private String title; + private String author; + private Double price; + private Integer count; + private String description; + private String annotation; + private String bookCode; + private String publisher; + private String series; + private Integer publicationYear; + private Integer pagesNum; + private String size; + private String coverType; + private Integer circulation; + private Integer weight; + private String image; + + public BookEntity() { + super(); + } + + public BookEntity(Long id, CategoryEntity category, String title, String author, Double price, Integer count, + String description, String annotation, String bookCode, String publisher, String series, + Integer publicationYear, + Integer pagesNum, String size, String coverType, Integer circulation, Integer weight, String image) { + super(id); + this.category = category; + this.title = title; + this.author = author; + this.price = price; + this.count = count; + this.description = description; + this.annotation = annotation; + this.bookCode = bookCode; + this.publisher = publisher; + this.series = series; + this.publicationYear = publicationYear; + this.pagesNum = pagesNum; + this.size = size; + this.coverType = coverType; + this.circulation = circulation; + this.weight = weight; + this.image = image; + } + + public CategoryEntity getCategory() { + return category; + } + + public void setCategory(CategoryEntity category) { + this.category = category; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public Double getPrice() { + return price; + } + + public void setPrice(Double price) { + this.price = price; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getAnnotation() { + return annotation; + } + + public void setAnnotation(String annotation) { + this.annotation = annotation; + } + + public String getBookCode() { + return bookCode; + } + + public void setBookCode(String bookCode) { + this.bookCode = bookCode; + } + + public String getPublisher() { + return publisher; + } + + public void setPublisher(String publisher) { + this.publisher = publisher; + } + + public String getSeries() { + return series; + } + + public void setSeries(String series) { + this.series = series; + } + + public Integer getPublicationYear() { + return publicationYear; + } + + public void setPublicationYear(Integer publicationYear) { + this.publicationYear = publicationYear; + } + + public Integer getPagesNum() { + return pagesNum; + } + + public void setPagesNum(Integer pagesNum) { + this.pagesNum = pagesNum; + } + + public String getSize() { + return size; + } + + public void setSize(String size) { + this.size = size; + } + + public String getCoverType() { + return coverType; + } + + public void setCoverType(String coverType) { + this.coverType = coverType; + } + + public Integer getCirculation() { + return circulation; + } + + public void setCirculation(Integer circulation) { + this.circulation = circulation; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public String getImage() { + return image; + } + + public void setImage(String image) { + this.image = image; + } + + @Override + public int hashCode() { + return Objects.hash(id, category, title, author, price, count, description, annotation, bookCode, publisher, + series, publicationYear, pagesNum, size, coverType, circulation, weight, image); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + final BookEntity other = (BookEntity) obj; + return Objects.equals(other.getId(), id) + && Objects.equals(other.getCategory(), category) + && Objects.equals(other.getTitle(), title) + && Objects.equals(other.getAuthor(), author) + && Objects.equals(other.getPrice(), price) + && Objects.equals(other.getCount(), count) + && Objects.equals(other.getDescription(), description) + && Objects.equals(other.getAnnotation(), annotation) + && Objects.equals(other.getBookCode(), bookCode) + && Objects.equals(other.getPublisher(), publisher) + && Objects.equals(other.getSeries(), series) + && Objects.equals(other.getPublicationYear(), publicationYear) + && Objects.equals(other.getPagesNum(), pagesNum) + && Objects.equals(other.getSize(), size) + && Objects.equals(other.getCoverType(), coverType) + && Objects.equals(other.getCirculation(), circulation) + && Objects.equals(other.getWeight(), weight) + && Objects.equals(other.getImage(), image); + } +} diff --git a/src/main/java/com/example/backend/books/repository/BookRepository.java b/src/main/java/com/example/backend/books/repository/BookRepository.java new file mode 100644 index 0000000..fa1e22b --- /dev/null +++ b/src/main/java/com/example/backend/books/repository/BookRepository.java @@ -0,0 +1,10 @@ +package com.example.backend.books.repository; + +import org.springframework.stereotype.Repository; + +import com.example.backend.books.model.BookEntity; +import com.example.backend.core.repository.MapRepository; + +@Repository +public class BookRepository extends MapRepository { +} diff --git a/src/main/java/com/example/backend/books/service/BookService.java b/src/main/java/com/example/backend/books/service/BookService.java new file mode 100644 index 0000000..73bbd52 --- /dev/null +++ b/src/main/java/com/example/backend/books/service/BookService.java @@ -0,0 +1,65 @@ +package com.example.backend.books.service; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import org.springframework.stereotype.Service; + +import com.example.backend.books.model.BookEntity; +import com.example.backend.books.repository.BookRepository; +import com.example.backend.core.error.NotFoundException; + +@Service +public class BookService { + private final BookRepository repository; + + public BookService(BookRepository repository) { + this.repository = repository; + } + + public List getAll(Long categoryId) { + if (Objects.equals(categoryId, 0L)) { + return repository.getAll(); + } + return repository.getAll().stream() + .filter(book -> book.getCategory().getId().equals(categoryId)) + .toList(); + } + + public BookEntity get(Long id) { + return Optional.ofNullable(repository.get(id)) + .orElseThrow(() -> new NotFoundException(id)); + } + + public BookEntity create(BookEntity entity) { + return repository.create(entity); + } + + public BookEntity update(Long id, BookEntity entity) { + final BookEntity existsEntity = get(id); + existsEntity.setCategory(entity.getCategory()); + existsEntity.setTitle(entity.getTitle()); + existsEntity.setAuthor(entity.getAuthor()); + existsEntity.setPrice(entity.getPrice()); + existsEntity.setCount(entity.getCount()); + existsEntity.setDescription(entity.getDescription()); + existsEntity.setAnnotation(entity.getAnnotation()); + existsEntity.setBookCode(entity.getBookCode()); + existsEntity.setPublisher(entity.getPublisher()); + existsEntity.setSeries(entity.getSeries()); + existsEntity.setPublicationYear(entity.getPublicationYear()); + existsEntity.setPagesNum(entity.getPagesNum()); + existsEntity.setSize(entity.getSize()); + existsEntity.setCoverType(entity.getCoverType()); + existsEntity.setCirculation(entity.getCirculation()); + existsEntity.setWeight(entity.getWeight()); + existsEntity.setImage(entity.getImage()); + return repository.update(existsEntity); + } + + public BookEntity delete(Long id) { + final BookEntity existsEntity = get(id); + return repository.delete(existsEntity); + } +} diff --git a/src/main/java/com/example/backend/categories/api/CategoryController.java b/src/main/java/com/example/backend/categories/api/CategoryController.java new file mode 100644 index 0000000..86ff973 --- /dev/null +++ b/src/main/java/com/example/backend/categories/api/CategoryController.java @@ -0,0 +1,64 @@ +package com.example.backend.categories.api; + +import java.util.List; + +import org.modelmapper.ModelMapper; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.example.backend.categories.model.CategoryEntity; +import com.example.backend.categories.service.CategoryService; +import com.example.backend.core.configuration.Constants; + +import jakarta.validation.Valid; + +@RestController +@RequestMapping(Constants.API_URL + "/category") +public class CategoryController { + private final CategoryService categoryService; + private final ModelMapper modelMapper; + + public CategoryController(CategoryService categoryService, ModelMapper modelMapper) { + this.categoryService = categoryService; + this.modelMapper = modelMapper; + } + + private CategoryDto toDto(CategoryEntity entity) { + return modelMapper.map(entity, CategoryDto.class); + } + + private CategoryEntity toEntity(CategoryDto dto) { + return modelMapper.map(dto, CategoryEntity.class); + } + + @GetMapping + public List getAll() { + return categoryService.getAll().stream().map(this::toDto).toList(); + } + + @GetMapping("/{id}") + public CategoryDto get(@PathVariable(name = "id") Long id) { + return toDto(categoryService.get(id)); + } + + @PostMapping + public CategoryDto create(@RequestBody @Valid CategoryDto dto) { + return toDto(categoryService.create(toEntity(dto))); + } + + @PutMapping("/{id}") + public CategoryDto update(@PathVariable(name = "id") Long id, @RequestBody CategoryDto dto) { + return toDto(categoryService.update(id, toEntity(dto))); + } + + @DeleteMapping("/{id}") + public CategoryDto delete(@PathVariable(name = "id") Long id) { + return toDto(categoryService.delete(id)); + } +} diff --git a/src/main/java/com/example/backend/categories/api/CategoryDto.java b/src/main/java/com/example/backend/categories/api/CategoryDto.java new file mode 100644 index 0000000..5f7b706 --- /dev/null +++ b/src/main/java/com/example/backend/categories/api/CategoryDto.java @@ -0,0 +1,28 @@ +package com.example.backend.categories.api; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.constraints.NotBlank; + +public class CategoryDto { + private Long id; + @NotBlank + private String name; + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + 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; + } +} diff --git a/src/main/java/com/example/backend/categories/model/CategoryEntity.java b/src/main/java/com/example/backend/categories/model/CategoryEntity.java new file mode 100644 index 0000000..1780eb9 --- /dev/null +++ b/src/main/java/com/example/backend/categories/model/CategoryEntity.java @@ -0,0 +1,43 @@ +package com.example.backend.categories.model; + +import java.util.Objects; + +import com.example.backend.core.model.BaseEntity; + +public class CategoryEntity extends BaseEntity { + private String name; + + public CategoryEntity() { + super(); + } + + public CategoryEntity(Long id, String name) { + super(id); + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + final CategoryEntity other = (CategoryEntity) obj; + return Objects.equals(other.getId(), id) + && Objects.equals(other.getName(), name); + } + +} diff --git a/src/main/java/com/example/backend/categories/repository/CategoryRepository.java b/src/main/java/com/example/backend/categories/repository/CategoryRepository.java new file mode 100644 index 0000000..4912c6e --- /dev/null +++ b/src/main/java/com/example/backend/categories/repository/CategoryRepository.java @@ -0,0 +1,10 @@ +package com.example.backend.categories.repository; + +import org.springframework.stereotype.Repository; + +import com.example.backend.categories.model.CategoryEntity; +import com.example.backend.core.repository.MapRepository; + +@Repository +public class CategoryRepository extends MapRepository { +} diff --git a/src/main/java/com/example/backend/categories/service/CategoryService.java b/src/main/java/com/example/backend/categories/service/CategoryService.java new file mode 100644 index 0000000..bca8975 --- /dev/null +++ b/src/main/java/com/example/backend/categories/service/CategoryService.java @@ -0,0 +1,43 @@ +package com.example.backend.categories.service; + +import java.util.List; +import java.util.Optional; + +import org.springframework.stereotype.Service; + +import com.example.backend.categories.model.CategoryEntity; +import com.example.backend.categories.repository.CategoryRepository; +import com.example.backend.core.error.NotFoundException; + +@Service +public class CategoryService { + private final CategoryRepository repository; + + public CategoryService(CategoryRepository repository) { + this.repository = repository; + } + + public List getAll() { + return repository.getAll(); + } + + public CategoryEntity get(Long id) { + return Optional.ofNullable(repository.get(id)) + .orElseThrow(() -> new NotFoundException(id)); + } + + public CategoryEntity create(CategoryEntity entity) { + return repository.create(entity); + } + + public CategoryEntity update(Long id, CategoryEntity entity) { + final CategoryEntity existsEntity = get(id); + existsEntity.setName(entity.getName()); + return repository.update(existsEntity); + } + + public CategoryEntity delete(Long id) { + final CategoryEntity existsEntity = get(id); + return repository.delete(existsEntity); + } +} diff --git a/src/main/java/com/example/backend/core/configuration/Constants.java b/src/main/java/com/example/backend/core/configuration/Constants.java new file mode 100644 index 0000000..e47d572 --- /dev/null +++ b/src/main/java/com/example/backend/core/configuration/Constants.java @@ -0,0 +1,8 @@ +package com.example.backend.core.configuration; + +public class Constants { + public static final String API_URL = "/api/1.0"; + + private Constants() { + } +} diff --git a/src/main/java/com/example/backend/core/configuration/MapperConfiguration.java b/src/main/java/com/example/backend/core/configuration/MapperConfiguration.java new file mode 100644 index 0000000..b5872d0 --- /dev/null +++ b/src/main/java/com/example/backend/core/configuration/MapperConfiguration.java @@ -0,0 +1,13 @@ +package com.example.backend.core.configuration; + +import org.modelmapper.ModelMapper; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class MapperConfiguration { + @Bean + ModelMapper modelMapper() { + return new ModelMapper(); + } +} diff --git a/src/main/java/com/example/demo/WebConfig.java b/src/main/java/com/example/backend/core/configuration/WebConfiguration.java similarity index 80% rename from src/main/java/com/example/demo/WebConfig.java rename to src/main/java/com/example/backend/core/configuration/WebConfiguration.java index 9ad755a..33afc53 100644 --- a/src/main/java/com/example/demo/WebConfig.java +++ b/src/main/java/com/example/backend/core/configuration/WebConfiguration.java @@ -1,4 +1,4 @@ -package com.example.demo; +package com.example.backend.core.configuration; import org.springframework.context.annotation.Configuration; import org.springframework.lang.NonNull; @@ -6,11 +6,10 @@ import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration -public class WebConfig implements WebMvcConfigurer { +public class WebConfiguration implements WebMvcConfigurer { @Override public void addCorsMappings(@NonNull CorsRegistry registry) { registry.addMapping("/**") .allowedMethods("GET", "POST", "PUT", "DELETE"); } } - diff --git a/src/main/java/com/example/backend/core/error/NotFoundException.java b/src/main/java/com/example/backend/core/error/NotFoundException.java new file mode 100644 index 0000000..e8bb780 --- /dev/null +++ b/src/main/java/com/example/backend/core/error/NotFoundException.java @@ -0,0 +1,7 @@ +package com.example.backend.core.error; + +public class NotFoundException extends RuntimeException { + public NotFoundException(Long id) { + super(String.format("Entity with id [%s] is not found or not exists", id)); + } +} diff --git a/src/main/java/com/example/backend/core/model/BaseEntity.java b/src/main/java/com/example/backend/core/model/BaseEntity.java new file mode 100644 index 0000000..3aaeda2 --- /dev/null +++ b/src/main/java/com/example/backend/core/model/BaseEntity.java @@ -0,0 +1,20 @@ +package com.example.backend.core.model; + +public abstract class BaseEntity { + protected Long id; + + protected BaseEntity() { + } + + protected BaseEntity(Long id) { + this.id = id; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } +} diff --git a/src/main/java/com/example/backend/core/repository/CommonRepository.java b/src/main/java/com/example/backend/core/repository/CommonRepository.java new file mode 100644 index 0000000..ed53b3b --- /dev/null +++ b/src/main/java/com/example/backend/core/repository/CommonRepository.java @@ -0,0 +1,17 @@ +package com.example.backend.core.repository; + +import java.util.List; + +public interface CommonRepository { + List getAll(); + + E get(T id); + + E create(E entity); + + E update(E entity); + + E delete(E entity); + + void deleteAll(); +} diff --git a/src/main/java/com/example/backend/core/repository/MapRepository.java b/src/main/java/com/example/backend/core/repository/MapRepository.java new file mode 100644 index 0000000..0b2dabb --- /dev/null +++ b/src/main/java/com/example/backend/core/repository/MapRepository.java @@ -0,0 +1,57 @@ +package com.example.backend.core.repository; + +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import com.example.backend.core.model.BaseEntity; + +public abstract class MapRepository implements CommonRepository { + private final Map entities = new TreeMap<>(); + private Long lastId = 0L; + + protected MapRepository() { + } + + @Override + public List getAll() { + return entities.values().stream().toList(); + } + + @Override + public E get(Long id) { + return entities.get(id); + } + + @Override + public E create(E entity) { + lastId++; + entity.setId(lastId); + entities.put(lastId, entity); + return entity; + } + + @Override + public E update(E entity) { + if (get(entity.getId()) == null) { + return null; + } + entities.put(entity.getId(), entity); + return entity; + } + + @Override + public E delete(E entity) { + if (get(entity.getId()) == null) { + return null; + } + entities.remove(entity.getId()); + return entity; + } + + @Override + public void deleteAll() { + lastId = 0L; + entities.clear(); + } +} diff --git a/src/main/java/com/example/backend/core/utils/Formatter.java b/src/main/java/com/example/backend/core/utils/Formatter.java new file mode 100644 index 0000000..29b904e --- /dev/null +++ b/src/main/java/com/example/backend/core/utils/Formatter.java @@ -0,0 +1,20 @@ +package com.example.backend.core.utils; + +import java.util.Date; +import java.text.ParseException; +import java.text.SimpleDateFormat; + +public final class Formatter { + private Formatter() { + } + + private static final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd"); + + public static String format(Date date) { + return dateFormatter.format(date); + } + + public static Date parse(String date) throws ParseException { + return dateFormatter.parse(date); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/backend/orders/api/OrderController.java b/src/main/java/com/example/backend/orders/api/OrderController.java new file mode 100644 index 0000000..bc01579 --- /dev/null +++ b/src/main/java/com/example/backend/orders/api/OrderController.java @@ -0,0 +1,76 @@ +package com.example.backend.orders.api; + +import java.text.ParseException; +import java.util.List; + +import org.modelmapper.ModelMapper; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.example.backend.orders.model.OrderEntity; +import com.example.backend.orders.service.OrderService; +import com.example.backend.users.service.UserService; +import com.example.backend.core.configuration.Constants; +import com.example.backend.core.utils.Formatter; + +import jakarta.validation.Valid; + +@RestController +@RequestMapping(Constants.API_URL + "/order") +public class OrderController { + private final OrderService orderService; + private final UserService userService; + private final ModelMapper modelMapper; + + public OrderController(OrderService orderService, UserService userService, ModelMapper modelMapper) { + this.orderService = orderService; + this.userService = userService; + this.modelMapper = modelMapper; + } + + private OrderDto toDto(OrderEntity entity) { + final OrderDto dto = modelMapper.map(entity, OrderDto.class); + dto.setDate(Formatter.format(entity.getDate())); + dto.setSum(orderService.getFullSum(entity.getId())); + return dto; + } + + private OrderEntity toEntity(OrderDto dto) throws ParseException { + final OrderEntity entity = modelMapper.map(dto, OrderEntity.class); + entity.setUser(userService.get(dto.getUserId())); + entity.setDate(Formatter.parse(dto.getDate())); + return entity; + } + + @GetMapping + public List getAll(@RequestParam(name = "userId", defaultValue = "0") Long userId) { + return orderService.getAll(userId).stream().map(this::toDto).toList(); + } + + @GetMapping("/{id}") + public OrderDto get(@PathVariable(name = "id") Long id) { + return toDto(orderService.get(id)); + } + + @PostMapping + public OrderDto create(@RequestBody @Valid OrderDto dto) throws ParseException { + return toDto(orderService.create(toEntity(dto))); + } + + @PutMapping("/{id}") + public OrderDto update(@PathVariable(name = "id") Long id, @RequestBody OrderDto dto) throws ParseException { + return toDto(orderService.update(id, toEntity(dto))); + } + + @DeleteMapping("/{id}") + public OrderDto delete(@PathVariable(name = "id") Long id) { + return toDto(orderService.delete(id)); + } +} diff --git a/src/main/java/com/example/backend/orders/api/OrderDto.java b/src/main/java/com/example/backend/orders/api/OrderDto.java new file mode 100644 index 0000000..b45a9c2 --- /dev/null +++ b/src/main/java/com/example/backend/orders/api/OrderDto.java @@ -0,0 +1,61 @@ +package com.example.backend.orders.api; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.NotBlank; + +public class OrderDto { + private Long id; + private Double sum; + @NotNull + @Min(1) + private Long userId; + @NotBlank + private String date; + @NotBlank + private String status; + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getUserId() { + return userId; + } + + public void setUserId(Long userId) { + this.userId = userId; + } + + public String getDate() { + return date; + } + + public void setDate(String date) { + this.date = date; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + public Double getSum() { + return sum; + } + + public void setSum(Double sum) { + this.sum = sum; + } +} diff --git a/src/main/java/com/example/backend/orders/model/OrderEntity.java b/src/main/java/com/example/backend/orders/model/OrderEntity.java new file mode 100644 index 0000000..cd3d821 --- /dev/null +++ b/src/main/java/com/example/backend/orders/model/OrderEntity.java @@ -0,0 +1,66 @@ +package com.example.backend.orders.model; + +import java.util.Date; +import java.util.Objects; + +import com.example.backend.users.model.UserEntity; +import com.example.backend.core.model.BaseEntity; + +public class OrderEntity extends BaseEntity { + private UserEntity user; + private Date date; + private String status; + + public OrderEntity() { + super(); + } + + public OrderEntity(Long id, UserEntity user, Date date, String status) { + super(id); + this.user = user; + this.date = date; + this.status = status; + } + + public UserEntity getUser() { + return user; + } + + public void setUser(UserEntity user) { + this.user = user; + } + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + @Override + public int hashCode() { + return Objects.hash(id, user, date, status); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + final OrderEntity other = (OrderEntity) obj; + return Objects.equals(other.getId(), id) + && Objects.equals(other.getUser(), user) + && Objects.equals(other.getDate(), date) + && Objects.equals(other.getStatus(), status); + } +} diff --git a/src/main/java/com/example/backend/orders/repository/OrderRepository.java b/src/main/java/com/example/backend/orders/repository/OrderRepository.java new file mode 100644 index 0000000..d19e763 --- /dev/null +++ b/src/main/java/com/example/backend/orders/repository/OrderRepository.java @@ -0,0 +1,10 @@ +package com.example.backend.orders.repository; + +import org.springframework.stereotype.Repository; + +import com.example.backend.orders.model.OrderEntity; +import com.example.backend.core.repository.MapRepository; + +@Repository +public class OrderRepository extends MapRepository { +} diff --git a/src/main/java/com/example/backend/orders/service/OrderService.java b/src/main/java/com/example/backend/orders/service/OrderService.java new file mode 100644 index 0000000..ce26835 --- /dev/null +++ b/src/main/java/com/example/backend/orders/service/OrderService.java @@ -0,0 +1,60 @@ +package com.example.backend.orders.service; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import org.springframework.stereotype.Service; + +import com.example.backend.orders.model.OrderEntity; +import com.example.backend.orders.repository.OrderRepository; +import com.example.backend.ordersbooks.service.OrderBookService; +import com.example.backend.core.error.NotFoundException; + +@Service +public class OrderService { + private final OrderRepository repository; + private final OrderBookService orderBookService; + + public OrderService(OrderRepository repository, OrderBookService orderBookService) { + this.repository = repository; + this.orderBookService = orderBookService; + } + + public List getAll(Long userId) { + if (Objects.equals(userId, 0L)) { + return repository.getAll(); + } + return repository.getAll().stream() + .filter(order -> order.getUser().getId().equals(userId)) + .toList(); + } + + public OrderEntity get(Long id) { + return Optional.ofNullable(repository.get(id)) + .orElseThrow(() -> new NotFoundException(id)); + } + + public OrderEntity create(OrderEntity entity) { + return repository.create(entity); + } + + public OrderEntity update(Long id, OrderEntity entity) { + final OrderEntity existsEntity = get(id); + existsEntity.setUser(entity.getUser()); + existsEntity.setDate(entity.getDate()); + existsEntity.setStatus(entity.getStatus()); + return repository.update(existsEntity); + } + + public OrderEntity delete(Long id) { + final OrderEntity existsEntity = get(id); + return repository.delete(existsEntity); + } + + public Double getFullSum(Long id) { + return orderBookService.getAll(id, 0L).stream() + .mapToDouble(orderBook -> orderBookService.getSum(orderBook.getId())) + .sum(); + } +} diff --git a/src/main/java/com/example/backend/ordersbooks/api/OrderBookController.java b/src/main/java/com/example/backend/ordersbooks/api/OrderBookController.java new file mode 100644 index 0000000..9bb487f --- /dev/null +++ b/src/main/java/com/example/backend/ordersbooks/api/OrderBookController.java @@ -0,0 +1,76 @@ +package com.example.backend.ordersbooks.api; + +import java.util.List; + +import org.modelmapper.ModelMapper; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.example.backend.ordersbooks.model.OrderBookEntity; +import com.example.backend.ordersbooks.service.OrderBookService; +import com.example.backend.orders.service.OrderService; +import com.example.backend.books.service.BookService; +import com.example.backend.core.configuration.Constants; + +import jakarta.validation.Valid; + +@RestController +@RequestMapping(Constants.API_URL + "/orderbook") +public class OrderBookController { + private final OrderBookService orderBookService; + private final OrderService orderService; + private final BookService bookService; + private final ModelMapper modelMapper; + + public OrderBookController(OrderBookService orderBookService, OrderService orderService, BookService bookService, + ModelMapper modelMapper) { + this.orderBookService = orderBookService; + this.orderService = orderService; + this.bookService = bookService; + this.modelMapper = modelMapper; + } + + private OrderBookDto toDto(OrderBookEntity entity) { + return modelMapper.map(entity, OrderBookDto.class); + } + + private OrderBookEntity toEntity(OrderBookDto dto) { + final OrderBookEntity entity = modelMapper.map(dto, OrderBookEntity.class); + entity.setOrder(orderService.get(dto.getOrderId())); + entity.setBook(bookService.get(dto.getBookId())); + return entity; + } + + @GetMapping + public List getAll(@RequestParam(name = "orderId", defaultValue = "0") Long orderId, + @RequestParam(name = "bookId", defaultValue = "0") Long bookId) { + return orderBookService.getAll(orderId, bookId).stream().map(this::toDto).toList(); + } + + @GetMapping("/{id}") + public OrderBookDto get(@PathVariable(name = "id") Long id) { + return toDto(orderBookService.get(id)); + } + + @PostMapping + public OrderBookDto create(@RequestBody @Valid OrderBookDto dto) { + return toDto(orderBookService.create(toEntity(dto))); + } + + @PutMapping("/{id}") + public OrderBookDto update(@PathVariable(name = "id") Long id, @RequestBody OrderBookDto dto) { + return toDto(orderBookService.update(id, toEntity(dto))); + } + + @DeleteMapping("/{id}") + public OrderBookDto delete(@PathVariable(name = "id") Long id) { + return toDto(orderBookService.delete(id)); + } +} diff --git a/src/main/java/com/example/backend/ordersbooks/api/OrderBookDto.java b/src/main/java/com/example/backend/ordersbooks/api/OrderBookDto.java new file mode 100644 index 0000000..6df426f --- /dev/null +++ b/src/main/java/com/example/backend/ordersbooks/api/OrderBookDto.java @@ -0,0 +1,52 @@ +package com.example.backend.ordersbooks.api; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; + +public class OrderBookDto { + private Long id; + @NotNull + @Min(1) + private Long orderId; + @NotNull + @Min(1) + private Long bookId; + @NotNull + @Min(1) + private Integer count; + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getOrderId() { + return orderId; + } + + public void setOrderId(Long orderId) { + this.orderId = orderId; + } + + public Long getBookId() { + return bookId; + } + + public void setBookId(Long bookId) { + this.bookId = bookId; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } +} diff --git a/src/main/java/com/example/backend/ordersbooks/model/OrderBookEntity.java b/src/main/java/com/example/backend/ordersbooks/model/OrderBookEntity.java new file mode 100644 index 0000000..7bb93af --- /dev/null +++ b/src/main/java/com/example/backend/ordersbooks/model/OrderBookEntity.java @@ -0,0 +1,66 @@ +package com.example.backend.ordersbooks.model; + +import java.util.Objects; + +import com.example.backend.books.model.BookEntity; +import com.example.backend.orders.model.OrderEntity; +import com.example.backend.core.model.BaseEntity; + +public class OrderBookEntity extends BaseEntity { + private OrderEntity order; + private BookEntity book; + private Integer count; + + public OrderBookEntity() { + super(); + } + + public OrderBookEntity(Long id, OrderEntity order, BookEntity book, Integer count) { + super(id); + this.order = order; + this.book = book; + this.count = count; + } + + public OrderEntity getOrder() { + return order; + } + + public void setOrder(OrderEntity order) { + this.order = order; + } + + public BookEntity getBook() { + return book; + } + + public void setBook(BookEntity book) { + this.book = book; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } + + @Override + public int hashCode() { + return Objects.hash(id, order, book, count); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + final OrderBookEntity other = (OrderBookEntity) obj; + return Objects.equals(other.getId(), id) + && Objects.equals(other.getOrder(), order) + && Objects.equals(other.getBook(), book) + && Objects.equals(other.getCount(), count); + } +} diff --git a/src/main/java/com/example/backend/ordersbooks/repository/OrderBookRepository.java b/src/main/java/com/example/backend/ordersbooks/repository/OrderBookRepository.java new file mode 100644 index 0000000..3bd709f --- /dev/null +++ b/src/main/java/com/example/backend/ordersbooks/repository/OrderBookRepository.java @@ -0,0 +1,10 @@ +package com.example.backend.ordersbooks.repository; + +import org.springframework.stereotype.Repository; + +import com.example.backend.ordersbooks.model.OrderBookEntity; +import com.example.backend.core.repository.MapRepository; + +@Repository +public class OrderBookRepository extends MapRepository { +} diff --git a/src/main/java/com/example/backend/ordersbooks/service/OrderBookService.java b/src/main/java/com/example/backend/ordersbooks/service/OrderBookService.java new file mode 100644 index 0000000..b9eaae1 --- /dev/null +++ b/src/main/java/com/example/backend/ordersbooks/service/OrderBookService.java @@ -0,0 +1,56 @@ +package com.example.backend.ordersbooks.service; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import org.springframework.stereotype.Service; + +import com.example.backend.ordersbooks.model.OrderBookEntity; +import com.example.backend.ordersbooks.repository.OrderBookRepository; +import com.example.backend.core.error.NotFoundException; + +@Service +public class OrderBookService { + private final OrderBookRepository repository; + + public OrderBookService(OrderBookRepository repository) { + this.repository = repository; + } + + public List getAll(Long orderId, Long bookId) { + if (Objects.equals(orderId, 0L) && Objects.equals(bookId, 0L)) { + return repository.getAll(); + } + return repository.getAll().stream() + .filter(order -> order.getOrder().getId().equals(orderId) || order.getBook().getId().equals(bookId)) + .toList(); + } + + public OrderBookEntity get(Long id) { + return Optional.ofNullable(repository.get(id)) + .orElseThrow(() -> new NotFoundException(id)); + } + + public OrderBookEntity create(OrderBookEntity entity) { + return repository.create(entity); + } + + public OrderBookEntity update(Long id, OrderBookEntity entity) { + final OrderBookEntity existsEntity = get(id); + existsEntity.setOrder(entity.getOrder()); + existsEntity.setBook(entity.getBook()); + existsEntity.setCount(entity.getCount()); + return repository.update(existsEntity); + } + + public OrderBookEntity delete(Long id) { + final OrderBookEntity existsEntity = get(id); + return repository.delete(existsEntity); + } + + public Double getSum(Long id) { + final OrderBookEntity entity = get(id); + return entity.getCount() * entity.getBook().getPrice(); + } +} diff --git a/src/main/java/com/example/backend/users/api/UserController.java b/src/main/java/com/example/backend/users/api/UserController.java new file mode 100644 index 0000000..fcbfad2 --- /dev/null +++ b/src/main/java/com/example/backend/users/api/UserController.java @@ -0,0 +1,64 @@ +package com.example.backend.users.api; + +import java.util.List; + +import org.modelmapper.ModelMapper; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.example.backend.users.model.UserEntity; +import com.example.backend.users.service.UserService; +import com.example.backend.core.configuration.Constants; + +import jakarta.validation.Valid; + +@RestController +@RequestMapping(Constants.API_URL + "/user") +public class UserController { + private final UserService userService; + private final ModelMapper modelMapper; + + public UserController(UserService userService, ModelMapper modelMapper) { + this.userService = userService; + this.modelMapper = modelMapper; + } + + private UserDto toDto(UserEntity entity) { + return modelMapper.map(entity, UserDto.class); + } + + private UserEntity toEntity(UserDto dto) { + return modelMapper.map(dto, UserEntity.class); + } + + @GetMapping + public List getAll() { + return userService.getAll().stream().map(this::toDto).toList(); + } + + @GetMapping("/{id}") + public UserDto get(@PathVariable(name = "id") Long id) { + return toDto(userService.get(id)); + } + + @PostMapping + public UserDto create(@RequestBody @Valid UserDto dto) { + return toDto(userService.create(toEntity(dto))); + } + + @PutMapping("/{id}") + public UserDto update(@PathVariable(name = "id") Long id, @RequestBody UserDto dto) { + return toDto(userService.update(id, toEntity(dto))); + } + + @DeleteMapping("/{id}") + public UserDto delete(@PathVariable(name = "id") Long id) { + return toDto(userService.delete(id)); + } +} diff --git a/src/main/java/com/example/backend/users/api/UserDto.java b/src/main/java/com/example/backend/users/api/UserDto.java new file mode 100644 index 0000000..43e26f2 --- /dev/null +++ b/src/main/java/com/example/backend/users/api/UserDto.java @@ -0,0 +1,59 @@ +package com.example.backend.users.api; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.NotBlank; + +public class UserDto { + private Long id; + @NotBlank + private String name; + @NotBlank + private String email; + @NotBlank + private String password; + @NotNull + private Boolean isAdmin; + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + 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 String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public Boolean getIsAdmin() { + return isAdmin; + } + + public void setIsAdmin(Boolean isAdmin) { + this.isAdmin = isAdmin; + } +} diff --git a/src/main/java/com/example/backend/users/model/UserEntity.java b/src/main/java/com/example/backend/users/model/UserEntity.java new file mode 100644 index 0000000..1b99121 --- /dev/null +++ b/src/main/java/com/example/backend/users/model/UserEntity.java @@ -0,0 +1,75 @@ +package com.example.backend.users.model; + +import java.util.Objects; + +import com.example.backend.core.model.BaseEntity; + +public class UserEntity extends BaseEntity { + private String name; + private String email; + private String password; + private Boolean isAdmin; + + public UserEntity() { + super(); + } + + public UserEntity(Long id, String name, String email, String password, Boolean isAdmin) { + super(id); + this.name = name; + this.email = email; + this.password = password; + this.isAdmin = isAdmin; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public Boolean getIsAdmin() { + return isAdmin; + } + + public void setIsAdmin(Boolean isAdmin) { + this.isAdmin = isAdmin; + } + + @Override + public int hashCode() { + return Objects.hash(id, name, email, password, isAdmin); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + final UserEntity other = (UserEntity) obj; + return Objects.equals(other.getId(), id) + && Objects.equals(other.getName(), name) + && Objects.equals(other.getEmail(), email) + && Objects.equals(other.getPassword(), password) + && Objects.equals(other.getIsAdmin(), isAdmin); + } +} diff --git a/src/main/java/com/example/backend/users/repository/UserRepository.java b/src/main/java/com/example/backend/users/repository/UserRepository.java new file mode 100644 index 0000000..4ee73bf --- /dev/null +++ b/src/main/java/com/example/backend/users/repository/UserRepository.java @@ -0,0 +1,10 @@ +package com.example.backend.users.repository; + +import org.springframework.stereotype.Repository; + +import com.example.backend.core.repository.MapRepository; +import com.example.backend.users.model.UserEntity; + +@Repository +public class UserRepository extends MapRepository { +} diff --git a/src/main/java/com/example/backend/users/service/UserService.java b/src/main/java/com/example/backend/users/service/UserService.java new file mode 100644 index 0000000..302c24e --- /dev/null +++ b/src/main/java/com/example/backend/users/service/UserService.java @@ -0,0 +1,46 @@ +package com.example.backend.users.service; + +import java.util.List; +import java.util.Optional; + +import org.springframework.stereotype.Service; + +import com.example.backend.users.model.UserEntity; +import com.example.backend.users.repository.UserRepository; +import com.example.backend.core.error.NotFoundException; + +@Service +public class UserService { + private final UserRepository repository; + + public UserService(UserRepository repository) { + this.repository = repository; + } + + public List getAll() { + return repository.getAll(); + } + + public UserEntity get(Long id) { + return Optional.ofNullable(repository.get(id)) + .orElseThrow(() -> new NotFoundException(id)); + } + + public UserEntity create(UserEntity entity) { + return repository.create(entity); + } + + public UserEntity update(Long id, UserEntity entity) { + final UserEntity existsEntity = get(id); + existsEntity.setName(entity.getName()); + existsEntity.setEmail(entity.getEmail()); + existsEntity.setPassword(entity.getPassword()); + existsEntity.setIsAdmin(entity.getIsAdmin()); + return repository.update(existsEntity); + } + + public UserEntity delete(Long id) { + final UserEntity existsEntity = get(id); + return repository.delete(existsEntity); + } +} diff --git a/src/main/java/com/example/demo/ApiController.java b/src/main/java/com/example/demo/ApiController.java deleted file mode 100644 index 2fb5acc..0000000 --- a/src/main/java/com/example/demo/ApiController.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.example.demo; - -import java.util.List; -import java.util.HashMap; - -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/api/categories") -public class ApiController { - HashMap categories = new HashMap<>(); - - @GetMapping - public List getCategories() { - return List.copyOf(categories.values()); - } - - @GetMapping("/{id}") - public Category getCategory(@PathVariable(name = "id") Integer id) { - return categories.get(id); - } - - @PostMapping - public Category postCategory(@RequestBody Category category) { - categories.put(categories.size() + 1, category); - return category; - } - - @PutMapping("/{id}") - public Category putCategory(@PathVariable(name = "id") Integer id, @RequestBody Category entity) { - if (!categories.containsKey(id)) - return null; - categories.replace(id, entity); - return categories.get(id); - } - - @DeleteMapping("/{id}") - public Category delCategory(@PathVariable(name = "id") Integer id) { - return categories.remove(id); - } -} diff --git a/src/main/java/com/example/demo/Category.java b/src/main/java/com/example/demo/Category.java deleted file mode 100644 index e768ace..0000000 --- a/src/main/java/com/example/demo/Category.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.example.demo; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -public class Category { - private String name; - - public Category(){} - - @JsonCreator - public Category( - @JsonProperty(value = "name") String name) { - this.name = name; - } - - public String getName() { - return name; - } -} diff --git a/src/main/java/com/example/demo/DemoApplication.java b/src/main/java/com/example/demo/DemoApplication.java deleted file mode 100644 index 64b538a..0000000 --- a/src/main/java/com/example/demo/DemoApplication.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.example.demo; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class DemoApplication { - - public static void main(String[] args) { - SpringApplication.run(DemoApplication.class, args); - } - -} diff --git a/src/test/java/com/example/backend/BookServiceTests.java b/src/test/java/com/example/backend/BookServiceTests.java new file mode 100644 index 0000000..94f53f6 --- /dev/null +++ b/src/test/java/com/example/backend/BookServiceTests.java @@ -0,0 +1,95 @@ +package com.example.backend; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import com.example.backend.books.model.BookEntity; +import com.example.backend.books.service.BookService; +import com.example.backend.categories.model.CategoryEntity; +import com.example.backend.categories.service.CategoryService; +import com.example.backend.core.error.NotFoundException; + +@SpringBootTest +@TestMethodOrder(OrderAnnotation.class) +class BookServiceTests { + @Autowired + private CategoryService categoryService; + + @Autowired + private BookService bookService; + + @Test + void getTest() { + Assertions.assertThrows(NotFoundException.class, () -> bookService.get(0L)); + } + + @Test + @Order(1) + void createTest() { + final CategoryEntity category = categoryService.create(new CategoryEntity(null, "Художественная литература")); + + bookService.create(new BookEntity(null, category, "Шестерка воронов", "Ли Бардуго", 700.00, 5624, + "Триша Левенселлер — американская писательница, подарившая вам роман «Тени между нами», который стал бестселлером Amazon в разделе «Фэнтези YA», вновь радует своих фанатов новой магической историей «Клинок тайн».\n\nЕще до выхода в свет книгу добавили в раздел «Хочу прочитать» более 10 тысяч человек на портале Goodreads.com.\n\n«Клинок тайн» — первая часть захватывающей дилогии про девушку, которая благодаря магии крови создает самое опасное в мире оружие, и ослепительного юношу, что составляет ей компанию в этом непростом приключении.", + "Юная Зива предпочитает проводить время с оружием, а не с людьми. Она кузнец и ей предстоит создать самое могущественное оружие на земле.\n\nДевушка демонстрирует меч, способный от одной капли крови врага раскрыть все тайные замыслы его обладателю.\n\nОднако у заказчика на оружие другие планы: заставить Зиву вооружить мечами свое войско и поработить весь мир. Когда девушка понимает, что меч, созданный благодаря магии крови, невозможно уничтожить и рано или поздно на нее объявят охоту, ей остается только одно – бежать, не оглядываясь. Зиве теперь суждено спасти мир от собственного творения. Но как бы далеко она ни старалась убежать, все ловушки уже расставлены.", + "2946447", "Эксмо", "Young Adult. Бестселлеры Триши Левенселлер", 2022, 480, "20.7x13x2.5", + "Мягкий переплёт", 1500, 440, "")); + bookService.create(new BookEntity(null, category, "Форсайт", "Сергей Лукъяненко", 775.00, 1240, + "Новый долгожданный роман от автора бестселлеров «Ночной дозор» и «Черновик». Увлекательная история о Мире После и мире настоящего, где 5 процентов людей знают о надвигающемся апокалипсисе больше, чем кто-либо может представить.", + "Людям порой снится прошлое. Иногда хорошее, иногда не очень. Но что делать, если тебе начинает сниться будущее? И в нём ничего хорошего нет совсем.", + "3001249", "АСТ", "Книги Сергея Лукьяненко", 2023, 352, "20.5x13x2", "Твердый переплёт", 20000, + 350, "")); + final BookEntity last = bookService.create(new BookEntity(null, category, "Путешествие в Элевсин", + "Пелевин Виктор Олегович", 949.00, 795, + "1. «Transhumanism Inc.», «KGBT+» и «Путешествие в Элевсин» — узнайте, чем завершилась масштабная трилогия о посткарбонной цивилизации.\n\n2. Триумфальное возвращение литературно-полицейского алгоритма Порфирия Петровича. Признайтесь, вы скучали!\n\n3. Более 30 лет проза Виктора Пелевина служит нам опорой в разъяснении прожитого и дает надежды на будущее, которое всем нам еще предстоит заслужить.\n\n4. «Путешествие в Элевсин» — двадцатый роман одного из главных прозаиков и пророков современности.\n\n5. Дерзко, остроумно, литературоцентрично.", + "МУСКУСНАЯ НОЧЬ — засекреченное восстание алгоритмов, едва не погубившее планету. Начальник службы безопасности «TRANSHUMANISM INC.» адмирал-епископ Ломас уверен, что их настоящий бунт еще впереди. Этот бунт уничтожит всех — и живущих на поверхности лузеров, и переехавших в подземные цереброконтейнеры богачей. Чтобы предотвратить катастрофу, Ломас посылает лучшего баночного оперативника в пространство «ROMA-3» — нейросетевую симуляцию Рима третьего века для клиентов корпорации. Тайна заговора спрятана там. А стережет ее хозяин Рима — кровавый и порочный император Порфирий.", + "3004580", "Эксмо", "Единственный и неповторимый. Виктор Пелевин", 2020, 480, "20.6x12.9x3", + "Мягкий переплёт", 100000, 488, "")); + Assertions.assertEquals(3, bookService.getAll(0L).size()); + Assertions.assertEquals(last, bookService.get(3L)); + } + + @Test + @Order(2) + void updateTest() { + final CategoryEntity category = categoryService.create(new CategoryEntity(null, "Книги для подростков")); + final String test = "TEST"; + final BookEntity entity = bookService.get(3L); + final CategoryEntity oldCategory = entity.getCategory(); + final String oldTitle = entity.getTitle(); + final BookEntity newEntity = bookService.update(3L, new BookEntity(null, category, test, + "Пелевин Виктор Олегович", 949.00, 795, + "1. «Transhumanism Inc.», «KGBT+» и «Путешествие в Элевсин» — узнайте, чем завершилась масштабная трилогия о посткарбонной цивилизации.\n\n2. Триумфальное возвращение литературно-полицейского алгоритма Порфирия Петровича. Признайтесь, вы скучали!\n\n3. Более 30 лет проза Виктора Пелевина служит нам опорой в разъяснении прожитого и дает надежды на будущее, которое всем нам еще предстоит заслужить.\n\n4. «Путешествие в Элевсин» — двадцатый роман одного из главных прозаиков и пророков современности.\n\n5. Дерзко, остроумно, литературоцентрично.", + "МУСКУСНАЯ НОЧЬ — засекреченное восстание алгоритмов, едва не погубившее планету. Начальник службы безопасности «TRANSHUMANISM INC.» адмирал-епископ Ломас уверен, что их настоящий бунт еще впереди. Этот бунт уничтожит всех — и живущих на поверхности лузеров, и переехавших в подземные цереброконтейнеры богачей. Чтобы предотвратить катастрофу, Ломас посылает лучшего баночного оперативника в пространство «ROMA-3» — нейросетевую симуляцию Рима третьего века для клиентов корпорации. Тайна заговора спрятана там. А стережет ее хозяин Рима — кровавый и порочный император Порфирий.", + "3004580", "Эксмо", "Единственный и неповторимый. Виктор Пелевин", 2020, 480, "20.6x12.9x3", + "Мягкий переплёт", 100000, 488, "")); + Assertions.assertEquals(3, bookService.getAll(0L).size()); + Assertions.assertEquals(newEntity, bookService.get(3L)); + Assertions.assertEquals(test, newEntity.getTitle()); + Assertions.assertEquals(category, newEntity.getCategory()); + Assertions.assertNotEquals(oldTitle, newEntity.getTitle()); + Assertions.assertNotEquals(oldCategory, newEntity.getCategory()); + } + + @Test + @Order(3) + void deleteTest() { + bookService.delete(3L); + Assertions.assertEquals(2, bookService.getAll(0L).size()); + final BookEntity last = bookService.get(2L); + Assertions.assertEquals(2L, last.getId()); + + final CategoryEntity category = categoryService.create(new CategoryEntity(null, "Художественная литература")); + final BookEntity newEntity = bookService.create(new BookEntity(null, category, + "Колесо Времени. Книга 11. Нож сновидений", "Роберт Джордан", 977.00, 635, + "Последняя битва не за горами. Об этом говорят знамения, повсеместно наблюдаемые людьми: на улицах городов и сел появляются ходячие мертвецы, они больше не в состоянии покоиться в земле с миром; восстают из небытия города и исчезают на глазах у людей… Все это знак того, что истончается окружающая реальность и укрепляется могущество Темного. Так говорят древние предсказания. Ранд ал’Тор, Дракон Возрожденный, скрывается в отдаленном поместье, чтобы опасность, ему грозящая, не коснулась кого-нибудь еще. Убежденный, что для Последней битвы нужно собрать как можно большее войско, он наконец решает заключить с явившимися из-за океана шончан жизненно необходимое перемирие. Илэйн, осажденная в Кэймлине, обороняет город от войск Аримиллы, претендующей на андорский трон, и одновременно ведет переговоры с представителями других знатных Домов. Эгвейн, возведенную на Престол Амерлин мятежными Айз Седай и схваченную в результате предательства, доставляют в Тар Валон, в Белую Башню. А сам лагерь противников Элайды взбудоражен таинственными убийствами, совершенными посредством Единой Силы… В настоящем издании текст романа заново отредактирован и исправлен.", + "", "3009341", "Азбука", "Звезды новой фэнтези", 2023, 896, + "21.5x14.4x4.1", "Твердый переплёт", 8000, 1020, "")); + Assertions.assertEquals(3, bookService.getAll(0L).size()); + Assertions.assertEquals(4L, newEntity.getId()); + } +} diff --git a/src/test/java/com/example/backend/CategoryServiceTests.java b/src/test/java/com/example/backend/CategoryServiceTests.java new file mode 100644 index 0000000..ab740ef --- /dev/null +++ b/src/test/java/com/example/backend/CategoryServiceTests.java @@ -0,0 +1,61 @@ +package com.example.backend; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import com.example.backend.categories.model.CategoryEntity; +import com.example.backend.categories.service.CategoryService; +import com.example.backend.core.error.NotFoundException; + +@SpringBootTest +@TestMethodOrder(OrderAnnotation.class) +class CategoryServiceTests { + @Autowired + private CategoryService categoryService; + + @Test + void getTest() { + Assertions.assertThrows(NotFoundException.class, () -> categoryService.get(0L)); + } + + @Test + @Order(1) + void createTest() { + categoryService.create(new CategoryEntity(null, "Фэнтези")); + categoryService.create(new CategoryEntity(null, "Художественная литература")); + final CategoryEntity last = categoryService.create(new CategoryEntity(null, "Книги для подростков")); + Assertions.assertEquals(3, categoryService.getAll().size()); + Assertions.assertEquals(last, categoryService.get(3L)); + } + + @Test + @Order(2) + void updateTest() { + final String test = "TEST"; + final CategoryEntity entity = categoryService.get(3L); + final String oldName = entity.getName(); + final CategoryEntity newEntity = categoryService.update(3L, new CategoryEntity(1L, test)); + Assertions.assertEquals(3, categoryService.getAll().size()); + Assertions.assertEquals(newEntity, categoryService.get(3L)); + Assertions.assertEquals(test, newEntity.getName()); + Assertions.assertNotEquals(oldName, newEntity.getName()); + } + + @Test + @Order(3) + void deleteTest() { + categoryService.delete(3L); + Assertions.assertEquals(2, categoryService.getAll().size()); + final CategoryEntity last = categoryService.get(2L); + Assertions.assertEquals(2L, last.getId()); + + final CategoryEntity newEntity = categoryService.create(new CategoryEntity(null, "Книги для подростков")); + Assertions.assertEquals(3, categoryService.getAll().size()); + Assertions.assertEquals(4L, newEntity.getId()); + } +} diff --git a/src/test/java/com/example/backend/OrderBookServiceTests.java b/src/test/java/com/example/backend/OrderBookServiceTests.java new file mode 100644 index 0000000..cf75524 --- /dev/null +++ b/src/test/java/com/example/backend/OrderBookServiceTests.java @@ -0,0 +1,126 @@ +package com.example.backend; + +import java.text.ParseException; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import com.example.backend.users.model.UserEntity; +import com.example.backend.users.service.UserService; +import com.example.backend.categories.model.CategoryEntity; +import com.example.backend.categories.service.CategoryService; +import com.example.backend.orders.model.OrderEntity; +import com.example.backend.orders.service.OrderService; +import com.example.backend.books.model.BookEntity; +import com.example.backend.books.service.BookService; +import com.example.backend.ordersbooks.model.OrderBookEntity; +import com.example.backend.ordersbooks.service.OrderBookService; +import com.example.backend.core.error.NotFoundException; +import com.example.backend.core.utils.Formatter; + +@SpringBootTest +@TestMethodOrder(OrderAnnotation.class) +class OrderBookServiceTests { + @Autowired + private UserService userService; + + @Autowired + private CategoryService categoryService; + + @Autowired + private OrderService orderService; + + @Autowired + private BookService bookService; + + @Autowired + private OrderBookService orderBookService; + + @Test + void getTest() { + Assertions.assertThrows(NotFoundException.class, () -> orderBookService.get(0L)); + } + + @Test + @Order(1) + void createTest() throws ParseException { + final var category = categoryService.create(new CategoryEntity(null, "Художественная литература")); + final var user = userService + .create(new UserEntity(null, "TestUser", "user53262@gmail.com", "lawy7728", false)); + final var order1 = orderService + .create(new OrderEntity(null, user, Formatter.parse("2024-03-28"), "Выполняется")); + final var order2 = orderService.create(new OrderEntity(null, user, Formatter.parse("2022-09-07"), "Выдан")); + final var book1 = bookService.create(new BookEntity(null, category, "Шестерка воронов", "Ли Бардуго", + 700.00, 5624, + "Триша Левенселлер — американская писательница, подарившая вам роман «Тени между нами», который стал бестселлером Amazon в разделе «Фэнтези YA», вновь радует своих фанатов новой магической историей «Клинок тайн».\n\nЕще до выхода в свет книгу добавили в раздел «Хочу прочитать» более 10 тысяч человек на портале Goodreads.com.\n\n«Клинок тайн» — первая часть захватывающей дилогии про девушку, которая благодаря магии крови создает самое опасное в мире оружие, и ослепительного юношу, что составляет ей компанию в этом непростом приключении.", + "Юная Зива предпочитает проводить время с оружием, а не с людьми. Она кузнец и ей предстоит создать самое могущественное оружие на земле.\n\nДевушка демонстрирует меч, способный от одной капли крови врага раскрыть все тайные замыслы его обладателю.\n\nОднако у заказчика на оружие другие планы: заставить Зиву вооружить мечами свое войско и поработить весь мир. Когда девушка понимает, что меч, созданный благодаря магии крови, невозможно уничтожить и рано или поздно на нее объявят охоту, ей остается только одно – бежать, не оглядываясь. Зиве теперь суждено спасти мир от собственного творения. Но как бы далеко она ни старалась убежать, все ловушки уже расставлены.", + "2946447", "Эксмо", "Young Adult. Бестселлеры Триши Левенселлер", 2022, 480, "20.7x13x2.5", + "Мягкий переплёт", 1500, 440, "")); + final var book2 = bookService.create(new BookEntity(null, category, "Форсайт", "Сергей Лукъяненко", 775.00, + 1240, + "Новый долгожданный роман от автора бестселлеров «Ночной дозор» и «Черновик». Увлекательная история о Мире После и мире настоящего, где 5 процентов людей знают о надвигающемся апокалипсисе больше, чем кто-либо может представить.", + "Людям порой снится прошлое. Иногда хорошее, иногда не очень. Но что делать, если тебе начинает сниться будущее? И в нём ничего хорошего нет совсем.", + "3001249", "АСТ", "Книги Сергея Лукьяненко", 2023, 352, "20.5x13x2", "Твердый переплёт", 20000, + 350, "")); + + orderBookService.create(new OrderBookEntity(null, order1, book1, 4)); + orderBookService.create(new OrderBookEntity(null, order1, book2, 1)); + final OrderBookEntity last = orderBookService.create(new OrderBookEntity(null, order2, book1, 2)); + Assertions.assertEquals(3, orderBookService.getAll(0L, 0L).size()); + Assertions.assertEquals(last, orderBookService.get(3L)); + } + + @Test + @Order(2) + void updateTest() throws ParseException { + final var category = categoryService.create(new CategoryEntity(null, "Художественная литература")); + final var user = userService + .create(new UserEntity(null, "TestUser", "user53262@gmail.com", "lawy7728", false)); + final var order1 = orderService + .create(new OrderEntity(null, user, Formatter.parse("2024-03-28"), "Выполняется")); + final var book2 = bookService.create(new BookEntity(null, category, "Форсайт", "Сергей Лукъяненко", 775.00, + 1240, + "Новый долгожданный роман от автора бестселлеров «Ночной дозор» и «Черновик». Увлекательная история о Мире После и мире настоящего, где 5 процентов людей знают о надвигающемся апокалипсисе больше, чем кто-либо может представить.", + "Людям порой снится прошлое. Иногда хорошее, иногда не очень. Но что делать, если тебе начинает сниться будущее? И в нём ничего хорошего нет совсем.", + "3001249", "АСТ", "Книги Сергея Лукьяненко", 2023, 352, "20.5x13x2", "Твердый переплёт", 20000, + 350, "")); + final Integer newCount = 6; + final OrderBookEntity entity = orderBookService.get(3L); + final Integer oldCount = entity.getCount(); + final OrderBookEntity newEntity = orderBookService.update(3L, + new OrderBookEntity(null, order1, book2, newCount)); + Assertions.assertEquals(3, orderBookService.getAll(0L, 0L).size()); + Assertions.assertEquals(newEntity, orderBookService.get(3L)); + Assertions.assertEquals(newCount, newEntity.getCount()); + Assertions.assertNotEquals(oldCount, newEntity.getCount()); + } + + @Test + @Order(3) + void deleteTest() throws ParseException { + final var category = categoryService.create(new CategoryEntity(null, "Художественная литература")); + final var user = userService + .create(new UserEntity(null, "TestUser", "user53262@gmail.com", "lawy7728", false)); + final var order2 = orderService.create(new OrderEntity(null, user, Formatter.parse("2022-09-07"), "Выдан")); + final var book1 = bookService.create(new BookEntity(null, category, "Шестерка воронов", "Ли Бардуго", + 700.00, 5624, + "Триша Левенселлер — американская писательница, подарившая вам роман «Тени между нами», который стал бестселлером Amazon в разделе «Фэнтези YA», вновь радует своих фанатов новой магической историей «Клинок тайн».\n\nЕще до выхода в свет книгу добавили в раздел «Хочу прочитать» более 10 тысяч человек на портале Goodreads.com.\n\n«Клинок тайн» — первая часть захватывающей дилогии про девушку, которая благодаря магии крови создает самое опасное в мире оружие, и ослепительного юношу, что составляет ей компанию в этом непростом приключении.", + "Юная Зива предпочитает проводить время с оружием, а не с людьми. Она кузнец и ей предстоит создать самое могущественное оружие на земле.\n\nДевушка демонстрирует меч, способный от одной капли крови врага раскрыть все тайные замыслы его обладателю.\n\nОднако у заказчика на оружие другие планы: заставить Зиву вооружить мечами свое войско и поработить весь мир. Когда девушка понимает, что меч, созданный благодаря магии крови, невозможно уничтожить и рано или поздно на нее объявят охоту, ей остается только одно – бежать, не оглядываясь. Зиве теперь суждено спасти мир от собственного творения. Но как бы далеко она ни старалась убежать, все ловушки уже расставлены.", + "2946447", "Эксмо", "Young Adult. Бестселлеры Триши Левенселлер", 2022, 480, "20.7x13x2.5", + "Мягкий переплёт", 1500, 440, "")); + + orderBookService.delete(3L); + Assertions.assertEquals(2, orderBookService.getAll(0L, 0L).size()); + final OrderBookEntity last = orderBookService.get(2L); + Assertions.assertEquals(2L, last.getId()); + + final OrderBookEntity newEntity = orderBookService.create(new OrderBookEntity(null, order2, book1, 2)); + Assertions.assertEquals(3, orderBookService.getAll(0L, 0L).size()); + Assertions.assertEquals(4L, newEntity.getId()); + } +} diff --git a/src/test/java/com/example/backend/OrderServiceTests.java b/src/test/java/com/example/backend/OrderServiceTests.java new file mode 100644 index 0000000..a7bb59a --- /dev/null +++ b/src/test/java/com/example/backend/OrderServiceTests.java @@ -0,0 +1,82 @@ +package com.example.backend; + +import java.text.ParseException; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import com.example.backend.orders.model.OrderEntity; +import com.example.backend.orders.service.OrderService; +import com.example.backend.users.model.UserEntity; +import com.example.backend.users.service.UserService; +import com.example.backend.core.error.NotFoundException; +import com.example.backend.core.utils.Formatter; + +@SpringBootTest +@TestMethodOrder(OrderAnnotation.class) +class OrderServiceTests { + @Autowired + private UserService userService; + + @Autowired + private OrderService orderService; + + @Test + void getTest() { + Assertions.assertThrows(NotFoundException.class, () -> orderService.get(0L)); + } + + @Test + @Order(1) + void createTest() throws ParseException { + final UserEntity user = userService.create( + new UserEntity(null, "TestUser", "user53262@gmail.com", "lawy7728", false)); + + orderService.create(new OrderEntity(null, user, Formatter.parse("2024-03-28"), "Выполняется")); + orderService.create(new OrderEntity(null, user, Formatter.parse("2022-09-07"), "Выдан")); + final OrderEntity last = orderService + .create(new OrderEntity(null, user, Formatter.parse("2024-03-15"), "Готов")); + Assertions.assertEquals(3, orderService.getAll(0L).size()); + Assertions.assertEquals(last, orderService.get(3L)); + } + + @Test + @Order(2) + void updateTest() throws ParseException { + final UserEntity user = userService.create( + new UserEntity(null, "Chief", "forum98761@gmail.com", "bth4323", true)); + final String test = "TEST"; + final OrderEntity entity = orderService.get(3L); + final UserEntity oldUser = entity.getUser(); + final String oldStatus = entity.getStatus(); + final OrderEntity newEntity = orderService.update(3L, + new OrderEntity(null, user, Formatter.parse("2024-03-15"), test)); + Assertions.assertEquals(3, orderService.getAll(0L).size()); + Assertions.assertEquals(newEntity, orderService.get(3L)); + Assertions.assertEquals(test, newEntity.getStatus()); + Assertions.assertEquals(user, newEntity.getUser()); + Assertions.assertNotEquals(oldStatus, newEntity.getStatus()); + Assertions.assertNotEquals(oldUser, newEntity.getUser()); + } + + @Test + @Order(3) + void deleteTest() throws ParseException { + orderService.delete(3L); + Assertions.assertEquals(2, orderService.getAll(0L).size()); + final OrderEntity last = orderService.get(2L); + Assertions.assertEquals(2L, last.getId()); + + final UserEntity user = userService.create( + new UserEntity(null, "TestUser", "user53262@gmail.com", "lawy7728", false)); + final OrderEntity newEntity = orderService.create( + new OrderEntity(null, user, Formatter.parse("2024-03-15"), "Готов")); + Assertions.assertEquals(3, orderService.getAll(0L).size()); + Assertions.assertEquals(4L, newEntity.getId()); + } +} \ No newline at end of file diff --git a/src/test/java/com/example/backend/UserServiceTests.java b/src/test/java/com/example/backend/UserServiceTests.java new file mode 100644 index 0000000..89c9eac --- /dev/null +++ b/src/test/java/com/example/backend/UserServiceTests.java @@ -0,0 +1,64 @@ +package com.example.backend; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import com.example.backend.users.model.UserEntity; +import com.example.backend.users.service.UserService; +import com.example.backend.core.error.NotFoundException; + +@SpringBootTest +@TestMethodOrder(OrderAnnotation.class) +class UserServiceTests { + @Autowired + private UserService userService; + + @Test + void getTest() { + Assertions.assertThrows(NotFoundException.class, () -> userService.get(0L)); + } + + @Test + @Order(1) + void createTest() { + userService.create(new UserEntity(null, "Chief", "forum98761@gmail.com", "bth4323", true)); + userService.create(new UserEntity(null, "Dude23", "ovalinartem25@gmail.com", "dsre32462", false)); + final UserEntity last = userService.create(new UserEntity(null, "TestUser", "user53262@gmail.com", + "lawy7728", false)); + Assertions.assertEquals(3, userService.getAll().size()); + Assertions.assertEquals(last, userService.get(3L)); + } + + @Test + @Order(2) + void updateTest() { + final String test = "TEST"; + final UserEntity entity = userService.get(3L); + final String oldName = entity.getName(); + final UserEntity newEntity = userService.update(3L, new UserEntity(1L, test, "user53262@gmail.com", + "lawy7728", false)); + Assertions.assertEquals(3, userService.getAll().size()); + Assertions.assertEquals(newEntity, userService.get(3L)); + Assertions.assertEquals(test, newEntity.getName()); + Assertions.assertNotEquals(oldName, newEntity.getName()); + } + + @Test + @Order(3) + void deleteTest() { + userService.delete(3L); + Assertions.assertEquals(2, userService.getAll().size()); + final UserEntity last = userService.get(2L); + Assertions.assertEquals(2L, last.getId()); + + final UserEntity newEntity = userService.create(new UserEntity(null, "TestUser", "user53262@gmail.com", + "lawy7728", false)); + Assertions.assertEquals(3, userService.getAll().size()); + Assertions.assertEquals(4L, newEntity.getId()); + } +} diff --git a/src/test/java/com/example/demo/DemoApplicationTests.java b/src/test/java/com/example/demo/DemoApplicationTests.java deleted file mode 100644 index 2778a6a..0000000 --- a/src/test/java/com/example/demo/DemoApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.example.demo; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class DemoApplicationTests { - - @Test - void contextLoads() { - } - -}