From e3e81340e52e078de78496c669f4676014282fd1 Mon Sep 17 00:00:00 2001
From: Leta Treiden <97164609+LetaTreiden@users.noreply.github.com>
Date: Fri, 3 Feb 2023 18:01:31 +0300
Subject: [PATCH 01/45] IT SHOULD WORKKKKKKK
---
pom.xml | 481 +++++++++---------
.../java/ru/practicum/shareit/ShareItApp.java | 1 +
.../shareit/booking/BookingController.java | 56 +-
.../shareit/booking/BookingMapper.java | 69 +++
.../shareit/booking/BookingRepository.java | 60 +++
.../ru/practicum/shareit/booking/State.java | 5 +
.../shareit/booking/dto/BookingDTO.java | 24 +
.../booking/dto/BookingDTOForItem.java | 12 +
.../booking/dto/BookingDTOToReturn.java | 24 +
.../shareit/booking/model/Booking.java | 55 ++
.../booking/service/BookingService.java | 18 +
.../booking/service/BookingServiceImpl.java | 179 +++++++
.../exception/BadRequestException.java | 7 +
.../shareit/exception/ConflictException.java | 7 +
.../shareit/exception/ErrorHandler.java | 69 +++
.../shareit/exception/ForbiddenException.java | 7 +
.../shareit/exception/NotFoundException.java | 11 +
.../exception/StatusBadRequestException.java | 11 +
.../shareit/item/CommentRepository.java | 11 +
.../shareit/item/ItemController.java | 59 ++-
.../shareit/item/ItemRepository.java | 18 +
.../practicum/shareit/item/dto/ItemDTO.java | 28 +
.../shareit/item/dto/ItemDTOWithComment.java | 23 +
.../shareit/item/dto/ItemDTOWithDate.java | 35 ++
.../shareit/item/mapper/CommentMapper.java | 41 ++
.../shareit/item/mapper/ItemMapper.java | 74 +++
.../practicum/shareit/item/model/Comment.java | 52 ++
.../ru/practicum/shareit/item/model/Item.java | 51 +-
.../shareit/item/service/ItemService.java | 22 +
.../shareit/item/service/ItemServiceImpl.java | 158 ++++++
.../item/storage/ItemInMemoryStorage.java | 85 ++++
.../shareit/item/storage/ItemStorage.java | 22 +
.../request/ItemRequestController.java | 3 -
.../shareit/request/dto/ItemRequestDto.java | 17 +-
.../shareit/request/model/ItemRequest.java | 29 ++
.../shareit/user/UserController.java | 47 +-
.../ru/practicum/shareit/user/UserMapper.java | 36 ++
.../shareit/user/UserRepository.java | 7 +
.../practicum/shareit/user/dto/UserDTO.java | 19 +
.../ru/practicum/shareit/user/model/User.java | 44 ++
.../shareit/user/service/UserService.java | 17 +
.../shareit/user/service/UserServiceImpl.java | 69 +++
.../user/storage/UserInMemoryStorage.java | 68 +++
.../shareit/user/storage/UserStorage.java | 19 +
src/main/resources/application.properties | 18 +-
src/main/resources/schema.sql | 55 ++
46 files changed, 1957 insertions(+), 266 deletions(-)
create mode 100644 src/main/java/ru/practicum/shareit/booking/BookingMapper.java
create mode 100644 src/main/java/ru/practicum/shareit/booking/BookingRepository.java
create mode 100644 src/main/java/ru/practicum/shareit/booking/State.java
create mode 100644 src/main/java/ru/practicum/shareit/booking/dto/BookingDTO.java
create mode 100644 src/main/java/ru/practicum/shareit/booking/dto/BookingDTOForItem.java
create mode 100644 src/main/java/ru/practicum/shareit/booking/dto/BookingDTOToReturn.java
create mode 100644 src/main/java/ru/practicum/shareit/booking/model/Booking.java
create mode 100644 src/main/java/ru/practicum/shareit/booking/service/BookingService.java
create mode 100644 src/main/java/ru/practicum/shareit/booking/service/BookingServiceImpl.java
create mode 100644 src/main/java/ru/practicum/shareit/exception/BadRequestException.java
create mode 100644 src/main/java/ru/practicum/shareit/exception/ConflictException.java
create mode 100644 src/main/java/ru/practicum/shareit/exception/ErrorHandler.java
create mode 100644 src/main/java/ru/practicum/shareit/exception/ForbiddenException.java
create mode 100644 src/main/java/ru/practicum/shareit/exception/NotFoundException.java
create mode 100644 src/main/java/ru/practicum/shareit/exception/StatusBadRequestException.java
create mode 100644 src/main/java/ru/practicum/shareit/item/CommentRepository.java
create mode 100644 src/main/java/ru/practicum/shareit/item/ItemRepository.java
create mode 100644 src/main/java/ru/practicum/shareit/item/dto/ItemDTO.java
create mode 100644 src/main/java/ru/practicum/shareit/item/dto/ItemDTOWithComment.java
create mode 100644 src/main/java/ru/practicum/shareit/item/dto/ItemDTOWithDate.java
create mode 100644 src/main/java/ru/practicum/shareit/item/mapper/CommentMapper.java
create mode 100644 src/main/java/ru/practicum/shareit/item/mapper/ItemMapper.java
create mode 100644 src/main/java/ru/practicum/shareit/item/model/Comment.java
create mode 100644 src/main/java/ru/practicum/shareit/item/service/ItemService.java
create mode 100644 src/main/java/ru/practicum/shareit/item/service/ItemServiceImpl.java
create mode 100644 src/main/java/ru/practicum/shareit/item/storage/ItemInMemoryStorage.java
create mode 100644 src/main/java/ru/practicum/shareit/item/storage/ItemStorage.java
create mode 100644 src/main/java/ru/practicum/shareit/request/model/ItemRequest.java
create mode 100644 src/main/java/ru/practicum/shareit/user/UserMapper.java
create mode 100644 src/main/java/ru/practicum/shareit/user/UserRepository.java
create mode 100644 src/main/java/ru/practicum/shareit/user/dto/UserDTO.java
create mode 100644 src/main/java/ru/practicum/shareit/user/model/User.java
create mode 100644 src/main/java/ru/practicum/shareit/user/service/UserService.java
create mode 100644 src/main/java/ru/practicum/shareit/user/service/UserServiceImpl.java
create mode 100644 src/main/java/ru/practicum/shareit/user/storage/UserInMemoryStorage.java
create mode 100644 src/main/java/ru/practicum/shareit/user/storage/UserStorage.java
create mode 100644 src/main/resources/schema.sql
diff --git a/pom.xml b/pom.xml
index 870ae8526..0efdef4b2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,241 +1,260 @@
- 4.0.0
-
- org.springframework.boot
- spring-boot-starter-parent
- 2.7.2
-
-
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.7.2
+
+
- ru.practicum
- shareit
- 0.0.1-SNAPSHOT
+ ru.practicum
+ shareit
+ 0.0.1-SNAPSHOT
- ShareIt
+ ShareIt
-
- 11
-
+
+ 11
+
-
-
- org.springframework.boot
- spring-boot-starter-web
-
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
-
- org.postgresql
- postgresql
- runtime
-
-
- com.h2database
- h2
- runtime
-
-
- org.springframework.boot
- spring-boot-configuration-processor
- true
-
-
- org.projectlombok
- lombok
- true
-
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
-
- org.springframework.boot
- spring-boot-starter-validation
-
-
+
+ org.postgresql
+ postgresql
+ runtime
+
+
+ org.hibernate.validator
+ hibernate-validator
+ 6.0.10.Final
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+ com.h2database
+ h2
+ runtime
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+ org.springframework.boot
+ spring-boot-starter
+
-
-
-
- src/main/resources
- true
-
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
-
- org.projectlombok
- lombok
-
-
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-surefire-plugin
-
-
- test
-
-
-
-
- org.apache.maven.plugins
- maven-checkstyle-plugin
- 3.1.2
-
- checkstyle.xml
- true
- true
- true
-
-
-
-
- check
-
- compile
-
-
-
-
- com.puppycrawl.tools
- checkstyle
- 10.3
-
-
-
-
- com.github.spotbugs
- spotbugs-maven-plugin
- 4.7.0.0
-
- Max
- High
-
-
-
-
- check
-
-
-
-
-
- org.jacoco
- jacoco-maven-plugin
- 0.8.8
-
-
-
-
-
- jacoco-initialize
-
- prepare-agent
-
-
-
- jacoco-check
-
- check
-
-
-
-
- BUNDLE
-
-
- INSTRUCTION
- COVEREDRATIO
- 0.01
-
-
- LINE
- COVEREDRATIO
- 0.9
-
-
- BRANCH
- COVEREDRATIO
- 0.6
-
-
- COMPLEXITY
- COVEREDRATIO
- 0.6
-
-
- METHOD
- COVEREDRATIO
- 0.7
-
-
- CLASS
- MISSEDCOUNT
- 1
-
-
-
-
-
-
-
- jacoco-report
- test
-
- report
-
-
-
-
-
-
-
-
-
- check
-
-
-
- org.apache.maven.plugins
- maven-checkstyle-plugin
-
-
- com.github.spotbugs
- spotbugs-maven-plugin
-
-
-
-
-
-
- com.github.spotbugs
- spotbugs-maven-plugin
-
-
-
-
-
- coverage
-
-
-
- org.jacoco
- jacoco-maven-plugin
-
-
-
-
-
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+
+
+
+
+ src/main/resources
+ true
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ test
+
+
+
+
+ org.apache.maven.plugins
+ maven-checkstyle-plugin
+ 3.1.2
+
+ checkstyle.xml
+ true
+ true
+ true
+
+
+
+
+ check
+
+ compile
+
+
+
+
+ com.puppycrawl.tools
+ checkstyle
+ 10.3
+
+
+
+
+ com.github.spotbugs
+ spotbugs-maven-plugin
+ 4.7.0.0
+
+ Max
+ High
+
+
+
+
+ check
+
+
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+ 0.8.8
+
+
+
+
+
+ jacoco-initialize
+
+ prepare-agent
+
+
+
+ jacoco-check
+
+ check
+
+
+
+
+ BUNDLE
+
+
+ INSTRUCTION
+ COVEREDRATIO
+ 0.01
+
+
+ LINE
+ COVEREDRATIO
+ 0.9
+
+
+ BRANCH
+ COVEREDRATIO
+ 0.6
+
+
+ COMPLEXITY
+ COVEREDRATIO
+ 0.6
+
+
+ METHOD
+ COVEREDRATIO
+ 0.7
+
+
+ CLASS
+ MISSEDCOUNT
+ 1
+
+
+
+
+
+
+
+ jacoco-report
+ test
+
+ report
+
+
+
+
+
+
+
+
+
+ check
+
+
+
+ org.apache.maven.plugins
+ maven-checkstyle-plugin
+
+
+ com.github.spotbugs
+ spotbugs-maven-plugin
+
+
+
+
+
+
+ com.github.spotbugs
+ spotbugs-maven-plugin
+
+
+
+
+
+ coverage
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+
+
+
+
+
diff --git a/src/main/java/ru/practicum/shareit/ShareItApp.java b/src/main/java/ru/practicum/shareit/ShareItApp.java
index a00ad567d..b69dbb5a6 100644
--- a/src/main/java/ru/practicum/shareit/ShareItApp.java
+++ b/src/main/java/ru/practicum/shareit/ShareItApp.java
@@ -7,6 +7,7 @@
public class ShareItApp {
public static void main(String[] args) {
+
SpringApplication.run(ShareItApp.class, args);
}
diff --git a/src/main/java/ru/practicum/shareit/booking/BookingController.java b/src/main/java/ru/practicum/shareit/booking/BookingController.java
index b94493d49..a75d450b7 100644
--- a/src/main/java/ru/practicum/shareit/booking/BookingController.java
+++ b/src/main/java/ru/practicum/shareit/booking/BookingController.java
@@ -1,12 +1,58 @@
package ru.practicum.shareit.booking;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import ru.practicum.shareit.booking.dto.BookingDTO;
+import ru.practicum.shareit.booking.dto.BookingDTOToReturn;
+import ru.practicum.shareit.booking.service.BookingService;
+
+import java.util.Collection;
-/**
- * TODO Sprint add-bookings.
- */
@RestController
@RequestMapping(path = "/bookings")
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
+@Slf4j
public class BookingController {
+ private final BookingService bookingService;
+
+ @PostMapping
+ public BookingDTOToReturn addBooking(@RequestHeader("X-Sharer-User-Id") Long userId,
+ @RequestBody BookingDTO bookingDto) {
+ log.info("Добавление запроса на аренду пользователем с id {}", userId);
+ return bookingService.addBooking(userId, bookingDto);
+ }
+
+ @PatchMapping("/{bookingId}")
+ public BookingDTOToReturn updateStatusBooking(@RequestHeader("X-Sharer-User-Id") Long userId,
+ @PathVariable Long bookingId,
+ @RequestParam Boolean approved) {
+ log.info("Обновление статуса запроса на аренду с id {}", bookingId);
+ return bookingService.updateStatusBooking(userId, bookingId, approved);
+
+ }
+
+ @GetMapping("/{bookingId}")
+ public BookingDTOToReturn getBooking(@RequestHeader("X-Sharer-User-Id") Long userId, @PathVariable Long bookingId) {
+ log.info("Просмотр запроса на пренду с id {}", bookingId);
+ return bookingService.getBooking(userId, bookingId);
+ }
+
+ @GetMapping
+ public Collection findBookingByBooker(@RequestHeader("X-Sharer-User-Id") Long userId,
+ @RequestParam(required = false)
+ String state) {
+ log.info("Получение списка бронирований пользовалеля с id {}", userId);
+ return bookingService.getBookingByBooker(userId, state);
+ }
+
+ @GetMapping("/owner")
+ public Collection findBookingByOwner(@RequestHeader("X-Sharer-User-Id") Long userId,
+ @RequestParam(required = false)
+ String state) {
+ log.info("Получение списка бронирований для всех вещей пользователя с id {}", userId);
+ return bookingService.getBookingByOwner(userId, state);
+ }
+
}
diff --git a/src/main/java/ru/practicum/shareit/booking/BookingMapper.java b/src/main/java/ru/practicum/shareit/booking/BookingMapper.java
new file mode 100644
index 000000000..35cbe56e9
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/booking/BookingMapper.java
@@ -0,0 +1,69 @@
+package ru.practicum.shareit.booking;
+
+import org.springframework.stereotype.Component;
+import ru.practicum.shareit.booking.dto.BookingDTO;
+import ru.practicum.shareit.booking.dto.BookingDTOForItem;
+import ru.practicum.shareit.booking.dto.BookingDTOToReturn;
+import ru.practicum.shareit.booking.model.Booking;
+import ru.practicum.shareit.item.model.Item;
+import ru.practicum.shareit.user.model.User;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+
+@Component
+public class BookingMapper {
+
+ public static BookingDTO toBookingDto(Booking booking) {
+ BookingDTO bookingDto = new BookingDTO();
+ bookingDto.setId(booking.getId());
+ bookingDto.setStart(booking.getStart());
+ bookingDto.setEnd(booking.getEnd());
+ bookingDto.setStatus(booking.getStatus());
+ bookingDto.setItemId(booking.getItem() != null ? booking.getItem().getId() : null);
+ bookingDto.setItemName(booking.getItem() != null ? booking.getItem().getName() : null);
+ bookingDto.setBookerId(booking.getBooker() != null ? booking.getBooker().getId() : null);
+ return bookingDto;
+ }
+
+
+ public static BookingDTOToReturn toBookingDtoFrom(Booking booking) {
+ BookingDTOToReturn bookingDto = new BookingDTOToReturn();
+ bookingDto.setId(booking.getId());
+ bookingDto.setStart(booking.getStart());
+ bookingDto.setEnd(booking.getEnd());
+ bookingDto.setStatus(booking.getStatus());
+ bookingDto.setItem(booking.getItem());
+ bookingDto.setBooker(booking.getBooker());
+ return bookingDto;
+ }
+
+ public static Booking toBooking(BookingDTO bookingDto, Item item, User user) {
+ Booking booking = new Booking();
+ booking.setStart(bookingDto.getStart());
+ booking.setEnd(bookingDto.getEnd());
+ booking.setId(bookingDto.getId());
+ booking.setStatus(bookingDto.getStatus());
+ booking.setItem(item);
+ booking.setBooker(user);
+ return booking;
+ }
+
+ public static BookingDTOForItem toBookingDtoForItem(Booking booking, LocalDateTime dateTime) {
+ BookingDTOForItem bookingDtoForItem = new BookingDTOForItem();
+ bookingDtoForItem.setId(booking.getId());
+ bookingDtoForItem.setBookerId(booking.getBooker().getId());
+ bookingDtoForItem.setDateTime(dateTime);
+ return bookingDtoForItem;
+ }
+
+
+ public static List mapToBookingDtoFrom(Iterable bookings) {
+ List dtos = new ArrayList<>();
+ for (Booking booking : bookings) {
+ dtos.add(toBookingDtoFrom(booking));
+ }
+ return dtos;
+ }
+}
diff --git a/src/main/java/ru/practicum/shareit/booking/BookingRepository.java b/src/main/java/ru/practicum/shareit/booking/BookingRepository.java
new file mode 100644
index 000000000..50c17dfe2
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/booking/BookingRepository.java
@@ -0,0 +1,60 @@
+package ru.practicum.shareit.booking;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import ru.practicum.shareit.booking.model.Booking;
+import ru.practicum.shareit.item.model.Item;
+import ru.practicum.shareit.user.model.User;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+public interface BookingRepository extends JpaRepository {
+
+ List findByItemOrderByStartDesc(Item item);
+
+ List findByBookerAndStatusOrderByStartDesc(User booker, State status);
+
+ List findByBookerOrderByStartDesc(User booker);
+
+ List findByBookerAndStartAfterOrderByStartDesc(User booker, LocalDateTime now);
+
+ List findByBookerAndStartBeforeAndEndAfterOrderByStartDesc(User booker, LocalDateTime s, LocalDateTime e);
+
+ List findByBookerAndStartBeforeAndEndBeforeOrderByStartDesc(User booker, LocalDateTime s,
+ LocalDateTime e);
+
+ List findByItemAndBookerAndStartBeforeAndEndBefore(Item item, User booker, LocalDateTime s,
+ LocalDateTime e);
+
+ @Query(nativeQuery = true, value = "SELECT * FROM BOOKINGS as b " +
+ "LEFT JOIN ITEMS as i ON b.ITEM_ID = i.ID " +
+ "WHERE i.OWNER_ID = ?1 AND b.END_DATE < ?2 AND b.START_DATE < ?3 " +
+ "ORDER BY b.START_DATE DESC")
+ List findByBookingForOwnerWithPast(Long i, LocalDateTime e, LocalDateTime s);
+
+ @Query(nativeQuery = true, value = "SELECT * FROM BOOKINGS as b " +
+ "LEFT JOIN ITEMS as i ON b.ITEM_ID = i.ID " +
+ "WHERE i.OWNER_ID = ?1 AND b.START_DATE < ?2 AND b.END_DATE > ?3 " +
+ "ORDER BY b.START_DATE DESC")
+ List findByBookingForOwnerWithCurrent(Long i, LocalDateTime s, LocalDateTime e);
+
+ @Query(nativeQuery = true, value = "SELECT * FROM BOOKINGS as b " +
+ "LEFT JOIN ITEMS as i ON b.ITEM_ID = i.ID " +
+ "WHERE i.OWNER_ID = ?1 AND b.START_DATE > ?2 " +
+ "ORDER BY b.START_DATE DESC")
+ List findByBookingForOwnerWithFuture(Long i, LocalDateTime s);
+
+ @Query(nativeQuery = true, value = "SELECT * FROM BOOKINGS as b " +
+ "LEFT JOIN ITEMS as i ON b.ITEM_ID = i.ID " +
+ "WHERE i.OWNER_ID = ?1 " +
+ "ORDER BY b.START_DATE DESC")
+ List findByBookingForOwnerWithAll(Long i);
+
+ @Query(nativeQuery = true, value = "SELECT * FROM BOOKINGS as b " +
+ "LEFT JOIN ITEMS as i ON b.ITEM_ID = i.ID " +
+ "WHERE i.OWNER_ID = ?1 AND b.STATUS LIKE ?2 " +
+ "ORDER BY b.START_DATE DESC")
+ List findByBookingForOwnerWithWaitingOrRejected(Long i, String status);
+
+}
diff --git a/src/main/java/ru/practicum/shareit/booking/State.java b/src/main/java/ru/practicum/shareit/booking/State.java
new file mode 100644
index 000000000..429348b1c
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/booking/State.java
@@ -0,0 +1,5 @@
+package ru.practicum.shareit.booking;
+
+public enum State {
+ WAITING, APPROVED, REJECTED, CANCELED;
+}
diff --git a/src/main/java/ru/practicum/shareit/booking/dto/BookingDTO.java b/src/main/java/ru/practicum/shareit/booking/dto/BookingDTO.java
new file mode 100644
index 000000000..3ebb00d24
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/booking/dto/BookingDTO.java
@@ -0,0 +1,24 @@
+package ru.practicum.shareit.booking.dto;
+
+import lombok.Data;
+import ru.practicum.shareit.booking.State;
+
+import java.time.LocalDateTime;
+
+@Data
+public class BookingDTO {
+
+ private long id;
+
+ private LocalDateTime start;
+
+ private LocalDateTime end;
+
+ private Long itemId;
+
+ private String itemName;
+
+ private Long bookerId;
+
+ private State status;
+}
diff --git a/src/main/java/ru/practicum/shareit/booking/dto/BookingDTOForItem.java b/src/main/java/ru/practicum/shareit/booking/dto/BookingDTOForItem.java
new file mode 100644
index 000000000..44b3f9077
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/booking/dto/BookingDTOForItem.java
@@ -0,0 +1,12 @@
+package ru.practicum.shareit.booking.dto;
+
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+public class BookingDTOForItem {
+ private long id;
+ private Long bookerId;
+ private LocalDateTime dateTime;
+}
diff --git a/src/main/java/ru/practicum/shareit/booking/dto/BookingDTOToReturn.java b/src/main/java/ru/practicum/shareit/booking/dto/BookingDTOToReturn.java
new file mode 100644
index 000000000..fefbdd7fa
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/booking/dto/BookingDTOToReturn.java
@@ -0,0 +1,24 @@
+package ru.practicum.shareit.booking.dto;
+
+import lombok.Data;
+import ru.practicum.shareit.booking.State;
+import ru.practicum.shareit.item.model.Item;
+import ru.practicum.shareit.user.model.User;
+
+import java.time.LocalDateTime;
+
+@Data
+public class BookingDTOToReturn {
+
+ private long id;
+
+ private LocalDateTime start;
+
+ private LocalDateTime end;
+
+ private Item item;
+
+ private User booker;
+
+ private State status;
+}
\ No newline at end of file
diff --git a/src/main/java/ru/practicum/shareit/booking/model/Booking.java b/src/main/java/ru/practicum/shareit/booking/model/Booking.java
new file mode 100644
index 000000000..defb511b1
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/booking/model/Booking.java
@@ -0,0 +1,55 @@
+package ru.practicum.shareit.booking.model;
+
+import lombok.*;
+import org.hibernate.Hibernate;
+import ru.practicum.shareit.booking.State;
+import ru.practicum.shareit.item.model.Item;
+import ru.practicum.shareit.user.model.User;
+
+import javax.persistence.*;
+import java.time.LocalDateTime;
+import java.util.Objects;
+
+@Entity
+@Table(name = "bookings", schema = "public")
+@Getter
+@Setter
+@ToString
+@RequiredArgsConstructor
+public class Booking {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private long id;
+
+ @Column(name = "start_date")
+ private LocalDateTime start;
+
+ @Column(name = "end_date")
+ private LocalDateTime end;
+
+ @ManyToOne
+ @JoinColumn(name = "item_id")
+ private Item item;
+
+ @OneToOne
+ @JoinColumn(name = "booker_id")
+ private User booker;
+
+ @Enumerated(EnumType.STRING)
+ @Column(nullable = false)
+ private State status;
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false;
+ Booking booking = (Booking) o;
+ return id != 0 && Objects.equals(id, booking.id);
+ }
+
+ @Override
+ public int hashCode() {
+ return getClass().hashCode();
+ }
+}
diff --git a/src/main/java/ru/practicum/shareit/booking/service/BookingService.java b/src/main/java/ru/practicum/shareit/booking/service/BookingService.java
new file mode 100644
index 000000000..3716e6a1a
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/booking/service/BookingService.java
@@ -0,0 +1,18 @@
+package ru.practicum.shareit.booking.service;
+
+import ru.practicum.shareit.booking.dto.BookingDTO;
+import ru.practicum.shareit.booking.dto.BookingDTOToReturn;
+
+import java.util.Collection;
+
+public interface BookingService {
+ BookingDTOToReturn addBooking(Long userId, BookingDTO bookingDto);
+
+ BookingDTOToReturn updateStatusBooking(Long userId, Long bookingId, Boolean approved);
+
+ BookingDTOToReturn getBooking(Long bookingId, Long userId);
+
+ Collection getBookingByBooker(Long usersId, String state);
+
+ Collection getBookingByOwner(Long usersId, String status);
+}
diff --git a/src/main/java/ru/practicum/shareit/booking/service/BookingServiceImpl.java b/src/main/java/ru/practicum/shareit/booking/service/BookingServiceImpl.java
new file mode 100644
index 000000000..bfe4702db
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/booking/service/BookingServiceImpl.java
@@ -0,0 +1,179 @@
+package ru.practicum.shareit.booking.service;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import ru.practicum.shareit.booking.BookingMapper;
+import ru.practicum.shareit.booking.BookingRepository;
+import ru.practicum.shareit.booking.State;
+import ru.practicum.shareit.booking.dto.BookingDTO;
+import ru.practicum.shareit.booking.dto.BookingDTOToReturn;
+import ru.practicum.shareit.booking.model.Booking;
+import ru.practicum.shareit.exception.BadRequestException;
+import ru.practicum.shareit.exception.StatusBadRequestException;
+import ru.practicum.shareit.exception.NotFoundException;
+import ru.practicum.shareit.item.ItemRepository;
+import ru.practicum.shareit.item.model.Item;
+import ru.practicum.shareit.user.UserRepository;
+import ru.practicum.shareit.user.model.User;
+
+import java.time.LocalDateTime;
+import java.util.*;
+
+@Service
+
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
+public class BookingServiceImpl implements BookingService {
+
+ private final BookingRepository bRepository;
+ private final ItemRepository iRepository;
+ private final UserRepository uRepository;
+
+ @Transactional
+ @Override
+ public BookingDTOToReturn addBooking(Long userId, BookingDTO bookingDto) {
+ Optional- item = iRepository.findById(bookingDto.getItemId());
+ Optional user = uRepository.findById(userId);
+ if (user.isEmpty()) {
+ throw new NotFoundException("User not found");
+ }
+ if (item.isPresent() && !item.get().getAvailable()) {
+ throw new BadRequestException("You can not book this item");
+ }
+ if (item.isEmpty()) {
+ throw new NotFoundException("Cannot create booking");
+ }
+ if (Objects.equals(item.get().getOwner().getId(), userId)) {
+ throw new NotFoundException("You cannot book your item");
+ }
+ if (bookingDto.getEnd().isBefore(LocalDateTime.now()) ||
+ bookingDto.getStart().isBefore(LocalDateTime.now()) ||
+ (bookingDto.getEnd().isBefore(bookingDto.getStart()) &&
+ !bookingDto.getEnd().equals(bookingDto.getStart()))) {
+ throw new BadRequestException("Wrong date");
+ }
+ bookingDto.setBookerId(userId);
+ bookingDto.setStatus(State.WAITING);
+ Booking booking = bRepository.save(BookingMapper.toBooking(bookingDto, item.get(), user.get()));
+ return BookingMapper.toBookingDtoFrom(booking);
+ }
+
+ @Transactional
+ @Override
+ public BookingDTOToReturn updateStatusBooking(Long userId, Long bookingId, Boolean approved) {
+ Booking booking;
+ if (bRepository.existsById(bookingId)) {
+ booking = bRepository.getReferenceById(bookingId);
+ } else {
+ throw new NotFoundException("Booking is empty");
+ }
+ Long ownerId = booking.getItem().getOwner().getId();
+
+ if (!Objects.equals(userId, ownerId)) {
+ throw new NotFoundException("No rights");
+ }
+
+ if (!Objects.equals(String.valueOf(booking.getStatus()), "WAITING")) {
+ throw new BadRequestException("Status has already been changed");
+ }
+
+ if (approved) {
+ booking.setStatus(State.APPROVED);
+ } else {
+ booking.setStatus(State.REJECTED);
+ }
+ return BookingMapper.toBookingDtoFrom(bRepository.save(booking));
+ }
+
+ @Override
+ public BookingDTOToReturn getBooking(Long userId, Long bookingId) {
+ Booking booking;
+ if (bRepository.existsById(bookingId)) {
+ booking = bRepository.getReferenceById(bookingId);
+ } else {
+ throw new NotFoundException("Booking not found");
+ }
+ Long ownerId = booking.getItem().getOwner().getId();
+ Long bookerId = booking.getBooker().getId();
+ if (Objects.equals(ownerId, userId) || Objects.equals(bookerId, userId)) {
+ return BookingMapper.toBookingDtoFrom(booking);
+ }
+ throw new NotFoundException("No rights");
+ }
+
+ @Override
+ public Collection getBookingByBooker(Long usersId, String status) {
+ Optional booker = uRepository.findById(usersId);
+ List bookingsByBooker;
+ if (booker.isEmpty()) {
+ throw new NotFoundException("No rights");
+ }
+ if (status == null || status.equals("")) {
+ status = "ALL";
+ }
+ switch (status) {
+ case "ALL":
+ bookingsByBooker = bRepository.findByBookerOrderByStartDesc(booker.get());
+ break;
+ case "CURRENT":
+ bookingsByBooker = bRepository.findByBookerAndStartBeforeAndEndAfterOrderByStartDesc(booker.get(),
+ LocalDateTime.now(), LocalDateTime.now());
+ break;
+ case "PAST":
+ bookingsByBooker = bRepository.findByBookerAndStartBeforeAndEndBeforeOrderByStartDesc(booker.get(),
+ LocalDateTime.now(), LocalDateTime.now());
+ break;
+ case "FUTURE":
+ bookingsByBooker = bRepository.findByBookerAndStartAfterOrderByStartDesc(booker.get(),
+ LocalDateTime.now());
+ break;
+ case "WAITING":
+ bookingsByBooker = bRepository.findByBookerAndStatusOrderByStartDesc(booker.get(), State.WAITING);
+ break;
+ case "REJECTED":
+ bookingsByBooker = bRepository.findByBookerAndStatusOrderByStartDesc(booker.get(), State.REJECTED);
+ break;
+ default:
+ throw new StatusBadRequestException("Unknown state: UNSUPPORTED_STATUS");
+ }
+ return BookingMapper.mapToBookingDtoFrom(bookingsByBooker);
+ }
+
+ @Override
+ public Collection getBookingByOwner(Long usersId, String status) {
+ Optional owner = uRepository.findById(usersId);
+ List bookingsByOwner;
+ if (owner.isEmpty()) {
+ throw new NotFoundException("No rights");
+ }
+ if (status == null || status.equals("")) {
+ status = "ALL";
+ }
+ switch (status) {
+ case "ALL":
+ bookingsByOwner = bRepository.findByBookingForOwnerWithAll(usersId);
+ break;
+ case "CURRENT":
+ bookingsByOwner = bRepository.findByBookingForOwnerWithCurrent(usersId, LocalDateTime.now(),
+ LocalDateTime.now());
+ break;
+ case "PAST":
+ bookingsByOwner = bRepository.findByBookingForOwnerWithPast(usersId, LocalDateTime.now(),
+ LocalDateTime.now());
+ break;
+ case "FUTURE":
+ bookingsByOwner = bRepository.findByBookingForOwnerWithFuture(usersId, LocalDateTime.now());
+ break;
+ case "WAITING":
+ bookingsByOwner = bRepository.findByBookingForOwnerWithWaitingOrRejected(usersId, "WAITING");
+ break;
+ case "REJECTED":
+ bookingsByOwner = bRepository.findByBookingForOwnerWithWaitingOrRejected(usersId, "REJECTED");
+ break;
+ default:
+ throw new StatusBadRequestException("Unknown state: UNSUPPORTED_STATUS");
+ }
+ return BookingMapper.mapToBookingDtoFrom(bookingsByOwner);
+ }
+}
diff --git a/src/main/java/ru/practicum/shareit/exception/BadRequestException.java b/src/main/java/ru/practicum/shareit/exception/BadRequestException.java
new file mode 100644
index 000000000..2d29b341e
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/exception/BadRequestException.java
@@ -0,0 +1,7 @@
+package ru.practicum.shareit.exception;
+
+public class BadRequestException extends IllegalArgumentException {
+ public BadRequestException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/ru/practicum/shareit/exception/ConflictException.java b/src/main/java/ru/practicum/shareit/exception/ConflictException.java
new file mode 100644
index 000000000..788512303
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/exception/ConflictException.java
@@ -0,0 +1,7 @@
+package ru.practicum.shareit.exception;
+
+public class ConflictException extends RuntimeException {
+ public ConflictException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/ru/practicum/shareit/exception/ErrorHandler.java b/src/main/java/ru/practicum/shareit/exception/ErrorHandler.java
new file mode 100644
index 000000000..91204e8d4
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/exception/ErrorHandler.java
@@ -0,0 +1,69 @@
+package ru.practicum.shareit.exception;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.http.converter.HttpMessageConversionException;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import java.util.Map;
+
+@RestControllerAdvice
+public class ErrorHandler {
+
+ @ExceptionHandler({HttpMessageConversionException.class, BadRequestException.class})
+ public ResponseEntity