From 4ea6be71d71149ee016b22aa9e51a3542357afa5 Mon Sep 17 00:00:00 2001 From: Egor Ilyin Date: Sun, 30 Nov 2025 22:34:03 +0300 Subject: [PATCH 1/7] add item request feature --- .../shareit/booking/mapper/BookingMapper.java | 1 + .../shareit/item/dto/ShortItemDto.java | 8 +- .../shareit/item/mapper/ItemMapper.java | 9 ++ .../ru/practicum/shareit/item/model/Item.java | 2 +- .../item/repository/ItemRepository.java | 5 ++ .../shareit/item/service/ItemServiceImpl.java | 12 +++ .../request/ItemRequestController.java | 44 ++++++++-- .../shareit/request/dto/ItemRequestDto.java | 5 ++ .../request/mapper/ItemRequestMapper.java | 20 ++++- .../request/{ => model}/ItemRequest.java | 8 +- .../repository/ItemRequestRepository.java | 12 +++ .../request/service/ItemRequestService.java | 16 ++++ .../service/ItemRequestServiceImpl.java | 85 +++++++++++++++++++ 13 files changed, 213 insertions(+), 14 deletions(-) rename src/main/java/ru/practicum/shareit/request/{ => model}/ItemRequest.java (81%) create mode 100644 src/main/java/ru/practicum/shareit/request/repository/ItemRequestRepository.java create mode 100644 src/main/java/ru/practicum/shareit/request/service/ItemRequestService.java create mode 100644 src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java diff --git a/src/main/java/ru/practicum/shareit/booking/mapper/BookingMapper.java b/src/main/java/ru/practicum/shareit/booking/mapper/BookingMapper.java index 2fd635c..e6fbcb3 100644 --- a/src/main/java/ru/practicum/shareit/booking/mapper/BookingMapper.java +++ b/src/main/java/ru/practicum/shareit/booking/mapper/BookingMapper.java @@ -19,6 +19,7 @@ public static BookingDto toBookingDto(Booking booking) { .item(ShortItemDto.builder() .id(booking.getItem().getId()) .name(booking.getItem().getName()) + .ownerId(booking.getItem().getOwner().getId()) .build()) .booker(ShortUserDto.builder() .id(booking.getBooker().getId()) diff --git a/src/main/java/ru/practicum/shareit/item/dto/ShortItemDto.java b/src/main/java/ru/practicum/shareit/item/dto/ShortItemDto.java index 2ecadbf..6eea332 100644 --- a/src/main/java/ru/practicum/shareit/item/dto/ShortItemDto.java +++ b/src/main/java/ru/practicum/shareit/item/dto/ShortItemDto.java @@ -1,11 +1,15 @@ package ru.practicum.shareit.item.dto; +import lombok.AccessLevel; import lombok.Builder; import lombok.Data; +import lombok.experimental.FieldDefaults; @Data @Builder +@FieldDefaults(level = AccessLevel.PRIVATE) public class ShortItemDto { - private Long id; - private String name; + Long id; + String name; + Long ownerId; } diff --git a/src/main/java/ru/practicum/shareit/item/mapper/ItemMapper.java b/src/main/java/ru/practicum/shareit/item/mapper/ItemMapper.java index b50085c..dccfd98 100644 --- a/src/main/java/ru/practicum/shareit/item/mapper/ItemMapper.java +++ b/src/main/java/ru/practicum/shareit/item/mapper/ItemMapper.java @@ -5,6 +5,7 @@ import ru.practicum.shareit.booking.model.Booking; import ru.practicum.shareit.item.dto.ItemDto; import ru.practicum.shareit.item.dto.ItemDtoWithBookingsAndComments; +import ru.practicum.shareit.item.dto.ShortItemDto; import ru.practicum.shareit.item.model.Comment; import ru.practicum.shareit.item.model.Item; @@ -26,6 +27,14 @@ public ItemDto toItemDto(Item item) { .build(); } + public ShortItemDto toShortItemDto(Item item) { + return ShortItemDto.builder() + .id(item.getId()) + .name(item.getName()) + .ownerId(item.getOwner().getId()) + .build(); + } + public Item toItem(ItemDto itemDto) { return Item.builder() .id(itemDto.getId()) diff --git a/src/main/java/ru/practicum/shareit/item/model/Item.java b/src/main/java/ru/practicum/shareit/item/model/Item.java index 4fe84d6..cea3ac0 100644 --- a/src/main/java/ru/practicum/shareit/item/model/Item.java +++ b/src/main/java/ru/practicum/shareit/item/model/Item.java @@ -3,7 +3,7 @@ import jakarta.persistence.*; import lombok.*; import lombok.experimental.FieldDefaults; -import ru.practicum.shareit.request.ItemRequest; +import ru.practicum.shareit.request.model.ItemRequest; import ru.practicum.shareit.user.model.User; @Data diff --git a/src/main/java/ru/practicum/shareit/item/repository/ItemRepository.java b/src/main/java/ru/practicum/shareit/item/repository/ItemRepository.java index 24ba577..b6cf185 100644 --- a/src/main/java/ru/practicum/shareit/item/repository/ItemRepository.java +++ b/src/main/java/ru/practicum/shareit/item/repository/ItemRepository.java @@ -5,6 +5,7 @@ import ru.practicum.shareit.item.model.Item; import java.util.Collection; +import java.util.List; public interface ItemRepository extends JpaRepository { @@ -17,4 +18,8 @@ public interface ItemRepository extends JpaRepository { OR UPPER(i.description) LIKE UPPER(CONCAT('%', ?1, '%'))) """) Collection search(String text); + + Collection findAllByRequestId(Long requestId); + + Collection findAllByRequestIdIn(List ids); } diff --git a/src/main/java/ru/practicum/shareit/item/service/ItemServiceImpl.java b/src/main/java/ru/practicum/shareit/item/service/ItemServiceImpl.java index 840da1c..778da95 100644 --- a/src/main/java/ru/practicum/shareit/item/service/ItemServiceImpl.java +++ b/src/main/java/ru/practicum/shareit/item/service/ItemServiceImpl.java @@ -18,6 +18,8 @@ import ru.practicum.shareit.item.model.Item; import ru.practicum.shareit.item.repository.CommentRepository; import ru.practicum.shareit.item.repository.ItemRepository; +import ru.practicum.shareit.request.model.ItemRequest; +import ru.practicum.shareit.request.repository.ItemRequestRepository; import ru.practicum.shareit.user.model.User; import ru.practicum.shareit.user.repository.UserRepository; @@ -36,6 +38,7 @@ public class ItemServiceImpl implements ItemService { private final UserRepository userRepository; private final BookingRepository bookingRepository; private final CommentRepository commentRepository; + private final ItemRequestRepository requestRepository; @Override public Collection getAllByUser(Long userId) { @@ -80,6 +83,10 @@ public ItemDtoWithBookingsAndComments getById(Long userId, Long itemId) { public ItemDto create(Long userId, ItemDto item) { User owner = throwIfUserNotExist(userId); Item newItem = ItemMapper.toItem(item); + if (item.getRequestId() != null) { + ItemRequest request = throwIfRequestNotExist(item.getRequestId()); + newItem.setRequest(request); + } newItem.setOwner(owner); newItem = itemRepository.save(newItem); return ItemMapper.toItemDto(newItem); @@ -143,4 +150,9 @@ private Item throwIfItemNotExist(Long id) { return itemRepository.findById(id) .orElseThrow(() -> new NotFoundException("Предмет с ID: %s не найден".formatted(id))); } + + private ItemRequest throwIfRequestNotExist(Long id) { + return requestRepository.findById(id) + .orElseThrow(() -> new NotFoundException("Запрос с ID: %s не найден".formatted(id))); + } } diff --git a/src/main/java/ru/practicum/shareit/request/ItemRequestController.java b/src/main/java/ru/practicum/shareit/request/ItemRequestController.java index 064e2e9..bb116b8 100644 --- a/src/main/java/ru/practicum/shareit/request/ItemRequestController.java +++ b/src/main/java/ru/practicum/shareit/request/ItemRequestController.java @@ -1,12 +1,46 @@ package ru.practicum.shareit.request; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; +import ru.practicum.shareit.request.dto.ItemRequestDto; +import ru.practicum.shareit.request.service.ItemRequestService; + +import java.util.Collection; + +import static ru.practicum.shareit.util.Constants.USER_ID_HEADER; -/** - * TODO Sprint add-item-requests. - */ @RestController @RequestMapping(path = "/requests") +@AllArgsConstructor public class ItemRequestController { + + private final ItemRequestService itemRequestService; + + @PostMapping + @Transactional + public ItemRequestDto create(@RequestHeader(USER_ID_HEADER) Long userId, + @RequestBody @Valid ItemRequestDto request) { + return itemRequestService.create(userId, request); + } + + @GetMapping + public Collection getByUser(@RequestHeader(USER_ID_HEADER) Long userId) { + return itemRequestService.getByUser(userId); + } + + @GetMapping("/all") + public Collection getAll(@RequestHeader(USER_ID_HEADER) Long userId) { + return itemRequestService.getAll(userId); + } + + @GetMapping("/{requestId}") + public ItemRequestDto getById(@RequestHeader(USER_ID_HEADER) Long userId, + @PathVariable Long requestId) { + return itemRequestService.getById(userId, requestId); + } + + } + diff --git a/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java b/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java index 308adc5..3013021 100644 --- a/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java +++ b/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java @@ -1,18 +1,23 @@ package ru.practicum.shareit.request.dto; +import jakarta.validation.constraints.NotNull; import lombok.AccessLevel; import lombok.Builder; import lombok.Data; import lombok.experimental.FieldDefaults; +import ru.practicum.shareit.item.dto.ShortItemDto; import java.time.LocalDateTime; +import java.util.List; @Data @Builder @FieldDefaults(level = AccessLevel.PRIVATE) public class ItemRequestDto { Long id; + @NotNull String description; Long requesterId; LocalDateTime created; + List items; } diff --git a/src/main/java/ru/practicum/shareit/request/mapper/ItemRequestMapper.java b/src/main/java/ru/practicum/shareit/request/mapper/ItemRequestMapper.java index 116e5d6..6fbb5cc 100644 --- a/src/main/java/ru/practicum/shareit/request/mapper/ItemRequestMapper.java +++ b/src/main/java/ru/practicum/shareit/request/mapper/ItemRequestMapper.java @@ -1,9 +1,16 @@ package ru.practicum.shareit.request.mapper; import lombok.experimental.UtilityClass; -import ru.practicum.shareit.request.ItemRequest; +import ru.practicum.shareit.item.dto.ShortItemDto; +import ru.practicum.shareit.item.mapper.ItemMapper; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.request.model.ItemRequest; import ru.practicum.shareit.request.dto.ItemRequestDto; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; + @UtilityClass public class ItemRequestMapper { @@ -16,11 +23,20 @@ public ItemRequestDto toItemRequestDto(ItemRequest itemRequest) { .build(); } + public ItemRequestDto toItemRequestDto(ItemRequest itemRequest, Collection answers) { + ItemRequestDto requestDto = toItemRequestDto(itemRequest); + List shortAnswers = answers.stream() + .map(ItemMapper::toShortItemDto) + .toList(); + requestDto.setItems(shortAnswers); + return requestDto; + } + public ItemRequest toItemRequest(ItemRequestDto itemRequestDto) { return ItemRequest.builder() .id(itemRequestDto.getId()) .description(itemRequestDto.getDescription()) - .created(itemRequestDto.getCreated()) + .created(itemRequestDto.getCreated() == null ? LocalDateTime.now() : itemRequestDto.getCreated()) .build(); } } diff --git a/src/main/java/ru/practicum/shareit/request/ItemRequest.java b/src/main/java/ru/practicum/shareit/request/model/ItemRequest.java similarity index 81% rename from src/main/java/ru/practicum/shareit/request/ItemRequest.java rename to src/main/java/ru/practicum/shareit/request/model/ItemRequest.java index 59579d9..bfe2684 100644 --- a/src/main/java/ru/practicum/shareit/request/ItemRequest.java +++ b/src/main/java/ru/practicum/shareit/request/model/ItemRequest.java @@ -1,9 +1,7 @@ -package ru.practicum.shareit.request; +package ru.practicum.shareit.request.model; import jakarta.persistence.*; -import lombok.AccessLevel; -import lombok.Builder; -import lombok.Data; +import lombok.*; import lombok.experimental.FieldDefaults; import ru.practicum.shareit.user.model.User; @@ -12,6 +10,8 @@ @Data @Builder @FieldDefaults(level = AccessLevel.PRIVATE) +@NoArgsConstructor +@AllArgsConstructor @Entity @Table(name = "requests") public class ItemRequest { diff --git a/src/main/java/ru/practicum/shareit/request/repository/ItemRequestRepository.java b/src/main/java/ru/practicum/shareit/request/repository/ItemRequestRepository.java new file mode 100644 index 0000000..07eb9c8 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/request/repository/ItemRequestRepository.java @@ -0,0 +1,12 @@ +package ru.practicum.shareit.request.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import ru.practicum.shareit.request.model.ItemRequest; + +import java.util.Collection; + +public interface ItemRequestRepository extends JpaRepository { + Collection findAllByRequesterIdOrderByCreatedDesc(Long requesterId); + + Collection findAllByRequesterIdNotOrderByCreatedDesc(Long requesterId); +} diff --git a/src/main/java/ru/practicum/shareit/request/service/ItemRequestService.java b/src/main/java/ru/practicum/shareit/request/service/ItemRequestService.java new file mode 100644 index 0000000..0de1470 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/request/service/ItemRequestService.java @@ -0,0 +1,16 @@ +package ru.practicum.shareit.request.service; + +import ru.practicum.shareit.request.dto.ItemRequestDto; + +import java.util.Collection; + +public interface ItemRequestService { + + ItemRequestDto create(Long userId, ItemRequestDto request); + + Collection getByUser(Long userId); + + Collection getAll(Long userId); + + ItemRequestDto getById(Long userId, Long requestId); +} diff --git a/src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java b/src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java new file mode 100644 index 0000000..deb09f9 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java @@ -0,0 +1,85 @@ +package ru.practicum.shareit.request.service; + +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ru.practicum.shareit.exception.NotFoundException; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.item.repository.ItemRepository; +import ru.practicum.shareit.request.dto.ItemRequestDto; +import ru.practicum.shareit.request.mapper.ItemRequestMapper; +import ru.practicum.shareit.request.model.ItemRequest; +import ru.practicum.shareit.request.repository.ItemRequestRepository; +import ru.practicum.shareit.user.model.User; +import ru.practicum.shareit.user.repository.UserRepository; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +@AllArgsConstructor +@Transactional(readOnly = true) +public class ItemRequestServiceImpl implements ItemRequestService { + + private final ItemRequestRepository itemRequestRepository; + private final UserRepository userRepository; + private final ItemRepository itemRepository; + + @Override + public ItemRequestDto create(Long userId, ItemRequestDto requestDto) { + User requester = throwIfUserNotExist(userId); + ItemRequest request = ItemRequestMapper.toItemRequest(requestDto); + request.setRequester(requester); + request = itemRequestRepository.save(request); + return ItemRequestMapper.toItemRequestDto(request); + } + + @Override + public Collection getByUser(Long userId) { + throwIfUserNotExist(userId); + Collection requests = itemRequestRepository.findAllByRequesterIdOrderByCreatedDesc(userId); + if (requests.isEmpty()) { + return Collections.emptyList(); + } + List requestsIds = requests.stream().map(ItemRequest::getId).toList(); + Collection items = itemRepository.findAllByRequestIdIn(requestsIds); + + Map> itemsByRequest = items.stream() + .collect(Collectors.groupingBy(item -> item.getRequest().getId())); + + return requests.stream() + .map(request -> ItemRequestMapper.toItemRequestDto(request, + itemsByRequest.getOrDefault(request.getId(), List.of()))) + .toList(); + } + + @Override + public Collection getAll(Long userId) { + throwIfUserNotExist(userId); + Collection requests = itemRequestRepository.findAllByRequesterIdNotOrderByCreatedDesc(userId); + if (requests.isEmpty()) { + return Collections.emptyList(); + } + return requests.stream() + .map(ItemRequestMapper::toItemRequestDto) + .toList(); + } + + @Override + public ItemRequestDto getById(Long userId, Long requestId) { + throwIfUserNotExist(userId); + Collection answers = itemRepository.findAllByRequestId(requestId); + + return itemRequestRepository.findById(requestId) + .map(itemRequest -> ItemRequestMapper.toItemRequestDto(itemRequest, answers)) + .orElseThrow(() -> new NotFoundException("Запрос с ID: %s не найден".formatted(requestId))); + } + + private User throwIfUserNotExist(Long id) { + return userRepository.findById(id) + .orElseThrow(() -> new NotFoundException("Пользователь с ID: %s не найден".formatted(id))); + } +} From ad1f1ef854c8c15473037e8845e723761d8922c2 Mon Sep 17 00:00:00 2001 From: Egor Ilyin Date: Sat, 6 Dec 2025 14:01:04 +0300 Subject: [PATCH 2/7] add two models --- .run/ShareItGateway.run.xml | 15 +++ .run/ShareItServer.run.xml | 15 +++ docker-compose.yaml | 32 ++++- gateway/Dockerfile | 5 + gateway/pom.xml | 70 ++++++++++ .../ru/practicum/shareit/ShareItGateway.java | 12 ++ .../shareit/booking/BookingClient.java | 60 +++++++++ .../shareit/booking/BookingController.java | 68 ++++++++++ .../shareit/booking/BookingState.java | 3 +- .../shareit/booking/BookingStatus.java | 0 .../shareit/booking/dto/BookingDto.java | 0 .../booking/dto/RequestBookingDto.java | 0 .../shareit/booking/dto/ShortBookingDto.java | 0 .../practicum/shareit/client/BaseClient.java | 121 +++++++++++++++++ .../ru/practicum/shareit/item/ItemClient.java | 55 ++++++++ .../shareit/item/ItemController.java | 65 +++++++++ .../shareit/item/dto/CommentDto.java | 0 .../practicum/shareit/item/dto/ItemDto.java | 0 .../dto/ItemDtoWithBookingsAndComments.java | 0 .../shareit/item/dto/ShortItemDto.java | 0 .../shareit/item/dto/UpdateItemDto.java | 0 .../shareit/request/RequestClient.java | 42 ++++++ .../shareit/request/RequestController.java | 47 +++++++ .../shareit/request/dto/ItemRequestDto.java | 0 .../ru/practicum/shareit/user/UserClient.java | 47 +++++++ .../shareit/user/UserController.java | 53 ++++++++ .../shareit/user/dto/ShortUserDto.java | 0 .../shareit/user/dto/UpdateUserDto.java | 0 .../practicum/shareit/user/dto/UserDto.java | 0 .../ru/practicum/shareit/util/Constants.java | 2 - .../src/main/resources/application.properties | 7 + pom.xml | 127 +++--------------- server/Dockerfile | 5 + server/pom.xml | 90 +++++++++++++ .../ru/practicum/shareit/ShareItServer.java | 9 +- .../shareit/booking/BookingController.java | 6 +- .../shareit/booking/BookingState.java | 19 +++ .../shareit/booking/BookingStatus.java | 8 ++ .../shareit/booking/dto/BookingDto.java | 23 ++++ .../booking/dto/RequestBookingDto.java | 17 +++ .../shareit/booking/dto/ShortBookingDto.java | 16 +++ .../shareit/booking/mapper/BookingMapper.java | 0 .../shareit/booking/model/Booking.java | 0 .../booking/repository/BookingRepository.java | 0 .../booking/service/BookingService.java | 5 +- .../booking/service/BookingServiceImpl.java | 10 +- .../DuplicateValidationException.java | 0 .../shareit/exception/ExceptionsHandler.java | 0 .../shareit/exception/ForbiddenException.java | 0 .../shareit/exception/NotFoundException.java | 0 .../exception/ValidationException.java | 0 .../shareit/item/ItemController.java | 12 +- .../shareit/item/dto/CommentDto.java | 19 +++ .../practicum/shareit/item/dto/ItemDto.java | 20 +++ .../dto/ItemDtoWithBookingsAndComments.java | 23 ++++ .../shareit/item/dto/ShortItemDto.java | 15 +++ .../shareit/item/dto/UpdateItemDto.java | 13 ++ .../shareit/item/mapper/CommentMapper.java | 0 .../shareit/item/mapper/ItemMapper.java | 0 .../practicum/shareit/item/model/Comment.java | 0 .../ru/practicum/shareit/item/model/Item.java | 0 .../item/repository/CommentRepository.java | 0 .../item/repository/ItemRepository.java | 0 .../shareit/item/service/ItemService.java | 0 .../shareit/item/service/ItemServiceImpl.java | 0 .../request/ItemRequestController.java | 5 +- .../shareit/request/dto/ItemRequestDto.java | 21 +++ .../request/mapper/ItemRequestMapper.java | 0 .../shareit/request/model/ItemRequest.java | 0 .../repository/ItemRequestRepository.java | 0 .../request/service/ItemRequestService.java | 0 .../service/ItemRequestServiceImpl.java | 0 .../shareit/user/UserController.java | 13 +- .../shareit/user/dto/ShortUserDto.java | 10 ++ .../shareit/user/dto/UpdateUserDto.java | 15 +++ .../practicum/shareit/user/dto/UserDto.java | 15 +++ .../shareit/user/mapper/UserMapper.java | 2 +- .../ru/practicum/shareit/user/model/User.java | 0 .../user/repository/UserRepository.java | 0 .../shareit/user/service/UserService.java | 0 .../shareit/user/service/UserServiceImpl.java | 0 .../ru/practicum/shareit/util/Constants.java | 5 + .../src/main/resources/application.properties | 17 +++ {src => server/src}/main/resources/schema.sql | 0 .../resources/application-test.properties | 12 -- src/main/resources/application.properties | 14 -- .../ru/practicum/shareit/ShareItTests.java | 13 -- 87 files changed, 1109 insertions(+), 189 deletions(-) create mode 100644 .run/ShareItGateway.run.xml create mode 100644 .run/ShareItServer.run.xml create mode 100644 gateway/Dockerfile create mode 100644 gateway/pom.xml create mode 100644 gateway/src/main/java/ru/practicum/shareit/ShareItGateway.java create mode 100644 gateway/src/main/java/ru/practicum/shareit/booking/BookingClient.java create mode 100644 gateway/src/main/java/ru/practicum/shareit/booking/BookingController.java rename {src => gateway/src}/main/java/ru/practicum/shareit/booking/BookingState.java (73%) rename {src => gateway/src}/main/java/ru/practicum/shareit/booking/BookingStatus.java (100%) rename {src => gateway/src}/main/java/ru/practicum/shareit/booking/dto/BookingDto.java (100%) rename {src => gateway/src}/main/java/ru/practicum/shareit/booking/dto/RequestBookingDto.java (100%) rename {src => gateway/src}/main/java/ru/practicum/shareit/booking/dto/ShortBookingDto.java (100%) create mode 100644 gateway/src/main/java/ru/practicum/shareit/client/BaseClient.java create mode 100644 gateway/src/main/java/ru/practicum/shareit/item/ItemClient.java create mode 100644 gateway/src/main/java/ru/practicum/shareit/item/ItemController.java rename {src => gateway/src}/main/java/ru/practicum/shareit/item/dto/CommentDto.java (100%) rename {src => gateway/src}/main/java/ru/practicum/shareit/item/dto/ItemDto.java (100%) rename {src => gateway/src}/main/java/ru/practicum/shareit/item/dto/ItemDtoWithBookingsAndComments.java (100%) rename {src => gateway/src}/main/java/ru/practicum/shareit/item/dto/ShortItemDto.java (100%) rename {src => gateway/src}/main/java/ru/practicum/shareit/item/dto/UpdateItemDto.java (100%) create mode 100644 gateway/src/main/java/ru/practicum/shareit/request/RequestClient.java create mode 100644 gateway/src/main/java/ru/practicum/shareit/request/RequestController.java rename {src => gateway/src}/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java (100%) create mode 100644 gateway/src/main/java/ru/practicum/shareit/user/UserClient.java create mode 100644 gateway/src/main/java/ru/practicum/shareit/user/UserController.java rename {src => gateway/src}/main/java/ru/practicum/shareit/user/dto/ShortUserDto.java (100%) rename {src => gateway/src}/main/java/ru/practicum/shareit/user/dto/UpdateUserDto.java (100%) rename {src => gateway/src}/main/java/ru/practicum/shareit/user/dto/UserDto.java (100%) rename {src => gateway/src}/main/java/ru/practicum/shareit/util/Constants.java (98%) create mode 100644 gateway/src/main/resources/application.properties create mode 100644 server/Dockerfile create mode 100644 server/pom.xml rename src/main/java/ru/practicum/shareit/ShareItApp.java => server/src/main/java/ru/practicum/shareit/ShareItServer.java (56%) rename {src => server/src}/main/java/ru/practicum/shareit/booking/BookingController.java (85%) create mode 100644 server/src/main/java/ru/practicum/shareit/booking/BookingState.java create mode 100644 server/src/main/java/ru/practicum/shareit/booking/BookingStatus.java create mode 100644 server/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java create mode 100644 server/src/main/java/ru/practicum/shareit/booking/dto/RequestBookingDto.java create mode 100644 server/src/main/java/ru/practicum/shareit/booking/dto/ShortBookingDto.java rename {src => server/src}/main/java/ru/practicum/shareit/booking/mapper/BookingMapper.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/booking/model/Booking.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/booking/repository/BookingRepository.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/booking/service/BookingService.java (67%) rename {src => server/src}/main/java/ru/practicum/shareit/booking/service/BookingServiceImpl.java (93%) rename {src => server/src}/main/java/ru/practicum/shareit/exception/DuplicateValidationException.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/exception/ExceptionsHandler.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/exception/ForbiddenException.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/exception/NotFoundException.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/exception/ValidationException.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/item/ItemController.java (80%) create mode 100644 server/src/main/java/ru/practicum/shareit/item/dto/CommentDto.java create mode 100644 server/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java create mode 100644 server/src/main/java/ru/practicum/shareit/item/dto/ItemDtoWithBookingsAndComments.java create mode 100644 server/src/main/java/ru/practicum/shareit/item/dto/ShortItemDto.java create mode 100644 server/src/main/java/ru/practicum/shareit/item/dto/UpdateItemDto.java rename {src => server/src}/main/java/ru/practicum/shareit/item/mapper/CommentMapper.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/item/mapper/ItemMapper.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/item/model/Comment.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/item/model/Item.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/item/repository/CommentRepository.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/item/repository/ItemRepository.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/item/service/ItemService.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/item/service/ItemServiceImpl.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/request/ItemRequestController.java (92%) create mode 100644 server/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java rename {src => server/src}/main/java/ru/practicum/shareit/request/mapper/ItemRequestMapper.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/request/model/ItemRequest.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/request/repository/ItemRequestRepository.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/request/service/ItemRequestService.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/user/UserController.java (75%) create mode 100644 server/src/main/java/ru/practicum/shareit/user/dto/ShortUserDto.java create mode 100644 server/src/main/java/ru/practicum/shareit/user/dto/UpdateUserDto.java create mode 100644 server/src/main/java/ru/practicum/shareit/user/dto/UserDto.java rename {src => server/src}/main/java/ru/practicum/shareit/user/mapper/UserMapper.java (99%) rename {src => server/src}/main/java/ru/practicum/shareit/user/model/User.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/user/repository/UserRepository.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/user/service/UserService.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/user/service/UserServiceImpl.java (100%) create mode 100644 server/src/main/java/ru/practicum/shareit/util/Constants.java create mode 100644 server/src/main/resources/application.properties rename {src => server/src}/main/resources/schema.sql (100%) delete mode 100644 src/main/resources/application-test.properties delete mode 100644 src/main/resources/application.properties delete mode 100644 src/test/java/ru/practicum/shareit/ShareItTests.java diff --git a/.run/ShareItGateway.run.xml b/.run/ShareItGateway.run.xml new file mode 100644 index 0000000..b30b178 --- /dev/null +++ b/.run/ShareItGateway.run.xml @@ -0,0 +1,15 @@ + + + + \ No newline at end of file diff --git a/.run/ShareItServer.run.xml b/.run/ShareItServer.run.xml new file mode 100644 index 0000000..b30b178 --- /dev/null +++ b/.run/ShareItServer.run.xml @@ -0,0 +1,15 @@ + + + + \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index b155d4e..abe6570 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,15 +1,37 @@ services: + gateway: + build: gateway + image: shareit-gateway + container_name: shareit-gateway + ports: + - "8080:8080" + depends_on: + - server + environment: + - SHAREIT_SERVER_URL=http://server:9090 + + server: + build: server + image: shareit-server + container_name: shareit-server + ports: + - "9090:9090" + depends_on: + - db + environment: + - SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/shareit + - SPRING_DATASOURCE_USERNAME=shareit + - SPRING_DATASOURCE_PASSWORD=shareit + db: image: postgres:16.1 container_name: postgres ports: - - "5432:5432" - volumes: - - ./volumes/postgres:/var/lib/postgresql/data/ + - "6541:5432" environment: + - POSTGRES_PASSWORD=shareit + - POSTGRES_USER=shareit - POSTGRES_DB=shareit - - POSTGRES_USER=sa - - POSTGRES_PASSWORD=password healthcheck: test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER timeout: 5s diff --git a/gateway/Dockerfile b/gateway/Dockerfile new file mode 100644 index 0000000..0ff1817 --- /dev/null +++ b/gateway/Dockerfile @@ -0,0 +1,5 @@ +FROM eclipse-temurin:21-jre-jammy +VOLUME /tmp +ARG JAR_FILE=target/*.jar +COPY ${JAR_FILE} app.jar +ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"] \ No newline at end of file diff --git a/gateway/pom.xml b/gateway/pom.xml new file mode 100644 index 0000000..f3394c1 --- /dev/null +++ b/gateway/pom.xml @@ -0,0 +1,70 @@ + + + 4.0.0 + + ru.practicum + shareit + 0.0.1-SNAPSHOT + + + shareit-gateway + 0.0.1-SNAPSHOT + + ShareIt Gateway + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-validation + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.hibernate.validator + hibernate-validator + + + + org.apache.httpcomponents.client5 + httpclient5 + + + + 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-maven-plugin + + + + + \ No newline at end of file diff --git a/gateway/src/main/java/ru/practicum/shareit/ShareItGateway.java b/gateway/src/main/java/ru/practicum/shareit/ShareItGateway.java new file mode 100644 index 0000000..e659d11 --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/ShareItGateway.java @@ -0,0 +1,12 @@ +package ru.practicum.shareit; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ShareItGateway { + public static void main(String[] args) { + SpringApplication.run(ShareItGateway.class, args); + } + +} diff --git a/gateway/src/main/java/ru/practicum/shareit/booking/BookingClient.java b/gateway/src/main/java/ru/practicum/shareit/booking/BookingClient.java new file mode 100644 index 0000000..ce168bc --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/booking/BookingClient.java @@ -0,0 +1,60 @@ +package ru.practicum.shareit.booking; + +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.stereotype.Service; +import org.springframework.web.util.DefaultUriBuilderFactory; + +import ru.practicum.shareit.booking.dto.RequestBookingDto; +import ru.practicum.shareit.client.BaseClient; + +@Service +public class BookingClient extends BaseClient { + private static final String API_PREFIX = "/bookings"; + + @Autowired + public BookingClient(@Value("${shareit-server.url}") String serverUrl, RestTemplateBuilder builder) { + super( + builder + .uriTemplateHandler(new DefaultUriBuilderFactory(serverUrl + API_PREFIX)) + .requestFactory(() -> new HttpComponentsClientHttpRequestFactory()) + .build() + ); + } + + public ResponseEntity getBookings(Long userId, BookingState state, Integer from, Integer size) { + Map params = Map.of( + "state", state.name(), + "from", from, + "size", size + ); + return get("?state={state}&from={from}&size={size}", userId, params); + } + + public ResponseEntity getBookingsByOwner(Long userId, BookingState state, Integer from, Integer size) { + Map params = Map.of( + "state", state.name(), + "from", from, + "size", size + ); + return get("/owner?state={state}&from={from}&size={size}", userId, params); + } + + public ResponseEntity bookItem(Long userId, RequestBookingDto requestDto) { + return post("", userId, requestDto); + } + + public ResponseEntity getBooking(Long userId, Long bookingId) { + return get("/" + bookingId, userId); + } + + public ResponseEntity updateBookingStatus(Long userId, Long bookingId, Boolean approved) { + Map params = Map.of("approved", approved); + return patch("/" + bookingId + "?approved={approved}", userId, params, null); + } +} diff --git a/gateway/src/main/java/ru/practicum/shareit/booking/BookingController.java b/gateway/src/main/java/ru/practicum/shareit/booking/BookingController.java new file mode 100644 index 0000000..dd37125 --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/booking/BookingController.java @@ -0,0 +1,68 @@ +package ru.practicum.shareit.booking; + +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.PositiveOrZero; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import ru.practicum.shareit.booking.dto.RequestBookingDto; + +import static ru.practicum.shareit.util.Constants.USER_ID_HEADER; + + +@Controller +@RequestMapping(path = "/bookings") +@RequiredArgsConstructor +@Slf4j +@Validated +public class BookingController { + private final BookingClient bookingClient; + + @GetMapping + public ResponseEntity getBookings(@RequestHeader(USER_ID_HEADER) Long userId, + @RequestParam(name = "state", defaultValue = "all") String stateParam, + @PositiveOrZero @RequestParam(name = "from", defaultValue = "0") Integer from, + @Positive @RequestParam(name = "size", defaultValue = "10") Integer size) { + BookingState state = BookingState.from(stateParam); + log.info("Запрос на бронирования со статусом {}, userId={}, from={}, size={}", stateParam, userId, from, size); + return bookingClient.getBookings(userId, state, from, size); + } + + @PostMapping + public ResponseEntity bookItem(@RequestHeader(USER_ID_HEADER) Long userId, + @RequestBody @Valid RequestBookingDto requestDto) { + log.info("Создание бронирования {}, userId={}", requestDto, userId); + return bookingClient.bookItem(userId, requestDto); + } + + @PatchMapping("/{bookingId}") + public ResponseEntity updateBookingStatus(@RequestHeader(USER_ID_HEADER) Long userId, + @Positive @PathVariable Long bookingId, + @RequestParam Boolean approved) { + log.info("Изменение статуса бронирования bookingId={}, userId={}, approved={}", bookingId, userId, approved); + return bookingClient.updateBookingStatus(userId, bookingId, approved); + } + + @GetMapping("/{bookingId}") + public ResponseEntity getBooking(@RequestHeader(USER_ID_HEADER) Long userId, + @PathVariable Long bookingId) { + log.info("Запрос информации о бронировании {}, userId={}", bookingId, userId); + return bookingClient.getBooking(userId, bookingId); + } + + @GetMapping("/owner") + public ResponseEntity getBookingsByOwner(@RequestHeader(USER_ID_HEADER) Long userId, + @RequestParam(name = "state", defaultValue = "all") String stateParam, + @PositiveOrZero @RequestParam(name = "from", defaultValue = "0") Integer from, + @Positive @RequestParam(name = "size", defaultValue = "10") Integer size) { + BookingState state = BookingState.from(stateParam); + log.info("Запрос на бронирования владельцем userId={} со статусом {}, from={}, size={}", + userId, stateParam, from, size); + return bookingClient.getBookingsByOwner(userId, state, from, size); + } +} diff --git a/src/main/java/ru/practicum/shareit/booking/BookingState.java b/gateway/src/main/java/ru/practicum/shareit/booking/BookingState.java similarity index 73% rename from src/main/java/ru/practicum/shareit/booking/BookingState.java rename to gateway/src/main/java/ru/practicum/shareit/booking/BookingState.java index db2af19..52bed18 100644 --- a/src/main/java/ru/practicum/shareit/booking/BookingState.java +++ b/gateway/src/main/java/ru/practicum/shareit/booking/BookingState.java @@ -1,7 +1,6 @@ package ru.practicum.shareit.booking; import lombok.Getter; -import ru.practicum.shareit.exception.ValidationException; import java.util.Arrays; @@ -24,6 +23,6 @@ public static BookingState from(String text) { return Arrays.stream(values()) .filter(s -> s.value.equalsIgnoreCase(text)) .findFirst() - .orElseThrow(() -> new ValidationException("Неизвестный статус бронирования: " + text)); + .orElseThrow(() -> new IllegalArgumentException("Неизвестный статус бронирования: " + text)); } } diff --git a/src/main/java/ru/practicum/shareit/booking/BookingStatus.java b/gateway/src/main/java/ru/practicum/shareit/booking/BookingStatus.java similarity index 100% rename from src/main/java/ru/practicum/shareit/booking/BookingStatus.java rename to gateway/src/main/java/ru/practicum/shareit/booking/BookingStatus.java diff --git a/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java b/gateway/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java similarity index 100% rename from src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java rename to gateway/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java diff --git a/src/main/java/ru/practicum/shareit/booking/dto/RequestBookingDto.java b/gateway/src/main/java/ru/practicum/shareit/booking/dto/RequestBookingDto.java similarity index 100% rename from src/main/java/ru/practicum/shareit/booking/dto/RequestBookingDto.java rename to gateway/src/main/java/ru/practicum/shareit/booking/dto/RequestBookingDto.java diff --git a/src/main/java/ru/practicum/shareit/booking/dto/ShortBookingDto.java b/gateway/src/main/java/ru/practicum/shareit/booking/dto/ShortBookingDto.java similarity index 100% rename from src/main/java/ru/practicum/shareit/booking/dto/ShortBookingDto.java rename to gateway/src/main/java/ru/practicum/shareit/booking/dto/ShortBookingDto.java diff --git a/gateway/src/main/java/ru/practicum/shareit/client/BaseClient.java b/gateway/src/main/java/ru/practicum/shareit/client/BaseClient.java new file mode 100644 index 0000000..fc1f6a1 --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/client/BaseClient.java @@ -0,0 +1,121 @@ +package ru.practicum.shareit.client; + +import java.util.List; +import java.util.Map; + +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.lang.Nullable; +import org.springframework.web.client.HttpStatusCodeException; +import org.springframework.web.client.RestTemplate; + +public class BaseClient { + protected final RestTemplate rest; + + public BaseClient(RestTemplate rest) { + this.rest = rest; + } + + protected ResponseEntity get(String path) { + return get(path, null, null); + } + + protected ResponseEntity get(String path, Long userId) { + return get(path, userId, null); + } + + protected ResponseEntity get(String path, Long userId, @Nullable Map parameters) { + return makeAndSendRequest(HttpMethod.GET, path, userId, parameters, null); + } + + protected ResponseEntity post(String path, T body) { + return post(path, null, null, body); + } + + protected ResponseEntity post(String path, Long userId, T body) { + return post(path, userId, null, body); + } + + protected ResponseEntity post(String path, Long userId, @Nullable Map parameters, T body) { + return makeAndSendRequest(HttpMethod.POST, path, userId, parameters, body); + } + + protected ResponseEntity put(String path, Long userId, T body) { + return put(path, userId, null, body); + } + + protected ResponseEntity put(String path, Long userId, @Nullable Map parameters, T body) { + return makeAndSendRequest(HttpMethod.PUT, path, userId, parameters, body); + } + + protected ResponseEntity patch(String path, T body) { + return patch(path, null, null, body); + } + + protected ResponseEntity patch(String path, Long userId) { + return patch(path, userId, null, null); + } + + protected ResponseEntity patch(String path, Long userId, T body) { + return patch(path, userId, null, body); + } + + protected ResponseEntity patch(String path, Long userId, @Nullable Map parameters, T body) { + return makeAndSendRequest(HttpMethod.PATCH, path, userId, parameters, body); + } + + protected ResponseEntity delete(String path) { + return delete(path, null, null); + } + + protected ResponseEntity delete(String path, Long userId) { + return delete(path, userId, null); + } + + protected ResponseEntity delete(String path, Long userId, @Nullable Map parameters) { + return makeAndSendRequest(HttpMethod.DELETE, path, userId, parameters, null); + } + + private ResponseEntity makeAndSendRequest(HttpMethod method, String path, Long userId, @Nullable Map parameters, @Nullable T body) { + HttpEntity requestEntity = new HttpEntity<>(body, defaultHeaders(userId)); + + ResponseEntity shareitServerResponse; + try { + if (parameters != null) { + shareitServerResponse = rest.exchange(path, method, requestEntity, Object.class, parameters); + } else { + shareitServerResponse = rest.exchange(path, method, requestEntity, Object.class); + } + } catch (HttpStatusCodeException e) { + return ResponseEntity.status(e.getStatusCode()).body(e.getResponseBodyAsByteArray()); + } + return prepareGatewayResponse(shareitServerResponse); + } + + private HttpHeaders defaultHeaders(Long userId) { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.setAccept(List.of(MediaType.APPLICATION_JSON)); + if (userId != null) { + headers.set("X-Sharer-User-Id", String.valueOf(userId)); + } + return headers; + } + + private static ResponseEntity prepareGatewayResponse(ResponseEntity response) { + if (response.getStatusCode().is2xxSuccessful()) { + return response; + } + + ResponseEntity.BodyBuilder responseBuilder = ResponseEntity.status(response.getStatusCode()); + + if (response.hasBody()) { + return responseBuilder.body(response.getBody()); + } + + return responseBuilder.build(); + } +} \ No newline at end of file diff --git a/gateway/src/main/java/ru/practicum/shareit/item/ItemClient.java b/gateway/src/main/java/ru/practicum/shareit/item/ItemClient.java new file mode 100644 index 0000000..56d8780 --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/item/ItemClient.java @@ -0,0 +1,55 @@ +package ru.practicum.shareit.item; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.stereotype.Service; +import org.springframework.web.util.DefaultUriBuilderFactory; +import ru.practicum.shareit.client.BaseClient; +import ru.practicum.shareit.item.dto.CommentDto; +import ru.practicum.shareit.item.dto.ItemDto; +import ru.practicum.shareit.item.dto.UpdateItemDto; + +import java.util.Map; + +@Service +public class ItemClient extends BaseClient { + private static final String API_PREFIX = "/items"; + + @Autowired + public ItemClient(@Value("${shareit-server.url}") String serverUrl, RestTemplateBuilder builder) { + super( + builder + .uriTemplateHandler(new DefaultUriBuilderFactory(serverUrl + API_PREFIX)) + .requestFactory(() -> new HttpComponentsClientHttpRequestFactory()) + .build() + ); + } + + public ResponseEntity getItems(Long userId) { + return get("", userId); + } + + public ResponseEntity getItem(Long userId, Long itemId) { + return get("/" + itemId, userId); + } + + public ResponseEntity createItem(Long userId, ItemDto itemDto) { + return post("", userId, itemDto); + } + + public ResponseEntity updateItem(Long userId, Long itemId, UpdateItemDto itemDto) { + return patch("/" + itemId, userId, itemDto); + } + + public ResponseEntity searchItems(String text) { + Map params = Map.of("text", text); + return get("/search?text={text}", null, params); + } + + public ResponseEntity addComment(Long authorId, Long itemId, CommentDto commentDto) { + return post("/" + itemId + "/comment", authorId, commentDto); + } +} diff --git a/gateway/src/main/java/ru/practicum/shareit/item/ItemController.java b/gateway/src/main/java/ru/practicum/shareit/item/ItemController.java new file mode 100644 index 0000000..6a87bca --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/item/ItemController.java @@ -0,0 +1,65 @@ +package ru.practicum.shareit.item; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.Positive; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import ru.practicum.shareit.item.dto.CommentDto; +import ru.practicum.shareit.item.dto.ItemDto; +import ru.practicum.shareit.item.dto.UpdateItemDto; + +import static ru.practicum.shareit.util.Constants.USER_ID_HEADER; + +@RestController +@RequestMapping("/items") +@AllArgsConstructor +@Slf4j +@Validated +public class ItemController { + private final ItemClient itemClient; + + @GetMapping + public ResponseEntity getAllItemsByUser(@RequestHeader(USER_ID_HEADER) Long userId) { + log.info("Запрос всех вещей пользователя с userId={}", userId); + return itemClient.getItems(userId); + } + + @GetMapping("/{itemId}") + public ResponseEntity getItemById(@RequestHeader(USER_ID_HEADER) Long userId, + @Positive @PathVariable Long itemId) { + log.info("Запрос вещи с itemId={}, пользователь userId={}", itemId, userId); + return itemClient.getItem(userId, itemId); + } + + @PostMapping + public ResponseEntity createItem(@RequestHeader(USER_ID_HEADER) Long userId, + @RequestBody @Valid ItemDto item) { + log.info("Создание вещи item={}, пользователь userId={}", item, userId); + return itemClient.createItem(userId, item); + } + + @PatchMapping("/{itemId}") + public ResponseEntity updateItem(@RequestHeader(USER_ID_HEADER) Long userId, + @PathVariable @Positive Long itemId, + @RequestBody @Valid UpdateItemDto item) { + log.info("Обновление вещи с itemId={}, item={} пользователь userId={}", itemId, item, userId); + return itemClient.updateItem(userId, itemId, item); + } + + @GetMapping("/search") + public ResponseEntity searchItem(@RequestParam(name = "text") String text) { + log.info("Поиск вещи с текстом={}", text); + return itemClient.searchItems(text); + } + + @PostMapping("{itemId}/comment") + public ResponseEntity addComment(@RequestHeader(USER_ID_HEADER) Long authorId, + @PathVariable @Positive Long itemId, + @RequestBody @Valid CommentDto commentRequest) { + log.info("Добавить комментарий {} от пользователя id={} к вещи itemId={}", commentRequest, authorId, itemId); + return itemClient.addComment(authorId, itemId, commentRequest); + } +} diff --git a/src/main/java/ru/practicum/shareit/item/dto/CommentDto.java b/gateway/src/main/java/ru/practicum/shareit/item/dto/CommentDto.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/dto/CommentDto.java rename to gateway/src/main/java/ru/practicum/shareit/item/dto/CommentDto.java diff --git a/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java b/gateway/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/dto/ItemDto.java rename to gateway/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java diff --git a/src/main/java/ru/practicum/shareit/item/dto/ItemDtoWithBookingsAndComments.java b/gateway/src/main/java/ru/practicum/shareit/item/dto/ItemDtoWithBookingsAndComments.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/dto/ItemDtoWithBookingsAndComments.java rename to gateway/src/main/java/ru/practicum/shareit/item/dto/ItemDtoWithBookingsAndComments.java diff --git a/src/main/java/ru/practicum/shareit/item/dto/ShortItemDto.java b/gateway/src/main/java/ru/practicum/shareit/item/dto/ShortItemDto.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/dto/ShortItemDto.java rename to gateway/src/main/java/ru/practicum/shareit/item/dto/ShortItemDto.java diff --git a/src/main/java/ru/practicum/shareit/item/dto/UpdateItemDto.java b/gateway/src/main/java/ru/practicum/shareit/item/dto/UpdateItemDto.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/dto/UpdateItemDto.java rename to gateway/src/main/java/ru/practicum/shareit/item/dto/UpdateItemDto.java diff --git a/gateway/src/main/java/ru/practicum/shareit/request/RequestClient.java b/gateway/src/main/java/ru/practicum/shareit/request/RequestClient.java new file mode 100644 index 0000000..2245347 --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/request/RequestClient.java @@ -0,0 +1,42 @@ +package ru.practicum.shareit.request; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.stereotype.Service; +import org.springframework.web.util.DefaultUriBuilderFactory; +import ru.practicum.shareit.client.BaseClient; +import ru.practicum.shareit.request.dto.ItemRequestDto; + +@Service +public class RequestClient extends BaseClient { + private static final String API_PREFIX = "/requests"; + + @Autowired + public RequestClient(@Value("${shareit-server.url}") String serverUrl, RestTemplateBuilder builder) { + super( + builder + .uriTemplateHandler(new DefaultUriBuilderFactory(serverUrl + API_PREFIX)) + .requestFactory(() -> new HttpComponentsClientHttpRequestFactory()) + .build() + ); + } + + public ResponseEntity createRequest(Long userId, ItemRequestDto requestDto) { + return post("", userId, requestDto); + } + + public ResponseEntity getRequestsByUser(Long userId) { + return get("", userId); + } + + public ResponseEntity getAllRequests(Long userId) { + return get("/all", userId); + } + + public ResponseEntity getRequestById(Long userId, Long requestId) { + return get("/" + requestId, userId); + } +} diff --git a/gateway/src/main/java/ru/practicum/shareit/request/RequestController.java b/gateway/src/main/java/ru/practicum/shareit/request/RequestController.java new file mode 100644 index 0000000..d707e49 --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/request/RequestController.java @@ -0,0 +1,47 @@ +package ru.practicum.shareit.request; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.Positive; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import ru.practicum.shareit.request.dto.ItemRequestDto; + +import static ru.practicum.shareit.util.Constants.USER_ID_HEADER; + +@RestController +@RequestMapping(path = "/requests") +@AllArgsConstructor +@Slf4j +@Validated +public class RequestController { + private final RequestClient requestClient; + + @PostMapping + public ResponseEntity createRequest(@RequestHeader(USER_ID_HEADER) Long userId, + @RequestBody @Valid ItemRequestDto request) { + log.info("Создать запрос на вещь {} от пользователя userId={}", request, userId); + return requestClient.createRequest(userId, request); + } + + @GetMapping + public ResponseEntity getRequestByUser(@RequestHeader(USER_ID_HEADER) Long userId) { + log.info("Получить запросы от пользователя userId={}", userId); + return requestClient.getRequestsByUser(userId); + } + + @GetMapping("/all") + public ResponseEntity getAllRequests(@RequestHeader(USER_ID_HEADER) Long userId) { + log.info("Получить все запросы, пользователь userId={}", userId); + return requestClient.getAllRequests(userId); + } + + @GetMapping("/{requestId}") + public ResponseEntity getRequestById(@RequestHeader(USER_ID_HEADER) Long userId, + @Positive @PathVariable Long requestId) { + log.info("Получить запрос на вещь requestId={} от пользователя userId={}", requestId, userId); + return requestClient.getRequestById(userId, requestId); + } +} diff --git a/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java b/gateway/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java similarity index 100% rename from src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java rename to gateway/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java diff --git a/gateway/src/main/java/ru/practicum/shareit/user/UserClient.java b/gateway/src/main/java/ru/practicum/shareit/user/UserClient.java new file mode 100644 index 0000000..63d296f --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/user/UserClient.java @@ -0,0 +1,47 @@ +package ru.practicum.shareit.user; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.stereotype.Service; +import org.springframework.web.util.DefaultUriBuilderFactory; +import ru.practicum.shareit.client.BaseClient; +import ru.practicum.shareit.user.dto.UpdateUserDto; +import ru.practicum.shareit.user.dto.UserDto; + +@Service +public class UserClient extends BaseClient { + private static final String API_PREFIX = "/users"; + + @Autowired + public UserClient(@Value("${shareit-server.url}") String serverUrl, RestTemplateBuilder builder) { + super( + builder + .uriTemplateHandler(new DefaultUriBuilderFactory(serverUrl + API_PREFIX)) + .requestFactory(() -> new HttpComponentsClientHttpRequestFactory()) + .build() + ); + } + + public ResponseEntity getAllUsers() { + return get(""); + } + + public ResponseEntity getUserById(Long userId) { + return get("/" + userId); + } + + public ResponseEntity createUser(UserDto userDto) { + return post("", userDto); + } + + public ResponseEntity updateUser(Long userId, UpdateUserDto userDto) { + return patch("/" + userId, userDto); + } + + public ResponseEntity deleteUser(Long userId) { + return delete("/" + userId); + } +} diff --git a/gateway/src/main/java/ru/practicum/shareit/user/UserController.java b/gateway/src/main/java/ru/practicum/shareit/user/UserController.java new file mode 100644 index 0000000..065cfeb --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/user/UserController.java @@ -0,0 +1,53 @@ +package ru.practicum.shareit.user; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.Positive; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import ru.practicum.shareit.user.dto.UpdateUserDto; +import ru.practicum.shareit.user.dto.UserDto; + +@RestController +@RequestMapping(path = "/users") +@RequiredArgsConstructor +@Slf4j +@Validated +public class UserController { + private final UserClient userClient; + + @GetMapping + public ResponseEntity getAllUsers() { + log.info("Запрошены все пользователи"); + return userClient.getAllUsers(); + } + + @GetMapping("/{userId}") + public ResponseEntity getUserById(@PathVariable @Positive Long userId) { + log.info("Запрошен пользователь с ID: " + userId); + return userClient.getUserById(userId); + } + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public ResponseEntity createUser(@RequestBody @Valid UserDto user) { + log.info("Запрос на создание пользователя user={}", user); + return userClient.createUser(user); + } + + @PatchMapping("/{userId}") + public ResponseEntity updateUser(@RequestBody @Valid UpdateUserDto user, + @PathVariable Long userId) { + log.info("Обновить пользователя userId={}, данные - {}", userId, user); + return userClient.updateUser(userId, user); + } + + @DeleteMapping("/{userId}") + public ResponseEntity deleteUser(@PathVariable @Positive Long userId) { + log.info("Удалить пользователя userId={}", userId); + return userClient.deleteUser(userId); + } +} diff --git a/src/main/java/ru/practicum/shareit/user/dto/ShortUserDto.java b/gateway/src/main/java/ru/practicum/shareit/user/dto/ShortUserDto.java similarity index 100% rename from src/main/java/ru/practicum/shareit/user/dto/ShortUserDto.java rename to gateway/src/main/java/ru/practicum/shareit/user/dto/ShortUserDto.java diff --git a/src/main/java/ru/practicum/shareit/user/dto/UpdateUserDto.java b/gateway/src/main/java/ru/practicum/shareit/user/dto/UpdateUserDto.java similarity index 100% rename from src/main/java/ru/practicum/shareit/user/dto/UpdateUserDto.java rename to gateway/src/main/java/ru/practicum/shareit/user/dto/UpdateUserDto.java diff --git a/src/main/java/ru/practicum/shareit/user/dto/UserDto.java b/gateway/src/main/java/ru/practicum/shareit/user/dto/UserDto.java similarity index 100% rename from src/main/java/ru/practicum/shareit/user/dto/UserDto.java rename to gateway/src/main/java/ru/practicum/shareit/user/dto/UserDto.java diff --git a/src/main/java/ru/practicum/shareit/util/Constants.java b/gateway/src/main/java/ru/practicum/shareit/util/Constants.java similarity index 98% rename from src/main/java/ru/practicum/shareit/util/Constants.java rename to gateway/src/main/java/ru/practicum/shareit/util/Constants.java index 5e4ed49..6a036d8 100644 --- a/src/main/java/ru/practicum/shareit/util/Constants.java +++ b/gateway/src/main/java/ru/practicum/shareit/util/Constants.java @@ -1,7 +1,5 @@ package ru.practicum.shareit.util; public class Constants { - public static final String USER_ID_HEADER = "X-Sharer-User-Id"; - } diff --git a/gateway/src/main/resources/application.properties b/gateway/src/main/resources/application.properties new file mode 100644 index 0000000..2ee0851 --- /dev/null +++ b/gateway/src/main/resources/application.properties @@ -0,0 +1,7 @@ +logging.level.org.springframework.web.client.RestTemplate=DEBUG +#logging.level.org.apache.http=DEBUG +#logging.level.httpclient.wire=DEBUG + +server.port=8080 + +shareit-server.url=http://localhost:9090 \ No newline at end of file diff --git a/pom.xml b/pom.xml index 10fe1c2..79cba37 100644 --- a/pom.xml +++ b/pom.xml @@ -11,6 +11,7 @@ ru.practicum shareit + pom 0.0.1-SNAPSHOT ShareIt @@ -19,103 +20,29 @@ 21 - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-actuator - - - org.springframework.boot - spring-boot-configuration-processor - true - - - - org.springframework.boot - spring-boot-starter-data-jpa - - - - org.postgresql - postgresql - runtime - - - - org.projectlombok - lombok - true - - - - com.h2database - h2 - test - - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.boot - spring-boot-starter-validation - - + + gateway + server + - - - src/main/resources - true - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - - - - org.apache.maven.plugins - maven-checkstyle-plugin - 3.1.2 - - checkstyle.xml - true - true - true - - - - - check - - compile - - - - - com.puppycrawl.tools - checkstyle - 10.3 - - - - + + org.springframework.boot + spring-boot-maven-plugin + + + true + + + + org.projectlombok + lombok + + + + org.apache.maven.plugins maven-surefire-plugin @@ -262,17 +189,5 @@ - - coverage - - - - org.jacoco - jacoco-maven-plugin - - - - - - + \ No newline at end of file diff --git a/server/Dockerfile b/server/Dockerfile new file mode 100644 index 0000000..0ff1817 --- /dev/null +++ b/server/Dockerfile @@ -0,0 +1,5 @@ +FROM eclipse-temurin:21-jre-jammy +VOLUME /tmp +ARG JAR_FILE=target/*.jar +COPY ${JAR_FILE} app.jar +ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"] \ No newline at end of file diff --git a/server/pom.xml b/server/pom.xml new file mode 100644 index 0000000..f496531 --- /dev/null +++ b/server/pom.xml @@ -0,0 +1,90 @@ + + + 4.0.0 + + ru.practicum + shareit + 0.0.1-SNAPSHOT + + + shareit-server + 0.0.1-SNAPSHOT + + ShareIt Server + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-actuator + + + + 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 + + + jakarta.validation + jakarta.validation-api + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + coverage + + + + org.jacoco + jacoco-maven-plugin + + + + + + + diff --git a/src/main/java/ru/practicum/shareit/ShareItApp.java b/server/src/main/java/ru/practicum/shareit/ShareItServer.java similarity index 56% rename from src/main/java/ru/practicum/shareit/ShareItApp.java rename to server/src/main/java/ru/practicum/shareit/ShareItServer.java index 92c71dc..e814eb2 100644 --- a/src/main/java/ru/practicum/shareit/ShareItApp.java +++ b/server/src/main/java/ru/practicum/shareit/ShareItServer.java @@ -4,9 +4,10 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication -public class ShareItApp { +public class ShareItServer { + + public static void main(String[] args) { + SpringApplication.run(ShareItServer.class, args); + } - public static void main(String[] args) { - SpringApplication.run(ShareItApp.class, args); - } } diff --git a/src/main/java/ru/practicum/shareit/booking/BookingController.java b/server/src/main/java/ru/practicum/shareit/booking/BookingController.java similarity index 85% rename from src/main/java/ru/practicum/shareit/booking/BookingController.java rename to server/src/main/java/ru/practicum/shareit/booking/BookingController.java index b4de626..75cfcd4 100644 --- a/src/main/java/ru/practicum/shareit/booking/BookingController.java +++ b/server/src/main/java/ru/practicum/shareit/booking/BookingController.java @@ -39,13 +39,15 @@ public BookingDto getById(@RequestHeader(USER_ID_HEADER) Long userId, @GetMapping public Collection getAllByBooker(@RequestHeader(USER_ID_HEADER) Long userId, @RequestParam(defaultValue = "ALL") String state) { - return bookingService.getAllByBooker(userId, state); + BookingState bookingState = BookingState.valueOf(state.toUpperCase()); + return bookingService.getAllByBooker(userId, bookingState); } @GetMapping("/owner") public Collection getAllByOwner(@RequestHeader(USER_ID_HEADER) Long userId, @RequestParam(defaultValue = "ALL") String state) { - return bookingService.getAllByOwner(userId, state); + BookingState bookingState = BookingState.valueOf(state.toUpperCase()); + return bookingService.getAllByOwner(userId, bookingState); } } diff --git a/server/src/main/java/ru/practicum/shareit/booking/BookingState.java b/server/src/main/java/ru/practicum/shareit/booking/BookingState.java new file mode 100644 index 0000000..726d2ed --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/booking/BookingState.java @@ -0,0 +1,19 @@ +package ru.practicum.shareit.booking; + +import lombok.Getter; + +@Getter +public enum BookingState { + ALL("ALL"), + CURRENT("CURRENT"), + PAST("PAST"), + FUTURE("FUTURE"), + WAITING("WAITING"), + REJECTED("REJECTED"); + + private final String value; + + BookingState(String value) { + this.value = value; + } +} diff --git a/server/src/main/java/ru/practicum/shareit/booking/BookingStatus.java b/server/src/main/java/ru/practicum/shareit/booking/BookingStatus.java new file mode 100644 index 0000000..51269e0 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/booking/BookingStatus.java @@ -0,0 +1,8 @@ +package ru.practicum.shareit.booking; + +public enum BookingStatus { + WAITING, + APPROVED, + REJECTED, + CANCELED +} diff --git a/server/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java b/server/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java new file mode 100644 index 0000000..5f8db58 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java @@ -0,0 +1,23 @@ +package ru.practicum.shareit.booking.dto; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Data; +import lombok.experimental.FieldDefaults; +import ru.practicum.shareit.booking.BookingStatus; +import ru.practicum.shareit.item.dto.ShortItemDto; +import ru.practicum.shareit.user.dto.ShortUserDto; + +import java.time.LocalDateTime; + +@Data +@Builder +@FieldDefaults(level = AccessLevel.PRIVATE) +public class BookingDto { + Long id; + LocalDateTime start; + LocalDateTime end; + ShortItemDto item; + ShortUserDto booker; + BookingStatus status; +} diff --git a/server/src/main/java/ru/practicum/shareit/booking/dto/RequestBookingDto.java b/server/src/main/java/ru/practicum/shareit/booking/dto/RequestBookingDto.java new file mode 100644 index 0000000..73235c8 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/booking/dto/RequestBookingDto.java @@ -0,0 +1,17 @@ +package ru.practicum.shareit.booking.dto; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Data; +import lombok.experimental.FieldDefaults; + +import java.time.LocalDateTime; + +@Data +@Builder +@FieldDefaults(level = AccessLevel.PRIVATE) +public class RequestBookingDto { + Long itemId; + LocalDateTime start; + LocalDateTime end; +} diff --git a/server/src/main/java/ru/practicum/shareit/booking/dto/ShortBookingDto.java b/server/src/main/java/ru/practicum/shareit/booking/dto/ShortBookingDto.java new file mode 100644 index 0000000..c06ab30 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/booking/dto/ShortBookingDto.java @@ -0,0 +1,16 @@ +package ru.practicum.shareit.booking.dto; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Data; +import lombok.experimental.FieldDefaults; + +import java.time.LocalDateTime; + +@Data +@Builder +@FieldDefaults(level = AccessLevel.PRIVATE) +public class ShortBookingDto { + LocalDateTime start; + LocalDateTime end; +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/booking/mapper/BookingMapper.java b/server/src/main/java/ru/practicum/shareit/booking/mapper/BookingMapper.java similarity index 100% rename from src/main/java/ru/practicum/shareit/booking/mapper/BookingMapper.java rename to server/src/main/java/ru/practicum/shareit/booking/mapper/BookingMapper.java diff --git a/src/main/java/ru/practicum/shareit/booking/model/Booking.java b/server/src/main/java/ru/practicum/shareit/booking/model/Booking.java similarity index 100% rename from src/main/java/ru/practicum/shareit/booking/model/Booking.java rename to server/src/main/java/ru/practicum/shareit/booking/model/Booking.java diff --git a/src/main/java/ru/practicum/shareit/booking/repository/BookingRepository.java b/server/src/main/java/ru/practicum/shareit/booking/repository/BookingRepository.java similarity index 100% rename from src/main/java/ru/practicum/shareit/booking/repository/BookingRepository.java rename to server/src/main/java/ru/practicum/shareit/booking/repository/BookingRepository.java diff --git a/src/main/java/ru/practicum/shareit/booking/service/BookingService.java b/server/src/main/java/ru/practicum/shareit/booking/service/BookingService.java similarity index 67% rename from src/main/java/ru/practicum/shareit/booking/service/BookingService.java rename to server/src/main/java/ru/practicum/shareit/booking/service/BookingService.java index 3c05348..aa1a6a6 100644 --- a/src/main/java/ru/practicum/shareit/booking/service/BookingService.java +++ b/server/src/main/java/ru/practicum/shareit/booking/service/BookingService.java @@ -1,5 +1,6 @@ package ru.practicum.shareit.booking.service; +import ru.practicum.shareit.booking.BookingState; import ru.practicum.shareit.booking.dto.BookingDto; import ru.practicum.shareit.booking.dto.RequestBookingDto; @@ -13,7 +14,7 @@ public interface BookingService { BookingDto getById(Long userId, Long bookingId); - Collection getAllByBooker(Long userId, String state); + Collection getAllByBooker(Long userId, BookingState state); - Collection getAllByOwner(Long userId, String state); + Collection getAllByOwner(Long userId, BookingState state); } diff --git a/src/main/java/ru/practicum/shareit/booking/service/BookingServiceImpl.java b/server/src/main/java/ru/practicum/shareit/booking/service/BookingServiceImpl.java similarity index 93% rename from src/main/java/ru/practicum/shareit/booking/service/BookingServiceImpl.java rename to server/src/main/java/ru/practicum/shareit/booking/service/BookingServiceImpl.java index d588846..101656a 100644 --- a/src/main/java/ru/practicum/shareit/booking/service/BookingServiceImpl.java +++ b/server/src/main/java/ru/practicum/shareit/booking/service/BookingServiceImpl.java @@ -74,10 +74,9 @@ public BookingDto getById(Long userId, Long bookingId) { } @Override - public Collection getAllByBooker(Long userId, String state) { + public Collection getAllByBooker(Long userId, BookingState state) { throwIfUserNotExist(userId); - BookingState bookingState = BookingState.from(state); - Collection bookings = switch (bookingState) { + Collection bookings = switch (state) { case ALL -> bookingRepository.findAllByBookerIdOrderByStartDesc(userId); case WAITING -> bookingRepository .findAllByBookerIdAndStatusOrderByStartDesc(userId, BookingStatus.WAITING); @@ -95,10 +94,9 @@ public Collection getAllByBooker(Long userId, String state) { } @Override - public Collection getAllByOwner(Long userId, String state) { + public Collection getAllByOwner(Long userId, BookingState state) { throwIfUserNotExist(userId); - BookingState bookingState = BookingState.from(state); - Collection bookings = switch (bookingState) { + Collection bookings = switch (state) { case ALL -> bookingRepository.findAllByItemOwnerIdOrderByStartDesc(userId); case WAITING -> bookingRepository .findAllByItemOwnerIdAndStatusOrderByStartDesc(userId, BookingStatus.WAITING); diff --git a/src/main/java/ru/practicum/shareit/exception/DuplicateValidationException.java b/server/src/main/java/ru/practicum/shareit/exception/DuplicateValidationException.java similarity index 100% rename from src/main/java/ru/practicum/shareit/exception/DuplicateValidationException.java rename to server/src/main/java/ru/practicum/shareit/exception/DuplicateValidationException.java diff --git a/src/main/java/ru/practicum/shareit/exception/ExceptionsHandler.java b/server/src/main/java/ru/practicum/shareit/exception/ExceptionsHandler.java similarity index 100% rename from src/main/java/ru/practicum/shareit/exception/ExceptionsHandler.java rename to server/src/main/java/ru/practicum/shareit/exception/ExceptionsHandler.java diff --git a/src/main/java/ru/practicum/shareit/exception/ForbiddenException.java b/server/src/main/java/ru/practicum/shareit/exception/ForbiddenException.java similarity index 100% rename from src/main/java/ru/practicum/shareit/exception/ForbiddenException.java rename to server/src/main/java/ru/practicum/shareit/exception/ForbiddenException.java diff --git a/src/main/java/ru/practicum/shareit/exception/NotFoundException.java b/server/src/main/java/ru/practicum/shareit/exception/NotFoundException.java similarity index 100% rename from src/main/java/ru/practicum/shareit/exception/NotFoundException.java rename to server/src/main/java/ru/practicum/shareit/exception/NotFoundException.java diff --git a/src/main/java/ru/practicum/shareit/exception/ValidationException.java b/server/src/main/java/ru/practicum/shareit/exception/ValidationException.java similarity index 100% rename from src/main/java/ru/practicum/shareit/exception/ValidationException.java rename to server/src/main/java/ru/practicum/shareit/exception/ValidationException.java diff --git a/src/main/java/ru/practicum/shareit/item/ItemController.java b/server/src/main/java/ru/practicum/shareit/item/ItemController.java similarity index 80% rename from src/main/java/ru/practicum/shareit/item/ItemController.java rename to server/src/main/java/ru/practicum/shareit/item/ItemController.java index 8b17d01..284c50b 100644 --- a/src/main/java/ru/practicum/shareit/item/ItemController.java +++ b/server/src/main/java/ru/practicum/shareit/item/ItemController.java @@ -1,7 +1,5 @@ package ru.practicum.shareit.item; -import jakarta.validation.Valid; -import jakarta.validation.constraints.Positive; import lombok.AllArgsConstructor; import org.springframework.web.bind.annotation.*; import ru.practicum.shareit.item.dto.CommentDto; @@ -34,14 +32,14 @@ public ItemDtoWithBookingsAndComments getById(@RequestHeader(USER_ID_HEADER) Lon @PostMapping public ItemDto create(@RequestHeader(USER_ID_HEADER) Long userId, - @RequestBody @Valid ItemDto item) { + @RequestBody ItemDto item) { return itemService.create(userId, item); } @PatchMapping("/{itemId}") public ItemDto update(@RequestHeader(USER_ID_HEADER) Long userId, - @PathVariable @Positive Long itemId, - @RequestBody @Valid UpdateItemDto item) { + @PathVariable Long itemId, + @RequestBody UpdateItemDto item) { return itemService.update(userId, itemId, item); } @@ -52,8 +50,8 @@ public Collection search(@RequestParam(name = "text") String text) { @PostMapping("{itemId}/comment") public CommentDto addComment(@RequestHeader(USER_ID_HEADER) Long authorId, - @PathVariable @Positive Long itemId, - @RequestBody @Valid CommentDto commentRequest) { + @PathVariable Long itemId, + @RequestBody CommentDto commentRequest) { return itemService.addComment(authorId, itemId, commentRequest); } diff --git a/server/src/main/java/ru/practicum/shareit/item/dto/CommentDto.java b/server/src/main/java/ru/practicum/shareit/item/dto/CommentDto.java new file mode 100644 index 0000000..bf4ef80 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/item/dto/CommentDto.java @@ -0,0 +1,19 @@ +package ru.practicum.shareit.item.dto; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Data; +import lombok.experimental.FieldDefaults; + +import java.time.LocalDateTime; + +@Data +@Builder +@FieldDefaults(level = AccessLevel.PRIVATE) +public class CommentDto { + Long id; + String text; + String authorName; + LocalDateTime created; +} + diff --git a/server/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java b/server/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java new file mode 100644 index 0000000..9587554 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java @@ -0,0 +1,20 @@ +package ru.practicum.shareit.item.dto; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Data; +import lombok.experimental.FieldDefaults; + +import java.util.Collection; + +@Data +@Builder +@FieldDefaults(level = AccessLevel.PRIVATE) +public class ItemDto { + Long id; + String name; + String description; + Boolean available; + Long requestId; + Collection comments; +} diff --git a/server/src/main/java/ru/practicum/shareit/item/dto/ItemDtoWithBookingsAndComments.java b/server/src/main/java/ru/practicum/shareit/item/dto/ItemDtoWithBookingsAndComments.java new file mode 100644 index 0000000..4cfa99f --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/item/dto/ItemDtoWithBookingsAndComments.java @@ -0,0 +1,23 @@ +package ru.practicum.shareit.item.dto; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Data; +import lombok.experimental.FieldDefaults; +import ru.practicum.shareit.booking.dto.ShortBookingDto; + +import java.util.Collection; + +@Data +@Builder +@FieldDefaults(level = AccessLevel.PRIVATE) +public class ItemDtoWithBookingsAndComments { + Long id; + String name; + String description; + Boolean available; + Long requestId; + ShortBookingDto lastBooking; + ShortBookingDto nextBooking; + Collection comments; +} diff --git a/server/src/main/java/ru/practicum/shareit/item/dto/ShortItemDto.java b/server/src/main/java/ru/practicum/shareit/item/dto/ShortItemDto.java new file mode 100644 index 0000000..6eea332 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/item/dto/ShortItemDto.java @@ -0,0 +1,15 @@ +package ru.practicum.shareit.item.dto; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Data; +import lombok.experimental.FieldDefaults; + +@Data +@Builder +@FieldDefaults(level = AccessLevel.PRIVATE) +public class ShortItemDto { + Long id; + String name; + Long ownerId; +} diff --git a/server/src/main/java/ru/practicum/shareit/item/dto/UpdateItemDto.java b/server/src/main/java/ru/practicum/shareit/item/dto/UpdateItemDto.java new file mode 100644 index 0000000..2f816a1 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/item/dto/UpdateItemDto.java @@ -0,0 +1,13 @@ +package ru.practicum.shareit.item.dto; + +import lombok.AccessLevel; +import lombok.Data; +import lombok.experimental.FieldDefaults; + +@Data +@FieldDefaults(level = AccessLevel.PRIVATE) +public class UpdateItemDto { + String name; + String description; + Boolean available; +} diff --git a/src/main/java/ru/practicum/shareit/item/mapper/CommentMapper.java b/server/src/main/java/ru/practicum/shareit/item/mapper/CommentMapper.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/mapper/CommentMapper.java rename to server/src/main/java/ru/practicum/shareit/item/mapper/CommentMapper.java diff --git a/src/main/java/ru/practicum/shareit/item/mapper/ItemMapper.java b/server/src/main/java/ru/practicum/shareit/item/mapper/ItemMapper.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/mapper/ItemMapper.java rename to server/src/main/java/ru/practicum/shareit/item/mapper/ItemMapper.java diff --git a/src/main/java/ru/practicum/shareit/item/model/Comment.java b/server/src/main/java/ru/practicum/shareit/item/model/Comment.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/model/Comment.java rename to server/src/main/java/ru/practicum/shareit/item/model/Comment.java diff --git a/src/main/java/ru/practicum/shareit/item/model/Item.java b/server/src/main/java/ru/practicum/shareit/item/model/Item.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/model/Item.java rename to server/src/main/java/ru/practicum/shareit/item/model/Item.java diff --git a/src/main/java/ru/practicum/shareit/item/repository/CommentRepository.java b/server/src/main/java/ru/practicum/shareit/item/repository/CommentRepository.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/repository/CommentRepository.java rename to server/src/main/java/ru/practicum/shareit/item/repository/CommentRepository.java diff --git a/src/main/java/ru/practicum/shareit/item/repository/ItemRepository.java b/server/src/main/java/ru/practicum/shareit/item/repository/ItemRepository.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/repository/ItemRepository.java rename to server/src/main/java/ru/practicum/shareit/item/repository/ItemRepository.java diff --git a/src/main/java/ru/practicum/shareit/item/service/ItemService.java b/server/src/main/java/ru/practicum/shareit/item/service/ItemService.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/service/ItemService.java rename to server/src/main/java/ru/practicum/shareit/item/service/ItemService.java diff --git a/src/main/java/ru/practicum/shareit/item/service/ItemServiceImpl.java b/server/src/main/java/ru/practicum/shareit/item/service/ItemServiceImpl.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/service/ItemServiceImpl.java rename to server/src/main/java/ru/practicum/shareit/item/service/ItemServiceImpl.java diff --git a/src/main/java/ru/practicum/shareit/request/ItemRequestController.java b/server/src/main/java/ru/practicum/shareit/request/ItemRequestController.java similarity index 92% rename from src/main/java/ru/practicum/shareit/request/ItemRequestController.java rename to server/src/main/java/ru/practicum/shareit/request/ItemRequestController.java index bb116b8..6f9cd91 100644 --- a/src/main/java/ru/practicum/shareit/request/ItemRequestController.java +++ b/server/src/main/java/ru/practicum/shareit/request/ItemRequestController.java @@ -1,6 +1,5 @@ package ru.practicum.shareit.request; -import jakarta.validation.Valid; import lombok.AllArgsConstructor; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; @@ -21,7 +20,7 @@ public class ItemRequestController { @PostMapping @Transactional public ItemRequestDto create(@RequestHeader(USER_ID_HEADER) Long userId, - @RequestBody @Valid ItemRequestDto request) { + @RequestBody ItemRequestDto request) { return itemRequestService.create(userId, request); } @@ -40,7 +39,5 @@ public ItemRequestDto getById(@RequestHeader(USER_ID_HEADER) Long userId, @PathVariable Long requestId) { return itemRequestService.getById(userId, requestId); } - - } diff --git a/server/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java b/server/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java new file mode 100644 index 0000000..067cf79 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java @@ -0,0 +1,21 @@ +package ru.practicum.shareit.request.dto; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Data; +import lombok.experimental.FieldDefaults; +import ru.practicum.shareit.item.dto.ShortItemDto; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +@FieldDefaults(level = AccessLevel.PRIVATE) +public class ItemRequestDto { + Long id; + String description; + Long requesterId; + LocalDateTime created; + List items; +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/request/mapper/ItemRequestMapper.java b/server/src/main/java/ru/practicum/shareit/request/mapper/ItemRequestMapper.java similarity index 100% rename from src/main/java/ru/practicum/shareit/request/mapper/ItemRequestMapper.java rename to server/src/main/java/ru/practicum/shareit/request/mapper/ItemRequestMapper.java diff --git a/src/main/java/ru/practicum/shareit/request/model/ItemRequest.java b/server/src/main/java/ru/practicum/shareit/request/model/ItemRequest.java similarity index 100% rename from src/main/java/ru/practicum/shareit/request/model/ItemRequest.java rename to server/src/main/java/ru/practicum/shareit/request/model/ItemRequest.java diff --git a/src/main/java/ru/practicum/shareit/request/repository/ItemRequestRepository.java b/server/src/main/java/ru/practicum/shareit/request/repository/ItemRequestRepository.java similarity index 100% rename from src/main/java/ru/practicum/shareit/request/repository/ItemRequestRepository.java rename to server/src/main/java/ru/practicum/shareit/request/repository/ItemRequestRepository.java diff --git a/src/main/java/ru/practicum/shareit/request/service/ItemRequestService.java b/server/src/main/java/ru/practicum/shareit/request/service/ItemRequestService.java similarity index 100% rename from src/main/java/ru/practicum/shareit/request/service/ItemRequestService.java rename to server/src/main/java/ru/practicum/shareit/request/service/ItemRequestService.java diff --git a/src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java b/server/src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java similarity index 100% rename from src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java rename to server/src/main/java/ru/practicum/shareit/request/service/ItemRequestServiceImpl.java diff --git a/src/main/java/ru/practicum/shareit/user/UserController.java b/server/src/main/java/ru/practicum/shareit/user/UserController.java similarity index 75% rename from src/main/java/ru/practicum/shareit/user/UserController.java rename to server/src/main/java/ru/practicum/shareit/user/UserController.java index 674b18f..40042a5 100644 --- a/src/main/java/ru/practicum/shareit/user/UserController.java +++ b/server/src/main/java/ru/practicum/shareit/user/UserController.java @@ -1,7 +1,5 @@ package ru.practicum.shareit.user; -import jakarta.validation.Valid; -import jakarta.validation.constraints.Positive; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; @@ -27,28 +25,25 @@ public Collection getAll() { } @GetMapping("/{userId}") - public UserDto getById(@PathVariable @Positive Long userId) { + public UserDto getById(@PathVariable Long userId) { log.info("Запрошен пользователь с ID: " + userId); return userService.getById(userId); } @PostMapping @ResponseStatus(HttpStatus.CREATED) - public UserDto create(@RequestBody @Valid UserDto user) { + public UserDto create(@RequestBody UserDto user) { return userService.create(user); } @PatchMapping("/{userId}") - public UserDto update(@RequestBody @Valid UpdateUserDto user, @PathVariable Long userId) { + public UserDto update(@RequestBody UpdateUserDto user, @PathVariable Long userId) { user.setId(userId); return userService.update(user); } @DeleteMapping("/{userId}") - public void update(@PathVariable @Positive Long userId) { + public void delete(@PathVariable Long userId) { userService.delete(userId); } - - - } diff --git a/server/src/main/java/ru/practicum/shareit/user/dto/ShortUserDto.java b/server/src/main/java/ru/practicum/shareit/user/dto/ShortUserDto.java new file mode 100644 index 0000000..707cacb --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/user/dto/ShortUserDto.java @@ -0,0 +1,10 @@ +package ru.practicum.shareit.user.dto; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class ShortUserDto { + private Long id; +} diff --git a/server/src/main/java/ru/practicum/shareit/user/dto/UpdateUserDto.java b/server/src/main/java/ru/practicum/shareit/user/dto/UpdateUserDto.java new file mode 100644 index 0000000..90e2626 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/user/dto/UpdateUserDto.java @@ -0,0 +1,15 @@ +package ru.practicum.shareit.user.dto; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Data; +import lombok.experimental.FieldDefaults; + +@Data +@Builder +@FieldDefaults(level = AccessLevel.PRIVATE) +public class UpdateUserDto { + Long id; + String name; + String email; +} diff --git a/server/src/main/java/ru/practicum/shareit/user/dto/UserDto.java b/server/src/main/java/ru/practicum/shareit/user/dto/UserDto.java new file mode 100644 index 0000000..7bcf078 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/user/dto/UserDto.java @@ -0,0 +1,15 @@ +package ru.practicum.shareit.user.dto; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Data; +import lombok.experimental.FieldDefaults; + +@Data +@Builder +@FieldDefaults(level = AccessLevel.PRIVATE) +public class UserDto { + Long id; + String name; + String email; +} diff --git a/src/main/java/ru/practicum/shareit/user/mapper/UserMapper.java b/server/src/main/java/ru/practicum/shareit/user/mapper/UserMapper.java similarity index 99% rename from src/main/java/ru/practicum/shareit/user/mapper/UserMapper.java rename to server/src/main/java/ru/practicum/shareit/user/mapper/UserMapper.java index 6bcc305..4c4758a 100644 --- a/src/main/java/ru/practicum/shareit/user/mapper/UserMapper.java +++ b/server/src/main/java/ru/practicum/shareit/user/mapper/UserMapper.java @@ -35,4 +35,4 @@ public User toUser(UpdateUserDto userDto) { } return updateUser; } -} +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/user/model/User.java b/server/src/main/java/ru/practicum/shareit/user/model/User.java similarity index 100% rename from src/main/java/ru/practicum/shareit/user/model/User.java rename to server/src/main/java/ru/practicum/shareit/user/model/User.java diff --git a/src/main/java/ru/practicum/shareit/user/repository/UserRepository.java b/server/src/main/java/ru/practicum/shareit/user/repository/UserRepository.java similarity index 100% rename from src/main/java/ru/practicum/shareit/user/repository/UserRepository.java rename to server/src/main/java/ru/practicum/shareit/user/repository/UserRepository.java diff --git a/src/main/java/ru/practicum/shareit/user/service/UserService.java b/server/src/main/java/ru/practicum/shareit/user/service/UserService.java similarity index 100% rename from src/main/java/ru/practicum/shareit/user/service/UserService.java rename to server/src/main/java/ru/practicum/shareit/user/service/UserService.java diff --git a/src/main/java/ru/practicum/shareit/user/service/UserServiceImpl.java b/server/src/main/java/ru/practicum/shareit/user/service/UserServiceImpl.java similarity index 100% rename from src/main/java/ru/practicum/shareit/user/service/UserServiceImpl.java rename to server/src/main/java/ru/practicum/shareit/user/service/UserServiceImpl.java diff --git a/server/src/main/java/ru/practicum/shareit/util/Constants.java b/server/src/main/java/ru/practicum/shareit/util/Constants.java new file mode 100644 index 0000000..6a036d8 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/util/Constants.java @@ -0,0 +1,5 @@ +package ru.practicum.shareit.util; + +public class Constants { + public static final String USER_ID_HEADER = "X-Sharer-User-Id"; +} diff --git a/server/src/main/resources/application.properties b/server/src/main/resources/application.properties new file mode 100644 index 0000000..6a96840 --- /dev/null +++ b/server/src/main/resources/application.properties @@ -0,0 +1,17 @@ +server.port=9090 + +spring.jpa.hibernate.ddl-auto=none +spring.jpa.properties.hibernate.format_sql=true +spring.sql.init.mode=always + +#--- +spring.datasource.driverClassName=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/shareit +spring.datasource.username=shareit +spring.datasource.password=shareit +#--- +spring.config.activate.on-profile=test +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.url=jdbc:h2:mem:shareit +spring.datasource.username=shareit +spring.datasource.password=shareit \ No newline at end of file diff --git a/src/main/resources/schema.sql b/server/src/main/resources/schema.sql similarity index 100% rename from src/main/resources/schema.sql rename to server/src/main/resources/schema.sql diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties deleted file mode 100644 index a7145cc..0000000 --- a/src/main/resources/application-test.properties +++ /dev/null @@ -1,12 +0,0 @@ -spring.jpa.hibernate.ddl-auto=none -spring.jpa.properties.hibernate.format_sql=true -spring.sql.init.mode=always -logging.level.org.springframework.orm.jpa=INFO -logging.level.org.springframework.transaction=INFO -logging.level.org.springframework.transaction.interceptor=TRACE -logging.level.org.springframework.orm.jpa.JpaTransactionManager=DEBUG - -spring.datasource.url=jdbc:h2:mem:./db/shareit -spring.datasource.driverClassName=org.h2.Driver -spring.datasource.username=sa -spring.datasource.password=password diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties deleted file mode 100644 index 9f62b8c..0000000 --- a/src/main/resources/application.properties +++ /dev/null @@ -1,14 +0,0 @@ -spring.jpa.hibernate.ddl-auto=none -spring.jpa.properties.hibernate.format_sql=true -spring.jpa.show-sql=true -spring.sql.init.mode=always - -logging.level.org.springframework.orm.jpa=INFO -logging.level.org.springframework.transaction=INFO -logging.level.org.springframework.transaction.interceptor=TRACE -logging.level.org.springframework.orm.jpa.JpaTransactionManager=DEBUG - -spring.datasource.driverClassName=org.postgresql.Driver -spring.datasource.url=jdbc:postgresql://localhost:5432/shareit -spring.datasource.username=sa -spring.datasource.password=password \ No newline at end of file diff --git a/src/test/java/ru/practicum/shareit/ShareItTests.java b/src/test/java/ru/practicum/shareit/ShareItTests.java deleted file mode 100644 index 4d79052..0000000 --- a/src/test/java/ru/practicum/shareit/ShareItTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package ru.practicum.shareit; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class ShareItTests { - - @Test - void contextLoads() { - } - -} From 5ae44e9263fbd7772b70185bd6a37401ce3fd0ee Mon Sep 17 00:00:00 2001 From: Egor Ilyin Date: Sat, 6 Dec 2025 17:37:10 +0300 Subject: [PATCH 3/7] add time zone to docker conteiners --- docker-compose.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docker-compose.yaml b/docker-compose.yaml index abe6570..92d83b3 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -9,6 +9,7 @@ services: - server environment: - SHAREIT_SERVER_URL=http://server:9090 + - TZ=Europe/Moscow server: build: server @@ -22,6 +23,7 @@ services: - SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/shareit - SPRING_DATASOURCE_USERNAME=shareit - SPRING_DATASOURCE_PASSWORD=shareit + - TZ=Europe/Moscow db: image: postgres:16.1 @@ -32,6 +34,7 @@ services: - POSTGRES_PASSWORD=shareit - POSTGRES_USER=shareit - POSTGRES_DB=shareit + - TZ=Europe/Moscow healthcheck: test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER timeout: 5s From 79c965000b62cc5218b8efb03f677fd396e7d2af Mon Sep 17 00:00:00 2001 From: Egor Ilyin Date: Mon, 8 Dec 2025 21:21:13 +0300 Subject: [PATCH 4/7] Add tests --- .../shareit/booking/BookingController.java | 2 + .../shareit/booking/dto/BookingDto.java | 2 + .../booking/dto/RequestBookingDto.java | 5 +- .../shareit/item/ItemController.java | 2 + .../shareit/item/dto/CommentDto.java | 2 + .../practicum/shareit/item/dto/ItemDto.java | 2 + .../dto/ItemDtoWithBookingsAndComments.java | 2 + .../shareit/item/dto/UpdateItemDto.java | 2 + .../request/ItemRequestController.java | 2 + .../shareit/request/dto/ItemRequestDto.java | 1 + .../shareit/user/dto/ShortUserDto.java | 4 + .../booking/BookingControllerTest.java | 114 ++++++ .../shareit/booking/BookingMapperTest.java | 89 +++++ .../booking/BookingServiceImplTest.java | 293 +++++++++++++++ .../shareit/booking/dto/BookingDtoTest.java | 78 ++++ .../booking/dto/RequestBookingDtoTest.java | 53 +++ .../booking/dto/ShortBookingDtoTest.java | 51 +++ .../shareit/item/CommentMapperTest.java | 73 ++++ .../shareit/item/ItemControllerTest.java | 139 +++++++ .../shareit/item/ItemMapperTest.java | 187 ++++++++++ .../shareit/item/ItemServiceImplTest.java | 349 ++++++++++++++++++ .../shareit/item/dto/CommentDtoTest.java | 47 +++ .../shareit/item/dto/ItemDtoTest.java | 68 ++++ .../ItemDtoWithBookingsAndCommentsTest.java | 75 ++++ .../shareit/item/dto/ShortItemDtoTest.java | 42 +++ .../request/ItemRequestControllerTest.java | 99 +++++ .../request/ItemRequestMapperTest.java | 125 +++++++ .../request/ItemRequestServiceImplTest.java | 195 ++++++++++ .../request/dto/ItemRequestDtoTest.java | 71 ++++ .../shareit/user/UserControllerTest.java | 111 ++++++ .../shareit/user/UserMapperTest.java | 86 +++++ .../shareit/user/UserServiceImplTest.java | 173 +++++++++ .../shareit/user/dto/ShortUserDtoTest.java | 42 +++ .../shareit/user/dto/UpdateUserDtoTest.java | 51 +++ .../shareit/user/dto/UserDtoTest.java | 51 +++ 35 files changed, 2685 insertions(+), 3 deletions(-) create mode 100644 server/src/test/java/ru/practicum/shareit/booking/BookingControllerTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/booking/BookingMapperTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/booking/BookingServiceImplTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/booking/dto/BookingDtoTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/booking/dto/RequestBookingDtoTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/booking/dto/ShortBookingDtoTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/item/CommentMapperTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/item/ItemControllerTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/item/ItemMapperTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/item/ItemServiceImplTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/item/dto/CommentDtoTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/item/dto/ItemDtoTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/item/dto/ItemDtoWithBookingsAndCommentsTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/item/dto/ShortItemDtoTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/request/ItemRequestControllerTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/request/ItemRequestMapperTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/request/ItemRequestServiceImplTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/request/dto/ItemRequestDtoTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/user/UserControllerTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/user/UserMapperTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/user/UserServiceImplTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/user/dto/ShortUserDtoTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/user/dto/UpdateUserDtoTest.java create mode 100644 server/src/test/java/ru/practicum/shareit/user/dto/UserDtoTest.java diff --git a/server/src/main/java/ru/practicum/shareit/booking/BookingController.java b/server/src/main/java/ru/practicum/shareit/booking/BookingController.java index 75cfcd4..798faf0 100644 --- a/server/src/main/java/ru/practicum/shareit/booking/BookingController.java +++ b/server/src/main/java/ru/practicum/shareit/booking/BookingController.java @@ -1,6 +1,7 @@ package ru.practicum.shareit.booking; import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import ru.practicum.shareit.booking.dto.BookingDto; import ru.practicum.shareit.booking.dto.RequestBookingDto; @@ -18,6 +19,7 @@ public class BookingController { private final BookingService bookingService; @PostMapping + @ResponseStatus(HttpStatus.CREATED) public BookingDto create(@RequestHeader(USER_ID_HEADER) Long userId, @RequestBody RequestBookingDto booking) { return bookingService.create(userId, booking); diff --git a/server/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java b/server/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java index 5f8db58..c374c94 100644 --- a/server/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java +++ b/server/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java @@ -1,6 +1,7 @@ package ru.practicum.shareit.booking.dto; import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.experimental.FieldDefaults; @@ -12,6 +13,7 @@ @Data @Builder +@AllArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) public class BookingDto { Long id; diff --git a/server/src/main/java/ru/practicum/shareit/booking/dto/RequestBookingDto.java b/server/src/main/java/ru/practicum/shareit/booking/dto/RequestBookingDto.java index 73235c8..e6adb8b 100644 --- a/server/src/main/java/ru/practicum/shareit/booking/dto/RequestBookingDto.java +++ b/server/src/main/java/ru/practicum/shareit/booking/dto/RequestBookingDto.java @@ -1,14 +1,13 @@ package ru.practicum.shareit.booking.dto; -import lombok.AccessLevel; -import lombok.Builder; -import lombok.Data; +import lombok.*; import lombok.experimental.FieldDefaults; import java.time.LocalDateTime; @Data @Builder +@AllArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) public class RequestBookingDto { Long itemId; diff --git a/server/src/main/java/ru/practicum/shareit/item/ItemController.java b/server/src/main/java/ru/practicum/shareit/item/ItemController.java index 284c50b..5e9263d 100644 --- a/server/src/main/java/ru/practicum/shareit/item/ItemController.java +++ b/server/src/main/java/ru/practicum/shareit/item/ItemController.java @@ -1,6 +1,7 @@ package ru.practicum.shareit.item; import lombok.AllArgsConstructor; +import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import ru.practicum.shareit.item.dto.CommentDto; import ru.practicum.shareit.item.dto.ItemDto; @@ -31,6 +32,7 @@ public ItemDtoWithBookingsAndComments getById(@RequestHeader(USER_ID_HEADER) Lon } @PostMapping + @ResponseStatus(HttpStatus.CREATED) public ItemDto create(@RequestHeader(USER_ID_HEADER) Long userId, @RequestBody ItemDto item) { return itemService.create(userId, item); diff --git a/server/src/main/java/ru/practicum/shareit/item/dto/CommentDto.java b/server/src/main/java/ru/practicum/shareit/item/dto/CommentDto.java index bf4ef80..a30a592 100644 --- a/server/src/main/java/ru/practicum/shareit/item/dto/CommentDto.java +++ b/server/src/main/java/ru/practicum/shareit/item/dto/CommentDto.java @@ -1,6 +1,7 @@ package ru.practicum.shareit.item.dto; import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.experimental.FieldDefaults; @@ -9,6 +10,7 @@ @Data @Builder +@AllArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) public class CommentDto { Long id; diff --git a/server/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java b/server/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java index 9587554..756845d 100644 --- a/server/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java +++ b/server/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java @@ -1,6 +1,7 @@ package ru.practicum.shareit.item.dto; import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.experimental.FieldDefaults; @@ -9,6 +10,7 @@ @Data @Builder +@AllArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) public class ItemDto { Long id; diff --git a/server/src/main/java/ru/practicum/shareit/item/dto/ItemDtoWithBookingsAndComments.java b/server/src/main/java/ru/practicum/shareit/item/dto/ItemDtoWithBookingsAndComments.java index 4cfa99f..afe86b3 100644 --- a/server/src/main/java/ru/practicum/shareit/item/dto/ItemDtoWithBookingsAndComments.java +++ b/server/src/main/java/ru/practicum/shareit/item/dto/ItemDtoWithBookingsAndComments.java @@ -1,6 +1,7 @@ package ru.practicum.shareit.item.dto; import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.experimental.FieldDefaults; @@ -10,6 +11,7 @@ @Data @Builder +@AllArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) public class ItemDtoWithBookingsAndComments { Long id; diff --git a/server/src/main/java/ru/practicum/shareit/item/dto/UpdateItemDto.java b/server/src/main/java/ru/practicum/shareit/item/dto/UpdateItemDto.java index 2f816a1..80bb2f7 100644 --- a/server/src/main/java/ru/practicum/shareit/item/dto/UpdateItemDto.java +++ b/server/src/main/java/ru/practicum/shareit/item/dto/UpdateItemDto.java @@ -1,10 +1,12 @@ package ru.practicum.shareit.item.dto; import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.experimental.FieldDefaults; @Data +@AllArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) public class UpdateItemDto { String name; diff --git a/server/src/main/java/ru/practicum/shareit/request/ItemRequestController.java b/server/src/main/java/ru/practicum/shareit/request/ItemRequestController.java index 6f9cd91..f26decf 100644 --- a/server/src/main/java/ru/practicum/shareit/request/ItemRequestController.java +++ b/server/src/main/java/ru/practicum/shareit/request/ItemRequestController.java @@ -1,6 +1,7 @@ package ru.practicum.shareit.request; import lombok.AllArgsConstructor; +import org.springframework.http.HttpStatus; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; import ru.practicum.shareit.request.dto.ItemRequestDto; @@ -19,6 +20,7 @@ public class ItemRequestController { @PostMapping @Transactional + @ResponseStatus(HttpStatus.CREATED) public ItemRequestDto create(@RequestHeader(USER_ID_HEADER) Long userId, @RequestBody ItemRequestDto request) { return itemRequestService.create(userId, request); diff --git a/server/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java b/server/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java index 067cf79..ffa911f 100644 --- a/server/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java +++ b/server/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java @@ -1,6 +1,7 @@ package ru.practicum.shareit.request.dto; import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.experimental.FieldDefaults; diff --git a/server/src/main/java/ru/practicum/shareit/user/dto/ShortUserDto.java b/server/src/main/java/ru/practicum/shareit/user/dto/ShortUserDto.java index 707cacb..280e574 100644 --- a/server/src/main/java/ru/practicum/shareit/user/dto/ShortUserDto.java +++ b/server/src/main/java/ru/practicum/shareit/user/dto/ShortUserDto.java @@ -1,10 +1,14 @@ package ru.practicum.shareit.user.dto; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; @Data @Builder +@NoArgsConstructor +@AllArgsConstructor public class ShortUserDto { private Long id; } diff --git a/server/src/test/java/ru/practicum/shareit/booking/BookingControllerTest.java b/server/src/test/java/ru/practicum/shareit/booking/BookingControllerTest.java new file mode 100644 index 0000000..ab71dd5 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/booking/BookingControllerTest.java @@ -0,0 +1,114 @@ +package ru.practicum.shareit.booking; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import ru.practicum.shareit.booking.dto.BookingDto; +import ru.practicum.shareit.booking.dto.RequestBookingDto; +import ru.practicum.shareit.booking.service.BookingService; + +import java.time.LocalDateTime; +import java.util.List; + +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static ru.practicum.shareit.util.Constants.USER_ID_HEADER; + +@WebMvcTest(BookingController.class) +@RequiredArgsConstructor(onConstructor_ = @Autowired) +public class BookingControllerTest { + + @Autowired + private MockMvc mockMvc; + @Autowired + private ObjectMapper objectMapper; + @MockBean + private BookingService bookingService; + private static final String BOOKING_PREFIX = "/bookings"; + private static final Long ITEM_ID = 1L; + private static final Long USER_ID = 1L; + private static final Long BOOKING_ID = 1L; + private RequestBookingDto requestBookingDto; + private BookingDto responseBookingDto; + + + @BeforeEach + public void setUp() { + requestBookingDto = new RequestBookingDto(ITEM_ID, + LocalDateTime.now().plusDays(1), + LocalDateTime.now().plusDays(2)); + + responseBookingDto = new BookingDto(BOOKING_ID, requestBookingDto.getStart(), requestBookingDto.getEnd(), + null, null, BookingStatus.WAITING); + } + + @Test + public void createBookingTest() throws Exception { + when(bookingService.create(anyLong(), any())).thenReturn(responseBookingDto); + + mockMvc.perform(post(BOOKING_PREFIX) + .header(USER_ID_HEADER, USER_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(responseBookingDto))) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.id").value(BOOKING_ID)); + } + + @Test + public void updateStatusTest() throws Exception { + responseBookingDto.setStatus(BookingStatus.APPROVED); + when(bookingService.updateStatus(anyLong(), any(), anyBoolean())).thenReturn(responseBookingDto); + + mockMvc.perform(patch(BOOKING_PREFIX + "/" + BOOKING_ID) + .header(USER_ID_HEADER, USER_ID) + .param("approved", "true") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(responseBookingDto))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id").value(BOOKING_ID)) + .andExpect(jsonPath("$.status").value("APPROVED")); + } + + @Test + public void getBookingTest() throws Exception { + when(bookingService.getById(anyLong(), anyLong())).thenReturn(responseBookingDto); + + mockMvc.perform(get(BOOKING_PREFIX + "/" + BOOKING_ID) + .header(USER_ID_HEADER, USER_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(responseBookingDto))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id").value(BOOKING_ID)); + } + + @Test + public void getUserBookings() throws Exception { + when(bookingService.getAllByBooker(anyLong(), any())).thenReturn(List.of(responseBookingDto)); + + mockMvc.perform(get(BOOKING_PREFIX) + .header(USER_ID_HEADER, USER_ID) + .param("state", "ALL")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].id").value(BOOKING_ID)); + } + + @Test + void getOwnerBookings() throws Exception { + when(bookingService.getAllByOwner(anyLong(), any())).thenReturn(List.of(responseBookingDto)); + + mockMvc.perform(get(BOOKING_PREFIX+ "/owner") + .header(USER_ID_HEADER, USER_ID) + .param("state", "ALL")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].id").value(BOOKING_ID)); + } +} diff --git a/server/src/test/java/ru/practicum/shareit/booking/BookingMapperTest.java b/server/src/test/java/ru/practicum/shareit/booking/BookingMapperTest.java new file mode 100644 index 0000000..2cc4e49 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/booking/BookingMapperTest.java @@ -0,0 +1,89 @@ +package ru.practicum.shareit.booking; + +import org.junit.jupiter.api.Test; +import ru.practicum.shareit.booking.dto.BookingDto; +import ru.practicum.shareit.booking.dto.RequestBookingDto; +import ru.practicum.shareit.booking.dto.ShortBookingDto; +import ru.practicum.shareit.booking.mapper.BookingMapper; +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 static org.assertj.core.api.Assertions.assertThat; + +class BookingMapperTest { + + @Test + void toBookingDtoTest() { + User owner = User.builder() + .id(100L) + .name("owner") + .email("o@example.com") + .build(); + + Item item = Item.builder() + .id(10L) + .name("Drill") + .owner(owner) + .build(); + + User booker = User.builder() + .id(20L) + .name("booker") + .email("b@example.com") + .build(); + + Booking booking = Booking.builder() + .id(1L) + .start(LocalDateTime.of(2024, 1, 1, 10, 0)) + .end(LocalDateTime.of(2024, 1, 1, 12, 0)) + .item(item) + .booker(booker) + .status(BookingStatus.APPROVED) + .build(); + + BookingDto dto = BookingMapper.toBookingDto(booking); + + assertThat(dto.getId()).isEqualTo(1L); + assertThat(dto.getStart()).isEqualTo(booking.getStart()); + assertThat(dto.getEnd()).isEqualTo(booking.getEnd()); + + assertThat(dto.getStatus()).isEqualTo(BookingStatus.APPROVED); + + assertThat(dto.getItem().getId()).isEqualTo(10L); + assertThat(dto.getItem().getName()).isEqualTo("Drill"); + assertThat(dto.getItem().getOwnerId()).isEqualTo(100L); + + assertThat(dto.getBooker().getId()).isEqualTo(20L); + } + + @Test + void toBookingFromRequestBookingDtoTest() { + RequestBookingDto req = RequestBookingDto.builder() + .start(LocalDateTime.of(2024, 2, 1, 14, 0)) + .end(LocalDateTime.of(2024, 2, 1, 16, 0)) + .build(); + + Booking booking = BookingMapper.toBookingFromRequest(req); + + assertThat(booking.getStart()).isEqualTo(req.getStart()); + assertThat(booking.getEnd()).isEqualTo(req.getEnd()); + assertThat(booking.getItem()).isNull(); + assertThat(booking.getBooker()).isNull(); + } + + @Test + void toShortBookingDtoTest() { + Booking booking = Booking.builder() + .start(LocalDateTime.of(2024, 3, 1, 9, 0)) + .end(LocalDateTime.of(2024, 3, 1, 11, 0)) + .build(); + + ShortBookingDto dto = BookingMapper.toShortBookingDto(booking); + + assertThat(dto.getStart()).isEqualTo(booking.getStart()); + assertThat(dto.getEnd()).isEqualTo(booking.getEnd()); + } +} diff --git a/server/src/test/java/ru/practicum/shareit/booking/BookingServiceImplTest.java b/server/src/test/java/ru/practicum/shareit/booking/BookingServiceImplTest.java new file mode 100644 index 0000000..96c3678 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/booking/BookingServiceImplTest.java @@ -0,0 +1,293 @@ +package ru.practicum.shareit.booking; + +import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.transaction.annotation.Transactional; +import ru.practicum.shareit.booking.dto.BookingDto; +import ru.practicum.shareit.booking.dto.RequestBookingDto; +import ru.practicum.shareit.booking.model.Booking; +import ru.practicum.shareit.booking.repository.BookingRepository; +import ru.practicum.shareit.booking.service.BookingServiceImpl; +import ru.practicum.shareit.exception.ForbiddenException; +import ru.practicum.shareit.exception.NotFoundException; +import ru.practicum.shareit.exception.ValidationException; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.item.repository.ItemRepository; +import ru.practicum.shareit.user.model.User; +import ru.practicum.shareit.user.repository.UserRepository; + +import java.time.LocalDateTime; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +@SpringBootTest +@Transactional +@RequiredArgsConstructor(onConstructor_ = @Autowired) +public class BookingServiceImplTest { + + private final BookingServiceImpl bookingService; + private final BookingRepository bookingRepository; + private final ItemRepository itemRepository; + private final UserRepository userRepository; + + User owner; + User booker; + Item item; + Booking currentBooking; + Booking futureRejectedBooking; + Booking pastWaitingBooking; + + @BeforeEach + void setUp() { + owner = new User(null, "Owner", "owner@mail.com"); + booker = new User(null, "Booker", "booker@mail.com"); + + item = new Item(null, + "Item-1", + "Desc", + true, + owner, + null + ); + + LocalDateTime now = LocalDateTime.now(); + + currentBooking = new Booking( + null, + now.minusDays(3), + now.plusDays(2), + item, + booker, + BookingStatus.APPROVED + ); + + futureRejectedBooking = new Booking( + null, + now.plusDays(3), + now.plusDays(5), + item, + booker, + BookingStatus.REJECTED + ); + + pastWaitingBooking = new Booking( + null, + now.minusDays(10), + now.minusDays(8), + item, + booker, + BookingStatus.WAITING + ); + } + + @Test + void createBookingSuccessTest() { + userRepository.save(owner); + userRepository.save(booker); + itemRepository.save(item); + + RequestBookingDto request = new RequestBookingDto( + item.getId(), + LocalDateTime.now(), + LocalDateTime.now().plusDays(1) + ); + + BookingDto created = bookingService.create(booker.getId(), request); + + assertThat(created).isNotNull(); + assertThat(created.getId()).isNotNull(); + assertThat(created.getStatus()).isEqualTo(BookingStatus.WAITING); + assertThat(created.getItem().getId()).isEqualTo(item.getId()); + assertThat(created.getBooker().getId()).isEqualTo(booker.getId()); + } + + @Test + void createBookingThrowIfItemUnavailableTest() { + userRepository.save(owner); + userRepository.save(booker); + + item.setAvailable(false); + itemRepository.save(item); + + RequestBookingDto request = new RequestBookingDto( + item.getId(), + LocalDateTime.now(), + LocalDateTime.now().plusDays(1) + ); + + assertThatThrownBy(() -> bookingService.create(booker.getId(), request)) + .isInstanceOf(ValidationException.class) + .hasMessage("Предмет уже забронирован"); + } + + @Test + void createBookingThrowIfItemNotFoundTest() { + userRepository.save(booker); + + RequestBookingDto request = new RequestBookingDto( + 999L, + LocalDateTime.now(), + LocalDateTime.now().plusDays(1) + ); + + assertThatThrownBy(() -> bookingService.create(booker.getId(), request)) + .isInstanceOf(NotFoundException.class) + .hasMessage("Предмет с ID: 999 не найден"); + } + + @Test + void createBookingThrowIfUserNotFoundTest() { + userRepository.save(owner); + itemRepository.save(item); + + RequestBookingDto request = new RequestBookingDto( + item.getId(), + LocalDateTime.now(), + LocalDateTime.now().plusDays(1) + ); + + assertThatThrownBy(() -> bookingService.create(999L, request)) + .isInstanceOf(NotFoundException.class) + .hasMessage("Пользователь с ID: 999 не найден"); + } + + @Test + void updateStatusApprovedTest() { + userRepository.save(owner); + userRepository.save(booker); + itemRepository.save(item); + bookingRepository.save(currentBooking); + + BookingDto updated = bookingService.updateStatus(owner.getId(), currentBooking.getId(), true); + + assertThat(updated.getStatus()).isEqualTo(BookingStatus.APPROVED); + } + + @Test + void updateStatusRejectTest() { + userRepository.save(owner); + userRepository.save(booker); + itemRepository.save(item); + bookingRepository.save(currentBooking); + + BookingDto updated = bookingService.updateStatus(owner.getId(), currentBooking.getId(), false); + + assertThat(updated.getStatus()).isEqualTo(BookingStatus.REJECTED); + } + + @Test + void updateStatusThrowIfNotOwnerTest() { + userRepository.save(owner); + userRepository.save(booker); + itemRepository.save(item); + bookingRepository.save(currentBooking); + + assertThatThrownBy(() -> bookingService.updateStatus(booker.getId(), currentBooking.getId(), true)) + .isInstanceOf(ForbiddenException.class) + .hasMessage("Изменить статус бронирования может только владелец предмета"); + } + + @Test + void updateStatusThrowIfBookingNotFoundTest() { + userRepository.save(owner); + + assertThatThrownBy(() -> bookingService.updateStatus(owner.getId(), 999L, true)) + .isInstanceOf(NotFoundException.class) + .hasMessage("Бронирование с номером: 999 не найдено"); + } + + @Test + void getByIdSuccessTest() { + userRepository.save(owner); + userRepository.save(booker); + itemRepository.save(item); + bookingRepository.save(currentBooking); + + BookingDto byOwner = bookingService.getById(owner.getId(), currentBooking.getId()); + BookingDto byBooker = bookingService.getById(booker.getId(), currentBooking.getId()); + + assertThat(byOwner.getId()).isEqualTo(currentBooking.getId()); + assertThat(byBooker.getId()).isEqualTo(currentBooking.getId()); + } + + @Test + void getByIdThrowIfNoAccessTest() { + userRepository.save(owner); + userRepository.save(booker); + itemRepository.save(item); + bookingRepository.save(currentBooking); + + User stranger = userRepository.save(new User(null, "str", "str@mail.com")); + + assertThatThrownBy(() -> bookingService.getById(stranger.getId(), currentBooking.getId())) + .isInstanceOf(ForbiddenException.class) + .hasMessage("Запросить информацию о бронировании может только создатель брони или владелец предмета"); + } + + @Test + void getByIdThrowIfBookingNotFoundTest() { + userRepository.save(owner); + + assertThatThrownBy(() -> bookingService.getById(owner.getId(), 999L)) + .isInstanceOf(NotFoundException.class) + .hasMessage("Бронирование с номером: 999 не найдено"); + } + + @Test + void getAllByBookerReturnCorrectForAllStatesTest() { + userRepository.save(owner); + userRepository.save(booker); + itemRepository.save(item); + + bookingRepository.save(currentBooking); + bookingRepository.save(futureRejectedBooking); + bookingRepository.save(pastWaitingBooking); + + assertThat(bookingService.getAllByBooker(booker.getId(), BookingState.ALL)).hasSize(3); + + assertThat(bookingService.getAllByBooker(booker.getId(), BookingState.CURRENT)).hasSize(1); + + assertThat(bookingService.getAllByBooker(booker.getId(), BookingState.FUTURE)).hasSize(1); + + assertThat(bookingService.getAllByBooker(booker.getId(), BookingState.PAST)).hasSize(1); + + assertThat(bookingService.getAllByBooker(booker.getId(), BookingState.WAITING)).hasSize(1); + + assertThat(bookingService.getAllByBooker(booker.getId(), BookingState.REJECTED)).hasSize(1); + } + + @Test + void getAllByBookerThrowIfUserNotFoundTest() { + assertThatThrownBy(() -> bookingService.getAllByBooker(999L, BookingState.ALL)) + .isInstanceOf(NotFoundException.class); + } + + @Test + void getAllByOwnerReturnCorrectForAllStatesTest() { + userRepository.save(owner); + userRepository.save(booker); + itemRepository.save(item); + + bookingRepository.save(currentBooking); + bookingRepository.save(futureRejectedBooking); + bookingRepository.save(pastWaitingBooking); + + assertThat(bookingService.getAllByOwner(owner.getId(), BookingState.ALL)).hasSize(3); + assertThat(bookingService.getAllByOwner(owner.getId(), BookingState.CURRENT)).hasSize(1); + assertThat(bookingService.getAllByOwner(owner.getId(), BookingState.FUTURE)).hasSize(1); + assertThat(bookingService.getAllByOwner(owner.getId(), BookingState.PAST)).hasSize(1); + assertThat(bookingService.getAllByOwner(owner.getId(), BookingState.WAITING)).hasSize(1); + assertThat(bookingService.getAllByOwner(owner.getId(), BookingState.REJECTED)).hasSize(1); + } + + @Test + void getAllByOwnerThrowIfUserNotFoundTest() { + assertThatThrownBy(() -> bookingService.getAllByOwner(999L, BookingState.ALL)) + .isInstanceOf(NotFoundException.class); + } +} + diff --git a/server/src/test/java/ru/practicum/shareit/booking/dto/BookingDtoTest.java b/server/src/test/java/ru/practicum/shareit/booking/dto/BookingDtoTest.java new file mode 100644 index 0000000..0265819 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/booking/dto/BookingDtoTest.java @@ -0,0 +1,78 @@ +package ru.practicum.shareit.booking.dto; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; +import ru.practicum.shareit.booking.BookingStatus; +import ru.practicum.shareit.item.dto.ShortItemDto; +import ru.practicum.shareit.user.dto.ShortUserDto; + +import java.time.LocalDateTime; + +import static org.assertj.core.api.Assertions.assertThat; + +@JsonTest +public class BookingDtoTest { + + @Autowired + private JacksonTester json; + + @Test + void serializeBookingDtoTest() throws Exception { + ShortItemDto item = ShortItemDto.builder() + .id(1L) + .name("Item-1") + .build(); + + ShortUserDto user = ShortUserDto.builder() + .id(2L) + .build(); + + BookingDto dto = BookingDto.builder() + .id(10L) + .start(LocalDateTime.of(2024, 1, 1, 12, 0)) + .end(LocalDateTime.of(2024, 1, 2, 12, 0)) + .item(item) + .booker(user) + .status(BookingStatus.APPROVED) + .build(); + + var result = json.write(dto); + + assertThat(result).hasJsonPath("$.id"); + assertThat(result).hasJsonPath("$.start"); + assertThat(result).hasJsonPath("$.end"); + assertThat(result).hasJsonPath("$.item"); + assertThat(result).hasJsonPath("$.booker"); + assertThat(result).hasJsonPath("$.status"); + + assertThat(result).extractingJsonPathNumberValue("$.id").isEqualTo(10); + assertThat(result).extractingJsonPathStringValue("$.status").isEqualTo("APPROVED"); + assertThat(result).extractingJsonPathStringValue("$.item.name").isEqualTo("Item-1"); + assertThat(result).extractingJsonPathNumberValue("$.booker.id").isEqualTo(2); + } + + @Test + void deserializeBookingDtoTest() throws Exception { + String jsonContent = """ + { + "id": 10, + "start": "2024-01-01T12:00:00", + "end": "2024-01-02T12:00:00", + "item": { "id": 1, "name": "Item-1" }, + "booker": { "id": 2 }, + "status": "APPROVED" + } + """; + + var parsed = json.parse(jsonContent); + + BookingDto dto = parsed.getObject(); + + assertThat(dto.getId()).isEqualTo(10L); + assertThat(dto.getStatus()).isEqualTo(BookingStatus.APPROVED); + assertThat(dto.getItem().getName()).isEqualTo("Item-1"); + } +} + diff --git a/server/src/test/java/ru/practicum/shareit/booking/dto/RequestBookingDtoTest.java b/server/src/test/java/ru/practicum/shareit/booking/dto/RequestBookingDtoTest.java new file mode 100644 index 0000000..1603114 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/booking/dto/RequestBookingDtoTest.java @@ -0,0 +1,53 @@ +package ru.practicum.shareit.booking.dto; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; + +import java.time.LocalDateTime; + +import static org.assertj.core.api.Assertions.assertThat; + +@JsonTest +public class RequestBookingDtoTest { + + @Autowired + private JacksonTester json; + + @Test + void serializeRequestBookingDtoTest() throws Exception { + var dto = RequestBookingDto.builder() + .itemId(5L) + .start(LocalDateTime.of(2024, 2, 1, 10, 0)) + .end(LocalDateTime.of(2024, 2, 1, 12, 0)) + .build(); + + var result = json.write(dto); + + assertThat(result).hasJsonPath("$.itemId"); + assertThat(result).hasJsonPath("$.start"); + assertThat(result).hasJsonPath("$.end"); + + assertThat(result).extractingJsonPathNumberValue("$.itemId").isEqualTo(5); + assertThat(result).extractingJsonPathStringValue("$.start").isEqualTo("2024-02-01T10:00:00"); + } + + @Test + void deserializeRequestBookingDtoTest() throws Exception { + String jsonContent = """ + { + "itemId": 5, + "start": "2024-02-01T10:00:00", + "end": "2024-02-01T12:00:00" + } + """; + + var result = json.parse(jsonContent); + + assertThat(result.getObject().getItemId()).isEqualTo(5L); + assertThat(result.getObject().getStart()) + .isEqualTo(LocalDateTime.of(2024, 2, 1, 10, 0)); + } +} + diff --git a/server/src/test/java/ru/practicum/shareit/booking/dto/ShortBookingDtoTest.java b/server/src/test/java/ru/practicum/shareit/booking/dto/ShortBookingDtoTest.java new file mode 100644 index 0000000..53400b1 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/booking/dto/ShortBookingDtoTest.java @@ -0,0 +1,51 @@ +package ru.practicum.shareit.booking.dto; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; + +import java.time.LocalDateTime; + +import static org.assertj.core.api.Assertions.assertThat; + +@JsonTest +public class ShortBookingDtoTest { + + @Autowired + private JacksonTester json; + + @Test + void serializeShortBookingDtoTest() throws Exception { + var dto = ShortBookingDto.builder() + .start(LocalDateTime.of(2024, 3, 10, 10, 0)) + .end(LocalDateTime.of(2024, 3, 10, 11, 0)) + .build(); + + var result = json.write(dto); + + assertThat(result).hasJsonPath("$.start"); + assertThat(result).hasJsonPath("$.end"); + + assertThat(result).extractingJsonPathStringValue("$.start") + .isEqualTo("2024-03-10T10:00:00"); + } + + @Test + void deserializeShortBookingDtoTest() throws Exception { + String jsonContent = """ + { + "start": "2024-03-10T10:00:00", + "end": "2024-03-10T11:00:00" + } + """; + + var parsed = json.parse(jsonContent); + + ShortBookingDto dto = parsed.getObject(); + + assertThat(dto.getStart()).isEqualTo(LocalDateTime.of(2024, 3, 10, 10, 0)); + assertThat(dto.getEnd()).isEqualTo(LocalDateTime.of(2024, 3, 10, 11, 0)); + } +} + diff --git a/server/src/test/java/ru/practicum/shareit/item/CommentMapperTest.java b/server/src/test/java/ru/practicum/shareit/item/CommentMapperTest.java new file mode 100644 index 0000000..4cfe245 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/item/CommentMapperTest.java @@ -0,0 +1,73 @@ +package ru.practicum.shareit.item; + +import org.junit.jupiter.api.Test; +import ru.practicum.shareit.item.dto.CommentDto; +import ru.practicum.shareit.item.mapper.CommentMapper; +import ru.practicum.shareit.item.model.Comment; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDateTime; + +import static org.assertj.core.api.Assertions.assertThat; + +class CommentMapperTest { + + @Test + void toCommentDtoTest() { + User author = User.builder() + .id(10L) + .name("John") + .email("john@example.com") + .build(); + + Comment comment = Comment.builder() + .id(1L) + .text("Nice item") + .author(author) + .created(LocalDateTime.of(2024, 1, 1, 10, 0)) + .build(); + + CommentDto dto = CommentMapper.toCommentDto(comment); + + assertThat(dto.getId()).isEqualTo(1L); + assertThat(dto.getText()).isEqualTo("Nice item"); + assertThat(dto.getAuthorName()).isEqualTo("John"); + assertThat(dto.getCreated()).isEqualTo(comment.getCreated()); + } + + @Test + void toCommentTest() { + CommentDto dto = CommentDto.builder() + .id(2L) + .text("Great!") + .created(LocalDateTime.of(2024, 3, 10, 15, 30)) + .build(); + + Comment comment = CommentMapper.toComment(dto); + + assertThat(comment.getId()).isEqualTo(2L); + assertThat(comment.getText()).isEqualTo("Great!"); + assertThat(comment.getCreated()).isEqualTo(dto.getCreated()); + } + + @Test + void toCommentIfCreatedIsNullTest() { + CommentDto dto = CommentDto.builder() + .id(3L) + .text("Cool") + .created(null) + .build(); + + LocalDateTime before = LocalDateTime.now(); + Comment comment = CommentMapper.toComment(dto); + LocalDateTime after = LocalDateTime.now(); + + assertThat(comment.getId()).isEqualTo(3L); + assertThat(comment.getText()).isEqualTo("Cool"); + + assertThat(comment.getCreated()).isNotNull(); + assertThat(comment.getCreated()).isAfterOrEqualTo(before); + assertThat(comment.getCreated()).isBeforeOrEqualTo(after); + } +} + diff --git a/server/src/test/java/ru/practicum/shareit/item/ItemControllerTest.java b/server/src/test/java/ru/practicum/shareit/item/ItemControllerTest.java new file mode 100644 index 0000000..7db22fc --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/item/ItemControllerTest.java @@ -0,0 +1,139 @@ +package ru.practicum.shareit.item; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import ru.practicum.shareit.item.dto.CommentDto; +import ru.practicum.shareit.item.dto.ItemDto; +import ru.practicum.shareit.item.dto.ItemDtoWithBookingsAndComments; +import ru.practicum.shareit.item.dto.UpdateItemDto; +import ru.practicum.shareit.item.service.ItemService; + +import java.time.LocalDateTime; +import java.util.List; + +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static ru.practicum.shareit.util.Constants.USER_ID_HEADER; + +@WebMvcTest(ItemController.class) +@RequiredArgsConstructor(onConstructor_ = @Autowired) +public class ItemControllerTest { + + @Autowired + private MockMvc mockMvc; + @Autowired + private ObjectMapper objectMapper; + @MockBean + private ItemService itemService; + private static final String ITEM_PREFIX = "/items"; + private static final Long ITEM_ID = 1L; + private static final Long USER_ID = 1L; + private ItemDto requestItemDto; + private UpdateItemDto updateItemDto; + private ItemDtoWithBookingsAndComments responseItemDto; + + @BeforeEach + public void setUp() { + requestItemDto = new ItemDto(null, "Thing", "Such a great thing", true, null, null); + updateItemDto = new UpdateItemDto("Updated thing", "It's even better!", true); + + responseItemDto = new ItemDtoWithBookingsAndComments(ITEM_ID, "Thing", "Such a great thing", true, + null, null, null, null); + } + + @Test + void createItemTest() throws Exception { + ItemDto createdItem = requestItemDto; + createdItem.setId(ITEM_ID); + when(itemService.create(anyLong(), any())).thenReturn(createdItem); + + mockMvc.perform(post(ITEM_PREFIX) + .header(USER_ID_HEADER, USER_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(createdItem))) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.name").value("Thing")) + .andExpect(jsonPath("$.id").value(ITEM_ID)); + } + + @Test + void updateItemTest() throws Exception { + ItemDto updatedItem = new ItemDto( + ITEM_ID, + "Updated thing", + "It's even better!", + true, + null, + null + ); + + when(itemService.update(anyLong(), anyLong(), any())).thenReturn(updatedItem); + + mockMvc.perform(patch(ITEM_PREFIX + "/" + ITEM_ID) + .header(USER_ID_HEADER, USER_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(updateItemDto))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.name").value("Updated thing")) + .andExpect(jsonPath("$.id").value(ITEM_ID)); + } + + @Test + void getItemByIdTest() throws Exception { + when(itemService.getById(anyLong(), anyLong())).thenReturn(responseItemDto); + + mockMvc.perform(get(ITEM_PREFIX + "/" + ITEM_ID) + .header(USER_ID_HEADER, USER_ID)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id").value(ITEM_ID)); + } + + @Test + void getItemsByUserTest() throws Exception { + when(itemService.getAllByUser(anyLong())).thenReturn(List.of(responseItemDto)); + + mockMvc.perform(get(ITEM_PREFIX) + .header(USER_ID_HEADER, USER_ID)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].id").value(ITEM_ID)); + } + + @Test + void searchItemsTest() throws Exception { + ItemDto searchResponse = requestItemDto; + searchResponse.setId(ITEM_ID); + + when(itemService.search(anyString())).thenReturn(List.of(searchResponse)); + + mockMvc.perform(get(ITEM_PREFIX + "/search") + .param("text", "thing")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].id").value(ITEM_ID)); + } + + @Test + void addCommentTest() throws Exception { + CommentDto requestComment = new CommentDto(null, "Nice item!", "Steve", LocalDateTime.now()); + CommentDto responseComment = requestComment; + responseComment.setId(1L); + + when(itemService.addComment(anyLong(), anyLong(), any())).thenReturn(responseComment); + + mockMvc.perform(post(ITEM_PREFIX + "/" + ITEM_ID + "/comment") + .header(USER_ID_HEADER, USER_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(requestComment))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id").value(1)); + } +} \ No newline at end of file diff --git a/server/src/test/java/ru/practicum/shareit/item/ItemMapperTest.java b/server/src/test/java/ru/practicum/shareit/item/ItemMapperTest.java new file mode 100644 index 0000000..9af25e3 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/item/ItemMapperTest.java @@ -0,0 +1,187 @@ +package ru.practicum.shareit.item; + +import org.junit.jupiter.api.Test; +import ru.practicum.shareit.booking.model.Booking; +import ru.practicum.shareit.item.dto.ItemDto; +import ru.practicum.shareit.item.dto.ItemDtoWithBookingsAndComments; +import ru.practicum.shareit.item.dto.ShortItemDto; +import ru.practicum.shareit.item.mapper.ItemMapper; +import ru.practicum.shareit.item.model.Comment; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.request.model.ItemRequest; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDateTime; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class ItemMapperTest { + + @Test + void toItemDtoIfNoRequestTest() { + Item item = Item.builder() + .id(1L) + .name("Item-1") + .description("Desc") + .isAvailable(true) + .request(null) + .build(); + + ItemDto dto = ItemMapper.toItemDto(item); + + assertThat(dto.getId()).isEqualTo(1L); + assertThat(dto.getRequestId()).isNull(); + } + + @Test + void toItemDtoIfRequestTest() { + ItemRequest req = new ItemRequest(5L, null, null, null); + + Item item = Item.builder() + .id(1L) + .name("Item-1") + .description("Desc") + .isAvailable(true) + .request(req) + .build(); + + ItemDto dto = ItemMapper.toItemDto(item); + + assertThat(dto.getRequestId()).isEqualTo(5L); + } + + @Test + void toShortItemDtoTest() { + User owner = User.builder().id(10L).name("John").email("j@e.com").build(); + + Item item = Item.builder() + .id(2L) + .name("Phone") + .owner(owner) + .build(); + + ShortItemDto dto = ItemMapper.toShortItemDto(item); + + assertThat(dto.getId()).isEqualTo(2L); + assertThat(dto.getName()).isEqualTo("Phone"); + assertThat(dto.getOwnerId()).isEqualTo(10L); + } + + @Test + void toItemTest() { + ItemDto dto = ItemDto.builder() + .id(3L) + .name("Table") + .description("Wood") + .available(true) + .build(); + + Item item = ItemMapper.toItem(dto); + + assertThat(item.getId()).isEqualTo(3L); + assertThat(item.getName()).isEqualTo("Table"); + assertThat(item.getDescription()).isEqualTo("Wood"); + assertThat(item.isAvailable()).isTrue(); + } + + @Test + void toItemDtoWithBookingsNoBookingsTest() { + Item item = Item.builder() + .id(1L) + .name("Item") + .description("D") + .isAvailable(true) + .build(); + + ItemDtoWithBookingsAndComments dto = + ItemMapper.toItemDtoWithBookingsAndComments(item, List.of(), List.of()); + + assertThat(dto.getLastBooking()).isNull(); + assertThat(dto.getNextBooking()).isNull(); + assertThat(dto.getComments()).isEmpty(); + } + + @Test + void toItemDtoWithBookingsOnlyLastBookingTest() { + Item item = Item.builder().id(1L).build(); + + Booking last = Booking.builder() + .id(10L) + .start(LocalDateTime.now().minusDays(3)) + .end(LocalDateTime.now().minusDays(1)) + .build(); + + ItemDtoWithBookingsAndComments dto = + ItemMapper.toItemDtoWithBookingsAndComments(item, List.of(last), List.of()); + + assertThat(dto.getLastBooking()).isNotNull(); + assertThat(dto.getNextBooking()).isNull(); + assertThat(dto.getLastBooking().getEnd()).isEqualTo(last.getEnd()); + } + + @Test + void toItemDtoWithBookingsOnlyNextBookingTest() { + Item item = Item.builder().id(1L).build(); + + Booking next = Booking.builder() + .id(11L) + .start(LocalDateTime.now().plusDays(1)) + .end(LocalDateTime.now().plusDays(2)) + .build(); + + ItemDtoWithBookingsAndComments dto = + ItemMapper.toItemDtoWithBookingsAndComments(item, List.of(next), List.of()); + + assertThat(dto.getLastBooking()).isNull(); + assertThat(dto.getNextBooking()).isNotNull(); + assertThat(dto.getNextBooking().getStart()).isEqualTo(next.getStart()); + } + + @Test + void toItemDtoWithBookingsTest() { + Item item = Item.builder().id(1L).build(); + + Booking last = Booking.builder() + .id(10L) + .start(LocalDateTime.now().minusDays(3)) + .end(LocalDateTime.now().minusDays(2)) + .build(); + + Booking next = Booking.builder() + .id(20L) + .start(LocalDateTime.now().plusDays(1)) + .end(LocalDateTime.now().plusDays(2)) + .build(); + + ItemDtoWithBookingsAndComments dto = + ItemMapper.toItemDtoWithBookingsAndComments(item, List.of(last, next), List.of()); + + assertThat(dto.getLastBooking()).isNotNull(); + assertThat(dto.getNextBooking()).isNotNull(); + assertThat(dto.getLastBooking().getEnd()).isEqualTo(last.getEnd()); + assertThat(dto.getNextBooking().getStart()).isEqualTo(next.getStart()); + } + + @Test + void toItemDtoWithBookingsCommentsTest() { + Item item = Item.builder().id(1L).build(); + + User author = User.builder().id(7L).name("Bob").email("b@e.com").build(); + + Comment comment = Comment.builder() + .id(100L) + .text("Nice!") + .author(author) + .created(LocalDateTime.now()) + .build(); + + ItemDtoWithBookingsAndComments dto = + ItemMapper.toItemDtoWithBookingsAndComments(item, List.of(), List.of(comment)); + + assertThat(dto.getComments()).hasSize(1); + assertThat(dto.getComments().iterator().next().getText()).isEqualTo("Nice!"); + assertThat(dto.getComments().iterator().next().getAuthorName()).isEqualTo("Bob"); + } +} + diff --git a/server/src/test/java/ru/practicum/shareit/item/ItemServiceImplTest.java b/server/src/test/java/ru/practicum/shareit/item/ItemServiceImplTest.java new file mode 100644 index 0000000..649455c --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/item/ItemServiceImplTest.java @@ -0,0 +1,349 @@ +package ru.practicum.shareit.item; + +import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.transaction.annotation.Transactional; +import ru.practicum.shareit.booking.BookingStatus; +import ru.practicum.shareit.booking.model.Booking; +import ru.practicum.shareit.booking.repository.BookingRepository; +import ru.practicum.shareit.exception.ForbiddenException; +import ru.practicum.shareit.exception.NotFoundException; +import ru.practicum.shareit.exception.ValidationException; +import ru.practicum.shareit.item.dto.CommentDto; +import ru.practicum.shareit.item.dto.ItemDto; +import ru.practicum.shareit.item.dto.ItemDtoWithBookingsAndComments; +import ru.practicum.shareit.item.dto.UpdateItemDto; +import ru.practicum.shareit.item.model.Comment; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.item.repository.CommentRepository; +import ru.practicum.shareit.item.repository.ItemRepository; +import ru.practicum.shareit.item.service.ItemServiceImpl; +import ru.practicum.shareit.request.model.ItemRequest; +import ru.practicum.shareit.request.repository.ItemRequestRepository; +import ru.practicum.shareit.user.model.User; +import ru.practicum.shareit.user.repository.UserRepository; + +import java.time.LocalDateTime; +import java.util.Collection; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +@SpringBootTest +@Transactional +@RequiredArgsConstructor(onConstructor_ = @Autowired) +public class ItemServiceImplTest { + + private final ItemServiceImpl itemService; + + private final UserRepository userRepository; + private final ItemRepository itemRepository; + private final ItemRequestRepository requestRepository; + private final BookingRepository bookingRepository; + private final CommentRepository commentRepository; + + private User owner; + private User user2; + private Item item1; + private Item item2; + + @BeforeEach + void setUp() { + owner = userRepository.save(new User(null, "Owner", "owner@mail.com")); + user2 = userRepository.save(new User(null, "User2", "user2@mail.com")); + + item1 = itemRepository.save( + new Item(null, "Item 1", "Description 1", true, owner, null) + ); + + item2 = itemRepository.save( + new Item(null, "Item 2", "Description 2", true, owner, null) + ); + } + + @Test + void getAllByUserTest() { + Long ownerId = owner.getId(); + Long itemId = item1.getId(); + + bookingRepository.save(new Booking( + null, + LocalDateTime.now().minusDays(5), + LocalDateTime.now().minusDays(1), + item1, + user2, + BookingStatus.APPROVED + )); + + commentRepository.save(new Comment( + null, + "Test comment", + item1, + user2, + LocalDateTime.now() + )); + + Collection result = itemService.getAllByUser(ownerId); + + assertThat(result).hasSize(2); + + ItemDtoWithBookingsAndComments dto = result.stream() + .filter(i -> i.getId().equals(itemId)) + .findFirst() + .orElseThrow(); + + assertThat(dto.getComments()).hasSize(1); + assertThat(dto.getLastBooking()).isNotNull(); + } + + @Test + void getAllByUserReturnEmptyIfUserHasNoItemsTest() { + User stranger = userRepository.save(new User(null, "Stranger", "s@gmail.com")); + + Collection result = + itemService.getAllByUser(stranger.getId()); + + assertThat(result).isEmpty(); + } + + @Test + void getAllByUserThrowIfUserNotFoundTest() { + assertThatThrownBy(() -> itemService.getAllByUser(999L)) + .isInstanceOf(NotFoundException.class) + .hasMessageContaining("Пользователь с ID"); + } + + @Test + void getByIdReturnItemIfOwnerTest() { + Long ownerId = owner.getId(); + Long itemId = item1.getId(); + + bookingRepository.save(new Booking( + null, + LocalDateTime.now().minusDays(3), + LocalDateTime.now().minusDays(1), + item1, + user2, + BookingStatus.APPROVED + )); + + ItemDtoWithBookingsAndComments dto = itemService.getById(ownerId, itemId); + + assertThat(dto).isNotNull(); + assertThat(dto.getLastBooking()).isNotNull(); + } + + @Test + void getByIdHideBookingsWhenNotOwnerTest() { + Long itemId = item1.getId(); + + bookingRepository.save(new Booking( + null, + LocalDateTime.now().minusDays(3), + LocalDateTime.now().minusDays(1), + item1, + user2, + BookingStatus.APPROVED + )); + + ItemDtoWithBookingsAndComments dto = itemService.getById(user2.getId(), itemId); + + assertThat(dto).isNotNull(); + assertThat(dto.getLastBooking()).isNull(); // НЕ владелец -> не видит брони + } + + @Test + void getByIdThrowIfUserNotFoundTest() { + assertThatThrownBy(() -> itemService.getById(999L, item1.getId())) + .isInstanceOf(NotFoundException.class); + } + + @Test + void getByIdThrowIfItemNotFoundTest() { + assertThatThrownBy(() -> itemService.getById(owner.getId(), 999L)) + .isInstanceOf(NotFoundException.class); + } + + @Test + void createItemWithoutItemRequestTest() { + ItemDto dto = ItemDto.builder() + .name("New") + .description("Desc") + .available(true) + .build(); + + ItemDto saved = itemService.create(owner.getId(), dto); + + assertThat(saved).isNotNull(); + assertThat(saved.getId()).isNotNull(); + assertThat(saved.getName()).isEqualTo(dto.getName()); + } + + @Test + void createSetRequestIfRequestExistsTest() { + ItemRequest request = requestRepository.save( + new ItemRequest(null, "Need item", user2, LocalDateTime.now()) + ); + + ItemDto dto = ItemDto.builder() + .name("Request") + .description("Request description") + .available(true) + .requestId(request.getId()) + .build(); + + ItemDto saved = itemService.create(owner.getId(), dto); + + assertThat(saved.getRequestId()).isEqualTo(request.getId()); + } + + @Test + void createThrowIfUserNotFoundTest() { + ItemDto dto = ItemDto.builder() + .name("X") + .description("Y") + .available(true) + .build(); + + assertThatThrownBy(() -> itemService.create(999L, dto)) + .isInstanceOf(NotFoundException.class); + } + + @Test + void createThrowIfRequestNotFoundTest() { + ItemDto dto = ItemDto.builder() + .name("X") + .description("Y") + .available(true) + .requestId(999L) + .build(); + + assertThatThrownBy(() -> itemService.create(owner.getId(), dto)) + .isInstanceOf(NotFoundException.class); + } + + @Test + void updateFieldsTest() { + Long id = item1.getId(); + + UpdateItemDto upd = new UpdateItemDto("New name", "New desc", false); + + ItemDto updated = itemService.update(owner.getId(), id, upd); + + assertThat(updated.getName()).isEqualTo("New name"); + assertThat(updated.getDescription()).isEqualTo("New desc"); + assertThat(updated.getAvailable()).isFalse(); + } + + @Test + void updateNotUpdateBlankFieldsTest() { + Long id = item1.getId(); + UpdateItemDto upd = new UpdateItemDto(" ", " ", null); + + ItemDto updated = itemService.update(owner.getId(), id, upd); + + assertThat(updated.getName()).isEqualTo(item1.getName()); + assertThat(updated.getDescription()).isEqualTo(item1.getDescription()); + } + + @Test + void updateThrowIfUserNotFoundTest() { + UpdateItemDto upd = new UpdateItemDto("X", "Y", true); + + assertThatThrownBy(() -> itemService.update(999L, item1.getId(), upd)) + .isInstanceOf(NotFoundException.class); + } + + @Test + void updateThrowIfItemNotFoundTest() { + UpdateItemDto upd = new UpdateItemDto("X", "Y", true); + + assertThatThrownBy(() -> itemService.update(owner.getId(), 999L, upd)) + .isInstanceOf(NotFoundException.class); + } + + @Test + void updateThrowIfNotOwnerTest() { + UpdateItemDto upd = new UpdateItemDto("X", "Y", true); + + assertThatThrownBy(() -> itemService.update(user2.getId(), item1.getId(), upd)) + .isInstanceOf(ForbiddenException.class) + .hasMessageContaining("только ее владелец"); + } + + @Test + void searchReturnItemsTest() { + Collection items = + itemService.search("Description"); + + assertThat(items).hasSize(2); + } + + @Test + void searchReturnEmptyIfBlankTest() { + assertThat(itemService.search("")).isEmpty(); + assertThat(itemService.search(" ")).isEmpty(); + assertThat(itemService.search(null)).isEmpty(); + } + + @Test + void addCommentIfUserHadBookingTest() { + Long itemId = item1.getId(); + Long userId = user2.getId(); + + // пользователь user2 завершил бронирование item1 в прошлом + bookingRepository.save(new Booking( + null, + LocalDateTime.now().minusDays(5), + LocalDateTime.now().minusDays(1), + item1, + user2, + BookingStatus.APPROVED + )); + + CommentDto req = CommentDto.builder() + .text("Comment") + .build(); + + CommentDto result = itemService.addComment(userId, itemId, req); + + assertThat(result.getText()).isEqualTo("Comment"); + assertThat(result.getAuthorName()).isEqualTo(user2.getName()); + assertThat(result.getCreated()).isNotNull(); + } + + @Test + void addCommentThrowIfUserNotBookedItemTest() { + CommentDto req = CommentDto.builder() + .text("Hello") + .build(); + + assertThatThrownBy(() -> itemService.addComment(user2.getId(), item1.getId(), req)) + .isInstanceOf(ValidationException.class) + .hasMessageContaining("не бронировал"); + } + + @Test + void addCommentThrowIfUserNotFoundTest() { + CommentDto req = CommentDto.builder() + .text("X") + .build(); + + assertThatThrownBy(() -> itemService.addComment(999L, item1.getId(), req)) + .isInstanceOf(NotFoundException.class); + } + + @Test + void addCommentThrowIfItemNotFoundTest() { + CommentDto req = CommentDto.builder() + .text("X") + .build(); + + assertThatThrownBy(() -> itemService.addComment(user2.getId(), 999L, req)) + .isInstanceOf(NotFoundException.class); + } +} + diff --git a/server/src/test/java/ru/practicum/shareit/item/dto/CommentDtoTest.java b/server/src/test/java/ru/practicum/shareit/item/dto/CommentDtoTest.java new file mode 100644 index 0000000..04d8a00 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/item/dto/CommentDtoTest.java @@ -0,0 +1,47 @@ +package ru.practicum.shareit.item.dto; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; + +import java.time.LocalDateTime; + +import static org.assertj.core.api.Assertions.assertThat; + +@JsonTest +class CommentDtoTest { + + @Autowired + private JacksonTester json; + + @Test + void serializeCommentDtoTest() throws Exception { + var dto = new CommentDto( + 1L, "Hello", "User", LocalDateTime.parse("2024-01-01T10:00:00") + ); + + var result = json.write(dto); + + assertThat(result).hasJsonPath("$.text"); + assertThat(result).extractingJsonPathStringValue("$.authorName").isEqualTo("User"); + } + + @Test + void deserializeCommentDtoTest() throws Exception { + String content = """ + { + "id": 1, + "text": "Hello", + "authorName": "User", + "created": "2024-01-01T10:00:00" + } + """; + + var dto = json.parseObject(content); + + assertThat(dto.getText()).isEqualTo("Hello"); + assertThat(dto.getAuthorName()).isEqualTo("User"); + } +} + diff --git a/server/src/test/java/ru/practicum/shareit/item/dto/ItemDtoTest.java b/server/src/test/java/ru/practicum/shareit/item/dto/ItemDtoTest.java new file mode 100644 index 0000000..af8dd16 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/item/dto/ItemDtoTest.java @@ -0,0 +1,68 @@ +package ru.practicum.shareit.item.dto; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; + +import java.time.LocalDateTime; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@JsonTest +class ItemDtoTest { + + @Autowired + private JacksonTester json; + + @Test + void serializeItemDtoTest() throws Exception { + var dto = ItemDto.builder() + .id(1L) + .name("Item") + .description("Desc") + .available(true) + .requestId(5L) + .comments(List.of( + new CommentDto(10L, "Comment", "Author", LocalDateTime.parse("2024-01-01T12:00:00")) + )) + .build(); + + var result = json.write(dto); + + assertThat(result).hasJsonPath("$.id"); + assertThat(result).hasJsonPath("$.comments[0].text"); + + assertThat(result).extractingJsonPathStringValue("$.name").isEqualTo("Item"); + assertThat(result).extractingJsonPathNumberValue("$.comments[0].id").isEqualTo(10); + } + + @Test + void deserializeItemDtoTest() throws Exception { + String content = """ + { + "id": 1, + "name": "Item", + "description": "Desc", + "available": true, + "requestId": 5, + "comments": [ + { + "id": 10, + "text": "Comment", + "authorName": "Auth", + "created": "2024-01-01T12:00:00" + } + ] + } + """; + + var dto = json.parseObject(content); + + assertThat(dto.getId()).isEqualTo(1L); + assertThat(dto.getComments()).hasSize(1); + assertThat(dto.getComments().iterator().next().getText()).isEqualTo("Comment"); + } +} + diff --git a/server/src/test/java/ru/practicum/shareit/item/dto/ItemDtoWithBookingsAndCommentsTest.java b/server/src/test/java/ru/practicum/shareit/item/dto/ItemDtoWithBookingsAndCommentsTest.java new file mode 100644 index 0000000..4012dcc --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/item/dto/ItemDtoWithBookingsAndCommentsTest.java @@ -0,0 +1,75 @@ +package ru.practicum.shareit.item.dto; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; +import ru.practicum.shareit.booking.dto.ShortBookingDto; + +import java.time.LocalDateTime; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@JsonTest +class ItemDtoWithBookingsAndCommentsTest { + + @Autowired + private JacksonTester json; + + @Test + void serializeItemDtoWithBookingsTest() throws Exception { + var dto = ItemDtoWithBookingsAndComments.builder() + .id(1L) + .name("Item") + .description("Desc") + .available(true) + .requestId(5L) + .lastBooking(ShortBookingDto.builder() + .start(LocalDateTime.parse("2024-01-01T12:00:00")) + .end(LocalDateTime.parse("2024-01-02T12:00:00")) + .build()) + .nextBooking(ShortBookingDto.builder() + .start(LocalDateTime.parse("2024-02-01T12:00:00")) + .end(LocalDateTime.parse("2024-02-02T12:00:00")) + .build()) + .comments(List.of(new CommentDto(1L, "Hi", "User", null))) + .build(); + + var result = json.write(dto); + + assertThat(result).hasJsonPath("$.lastBooking.start"); + assertThat(result).hasJsonPath("$.comments[0].text"); + } + + @Test + void deserializeItemDtoWithBookingsTest() throws Exception { + String content = """ + { + "id": 1, + "name": "Item", + "description": "Desc", + "available": true, + "requestId": 5, + "lastBooking": { + "start": "2024-01-01T12:00:00", + "end": "2024-01-02T12:00:00" + }, + "nextBooking": { + "start": "2024-02-01T12:00:00", + "end": "2024-02-02T12:00:00" + }, + "comments": [ + { "id": 1, "text": "Hi", "authorName": "User" } + ] + } + """; + + var dto = json.parseObject(content); + + assertThat(dto.getId()).isEqualTo(1L); + assertThat(dto.getLastBooking()).isNotNull(); + assertThat(dto.getComments()).hasSize(1); + } +} + diff --git a/server/src/test/java/ru/practicum/shareit/item/dto/ShortItemDtoTest.java b/server/src/test/java/ru/practicum/shareit/item/dto/ShortItemDtoTest.java new file mode 100644 index 0000000..189814a --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/item/dto/ShortItemDtoTest.java @@ -0,0 +1,42 @@ +package ru.practicum.shareit.item.dto; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; + +import static org.assertj.core.api.Assertions.assertThat; + +@JsonTest +class ShortItemDtoTest { + + @Autowired + private JacksonTester json; + + @Test + void serializeShortItemDtoTest() throws Exception { + var dto = ShortItemDto.builder() + .id(1L) + .name("Item") + .ownerId(10L) + .build(); + + var result = json.write(dto); + + assertThat(result).hasJsonPath("$.ownerId"); + assertThat(result).extractingJsonPathStringValue("$.name").isEqualTo("Item"); + } + + @Test + void deserializeShortItemDtoTest() throws Exception { + String content = """ + { "id": 1, "name": "Item", "ownerId": 10 } + """; + + var dto = json.parseObject(content); + + assertThat(dto.getId()).isEqualTo(1L); + assertThat(dto.getOwnerId()).isEqualTo(10L); + } +} + diff --git a/server/src/test/java/ru/practicum/shareit/request/ItemRequestControllerTest.java b/server/src/test/java/ru/practicum/shareit/request/ItemRequestControllerTest.java new file mode 100644 index 0000000..7958226 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/request/ItemRequestControllerTest.java @@ -0,0 +1,99 @@ +package ru.practicum.shareit.request; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import ru.practicum.shareit.request.dto.ItemRequestDto; +import ru.practicum.shareit.request.service.ItemRequestService; + +import java.time.LocalDateTime; +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static ru.practicum.shareit.util.Constants.USER_ID_HEADER; + +@WebMvcTest(ItemRequestController.class) +@RequiredArgsConstructor(onConstructor_ = @Autowired) +public class ItemRequestControllerTest { + + @Autowired + private MockMvc mockMvc; + @Autowired + private ObjectMapper objectMapper; + @MockBean + private ItemRequestService requestService; + private static final String REQUEST_PREFIX = "/requests"; + private static final Long REQUEST_ID = 1L; + private static final Long USER_ID = 1L; + private ItemRequestDto request; + private ItemRequestDto response; + + @BeforeEach + public void setUp() { + request = ItemRequestDto.builder() + .id(null) + .description("I need your jacket") + .requesterId(USER_ID) + .created(LocalDateTime.now()) + .items(List.of()) + .build(); + + response = request; + response.setId(REQUEST_ID); + } + + @Test + void createRequestTest() throws Exception { + when(requestService.create(anyLong(), any())).thenReturn(response); + + mockMvc.perform(post(REQUEST_PREFIX) + .header(USER_ID_HEADER, USER_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.id").value(REQUEST_ID)) + .andExpect(jsonPath("$.description").value("I need your jacket")); + } + + @Test + void getByUserTest() throws Exception { + when(requestService.getByUser(anyLong())).thenReturn(List.of(response)); + + mockMvc.perform(get(REQUEST_PREFIX) + .header(USER_ID_HEADER, USER_ID)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].id").value(REQUEST_ID)); + } + + @Test + void getAllTest() throws Exception { + when(requestService.getAll(anyLong())).thenReturn(List.of(response)); + + mockMvc.perform(get(REQUEST_PREFIX + "/all") + .header(USER_ID_HEADER, USER_ID)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].id").value(REQUEST_ID)); + } + + @Test + void getByIdTest() throws Exception { + when(requestService.getById(anyLong(), anyLong())).thenReturn(response); + + mockMvc.perform(get(REQUEST_PREFIX + "/" + REQUEST_ID) + .header(USER_ID_HEADER, USER_ID)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id").value(REQUEST_ID)) + .andExpect(jsonPath("$.description").value("I need your jacket")); + } +} diff --git a/server/src/test/java/ru/practicum/shareit/request/ItemRequestMapperTest.java b/server/src/test/java/ru/practicum/shareit/request/ItemRequestMapperTest.java new file mode 100644 index 0000000..fe5fe23 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/request/ItemRequestMapperTest.java @@ -0,0 +1,125 @@ +package ru.practicum.shareit.request; + +import org.junit.jupiter.api.Test; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.request.dto.ItemRequestDto; +import ru.practicum.shareit.request.mapper.ItemRequestMapper; +import ru.practicum.shareit.request.model.ItemRequest; +import ru.practicum.shareit.user.model.User; + +import java.time.LocalDateTime; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class ItemRequestMapperTest { + + @Test + void toItemRequestDtoTest() { + LocalDateTime now = LocalDateTime.now(); + + ItemRequest request = ItemRequest.builder() + .id(10L) + .description("Need a pencil") + .created(now) + .build(); + + ItemRequestDto dto = ItemRequestMapper.toItemRequestDto(request); + + assertThat(dto.getId()).isEqualTo(10L); + assertThat(dto.getDescription()).isEqualTo("Need a pencil"); + + assertThat(dto.getRequesterId()).isEqualTo(10L); + + assertThat(dto.getCreated()).isEqualTo(now); + assertThat(dto.getItems()).isNull(); + } + + @Test + void toItemRequestDtoWithItemsTest() { + LocalDateTime now = LocalDateTime.now(); + + ItemRequest request = ItemRequest.builder() + .id(1L) + .description("Need tools") + .created(now) + .build(); + + User owner = new User(); + owner.setId(10L); + + Item item1 = Item.builder() + .id(2L) + .name("Hammer") + .owner(owner) + .build(); + + Item item2 = Item.builder() + .id(3L) + .name("Saw") + .owner(owner) + .build(); + + ItemRequestDto dto = ItemRequestMapper.toItemRequestDto(request, List.of(item1, item2)); + + assertThat(dto.getItems()).hasSize(2); + + assertThat(dto.getItems().get(0).getId()).isEqualTo(2L); + assertThat(dto.getItems().get(0).getName()).isEqualTo("Hammer"); + assertThat(dto.getItems().get(0).getOwnerId()).isEqualTo(10L); + + assertThat(dto.getItems().get(1).getId()).isEqualTo(3L); + assertThat(dto.getItems().get(1).getName()).isEqualTo("Saw"); + assertThat(dto.getItems().get(1).getOwnerId()).isEqualTo(10L); + } + + + @Test + void toItemRequestDtoWithEmptyItemsTest() { + LocalDateTime now = LocalDateTime.now(); + + ItemRequest request = ItemRequest.builder() + .id(1L) + .description("Need a TV") + .created(now) + .build(); + + ItemRequestDto dto = ItemRequestMapper.toItemRequestDto(request, List.of()); + + assertThat(dto.getItems()).isEmpty(); + } + + @Test + void toItemRequestTest() { + LocalDateTime now = LocalDateTime.now(); + + ItemRequestDto dto = ItemRequestDto.builder() + .id(5L) + .description("Test desc") + .created(now) + .build(); + + ItemRequest request = ItemRequestMapper.toItemRequest(dto); + + assertThat(request.getId()).isEqualTo(5L); + assertThat(request.getDescription()).isEqualTo("Test desc"); + assertThat(request.getCreated()).isEqualTo(now); + } + + @Test + void toItemRequestCreatedNowIfNullTest() { + ItemRequestDto dto = ItemRequestDto.builder() + .id(7L) + .description("Some request") + .created(null) + .build(); + + ItemRequest request = ItemRequestMapper.toItemRequest(dto); + + assertThat(request.getId()).isEqualTo(7L); + assertThat(request.getDescription()).isEqualTo("Some request"); + + assertThat(request.getCreated()).isNotNull(); + } +} + diff --git a/server/src/test/java/ru/practicum/shareit/request/ItemRequestServiceImplTest.java b/server/src/test/java/ru/practicum/shareit/request/ItemRequestServiceImplTest.java new file mode 100644 index 0000000..9f1ac55 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/request/ItemRequestServiceImplTest.java @@ -0,0 +1,195 @@ +package ru.practicum.shareit.request; + +import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.transaction.annotation.Transactional; +import ru.practicum.shareit.exception.NotFoundException; +import ru.practicum.shareit.item.model.Item; +import ru.practicum.shareit.item.repository.ItemRepository; +import ru.practicum.shareit.request.dto.ItemRequestDto; +import ru.practicum.shareit.request.model.ItemRequest; +import ru.practicum.shareit.request.repository.ItemRequestRepository; +import ru.practicum.shareit.request.service.ItemRequestServiceImpl; +import ru.practicum.shareit.user.model.User; +import ru.practicum.shareit.user.repository.UserRepository; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; + +@SpringBootTest +@Transactional +@RequiredArgsConstructor(onConstructor_ = @Autowired) +public class ItemRequestServiceImplTest { + + private final ItemRequestServiceImpl requestService; + private final ItemRequestRepository requestRepository; + private final UserRepository userRepository; + private final ItemRepository itemRepository; + + User requester; + User owner; + ItemRequest request; + Item response; + + @BeforeEach + void setUp() { + requester = new User(null, "Requester", "requester@mail.com"); + owner = new User(null, "Owner", "owner@mail.com"); + + request = new ItemRequest( + null, + "Need a drill", + requester, + LocalDateTime.now().minusDays(1) + ); + + response = new Item( + null, + "Drill", + "Powerful drill", + true, + owner, + request + ); + } + + @Test + void createRequestShouldBeCreatedTest() { + requester = userRepository.save(requester); + + ItemRequestDto dto = ItemRequestDto.builder() + .description("New Request") + .build(); + + ItemRequestDto created = requestService.create(requester.getId(), dto); + + Optional fromDb = requestRepository.findById(created.getId()); + + assertThat(fromDb).isPresent(); + assertThat(fromDb.get().getDescription()).isEqualTo(dto.getDescription()); + assertThat(fromDb.get().getRequester().getId()).isEqualTo(requester.getId()); + } + + @Test + void createThrowIfUserNotFoundTest() { + ItemRequestDto dto = ItemRequestDto.builder() + .description("Need a chair") + .build(); + + assertThatThrownBy(() -> requestService.create(999L, dto)) + .isInstanceOf(NotFoundException.class) + .hasMessageContaining("999"); + } + + @Test + void getByUserShouldReturnRequestsWithItemsTest() { + requester = userRepository.save(requester); + owner = userRepository.save(owner); + + request = requestRepository.save(request); + response = itemRepository.save(response); + + Collection result = requestService.getByUser(requester.getId()); + + assertThat(result).isNotEmpty(); + ItemRequestDto dto = result.iterator().next(); + + assertThat(dto.getId()).isEqualTo(request.getId()); + assertThat(dto.getItems()).isNotEmpty(); + assertThat(dto.getItems().getFirst().getId()).isEqualTo(response.getId()); + } + + @Test + void getByUserShouldReturnEmptyListTest() { + requester = userRepository.save(requester); + + Collection result = requestService.getByUser(requester.getId()); + + assertThat(result).isEmpty(); + } + + @Test + void getByUserThrowIfUserNotFoundTest() { + assertThatThrownBy(() -> requestService.getByUser(999L)) + .isInstanceOf(NotFoundException.class); + } + + @Test + void getAllShouldReturnOtherUsersRequestsTest() { + requester = userRepository.save(requester); + owner = userRepository.save(owner); + + request = requestRepository.save(request); + + Collection result = requestService.getAll(owner.getId()); + + assertThat(result).isNotEmpty(); + assertThat(result.iterator().next().getId()).isEqualTo(request.getId()); + } + + @Test + void getAllShouldReturnEmptyListTest() { + requester = userRepository.save(requester); + + Collection result = requestService.getAll(requester.getId()); + + assertThat(result).isEmpty(); + } + + @Test + void getAllThrowIfUserNotFoundTest() { + assertThatThrownBy(() -> requestService.getAll(999L)) + .isInstanceOf(NotFoundException.class); + } + + @Test + void getByIdShouldReturnRequestWithItemsTest() { + requester = userRepository.save(requester); + owner = userRepository.save(owner); + + request = requestRepository.save(request); + response = itemRepository.save(response); + + ItemRequestDto dto = requestService.getById(requester.getId(), request.getId()); + + assertThat(dto).isNotNull(); + assertThat(dto.getId()).isEqualTo(request.getId()); + assertThat(dto.getItems()).hasSize(1); + assertThat(dto.getItems().getFirst().getId()).isEqualTo(response.getId()); + } + + @Test + void getByIdShouldReturnRequestWithoutItemsTest() { + requester = userRepository.save(requester); + + request = requestRepository.save(request); + + ItemRequestDto dto = requestService.getById(requester.getId(), request.getId()); + + assertThat(dto).isNotNull(); + assertThat(dto.getId()).isEqualTo(request.getId()); + assertThat(dto.getItems()).isEmpty(); + } + + @Test + void getByIdThrowIfUserNotFoundTest() { + assertThatThrownBy(() -> requestService.getById(999L, 1L)) + .isInstanceOf(NotFoundException.class); + } + + @Test + void getByIdThrowIfRequestNotFoundTest() { + requester = userRepository.save(requester); + + assertThatThrownBy(() -> requestService.getById(requester.getId(), 999L)) + .isInstanceOf(NotFoundException.class) + .hasMessageContaining("999"); + } +} \ No newline at end of file diff --git a/server/src/test/java/ru/practicum/shareit/request/dto/ItemRequestDtoTest.java b/server/src/test/java/ru/practicum/shareit/request/dto/ItemRequestDtoTest.java new file mode 100644 index 0000000..fd9e4e0 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/request/dto/ItemRequestDtoTest.java @@ -0,0 +1,71 @@ +package ru.practicum.shareit.request.dto; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; +import ru.practicum.shareit.item.dto.ShortItemDto; + +import java.time.LocalDateTime; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@JsonTest +class ItemRequestDtoTest { + + @Autowired + private JacksonTester json; + + @Test + void serializeItemRequestDtoTest() throws Exception { + var dto = ItemRequestDto.builder() + .id(1L) + .description("Need a Play Station") + .requesterId(10L) + .created(LocalDateTime.parse("2024-01-01T12:00:00")) + .items(List.of( + ShortItemDto.builder() + .id(5L) + .name("Play Station") + .ownerId(10L) + .build() + )) + .build(); + + var result = json.write(dto); + + assertThat(result).hasJsonPath("$.id"); + assertThat(result).hasJsonPath("$.items[0].name"); + + assertThat(result).extractingJsonPathStringValue("$.description") + .isEqualTo("Need a Play Station"); + + assertThat(result).extractingJsonPathNumberValue("$.items[0].id") + .isEqualTo(5); + } + + @Test + void deserializeItemRequestDtoTest() throws Exception { + String content = """ + { + "id": 1, + "description": "Need a Play Station", + "requesterId": 10, + "created": "2024-01-01T12:00:00", + "items": [ + { "id": 5, "name": "Play Station", "ownerId": 10 } + ] + } + """; + + var dto = json.parseObject(content); + + assertThat(dto.getId()).isEqualTo(1L); + assertThat(dto.getDescription()).isEqualTo("Need a Play Station"); + assertThat(dto.getItems()).hasSize(1); + assertThat(dto.getItems().getFirst().getName()).isEqualTo("Play Station"); + } +} + + diff --git a/server/src/test/java/ru/practicum/shareit/user/UserControllerTest.java b/server/src/test/java/ru/practicum/shareit/user/UserControllerTest.java new file mode 100644 index 0000000..8b70132 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/user/UserControllerTest.java @@ -0,0 +1,111 @@ +package ru.practicum.shareit.user; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import ru.practicum.shareit.user.dto.UpdateUserDto; +import ru.practicum.shareit.user.dto.UserDto; +import ru.practicum.shareit.user.service.UserService; + +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(UserController.class) +class UserControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private UserService userService; + + @Autowired + private ObjectMapper objectMapper; + + private UserDto userDto; + private UpdateUserDto updateUserDto; + + private static final Long USER_ID = 1L; + private static final String USERS_PREFIX = "/users"; + + @BeforeEach + void setup() { + userDto = UserDto.builder() + .id(USER_ID) + .name("John") + .email("john@example.com") + .build(); + + updateUserDto = UpdateUserDto.builder() + .id(USER_ID) + .name("Updated") + .email("upd@example.com") + .build(); + } + + @Test + void getAllUsersTest() throws Exception { + when(userService.getAll()).thenReturn(List.of(userDto)); + + mockMvc.perform(get(USERS_PREFIX) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].id").value(USER_ID)) + .andExpect(jsonPath("$[0].name").value("John")); + } + + @Test + void getUserByIdTest() throws Exception { + when(userService.getById(anyLong())).thenReturn(userDto); + + mockMvc.perform(get(USERS_PREFIX + "/" + USER_ID) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id").value(USER_ID)) + .andExpect(jsonPath("$.email").value("john@example.com")); + } + + @Test + void createUserTest() throws Exception { + when(userService.create(any())).thenReturn(userDto); + + mockMvc.perform(post(USERS_PREFIX) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(userDto))) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.id").value(USER_ID)) + .andExpect(jsonPath("$.name").value("John")); + } + + @Test + void updateUserTest() throws Exception { + when(userService.update(any())).thenReturn(userDto); + + mockMvc.perform(patch(USERS_PREFIX + "/" + USER_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(updateUserDto))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id").value(USER_ID)) + .andExpect(jsonPath("$.name").value("John")); + } + + @Test + void deleteUserTest() throws Exception { + mockMvc.perform(delete(USERS_PREFIX + "/" + USER_ID) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + + verify(userService, times(1)).delete(USER_ID); + } +} diff --git a/server/src/test/java/ru/practicum/shareit/user/UserMapperTest.java b/server/src/test/java/ru/practicum/shareit/user/UserMapperTest.java new file mode 100644 index 0000000..0411a8b --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/user/UserMapperTest.java @@ -0,0 +1,86 @@ +package ru.practicum.shareit.user; + +import org.junit.jupiter.api.Test; +import ru.practicum.shareit.user.dto.UpdateUserDto; +import ru.practicum.shareit.user.dto.UserDto; +import ru.practicum.shareit.user.mapper.UserMapper; +import ru.practicum.shareit.user.model.User; + +import static org.assertj.core.api.Assertions.assertThat; + +public class UserMapperTest { + + @Test + void toUserDtoTest() { + User user = new User(); + user.setId(1L); + user.setName("John Doe"); + user.setEmail("john@example.com"); + + UserDto dto = UserMapper.toUserDto(user); + + assertThat(dto.getId()).isEqualTo(1L); + assertThat(dto.getName()).isEqualTo("John Doe"); + assertThat(dto.getEmail()).isEqualTo("john@example.com"); + } + + @Test + void toUserFromUserDtoTest() { + UserDto dto = UserDto.builder() + .id(2L) + .name("Jane Doe") + .email("jane@example.com") + .build(); + + User user = UserMapper.toUser(dto); + + assertThat(user.getId()).isEqualTo(2L); + assertThat(user.getName()).isEqualTo("Jane Doe"); + assertThat(user.getEmail()).isEqualTo("jane@example.com"); + } + + @Test + void toUserFromUpdateUserDtoTest() { + UpdateUserDto dto = UpdateUserDto.builder() + .id(3L) + .name("Mike") + .email("mike@example.com") + .build(); + + User user = UserMapper.toUser(dto); + + assertThat(user.getId()).isEqualTo(3L); + assertThat(user.getName()).isEqualTo("Mike"); + assertThat(user.getEmail()).isEqualTo("mike@example.com"); + } + + @Test + void toUserFromUpdateUserDtoNameNullTest() { + UpdateUserDto dto = UpdateUserDto.builder() + .id(4L) + .name(null) + .email("test@example.com") + .build(); + + User user = UserMapper.toUser(dto); + + assertThat(user.getId()).isEqualTo(4L); + assertThat(user.getName()).isNull(); + assertThat(user.getEmail()).isEqualTo("test@example.com"); + } + + @Test + void toUserFromUpdateUserDtoEmailNullTest() { + UpdateUserDto dto = UpdateUserDto.builder() + .id(5L) + .name("Alice") + .email(null) + .build(); + + User user = UserMapper.toUser(dto); + + assertThat(user.getId()).isEqualTo(5L); + assertThat(user.getName()).isEqualTo("Alice"); + assertThat(user.getEmail()).isNull(); + } +} diff --git a/server/src/test/java/ru/practicum/shareit/user/UserServiceImplTest.java b/server/src/test/java/ru/practicum/shareit/user/UserServiceImplTest.java new file mode 100644 index 0000000..0de8a7c --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/user/UserServiceImplTest.java @@ -0,0 +1,173 @@ +package ru.practicum.shareit.user; + +import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.transaction.annotation.Transactional; +import ru.practicum.shareit.exception.DuplicateValidationException; +import ru.practicum.shareit.exception.NotFoundException; +import ru.practicum.shareit.user.dto.UpdateUserDto; +import ru.practicum.shareit.user.dto.UserDto; +import ru.practicum.shareit.user.model.User; +import ru.practicum.shareit.user.repository.UserRepository; +import ru.practicum.shareit.user.service.UserServiceImpl; + +import java.util.Collection; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertFalse; + +@SpringBootTest +@Transactional +@RequiredArgsConstructor(onConstructor_ = @Autowired) +class UserServiceImplTest { + + private final UserServiceImpl userService; + private final UserRepository userRepository; + + UserDto userDto; + UpdateUserDto updateUserDto; + + @BeforeEach + void setUp() { + userDto = UserDto.builder() + .name("User-1") + .email("user@gmail.com") + .build(); + + updateUserDto = UpdateUserDto.builder() + .name("Updated") + .email("updated@gmail.com") + .build(); + } + + @Test + void createUserSuccessTest() { + UserDto saved = userService.create(userDto); + + assertThat(saved).isNotNull(); + assertThat(saved.getId()).isNotNull(); + assertThat(saved.getName()).isEqualTo(userDto.getName()); + assertThat(saved.getEmail()).isEqualTo(userDto.getEmail()); + } + + @Test + void createThrowIfEmailNotUniqueTest() { + userRepository.save(new User(null, "Another", userDto.getEmail())); + + assertThatThrownBy(() -> userService.create(userDto)) + .isInstanceOf(DuplicateValidationException.class) + .hasMessageContaining("уже существует"); + } + + @Test + void getUserByIdTest() { + User saved = userRepository.save(new User(null, userDto.getName(), userDto.getEmail())); + + UserDto found = userService.getById(saved.getId()); + + assertThat(found).isNotNull(); + assertThat(found.getId()).isEqualTo(saved.getId()); + assertThat(found.getName()).isEqualTo(saved.getName()); + assertThat(found.getEmail()).isEqualTo(saved.getEmail()); + } + + @Test + void getUserByIdThrowIfUserNotFoundTest() { + assertThatThrownBy(() -> userService.getById(999L)) + .isInstanceOf(NotFoundException.class); + } + + @Test + void updateUserNameAndEmailTest() { + Long id = userRepository.save(new User(null, "Old", "old@mail.com")).getId(); + + updateUserDto.setId(id); + + UserDto updated = userService.update(updateUserDto); + + assertThat(updated.getName()).isEqualTo(updateUserDto.getName()); + assertThat(updated.getEmail()).isEqualTo(updateUserDto.getEmail()); + } + + @Test + void updateOnlyEmailIfNameNullTest() { + Long id = userRepository.save(new User(null, "Old", "old@mail.com")).getId(); + + updateUserDto.setId(id); + updateUserDto.setName(null); + + UserDto updated = userService.update(updateUserDto); + + assertThat(updated.getName()).isEqualTo("Old"); + assertThat(updated.getEmail()).isEqualTo(updateUserDto.getEmail()); + } + + @Test + void updateOnlyNameIfEmailNullTest() { + Long id = userRepository.save(new User(null, "Old", "old@mail.com")).getId(); + + updateUserDto.setId(id); + updateUserDto.setEmail(null); + + UserDto updated = userService.update(updateUserDto); + + assertThat(updated.getName()).isEqualTo(updateUserDto.getName()); + assertThat(updated.getEmail()).isEqualTo("old@mail.com"); + } + + @Test + void updateThrowIfEmailNotUniqueTest() { + User u1 = userRepository.save(new User(null, "U1", "mail1@test.com")); + User u2 = userRepository.save(new User(null, "U2", "mail2@test.com")); + + updateUserDto.setId(u2.getId()); + updateUserDto.setEmail(u1.getEmail()); // пытаемся поставить email другого пользователя + + assertThatThrownBy(() -> userService.update(updateUserDto)) + .isInstanceOf(DuplicateValidationException.class); + } + + @Test + void updateThrowIfUserNotFoundTest() { + updateUserDto.setId(999L); + + assertThatThrownBy(() -> userService.update(updateUserDto)) + .isInstanceOf(NotFoundException.class); + } + + @Test + void deleteUserTest() { + Long id = userRepository.save(new User(null, "Name", "mail@test.com")).getId(); + + assertDoesNotThrow(() -> userService.delete(id)); + + assertFalse(userRepository.findById(id).isPresent()); + } + + @Test + void deleteNotThrowIfUserNotExistTest() { + assertDoesNotThrow(() -> userService.delete(999L)); + } + + @Test + void getAllUsersTest() { + userRepository.save(new User(null, "U1", "u1@test.com")); + userRepository.save(new User(null, "U2", "u2@test.com")); + + Collection users = userService.getAll(); + + assertThat(users).hasSize(2); + } + + @Test + void getAllReturnEmptyListTest() { + Collection users = userService.getAll(); + + assertThat(users).isEmpty(); + } +} diff --git a/server/src/test/java/ru/practicum/shareit/user/dto/ShortUserDtoTest.java b/server/src/test/java/ru/practicum/shareit/user/dto/ShortUserDtoTest.java new file mode 100644 index 0000000..d83c2b1 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/user/dto/ShortUserDtoTest.java @@ -0,0 +1,42 @@ +package ru.practicum.shareit.user.dto; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; + +import static org.assertj.core.api.Assertions.assertThat; + +@JsonTest +class ShortUserDtoTest { + + @Autowired + private JacksonTester json; + + @Test + void serializeShortUserDtoTest() throws Exception { + var dto = ShortUserDto.builder() + .id(1L) + .build(); + + var result = json.write(dto); + + assertThat(result).hasJsonPath("$.id"); + assertThat(result).extractingJsonPathNumberValue("$.id").isEqualTo(1); + } + + @Test + void deserializeShortUserDtoTest() throws Exception { + String content = """ + { + "id": 5 + } + """; + + var dto = json.parseObject(content); + + assertThat(dto.getId()).isEqualTo(5L); + } +} + + diff --git a/server/src/test/java/ru/practicum/shareit/user/dto/UpdateUserDtoTest.java b/server/src/test/java/ru/practicum/shareit/user/dto/UpdateUserDtoTest.java new file mode 100644 index 0000000..d70cfa2 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/user/dto/UpdateUserDtoTest.java @@ -0,0 +1,51 @@ +package ru.practicum.shareit.user.dto; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; + +import static org.assertj.core.api.Assertions.assertThat; + +@JsonTest +class UpdateUserDtoTest { + + @Autowired + private JacksonTester json; + + @Test + void serializeUpdateUserDtoTest() throws Exception { + var dto = UpdateUserDto.builder() + .id(10L) + .name("John") + .email("john@example.com") + .build(); + + var result = json.write(dto); + + assertThat(result).hasJsonPath("$.id"); + assertThat(result).hasJsonPath("$.name"); + assertThat(result).hasJsonPath("$.email"); + + assertThat(result).extractingJsonPathStringValue("$.name").isEqualTo("John"); + assertThat(result).extractingJsonPathStringValue("$.email").isEqualTo("john@example.com"); + } + + @Test + void deserializeUpdateUserDtoTest() throws Exception { + String content = """ + { + "id": 2, + "name": "Kate", + "email": "kate@example.com" + } + """; + + var dto = json.parseObject(content); + + assertThat(dto.getId()).isEqualTo(2L); + assertThat(dto.getName()).isEqualTo("Kate"); + assertThat(dto.getEmail()).isEqualTo("kate@example.com"); + } +} + diff --git a/server/src/test/java/ru/practicum/shareit/user/dto/UserDtoTest.java b/server/src/test/java/ru/practicum/shareit/user/dto/UserDtoTest.java new file mode 100644 index 0000000..ccb4463 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/user/dto/UserDtoTest.java @@ -0,0 +1,51 @@ +package ru.practicum.shareit.user.dto; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; + +import static org.assertj.core.api.Assertions.assertThat; + +@JsonTest +class UserDtoTest { + + @Autowired + private JacksonTester json; + + @Test + void serializeUserDtoTest() throws Exception { + var dto = UserDto.builder() + .id(3L) + .name("Mike") + .email("mike@example.com") + .build(); + + var result = json.write(dto); + + assertThat(result).hasJsonPath("$.id"); + assertThat(result).hasJsonPath("$.name"); + assertThat(result).hasJsonPath("$.email"); + + assertThat(result).extractingJsonPathStringValue("$.name").isEqualTo("Mike"); + assertThat(result).extractingJsonPathStringValue("$.email").isEqualTo("mike@example.com"); + } + + @Test + void deserializeUserDtoTest() throws Exception { + String content = """ + { + "id": 4, + "name": "Sara", + "email": "sara@example.com" + } + """; + + var dto = json.parseObject(content); + + assertThat(dto.getId()).isEqualTo(4L); + assertThat(dto.getName()).isEqualTo("Sara"); + assertThat(dto.getEmail()).isEqualTo("sara@example.com"); + } +} + From 28123f5870996255fe0d10e736b37bb0909087fe Mon Sep 17 00:00:00 2001 From: Egor Ilyin Date: Mon, 8 Dec 2025 21:43:40 +0300 Subject: [PATCH 5/7] fix checkstyle --- .../java/ru/practicum/shareit/request/dto/ItemRequestDto.java | 1 - .../ru/practicum/shareit/booking/BookingControllerTest.java | 2 +- .../java/ru/practicum/shareit/booking/dto/BookingDtoTest.java | 1 + .../practicum/shareit/booking/dto/RequestBookingDtoTest.java | 1 + .../ru/practicum/shareit/booking/dto/ShortBookingDtoTest.java | 1 + .../java/ru/practicum/shareit/item/ItemControllerTest.java | 3 ++- .../java/ru/practicum/shareit/item/ItemServiceImplTest.java | 1 - .../java/ru/practicum/shareit/item/dto/CommentDtoTest.java | 1 + .../test/java/ru/practicum/shareit/item/dto/ItemDtoTest.java | 1 + .../shareit/item/dto/ItemDtoWithBookingsAndCommentsTest.java | 1 + .../java/ru/practicum/shareit/item/dto/ShortItemDtoTest.java | 1 + .../ru/practicum/shareit/request/dto/ItemRequestDtoTest.java | 1 + .../java/ru/practicum/shareit/user/dto/ShortUserDtoTest.java | 1 + .../java/ru/practicum/shareit/user/dto/UpdateUserDtoTest.java | 1 + .../test/java/ru/practicum/shareit/user/dto/UserDtoTest.java | 1 + 15 files changed, 14 insertions(+), 4 deletions(-) diff --git a/server/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java b/server/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java index ffa911f..067cf79 100644 --- a/server/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java +++ b/server/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java @@ -1,7 +1,6 @@ package ru.practicum.shareit.request.dto; import lombok.AccessLevel; -import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.experimental.FieldDefaults; diff --git a/server/src/test/java/ru/practicum/shareit/booking/BookingControllerTest.java b/server/src/test/java/ru/practicum/shareit/booking/BookingControllerTest.java index ab71dd5..506ae73 100644 --- a/server/src/test/java/ru/practicum/shareit/booking/BookingControllerTest.java +++ b/server/src/test/java/ru/practicum/shareit/booking/BookingControllerTest.java @@ -105,7 +105,7 @@ public void getUserBookings() throws Exception { void getOwnerBookings() throws Exception { when(bookingService.getAllByOwner(anyLong(), any())).thenReturn(List.of(responseBookingDto)); - mockMvc.perform(get(BOOKING_PREFIX+ "/owner") + mockMvc.perform(get(BOOKING_PREFIX + "/owner") .header(USER_ID_HEADER, USER_ID) .param("state", "ALL")) .andExpect(status().isOk()) diff --git a/server/src/test/java/ru/practicum/shareit/booking/dto/BookingDtoTest.java b/server/src/test/java/ru/practicum/shareit/booking/dto/BookingDtoTest.java index 0265819..01881b4 100644 --- a/server/src/test/java/ru/practicum/shareit/booking/dto/BookingDtoTest.java +++ b/server/src/test/java/ru/practicum/shareit/booking/dto/BookingDtoTest.java @@ -12,6 +12,7 @@ import static org.assertj.core.api.Assertions.assertThat; +@SuppressWarnings("checkstyle:RegexpSinglelineJava") @JsonTest public class BookingDtoTest { diff --git a/server/src/test/java/ru/practicum/shareit/booking/dto/RequestBookingDtoTest.java b/server/src/test/java/ru/practicum/shareit/booking/dto/RequestBookingDtoTest.java index 1603114..c46ce50 100644 --- a/server/src/test/java/ru/practicum/shareit/booking/dto/RequestBookingDtoTest.java +++ b/server/src/test/java/ru/practicum/shareit/booking/dto/RequestBookingDtoTest.java @@ -9,6 +9,7 @@ import static org.assertj.core.api.Assertions.assertThat; +@SuppressWarnings("checkstyle:RegexpSinglelineJava") @JsonTest public class RequestBookingDtoTest { diff --git a/server/src/test/java/ru/practicum/shareit/booking/dto/ShortBookingDtoTest.java b/server/src/test/java/ru/practicum/shareit/booking/dto/ShortBookingDtoTest.java index 53400b1..e549c44 100644 --- a/server/src/test/java/ru/practicum/shareit/booking/dto/ShortBookingDtoTest.java +++ b/server/src/test/java/ru/practicum/shareit/booking/dto/ShortBookingDtoTest.java @@ -9,6 +9,7 @@ import static org.assertj.core.api.Assertions.assertThat; +@SuppressWarnings("checkstyle:RegexpSinglelineJava") @JsonTest public class ShortBookingDtoTest { diff --git a/server/src/test/java/ru/practicum/shareit/item/ItemControllerTest.java b/server/src/test/java/ru/practicum/shareit/item/ItemControllerTest.java index 7db22fc..dd9c9fa 100644 --- a/server/src/test/java/ru/practicum/shareit/item/ItemControllerTest.java +++ b/server/src/test/java/ru/practicum/shareit/item/ItemControllerTest.java @@ -35,13 +35,14 @@ public class ItemControllerTest { private ObjectMapper objectMapper; @MockBean private ItemService itemService; + private static final String ITEM_PREFIX = "/items"; private static final Long ITEM_ID = 1L; private static final Long USER_ID = 1L; private ItemDto requestItemDto; private UpdateItemDto updateItemDto; private ItemDtoWithBookingsAndComments responseItemDto; - + @BeforeEach public void setUp() { requestItemDto = new ItemDto(null, "Thing", "Such a great thing", true, null, null); diff --git a/server/src/test/java/ru/practicum/shareit/item/ItemServiceImplTest.java b/server/src/test/java/ru/practicum/shareit/item/ItemServiceImplTest.java index 649455c..130017e 100644 --- a/server/src/test/java/ru/practicum/shareit/item/ItemServiceImplTest.java +++ b/server/src/test/java/ru/practicum/shareit/item/ItemServiceImplTest.java @@ -68,7 +68,6 @@ void setUp() { void getAllByUserTest() { Long ownerId = owner.getId(); Long itemId = item1.getId(); - bookingRepository.save(new Booking( null, LocalDateTime.now().minusDays(5), diff --git a/server/src/test/java/ru/practicum/shareit/item/dto/CommentDtoTest.java b/server/src/test/java/ru/practicum/shareit/item/dto/CommentDtoTest.java index 04d8a00..2cd2481 100644 --- a/server/src/test/java/ru/practicum/shareit/item/dto/CommentDtoTest.java +++ b/server/src/test/java/ru/practicum/shareit/item/dto/CommentDtoTest.java @@ -9,6 +9,7 @@ import static org.assertj.core.api.Assertions.assertThat; +@SuppressWarnings("checkstyle:RegexpSinglelineJava") @JsonTest class CommentDtoTest { diff --git a/server/src/test/java/ru/practicum/shareit/item/dto/ItemDtoTest.java b/server/src/test/java/ru/practicum/shareit/item/dto/ItemDtoTest.java index af8dd16..7a92c87 100644 --- a/server/src/test/java/ru/practicum/shareit/item/dto/ItemDtoTest.java +++ b/server/src/test/java/ru/practicum/shareit/item/dto/ItemDtoTest.java @@ -10,6 +10,7 @@ import static org.assertj.core.api.Assertions.assertThat; +@SuppressWarnings("checkstyle:RegexpSinglelineJava") @JsonTest class ItemDtoTest { diff --git a/server/src/test/java/ru/practicum/shareit/item/dto/ItemDtoWithBookingsAndCommentsTest.java b/server/src/test/java/ru/practicum/shareit/item/dto/ItemDtoWithBookingsAndCommentsTest.java index 4012dcc..9dca23a 100644 --- a/server/src/test/java/ru/practicum/shareit/item/dto/ItemDtoWithBookingsAndCommentsTest.java +++ b/server/src/test/java/ru/practicum/shareit/item/dto/ItemDtoWithBookingsAndCommentsTest.java @@ -11,6 +11,7 @@ import static org.assertj.core.api.Assertions.assertThat; +@SuppressWarnings("checkstyle:RegexpSinglelineJava") @JsonTest class ItemDtoWithBookingsAndCommentsTest { diff --git a/server/src/test/java/ru/practicum/shareit/item/dto/ShortItemDtoTest.java b/server/src/test/java/ru/practicum/shareit/item/dto/ShortItemDtoTest.java index 189814a..a495853 100644 --- a/server/src/test/java/ru/practicum/shareit/item/dto/ShortItemDtoTest.java +++ b/server/src/test/java/ru/practicum/shareit/item/dto/ShortItemDtoTest.java @@ -7,6 +7,7 @@ import static org.assertj.core.api.Assertions.assertThat; +@SuppressWarnings("checkstyle:RegexpSinglelineJava") @JsonTest class ShortItemDtoTest { diff --git a/server/src/test/java/ru/practicum/shareit/request/dto/ItemRequestDtoTest.java b/server/src/test/java/ru/practicum/shareit/request/dto/ItemRequestDtoTest.java index fd9e4e0..8065cc9 100644 --- a/server/src/test/java/ru/practicum/shareit/request/dto/ItemRequestDtoTest.java +++ b/server/src/test/java/ru/practicum/shareit/request/dto/ItemRequestDtoTest.java @@ -11,6 +11,7 @@ import static org.assertj.core.api.Assertions.assertThat; +@SuppressWarnings("checkstyle:RegexpSinglelineJava") @JsonTest class ItemRequestDtoTest { diff --git a/server/src/test/java/ru/practicum/shareit/user/dto/ShortUserDtoTest.java b/server/src/test/java/ru/practicum/shareit/user/dto/ShortUserDtoTest.java index d83c2b1..f98baca 100644 --- a/server/src/test/java/ru/practicum/shareit/user/dto/ShortUserDtoTest.java +++ b/server/src/test/java/ru/practicum/shareit/user/dto/ShortUserDtoTest.java @@ -7,6 +7,7 @@ import static org.assertj.core.api.Assertions.assertThat; +@SuppressWarnings("checkstyle:RegexpSinglelineJava") @JsonTest class ShortUserDtoTest { diff --git a/server/src/test/java/ru/practicum/shareit/user/dto/UpdateUserDtoTest.java b/server/src/test/java/ru/practicum/shareit/user/dto/UpdateUserDtoTest.java index d70cfa2..c68eae1 100644 --- a/server/src/test/java/ru/practicum/shareit/user/dto/UpdateUserDtoTest.java +++ b/server/src/test/java/ru/practicum/shareit/user/dto/UpdateUserDtoTest.java @@ -7,6 +7,7 @@ import static org.assertj.core.api.Assertions.assertThat; +@SuppressWarnings("checkstyle:RegexpSinglelineJava") @JsonTest class UpdateUserDtoTest { diff --git a/server/src/test/java/ru/practicum/shareit/user/dto/UserDtoTest.java b/server/src/test/java/ru/practicum/shareit/user/dto/UserDtoTest.java index ccb4463..13ec064 100644 --- a/server/src/test/java/ru/practicum/shareit/user/dto/UserDtoTest.java +++ b/server/src/test/java/ru/practicum/shareit/user/dto/UserDtoTest.java @@ -7,6 +7,7 @@ import static org.assertj.core.api.Assertions.assertThat; +@SuppressWarnings("checkstyle:RegexpSinglelineJava") @JsonTest class UserDtoTest { From c00b3ffff694388e075dc5198d8c2776063e79f6 Mon Sep 17 00:00:00 2001 From: Egor Ilyin Date: Mon, 8 Dec 2025 23:21:45 +0300 Subject: [PATCH 6/7] add exceptionHandler test --- .../exception/ExceptionsHandlerTest.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 server/src/test/java/ru/practicum/shareit/exception/ExceptionsHandlerTest.java diff --git a/server/src/test/java/ru/practicum/shareit/exception/ExceptionsHandlerTest.java b/server/src/test/java/ru/practicum/shareit/exception/ExceptionsHandlerTest.java new file mode 100644 index 0000000..bc83222 --- /dev/null +++ b/server/src/test/java/ru/practicum/shareit/exception/ExceptionsHandlerTest.java @@ -0,0 +1,50 @@ +package ru.practicum.shareit.exception; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class ExceptionsHandlerTest { + + private final ExceptionsHandler handler = new ExceptionsHandler(); + + @Test + void handleNotFoundError_shouldReturnErrorResponse() { + NotFoundException exception = new NotFoundException("Сущность не найдена"); + + ExceptionsHandler.ErrorResponse response = handler.handleNotFoundError(exception); + + assertThat(response.error()).isEqualTo("Не найдено"); + assertThat(response.details()).isEqualTo("Сущность не найдена"); + } + + @Test + void handleDuplicateError_shouldReturnErrorResponse() { + DuplicateValidationException exception = new DuplicateValidationException("Конфликт данных"); + + ExceptionsHandler.ErrorResponse response = handler.handleDuplicateError(exception); + + assertThat(response.error()).isEqualTo("Дупликация информации:"); + assertThat(response.details()).isEqualTo("Конфликт данных"); + } + + @Test + void handleForbiddenError_shouldReturnErrorResponse() { + ForbiddenException exception = new ForbiddenException("Нет прав"); + + ExceptionsHandler.ErrorResponse response = handler.handleForbiddenError(exception); + + assertThat(response.error()).isEqualTo("Доступ запрещен:"); + assertThat(response.details()).isEqualTo("Нет прав"); + } + + @Test + void handleValidationError_shouldReturnErrorResponse() { + ValidationException exception = new ValidationException("Некорректные данные"); + + ExceptionsHandler.ErrorResponse response = handler.handleValidationError(exception); + + assertThat(response.error()).isEqualTo("Ошибка запроса: "); + assertThat(response.details()).isEqualTo("Некорректные данные"); + } +} From 1f238cad2b47031b955f138d31f07cbb2565b71f Mon Sep 17 00:00:00 2001 From: Egor Ilyin Date: Tue, 9 Dec 2025 19:19:10 +0300 Subject: [PATCH 7/7] fix after review --- .../shareit/booking/BookingControllerTest.java | 3 +-- .../shareit/booking/BookingServiceImplTest.java | 12 ++++++------ .../shareit/request/ItemRequestServiceImplTest.java | 8 ++++---- .../practicum/shareit/user/UserServiceImplTest.java | 4 ++-- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/server/src/test/java/ru/practicum/shareit/booking/BookingControllerTest.java b/server/src/test/java/ru/practicum/shareit/booking/BookingControllerTest.java index 506ae73..bc766ae 100644 --- a/server/src/test/java/ru/practicum/shareit/booking/BookingControllerTest.java +++ b/server/src/test/java/ru/practicum/shareit/booking/BookingControllerTest.java @@ -37,13 +37,12 @@ public class BookingControllerTest { private static final Long ITEM_ID = 1L; private static final Long USER_ID = 1L; private static final Long BOOKING_ID = 1L; - private RequestBookingDto requestBookingDto; private BookingDto responseBookingDto; @BeforeEach public void setUp() { - requestBookingDto = new RequestBookingDto(ITEM_ID, + RequestBookingDto requestBookingDto = new RequestBookingDto(ITEM_ID, LocalDateTime.now().plusDays(1), LocalDateTime.now().plusDays(2)); diff --git a/server/src/test/java/ru/practicum/shareit/booking/BookingServiceImplTest.java b/server/src/test/java/ru/practicum/shareit/booking/BookingServiceImplTest.java index 96c3678..f18a7b5 100644 --- a/server/src/test/java/ru/practicum/shareit/booking/BookingServiceImplTest.java +++ b/server/src/test/java/ru/practicum/shareit/booking/BookingServiceImplTest.java @@ -34,12 +34,12 @@ public class BookingServiceImplTest { private final ItemRepository itemRepository; private final UserRepository userRepository; - User owner; - User booker; - Item item; - Booking currentBooking; - Booking futureRejectedBooking; - Booking pastWaitingBooking; + private User owner; + private User booker; + private Item item; + private Booking currentBooking; + private Booking futureRejectedBooking; + private Booking pastWaitingBooking; @BeforeEach void setUp() { diff --git a/server/src/test/java/ru/practicum/shareit/request/ItemRequestServiceImplTest.java b/server/src/test/java/ru/practicum/shareit/request/ItemRequestServiceImplTest.java index 9f1ac55..0541fd0 100644 --- a/server/src/test/java/ru/practicum/shareit/request/ItemRequestServiceImplTest.java +++ b/server/src/test/java/ru/practicum/shareit/request/ItemRequestServiceImplTest.java @@ -33,10 +33,10 @@ public class ItemRequestServiceImplTest { private final UserRepository userRepository; private final ItemRepository itemRepository; - User requester; - User owner; - ItemRequest request; - Item response; + private User requester; + private User owner; + private ItemRequest request; + private Item response; @BeforeEach void setUp() { diff --git a/server/src/test/java/ru/practicum/shareit/user/UserServiceImplTest.java b/server/src/test/java/ru/practicum/shareit/user/UserServiceImplTest.java index 0de8a7c..54f4612 100644 --- a/server/src/test/java/ru/practicum/shareit/user/UserServiceImplTest.java +++ b/server/src/test/java/ru/practicum/shareit/user/UserServiceImplTest.java @@ -29,8 +29,8 @@ class UserServiceImplTest { private final UserServiceImpl userService; private final UserRepository userRepository; - UserDto userDto; - UpdateUserDto updateUserDto; + private UserDto userDto; + private UpdateUserDto updateUserDto; @BeforeEach void setUp() {