From 38dd6791ba496e42323d1e633501a812b90e4449 Mon Sep 17 00:00:00 2001 From: Sergey Filippovskikh <116564864+SergikF@users.noreply.github.com> Date: Sat, 26 Apr 2025 20:48:03 +0300 Subject: [PATCH 1/6] =?UTF-8?q?=D0=92=D1=8B=D0=BF=D0=BE=D0=BB=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=2016=20=D1=81=D0=BF=D1=80=D0=B8=D0=BD=D1=82?= =?UTF-8?q?=D0=B0.=20=D0=9F=D0=B5=D1=80=D0=B2=D0=B8=D1=87=D0=BD=D0=B0?= =?UTF-8?q?=D1=8F=20=D0=B7=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=BA=D0=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 +- checkstyle.xml | 2 +- docker-compose.yml | 39 + gateway/Dockerfile | 5 + gateway/pom.xml | 70 + .../ru/practicum/shareit/ShareItGateway.java | 12 + .../shareit/booking/BookingClient.java | 58 + .../shareit/booking/BookingController.java | 100 + .../shareit/booking/BookingDtoInput.java | 28 + .../shareit/booking/BookingState.java | 16 + .../practicum/shareit/client/BaseClient.java | 121 + .../shareit/exception/ErrorHandler.java | 65 + .../exception/ValidationException.java | 0 .../shareit/item/CommentDtoInput.java | 18 + .../ru/practicum/shareit/item/ItemClient.java | 54 + .../shareit/item/ItemController.java | 122 + .../practicum/shareit/item/ItemDtoInput.java | 21 +- .../shareit/request/RequestClient.java | 41 + .../shareit/request/RequestController.java | 73 + .../shareit/request/RequestDtoInput.java | 18 + .../ru/practicum/shareit/user/UserClient.java | 46 + .../shareit/user/UserController.java | 81 + .../practicum/shareit/user/UserDtoInput.java | 18 +- .../shareit/validation/CreateObject.java | 0 .../shareit/validation/UpdateObject.java | 0 .../src/main/resources/application.properties | 7 + pom.xml | 97 +- postman_for_shareit_14.json | 2725 ----------------- ...eit_15.json => postman_for_shareit_16.json | 1213 ++------ server/Dockerfile | 5 + server/pom.xml | 86 + .../ru/practicum/shareit/ShareItServer.java | 8 +- .../ru/practicum/shareit/booking/Booking.java | 0 .../shareit/booking/BookingController.java | 3 +- .../practicum/shareit/booking/BookingDto.java | 0 .../shareit/booking/BookingDtoInput.java | 20 + .../shareit/booking/BookingDtoOutput.java | 0 .../shareit/booking/BookingDtoShort.java | 0 .../shareit/booking/BookingMapper.java | 0 .../shareit/booking/BookingRepository.java | 0 .../shareit/booking/BookingService.java | 0 .../shareit/booking/BookingServiceImpl.java | 13 - .../shareit/booking/BookingState.java | 2 +- .../shareit/booking/BookingStatus.java | 0 .../exception/DataConflictException.java | 0 .../shareit/exception/ErrorHandler.java | 0 .../shareit/exception/NotFoundException.java | 0 .../exception/RestrictedAccessException.java | 0 .../exception/ValidationException.java | 7 + .../ru/practicum/shareit/item/Comment.java | 0 .../ru/practicum/shareit/item/CommentDto.java | 5 - .../shareit/item/CommentDtoOutput.java | 0 .../shareit/item/CommentDtoShort.java | 0 .../practicum/shareit/item/CommentMapper.java | 0 .../shareit/item/CommentRepository.java | 0 .../java/ru/practicum/shareit/item/Item.java | 2 +- .../shareit/item/ItemController.java | 11 +- .../ru/practicum/shareit/item/ItemDto.java | 37 + .../practicum/shareit/item/ItemDtoInput.java | 20 + .../practicum/shareit/item/ItemDtoOutput.java | 4 +- .../shareit/item/ItemDtoRequest.java | 20 + .../practicum/shareit/item/ItemDtoShort.java | 0 .../ru/practicum/shareit/item/ItemMapper.java | 21 +- .../shareit/item/ItemRepository.java | 0 .../practicum/shareit/item/ItemService.java | 4 +- .../shareit/item/ItemServiceImpl.java | 48 +- .../ru/practicum/shareit/request/Request.java | 7 +- .../shareit/request/RequestController.java | 39 + .../practicum/shareit/request/RequestDto.java | 5 +- .../shareit/request/RequestDtoInput.java | 14 + .../shareit/request/RequestDtoItems.java | 26 + .../shareit/request/RequestMapper.java | 62 + .../shareit/request/RequestRepository.java | 17 + .../shareit/request/RequestService.java | 15 + .../shareit/request/RequestServiceImpl.java | 107 + .../java/ru/practicum/shareit/user/User.java | 0 .../shareit/user/UserController.java | 9 +- .../ru/practicum/shareit/user/UserDto.java | 29 + .../practicum/shareit/user/UserDtoOutput.java | 0 .../practicum/shareit/user/UserDtoShort.java | 0 .../ru/practicum/shareit/user/UserMapper.java | 0 .../shareit/user/UserRepository.java | 0 .../practicum/shareit/user/UserService.java | 0 .../shareit/user/UserServiceImpl.java | 0 .../src/main/resources/application.properties | 17 + {src => server/src}/main/resources/schema.sql | 0 .../shareit/booking/BookingDtoInput.java | 28 - .../request/ItemRequestController.java | 12 - src/main/resources/application.yaml | 20 - 89 files changed, 1828 insertions(+), 3951 deletions(-) create mode 100644 docker-compose.yml 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 create mode 100644 gateway/src/main/java/ru/practicum/shareit/booking/BookingDtoInput.java create mode 100644 gateway/src/main/java/ru/practicum/shareit/booking/BookingState.java create mode 100644 gateway/src/main/java/ru/practicum/shareit/client/BaseClient.java create mode 100644 gateway/src/main/java/ru/practicum/shareit/exception/ErrorHandler.java rename {src => gateway/src}/main/java/ru/practicum/shareit/exception/ValidationException.java (100%) create mode 100644 gateway/src/main/java/ru/practicum/shareit/item/CommentDtoInput.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/main/java/ru/practicum/shareit/item/ItemDto.java => gateway/src/main/java/ru/practicum/shareit/item/ItemDtoInput.java (72%) 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 create mode 100644 gateway/src/main/java/ru/practicum/shareit/request/RequestDtoInput.java 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/main/java/ru/practicum/shareit/user/UserDto.java => gateway/src/main/java/ru/practicum/shareit/user/UserDtoInput.java (59%) rename {src => gateway/src}/main/java/ru/practicum/shareit/validation/CreateObject.java (100%) rename {src => gateway/src}/main/java/ru/practicum/shareit/validation/UpdateObject.java (100%) create mode 100644 gateway/src/main/resources/application.properties delete mode 100644 postman_for_shareit_14.json rename postman_for_shareit_15.json => postman_for_shareit_16.json (81%) 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 (57%) rename {src => server/src}/main/java/ru/practicum/shareit/booking/Booking.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/booking/BookingController.java (97%) rename {src => server/src}/main/java/ru/practicum/shareit/booking/BookingDto.java (100%) create mode 100644 server/src/main/java/ru/practicum/shareit/booking/BookingDtoInput.java rename {src => server/src}/main/java/ru/practicum/shareit/booking/BookingDtoOutput.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/booking/BookingDtoShort.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/booking/BookingMapper.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/booking/BookingRepository.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/booking/BookingService.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/booking/BookingServiceImpl.java (95%) rename {src => server/src}/main/java/ru/practicum/shareit/booking/BookingState.java (57%) rename {src => server/src}/main/java/ru/practicum/shareit/booking/BookingStatus.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/exception/DataConflictException.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/exception/ErrorHandler.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/RestrictedAccessException.java (100%) create mode 100644 server/src/main/java/ru/practicum/shareit/exception/ValidationException.java rename {src => server/src}/main/java/ru/practicum/shareit/item/Comment.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/item/CommentDto.java (51%) rename {src => server/src}/main/java/ru/practicum/shareit/item/CommentDtoOutput.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/item/CommentDtoShort.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/item/CommentMapper.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/item/CommentRepository.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/item/Item.java (98%) rename {src => server/src}/main/java/ru/practicum/shareit/item/ItemController.java (85%) create mode 100644 server/src/main/java/ru/practicum/shareit/item/ItemDto.java create mode 100644 server/src/main/java/ru/practicum/shareit/item/ItemDtoInput.java rename {src => server/src}/main/java/ru/practicum/shareit/item/ItemDtoOutput.java (88%) create mode 100644 server/src/main/java/ru/practicum/shareit/item/ItemDtoRequest.java rename {src => server/src}/main/java/ru/practicum/shareit/item/ItemDtoShort.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/item/ItemMapper.java (89%) rename {src => server/src}/main/java/ru/practicum/shareit/item/ItemRepository.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/item/ItemService.java (73%) rename {src => server/src}/main/java/ru/practicum/shareit/item/ItemServiceImpl.java (86%) rename {src => server/src}/main/java/ru/practicum/shareit/request/Request.java (88%) create mode 100644 server/src/main/java/ru/practicum/shareit/request/RequestController.java rename src/main/java/ru/practicum/shareit/request/ItemRequestDto.java => server/src/main/java/ru/practicum/shareit/request/RequestDto.java (87%) create mode 100644 server/src/main/java/ru/practicum/shareit/request/RequestDtoInput.java create mode 100644 server/src/main/java/ru/practicum/shareit/request/RequestDtoItems.java create mode 100644 server/src/main/java/ru/practicum/shareit/request/RequestMapper.java create mode 100644 server/src/main/java/ru/practicum/shareit/request/RequestRepository.java create mode 100644 server/src/main/java/ru/practicum/shareit/request/RequestService.java create mode 100644 server/src/main/java/ru/practicum/shareit/request/RequestServiceImpl.java rename {src => server/src}/main/java/ru/practicum/shareit/user/User.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/user/UserController.java (73%) create mode 100644 server/src/main/java/ru/practicum/shareit/user/UserDto.java rename {src => server/src}/main/java/ru/practicum/shareit/user/UserDtoOutput.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/user/UserDtoShort.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/user/UserMapper.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/user/UserRepository.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/user/UserService.java (100%) rename {src => server/src}/main/java/ru/practicum/shareit/user/UserServiceImpl.java (100%) create mode 100644 server/src/main/resources/application.properties rename {src => server/src}/main/resources/schema.sql (100%) delete mode 100644 src/main/java/ru/practicum/shareit/booking/BookingDtoInput.java delete mode 100644 src/main/java/ru/practicum/shareit/request/ItemRequestController.java delete mode 100644 src/main/resources/application.yaml diff --git a/README.md b/README.md index d4b18b6..bd0da80 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ _java-shareit_ # Шеринг вещей -### Согласно задания спринта № 14 (add-controllers) +### Согласно задания спринта № 16 (add-item-requests-and-gateway) ## выполнено Филипповских Сергеем _**Когорта-53**_ -_**Для проверки выполнения 14 спринта использовался postman: -[postman_for_shareit_14.json](/postman_for_shareit_14.json)**_ +_**Для проверки выполнения 16 спринта использовался postman: +[postman_for_shareit_16.json](/postman_for_shareit_16.json)**_ ![](/er_diagram_shareit.png) diff --git a/checkstyle.xml b/checkstyle.xml index c28a0d3..05d5086 100644 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -161,7 +161,7 @@ - + diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..abe6570 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,39 @@ +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: + - "6541:5432" + environment: + - POSTGRES_PASSWORD=shareit + - POSTGRES_USER=shareit + - POSTGRES_DB=shareit + healthcheck: + test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER + timeout: 5s + interval: 5s + retries: 10 \ No newline at end of file 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..0aa75c3 --- /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..7975693 --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/booking/BookingClient.java @@ -0,0 +1,58 @@ +package ru.practicum.shareit.booking; + +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.exception.ValidationException; + +import java.util.Map; + +@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 addBooking(Long userId, BookingDtoInput requestDto) { + if (requestDto.getStart().equals(requestDto.getEnd())) { + throw new ValidationException("Начало и окончание бронирования не может быть одним и тем же моментом."); + } + if (requestDto.getEnd().isBefore(requestDto.getStart())) { + throw new ValidationException("Окончание бронирования не может быть раньше его начала."); + } + return post("", userId, requestDto); + } + + public ResponseEntity updateByOwner(Long userId, Long bookingId, Boolean approved) { + Map parameters = Map.of( + "approved", approved + ); + return patch("/" + bookingId + "?approved={approved}", userId, parameters, null); + } + + public ResponseEntity getWithStatusById(Long bookingId, Long userId) { + return get("/" + bookingId, userId); + } + + public ResponseEntity getByUserId(Long userId, BookingState state) { + return get("?state=" + state, userId); + } + + public ResponseEntity getByOwnerId(Long userId, BookingState state) { + return get("/owner?state=" + state, userId); + } +} 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..6d368fb --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/booking/BookingController.java @@ -0,0 +1,100 @@ +package ru.practicum.shareit.booking; + +import jakarta.validation.Valid; +import jakarta.validation.ValidationException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +@Controller +@RequestMapping(path = "/bookings") +@RequiredArgsConstructor +@Slf4j +@Validated +public class BookingController { + + private final BookingClient bookingClient; + + /** + * Создает бронирование. + * + * @param bookerId идентификатор пользователя, создающего бронирование + * @param bookingDto данные бронирования + * @return ResponseEntity с объектом, представляющим результат создания бронирования + */ + @PostMapping + public ResponseEntity addBooking(@RequestHeader("X-Sharer-User-Id") Long bookerId, + @Valid @RequestBody BookingDtoInput bookingDto) { + log.info("Создано бронирование {}, пользователем {}", bookingDto, bookerId); + return bookingClient.addBooking(bookerId, bookingDto); + } + + /** + * Обновляет бронирование владельцем. + * + * @param ownerId идентификатор владельца бронирования + * @param bookingId идентификатор бронирования + * @param approved флаг, указывающий, одобрено ли бронирование + * @return ResponseEntity с объектом, представляющим результат обновления бронирования + */ + @PatchMapping("/{bookingId}") + public ResponseEntity updateByOwner(@RequestHeader("X-Sharer-User-Id") Long ownerId, + @PathVariable Long bookingId, + @RequestParam Boolean approved) { + log.info("Обновление бронирования {}, владельцем {}, в состояние {}", bookingId, ownerId, approved); + return bookingClient.updateByOwner(ownerId, bookingId, approved); + } + + /** + * Получает данные о бронировании по его идентификатору. + * + * @param userId идентификатор пользователя, запрашивающего данные о бронировании + * @param bookingId идентификатор бронирования + * @return ResponseEntity с объектом, представляющим результат получения данных о бронировании + */ + @GetMapping("/{bookingId}") + public ResponseEntity getWithStatusById(@RequestHeader("X-Sharer-User-Id") Long userId, + @PathVariable Long bookingId) { + log.info("Получение данных о бронировании {}, пользователем {}", bookingId, userId); + return bookingClient.getWithStatusById( bookingId, userId); + } + + /** + * Получает все бронирования пользователя по его идентификатору и состоянию. + * + * @param userId идентификатор пользователя, запрашивающего данные о бронировании + * @param stateParam состояние бронирования + * @return ResponseEntity с объектом, представляющим результат получения данных о бронировании + */ + @GetMapping + public ResponseEntity getByUserId(@RequestHeader("X-Sharer-User-Id") Long userId, + @RequestParam(value = "state", + defaultValue = "ALL", required = false) String stateParam) { + BookingState state = BookingState.from(stateParam) + .orElseThrow(() -> + new ValidationException("Неизвестное состояние бронирования: " + stateParam)); + log.info("Получение всех бронирований пользователя{}, в состоянии {}", userId, state); + return bookingClient.getByUserId(userId, state); + } + + /** + * Получает все забронированные вещи пользователя по его идентификатору и состоянию. + * + * @param userId идентификатор пользователя, запрашивающего данные о бронировании + * @param stateParam состояние бронирования + * @return ResponseEntity с объектом, представляющим результат получения данных о бронировании + */ + @GetMapping("/owner") + public ResponseEntity getByOwnerId(@RequestHeader("X-Sharer-User-Id") Long userId, + @RequestParam(value = "state", defaultValue = "ALL", + required = false) String stateParam) { + BookingState state = BookingState.from(stateParam) + .orElseThrow(() -> + new ValidationException("Неизвестное состояние бронирования: " + stateParam)); + log.info("Получение всех забронированных вещей пользователя{}, в состоянии {}", userId, state); + return bookingClient.getByOwnerId(userId, state); + } +} \ No newline at end of file diff --git a/gateway/src/main/java/ru/practicum/shareit/booking/BookingDtoInput.java b/gateway/src/main/java/ru/practicum/shareit/booking/BookingDtoInput.java new file mode 100644 index 0000000..0441ea2 --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/booking/BookingDtoInput.java @@ -0,0 +1,28 @@ +package ru.practicum.shareit.booking; + +import jakarta.validation.constraints.Future; +import jakarta.validation.constraints.FutureOrPresent; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class BookingDtoInput { + + @NotNull(message = "При создании брони должна быть информация о вещи.") + private Long itemId; + + @FutureOrPresent(message = "Дата начала бронирования не должна быть в прошлом") + @NotNull(message = "Дата бронирования не должна быть пустой") + private LocalDateTime start; + + @Future(message = "Дата завершения бронирования должна быть в будущем") + @NotNull(message = "Дата бронирования не должна быть пустой") + private LocalDateTime end; + +} diff --git a/gateway/src/main/java/ru/practicum/shareit/booking/BookingState.java b/gateway/src/main/java/ru/practicum/shareit/booking/BookingState.java new file mode 100644 index 0000000..e633731 --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/booking/BookingState.java @@ -0,0 +1,16 @@ +package ru.practicum.shareit.booking; + +import java.util.Optional; + +public enum BookingState { + ALL, CURRENT, PAST, FUTURE, WAITING, REJECTED; + + public static Optional from(String stringState) { + for (ru.practicum.shareit.booking.BookingState state : values()) { + if (state.name().equalsIgnoreCase(stringState)) { + return Optional.of(state); + } + } + return Optional.empty(); + } +} 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..1a2d33a --- /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(); + } +} diff --git a/gateway/src/main/java/ru/practicum/shareit/exception/ErrorHandler.java b/gateway/src/main/java/ru/practicum/shareit/exception/ErrorHandler.java new file mode 100644 index 0000000..6e40c90 --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/exception/ErrorHandler.java @@ -0,0 +1,65 @@ +package ru.practicum.shareit.exception; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.validation.BindingResult; +import org.springframework.validation.ObjectError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.MissingRequestHeaderException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +@Slf4j +@RestControllerAdvice +public class ErrorHandler { + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ErrorResponse handleValidationException(final ValidationException e) { + log.error("{} - {}", HttpStatus.BAD_REQUEST, e.getMessage()); + return new ErrorResponse(e.getMessage()); + } + + + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ErrorResponse handleMethodArgumentNotValidException(final MethodArgumentNotValidException e) { + BindingResult bindingResult = e.getBindingResult(); + List allErrors = bindingResult.getAllErrors(); + String defaultMessage = allErrors.stream() + .map(error -> Objects.requireNonNull(error.getDefaultMessage())) + .collect(Collectors.joining(", ")); + log.error("{} - {}", HttpStatus.BAD_REQUEST, defaultMessage); + return new ErrorResponse(defaultMessage); + } + + + @ExceptionHandler + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public ErrorResponse handleRunTimeException(final RuntimeException e) { + log.error("{} - {}", HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage()); + return new ErrorResponse(e.getMessage()); + } + + @ExceptionHandler(MissingRequestHeaderException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ErrorResponse handleMissingRequestHeaderException(MissingRequestHeaderException e) { + log.error("{} - {}", HttpStatus.BAD_REQUEST, e.getMessage()); + return new ErrorResponse(e.getMessage()); + } + + @Getter + public static class ErrorResponse { + private final String error; + + public ErrorResponse(String error) { + this.error = error; + } + + } +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/exception/ValidationException.java b/gateway/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 gateway/src/main/java/ru/practicum/shareit/exception/ValidationException.java diff --git a/gateway/src/main/java/ru/practicum/shareit/item/CommentDtoInput.java b/gateway/src/main/java/ru/practicum/shareit/item/CommentDtoInput.java new file mode 100644 index 0000000..d15069d --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/item/CommentDtoInput.java @@ -0,0 +1,18 @@ +package ru.practicum.shareit.item; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CommentDtoInput { + + @NotNull(message = "Комментарий должен быть указан.") + @NotBlank(message = "Комментарий не может быть пустым.") + private String text; + +} 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..ddf344c --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/item/ItemClient.java @@ -0,0 +1,54 @@ +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; + +@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 addItem(Long userId, ItemDtoInput itemDto) { + return post("", userId, itemDto); + } + + public ResponseEntity updateItem(Long userId, Long idItem, ItemDtoInput itemDto) { + return patch("/" + idItem, userId, itemDto); + } + + public ResponseEntity getItemById(Long idItem, Long userId) { + return get("/" + idItem, userId); + } + + public ResponseEntity getAllItems(Long userId) { + return get("", userId); + } + + public ResponseEntity removeItem(Long userId, Long idItem) { + return delete("/" + idItem, userId); + } + + public ResponseEntity searchItems(String text) { + return get("/search?text=" + text); + } + + public ResponseEntity saveComment(Long userId, Long itemId, CommentDtoInput commentDto) { + return post("/" + itemId + "/comment", userId, 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..6de8007 --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/item/ItemController.java @@ -0,0 +1,122 @@ +package ru.practicum.shareit.item; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import ru.practicum.shareit.validation.CreateObject; +import ru.practicum.shareit.validation.UpdateObject; + +@Controller +@RequestMapping(path = "/items") +@RequiredArgsConstructor +@Slf4j +@Validated +public class ItemController { + private final ItemClient itemClient; + + /** + * Добавляет новую вещь. + * + * @param itemDto Данные вещи. + * @param idUser Идентификатор пользователя, добавляющего вещь. + * @return ResponseEntity с объектом, представляющим результат добавления вещи. + */ + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public ResponseEntity addItem(@Validated(CreateObject.class) @RequestBody ItemDtoInput itemDto, + @RequestHeader(value = "X-Sharer-User-Id") Long idUser) { + log.info("Получен запрос пользователем {} на добавление вещи {}", idUser, itemDto); + return itemClient.addItem(idUser, itemDto); + } + + /** + * Обновляет вещь. + * + * @param idItem Идентификатор вещи, которую нужно обновить. + * @param itemDto Данные вещи. + * @param idUser Идентификатор пользователя, обновляющего вещь. + * @return ResponseEntity с объектом, представляющим результат обновления вещи. + */ + @PatchMapping("/{idItem}") + public ResponseEntity updateItem(@PathVariable Long idItem, + @Validated(UpdateObject.class) @RequestBody ItemDtoInput itemDto, + @RequestHeader(value = "X-Sharer-User-Id") Long idUser) { + log.info("Получен запрос пользователем {} на обновление вещи {}", idUser, itemDto); + return itemClient.updateItem(idUser, idItem, itemDto); + } + + /** + * Возвращает вещь по ее идентификатору. + * + * @param idItem Идентификатор вещи, которую нужно вернуть. + * @param idUser Идентификатор пользователя, запрашивающего вещь. + * @return ResponseEntity с объектом, представляющим вещь по ее идентификатору. + */ + @GetMapping("/{idItem}") + public ResponseEntity getItemById(@PathVariable Long idItem, + @RequestHeader(value = "X-Sharer-User-Id") Long idUser) { + log.info("Получен запрос пользователем {} на получение вещи с id={}", idUser, idItem); + return itemClient.getItemById(idItem, idUser); + } + + /** + * Возвращает все вещи пользователя. + * + * @param idUser Идентификатор пользователя, вещи которого нужно вернуть. + * @return ResponseEntity с объектом, представляющим все вещи пользователя. + */ + @GetMapping + public ResponseEntity getAllItemsByUser(@RequestHeader(value = "X-Sharer-User-Id") Long idUser) { + log.info("Получен запрос пользователем {} на получение всех своих вещей", idUser); + return itemClient.getAllItems(idUser); + } + + /** + * Удаляет вещь по ее идентификатору. + * + * @param idItem Идентификатор вещи, которую нужно удалить. + * @param idUser Идентификатор пользователя, удаляющего вещь. + * @return ResponseEntity с объектом, представляющим результат удаления вещи. + */ + @DeleteMapping("/{idItem}") + public ResponseEntity removeItem(@PathVariable Long idItem, + @RequestHeader(value = "X-Sharer-User-Id") Long idUser) { + log.info("Получен запрос пользователем {} на удаление вещи с id={}", idUser, idItem); + return itemClient.removeItem(idUser, idItem); + } + + /** + * Ищет вещи по тексту. + * + * @param text Текст, по которому нужно искать вещи. + * @param idUser Идентификатор пользователя, инициирующего поиск. + * @return ResponseEntity с объектом, представляющим результат поиска вещей по тексту. + */ + @GetMapping("/search") + public ResponseEntity searchItemsByText(@RequestParam String text, + @RequestHeader(value = "X-Sharer-User-Id") Long idUser) { + log.info("Получен запрос пользователем {} на поиск вещей по тексту: {}", idUser, text); + return itemClient.searchItems(text); + } + + /** + * Добавляет комментарий к вещи. + * + * @param userId Идентификатор пользователя, добавляющего комментарий. + * @param itemId Идентификатор вещи, к которой добавляется комментарий. + * @param commentDto Данные комментария. + * @return ResponseEntity с объектом, представляющим результат добавления комментария. + */ + @PostMapping("/{itemId}/comment") + public ResponseEntity addCommentToItem(@RequestHeader("X-Sharer-User-Id") Long userId, + @PathVariable Long itemId, + @RequestBody CommentDtoInput commentDto) { + log.info("Получен запрос пользователем {} на добавление отзыва на вещь с id={} с текстом: {}", + userId, itemId, commentDto.getText()); + return itemClient.saveComment(userId, itemId, commentDto); + } +} diff --git a/src/main/java/ru/practicum/shareit/item/ItemDto.java b/gateway/src/main/java/ru/practicum/shareit/item/ItemDtoInput.java similarity index 72% rename from src/main/java/ru/practicum/shareit/item/ItemDto.java rename to gateway/src/main/java/ru/practicum/shareit/item/ItemDtoInput.java index 2fb9d3e..3173be9 100644 --- a/src/main/java/ru/practicum/shareit/item/ItemDto.java +++ b/gateway/src/main/java/ru/practicum/shareit/item/ItemDtoInput.java @@ -5,19 +5,12 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import ru.practicum.shareit.booking.Booking; -import ru.practicum.shareit.request.Request; -import ru.practicum.shareit.user.User; import ru.practicum.shareit.validation.CreateObject; -import java.util.List; - @Data @AllArgsConstructor @NoArgsConstructor -public class ItemDto { - - private Long id; +public class ItemDtoInput { @NotNull(groups = {CreateObject.class}, message = "Название вещи должно быть указано.") @NotBlank(groups = {CreateObject.class}, message = "Название вещи не может быть пустым.") @@ -30,16 +23,6 @@ public class ItemDto { @NotNull(groups = {CreateObject.class}, message = "Доступность вещи должна быть указана.") private Boolean available; - private User owner; - - private Request request; - - private List comments; - - private List bookings; - - private Booking lastBooking; - - private Booking nextBooking; + private Long requestId; } 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..ba2c019 --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/request/RequestClient.java @@ -0,0 +1,41 @@ +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; + +@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 addRequest(Long userId, RequestDtoInput requestDto) { + return post("", userId, requestDto); + } + + public ResponseEntity getRequests(Long userId) { + return get("", userId); + } + + public ResponseEntity getAllRequests(Long userId) { + return get("/all", userId); + } + + public ResponseEntity getRequestById(Long requestId) { + return get("/" + requestId); + } +} 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..6f1d1b4 --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/request/RequestController.java @@ -0,0 +1,73 @@ +package ru.practicum.shareit.request; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +@Controller +@RequestMapping(path = "/requests") +@RequiredArgsConstructor +@Slf4j +@Validated +public class RequestController { + + private final RequestClient requestClient; + + /** + * Добавляет новый запрос. + * + * @param requestorId Идентификатор пользователя, добавляющего запрос. + * @param requestDto Данные запроса. + * @return ResponseEntity с объектом, представляющим результат добавления запроса. + */ + @PostMapping + public ResponseEntity addRequest(@RequestHeader("X-Sharer-User-Id") Long requestorId, + @Valid @RequestBody RequestDtoInput requestDto) { + log.info("Получен запрос на добавление запроса с параметрами: {}", requestDto); + return requestClient.addRequest(requestorId, requestDto); + } + + /** + * Возвращает расширенный список запросов конкретного пользователя. + * + * @param requestorId Идентификатор пользователя, запросы которого нужно вернуть. + * @return ResponseEntity с объектом, представляющим список запросов пользователя. + */ + @GetMapping + public ResponseEntity getRequests(@RequestHeader("X-Sharer-User-Id") Long requestorId) { + log.info("Получен запрос на получение расширенного списка запросов пользователя с id: {}", requestorId); + return requestClient.getRequests(requestorId); + } + + /** + * Возвращает все запросы (за исключением запросов самого пользователя). + * + * @param requestorId Идентификатор пользователя. + * @return ResponseEntity с объектом, представляющим все запросы. + */ + @GetMapping("/all") + public ResponseEntity getAllRequests(@RequestHeader("X-Sharer-User-Id") Long requestorId) { + log.info("Получен запрос на получение всех запросов, кроме запросов самого пользователя с id: {}", requestorId); + return requestClient.getAllRequests(requestorId); + } + + /** + * Возвращает запрос по его идентификатору. + * + * @param requestorId Идентификатор пользователя, который делает запрос. + * @param requestId Идентификатор запроса, который нужно вернуть. + * @return ResponseEntity с объектом, представляющим запрос по его идентификатору. + */ + @GetMapping("/{requestId}") + public ResponseEntity getRequestsById(@RequestHeader("X-Sharer-User-Id") Long requestorId, + @PathVariable Long requestId) { + log.info("Получен запрос на получение запроса с id: {} по идентификатору пользователя с id: {}", + requestId, requestorId); + return requestClient.getRequestById(requestId); + } + +} \ No newline at end of file diff --git a/gateway/src/main/java/ru/practicum/shareit/request/RequestDtoInput.java b/gateway/src/main/java/ru/practicum/shareit/request/RequestDtoInput.java new file mode 100644 index 0000000..90542a2 --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/request/RequestDtoInput.java @@ -0,0 +1,18 @@ +package ru.practicum.shareit.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class RequestDtoInput { + + @NotNull(message = "Запрос не может быть пустым.") + @NotBlank(message = "Запрос не может быть пустым.") + private String description; + +} 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..fe6a014 --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/user/UserClient.java @@ -0,0 +1,46 @@ +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; + +@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 addUser( UserDtoInput userDto) { + return post("", userDto); + } + + public ResponseEntity updateUser(Long userId, UserDtoInput userDto) { + return patch("/" + userId, userDto); + } + + public ResponseEntity getUserById(Long userId) { + return get("/" + userId); + } + + public ResponseEntity getAllUsers() { + return get(API_PREFIX); + } + + public ResponseEntity removeUser(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..5c5f256 --- /dev/null +++ b/gateway/src/main/java/ru/practicum/shareit/user/UserController.java @@ -0,0 +1,81 @@ +package ru.practicum.shareit.user; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import ru.practicum.shareit.validation.CreateObject; +import ru.practicum.shareit.validation.UpdateObject; + +@Controller +@RequestMapping("/users") +@RequiredArgsConstructor +@Slf4j +@Validated +public class UserController { + private final UserClient userClient; + + /** + * Добавляет нового пользователя. + * + * @param userDto данные пользователя + * @return ResponseEntity с объектом, представляющим результат добавления пользователя + */ + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public ResponseEntity addUser(@Validated(CreateObject.class) @RequestBody UserDtoInput userDto) { + log.info("Добавление нового пользователя {}", userDto); + return userClient.addUser(userDto); + } + + /** + * Обновляет данные пользователя. + * + * @param idUser идентификатор пользователя, данные которого нужно обновить + * @param userDto новые данные пользователя + * @return ResponseEntity с объектом, представляющим результат обновления данных пользователя + */ + @PatchMapping("/{idUser}") + public ResponseEntity updateUser(@PathVariable Long idUser, + @Validated(UpdateObject.class) @RequestBody UserDtoInput userDto) { + log.info("Обновление данных пользователя с id {} на основе данных {}", idUser, userDto); + return userClient.updateUser(idUser, userDto); + } + + /** + * Получает данные пользователя по его идентификатору. + * + * @param idUser идентификатор пользователя, данные которого нужно получить + * @return ResponseEntity с объектом, представляющим результат получения данных пользователя + */ + @GetMapping("/{idUser}") + public ResponseEntity getUserById(@PathVariable Long idUser) { + log.info("Получение данных пользователя с id {}", idUser); + return userClient.getUserById(idUser); + } + + /** + * Получает всех пользователей. + * + * @return ResponseEntity с объектом, представляющим результат получения всех пользователей + */ + @GetMapping + public ResponseEntity getAllUsers() { + log.info("Получение всех пользователей"); + return userClient.getAllUsers(); + } + + /** + * Удаляет пользователя по его идентификатору. + * + * @param idUser идентификатор пользователя, которого нужно удалить + */ + @DeleteMapping("/{idUser}") + public ResponseEntity removeUser(@PathVariable Long idUser) { + log.info("Удаление пользователя с id {}", idUser); + return userClient.removeUser(idUser); + } +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/user/UserDto.java b/gateway/src/main/java/ru/practicum/shareit/user/UserDtoInput.java similarity index 59% rename from src/main/java/ru/practicum/shareit/user/UserDto.java rename to gateway/src/main/java/ru/practicum/shareit/user/UserDtoInput.java index 122a434..702908a 100644 --- a/src/main/java/ru/practicum/shareit/user/UserDto.java +++ b/gateway/src/main/java/ru/practicum/shareit/user/UserDtoInput.java @@ -6,33 +6,19 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import ru.practicum.shareit.booking.Booking; -import ru.practicum.shareit.item.Comment; -import ru.practicum.shareit.item.Item; import ru.practicum.shareit.validation.CreateObject; -import ru.practicum.shareit.validation.UpdateObject; - -import java.util.List; @Data @AllArgsConstructor @NoArgsConstructor -public class UserDto { - - private Long id; +public class UserDtoInput { @NotNull(groups = {CreateObject.class}, message = "Имя должно быть указано.") @NotBlank(groups = {CreateObject.class}, message = "Имя не может быть пустым.") private String name; @NotNull(groups = {CreateObject.class}, message = "Email должен быть указан.") - @Email(groups = {CreateObject.class, UpdateObject.class}, message = "Email должен быть указан корректно.") + @Email(groups = {CreateObject.class}, message = "Email должен быть указан корректно.") private String email; - private List items; - - private List bookings; - - private List comments; - } diff --git a/src/main/java/ru/practicum/shareit/validation/CreateObject.java b/gateway/src/main/java/ru/practicum/shareit/validation/CreateObject.java similarity index 100% rename from src/main/java/ru/practicum/shareit/validation/CreateObject.java rename to gateway/src/main/java/ru/practicum/shareit/validation/CreateObject.java diff --git a/src/main/java/ru/practicum/shareit/validation/UpdateObject.java b/gateway/src/main/java/ru/practicum/shareit/validation/UpdateObject.java similarity index 100% rename from src/main/java/ru/practicum/shareit/validation/UpdateObject.java rename to gateway/src/main/java/ru/practicum/shareit/validation/UpdateObject.java 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 2185679..79cba37 100644 --- a/pom.xml +++ b/pom.xml @@ -11,6 +11,7 @@ ru.practicum shareit + pom 0.0.1-SNAPSHOT ShareIt @@ -19,73 +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.postgresql - postgresql - - - - org.projectlombok - lombok - true - - - - org.springframework.boot - spring-boot-starter-test - test - - - - org.springframework.boot - spring-boot-starter-validation - - - - org.springframework.boot - spring-boot-starter-data-jpa - - - + + gateway + server + - - - src/main/resources - true - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - - - + + org.springframework.boot + spring-boot-maven-plugin + + + true + + + + org.projectlombok + lombok + + + + org.apache.maven.plugins maven-surefire-plugin @@ -232,17 +189,5 @@ - - coverage - - - - org.jacoco - jacoco-maven-plugin - - - - - - + \ No newline at end of file diff --git a/postman_for_shareit_14.json b/postman_for_shareit_14.json deleted file mode 100644 index d04cf55..0000000 --- a/postman_for_shareit_14.json +++ /dev/null @@ -1,2725 +0,0 @@ -{ - "info": { - "_postman_id": "f4a82602-e802-4363-87b5-c1814ccd49db", - "name": "Sprint 14 ShareIt (add-controllers)", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "23073145", - "_collection_link": "https://universal-shadow-295426.postman.co/workspace/My-Workspace~4200f6aa-0504-44b1-8a1d-707d0dcbd5ce/collection/13708500-f4a82602-e802-4363-87b5-c1814ccd49db?action=share&source=collection_link&creator=23073145" - }, - "item": [ - { - "name": "users", - "item": [ - { - "name": "Create user", - "event": [ - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user = rnd.getUser();\r", - " pm.collectionVariables.set(\"userName\", user.name);\r", - " pm.collectionVariables.set(\"userEmail\", user.email);\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200 or 201\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([200,201]);\r", - "});\r", - "pm.test(\"Response have body\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});\r", - "" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"{{userName}}\",\n \"email\": \"{{userEmail}}\"\n}" - }, - "url": { - "raw": "localhost:8080/users", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "users" - ] - } - }, - "response": [] - }, - { - "name": "Create user without email", - "event": [ - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user2 = rnd.getUser();\r", - " pm.collectionVariables.set(\"userName\", user2.name);\r", - " pm.collectionVariables.set(\"userEmail\", user2.email);\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 400\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([400, 500]);\r", - "});\r", - "pm.test(\"Response have body\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});\r", - "" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"{{userName}}\"\n}" - }, - "url": { - "raw": "localhost:8080/users", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "users" - ] - } - }, - "response": [] - }, - { - "name": "Create 2 users with same email", - "event": [ - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user1 = rnd.getUser();\r", - " us = await api.addUser(user1);\r", - " user2 = rnd.getUser();\r", - " user2.email = user1.email;\r", - " pm.collectionVariables.set(\"userName\", user2.name);\r", - " pm.collectionVariables.set(\"userEmail\", user2.email);\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 409\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([409, 500]);\r", - "});\r", - "pm.test(\"Response have body\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});\r", - "" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"{{userName}}\",\n \"email\": \"{{userEmail}}\"\n}" - }, - "url": { - "raw": "localhost:8080/users", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "users" - ] - } - }, - "response": [] - }, - { - "name": "Create user with invalid email", - "event": [ - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user = rnd.getUser();\r", - " pm.collectionVariables.set(\"userName\", user.name);\r", - " pm.collectionVariables.set(\"userEmail\", user.email);\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 400\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([400, 500]);\r", - "});\r", - "pm.test(\"Response have body\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});\r", - "" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"{{userName}}\",\n \"email\": \"user.com\"\n}" - }, - "url": { - "raw": "localhost:8080/users", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "users" - ] - } - }, - "response": [] - }, - { - "name": "User update", - "event": [ - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user = rnd.getUser();\r", - " us = await api.addUser(user);\r", - " pm.collectionVariables.set(\"userId\", us.id);\r", - " us = rnd.getUser()\r", - " pm.collectionVariables.set(\"userName\", us.name);\r", - " pm.collectionVariables.set(\"userEmail\", us.email);\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {\r", - " pm.response.to.be.ok;\r", - "});\r", - "pm.test(\"Response have body\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});\r", - "pm.test(\"Test user 'id' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('id');\r", - " var id = pm.collectionVariables.get(\"userId\");\r", - " pm.expect(jsonData.id, '\"id\" must be ' + id).to.eql(Number(id));\r", - "});\r", - "pm.test(\"Test user 'email' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('email');\r", - " var email = pm.collectionVariables.get(\"userEmail\");\r", - " pm.expect(jsonData.email, '\"email\" must be ' + email).to.eql(email);\r", - "});\r", - "pm.test(\"Test user 'name' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('name');\r", - " var name = pm.collectionVariables.get(\"userName\");\r", - " pm.expect(jsonData.name, '\"name\" must be ' + name).to.eql(name);\r", - "});\r", - "" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"{{userName}}\",\n \"email\": \"{{userEmail}}\"\n}" - }, - "url": { - "raw": "{{baseUrl}}/users/{{userId}}", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "users", - "{{userId}}" - ] - } - }, - "response": [] - }, - { - "name": "User update name", - "event": [ - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user = rnd.getUser();\r", - " us = await api.addUser(user);\r", - " pm.collectionVariables.set(\"userId\", us.id);\r", - " us = rnd.getUser()\r", - " pm.collectionVariables.set(\"userName\", us.name);\r", - " pm.collectionVariables.set(\"userEmail\", us.email);\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {\r", - " pm.response.to.be.ok;\r", - "});\r", - "pm.test(\"Response have body\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});\r", - "pm.test(\"Test user 'id' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('id');\r", - " var id = pm.collectionVariables.get(\"userId\");\r", - " pm.expect(jsonData.id, '\"id\" must be ' + id).to.eql(Number(id));\r", - "});\r", - "pm.test(\"Test user 'name' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('name');\r", - " var name = pm.collectionVariables.get(\"userName\");\r", - " pm.expect(jsonData.name, '\"name\" must be ' + name).to.eql(name);\r", - "});\r", - "" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"{{userName}}\"\n}" - }, - "url": { - "raw": "{{baseUrl}}/users/{{userId}}", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "users", - "{{userId}}" - ] - } - }, - "response": [] - }, - { - "name": "User update email", - "event": [ - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user = rnd.getUser();\r", - " us = await api.addUser(user);\r", - " pm.collectionVariables.set(\"userId\", us.id);\r", - " us = rnd.getUser()\r", - " pm.collectionVariables.set(\"userName\", us.name);\r", - " pm.collectionVariables.set(\"userEmail\", us.email);\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {\r", - " pm.response.to.be.ok;\r", - "});\r", - "pm.test(\"Response have body\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});\r", - "pm.test(\"Test user 'id' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('id');\r", - " var id = pm.collectionVariables.get(\"userId\");\r", - " pm.expect(jsonData.id, '\"id\" must be ' + id).to.eql(Number(id));\r", - "});\r", - "pm.test(\"Test user 'email' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('email');\r", - " var email = pm.collectionVariables.get(\"userEmail\");\r", - " pm.expect(jsonData.email, '\"email\" must be ' + email).to.eql(email);\r", - "});" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"email\": \"{{userEmail}}\"\n}" - }, - "url": { - "raw": "{{baseUrl}}/users/{{userId}}", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "users", - "{{userId}}" - ] - } - }, - "response": [] - }, - { - "name": "User update with existing email", - "event": [ - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user = rnd.getUser();\r", - " us = await api.addUser(user);\r", - " user2 = rnd.getUser();\r", - " us2 = await api.addUser(user2)\r", - " pm.collectionVariables.set(\"userId\", us2.id);\r", - " usa = rnd.getUser()\r", - " pm.collectionVariables.set(\"userName\", usa.name);\r", - " pm.collectionVariables.set(\"userEmail\", user.email);\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 409\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([409, 500]);\r", - "});\r", - "pm.test(\"Response have body\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});\r", - "" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"{{userName}}\",\n \"email\": \"{{userEmail}}\"\n}" - }, - "url": { - "raw": "{{baseUrl}}/users/{{userId}}", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "users", - "{{userId}}" - ] - } - }, - "response": [] - }, - { - "name": "Get user", - "event": [ - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user = rnd.getUser();\r", - " us = await api.addUser(user);\r", - " pm.collectionVariables.set(\"userId\", us.id);\r", - " pm.collectionVariables.set(\"userName\", us.name);\r", - " pm.collectionVariables.set(\"userEmail\", us.email);\r", - "\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {\r", - " pm.response.to.be.ok;\r", - "});\r", - "pm.test(\"Response have body\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});\r", - "pm.test(\"Test user 'id' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('id');\r", - " var id = pm.collectionVariables.get(\"userId\");\r", - " pm.expect(jsonData.id, '\"id\" must be ' + id).to.eql(Number(id));\r", - "});\r", - "pm.test(\"Test user 'email' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('email');\r", - " var email = pm.collectionVariables.get(\"userEmail\");\r", - " pm.expect(jsonData.email, '\"email\" must be ' + email).to.eql(email);\r", - "});\r", - "pm.test(\"Test user 'name' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('name');\r", - " var name = pm.collectionVariables.get(\"userName\");\r", - " pm.expect(jsonData.name, '\"name\" must be ' + name).to.eql(name);\r", - "});\r", - "" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "" - }, - "url": { - "raw": "{{baseUrl}}/users/{{userId}}", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "users", - "{{userId}}" - ] - } - }, - "response": [] - }, - { - "name": "User delete", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([200,204]);", - "});", - "" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user = rnd.getUser();\r", - " us = await api.addUser(user);\r", - " pm.collectionVariables.set(\"userId\", us.id);\r", - " pm.collectionVariables.set(\"userName\", us.name);\r", - " pm.collectionVariables.set(\"userEmail\", us.email);\r", - "\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "DELETE", - "header": [ - { - "key": "Accept", - "value": "*/*", - "type": "text" - } - ], - "url": { - "raw": "{{baseUrl}}/users/{{userId}}", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "users", - "{{userId}}" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "items", - "item": [ - { - "name": "Item create", - "event": [ - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " item = rnd.getItem();\r", - " pm.collectionVariables.set(\"item\", item);\r", - " pm.collectionVariables.set(\"itemName\", item.name);\r", - " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", - " pm.collectionVariables.set(\"itemDescription\", item.description);\r", - " user = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user.id);\r", - "\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200 or 201\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([200,201]);\r", - "});\r", - "pm.test(\"Response have body\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});\r", - "var item = pm.collectionVariables.get(\"item\");\r", - "\r", - "pm.test(\"Response data equal to request\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('id');\r", - " pm.expect(jsonData).to.have.property('name');\r", - " pm.expect(jsonData).to.have.property('description');\r", - " pm.expect(jsonData).to.have.property('available');\r", - " pm.expect(jsonData.name, `\"name\" must be ${item.name}`).to.eql(item.name);\r", - " pm.expect(jsonData.description, `\"description\" must be ${item.description}`).to.eql(item.description);\r", - " pm.expect(jsonData.available.toString(), `\"available\" must be ${item.available}`).to.eql(item.available.toString());\r", - "});" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}}\n}" - }, - "url": { - "raw": "localhost:8080/items", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "items" - ] - } - }, - "response": [] - }, - { - "name": "Item create without X-Sharer-User-Id", - "event": [ - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " item = rnd.getItem();\r", - " pm.collectionVariables.set(\"item\", item);\r", - " pm.collectionVariables.set(\"itemName\", item.name);\r", - " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", - " pm.collectionVariables.set(\"itemDescription\", item.description);\r", - " user = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user.id);\r", - "\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 400 or 500\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([500, 400]);\r", - "});\r", - "" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "disabled": true - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}}\n}" - }, - "url": { - "raw": "localhost:8080/items", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "items" - ] - } - }, - "response": [] - }, - { - "name": "Item create with non-existent user", - "event": [ - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " item = rnd.getItem();\r", - " pm.collectionVariables.set(\"item\", item);\r", - " pm.collectionVariables.set(\"itemName\", item.name);\r", - " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", - " pm.collectionVariables.set(\"itemDescription\", item.description);\r", - " user = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user.id + '1');\r", - "\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 404\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([404]);\r", - "});\r", - "" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}}\n}" - }, - "url": { - "raw": "localhost:8080/items", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "items" - ] - } - }, - "response": [] - }, - { - "name": "Item create without available field", - "event": [ - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " item = rnd.getItem();\r", - " pm.collectionVariables.set(\"item\", item);\r", - " pm.collectionVariables.set(\"itemName\", item.name);\r", - " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", - " pm.collectionVariables.set(\"itemDescription\", item.description);\r", - " user = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user.id);\r", - "\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 400\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([400, 500]);\r", - "});" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\"\n}" - }, - "url": { - "raw": "localhost:8080/items", - "host": [ - "localhost" - ], - "port": "8080", - "path": [ - "items" - ] - } - }, - "response": [] - }, - { - "name": "Item create with empty name field", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 400\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([400, 500]);", - "});", - "" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text" - }, - { - "key": "Content-Type", - "value": "application/json", - "type": "text" - }, - { - "key": "Accept", - "value": "*/*", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"\",\n \"description\": \"Аккумуляторная отвертка\",\n \"available\": true\n}" - }, - "url": { - "raw": "{{baseUrl}}/items", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "items" - ] - } - }, - "response": [] - }, - { - "name": "Item create with empty description field", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 400\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([400, 500]);", - "});", - "" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text" - }, - { - "key": "Content-Type", - "value": "application/json", - "type": "text" - }, - { - "key": "Accept", - "value": "*/*", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"Отвертка\",\n \"available\": true\n}" - }, - "url": { - "raw": "{{baseUrl}}/items", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "items" - ] - } - }, - "response": [] - }, - { - "name": "Item update", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.be.ok;", - "});", - "pm.test(\"Response have body\", function () {", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - "});", - "var item = pm.collectionVariables.get(\"item\");", - "", - "pm.test(\"Response data equal to request\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData).to.have.property('id');", - " pm.expect(jsonData).to.have.property('name');", - " pm.expect(jsonData).to.have.property('description');", - " pm.expect(jsonData).to.have.property('available');", - " pm.expect(jsonData.name, `\"name\" must be ${item.name}`).to.eql(item.name);", - " pm.expect(jsonData.description, `\"description\" must be ${item.description}`).to.eql(item.description);", - " pm.expect(jsonData.available.toString(), `\"available\" must be ${item.available}`).to.eql(item.available.toString());", - "});" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user.id);\r", - " item = rnd.getItem();\r", - " var it = await api.addItem(item, user.id)\r", - " item = rnd.getItem();\r", - " pm.collectionVariables.set(\"item\", item); \r", - " pm.collectionVariables.set(\"itemId\", it.id);\r", - " pm.collectionVariables.set(\"itemName\", item.name);\r", - " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", - " pm.collectionVariables.set(\"itemDescription\", item.description);\r", - "\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text" - }, - { - "key": "Content-Type", - "value": "application/json", - "type": "text" - }, - { - "key": "Accept", - "value": "*/*", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}}\n}" - }, - "url": { - "raw": "{{baseUrl}}/items/{{itemId}}", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "items", - "{{itemId}}" - ] - } - }, - "response": [] - }, - { - "name": "Item update without X-Sharer-User-Id", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 500\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([500, 400]);", - "});" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user.id);\r", - " item = rnd.getItem();\r", - " var it = await api.addItem(item, user.id)\r", - " item = rnd.getItem();\r", - " pm.collectionVariables.set(\"item\", item); \r", - " pm.collectionVariables.set(\"itemId\", it.id);\r", - " pm.collectionVariables.set(\"itemName\", item.name);\r", - " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", - " pm.collectionVariables.set(\"itemDescription\", item.description);\r", - "\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text", - "disabled": true - }, - { - "key": "Content-Type", - "value": "application/json", - "type": "text" - }, - { - "key": "Accept", - "value": "*/*", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}}\n}" - }, - "url": { - "raw": "{{baseUrl}}/items/{{itemId}}", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "items", - "{{itemId}}" - ] - } - }, - "response": [] - }, - { - "name": "Item update with other user", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 404\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([404, 403]);", - "});" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user.id + 1);\r", - " item = rnd.getItem();\r", - " var it = await api.addItem(item, user.id)\r", - " item = rnd.getItem();\r", - " pm.collectionVariables.set(\"item\", item); \r", - " pm.collectionVariables.set(\"itemId\", it.id);\r", - " pm.collectionVariables.set(\"itemName\", item.name);\r", - " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", - " pm.collectionVariables.set(\"itemDescription\", item.description);\r", - "\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text" - }, - { - "key": "Content-Type", - "value": "application/json", - "type": "text" - }, - { - "key": "Accept", - "value": "*/*", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}}\n}" - }, - "url": { - "raw": "{{baseUrl}}/items/{{itemId}}", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "items", - "{{itemId}}" - ] - } - }, - "response": [] - }, - { - "name": "Item update available field", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.be.ok;", - "});", - "pm.test(\"Response have body\", function () {", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - "});", - "var item = pm.collectionVariables.get(\"item\");", - "", - "pm.test(\"Response data equal to request\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData).to.have.property('id');", - " pm.expect(jsonData).to.have.property('available');", - " pm.expect(jsonData.available.toString(), `\"available\" must be ${item.available}`).to.eql(item.available.toString());", - "});" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user.id);\r", - " item = rnd.getItem();\r", - " var it = await api.addItem(item, user.id)\r", - " item = rnd.getItem();\r", - " pm.collectionVariables.set(\"item\", item); \r", - " pm.collectionVariables.set(\"itemId\", it.id);\r", - " pm.collectionVariables.set(\"itemName\", item.name);\r", - " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", - " pm.collectionVariables.set(\"itemDescription\", item.description);\r", - "\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text" - }, - { - "key": "Content-Type", - "value": "application/json", - "type": "text" - }, - { - "key": "Accept", - "value": "*/*", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"available\": {{itemAvailable}}\n}" - }, - "url": { - "raw": "{{baseUrl}}/items/{{itemId}}", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "items", - "{{itemId}}" - ] - } - }, - "response": [] - }, - { - "name": "Item update description field", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.be.ok;", - "});", - "pm.test(\"Response have body\", function () {", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - "});", - "var item = pm.collectionVariables.get(\"item\");", - "", - "pm.test(\"Response data equal to request\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData).to.have.property('id');", - " pm.expect(jsonData).to.have.property('name');", - " pm.expect(jsonData).to.have.property('description');", - " pm.expect(jsonData).to.have.property('available');", - " pm.expect(jsonData.description, `\"description\" must be ${item.description}`).to.eql(item.description);", - "});" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user.id);\r", - " item = rnd.getItem();\r", - " var it = await api.addItem(item, user.id)\r", - " item = rnd.getItem();\r", - " pm.collectionVariables.set(\"item\", item); \r", - " pm.collectionVariables.set(\"itemId\", it.id);\r", - " pm.collectionVariables.set(\"itemName\", item.name);\r", - " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", - " pm.collectionVariables.set(\"itemDescription\", item.description);\r", - "\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text" - }, - { - "key": "Content-Type", - "value": "application/json", - "type": "text" - }, - { - "key": "Accept", - "value": "*/*", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"description\": \"{{itemDescription}}\"\n}" - }, - "url": { - "raw": "{{baseUrl}}/items/{{itemId}}", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "items", - "{{itemId}}" - ] - } - }, - "response": [] - }, - { - "name": "Item update name field", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.be.ok;", - "});", - "pm.test(\"Response have body\", function () {", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - "});", - "var item = pm.collectionVariables.get(\"item\");", - "", - "pm.test(\"Response data equal to request\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData).to.have.property('id');", - " pm.expect(jsonData).to.have.property('name');", - " pm.expect(jsonData).to.have.property('description');", - " pm.expect(jsonData).to.have.property('available');", - " pm.expect(jsonData.name, `\"name\" must be ${item.name}`).to.eql(item.name);", - "});" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user.id);\r", - " item = rnd.getItem();\r", - " var it = await api.addItem(item, user.id)\r", - " item = rnd.getItem();\r", - " pm.collectionVariables.set(\"item\", item); \r", - " pm.collectionVariables.set(\"itemId\", it.id);\r", - " pm.collectionVariables.set(\"itemName\", item.name);\r", - " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", - " pm.collectionVariables.set(\"itemDescription\", item.description);\r", - "\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text" - }, - { - "key": "Content-Type", - "value": "application/json", - "type": "text" - }, - { - "key": "Accept", - "value": "*/*", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"{{itemName}}\"\n}" - }, - "url": { - "raw": "{{baseUrl}}/items/{{itemId}}", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "items", - "{{itemId}}" - ] - } - }, - "response": [] - }, - { - "name": "Item get", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.be.ok;", - "});", - "pm.test(\"Response have body\", function () {", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - "});", - "var item = pm.collectionVariables.get(\"item\");", - "", - "pm.test(\"Response data equal to request\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData).to.have.property('id');", - " pm.expect(jsonData).to.have.property('name');", - " pm.expect(jsonData).to.have.property('description');", - " pm.expect(jsonData).to.have.property('available');", - " pm.expect(jsonData.name, `\"name\" must be ${item.name}`).to.eql(item.name);", - " pm.expect(jsonData.description, `\"description\" must be ${item.description}`).to.eql(item.description);", - " pm.expect(jsonData.available.toString(), `\"available\" must be ${item.available}`).to.eql(item.available.toString());", - "});" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user.id);\r", - " item = await api.addItem(rnd.getItem(), user.id)\r", - " pm.collectionVariables.set(\"item\", item);\r", - " pm.collectionVariables.set(\"itemId\", item.id);\r", - " pm.collectionVariables.set(\"itemName\", item.name);\r", - " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", - " pm.collectionVariables.set(\"itemDescription\", item.description);\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text" - }, - { - "key": "Accept", - "value": "*/*", - "type": "text" - } - ], - "url": { - "raw": "{{baseUrl}}/items/{{itemId}}", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "items", - "{{itemId}}" - ] - } - }, - "response": [] - }, - { - "name": "Get all items from user", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.be.ok;", - "});", - "pm.test(\"Test list item response\", function () {", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.length, 'List length must be 2').to.eql(2);", - "});", - "", - "" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user.id);\r", - " await api.addItem(rnd.getItem(), user.id)\r", - " await api.addItem(rnd.getItem(), user.id)\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text" - }, - { - "key": "Accept", - "value": "*/*", - "type": "text" - } - ], - "url": { - "raw": "{{baseUrl}}/items", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "items" - ] - } - }, - "response": [] - }, - { - "name": "Item search", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.be.ok;", - "});", - "pm.test(\"Test list item response\", function () {", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.length, 'List length must be 1').to.eql(1);", - " pm.expect(jsonData[0].name.toUpperCase(), 'Name should include ' + pm.collectionVariables.get(\"searchString\")).to.eql(pm.collectionVariables.get(\"searchString\"))", - "});", - "" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user.id);\r", - " it = rnd.getItem()\r", - " it.available = true\r", - " item = await api.addItem(it, user.id)\r", - " pm.collectionVariables.set(\"item\", item);\r", - " pm.collectionVariables.set(\"itemId\", item.id);\r", - " pm.collectionVariables.set(\"itemName\", item.name);\r", - " pm.collectionVariables.set(\"searchString\", item.name.toUpperCase());\r", - " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", - " pm.collectionVariables.set(\"itemDescription\", item.description);\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text" - }, - { - "key": "Accept", - "value": "*/*", - "type": "text" - } - ], - "url": { - "raw": "{{baseUrl}}/items/search?text={{searchString}}", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "items", - "search" - ], - "query": [ - { - "key": "text", - "value": "{{searchString}}" - } - ] - } - }, - "response": [] - }, - { - "name": "Item search unavailable", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.be.ok;", - "});", - "pm.test(\"Test list item response\", function () {", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.length, 'List length must be 0').to.eql(0);", - "});", - "" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user.id);\r", - " it = rnd.getItem()\r", - " it.available = false\r", - " item = await api.addItem(it, user.id)\r", - " pm.collectionVariables.set(\"item\", item);\r", - " pm.collectionVariables.set(\"itemId\", item.id);\r", - " pm.collectionVariables.set(\"itemName\", item.name);\r", - " pm.collectionVariables.set(\"searchString\", item.name.toUpperCase());\r", - " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", - " pm.collectionVariables.set(\"itemDescription\", item.description);\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text" - }, - { - "key": "Accept", - "value": "*/*", - "type": "text" - } - ], - "url": { - "raw": "{{baseUrl}}/items/search?text={{searchString}}", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "items", - "search" - ], - "query": [ - { - "key": "text", - "value": "{{searchString}}" - } - ] - } - }, - "response": [] - }, - { - "name": "Item search empty", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.be.ok;", - "});", - "pm.test(\"Test search item response\", function () {", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.length, 'List length must be 0').to.eql(0);", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text" - }, - { - "key": "Accept", - "value": "*/*", - "type": "text" - } - ], - "url": { - "raw": "{{baseUrl}}/items/search?text=", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "items", - "search" - ], - "query": [ - { - "key": "text", - "value": "" - } - ] - } - }, - "response": [] - } - ] - } - ], - "event": [ - { - "listen": "prerequest", - "script": { - "type": "text/javascript", - "packages": {}, - "exec": [ - "API = class {\r", - " constructor(postman, verbose = false, baseUrl = \"http://localhost:8080\") {\r", - " this.baseUrl = baseUrl;\r", - " this.pm = postman;\r", - " this._verbose = verbose;\r", - " }\r", - "\r", - " async addUser(user, id=0, verbose=null) {\r", - " return this.post(\"/users\", user, id, \"Ошибка при добавлении нового пользователя: \", verbose);\r", - " }\r", - "\r", - " async addItem(item, id=0, verbose=null) {\r", - " return this.post(\"/items\", item, id, \"Ошибка при добавлении новой вещи: \", verbose);\r", - " }\r", - "\r", - " async addRequest(request, id=0, verbose=null) {\r", - " return this.post(\"/requests\", request, id, \"Ошибка при добавлении нового запроса: \", verbose);\r", - " }\r", - " \r", - " async post(path, body, id=0, errorText = \"Ошибка при выполнении post-запроса: \", verbose=null) {\r", - " return this.sendRequest(\"POST\", path, body, id, errorText, verbose);\r", - " }\r", - "\r", - " async patch(path, body = null, id=0, errorText = \"Ошибка при выполнении patch-запроса: \", verbose=null) {\r", - " return this.sendRequest(\"PATCH\", path, body, id, errorText, verbose);\r", - " }\r", - "\r", - " async get(path, body = null, id=0, errorText = \"Ошибка при выполнении get-запроса: \", verbose=null) {\r", - " return this.sendRequest(\"GET\", path, body, id, errorText, verbose);\r", - " }\r", - "\r", - " async put(path, body = null, id=0, errorText = \"Ошибка при выполнении put-запроса: \", verbose=null) {\r", - " return this.sendRequest(\"PUT\", path, body, id, errorText, verbose);\r", - " }\r", - "\r", - " async delete(path, body = null, id=0, errorText = \"Ошибка при выполнении delte-запроса: \", verbose=null) {\r", - " return this.sendRequest(\"DELETE\", path, body, id, errorText, verbose);\r", - " }\r", - "\r", - " async sendRequest(method, path, body=null, id=0, errorText = \"Ошибка при выполнении запроса: \", verbose=null) {\r", - " return new Promise((resolve, reject) => {\r", - " verbose = verbose == null ? this._verbose : verbose;\r", - " var req = {};\r", - " if (id == 0){\r", - " req = {\r", - " url: this.baseUrl + path,\r", - " method: method,\r", - " body: body == null ? \"\" : JSON.stringify(body),\r", - " header: { \"Content-Type\": \"application/json\"},\r", - " };\r", - " }else{\r", - " req = {\r", - " url: this.baseUrl + path,\r", - " method: method,\r", - " body: body == null ? \"\" : JSON.stringify(body),\r", - " header: [{\r", - " \"key\": \"X-Sharer-User-Id\",\r", - " \"value\": id,\r", - " \"type\": \"text\",\r", - " },\r", - " {\r", - " \"key\": \"Content-Type\",\r", - " \"name\": \"Content-Type\",\r", - " \"value\": \"application/json\",\r", - " \"type\": \"text\"\r", - " }]\r", - " };\r", - " }\r", - " if(verbose) {\r", - " console.log(\"Отправляю запрос: \", req);\r", - " }\r", - "\r", - " try {\r", - " this.pm.sendRequest(req, (error, response) => {\r", - " if(error || (response.code >= 400 && response.code <= 599)) {\r", - " let err = error ? error : JSON.stringify(response.json());\r", - " console.error(\"При выполнении запроса к серверу возникла ошибка.\\n\", err,\r", - " \"\\nДля отладки проблемы повторите такой же запрос к вашей программе \" + \r", - " \"на локальном компьютере. Данные запроса:\\n\", JSON.stringify(request));\r", - "\r", - " reject(new Error(errorText + err));\r", - " }\r", - " if(verbose) {\r", - " console.log(\"Результат обработки запроса: код состояния - \", response.code, \", тело: \", response.json());\r", - " }\r", - " if (response.stream.length === 0){\r", - " resolve(null);\r", - " }else{\r", - " resolve(response.json());\r", - " }\r", - " });\r", - " \r", - " } catch(err) {\r", - " if(verbose) {\r", - " console.error(errorText, err);\r", - " }\r", - " return Promise.reject(err);\r", - " }\r", - " });\r", - " }\r", - "};\r", - "\r", - "RandomUtils = class {\r", - " constructor() {}\r", - "\r", - " getUser() {\r", - " return {\r", - " name: pm.variables.replaceIn('{{$randomFullName}}'),\r", - " email: pm.variables.replaceIn('{{$randomEmail}}'),\r", - " };\r", - " }\r", - "\r", - " getRequest() {\r", - " return {\r", - " description: this.getWord(50)\r", - " };\r", - " }\r", - "\r", - " getItem() {\r", - " return {\r", - " name: this.getWord(10),\r", - " description: this.getWord(50),\r", - " available: pm.variables.replaceIn('{{$randomBoolean}}')\t\r", - " };\r", - " }\r", - "\r", - " getItemForRequest(id) {\r", - " return {\r", - " name: this.getWord(10),\r", - " description: this.getWord(50),\r", - " available: pm.variables.replaceIn('{{$randomBoolean}}'),\r", - " requestId: id\r", - " };\r", - " }\r", - "\r", - " getFilm(director=null) {\r", - " let date = new Date(new Date(1960, 0, 1).getTime() + Math.random() * (new Date(2010, 0, 1).getTime() - new Date(1960, 0, 1).getTime()));\r", - " var toReturn = {\r", - " name: this.getWord(15),\r", - " description: this.getWord(50),\r", - " releaseDate: date.toISOString().slice(0,10),\r", - " duration: Math.floor(Math.random() * (180 - 60 + 1) + 60),\r", - " mpa: { id: Math.floor(Math.random() * (5 - 1 + 1) + 1)},\r", - " genres: [{ id: Math.floor(Math.random() * (6 - 1 + 1) + 1)}]\r", - " };\r", - " if (director!==null)\r", - " toReturn.directors = [{ id: director.id}];\r", - " return toReturn;\r", - " }\r", - "\r", - "\r", - " getWord(length = 1) {\r", - " let result = '';\r", - " const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\r", - " const charactersLength = characters.length;\r", - " let counter = 0;\r", - " while (counter < length) {\r", - " result += characters.charAt(Math.floor(Math.random() * charactersLength));\r", - " counter += 1;\r", - " }\r", - " return result;\r", - " }\r", - "\r", - " getName(length = 1) {\r", - " let result = '';\r", - " const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';\r", - " const charactersLength = characters.length;\r", - " let counter = 0;\r", - " while (counter < length) {\r", - " result += characters.charAt(Math.floor(Math.random() * charactersLength));\r", - " counter += 1;\r", - " }\r", - " return result;\r", - " }\r", - "\r", - "}" - ] - } - }, - { - "listen": "test", - "script": { - "type": "text/javascript", - "packages": {}, - "exec": [ - "" - ] - } - } - ], - "variable": [ - { - "key": "baseUrl", - "value": "http://localhost:8080" - }, - { - "key": "userName", - "value": "" - }, - { - "key": "userEmail", - "value": "" - }, - { - "key": "userId", - "value": "1", - "type": "string" - }, - { - "key": "item", - "value": "" - }, - { - "key": "itemName", - "value": "" - }, - { - "key": "itemAvailable", - "value": "" - }, - { - "key": "itemDescription", - "value": "" - }, - { - "key": "itemId", - "value": "" - }, - { - "key": "searchString", - "value": "" - } - ] -} diff --git a/postman_for_shareit_15.json b/postman_for_shareit_16.json similarity index 81% rename from postman_for_shareit_15.json rename to postman_for_shareit_16.json index 26845fe..6e87b6b 100644 --- a/postman_for_shareit_15.json +++ b/postman_for_shareit_16.json @@ -1,10 +1,10 @@ { "info": { - "_postman_id": "069d256e-037e-4bd9-a5de-be6910726adc", - "name": "Sprint 15 ShareIt (add-bookings)", + "_postman_id": "7fc26681-0775-4307-885f-fd53560f0317", + "name": "Sprint 16 ShareIt (add-item-requests-and-gateway)", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", "_exporter_id": "23073145", - "_collection_link": "https://universal-shadow-295426.postman.co/workspace/My-Workspace~4200f6aa-0504-44b1-8a1d-707d0dcbd5ce/collection/13708500-069d256e-037e-4bd9-a5de-be6910726adc?action=share&source=collection_link&creator=23073145" + "_collection_link": "https://universal-shadow-295426.postman.co/workspace/My-Workspace~4200f6aa-0504-44b1-8a1d-707d0dcbd5ce/collection/13708500-7fc26681-0775-4307-885f-fd53560f0317?action=share&source=collection_link&creator=23073145" }, "item": [ { @@ -921,10 +921,10 @@ ] }, { - "name": "items", + "name": "Item", "item": [ { - "name": "Item create", + "name": "Create Item", "event": [ { "listen": "prerequest", @@ -1027,7 +1027,7 @@ "response": [] }, { - "name": "Item create without X-Sharer-User-Id", + "name": "Create Item on request", "event": [ { "listen": "prerequest", @@ -1038,13 +1038,18 @@ " const rnd = new RandomUtils();\r", "\r", " try {\r", + " user1 = await api.addUser(rnd.getUser());\r", + " var request = await api.addRequest(rnd.getRequest(), user1.id);\r", + " pm.collectionVariables.set(\"requestId\", request.id);\r", + " user2 = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user2.id);\r", + "\r", " item = rnd.getItem();\r", " pm.collectionVariables.set(\"item\", item);\r", " pm.collectionVariables.set(\"itemName\", item.name);\r", " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", " pm.collectionVariables.set(\"itemDescription\", item.description);\r", - " user = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user.id);\r", + "\r", "\r", " } catch(err) {\r", " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", @@ -1075,10 +1080,25 @@ "listen": "test", "script": { "exec": [ - "pm.test(\"Status code is 400 or 500\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([500, 400]);\r", + "pm.test(\"Status code is 200 or 201\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200,201]);\r", "});\r", - "" + "pm.test(\"Response have body\", function () {\r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "var item = pm.collectionVariables.get(\"item\");\r", + "\r", + "pm.test(\"Response data equal to request\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.have.property('id');\r", + " pm.expect(jsonData).to.have.property('name');\r", + " pm.expect(jsonData).to.have.property('description');\r", + " pm.expect(jsonData).to.have.property('available');\r", + " pm.expect(jsonData.name, `\"name\" must be ${item.name}`).to.eql(item.name);\r", + " pm.expect(jsonData.description, `\"description\" must be ${item.description}`).to.eql(item.description);\r", + " pm.expect(jsonData.available.toString(), `\"available\" must be ${item.available}`).to.eql(item.available.toString());\r", + "});" ], "type": "text/javascript", "packages": {} @@ -1094,13 +1114,12 @@ }, { "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "disabled": true + "value": "{{userId}}" } ], "body": { "mode": "raw", - "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}}\n}" + "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}},\n \"requestId\": {{requestId}}\n}" }, "url": { "raw": "localhost:8080/items", @@ -1116,7 +1135,7 @@ "response": [] }, { - "name": "Item create with non-existent user", + "name": "Create Item without name on request", "event": [ { "listen": "prerequest", @@ -1127,13 +1146,18 @@ " const rnd = new RandomUtils();\r", "\r", " try {\r", + " user1 = await api.addUser(rnd.getUser());\r", + " var request = await api.addRequest(rnd.getRequest(), user1.id);\r", + " pm.collectionVariables.set(\"requestId\", request.id);\r", + " user2 = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user2.id);\r", + "\r", " item = rnd.getItem();\r", " pm.collectionVariables.set(\"item\", item);\r", " pm.collectionVariables.set(\"itemName\", item.name);\r", " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", " pm.collectionVariables.set(\"itemDescription\", item.description);\r", - " user = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user.id + '1');\r", + "\r", "\r", " } catch(err) {\r", " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", @@ -1164,10 +1188,17 @@ "listen": "test", "script": { "exec": [ - "pm.test(\"Status code is 404\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([404]);\r", + "pm.test(\"Status code is 400\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([400, 500]);\r", "});\r", - "" + "pm.test(\"Response have body\", function () {\r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "pm.test(\"Response data have error\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.have.property('error');\r", + "});" ], "type": "text/javascript", "packages": {} @@ -1188,7 +1219,7 @@ ], "body": { "mode": "raw", - "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}}\n}" + "raw": "{\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}},\n \"requestId\": {{requestId}}\n}" }, "url": { "raw": "localhost:8080/items", @@ -1204,7 +1235,7 @@ "response": [] }, { - "name": "Item create without available field", + "name": "Create Item without description on request", "event": [ { "listen": "prerequest", @@ -1215,13 +1246,18 @@ " const rnd = new RandomUtils();\r", "\r", " try {\r", + " user1 = await api.addUser(rnd.getUser());\r", + " var request = await api.addRequest(rnd.getRequest(), user1.id);\r", + " pm.collectionVariables.set(\"requestId\", request.id);\r", + " user2 = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user2.id);\r", + "\r", " item = rnd.getItem();\r", " pm.collectionVariables.set(\"item\", item);\r", " pm.collectionVariables.set(\"itemName\", item.name);\r", " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", " pm.collectionVariables.set(\"itemDescription\", item.description);\r", - " user = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user.id);\r", + "\r", "\r", " } catch(err) {\r", " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", @@ -1254,6 +1290,14 @@ "exec": [ "pm.test(\"Status code is 400\", function () {\r", " pm.expect(pm.response.code).to.be.oneOf([400, 500]);\r", + "});\r", + "pm.test(\"Response have body\", function () {\r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "pm.test(\"Response data have error\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.have.property('error');\r", "});" ], "type": "text/javascript", @@ -1275,7 +1319,7 @@ ], "body": { "mode": "raw", - "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\"\n}" + "raw": "{\n \"name\": \"{{itemName}}\",\n \"available\": {{itemAvailable}},\n \"requestId\": {{requestId}}\n}" }, "url": { "raw": "localhost:8080/items", @@ -1291,140 +1335,8 @@ "response": [] }, { - "name": "Item create with empty name field", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 400\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([400, 500]);", - "});", - "" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text" - }, - { - "key": "Content-Type", - "value": "application/json", - "type": "text" - }, - { - "key": "Accept", - "value": "*/*", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"\",\n \"description\": \"Аккумуляторная отвертка\",\n \"available\": true\n}" - }, - "url": { - "raw": "{{baseUrl}}/items", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "items" - ] - } - }, - "response": [] - }, - { - "name": "Item create with empty description field", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 400\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([400, 500]);", - "});", - "" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text" - }, - { - "key": "Content-Type", - "value": "application/json", - "type": "text" - }, - { - "key": "Accept", - "value": "*/*", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"Отвертка\",\n \"available\": true\n}" - }, - "url": { - "raw": "{{baseUrl}}/items", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "items" - ] - } - }, - "response": [] - }, - { - "name": "Item update", + "name": "Create Item without available on request", "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.be.ok;", - "});", - "pm.test(\"Response have body\", function () {", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - "});", - "var item = pm.collectionVariables.get(\"item\");", - "", - "pm.test(\"Response data equal to request\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData).to.have.property('id');", - " pm.expect(jsonData).to.have.property('name');", - " pm.expect(jsonData).to.have.property('description');", - " pm.expect(jsonData).to.have.property('available');", - " pm.expect(jsonData.name, `\"name\" must be ${item.name}`).to.eql(item.name);", - " pm.expect(jsonData.description, `\"description\" must be ${item.description}`).to.eql(item.description);", - " pm.expect(jsonData.available.toString(), `\"available\" must be ${item.available}`).to.eql(item.available.toString());", - "});" - ], - "type": "text/javascript", - "packages": {} - } - }, { "listen": "prerequest", "script": { @@ -1434,17 +1346,19 @@ " const rnd = new RandomUtils();\r", "\r", " try {\r", - " user = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user.id);\r", - " item = rnd.getItem();\r", - " var it = await api.addItem(item, user.id)\r", + " user1 = await api.addUser(rnd.getUser());\r", + " var request = await api.addRequest(rnd.getRequest(), user1.id);\r", + " pm.collectionVariables.set(\"requestId\", request.id);\r", + " user2 = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user2.id);\r", + "\r", " item = rnd.getItem();\r", - " pm.collectionVariables.set(\"item\", item); \r", - " pm.collectionVariables.set(\"itemId\", it.id);\r", + " pm.collectionVariables.set(\"item\", item);\r", " pm.collectionVariables.set(\"itemName\", item.name);\r", " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", " pm.collectionVariables.set(\"itemDescription\", item.description);\r", "\r", + "\r", " } catch(err) {\r", " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", " }\r", @@ -1469,694 +1383,65 @@ "type": "text/javascript", "packages": {} } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text" - }, - { - "key": "Content-Type", - "value": "application/json", - "type": "text" - }, - { - "key": "Accept", - "value": "*/*", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}}\n}" }, - "url": { - "raw": "{{baseUrl}}/items/{{itemId}}", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "items", - "{{itemId}}" - ] - } - }, - "response": [] - }, - { - "name": "Item update without X-Sharer-User-Id", - "event": [ { "listen": "test", "script": { "exec": [ - "pm.test(\"Status code is 500\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([500, 400]);", + "pm.test(\"Status code is 400\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([400, 500]);\r", + "});\r", + "pm.test(\"Response have body\", function () {\r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "pm.test(\"Response data have error\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.have.property('error');\r", "});" ], "type": "text/javascript", "packages": {} } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user.id);\r", - " item = rnd.getItem();\r", - " var it = await api.addItem(item, user.id)\r", - " item = rnd.getItem();\r", - " pm.collectionVariables.set(\"item\", item); \r", - " pm.collectionVariables.set(\"itemId\", it.id);\r", - " pm.collectionVariables.set(\"itemName\", item.name);\r", - " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", - " pm.collectionVariables.set(\"itemDescription\", item.description);\r", - "\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text", - "disabled": true - }, - { - "key": "Content-Type", - "value": "application/json", - "type": "text" - }, - { - "key": "Accept", - "value": "*/*", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}}\n}" - }, - "url": { - "raw": "{{baseUrl}}/items/{{itemId}}", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "items", - "{{itemId}}" - ] - } - }, - "response": [] - }, - { - "name": "Item update with other user", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 404\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([404, 403]);", - "});" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user.id + 1);\r", - " item = rnd.getItem();\r", - " var it = await api.addItem(item, user.id)\r", - " item = rnd.getItem();\r", - " pm.collectionVariables.set(\"item\", item); \r", - " pm.collectionVariables.set(\"itemId\", it.id);\r", - " pm.collectionVariables.set(\"itemName\", item.name);\r", - " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", - " pm.collectionVariables.set(\"itemDescription\", item.description);\r", - "\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text" - }, - { - "key": "Content-Type", - "value": "application/json", - "type": "text" - }, - { - "key": "Accept", - "value": "*/*", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}}\n}" - }, - "url": { - "raw": "{{baseUrl}}/items/{{itemId}}", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "items", - "{{itemId}}" - ] - } - }, - "response": [] - }, - { - "name": "Item update available field", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.be.ok;", - "});", - "pm.test(\"Response have body\", function () {", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - "});", - "var item = pm.collectionVariables.get(\"item\");", - "", - "pm.test(\"Response data equal to request\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData).to.have.property('id');", - " pm.expect(jsonData).to.have.property('available');", - " pm.expect(jsonData.available.toString(), `\"available\" must be ${item.available}`).to.eql(item.available.toString());", - "});" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user.id);\r", - " item = rnd.getItem();\r", - " var it = await api.addItem(item, user.id)\r", - " item = rnd.getItem();\r", - " pm.collectionVariables.set(\"item\", item); \r", - " pm.collectionVariables.set(\"itemId\", it.id);\r", - " pm.collectionVariables.set(\"itemName\", item.name);\r", - " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", - " pm.collectionVariables.set(\"itemDescription\", item.description);\r", - "\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text" - }, - { - "key": "Content-Type", - "value": "application/json", - "type": "text" - }, - { - "key": "Accept", - "value": "*/*", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"available\": {{itemAvailable}}\n}" - }, - "url": { - "raw": "{{baseUrl}}/items/{{itemId}}", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "items", - "{{itemId}}" - ] - } - }, - "response": [] - }, - { - "name": "Item update description field", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.be.ok;", - "});", - "pm.test(\"Response have body\", function () {", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - "});", - "var item = pm.collectionVariables.get(\"item\");", - "", - "pm.test(\"Response data equal to request\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData).to.have.property('id');", - " pm.expect(jsonData).to.have.property('name');", - " pm.expect(jsonData).to.have.property('description');", - " pm.expect(jsonData).to.have.property('available');", - " pm.expect(jsonData.description, `\"description\" must be ${item.description}`).to.eql(item.description);", - "});" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user.id);\r", - " item = rnd.getItem();\r", - " var it = await api.addItem(item, user.id)\r", - " item = rnd.getItem();\r", - " pm.collectionVariables.set(\"item\", item); \r", - " pm.collectionVariables.set(\"itemId\", it.id);\r", - " pm.collectionVariables.set(\"itemName\", item.name);\r", - " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", - " pm.collectionVariables.set(\"itemDescription\", item.description);\r", - "\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "PATCH", - "header": [ - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text" - }, - { - "key": "Content-Type", - "value": "application/json", - "type": "text" - }, - { - "key": "Accept", - "value": "*/*", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"description\": \"{{itemDescription}}\"\n}" - }, - "url": { - "raw": "{{baseUrl}}/items/{{itemId}}", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "items", - "{{itemId}}" - ] - } - }, - "response": [] - }, - { - "name": "Item update name field", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.be.ok;", - "});", - "pm.test(\"Response have body\", function () {", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - "});", - "var item = pm.collectionVariables.get(\"item\");", - "", - "pm.test(\"Response data equal to request\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData).to.have.property('id');", - " pm.expect(jsonData).to.have.property('name');", - " pm.expect(jsonData).to.have.property('description');", - " pm.expect(jsonData).to.have.property('available');", - " pm.expect(jsonData.name, `\"name\" must be ${item.name}`).to.eql(item.name);", - "});" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user.id);\r", - " item = rnd.getItem();\r", - " var it = await api.addItem(item, user.id)\r", - " item = rnd.getItem();\r", - " pm.collectionVariables.set(\"item\", item); \r", - " pm.collectionVariables.set(\"itemId\", it.id);\r", - " pm.collectionVariables.set(\"itemName\", item.name);\r", - " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", - " pm.collectionVariables.set(\"itemDescription\", item.description);\r", - "\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } } ], "request": { - "method": "PATCH", + "method": "POST", "header": [ - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text" - }, { "key": "Content-Type", - "value": "application/json", - "type": "text" - }, - { - "key": "Accept", - "value": "*/*", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"{{itemName}}\"\n}" - }, - "url": { - "raw": "{{baseUrl}}/items/{{itemId}}", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "items", - "{{itemId}}" - ] - } - }, - "response": [] - }, - { - "name": "Item get", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.be.ok;", - "});", - "pm.test(\"Response have body\", function () {", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - "});", - "var item = pm.collectionVariables.get(\"item\");", - "", - "pm.test(\"Response data equal to request\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData).to.have.property('id');", - " pm.expect(jsonData).to.have.property('name');", - " pm.expect(jsonData).to.have.property('description');", - " pm.expect(jsonData).to.have.property('available');", - " pm.expect(jsonData.name, `\"name\" must be ${item.name}`).to.eql(item.name);", - " pm.expect(jsonData.description, `\"description\" must be ${item.description}`).to.eql(item.description);", - " pm.expect(jsonData.available.toString(), `\"available\" must be ${item.available}`).to.eql(item.available.toString());", - "});" - ], - "type": "text/javascript", - "packages": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "const main = async () => {\r", - " const api = new API(pm);\r", - " const rnd = new RandomUtils();\r", - "\r", - " try {\r", - " user = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user.id);\r", - " item = await api.addItem(rnd.getItem(), user.id)\r", - " pm.collectionVariables.set(\"item\", item);\r", - " pm.collectionVariables.set(\"itemId\", item.id);\r", - " pm.collectionVariables.set(\"itemName\", item.name);\r", - " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", - " pm.collectionVariables.set(\"itemDescription\", item.description);\r", - " } catch(err) {\r", - " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", - " }\r", - "\r", - "};\r", - "\r", - "const interval = setInterval(() => {}, 1000);\r", - "\r", - "setTimeout(async () => \r", - " {\r", - " try {\r", - " await main();\r", - " } catch (e) {\r", - " console.error(e);\r", - " } finally {\r", - " clearInterval(interval);\r", - " }\r", - " }, \r", - " 100 \r", - ");" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text" + "value": "application/json" }, - { - "key": "Accept", - "value": "*/*", - "type": "text" + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}" } ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"requestId\": {{requestId}}\n}" + }, "url": { - "raw": "{{baseUrl}}/items/{{itemId}}", + "raw": "localhost:8080/items", "host": [ - "{{baseUrl}}" + "localhost" ], + "port": "8080", "path": [ - "items", - "{{itemId}}" + "items" ] } }, "response": [] - }, + } + ] + }, + { + "name": "requests", + "item": [ { - "name": "Get all items from user", + "name": "Create request", "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.be.ok;", - "});", - "pm.test(\"Test list item response\", function () {", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.length, 'List length must be 2').to.eql(2);", - "});", - "", - "" - ], - "type": "text/javascript", - "packages": {} - } - }, { "listen": "prerequest", "script": { @@ -2166,10 +1451,11 @@ " const rnd = new RandomUtils();\r", "\r", " try {\r", + " request1 = rnd.getRequest();\r", + " pm.collectionVariables.set(\"requestDescription\", request1.description);\r", " user = await api.addUser(rnd.getUser());\r", " pm.collectionVariables.set(\"userId\", user.id);\r", - " await api.addItem(rnd.getItem(), user.id)\r", - " await api.addItem(rnd.getItem(), user.id)\r", + "\r", " } catch(err) {\r", " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", " }\r", @@ -2194,57 +1480,65 @@ "type": "text/javascript", "packages": {} } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200 or 201\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200,201]);\r", + "});\r", + "pm.test(\"Response have body\", function () {\r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "\r", + "pm.test(\"Response data equal to request\", function () {\r", + " var description = pm.collectionVariables.get(\"requestDescription\");\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.have.property('id');\r", + " pm.expect(jsonData).to.have.property('description');\r", + " pm.expect(jsonData).to.have.property('created');\r", + " pm.expect(jsonData.description, `\"description\" must be ${description}`).to.eql(description);\r", + "});" + ], + "type": "text/javascript", + "packages": {} + } } ], "request": { - "method": "GET", + "method": "POST", "header": [ { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text" + "key": "Content-Type", + "value": "application/json" }, { - "key": "Accept", - "value": "*/*", - "type": "text" + "key": "X-Sharer-User-Id", + "value": "{{userId}}" } ], + "body": { + "mode": "raw", + "raw": "{ \n \"description\": \"{{requestDescription}}\"\n}" + }, "url": { - "raw": "{{baseUrl}}/items", + "raw": "localhost:8080/requests", "host": [ - "{{baseUrl}}" + "localhost" ], + "port": "8080", "path": [ - "items" + "requests" ] } }, "response": [] }, { - "name": "Item search", + "name": "Get user requests", "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.be.ok;", - "});", - "pm.test(\"Test list item response\", function () {", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.length, 'List length must be 1').to.eql(1);", - " pm.expect(jsonData[0].name.toUpperCase(), 'Name should include ' + pm.collectionVariables.get(\"searchString\")).to.eql(pm.collectionVariables.get(\"searchString\"))", - "});", - "" - ], - "type": "text/javascript", - "packages": {} - } - }, { "listen": "prerequest", "script": { @@ -2256,15 +1550,9 @@ " try {\r", " user = await api.addUser(rnd.getUser());\r", " pm.collectionVariables.set(\"userId\", user.id);\r", - " it = rnd.getItem()\r", - " it.available = true\r", - " item = await api.addItem(it, user.id)\r", - " pm.collectionVariables.set(\"item\", item);\r", - " pm.collectionVariables.set(\"itemId\", item.id);\r", - " pm.collectionVariables.set(\"itemName\", item.name);\r", - " pm.collectionVariables.set(\"searchString\", item.name.toUpperCase());\r", - " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", - " pm.collectionVariables.set(\"itemDescription\", item.description);\r", + " request1 = await api.addRequest(rnd.getRequest(), user.id);\r", + " request2 = await api.addRequest(rnd.getRequest(), user.id);\r", + "\r", " } catch(err) {\r", " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", " }\r", @@ -2289,63 +1577,54 @@ "type": "text/javascript", "packages": {} } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {\r", + " pm.response.to.be.ok;\r", + "});\r", + "pm.test(\"User requests amount\", function () {\r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData.length, 'List length must be 2').to.eql(2);\r", + "});" + ], + "type": "text/javascript", + "packages": {} + } } ], "request": { "method": "GET", "header": [ { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text" + "key": "Content-Type", + "value": "application/json" }, { - "key": "Accept", - "value": "*/*", - "type": "text" + "key": "X-Sharer-User-Id", + "value": "{{userId}}" } ], "url": { - "raw": "{{baseUrl}}/items/search?text={{searchString}}", + "raw": "localhost:8080/requests", "host": [ - "{{baseUrl}}" + "localhost" ], + "port": "8080", "path": [ - "items", - "search" - ], - "query": [ - { - "key": "text", - "value": "{{searchString}}" - } + "requests" ] } }, "response": [] }, { - "name": "Item search unavailable", + "name": "Get user request by id", "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.be.ok;", - "});", - "pm.test(\"Test list item response\", function () {", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.length, 'List length must be 0').to.eql(0);", - "});", - "" - ], - "type": "text/javascript", - "packages": {} - } - }, { "listen": "prerequest", "script": { @@ -2355,17 +1634,13 @@ " const rnd = new RandomUtils();\r", "\r", " try {\r", - " user = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user.id);\r", - " it = rnd.getItem()\r", - " it.available = false\r", - " item = await api.addItem(it, user.id)\r", - " pm.collectionVariables.set(\"item\", item);\r", - " pm.collectionVariables.set(\"itemId\", item.id);\r", + " user1 = await api.addUser(rnd.getUser());\r", + " user2 = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user2.id);\r", + " req = await api.addRequest(rnd.getRequest(), user1.id);\r", + " pm.collectionVariables.set(\"requestId\", req.id);\r", + " item = await api.addItem(rnd.getItemForRequest(req.id), user2.id);\r", " pm.collectionVariables.set(\"itemName\", item.name);\r", - " pm.collectionVariables.set(\"searchString\", item.name.toUpperCase());\r", - " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", - " pm.collectionVariables.set(\"itemDescription\", item.description);\r", " } catch(err) {\r", " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", " }\r", @@ -2390,59 +1665,28 @@ "type": "text/javascript", "packages": {} } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text" - }, - { - "key": "Accept", - "value": "*/*", - "type": "text" - } - ], - "url": { - "raw": "{{baseUrl}}/items/search?text={{searchString}}", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "items", - "search" - ], - "query": [ - { - "key": "text", - "value": "{{searchString}}" - } - ] - } - }, - "response": [] - }, - { - "name": "Item search empty", - "event": [ + }, { "listen": "test", "script": { "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.be.ok;", - "});", - "pm.test(\"Test search item response\", function () {", - " pm.response.to.be.withBody;", - " pm.response.to.be.json;", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.length, 'List length must be 0').to.eql(0);", + "pm.test(\"Status code is 200\", function () {\r", + " pm.response.to.be.ok;\r", + "});\r", + "pm.test(\"User requests amount\", function () {\r", + " var name = pm.collectionVariables.get(\"itemName\");\r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.have.property('id');\r", + " pm.expect(jsonData).to.have.property('description');\r", + " pm.expect(jsonData).to.have.property('created');\r", + " pm.expect(jsonData).to.have.property('items');\r", + " pm.expect(jsonData.items[0].name, `\"item name\" must be ${name}`).to.eql(name);\r", "});" ], - "type": "text/javascript" + "type": "text/javascript", + "packages": {} } } ], @@ -2450,30 +1694,23 @@ "method": "GET", "header": [ { - "key": "X-Sharer-User-Id", - "value": "{{userId}}", - "type": "text" + "key": "Content-Type", + "value": "application/json" }, { - "key": "Accept", - "value": "*/*", - "type": "text" + "key": "X-Sharer-User-Id", + "value": "{{userId}}" } ], "url": { - "raw": "{{baseUrl}}/items/search?text=", + "raw": "localhost:8080/requests/{{requestId}}", "host": [ - "{{baseUrl}}" + "localhost" ], + "port": "8080", "path": [ - "items", - "search" - ], - "query": [ - { - "key": "text", - "value": "" - } + "requests", + "{{requestId}}" ] } }, @@ -4739,10 +3976,6 @@ } ], "variable": [ - { - "key": "baseUrl", - "value": "http://localhost:8080" - }, { "key": "userName", "value": "" @@ -4753,11 +3986,7 @@ }, { "key": "userId", - "value": "" - }, - { - "key": "item", - "value": "" + "value": "1" }, { "key": "itemName", @@ -4772,13 +4001,21 @@ "value": "" }, { - "key": "itemId", + "key": "item", + "value": "" + }, + { + "key": "requestId", "value": "" }, { - "key": "searchString", + "key": "requestDescription", "value": "" }, + { + "key": "baseUrl", + "value": "localhost:8080" + }, { "key": "start", "value": "" @@ -4787,6 +4024,10 @@ "key": "end", "value": "" }, + { + "key": "itemId", + "value": "" + }, { "key": "user1", "value": "" @@ -4797,7 +4038,7 @@ }, { "key": "bookingId", - "value": "" + "value": "1" }, { "key": "booking", 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..566db3e --- /dev/null +++ b/server/pom.xml @@ -0,0 +1,86 @@ + + + 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 + + + + + + + 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 57% rename from src/main/java/ru/practicum/shareit/ShareItApp.java rename to server/src/main/java/ru/practicum/shareit/ShareItServer.java index a10a87d..303541d 100644 --- a/src/main/java/ru/practicum/shareit/ShareItApp.java +++ b/server/src/main/java/ru/practicum/shareit/ShareItServer.java @@ -4,10 +4,10 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication -public class ShareItApp { +public class ShareItServer { - public static void main(String[] args) { - SpringApplication.run(ShareItApp.class, args); - } + public static void main(String[] args) { + SpringApplication.run(ShareItServer.class, args); + } } diff --git a/src/main/java/ru/practicum/shareit/booking/Booking.java b/server/src/main/java/ru/practicum/shareit/booking/Booking.java similarity index 100% rename from src/main/java/ru/practicum/shareit/booking/Booking.java rename to server/src/main/java/ru/practicum/shareit/booking/Booking.java 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 97% rename from src/main/java/ru/practicum/shareit/booking/BookingController.java rename to server/src/main/java/ru/practicum/shareit/booking/BookingController.java index 40df0bc..fd62891 100644 --- a/src/main/java/ru/practicum/shareit/booking/BookingController.java +++ b/server/src/main/java/ru/practicum/shareit/booking/BookingController.java @@ -1,6 +1,5 @@ package ru.practicum.shareit.booking; -import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; @@ -20,7 +19,7 @@ public class BookingController { */ @PostMapping public BookingDtoOutput addBooking(@RequestHeader("X-Sharer-User-Id") Long bookerId, - @Valid @RequestBody BookingDtoInput bookingDto) { + @RequestBody BookingDtoInput bookingDto) { return BookingMapper.toBookingDtoOutput(bookingService.addBooking(bookerId, bookingDto)); } diff --git a/src/main/java/ru/practicum/shareit/booking/BookingDto.java b/server/src/main/java/ru/practicum/shareit/booking/BookingDto.java similarity index 100% rename from src/main/java/ru/practicum/shareit/booking/BookingDto.java rename to server/src/main/java/ru/practicum/shareit/booking/BookingDto.java diff --git a/server/src/main/java/ru/practicum/shareit/booking/BookingDtoInput.java b/server/src/main/java/ru/practicum/shareit/booking/BookingDtoInput.java new file mode 100644 index 0000000..382f6a2 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/booking/BookingDtoInput.java @@ -0,0 +1,20 @@ +package ru.practicum.shareit.booking; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class BookingDtoInput { + + private Long itemId; + + private LocalDateTime start; + + private LocalDateTime end; + +} diff --git a/src/main/java/ru/practicum/shareit/booking/BookingDtoOutput.java b/server/src/main/java/ru/practicum/shareit/booking/BookingDtoOutput.java similarity index 100% rename from src/main/java/ru/practicum/shareit/booking/BookingDtoOutput.java rename to server/src/main/java/ru/practicum/shareit/booking/BookingDtoOutput.java diff --git a/src/main/java/ru/practicum/shareit/booking/BookingDtoShort.java b/server/src/main/java/ru/practicum/shareit/booking/BookingDtoShort.java similarity index 100% rename from src/main/java/ru/practicum/shareit/booking/BookingDtoShort.java rename to server/src/main/java/ru/practicum/shareit/booking/BookingDtoShort.java diff --git a/src/main/java/ru/practicum/shareit/booking/BookingMapper.java b/server/src/main/java/ru/practicum/shareit/booking/BookingMapper.java similarity index 100% rename from src/main/java/ru/practicum/shareit/booking/BookingMapper.java rename to server/src/main/java/ru/practicum/shareit/booking/BookingMapper.java diff --git a/src/main/java/ru/practicum/shareit/booking/BookingRepository.java b/server/src/main/java/ru/practicum/shareit/booking/BookingRepository.java similarity index 100% rename from src/main/java/ru/practicum/shareit/booking/BookingRepository.java rename to server/src/main/java/ru/practicum/shareit/booking/BookingRepository.java diff --git a/src/main/java/ru/practicum/shareit/booking/BookingService.java b/server/src/main/java/ru/practicum/shareit/booking/BookingService.java similarity index 100% rename from src/main/java/ru/practicum/shareit/booking/BookingService.java rename to server/src/main/java/ru/practicum/shareit/booking/BookingService.java diff --git a/src/main/java/ru/practicum/shareit/booking/BookingServiceImpl.java b/server/src/main/java/ru/practicum/shareit/booking/BookingServiceImpl.java similarity index 95% rename from src/main/java/ru/practicum/shareit/booking/BookingServiceImpl.java rename to server/src/main/java/ru/practicum/shareit/booking/BookingServiceImpl.java index 991eba2..d0f22f3 100644 --- a/src/main/java/ru/practicum/shareit/booking/BookingServiceImpl.java +++ b/server/src/main/java/ru/practicum/shareit/booking/BookingServiceImpl.java @@ -203,7 +203,6 @@ public List getByOwnerId(Long userId, String state) { switch (bookingState) { case ALL: { result = bookingRepository.findAllByItem_OwnerOrderByStartDesc(bookerFromDb); - System.out.println(result); break; } case CURRENT: { @@ -253,18 +252,6 @@ private void validateBooking(BookingDto bookingDto, Item item, User booker) { throw new ValidationException(message); } - if (bookingDto.getStart().equals(bookingDto.getEnd())) { - String message = "Начало и окончание бронирования не может быть одним и тем же временем."; - log.info(message); - throw new ValidationException(message); - } - - if (bookingDto.getEnd().isBefore(bookingDto.getStart())) { - String message = "Окончание бронирования не может быть раньше его начала."; - log.info(message); - throw new ValidationException(message); - } - List bookings = item.getBookings(); if (!bookings.isEmpty()) { for (Booking b : bookings) { diff --git a/src/main/java/ru/practicum/shareit/booking/BookingState.java b/server/src/main/java/ru/practicum/shareit/booking/BookingState.java similarity index 57% rename from src/main/java/ru/practicum/shareit/booking/BookingState.java rename to server/src/main/java/ru/practicum/shareit/booking/BookingState.java index 75be8b4..76499ce 100644 --- a/src/main/java/ru/practicum/shareit/booking/BookingState.java +++ b/server/src/main/java/ru/practicum/shareit/booking/BookingState.java @@ -1,5 +1,5 @@ package ru.practicum.shareit.booking; public enum BookingState { - ALL, CURRENT, PAST, FUTURE, WAITING, REJECTED; + ALL, CURRENT, PAST, FUTURE, WAITING, REJECTED } diff --git a/src/main/java/ru/practicum/shareit/booking/BookingStatus.java b/server/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 server/src/main/java/ru/practicum/shareit/booking/BookingStatus.java diff --git a/src/main/java/ru/practicum/shareit/exception/DataConflictException.java b/server/src/main/java/ru/practicum/shareit/exception/DataConflictException.java similarity index 100% rename from src/main/java/ru/practicum/shareit/exception/DataConflictException.java rename to server/src/main/java/ru/practicum/shareit/exception/DataConflictException.java diff --git a/src/main/java/ru/practicum/shareit/exception/ErrorHandler.java b/server/src/main/java/ru/practicum/shareit/exception/ErrorHandler.java similarity index 100% rename from src/main/java/ru/practicum/shareit/exception/ErrorHandler.java rename to server/src/main/java/ru/practicum/shareit/exception/ErrorHandler.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/RestrictedAccessException.java b/server/src/main/java/ru/practicum/shareit/exception/RestrictedAccessException.java similarity index 100% rename from src/main/java/ru/practicum/shareit/exception/RestrictedAccessException.java rename to server/src/main/java/ru/practicum/shareit/exception/RestrictedAccessException.java diff --git a/server/src/main/java/ru/practicum/shareit/exception/ValidationException.java b/server/src/main/java/ru/practicum/shareit/exception/ValidationException.java new file mode 100644 index 0000000..59043da --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/exception/ValidationException.java @@ -0,0 +1,7 @@ +package ru.practicum.shareit.exception; + +public class ValidationException extends RuntimeException { + public ValidationException(String message) { + super(message); + } +} diff --git a/src/main/java/ru/practicum/shareit/item/Comment.java b/server/src/main/java/ru/practicum/shareit/item/Comment.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/Comment.java rename to server/src/main/java/ru/practicum/shareit/item/Comment.java diff --git a/src/main/java/ru/practicum/shareit/item/CommentDto.java b/server/src/main/java/ru/practicum/shareit/item/CommentDto.java similarity index 51% rename from src/main/java/ru/practicum/shareit/item/CommentDto.java rename to server/src/main/java/ru/practicum/shareit/item/CommentDto.java index bd2daa4..fc9956b 100644 --- a/src/main/java/ru/practicum/shareit/item/CommentDto.java +++ b/server/src/main/java/ru/practicum/shareit/item/CommentDto.java @@ -1,12 +1,9 @@ package ru.practicum.shareit.item; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import ru.practicum.shareit.user.User; -import ru.practicum.shareit.validation.CreateObject; import java.time.LocalDateTime; @@ -17,8 +14,6 @@ public class CommentDto { private Long id; - @NotNull(groups = {CreateObject.class}, message = "комментарий должен быть указан.") - @NotBlank(groups = {CreateObject.class}, message = "Комментарий не может быть пустым.") private String text; private Item item; diff --git a/src/main/java/ru/practicum/shareit/item/CommentDtoOutput.java b/server/src/main/java/ru/practicum/shareit/item/CommentDtoOutput.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/CommentDtoOutput.java rename to server/src/main/java/ru/practicum/shareit/item/CommentDtoOutput.java diff --git a/src/main/java/ru/practicum/shareit/item/CommentDtoShort.java b/server/src/main/java/ru/practicum/shareit/item/CommentDtoShort.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/CommentDtoShort.java rename to server/src/main/java/ru/practicum/shareit/item/CommentDtoShort.java diff --git a/src/main/java/ru/practicum/shareit/item/CommentMapper.java b/server/src/main/java/ru/practicum/shareit/item/CommentMapper.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/CommentMapper.java rename to server/src/main/java/ru/practicum/shareit/item/CommentMapper.java diff --git a/src/main/java/ru/practicum/shareit/item/CommentRepository.java b/server/src/main/java/ru/practicum/shareit/item/CommentRepository.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/CommentRepository.java rename to server/src/main/java/ru/practicum/shareit/item/CommentRepository.java diff --git a/src/main/java/ru/practicum/shareit/item/Item.java b/server/src/main/java/ru/practicum/shareit/item/Item.java similarity index 98% rename from src/main/java/ru/practicum/shareit/item/Item.java rename to server/src/main/java/ru/practicum/shareit/item/Item.java index 99e8100..bd80d79 100644 --- a/src/main/java/ru/practicum/shareit/item/Item.java +++ b/server/src/main/java/ru/practicum/shareit/item/Item.java @@ -39,7 +39,7 @@ public class Item { @JoinColumn(name = "owner_id", nullable = false) private User owner; - @OneToOne + @ManyToOne @JoinColumn(name = "request_id") private Request request; 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 85% rename from src/main/java/ru/practicum/shareit/item/ItemController.java rename to server/src/main/java/ru/practicum/shareit/item/ItemController.java index affabdd..c95d869 100644 --- a/src/main/java/ru/practicum/shareit/item/ItemController.java +++ b/server/src/main/java/ru/practicum/shareit/item/ItemController.java @@ -2,11 +2,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; -import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import ru.practicum.shareit.validation.CreateObject; -import ru.practicum.shareit.validation.UpdateObject; - import java.util.List; @RestController @@ -17,14 +13,14 @@ public class ItemController { @PostMapping @ResponseStatus(HttpStatus.CREATED) - public ItemDtoOutput addItem(@Validated(CreateObject.class) @RequestBody ItemDto itemDto, + public ItemDtoOutput addItem(@RequestBody ItemDtoInput itemDto, @RequestHeader(value = "X-Sharer-User-Id") Long idUser) { return ItemMapper.toItemDtoOutput(itemService.addItem(idUser, itemDto), idUser); } @PatchMapping("/{idItem}") public ItemDtoOutput updateItem(@PathVariable Long idItem, - @Validated(UpdateObject.class) @RequestBody ItemDto itemDto, + @RequestBody ItemDtoInput itemDto, @RequestHeader(value = "X-Sharer-User-Id") Long idUser) { return ItemMapper.toItemDtoOutput(itemService.updateItem(idUser, idItem, itemDto), idUser); } @@ -56,7 +52,8 @@ public List searchItemsByText(@RequestParam String text, @PostMapping("/{itemId}/comment") public CommentDtoOutput addCommentToItem(@RequestHeader("X-Sharer-User-Id") Long userId, - @PathVariable Long itemId, @RequestBody CommentDto commentDto) { + @PathVariable Long itemId, + @RequestBody CommentDto commentDto) { return CommentMapper.toCommentDtoOutput((itemService.saveComment(userId, itemId, commentDto))); } } diff --git a/server/src/main/java/ru/practicum/shareit/item/ItemDto.java b/server/src/main/java/ru/practicum/shareit/item/ItemDto.java new file mode 100644 index 0000000..4f5f206 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/item/ItemDto.java @@ -0,0 +1,37 @@ +package ru.practicum.shareit.item; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import ru.practicum.shareit.booking.Booking; +import ru.practicum.shareit.request.RequestDto; +import ru.practicum.shareit.user.User; + +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ItemDto { + + private Long id; + + private String name; + + private String description; + + private Boolean available; + + private User owner; + + private RequestDto request; + + private List comments; + + private List bookings; + + private Booking lastBooking; + + private Booking nextBooking; + +} diff --git a/server/src/main/java/ru/practicum/shareit/item/ItemDtoInput.java b/server/src/main/java/ru/practicum/shareit/item/ItemDtoInput.java new file mode 100644 index 0000000..97209f5 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/item/ItemDtoInput.java @@ -0,0 +1,20 @@ +package ru.practicum.shareit.item; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ItemDtoInput { + + private String name; + + private String description; + + private Boolean available; + + private Long requestId; + +} diff --git a/src/main/java/ru/practicum/shareit/item/ItemDtoOutput.java b/server/src/main/java/ru/practicum/shareit/item/ItemDtoOutput.java similarity index 88% rename from src/main/java/ru/practicum/shareit/item/ItemDtoOutput.java rename to server/src/main/java/ru/practicum/shareit/item/ItemDtoOutput.java index 36ff82c..c68c82f 100644 --- a/src/main/java/ru/practicum/shareit/item/ItemDtoOutput.java +++ b/server/src/main/java/ru/practicum/shareit/item/ItemDtoOutput.java @@ -4,7 +4,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import ru.practicum.shareit.booking.BookingDtoShort; -import ru.practicum.shareit.request.Request; +import ru.practicum.shareit.request.RequestDto; import ru.practicum.shareit.user.UserDtoShort; import java.util.List; @@ -24,7 +24,7 @@ public class ItemDtoOutput { private UserDtoShort owner; - private Request request; + private RequestDto request; private List comments; diff --git a/server/src/main/java/ru/practicum/shareit/item/ItemDtoRequest.java b/server/src/main/java/ru/practicum/shareit/item/ItemDtoRequest.java new file mode 100644 index 0000000..95ffbee --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/item/ItemDtoRequest.java @@ -0,0 +1,20 @@ +package ru.practicum.shareit.item; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ItemDtoRequest { + + private Long idItem; + + private String name; + + private Long idOwner; + + private String Owner; + +} diff --git a/src/main/java/ru/practicum/shareit/item/ItemDtoShort.java b/server/src/main/java/ru/practicum/shareit/item/ItemDtoShort.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/ItemDtoShort.java rename to server/src/main/java/ru/practicum/shareit/item/ItemDtoShort.java diff --git a/src/main/java/ru/practicum/shareit/item/ItemMapper.java b/server/src/main/java/ru/practicum/shareit/item/ItemMapper.java similarity index 89% rename from src/main/java/ru/practicum/shareit/item/ItemMapper.java rename to server/src/main/java/ru/practicum/shareit/item/ItemMapper.java index d076fa1..9f81b4e 100644 --- a/src/main/java/ru/practicum/shareit/item/ItemMapper.java +++ b/server/src/main/java/ru/practicum/shareit/item/ItemMapper.java @@ -3,6 +3,7 @@ import ru.practicum.shareit.booking.Booking; import ru.practicum.shareit.booking.BookingMapper; import ru.practicum.shareit.booking.BookingStatus; +import ru.practicum.shareit.request.RequestMapper; import ru.practicum.shareit.user.UserMapper; import java.time.LocalDateTime; @@ -24,7 +25,7 @@ public static ItemDto toItemDto(Item item) { itemDto.setDescription(item.getDescription()); itemDto.setAvailable(item.getAvailable()); itemDto.setOwner(item.getOwner()); - itemDto.setRequest(item.getRequest()); + itemDto.setRequest(RequestMapper.toRequestDto(item.getRequest())); itemDto.setComments(item.getComments()); itemDto.setBookings(item.getBookings()); @@ -42,7 +43,7 @@ public static ItemDtoOutput toItemDtoOutput(Item item, Long userId) { itemDto.setDescription(item.getDescription()); itemDto.setAvailable(item.getAvailable()); itemDto.setOwner(UserMapper.toUserDtoShort(item.getOwner())); - itemDto.setRequest(item.getRequest()); + itemDto.setRequest(RequestMapper.toRequestDto(item.getRequest())); List comments = Optional.ofNullable(item.getComments()).orElse(Collections.emptyList()); if (!comments.isEmpty()) { itemDto.setComments(comments.stream().map(CommentMapper::toCommentDtoShort).toList()); @@ -83,6 +84,20 @@ public static ItemDtoShort toItemDtoShort(Item item) { return itemDto; } + public static ItemDtoRequest toItemDtoRequest(Item item) { + if (item == null) { + return null; + } + ItemDtoRequest itemDto = new ItemDtoRequest(); + + itemDto.setIdItem(item.getId()); + itemDto.setName(item.getName()); + itemDto.setIdOwner(item.getOwner().getId()); + itemDto.setOwner(item.getOwner().getName()); + + return itemDto; + } + public static Item toItem(ItemDto itemDto) { Item item = new Item(); @@ -107,7 +122,7 @@ public static Item toItem(ItemDto itemDto) { } if (itemDto.getRequest() != null) { if (itemDto.getRequest().getId() > 0) { - item.setRequest(itemDto.getRequest()); + item.setRequest(RequestMapper.toRequest(itemDto.getRequest())); } } if (itemDto.getComments() != null) { diff --git a/src/main/java/ru/practicum/shareit/item/ItemRepository.java b/server/src/main/java/ru/practicum/shareit/item/ItemRepository.java similarity index 100% rename from src/main/java/ru/practicum/shareit/item/ItemRepository.java rename to server/src/main/java/ru/practicum/shareit/item/ItemRepository.java diff --git a/src/main/java/ru/practicum/shareit/item/ItemService.java b/server/src/main/java/ru/practicum/shareit/item/ItemService.java similarity index 73% rename from src/main/java/ru/practicum/shareit/item/ItemService.java rename to server/src/main/java/ru/practicum/shareit/item/ItemService.java index ba5bf8a..c72f72e 100644 --- a/src/main/java/ru/practicum/shareit/item/ItemService.java +++ b/server/src/main/java/ru/practicum/shareit/item/ItemService.java @@ -4,9 +4,9 @@ public interface ItemService { - Item addItem(Long idUser, ItemDto itemDto); + Item addItem(Long idUser, ItemDtoInput itemDto); - Item updateItem(Long idUser, Long idItem, ItemDto itemDto); + Item updateItem(Long idUser, Long idItem, ItemDtoInput itemDto); Item getItemById(Long idItem); diff --git a/src/main/java/ru/practicum/shareit/item/ItemServiceImpl.java b/server/src/main/java/ru/practicum/shareit/item/ItemServiceImpl.java similarity index 86% rename from src/main/java/ru/practicum/shareit/item/ItemServiceImpl.java rename to server/src/main/java/ru/practicum/shareit/item/ItemServiceImpl.java index edaf54d..e939b0e 100644 --- a/src/main/java/ru/practicum/shareit/item/ItemServiceImpl.java +++ b/server/src/main/java/ru/practicum/shareit/item/ItemServiceImpl.java @@ -1,5 +1,6 @@ package ru.practicum.shareit.item; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; @@ -7,6 +8,8 @@ import ru.practicum.shareit.exception.NotFoundException; import ru.practicum.shareit.exception.RestrictedAccessException; import ru.practicum.shareit.exception.ValidationException; +import ru.practicum.shareit.request.RequestMapper; +import ru.practicum.shareit.request.RequestRepository; import ru.practicum.shareit.user.User; import ru.practicum.shareit.user.UserMapper; import ru.practicum.shareit.user.UserRepository; @@ -17,35 +20,41 @@ @Slf4j @Service +@RequiredArgsConstructor public class ItemServiceImpl implements ItemService { private final ItemRepository itemRepository; private final UserRepository userRepository; private final CommentRepository commentRepository; - - public ItemServiceImpl(ItemRepository itemRepository, UserRepository userRepository, CommentRepository commentRepository) { - this.itemRepository = itemRepository; - this.userRepository = userRepository; - this.commentRepository = commentRepository; - } + private final RequestRepository requestRepository; /** * Метод для добавления новой вещи. * * @param idUser идентификатор пользователя - * @param itemDto объект ItemDto, содержащий данные новой вещи + * @param inputItemDto объект ItemDtoInput, содержащий данные новой вещи * @return объект Item, содержащий данные добавленной вещи * @throws ValidationException если идентификатор пользователя не указан * @throws NotFoundException если пользователь с указанным id не найден в БД */ @Override - public Item addItem(Long idUser, ItemDto itemDto) { - if (userRepository.findById(idUser).isEmpty()) { + public Item addItem(Long idUser, ItemDtoInput inputItemDto) { + ItemDto itemDto = new ItemDto(); + User user = userRepository.findById(idUser).orElse(null); + if (user == null) { String error = "Пользователь с id [ " + idUser + " ] не найден в БД при добавлении вещи."; log.info(error); throw new NotFoundException(error); } - itemDto.setOwner(userRepository.findById(idUser).get()); + itemDto.setOwner(user); + itemDto.setName(inputItemDto.getName()); + itemDto.setDescription(inputItemDto.getDescription()); + itemDto.setAvailable(inputItemDto.getAvailable()); + if (inputItemDto.getRequestId() == null) { + itemDto.setRequest(null); + } else { + itemDto.setRequest(RequestMapper.toRequestDto(requestRepository.findById(inputItemDto.getRequestId()).orElse(null))); + } Item result = ItemMapper.toItem(itemDto); itemRepository.save(result); log.info("Добавлена вещь [ {} ] пользователем [ {} ]", result.getId(), idUser); @@ -57,14 +66,15 @@ public Item addItem(Long idUser, ItemDto itemDto) { * * @param idUser идентификатор пользователя * @param idItem идентификатор вещи - * @param itemDto объект ItemDto, содержащий новые данные вещи + * @param itemDtoInput объект ItemDtoInput, содержащий новые данные вещи * @return объект Item, содержащий обновленные данные вещи * @throws ValidationException если идентификатор пользователя не указан * @throws NotFoundException если пользователь или вещь с указанным id не найдены в БД * @throws RestrictedAccessException если пользователь не является владельцем вещи */ @Override - public Item updateItem(Long idUser, Long idItem, ItemDto itemDto) { + public Item updateItem(Long idUser, Long idItem, ItemDtoInput itemDtoInput) { + ItemDto itemDto = new ItemDto(); if (userRepository.findById(idUser).isEmpty()) { String error = "Пользователь с id [ " + idUser + " ] не найден в БД при изменение данных вещи."; log.info(error); @@ -83,15 +93,21 @@ public Item updateItem(Long idUser, Long idItem, ItemDto itemDto) { } itemDto.setId(idItem); itemDto.setOwner(oldItem.get().getOwner()); - itemDto.setRequest(oldItem.get().getRequest()); - if (itemDto.getName() == null) { + itemDto.setRequest(RequestMapper.toRequestDto(oldItem.get().getRequest())); + if (itemDtoInput.getName() == null) { itemDto.setName(oldItem.get().getName()); + } else { + itemDto.setName(itemDtoInput.getName()); } - if (itemDto.getDescription() == null) { + if (itemDtoInput.getDescription() == null) { itemDto.setDescription(oldItem.get().getDescription()); + } else { + itemDto.setDescription(itemDtoInput.getDescription()); } - if (itemDto.getAvailable() == null) { + if (itemDtoInput.getAvailable() == null) { itemDto.setAvailable(oldItem.get().getAvailable()); + } else { + itemDto.setAvailable(itemDtoInput.getAvailable()); } Item newItem = ItemMapper.toItem(itemDto); itemRepository.save(newItem); diff --git a/src/main/java/ru/practicum/shareit/request/Request.java b/server/src/main/java/ru/practicum/shareit/request/Request.java similarity index 88% rename from src/main/java/ru/practicum/shareit/request/Request.java rename to server/src/main/java/ru/practicum/shareit/request/Request.java index 2e67520..5947b30 100644 --- a/src/main/java/ru/practicum/shareit/request/Request.java +++ b/server/src/main/java/ru/practicum/shareit/request/Request.java @@ -6,6 +6,7 @@ import ru.practicum.shareit.user.User; import java.time.LocalDateTime; +import java.util.List; @Getter @Setter @@ -27,9 +28,9 @@ public class Request { @JoinColumn(name = "requestor_id", nullable = false) private User requestor; - @OneToOne(mappedBy = "request") - private Item requestItem; - @Column(nullable = false) private LocalDateTime created; + + @OneToMany(mappedBy = "request") + private List items; } diff --git a/server/src/main/java/ru/practicum/shareit/request/RequestController.java b/server/src/main/java/ru/practicum/shareit/request/RequestController.java new file mode 100644 index 0000000..d3c49ec --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/request/RequestController.java @@ -0,0 +1,39 @@ +package ru.practicum.shareit.request; + +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * TODO Sprint add-item-requests. + */ +@RestController +@RequestMapping(path = "/requests") +@RequiredArgsConstructor +public class RequestController { + + private final RequestService requestService; + + @PostMapping + public RequestDto addRequest(@RequestHeader("X-Sharer-User-Id") Long requestorId, + @RequestBody RequestDtoInput requestDto) { + return RequestMapper.toRequestDto(requestService.addRequest(requestorId, requestDto)); + } + + @GetMapping + public List getRequests(@RequestHeader("X-Sharer-User-Id") Long requestorId) { + return requestService.getRequests(requestorId).stream().map(RequestMapper::toRequestDtoItems).toList(); + } + + @GetMapping("/all") + public List getAllRequests(@RequestHeader("X-Sharer-User-Id") Long requestorId) { + return requestService.getAllRequests(requestorId).stream().map(RequestMapper::toRequestDto).toList(); + } + + @GetMapping("/{requestId}") + public RequestDtoItems getRequestsById(@PathVariable Long requestId) { + return RequestMapper.toRequestDtoItems(requestService.getRequestById(requestId)); + } + +} \ No newline at end of file diff --git a/src/main/java/ru/practicum/shareit/request/ItemRequestDto.java b/server/src/main/java/ru/practicum/shareit/request/RequestDto.java similarity index 87% rename from src/main/java/ru/practicum/shareit/request/ItemRequestDto.java rename to server/src/main/java/ru/practicum/shareit/request/RequestDto.java index 16d55ee..a49428d 100644 --- a/src/main/java/ru/practicum/shareit/request/ItemRequestDto.java +++ b/server/src/main/java/ru/practicum/shareit/request/RequestDto.java @@ -10,11 +10,14 @@ @Data @AllArgsConstructor @NoArgsConstructor -public class ItemRequestDto { +public class RequestDto { + + private Long id; private String description; private User requestor; private LocalDateTime created; + } diff --git a/server/src/main/java/ru/practicum/shareit/request/RequestDtoInput.java b/server/src/main/java/ru/practicum/shareit/request/RequestDtoInput.java new file mode 100644 index 0000000..8d44bc6 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/request/RequestDtoInput.java @@ -0,0 +1,14 @@ +package ru.practicum.shareit.request; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class RequestDtoInput { + + private String description; + +} diff --git a/server/src/main/java/ru/practicum/shareit/request/RequestDtoItems.java b/server/src/main/java/ru/practicum/shareit/request/RequestDtoItems.java new file mode 100644 index 0000000..178918b --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/request/RequestDtoItems.java @@ -0,0 +1,26 @@ +package ru.practicum.shareit.request; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import ru.practicum.shareit.item.ItemDtoRequest; +import ru.practicum.shareit.user.User; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class RequestDtoItems { + + private Long id; + + private String description; + + private User requestor; + + private LocalDateTime created; + + List items; +} diff --git a/server/src/main/java/ru/practicum/shareit/request/RequestMapper.java b/server/src/main/java/ru/practicum/shareit/request/RequestMapper.java new file mode 100644 index 0000000..9608ce2 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/request/RequestMapper.java @@ -0,0 +1,62 @@ +package ru.practicum.shareit.request; + +import ru.practicum.shareit.item.ItemMapper; + +public class RequestMapper { + + public static RequestDto toRequestDto(Request request) { + if (request == null) { + return null; + } + RequestDto requestDto = new RequestDto(); + + requestDto.setId(request.getId()); + requestDto.setDescription(request.getDescription()); + requestDto.setRequestor(request.getRequestor()); + requestDto.setCreated(request.getCreated()); + + return requestDto; + } + + public static RequestDtoItems toRequestDtoItems(Request request) { + if (request == null) { + return null; + } + RequestDtoItems requestDto = new RequestDtoItems(); + + requestDto.setId(request.getId()); + requestDto.setDescription(request.getDescription()); + requestDto.setRequestor(request.getRequestor()); + requestDto.setCreated(request.getCreated()); + requestDto.setItems(request.getItems().stream().map(ItemMapper::toItemDtoRequest).toList()); + + return requestDto; + } + + + public static Request toRequest(RequestDto requestDto) { + Request request = new Request(); + + if (requestDto.getId() != null) { + if (requestDto.getId() > 0) { + request.setId(requestDto.getId()); + } + } + if (requestDto.getDescription() != null) { + if (!requestDto.getDescription().trim().isEmpty()) { + request.setDescription(requestDto.getDescription().trim()); + } + } + if (requestDto.getRequestor().getId() != null) { + if (requestDto.getRequestor().getId() > 0) { + request.setRequestor(requestDto.getRequestor()); + } + } + if (requestDto.getCreated() != null) { + request.setCreated(requestDto.getCreated()); + } + + return request; + } + +} diff --git a/server/src/main/java/ru/practicum/shareit/request/RequestRepository.java b/server/src/main/java/ru/practicum/shareit/request/RequestRepository.java new file mode 100644 index 0000000..db723d3 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/request/RequestRepository.java @@ -0,0 +1,17 @@ +package ru.practicum.shareit.request; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import ru.practicum.shareit.user.User; + +import java.util.List; + +@Repository +public interface RequestRepository extends JpaRepository { + + List findAllByRequestorOrderByCreatedDesc(User requestor); + + List findAllByOrderByCreatedDesc(); + + List findAllByRequestorNotOrderByCreatedDesc(User requestor); +} diff --git a/server/src/main/java/ru/practicum/shareit/request/RequestService.java b/server/src/main/java/ru/practicum/shareit/request/RequestService.java new file mode 100644 index 0000000..6e3bba3 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/request/RequestService.java @@ -0,0 +1,15 @@ +package ru.practicum.shareit.request; + +import java.util.List; + +public interface RequestService { + + Request addRequest(Long requestorId, RequestDtoInput requestDto); + + List getRequests(Long requestorId); + + List getAllRequests(Long requestorId); + + Request getRequestById(Long requestId); + +} diff --git a/server/src/main/java/ru/practicum/shareit/request/RequestServiceImpl.java b/server/src/main/java/ru/practicum/shareit/request/RequestServiceImpl.java new file mode 100644 index 0000000..60dae61 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/request/RequestServiceImpl.java @@ -0,0 +1,107 @@ +package ru.practicum.shareit.request; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import ru.practicum.shareit.exception.NotFoundException; +import ru.practicum.shareit.item.ItemRepository; +import ru.practicum.shareit.user.User; +import ru.practicum.shareit.user.UserRepository; + +import java.time.LocalDateTime; +import java.util.List; + +@Slf4j +@Service +@RequiredArgsConstructor +public class RequestServiceImpl implements RequestService { + + private final RequestRepository requestRepository; + private final UserRepository userRepository; + + /** + * Добавляет новый запрос в базу данных. + * + * @param requestorId идентификатор пользователя, который создает запрос + * @param requestDto объект, содержащий данные для создания запроса + * @return созданный запрос + * @throws NotFoundException если пользователь с указанным идентификатором не найден в базе данных + */ + @Override + public Request addRequest(Long requestorId, RequestDtoInput requestDto) { + User requestor = new User(); + Request request = new Request(); + requestor = userRepository.findById(requestorId).orElse(null); + if (requestor == null) { + String error = "Пользователь с id [ " + requestorId + " ] не найден в БД при добавлении запроса."; + log.info(error); + throw new NotFoundException(error); + } + request.setDescription(requestDto.getDescription()); + request.setRequestor(requestor); + request.setCreated(LocalDateTime.now()); + request = requestRepository.save(request); + log.info("Запрос [ {} ] добавлен в БД.",request); + return request; + } + + /** + * Возвращает список запросов, созданных определенным пользователем, отсортированный по дате создания в обратном порядке. + * + * @param requestorId идентификатор пользователя, чьи запросы нужно получить + * @return список запросов, созданных пользователем + */ + @Override + public List getRequests(Long requestorId) { + User requestor = new User(); + requestor = userRepository.findById(requestorId).orElse(null); + if (requestor == null) { + log.info("Пользователь с id [ {} ] не найден в БД при получении своего списка запросов - вернулся пустой список.", requestorId); + return List.of(); + } + List requests = requestRepository.findAllByRequestorOrderByCreatedDesc(requestor); + log.info("Список запросов пользователя [ {} ] получен из БД в количестве [ {} ].", requestorId, requests.size()); + return requests; + } + + /** + * Возвращает список всех запросов, отсортированных по дате создания в обратном порядке. + * Если передан идентификатор пользователя, то возвращаются все запросы, + * кроме тех, которые были созданы этим пользователем. + * + * @param requestorId идентификатор пользователя, чьи запросы нужно исключить из списка (может быть null) + * @return список всех запросов, отсортированных по дате создания в обратном порядке + */ + @Override + public List getAllRequests(Long requestorId) { + User requestor = new User(); + requestor = userRepository.findById(requestorId).orElse(null); + if (requestor == null) { + List requests = requestRepository.findAllByOrderByCreatedDesc(); + log.info("Список доступных запросов получен из БД в количестве [ {} ].", requests.size()); + return requests; + } + List requests = requestRepository.findAllByRequestorNotOrderByCreatedDesc(requestor); + log.info("Список доступных запросов ( кроме запросов пользователя [ {} ] ) получен из БД в количестве [ {} ].", + requestorId, requests.size()); + return requests; + } + + /** + * Возвращает запрос по его идентификатору. + * + * @param requestId идентификатор запроса + * @return запрос с указанным идентификатором + * @throws NotFoundException если запрос с указанным идентификатором не найден в базе данных + */ + @Override + public Request getRequestById(Long requestId) { + Request request = requestRepository.findById(requestId).orElse(null); + if (request == null) { + String error = "Запрос с id [ " + requestId + " ] не найден в БД при получении."; + log.info(error); + throw new NotFoundException(error); + } + return request; + } +} diff --git a/src/main/java/ru/practicum/shareit/user/User.java b/server/src/main/java/ru/practicum/shareit/user/User.java similarity index 100% rename from src/main/java/ru/practicum/shareit/user/User.java rename to server/src/main/java/ru/practicum/shareit/user/User.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 73% rename from src/main/java/ru/practicum/shareit/user/UserController.java rename to server/src/main/java/ru/practicum/shareit/user/UserController.java index 38dff38..98c0885 100644 --- a/src/main/java/ru/practicum/shareit/user/UserController.java +++ b/server/src/main/java/ru/practicum/shareit/user/UserController.java @@ -2,10 +2,8 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; -import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import ru.practicum.shareit.validation.CreateObject; -import ru.practicum.shareit.validation.UpdateObject; + import java.util.List; @@ -17,12 +15,13 @@ public class UserController { @PostMapping @ResponseStatus(HttpStatus.CREATED) - public UserDtoOutput addUser(@Validated(CreateObject.class) @RequestBody UserDto userDto) { + public UserDtoOutput addUser(@RequestBody UserDto userDto) { return UserMapper.toUserDtoOutput(userService.addUser(userDto)); } @PatchMapping("/{idUser}") - public UserDtoOutput updateUser(@PathVariable Long idUser, @Validated(UpdateObject.class) @RequestBody UserDto userDto) { + public UserDtoOutput updateUser(@PathVariable Long idUser, + @RequestBody UserDto userDto) { return UserMapper.toUserDtoOutput(userService.updateUser(idUser, userDto)); } diff --git a/server/src/main/java/ru/practicum/shareit/user/UserDto.java b/server/src/main/java/ru/practicum/shareit/user/UserDto.java new file mode 100644 index 0000000..924c595 --- /dev/null +++ b/server/src/main/java/ru/practicum/shareit/user/UserDto.java @@ -0,0 +1,29 @@ +package ru.practicum.shareit.user; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import ru.practicum.shareit.booking.Booking; +import ru.practicum.shareit.item.Comment; +import ru.practicum.shareit.item.Item; + +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UserDto { + + private Long id; + + private String name; + + private String email; + + private List items; + + private List bookings; + + private List comments; + +} diff --git a/src/main/java/ru/practicum/shareit/user/UserDtoOutput.java b/server/src/main/java/ru/practicum/shareit/user/UserDtoOutput.java similarity index 100% rename from src/main/java/ru/practicum/shareit/user/UserDtoOutput.java rename to server/src/main/java/ru/practicum/shareit/user/UserDtoOutput.java diff --git a/src/main/java/ru/practicum/shareit/user/UserDtoShort.java b/server/src/main/java/ru/practicum/shareit/user/UserDtoShort.java similarity index 100% rename from src/main/java/ru/practicum/shareit/user/UserDtoShort.java rename to server/src/main/java/ru/practicum/shareit/user/UserDtoShort.java diff --git a/src/main/java/ru/practicum/shareit/user/UserMapper.java b/server/src/main/java/ru/practicum/shareit/user/UserMapper.java similarity index 100% rename from src/main/java/ru/practicum/shareit/user/UserMapper.java rename to server/src/main/java/ru/practicum/shareit/user/UserMapper.java diff --git a/src/main/java/ru/practicum/shareit/user/UserRepository.java b/server/src/main/java/ru/practicum/shareit/user/UserRepository.java similarity index 100% rename from src/main/java/ru/practicum/shareit/user/UserRepository.java rename to server/src/main/java/ru/practicum/shareit/user/UserRepository.java diff --git a/src/main/java/ru/practicum/shareit/user/UserService.java b/server/src/main/java/ru/practicum/shareit/user/UserService.java similarity index 100% rename from src/main/java/ru/practicum/shareit/user/UserService.java rename to server/src/main/java/ru/practicum/shareit/user/UserService.java diff --git a/src/main/java/ru/practicum/shareit/user/UserServiceImpl.java b/server/src/main/java/ru/practicum/shareit/user/UserServiceImpl.java similarity index 100% rename from src/main/java/ru/practicum/shareit/user/UserServiceImpl.java rename to server/src/main/java/ru/practicum/shareit/user/UserServiceImpl.java diff --git a/server/src/main/resources/application.properties b/server/src/main/resources/application.properties new file mode 100644 index 0000000..0f5ef57 --- /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=shareituser +spring.datasource.password=12345678 +#--- +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/java/ru/practicum/shareit/booking/BookingDtoInput.java b/src/main/java/ru/practicum/shareit/booking/BookingDtoInput.java deleted file mode 100644 index b39e330..0000000 --- a/src/main/java/ru/practicum/shareit/booking/BookingDtoInput.java +++ /dev/null @@ -1,28 +0,0 @@ -package ru.practicum.shareit.booking; - -import jakarta.validation.constraints.FutureOrPresent; -import jakarta.validation.constraints.NotNull; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import ru.practicum.shareit.validation.CreateObject; - -import java.time.LocalDateTime; - -@Data -@AllArgsConstructor -@NoArgsConstructor -public class BookingDtoInput { - - @NotNull(groups = {CreateObject.class}, message = "При создании брони должна быть информация о вещи.") - private Long itemId; - - @FutureOrPresent(groups = {CreateObject.class}, message = "Дата не должна быть в прошлом") - @NotNull(groups = {CreateObject.class}, message = "Дата не должна быть пустой") - private LocalDateTime start; - - @FutureOrPresent(groups = {CreateObject.class}, message = "Дата не должна быть в прошлом") - @NotNull(groups = {CreateObject.class}, message = "Дата не должна быть пустой") - private LocalDateTime end; - -} diff --git a/src/main/java/ru/practicum/shareit/request/ItemRequestController.java b/src/main/java/ru/practicum/shareit/request/ItemRequestController.java deleted file mode 100644 index 064e2e9..0000000 --- a/src/main/java/ru/practicum/shareit/request/ItemRequestController.java +++ /dev/null @@ -1,12 +0,0 @@ -package ru.practicum.shareit.request; - -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * TODO Sprint add-item-requests. - */ -@RestController -@RequestMapping(path = "/requests") -public class ItemRequestController { -} diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml deleted file mode 100644 index faf6257..0000000 --- a/src/main/resources/application.yaml +++ /dev/null @@ -1,20 +0,0 @@ -spring: - application.name: shareit - main.banner-mode: off - datasource: - url: jdbc:postgresql://localhost:5432/shareit - driver-class-name: org.postgresql.Driver - username: shareituser - password: 12345678 - jpa: - show-sql: true - hibernate: - ddl-auto: update - properties: - hibernate.jdbc.time_zone: UTC - dialect: org.hibernate.dialect.PostgreSQL95Dialect - format_sql: true - sql: - init: - mode: always - From fe2cbe3dc5b7124c5a01c5d5c2b6450b2af54120 Mon Sep 17 00:00:00 2001 From: Sergey Filippovskikh <116564864+SergikF@users.noreply.github.com> Date: Sat, 26 Apr 2025 20:50:29 +0300 Subject: [PATCH 2/6] =?UTF-8?q?=D0=92=D1=8B=D0=BF=D0=BE=D0=BB=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=2016=20=D1=81=D0=BF=D1=80=D0=B8=D0=BD=D1=82?= =?UTF-8?q?=D0=B0.=20=D0=9F=D0=B5=D1=80=D0=B2=D0=B8=D1=87=D0=BD=D0=B0?= =?UTF-8?q?=D1=8F=20=D0=B7=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=BA=D0=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- checkstyle.xml | 257 ----------------------------------------------- suppressions.xml | 7 -- 2 files changed, 264 deletions(-) delete mode 100644 checkstyle.xml delete mode 100644 suppressions.xml diff --git a/checkstyle.xml b/checkstyle.xml deleted file mode 100644 index 05d5086..0000000 --- a/checkstyle.xml +++ /dev/null @@ -1,257 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/suppressions.xml b/suppressions.xml deleted file mode 100644 index b2c6822..0000000 --- a/suppressions.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - \ No newline at end of file From 50aeb407e5fe954709dd18576bafd71e040c6b09 Mon Sep 17 00:00:00 2001 From: Sergey Filippovskikh <116564864+SergikF@users.noreply.github.com> Date: Sat, 26 Apr 2025 20:59:01 +0300 Subject: [PATCH 3/6] =?UTF-8?q?=D0=92=D1=8B=D0=BF=D0=BE=D0=BB=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=2016=20=D1=81=D0=BF=D1=80=D0=B8=D0=BD=D1=82?= =?UTF-8?q?=D0=B0.=20=D0=9F=D0=B5=D1=80=D0=B2=D0=B8=D1=87=D0=BD=D0=B0?= =?UTF-8?q?=D1=8F=20=D0=B7=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=BA=D0=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/pom.xml b/pom.xml index 79cba37..0095bb0 100644 --- a/pom.xml +++ b/pom.xml @@ -74,7 +74,6 @@ com.puppycrawl.tools checkstyle - 10.3 From 9d8d0ed4ba1dae2293aea62644a24fd9a1ecbfc3 Mon Sep 17 00:00:00 2001 From: Sergey Filippovskikh <116564864+SergikF@users.noreply.github.com> Date: Sat, 26 Apr 2025 21:10:27 +0300 Subject: [PATCH 4/6] =?UTF-8?q?Revert=20"=D0=92=D1=8B=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=2016=20=D1=81=D0=BF=D1=80=D0=B8?= =?UTF-8?q?=D0=BD=D1=82=D0=B0."?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 50aeb407e5fe954709dd18576bafd71e040c6b09. --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 0095bb0..79cba37 100644 --- a/pom.xml +++ b/pom.xml @@ -74,6 +74,7 @@ com.puppycrawl.tools checkstyle + 10.3 From 7289d4d5f60f32b055f895bfd225899130d1954d Mon Sep 17 00:00:00 2001 From: Sergey Filippovskikh <116564864+SergikF@users.noreply.github.com> Date: Sat, 26 Apr 2025 21:11:49 +0300 Subject: [PATCH 5/6] =?UTF-8?q?Revert=20"=D0=92=D1=8B=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=2016=20=D1=81=D0=BF=D1=80=D0=B8?= =?UTF-8?q?=D0=BD=D1=82=D0=B0."?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit fe2cbe3dc5b7124c5a01c5d5c2b6450b2af54120. --- checkstyle.xml | 257 +++++++++++++++++++++++++++++++++++++++++++++++ suppressions.xml | 7 ++ 2 files changed, 264 insertions(+) create mode 100644 checkstyle.xml create mode 100644 suppressions.xml diff --git a/checkstyle.xml b/checkstyle.xml new file mode 100644 index 0000000..05d5086 --- /dev/null +++ b/checkstyle.xml @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/suppressions.xml b/suppressions.xml new file mode 100644 index 0000000..b2c6822 --- /dev/null +++ b/suppressions.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file From 209dd47ed128c1e3f355da4884b92d94a5db420d Mon Sep 17 00:00:00 2001 From: Sergey Filippovskikh <116564864+SergikF@users.noreply.github.com> Date: Sat, 26 Apr 2025 21:12:00 +0300 Subject: [PATCH 6/6] =?UTF-8?q?Revert=20"=D0=92=D1=8B=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=2016=20=D1=81=D0=BF=D1=80=D0=B8?= =?UTF-8?q?=D0=BD=D1=82=D0=B0."?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 38dd6791ba496e42323d1e633501a812b90e4449. --- README.md | 6 +- checkstyle.xml | 2 +- docker-compose.yml | 39 - gateway/Dockerfile | 5 - gateway/pom.xml | 70 - .../ru/practicum/shareit/ShareItGateway.java | 12 - .../shareit/booking/BookingClient.java | 58 - .../shareit/booking/BookingController.java | 100 - .../shareit/booking/BookingDtoInput.java | 28 - .../shareit/booking/BookingState.java | 16 - .../practicum/shareit/client/BaseClient.java | 121 - .../shareit/exception/ErrorHandler.java | 65 - .../shareit/item/CommentDtoInput.java | 18 - .../ru/practicum/shareit/item/ItemClient.java | 54 - .../shareit/item/ItemController.java | 122 - .../shareit/request/RequestClient.java | 41 - .../shareit/request/RequestController.java | 73 - .../shareit/request/RequestDtoInput.java | 18 - .../ru/practicum/shareit/user/UserClient.java | 46 - .../shareit/user/UserController.java | 81 - .../src/main/resources/application.properties | 7 - pom.xml | 97 +- postman_for_shareit_14.json | 2725 +++++++++++++++++ ...eit_16.json => postman_for_shareit_15.json | 1227 ++++++-- server/Dockerfile | 5 - server/pom.xml | 86 - .../shareit/booking/BookingDtoInput.java | 20 - .../exception/ValidationException.java | 7 - .../ru/practicum/shareit/item/ItemDto.java | 37 - .../practicum/shareit/item/ItemDtoInput.java | 20 - .../shareit/item/ItemDtoRequest.java | 20 - .../shareit/request/RequestController.java | 39 - .../shareit/request/RequestDtoInput.java | 14 - .../shareit/request/RequestDtoItems.java | 26 - .../shareit/request/RequestMapper.java | 62 - .../shareit/request/RequestRepository.java | 17 - .../shareit/request/RequestService.java | 15 - .../shareit/request/RequestServiceImpl.java | 107 - .../ru/practicum/shareit/user/UserDto.java | 29 - .../src/main/resources/application.properties | 17 - .../java/ru/practicum/shareit/ShareItApp.java | 8 +- .../ru/practicum/shareit/booking/Booking.java | 0 .../shareit/booking/BookingController.java | 3 +- .../practicum/shareit/booking/BookingDto.java | 0 .../shareit/booking/BookingDtoInput.java | 28 + .../shareit/booking/BookingDtoOutput.java | 0 .../shareit/booking/BookingDtoShort.java | 0 .../shareit/booking/BookingMapper.java | 0 .../shareit/booking/BookingRepository.java | 0 .../shareit/booking/BookingService.java | 0 .../shareit/booking/BookingServiceImpl.java | 13 + .../shareit/booking/BookingState.java | 2 +- .../shareit/booking/BookingStatus.java | 0 .../exception/DataConflictException.java | 0 .../shareit/exception/ErrorHandler.java | 0 .../shareit/exception/NotFoundException.java | 0 .../exception/RestrictedAccessException.java | 0 .../exception/ValidationException.java | 0 .../ru/practicum/shareit/item/Comment.java | 0 .../ru/practicum/shareit/item/CommentDto.java | 5 + .../shareit/item/CommentDtoOutput.java | 0 .../shareit/item/CommentDtoShort.java | 0 .../practicum/shareit/item/CommentMapper.java | 0 .../shareit/item/CommentRepository.java | 0 .../java/ru/practicum/shareit/item/Item.java | 2 +- .../shareit/item/ItemController.java | 11 +- .../ru/practicum/shareit/item/ItemDto.java | 21 +- .../practicum/shareit/item/ItemDtoOutput.java | 4 +- .../practicum/shareit/item/ItemDtoShort.java | 0 .../ru/practicum/shareit/item/ItemMapper.java | 21 +- .../shareit/item/ItemRepository.java | 0 .../practicum/shareit/item/ItemService.java | 4 +- .../shareit/item/ItemServiceImpl.java | 48 +- .../request/ItemRequestController.java | 12 + .../shareit/request/ItemRequestDto.java | 5 +- .../ru/practicum/shareit/request/Request.java | 7 +- .../java/ru/practicum/shareit/user/User.java | 0 .../shareit/user/UserController.java | 9 +- .../ru/practicum/shareit/user/UserDto.java | 18 +- .../practicum/shareit/user/UserDtoOutput.java | 0 .../practicum/shareit/user/UserDtoShort.java | 0 .../ru/practicum/shareit/user/UserMapper.java | 0 .../shareit/user/UserRepository.java | 0 .../practicum/shareit/user/UserService.java | 0 .../shareit/user/UserServiceImpl.java | 0 .../shareit/validation/CreateObject.java | 0 .../shareit/validation/UpdateObject.java | 0 src/main/resources/application.yaml | 20 + {server/src => src}/main/resources/schema.sql | 0 89 files changed, 3958 insertions(+), 1835 deletions(-) delete mode 100644 docker-compose.yml delete mode 100644 gateway/Dockerfile delete mode 100644 gateway/pom.xml delete mode 100644 gateway/src/main/java/ru/practicum/shareit/ShareItGateway.java delete mode 100644 gateway/src/main/java/ru/practicum/shareit/booking/BookingClient.java delete mode 100644 gateway/src/main/java/ru/practicum/shareit/booking/BookingController.java delete mode 100644 gateway/src/main/java/ru/practicum/shareit/booking/BookingDtoInput.java delete mode 100644 gateway/src/main/java/ru/practicum/shareit/booking/BookingState.java delete mode 100644 gateway/src/main/java/ru/practicum/shareit/client/BaseClient.java delete mode 100644 gateway/src/main/java/ru/practicum/shareit/exception/ErrorHandler.java delete mode 100644 gateway/src/main/java/ru/practicum/shareit/item/CommentDtoInput.java delete mode 100644 gateway/src/main/java/ru/practicum/shareit/item/ItemClient.java delete mode 100644 gateway/src/main/java/ru/practicum/shareit/item/ItemController.java delete mode 100644 gateway/src/main/java/ru/practicum/shareit/request/RequestClient.java delete mode 100644 gateway/src/main/java/ru/practicum/shareit/request/RequestController.java delete mode 100644 gateway/src/main/java/ru/practicum/shareit/request/RequestDtoInput.java delete mode 100644 gateway/src/main/java/ru/practicum/shareit/user/UserClient.java delete mode 100644 gateway/src/main/java/ru/practicum/shareit/user/UserController.java delete mode 100644 gateway/src/main/resources/application.properties create mode 100644 postman_for_shareit_14.json rename postman_for_shareit_16.json => postman_for_shareit_15.json (81%) delete mode 100644 server/Dockerfile delete mode 100644 server/pom.xml delete mode 100644 server/src/main/java/ru/practicum/shareit/booking/BookingDtoInput.java delete mode 100644 server/src/main/java/ru/practicum/shareit/exception/ValidationException.java delete mode 100644 server/src/main/java/ru/practicum/shareit/item/ItemDto.java delete mode 100644 server/src/main/java/ru/practicum/shareit/item/ItemDtoInput.java delete mode 100644 server/src/main/java/ru/practicum/shareit/item/ItemDtoRequest.java delete mode 100644 server/src/main/java/ru/practicum/shareit/request/RequestController.java delete mode 100644 server/src/main/java/ru/practicum/shareit/request/RequestDtoInput.java delete mode 100644 server/src/main/java/ru/practicum/shareit/request/RequestDtoItems.java delete mode 100644 server/src/main/java/ru/practicum/shareit/request/RequestMapper.java delete mode 100644 server/src/main/java/ru/practicum/shareit/request/RequestRepository.java delete mode 100644 server/src/main/java/ru/practicum/shareit/request/RequestService.java delete mode 100644 server/src/main/java/ru/practicum/shareit/request/RequestServiceImpl.java delete mode 100644 server/src/main/java/ru/practicum/shareit/user/UserDto.java delete mode 100644 server/src/main/resources/application.properties rename server/src/main/java/ru/practicum/shareit/ShareItServer.java => src/main/java/ru/practicum/shareit/ShareItApp.java (57%) rename {server/src => src}/main/java/ru/practicum/shareit/booking/Booking.java (100%) rename {server/src => src}/main/java/ru/practicum/shareit/booking/BookingController.java (97%) rename {server/src => src}/main/java/ru/practicum/shareit/booking/BookingDto.java (100%) create mode 100644 src/main/java/ru/practicum/shareit/booking/BookingDtoInput.java rename {server/src => src}/main/java/ru/practicum/shareit/booking/BookingDtoOutput.java (100%) rename {server/src => src}/main/java/ru/practicum/shareit/booking/BookingDtoShort.java (100%) rename {server/src => src}/main/java/ru/practicum/shareit/booking/BookingMapper.java (100%) rename {server/src => src}/main/java/ru/practicum/shareit/booking/BookingRepository.java (100%) rename {server/src => src}/main/java/ru/practicum/shareit/booking/BookingService.java (100%) rename {server/src => src}/main/java/ru/practicum/shareit/booking/BookingServiceImpl.java (95%) rename {server/src => src}/main/java/ru/practicum/shareit/booking/BookingState.java (57%) rename {server/src => src}/main/java/ru/practicum/shareit/booking/BookingStatus.java (100%) rename {server/src => src}/main/java/ru/practicum/shareit/exception/DataConflictException.java (100%) rename {server/src => src}/main/java/ru/practicum/shareit/exception/ErrorHandler.java (100%) rename {server/src => src}/main/java/ru/practicum/shareit/exception/NotFoundException.java (100%) rename {server/src => src}/main/java/ru/practicum/shareit/exception/RestrictedAccessException.java (100%) rename {gateway/src => src}/main/java/ru/practicum/shareit/exception/ValidationException.java (100%) rename {server/src => src}/main/java/ru/practicum/shareit/item/Comment.java (100%) rename {server/src => src}/main/java/ru/practicum/shareit/item/CommentDto.java (51%) rename {server/src => src}/main/java/ru/practicum/shareit/item/CommentDtoOutput.java (100%) rename {server/src => src}/main/java/ru/practicum/shareit/item/CommentDtoShort.java (100%) rename {server/src => src}/main/java/ru/practicum/shareit/item/CommentMapper.java (100%) rename {server/src => src}/main/java/ru/practicum/shareit/item/CommentRepository.java (100%) rename {server/src => src}/main/java/ru/practicum/shareit/item/Item.java (98%) rename {server/src => src}/main/java/ru/practicum/shareit/item/ItemController.java (85%) rename gateway/src/main/java/ru/practicum/shareit/item/ItemDtoInput.java => src/main/java/ru/practicum/shareit/item/ItemDto.java (72%) rename {server/src => src}/main/java/ru/practicum/shareit/item/ItemDtoOutput.java (88%) rename {server/src => src}/main/java/ru/practicum/shareit/item/ItemDtoShort.java (100%) rename {server/src => src}/main/java/ru/practicum/shareit/item/ItemMapper.java (89%) rename {server/src => src}/main/java/ru/practicum/shareit/item/ItemRepository.java (100%) rename {server/src => src}/main/java/ru/practicum/shareit/item/ItemService.java (73%) rename {server/src => src}/main/java/ru/practicum/shareit/item/ItemServiceImpl.java (86%) create mode 100644 src/main/java/ru/practicum/shareit/request/ItemRequestController.java rename server/src/main/java/ru/practicum/shareit/request/RequestDto.java => src/main/java/ru/practicum/shareit/request/ItemRequestDto.java (87%) rename {server/src => src}/main/java/ru/practicum/shareit/request/Request.java (88%) rename {server/src => src}/main/java/ru/practicum/shareit/user/User.java (100%) rename {server/src => src}/main/java/ru/practicum/shareit/user/UserController.java (73%) rename gateway/src/main/java/ru/practicum/shareit/user/UserDtoInput.java => src/main/java/ru/practicum/shareit/user/UserDto.java (59%) rename {server/src => src}/main/java/ru/practicum/shareit/user/UserDtoOutput.java (100%) rename {server/src => src}/main/java/ru/practicum/shareit/user/UserDtoShort.java (100%) rename {server/src => src}/main/java/ru/practicum/shareit/user/UserMapper.java (100%) rename {server/src => src}/main/java/ru/practicum/shareit/user/UserRepository.java (100%) rename {server/src => src}/main/java/ru/practicum/shareit/user/UserService.java (100%) rename {server/src => src}/main/java/ru/practicum/shareit/user/UserServiceImpl.java (100%) rename {gateway/src => src}/main/java/ru/practicum/shareit/validation/CreateObject.java (100%) rename {gateway/src => src}/main/java/ru/practicum/shareit/validation/UpdateObject.java (100%) create mode 100644 src/main/resources/application.yaml rename {server/src => src}/main/resources/schema.sql (100%) diff --git a/README.md b/README.md index bd0da80..d4b18b6 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ _java-shareit_ # Шеринг вещей -### Согласно задания спринта № 16 (add-item-requests-and-gateway) +### Согласно задания спринта № 14 (add-controllers) ## выполнено Филипповских Сергеем _**Когорта-53**_ -_**Для проверки выполнения 16 спринта использовался postman: -[postman_for_shareit_16.json](/postman_for_shareit_16.json)**_ +_**Для проверки выполнения 14 спринта использовался postman: +[postman_for_shareit_14.json](/postman_for_shareit_14.json)**_ ![](/er_diagram_shareit.png) diff --git a/checkstyle.xml b/checkstyle.xml index 05d5086..c28a0d3 100644 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -161,7 +161,7 @@ - + diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index abe6570..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,39 +0,0 @@ -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: - - "6541:5432" - environment: - - POSTGRES_PASSWORD=shareit - - POSTGRES_USER=shareit - - POSTGRES_DB=shareit - healthcheck: - test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER - timeout: 5s - interval: 5s - retries: 10 \ No newline at end of file diff --git a/gateway/Dockerfile b/gateway/Dockerfile deleted file mode 100644 index 0ff1817..0000000 --- a/gateway/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index f3394c1..0000000 --- a/gateway/pom.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - 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 deleted file mode 100644 index 0aa75c3..0000000 --- a/gateway/src/main/java/ru/practicum/shareit/ShareItGateway.java +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index 7975693..0000000 --- a/gateway/src/main/java/ru/practicum/shareit/booking/BookingClient.java +++ /dev/null @@ -1,58 +0,0 @@ -package ru.practicum.shareit.booking; - -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.exception.ValidationException; - -import java.util.Map; - -@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 addBooking(Long userId, BookingDtoInput requestDto) { - if (requestDto.getStart().equals(requestDto.getEnd())) { - throw new ValidationException("Начало и окончание бронирования не может быть одним и тем же моментом."); - } - if (requestDto.getEnd().isBefore(requestDto.getStart())) { - throw new ValidationException("Окончание бронирования не может быть раньше его начала."); - } - return post("", userId, requestDto); - } - - public ResponseEntity updateByOwner(Long userId, Long bookingId, Boolean approved) { - Map parameters = Map.of( - "approved", approved - ); - return patch("/" + bookingId + "?approved={approved}", userId, parameters, null); - } - - public ResponseEntity getWithStatusById(Long bookingId, Long userId) { - return get("/" + bookingId, userId); - } - - public ResponseEntity getByUserId(Long userId, BookingState state) { - return get("?state=" + state, userId); - } - - public ResponseEntity getByOwnerId(Long userId, BookingState state) { - return get("/owner?state=" + state, userId); - } -} diff --git a/gateway/src/main/java/ru/practicum/shareit/booking/BookingController.java b/gateway/src/main/java/ru/practicum/shareit/booking/BookingController.java deleted file mode 100644 index 6d368fb..0000000 --- a/gateway/src/main/java/ru/practicum/shareit/booking/BookingController.java +++ /dev/null @@ -1,100 +0,0 @@ -package ru.practicum.shareit.booking; - -import jakarta.validation.Valid; -import jakarta.validation.ValidationException; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -@Controller -@RequestMapping(path = "/bookings") -@RequiredArgsConstructor -@Slf4j -@Validated -public class BookingController { - - private final BookingClient bookingClient; - - /** - * Создает бронирование. - * - * @param bookerId идентификатор пользователя, создающего бронирование - * @param bookingDto данные бронирования - * @return ResponseEntity с объектом, представляющим результат создания бронирования - */ - @PostMapping - public ResponseEntity addBooking(@RequestHeader("X-Sharer-User-Id") Long bookerId, - @Valid @RequestBody BookingDtoInput bookingDto) { - log.info("Создано бронирование {}, пользователем {}", bookingDto, bookerId); - return bookingClient.addBooking(bookerId, bookingDto); - } - - /** - * Обновляет бронирование владельцем. - * - * @param ownerId идентификатор владельца бронирования - * @param bookingId идентификатор бронирования - * @param approved флаг, указывающий, одобрено ли бронирование - * @return ResponseEntity с объектом, представляющим результат обновления бронирования - */ - @PatchMapping("/{bookingId}") - public ResponseEntity updateByOwner(@RequestHeader("X-Sharer-User-Id") Long ownerId, - @PathVariable Long bookingId, - @RequestParam Boolean approved) { - log.info("Обновление бронирования {}, владельцем {}, в состояние {}", bookingId, ownerId, approved); - return bookingClient.updateByOwner(ownerId, bookingId, approved); - } - - /** - * Получает данные о бронировании по его идентификатору. - * - * @param userId идентификатор пользователя, запрашивающего данные о бронировании - * @param bookingId идентификатор бронирования - * @return ResponseEntity с объектом, представляющим результат получения данных о бронировании - */ - @GetMapping("/{bookingId}") - public ResponseEntity getWithStatusById(@RequestHeader("X-Sharer-User-Id") Long userId, - @PathVariable Long bookingId) { - log.info("Получение данных о бронировании {}, пользователем {}", bookingId, userId); - return bookingClient.getWithStatusById( bookingId, userId); - } - - /** - * Получает все бронирования пользователя по его идентификатору и состоянию. - * - * @param userId идентификатор пользователя, запрашивающего данные о бронировании - * @param stateParam состояние бронирования - * @return ResponseEntity с объектом, представляющим результат получения данных о бронировании - */ - @GetMapping - public ResponseEntity getByUserId(@RequestHeader("X-Sharer-User-Id") Long userId, - @RequestParam(value = "state", - defaultValue = "ALL", required = false) String stateParam) { - BookingState state = BookingState.from(stateParam) - .orElseThrow(() -> - new ValidationException("Неизвестное состояние бронирования: " + stateParam)); - log.info("Получение всех бронирований пользователя{}, в состоянии {}", userId, state); - return bookingClient.getByUserId(userId, state); - } - - /** - * Получает все забронированные вещи пользователя по его идентификатору и состоянию. - * - * @param userId идентификатор пользователя, запрашивающего данные о бронировании - * @param stateParam состояние бронирования - * @return ResponseEntity с объектом, представляющим результат получения данных о бронировании - */ - @GetMapping("/owner") - public ResponseEntity getByOwnerId(@RequestHeader("X-Sharer-User-Id") Long userId, - @RequestParam(value = "state", defaultValue = "ALL", - required = false) String stateParam) { - BookingState state = BookingState.from(stateParam) - .orElseThrow(() -> - new ValidationException("Неизвестное состояние бронирования: " + stateParam)); - log.info("Получение всех забронированных вещей пользователя{}, в состоянии {}", userId, state); - return bookingClient.getByOwnerId(userId, state); - } -} \ No newline at end of file diff --git a/gateway/src/main/java/ru/practicum/shareit/booking/BookingDtoInput.java b/gateway/src/main/java/ru/practicum/shareit/booking/BookingDtoInput.java deleted file mode 100644 index 0441ea2..0000000 --- a/gateway/src/main/java/ru/practicum/shareit/booking/BookingDtoInput.java +++ /dev/null @@ -1,28 +0,0 @@ -package ru.practicum.shareit.booking; - -import jakarta.validation.constraints.Future; -import jakarta.validation.constraints.FutureOrPresent; -import jakarta.validation.constraints.NotNull; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.time.LocalDateTime; - -@Data -@AllArgsConstructor -@NoArgsConstructor -public class BookingDtoInput { - - @NotNull(message = "При создании брони должна быть информация о вещи.") - private Long itemId; - - @FutureOrPresent(message = "Дата начала бронирования не должна быть в прошлом") - @NotNull(message = "Дата бронирования не должна быть пустой") - private LocalDateTime start; - - @Future(message = "Дата завершения бронирования должна быть в будущем") - @NotNull(message = "Дата бронирования не должна быть пустой") - private LocalDateTime end; - -} diff --git a/gateway/src/main/java/ru/practicum/shareit/booking/BookingState.java b/gateway/src/main/java/ru/practicum/shareit/booking/BookingState.java deleted file mode 100644 index e633731..0000000 --- a/gateway/src/main/java/ru/practicum/shareit/booking/BookingState.java +++ /dev/null @@ -1,16 +0,0 @@ -package ru.practicum.shareit.booking; - -import java.util.Optional; - -public enum BookingState { - ALL, CURRENT, PAST, FUTURE, WAITING, REJECTED; - - public static Optional from(String stringState) { - for (ru.practicum.shareit.booking.BookingState state : values()) { - if (state.name().equalsIgnoreCase(stringState)) { - return Optional.of(state); - } - } - return Optional.empty(); - } -} diff --git a/gateway/src/main/java/ru/practicum/shareit/client/BaseClient.java b/gateway/src/main/java/ru/practicum/shareit/client/BaseClient.java deleted file mode 100644 index 1a2d33a..0000000 --- a/gateway/src/main/java/ru/practicum/shareit/client/BaseClient.java +++ /dev/null @@ -1,121 +0,0 @@ -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(); - } -} diff --git a/gateway/src/main/java/ru/practicum/shareit/exception/ErrorHandler.java b/gateway/src/main/java/ru/practicum/shareit/exception/ErrorHandler.java deleted file mode 100644 index 6e40c90..0000000 --- a/gateway/src/main/java/ru/practicum/shareit/exception/ErrorHandler.java +++ /dev/null @@ -1,65 +0,0 @@ -package ru.practicum.shareit.exception; - -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; -import org.springframework.validation.BindingResult; -import org.springframework.validation.ObjectError; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.bind.MissingRequestHeaderException; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.bind.annotation.RestControllerAdvice; - -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; - -@Slf4j -@RestControllerAdvice -public class ErrorHandler { - @ExceptionHandler - @ResponseStatus(HttpStatus.BAD_REQUEST) - public ErrorResponse handleValidationException(final ValidationException e) { - log.error("{} - {}", HttpStatus.BAD_REQUEST, e.getMessage()); - return new ErrorResponse(e.getMessage()); - } - - - @ExceptionHandler - @ResponseStatus(HttpStatus.BAD_REQUEST) - public ErrorResponse handleMethodArgumentNotValidException(final MethodArgumentNotValidException e) { - BindingResult bindingResult = e.getBindingResult(); - List allErrors = bindingResult.getAllErrors(); - String defaultMessage = allErrors.stream() - .map(error -> Objects.requireNonNull(error.getDefaultMessage())) - .collect(Collectors.joining(", ")); - log.error("{} - {}", HttpStatus.BAD_REQUEST, defaultMessage); - return new ErrorResponse(defaultMessage); - } - - - @ExceptionHandler - @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) - public ErrorResponse handleRunTimeException(final RuntimeException e) { - log.error("{} - {}", HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage()); - return new ErrorResponse(e.getMessage()); - } - - @ExceptionHandler(MissingRequestHeaderException.class) - @ResponseStatus(HttpStatus.BAD_REQUEST) - public ErrorResponse handleMissingRequestHeaderException(MissingRequestHeaderException e) { - log.error("{} - {}", HttpStatus.BAD_REQUEST, e.getMessage()); - return new ErrorResponse(e.getMessage()); - } - - @Getter - public static class ErrorResponse { - private final String error; - - public ErrorResponse(String error) { - this.error = error; - } - - } -} \ No newline at end of file diff --git a/gateway/src/main/java/ru/practicum/shareit/item/CommentDtoInput.java b/gateway/src/main/java/ru/practicum/shareit/item/CommentDtoInput.java deleted file mode 100644 index d15069d..0000000 --- a/gateway/src/main/java/ru/practicum/shareit/item/CommentDtoInput.java +++ /dev/null @@ -1,18 +0,0 @@ -package ru.practicum.shareit.item; - -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@AllArgsConstructor -@NoArgsConstructor -public class CommentDtoInput { - - @NotNull(message = "Комментарий должен быть указан.") - @NotBlank(message = "Комментарий не может быть пустым.") - private String text; - -} diff --git a/gateway/src/main/java/ru/practicum/shareit/item/ItemClient.java b/gateway/src/main/java/ru/practicum/shareit/item/ItemClient.java deleted file mode 100644 index ddf344c..0000000 --- a/gateway/src/main/java/ru/practicum/shareit/item/ItemClient.java +++ /dev/null @@ -1,54 +0,0 @@ -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; - -@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 addItem(Long userId, ItemDtoInput itemDto) { - return post("", userId, itemDto); - } - - public ResponseEntity updateItem(Long userId, Long idItem, ItemDtoInput itemDto) { - return patch("/" + idItem, userId, itemDto); - } - - public ResponseEntity getItemById(Long idItem, Long userId) { - return get("/" + idItem, userId); - } - - public ResponseEntity getAllItems(Long userId) { - return get("", userId); - } - - public ResponseEntity removeItem(Long userId, Long idItem) { - return delete("/" + idItem, userId); - } - - public ResponseEntity searchItems(String text) { - return get("/search?text=" + text); - } - - public ResponseEntity saveComment(Long userId, Long itemId, CommentDtoInput commentDto) { - return post("/" + itemId + "/comment", userId, 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 deleted file mode 100644 index 6de8007..0000000 --- a/gateway/src/main/java/ru/practicum/shareit/item/ItemController.java +++ /dev/null @@ -1,122 +0,0 @@ -package ru.practicum.shareit.item; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; -import ru.practicum.shareit.validation.CreateObject; -import ru.practicum.shareit.validation.UpdateObject; - -@Controller -@RequestMapping(path = "/items") -@RequiredArgsConstructor -@Slf4j -@Validated -public class ItemController { - private final ItemClient itemClient; - - /** - * Добавляет новую вещь. - * - * @param itemDto Данные вещи. - * @param idUser Идентификатор пользователя, добавляющего вещь. - * @return ResponseEntity с объектом, представляющим результат добавления вещи. - */ - @PostMapping - @ResponseStatus(HttpStatus.CREATED) - public ResponseEntity addItem(@Validated(CreateObject.class) @RequestBody ItemDtoInput itemDto, - @RequestHeader(value = "X-Sharer-User-Id") Long idUser) { - log.info("Получен запрос пользователем {} на добавление вещи {}", idUser, itemDto); - return itemClient.addItem(idUser, itemDto); - } - - /** - * Обновляет вещь. - * - * @param idItem Идентификатор вещи, которую нужно обновить. - * @param itemDto Данные вещи. - * @param idUser Идентификатор пользователя, обновляющего вещь. - * @return ResponseEntity с объектом, представляющим результат обновления вещи. - */ - @PatchMapping("/{idItem}") - public ResponseEntity updateItem(@PathVariable Long idItem, - @Validated(UpdateObject.class) @RequestBody ItemDtoInput itemDto, - @RequestHeader(value = "X-Sharer-User-Id") Long idUser) { - log.info("Получен запрос пользователем {} на обновление вещи {}", idUser, itemDto); - return itemClient.updateItem(idUser, idItem, itemDto); - } - - /** - * Возвращает вещь по ее идентификатору. - * - * @param idItem Идентификатор вещи, которую нужно вернуть. - * @param idUser Идентификатор пользователя, запрашивающего вещь. - * @return ResponseEntity с объектом, представляющим вещь по ее идентификатору. - */ - @GetMapping("/{idItem}") - public ResponseEntity getItemById(@PathVariable Long idItem, - @RequestHeader(value = "X-Sharer-User-Id") Long idUser) { - log.info("Получен запрос пользователем {} на получение вещи с id={}", idUser, idItem); - return itemClient.getItemById(idItem, idUser); - } - - /** - * Возвращает все вещи пользователя. - * - * @param idUser Идентификатор пользователя, вещи которого нужно вернуть. - * @return ResponseEntity с объектом, представляющим все вещи пользователя. - */ - @GetMapping - public ResponseEntity getAllItemsByUser(@RequestHeader(value = "X-Sharer-User-Id") Long idUser) { - log.info("Получен запрос пользователем {} на получение всех своих вещей", idUser); - return itemClient.getAllItems(idUser); - } - - /** - * Удаляет вещь по ее идентификатору. - * - * @param idItem Идентификатор вещи, которую нужно удалить. - * @param idUser Идентификатор пользователя, удаляющего вещь. - * @return ResponseEntity с объектом, представляющим результат удаления вещи. - */ - @DeleteMapping("/{idItem}") - public ResponseEntity removeItem(@PathVariable Long idItem, - @RequestHeader(value = "X-Sharer-User-Id") Long idUser) { - log.info("Получен запрос пользователем {} на удаление вещи с id={}", idUser, idItem); - return itemClient.removeItem(idUser, idItem); - } - - /** - * Ищет вещи по тексту. - * - * @param text Текст, по которому нужно искать вещи. - * @param idUser Идентификатор пользователя, инициирующего поиск. - * @return ResponseEntity с объектом, представляющим результат поиска вещей по тексту. - */ - @GetMapping("/search") - public ResponseEntity searchItemsByText(@RequestParam String text, - @RequestHeader(value = "X-Sharer-User-Id") Long idUser) { - log.info("Получен запрос пользователем {} на поиск вещей по тексту: {}", idUser, text); - return itemClient.searchItems(text); - } - - /** - * Добавляет комментарий к вещи. - * - * @param userId Идентификатор пользователя, добавляющего комментарий. - * @param itemId Идентификатор вещи, к которой добавляется комментарий. - * @param commentDto Данные комментария. - * @return ResponseEntity с объектом, представляющим результат добавления комментария. - */ - @PostMapping("/{itemId}/comment") - public ResponseEntity addCommentToItem(@RequestHeader("X-Sharer-User-Id") Long userId, - @PathVariable Long itemId, - @RequestBody CommentDtoInput commentDto) { - log.info("Получен запрос пользователем {} на добавление отзыва на вещь с id={} с текстом: {}", - userId, itemId, commentDto.getText()); - return itemClient.saveComment(userId, itemId, commentDto); - } -} diff --git a/gateway/src/main/java/ru/practicum/shareit/request/RequestClient.java b/gateway/src/main/java/ru/practicum/shareit/request/RequestClient.java deleted file mode 100644 index ba2c019..0000000 --- a/gateway/src/main/java/ru/practicum/shareit/request/RequestClient.java +++ /dev/null @@ -1,41 +0,0 @@ -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; - -@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 addRequest(Long userId, RequestDtoInput requestDto) { - return post("", userId, requestDto); - } - - public ResponseEntity getRequests(Long userId) { - return get("", userId); - } - - public ResponseEntity getAllRequests(Long userId) { - return get("/all", userId); - } - - public ResponseEntity getRequestById(Long requestId) { - return get("/" + requestId); - } -} diff --git a/gateway/src/main/java/ru/practicum/shareit/request/RequestController.java b/gateway/src/main/java/ru/practicum/shareit/request/RequestController.java deleted file mode 100644 index 6f1d1b4..0000000 --- a/gateway/src/main/java/ru/practicum/shareit/request/RequestController.java +++ /dev/null @@ -1,73 +0,0 @@ -package ru.practicum.shareit.request; - -import jakarta.validation.Valid; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -@Controller -@RequestMapping(path = "/requests") -@RequiredArgsConstructor -@Slf4j -@Validated -public class RequestController { - - private final RequestClient requestClient; - - /** - * Добавляет новый запрос. - * - * @param requestorId Идентификатор пользователя, добавляющего запрос. - * @param requestDto Данные запроса. - * @return ResponseEntity с объектом, представляющим результат добавления запроса. - */ - @PostMapping - public ResponseEntity addRequest(@RequestHeader("X-Sharer-User-Id") Long requestorId, - @Valid @RequestBody RequestDtoInput requestDto) { - log.info("Получен запрос на добавление запроса с параметрами: {}", requestDto); - return requestClient.addRequest(requestorId, requestDto); - } - - /** - * Возвращает расширенный список запросов конкретного пользователя. - * - * @param requestorId Идентификатор пользователя, запросы которого нужно вернуть. - * @return ResponseEntity с объектом, представляющим список запросов пользователя. - */ - @GetMapping - public ResponseEntity getRequests(@RequestHeader("X-Sharer-User-Id") Long requestorId) { - log.info("Получен запрос на получение расширенного списка запросов пользователя с id: {}", requestorId); - return requestClient.getRequests(requestorId); - } - - /** - * Возвращает все запросы (за исключением запросов самого пользователя). - * - * @param requestorId Идентификатор пользователя. - * @return ResponseEntity с объектом, представляющим все запросы. - */ - @GetMapping("/all") - public ResponseEntity getAllRequests(@RequestHeader("X-Sharer-User-Id") Long requestorId) { - log.info("Получен запрос на получение всех запросов, кроме запросов самого пользователя с id: {}", requestorId); - return requestClient.getAllRequests(requestorId); - } - - /** - * Возвращает запрос по его идентификатору. - * - * @param requestorId Идентификатор пользователя, который делает запрос. - * @param requestId Идентификатор запроса, который нужно вернуть. - * @return ResponseEntity с объектом, представляющим запрос по его идентификатору. - */ - @GetMapping("/{requestId}") - public ResponseEntity getRequestsById(@RequestHeader("X-Sharer-User-Id") Long requestorId, - @PathVariable Long requestId) { - log.info("Получен запрос на получение запроса с id: {} по идентификатору пользователя с id: {}", - requestId, requestorId); - return requestClient.getRequestById(requestId); - } - -} \ No newline at end of file diff --git a/gateway/src/main/java/ru/practicum/shareit/request/RequestDtoInput.java b/gateway/src/main/java/ru/practicum/shareit/request/RequestDtoInput.java deleted file mode 100644 index 90542a2..0000000 --- a/gateway/src/main/java/ru/practicum/shareit/request/RequestDtoInput.java +++ /dev/null @@ -1,18 +0,0 @@ -package ru.practicum.shareit.request; - -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@AllArgsConstructor -@NoArgsConstructor -public class RequestDtoInput { - - @NotNull(message = "Запрос не может быть пустым.") - @NotBlank(message = "Запрос не может быть пустым.") - private String description; - -} diff --git a/gateway/src/main/java/ru/practicum/shareit/user/UserClient.java b/gateway/src/main/java/ru/practicum/shareit/user/UserClient.java deleted file mode 100644 index fe6a014..0000000 --- a/gateway/src/main/java/ru/practicum/shareit/user/UserClient.java +++ /dev/null @@ -1,46 +0,0 @@ -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; - -@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 addUser( UserDtoInput userDto) { - return post("", userDto); - } - - public ResponseEntity updateUser(Long userId, UserDtoInput userDto) { - return patch("/" + userId, userDto); - } - - public ResponseEntity getUserById(Long userId) { - return get("/" + userId); - } - - public ResponseEntity getAllUsers() { - return get(API_PREFIX); - } - - public ResponseEntity removeUser(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 deleted file mode 100644 index 5c5f256..0000000 --- a/gateway/src/main/java/ru/practicum/shareit/user/UserController.java +++ /dev/null @@ -1,81 +0,0 @@ -package ru.practicum.shareit.user; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; -import ru.practicum.shareit.validation.CreateObject; -import ru.practicum.shareit.validation.UpdateObject; - -@Controller -@RequestMapping("/users") -@RequiredArgsConstructor -@Slf4j -@Validated -public class UserController { - private final UserClient userClient; - - /** - * Добавляет нового пользователя. - * - * @param userDto данные пользователя - * @return ResponseEntity с объектом, представляющим результат добавления пользователя - */ - @PostMapping - @ResponseStatus(HttpStatus.CREATED) - public ResponseEntity addUser(@Validated(CreateObject.class) @RequestBody UserDtoInput userDto) { - log.info("Добавление нового пользователя {}", userDto); - return userClient.addUser(userDto); - } - - /** - * Обновляет данные пользователя. - * - * @param idUser идентификатор пользователя, данные которого нужно обновить - * @param userDto новые данные пользователя - * @return ResponseEntity с объектом, представляющим результат обновления данных пользователя - */ - @PatchMapping("/{idUser}") - public ResponseEntity updateUser(@PathVariable Long idUser, - @Validated(UpdateObject.class) @RequestBody UserDtoInput userDto) { - log.info("Обновление данных пользователя с id {} на основе данных {}", idUser, userDto); - return userClient.updateUser(idUser, userDto); - } - - /** - * Получает данные пользователя по его идентификатору. - * - * @param idUser идентификатор пользователя, данные которого нужно получить - * @return ResponseEntity с объектом, представляющим результат получения данных пользователя - */ - @GetMapping("/{idUser}") - public ResponseEntity getUserById(@PathVariable Long idUser) { - log.info("Получение данных пользователя с id {}", idUser); - return userClient.getUserById(idUser); - } - - /** - * Получает всех пользователей. - * - * @return ResponseEntity с объектом, представляющим результат получения всех пользователей - */ - @GetMapping - public ResponseEntity getAllUsers() { - log.info("Получение всех пользователей"); - return userClient.getAllUsers(); - } - - /** - * Удаляет пользователя по его идентификатору. - * - * @param idUser идентификатор пользователя, которого нужно удалить - */ - @DeleteMapping("/{idUser}") - public ResponseEntity removeUser(@PathVariable Long idUser) { - log.info("Удаление пользователя с id {}", idUser); - return userClient.removeUser(idUser); - } -} \ No newline at end of file diff --git a/gateway/src/main/resources/application.properties b/gateway/src/main/resources/application.properties deleted file mode 100644 index 2ee0851..0000000 --- a/gateway/src/main/resources/application.properties +++ /dev/null @@ -1,7 +0,0 @@ -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 79cba37..2185679 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,6 @@ ru.practicum shareit - pom 0.0.1-SNAPSHOT ShareIt @@ -20,29 +19,73 @@ 21 - - gateway - server - + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + org.postgresql + postgresql + + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.boot + spring-boot-starter-validation + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + + src/main/resources + true + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + - - org.springframework.boot - spring-boot-maven-plugin - - - true - - - - org.projectlombok - lombok - - - - org.apache.maven.plugins maven-surefire-plugin @@ -189,5 +232,17 @@ + + coverage + + + + org.jacoco + jacoco-maven-plugin + + + + - \ No newline at end of file + + diff --git a/postman_for_shareit_14.json b/postman_for_shareit_14.json new file mode 100644 index 0000000..d04cf55 --- /dev/null +++ b/postman_for_shareit_14.json @@ -0,0 +1,2725 @@ +{ + "info": { + "_postman_id": "f4a82602-e802-4363-87b5-c1814ccd49db", + "name": "Sprint 14 ShareIt (add-controllers)", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "23073145", + "_collection_link": "https://universal-shadow-295426.postman.co/workspace/My-Workspace~4200f6aa-0504-44b1-8a1d-707d0dcbd5ce/collection/13708500-f4a82602-e802-4363-87b5-c1814ccd49db?action=share&source=collection_link&creator=23073145" + }, + "item": [ + { + "name": "users", + "item": [ + { + "name": "Create user", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user = rnd.getUser();\r", + " pm.collectionVariables.set(\"userName\", user.name);\r", + " pm.collectionVariables.set(\"userEmail\", user.email);\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200 or 201\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200,201]);\r", + "});\r", + "pm.test(\"Response have body\", function () {\r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"{{userName}}\",\n \"email\": \"{{userEmail}}\"\n}" + }, + "url": { + "raw": "localhost:8080/users", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users" + ] + } + }, + "response": [] + }, + { + "name": "Create user without email", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user2 = rnd.getUser();\r", + " pm.collectionVariables.set(\"userName\", user2.name);\r", + " pm.collectionVariables.set(\"userEmail\", user2.email);\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 400\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([400, 500]);\r", + "});\r", + "pm.test(\"Response have body\", function () {\r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"{{userName}}\"\n}" + }, + "url": { + "raw": "localhost:8080/users", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users" + ] + } + }, + "response": [] + }, + { + "name": "Create 2 users with same email", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user1 = rnd.getUser();\r", + " us = await api.addUser(user1);\r", + " user2 = rnd.getUser();\r", + " user2.email = user1.email;\r", + " pm.collectionVariables.set(\"userName\", user2.name);\r", + " pm.collectionVariables.set(\"userEmail\", user2.email);\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 409\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([409, 500]);\r", + "});\r", + "pm.test(\"Response have body\", function () {\r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"{{userName}}\",\n \"email\": \"{{userEmail}}\"\n}" + }, + "url": { + "raw": "localhost:8080/users", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users" + ] + } + }, + "response": [] + }, + { + "name": "Create user with invalid email", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user = rnd.getUser();\r", + " pm.collectionVariables.set(\"userName\", user.name);\r", + " pm.collectionVariables.set(\"userEmail\", user.email);\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 400\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([400, 500]);\r", + "});\r", + "pm.test(\"Response have body\", function () {\r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"{{userName}}\",\n \"email\": \"user.com\"\n}" + }, + "url": { + "raw": "localhost:8080/users", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "users" + ] + } + }, + "response": [] + }, + { + "name": "User update", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user = rnd.getUser();\r", + " us = await api.addUser(user);\r", + " pm.collectionVariables.set(\"userId\", us.id);\r", + " us = rnd.getUser()\r", + " pm.collectionVariables.set(\"userName\", us.name);\r", + " pm.collectionVariables.set(\"userEmail\", us.email);\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {\r", + " pm.response.to.be.ok;\r", + "});\r", + "pm.test(\"Response have body\", function () {\r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "pm.test(\"Test user 'id' field\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.have.property('id');\r", + " var id = pm.collectionVariables.get(\"userId\");\r", + " pm.expect(jsonData.id, '\"id\" must be ' + id).to.eql(Number(id));\r", + "});\r", + "pm.test(\"Test user 'email' field\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.have.property('email');\r", + " var email = pm.collectionVariables.get(\"userEmail\");\r", + " pm.expect(jsonData.email, '\"email\" must be ' + email).to.eql(email);\r", + "});\r", + "pm.test(\"Test user 'name' field\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.have.property('name');\r", + " var name = pm.collectionVariables.get(\"userName\");\r", + " pm.expect(jsonData.name, '\"name\" must be ' + name).to.eql(name);\r", + "});\r", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"{{userName}}\",\n \"email\": \"{{userEmail}}\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/users/{{userId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "users", + "{{userId}}" + ] + } + }, + "response": [] + }, + { + "name": "User update name", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user = rnd.getUser();\r", + " us = await api.addUser(user);\r", + " pm.collectionVariables.set(\"userId\", us.id);\r", + " us = rnd.getUser()\r", + " pm.collectionVariables.set(\"userName\", us.name);\r", + " pm.collectionVariables.set(\"userEmail\", us.email);\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {\r", + " pm.response.to.be.ok;\r", + "});\r", + "pm.test(\"Response have body\", function () {\r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "pm.test(\"Test user 'id' field\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.have.property('id');\r", + " var id = pm.collectionVariables.get(\"userId\");\r", + " pm.expect(jsonData.id, '\"id\" must be ' + id).to.eql(Number(id));\r", + "});\r", + "pm.test(\"Test user 'name' field\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.have.property('name');\r", + " var name = pm.collectionVariables.get(\"userName\");\r", + " pm.expect(jsonData.name, '\"name\" must be ' + name).to.eql(name);\r", + "});\r", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"{{userName}}\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/users/{{userId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "users", + "{{userId}}" + ] + } + }, + "response": [] + }, + { + "name": "User update email", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user = rnd.getUser();\r", + " us = await api.addUser(user);\r", + " pm.collectionVariables.set(\"userId\", us.id);\r", + " us = rnd.getUser()\r", + " pm.collectionVariables.set(\"userName\", us.name);\r", + " pm.collectionVariables.set(\"userEmail\", us.email);\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {\r", + " pm.response.to.be.ok;\r", + "});\r", + "pm.test(\"Response have body\", function () {\r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "pm.test(\"Test user 'id' field\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.have.property('id');\r", + " var id = pm.collectionVariables.get(\"userId\");\r", + " pm.expect(jsonData.id, '\"id\" must be ' + id).to.eql(Number(id));\r", + "});\r", + "pm.test(\"Test user 'email' field\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.have.property('email');\r", + " var email = pm.collectionVariables.get(\"userEmail\");\r", + " pm.expect(jsonData.email, '\"email\" must be ' + email).to.eql(email);\r", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"email\": \"{{userEmail}}\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/users/{{userId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "users", + "{{userId}}" + ] + } + }, + "response": [] + }, + { + "name": "User update with existing email", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user = rnd.getUser();\r", + " us = await api.addUser(user);\r", + " user2 = rnd.getUser();\r", + " us2 = await api.addUser(user2)\r", + " pm.collectionVariables.set(\"userId\", us2.id);\r", + " usa = rnd.getUser()\r", + " pm.collectionVariables.set(\"userName\", usa.name);\r", + " pm.collectionVariables.set(\"userEmail\", user.email);\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 409\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([409, 500]);\r", + "});\r", + "pm.test(\"Response have body\", function () {\r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"{{userName}}\",\n \"email\": \"{{userEmail}}\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/users/{{userId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "users", + "{{userId}}" + ] + } + }, + "response": [] + }, + { + "name": "Get user", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user = rnd.getUser();\r", + " us = await api.addUser(user);\r", + " pm.collectionVariables.set(\"userId\", us.id);\r", + " pm.collectionVariables.set(\"userName\", us.name);\r", + " pm.collectionVariables.set(\"userEmail\", us.email);\r", + "\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {\r", + " pm.response.to.be.ok;\r", + "});\r", + "pm.test(\"Response have body\", function () {\r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "pm.test(\"Test user 'id' field\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.have.property('id');\r", + " var id = pm.collectionVariables.get(\"userId\");\r", + " pm.expect(jsonData.id, '\"id\" must be ' + id).to.eql(Number(id));\r", + "});\r", + "pm.test(\"Test user 'email' field\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.have.property('email');\r", + " var email = pm.collectionVariables.get(\"userEmail\");\r", + " pm.expect(jsonData.email, '\"email\" must be ' + email).to.eql(email);\r", + "});\r", + "pm.test(\"Test user 'name' field\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.have.property('name');\r", + " var name = pm.collectionVariables.get(\"userName\");\r", + " pm.expect(jsonData.name, '\"name\" must be ' + name).to.eql(name);\r", + "});\r", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{baseUrl}}/users/{{userId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "users", + "{{userId}}" + ] + } + }, + "response": [] + }, + { + "name": "User delete", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200,204]);", + "});", + "" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user = rnd.getUser();\r", + " us = await api.addUser(user);\r", + " pm.collectionVariables.set(\"userId\", us.id);\r", + " pm.collectionVariables.set(\"userName\", us.name);\r", + " pm.collectionVariables.set(\"userEmail\", us.email);\r", + "\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "DELETE", + "header": [ + { + "key": "Accept", + "value": "*/*", + "type": "text" + } + ], + "url": { + "raw": "{{baseUrl}}/users/{{userId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "users", + "{{userId}}" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "items", + "item": [ + { + "name": "Item create", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " item = rnd.getItem();\r", + " pm.collectionVariables.set(\"item\", item);\r", + " pm.collectionVariables.set(\"itemName\", item.name);\r", + " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", + " pm.collectionVariables.set(\"itemDescription\", item.description);\r", + " user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user.id);\r", + "\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200 or 201\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200,201]);\r", + "});\r", + "pm.test(\"Response have body\", function () {\r", + " pm.response.to.be.withBody;\r", + " pm.response.to.be.json;\r", + "});\r", + "var item = pm.collectionVariables.get(\"item\");\r", + "\r", + "pm.test(\"Response data equal to request\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.have.property('id');\r", + " pm.expect(jsonData).to.have.property('name');\r", + " pm.expect(jsonData).to.have.property('description');\r", + " pm.expect(jsonData).to.have.property('available');\r", + " pm.expect(jsonData.name, `\"name\" must be ${item.name}`).to.eql(item.name);\r", + " pm.expect(jsonData.description, `\"description\" must be ${item.description}`).to.eql(item.description);\r", + " pm.expect(jsonData.available.toString(), `\"available\" must be ${item.available}`).to.eql(item.available.toString());\r", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}}\n}" + }, + "url": { + "raw": "localhost:8080/items", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "items" + ] + } + }, + "response": [] + }, + { + "name": "Item create without X-Sharer-User-Id", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " item = rnd.getItem();\r", + " pm.collectionVariables.set(\"item\", item);\r", + " pm.collectionVariables.set(\"itemName\", item.name);\r", + " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", + " pm.collectionVariables.set(\"itemDescription\", item.description);\r", + " user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user.id);\r", + "\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 400 or 500\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([500, 400]);\r", + "});\r", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "disabled": true + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}}\n}" + }, + "url": { + "raw": "localhost:8080/items", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "items" + ] + } + }, + "response": [] + }, + { + "name": "Item create with non-existent user", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " item = rnd.getItem();\r", + " pm.collectionVariables.set(\"item\", item);\r", + " pm.collectionVariables.set(\"itemName\", item.name);\r", + " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", + " pm.collectionVariables.set(\"itemDescription\", item.description);\r", + " user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user.id + '1');\r", + "\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 404\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([404]);\r", + "});\r", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}}\n}" + }, + "url": { + "raw": "localhost:8080/items", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "items" + ] + } + }, + "response": [] + }, + { + "name": "Item create without available field", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " item = rnd.getItem();\r", + " pm.collectionVariables.set(\"item\", item);\r", + " pm.collectionVariables.set(\"itemName\", item.name);\r", + " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", + " pm.collectionVariables.set(\"itemDescription\", item.description);\r", + " user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user.id);\r", + "\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 400\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([400, 500]);\r", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\"\n}" + }, + "url": { + "raw": "localhost:8080/items", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "items" + ] + } + }, + "response": [] + }, + { + "name": "Item create with empty name field", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 400\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([400, 500]);", + "});", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "Accept", + "value": "*/*", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"\",\n \"description\": \"Аккумуляторная отвертка\",\n \"available\": true\n}" + }, + "url": { + "raw": "{{baseUrl}}/items", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "items" + ] + } + }, + "response": [] + }, + { + "name": "Item create with empty description field", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 400\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([400, 500]);", + "});", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "Accept", + "value": "*/*", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"Отвертка\",\n \"available\": true\n}" + }, + "url": { + "raw": "{{baseUrl}}/items", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "items" + ] + } + }, + "response": [] + }, + { + "name": "Item update", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.be.ok;", + "});", + "pm.test(\"Response have body\", function () {", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "var item = pm.collectionVariables.get(\"item\");", + "", + "pm.test(\"Response data equal to request\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData).to.have.property('id');", + " pm.expect(jsonData).to.have.property('name');", + " pm.expect(jsonData).to.have.property('description');", + " pm.expect(jsonData).to.have.property('available');", + " pm.expect(jsonData.name, `\"name\" must be ${item.name}`).to.eql(item.name);", + " pm.expect(jsonData.description, `\"description\" must be ${item.description}`).to.eql(item.description);", + " pm.expect(jsonData.available.toString(), `\"available\" must be ${item.available}`).to.eql(item.available.toString());", + "});" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user.id);\r", + " item = rnd.getItem();\r", + " var it = await api.addItem(item, user.id)\r", + " item = rnd.getItem();\r", + " pm.collectionVariables.set(\"item\", item); \r", + " pm.collectionVariables.set(\"itemId\", it.id);\r", + " pm.collectionVariables.set(\"itemName\", item.name);\r", + " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", + " pm.collectionVariables.set(\"itemDescription\", item.description);\r", + "\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "Accept", + "value": "*/*", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}}\n}" + }, + "url": { + "raw": "{{baseUrl}}/items/{{itemId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "items", + "{{itemId}}" + ] + } + }, + "response": [] + }, + { + "name": "Item update without X-Sharer-User-Id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 500\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([500, 400]);", + "});" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user.id);\r", + " item = rnd.getItem();\r", + " var it = await api.addItem(item, user.id)\r", + " item = rnd.getItem();\r", + " pm.collectionVariables.set(\"item\", item); \r", + " pm.collectionVariables.set(\"itemId\", it.id);\r", + " pm.collectionVariables.set(\"itemName\", item.name);\r", + " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", + " pm.collectionVariables.set(\"itemDescription\", item.description);\r", + "\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text", + "disabled": true + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "Accept", + "value": "*/*", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}}\n}" + }, + "url": { + "raw": "{{baseUrl}}/items/{{itemId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "items", + "{{itemId}}" + ] + } + }, + "response": [] + }, + { + "name": "Item update with other user", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 404\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([404, 403]);", + "});" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user.id + 1);\r", + " item = rnd.getItem();\r", + " var it = await api.addItem(item, user.id)\r", + " item = rnd.getItem();\r", + " pm.collectionVariables.set(\"item\", item); \r", + " pm.collectionVariables.set(\"itemId\", it.id);\r", + " pm.collectionVariables.set(\"itemName\", item.name);\r", + " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", + " pm.collectionVariables.set(\"itemDescription\", item.description);\r", + "\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "Accept", + "value": "*/*", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}}\n}" + }, + "url": { + "raw": "{{baseUrl}}/items/{{itemId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "items", + "{{itemId}}" + ] + } + }, + "response": [] + }, + { + "name": "Item update available field", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.be.ok;", + "});", + "pm.test(\"Response have body\", function () {", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "var item = pm.collectionVariables.get(\"item\");", + "", + "pm.test(\"Response data equal to request\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData).to.have.property('id');", + " pm.expect(jsonData).to.have.property('available');", + " pm.expect(jsonData.available.toString(), `\"available\" must be ${item.available}`).to.eql(item.available.toString());", + "});" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user.id);\r", + " item = rnd.getItem();\r", + " var it = await api.addItem(item, user.id)\r", + " item = rnd.getItem();\r", + " pm.collectionVariables.set(\"item\", item); \r", + " pm.collectionVariables.set(\"itemId\", it.id);\r", + " pm.collectionVariables.set(\"itemName\", item.name);\r", + " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", + " pm.collectionVariables.set(\"itemDescription\", item.description);\r", + "\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "Accept", + "value": "*/*", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"available\": {{itemAvailable}}\n}" + }, + "url": { + "raw": "{{baseUrl}}/items/{{itemId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "items", + "{{itemId}}" + ] + } + }, + "response": [] + }, + { + "name": "Item update description field", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.be.ok;", + "});", + "pm.test(\"Response have body\", function () {", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "var item = pm.collectionVariables.get(\"item\");", + "", + "pm.test(\"Response data equal to request\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData).to.have.property('id');", + " pm.expect(jsonData).to.have.property('name');", + " pm.expect(jsonData).to.have.property('description');", + " pm.expect(jsonData).to.have.property('available');", + " pm.expect(jsonData.description, `\"description\" must be ${item.description}`).to.eql(item.description);", + "});" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user.id);\r", + " item = rnd.getItem();\r", + " var it = await api.addItem(item, user.id)\r", + " item = rnd.getItem();\r", + " pm.collectionVariables.set(\"item\", item); \r", + " pm.collectionVariables.set(\"itemId\", it.id);\r", + " pm.collectionVariables.set(\"itemName\", item.name);\r", + " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", + " pm.collectionVariables.set(\"itemDescription\", item.description);\r", + "\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "Accept", + "value": "*/*", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"description\": \"{{itemDescription}}\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/items/{{itemId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "items", + "{{itemId}}" + ] + } + }, + "response": [] + }, + { + "name": "Item update name field", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.be.ok;", + "});", + "pm.test(\"Response have body\", function () {", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "var item = pm.collectionVariables.get(\"item\");", + "", + "pm.test(\"Response data equal to request\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData).to.have.property('id');", + " pm.expect(jsonData).to.have.property('name');", + " pm.expect(jsonData).to.have.property('description');", + " pm.expect(jsonData).to.have.property('available');", + " pm.expect(jsonData.name, `\"name\" must be ${item.name}`).to.eql(item.name);", + "});" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user.id);\r", + " item = rnd.getItem();\r", + " var it = await api.addItem(item, user.id)\r", + " item = rnd.getItem();\r", + " pm.collectionVariables.set(\"item\", item); \r", + " pm.collectionVariables.set(\"itemId\", it.id);\r", + " pm.collectionVariables.set(\"itemName\", item.name);\r", + " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", + " pm.collectionVariables.set(\"itemDescription\", item.description);\r", + "\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "Accept", + "value": "*/*", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"{{itemName}}\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/items/{{itemId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "items", + "{{itemId}}" + ] + } + }, + "response": [] + }, + { + "name": "Item get", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.be.ok;", + "});", + "pm.test(\"Response have body\", function () {", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "var item = pm.collectionVariables.get(\"item\");", + "", + "pm.test(\"Response data equal to request\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData).to.have.property('id');", + " pm.expect(jsonData).to.have.property('name');", + " pm.expect(jsonData).to.have.property('description');", + " pm.expect(jsonData).to.have.property('available');", + " pm.expect(jsonData.name, `\"name\" must be ${item.name}`).to.eql(item.name);", + " pm.expect(jsonData.description, `\"description\" must be ${item.description}`).to.eql(item.description);", + " pm.expect(jsonData.available.toString(), `\"available\" must be ${item.available}`).to.eql(item.available.toString());", + "});" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user.id);\r", + " item = await api.addItem(rnd.getItem(), user.id)\r", + " pm.collectionVariables.set(\"item\", item);\r", + " pm.collectionVariables.set(\"itemId\", item.id);\r", + " pm.collectionVariables.set(\"itemName\", item.name);\r", + " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", + " pm.collectionVariables.set(\"itemDescription\", item.description);\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text" + }, + { + "key": "Accept", + "value": "*/*", + "type": "text" + } + ], + "url": { + "raw": "{{baseUrl}}/items/{{itemId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "items", + "{{itemId}}" + ] + } + }, + "response": [] + }, + { + "name": "Get all items from user", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.be.ok;", + "});", + "pm.test(\"Test list item response\", function () {", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.length, 'List length must be 2').to.eql(2);", + "});", + "", + "" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user.id);\r", + " await api.addItem(rnd.getItem(), user.id)\r", + " await api.addItem(rnd.getItem(), user.id)\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text" + }, + { + "key": "Accept", + "value": "*/*", + "type": "text" + } + ], + "url": { + "raw": "{{baseUrl}}/items", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "items" + ] + } + }, + "response": [] + }, + { + "name": "Item search", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.be.ok;", + "});", + "pm.test(\"Test list item response\", function () {", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.length, 'List length must be 1').to.eql(1);", + " pm.expect(jsonData[0].name.toUpperCase(), 'Name should include ' + pm.collectionVariables.get(\"searchString\")).to.eql(pm.collectionVariables.get(\"searchString\"))", + "});", + "" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user.id);\r", + " it = rnd.getItem()\r", + " it.available = true\r", + " item = await api.addItem(it, user.id)\r", + " pm.collectionVariables.set(\"item\", item);\r", + " pm.collectionVariables.set(\"itemId\", item.id);\r", + " pm.collectionVariables.set(\"itemName\", item.name);\r", + " pm.collectionVariables.set(\"searchString\", item.name.toUpperCase());\r", + " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", + " pm.collectionVariables.set(\"itemDescription\", item.description);\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text" + }, + { + "key": "Accept", + "value": "*/*", + "type": "text" + } + ], + "url": { + "raw": "{{baseUrl}}/items/search?text={{searchString}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "items", + "search" + ], + "query": [ + { + "key": "text", + "value": "{{searchString}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Item search unavailable", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.be.ok;", + "});", + "pm.test(\"Test list item response\", function () {", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.length, 'List length must be 0').to.eql(0);", + "});", + "" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user.id);\r", + " it = rnd.getItem()\r", + " it.available = false\r", + " item = await api.addItem(it, user.id)\r", + " pm.collectionVariables.set(\"item\", item);\r", + " pm.collectionVariables.set(\"itemId\", item.id);\r", + " pm.collectionVariables.set(\"itemName\", item.name);\r", + " pm.collectionVariables.set(\"searchString\", item.name.toUpperCase());\r", + " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", + " pm.collectionVariables.set(\"itemDescription\", item.description);\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text" + }, + { + "key": "Accept", + "value": "*/*", + "type": "text" + } + ], + "url": { + "raw": "{{baseUrl}}/items/search?text={{searchString}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "items", + "search" + ], + "query": [ + { + "key": "text", + "value": "{{searchString}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Item search empty", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.be.ok;", + "});", + "pm.test(\"Test search item response\", function () {", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.length, 'List length must be 0').to.eql(0);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text" + }, + { + "key": "Accept", + "value": "*/*", + "type": "text" + } + ], + "url": { + "raw": "{{baseUrl}}/items/search?text=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "items", + "search" + ], + "query": [ + { + "key": "text", + "value": "" + } + ] + } + }, + "response": [] + } + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [ + "API = class {\r", + " constructor(postman, verbose = false, baseUrl = \"http://localhost:8080\") {\r", + " this.baseUrl = baseUrl;\r", + " this.pm = postman;\r", + " this._verbose = verbose;\r", + " }\r", + "\r", + " async addUser(user, id=0, verbose=null) {\r", + " return this.post(\"/users\", user, id, \"Ошибка при добавлении нового пользователя: \", verbose);\r", + " }\r", + "\r", + " async addItem(item, id=0, verbose=null) {\r", + " return this.post(\"/items\", item, id, \"Ошибка при добавлении новой вещи: \", verbose);\r", + " }\r", + "\r", + " async addRequest(request, id=0, verbose=null) {\r", + " return this.post(\"/requests\", request, id, \"Ошибка при добавлении нового запроса: \", verbose);\r", + " }\r", + " \r", + " async post(path, body, id=0, errorText = \"Ошибка при выполнении post-запроса: \", verbose=null) {\r", + " return this.sendRequest(\"POST\", path, body, id, errorText, verbose);\r", + " }\r", + "\r", + " async patch(path, body = null, id=0, errorText = \"Ошибка при выполнении patch-запроса: \", verbose=null) {\r", + " return this.sendRequest(\"PATCH\", path, body, id, errorText, verbose);\r", + " }\r", + "\r", + " async get(path, body = null, id=0, errorText = \"Ошибка при выполнении get-запроса: \", verbose=null) {\r", + " return this.sendRequest(\"GET\", path, body, id, errorText, verbose);\r", + " }\r", + "\r", + " async put(path, body = null, id=0, errorText = \"Ошибка при выполнении put-запроса: \", verbose=null) {\r", + " return this.sendRequest(\"PUT\", path, body, id, errorText, verbose);\r", + " }\r", + "\r", + " async delete(path, body = null, id=0, errorText = \"Ошибка при выполнении delte-запроса: \", verbose=null) {\r", + " return this.sendRequest(\"DELETE\", path, body, id, errorText, verbose);\r", + " }\r", + "\r", + " async sendRequest(method, path, body=null, id=0, errorText = \"Ошибка при выполнении запроса: \", verbose=null) {\r", + " return new Promise((resolve, reject) => {\r", + " verbose = verbose == null ? this._verbose : verbose;\r", + " var req = {};\r", + " if (id == 0){\r", + " req = {\r", + " url: this.baseUrl + path,\r", + " method: method,\r", + " body: body == null ? \"\" : JSON.stringify(body),\r", + " header: { \"Content-Type\": \"application/json\"},\r", + " };\r", + " }else{\r", + " req = {\r", + " url: this.baseUrl + path,\r", + " method: method,\r", + " body: body == null ? \"\" : JSON.stringify(body),\r", + " header: [{\r", + " \"key\": \"X-Sharer-User-Id\",\r", + " \"value\": id,\r", + " \"type\": \"text\",\r", + " },\r", + " {\r", + " \"key\": \"Content-Type\",\r", + " \"name\": \"Content-Type\",\r", + " \"value\": \"application/json\",\r", + " \"type\": \"text\"\r", + " }]\r", + " };\r", + " }\r", + " if(verbose) {\r", + " console.log(\"Отправляю запрос: \", req);\r", + " }\r", + "\r", + " try {\r", + " this.pm.sendRequest(req, (error, response) => {\r", + " if(error || (response.code >= 400 && response.code <= 599)) {\r", + " let err = error ? error : JSON.stringify(response.json());\r", + " console.error(\"При выполнении запроса к серверу возникла ошибка.\\n\", err,\r", + " \"\\nДля отладки проблемы повторите такой же запрос к вашей программе \" + \r", + " \"на локальном компьютере. Данные запроса:\\n\", JSON.stringify(request));\r", + "\r", + " reject(new Error(errorText + err));\r", + " }\r", + " if(verbose) {\r", + " console.log(\"Результат обработки запроса: код состояния - \", response.code, \", тело: \", response.json());\r", + " }\r", + " if (response.stream.length === 0){\r", + " resolve(null);\r", + " }else{\r", + " resolve(response.json());\r", + " }\r", + " });\r", + " \r", + " } catch(err) {\r", + " if(verbose) {\r", + " console.error(errorText, err);\r", + " }\r", + " return Promise.reject(err);\r", + " }\r", + " });\r", + " }\r", + "};\r", + "\r", + "RandomUtils = class {\r", + " constructor() {}\r", + "\r", + " getUser() {\r", + " return {\r", + " name: pm.variables.replaceIn('{{$randomFullName}}'),\r", + " email: pm.variables.replaceIn('{{$randomEmail}}'),\r", + " };\r", + " }\r", + "\r", + " getRequest() {\r", + " return {\r", + " description: this.getWord(50)\r", + " };\r", + " }\r", + "\r", + " getItem() {\r", + " return {\r", + " name: this.getWord(10),\r", + " description: this.getWord(50),\r", + " available: pm.variables.replaceIn('{{$randomBoolean}}')\t\r", + " };\r", + " }\r", + "\r", + " getItemForRequest(id) {\r", + " return {\r", + " name: this.getWord(10),\r", + " description: this.getWord(50),\r", + " available: pm.variables.replaceIn('{{$randomBoolean}}'),\r", + " requestId: id\r", + " };\r", + " }\r", + "\r", + " getFilm(director=null) {\r", + " let date = new Date(new Date(1960, 0, 1).getTime() + Math.random() * (new Date(2010, 0, 1).getTime() - new Date(1960, 0, 1).getTime()));\r", + " var toReturn = {\r", + " name: this.getWord(15),\r", + " description: this.getWord(50),\r", + " releaseDate: date.toISOString().slice(0,10),\r", + " duration: Math.floor(Math.random() * (180 - 60 + 1) + 60),\r", + " mpa: { id: Math.floor(Math.random() * (5 - 1 + 1) + 1)},\r", + " genres: [{ id: Math.floor(Math.random() * (6 - 1 + 1) + 1)}]\r", + " };\r", + " if (director!==null)\r", + " toReturn.directors = [{ id: director.id}];\r", + " return toReturn;\r", + " }\r", + "\r", + "\r", + " getWord(length = 1) {\r", + " let result = '';\r", + " const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\r", + " const charactersLength = characters.length;\r", + " let counter = 0;\r", + " while (counter < length) {\r", + " result += characters.charAt(Math.floor(Math.random() * charactersLength));\r", + " counter += 1;\r", + " }\r", + " return result;\r", + " }\r", + "\r", + " getName(length = 1) {\r", + " let result = '';\r", + " const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';\r", + " const charactersLength = characters.length;\r", + " let counter = 0;\r", + " while (counter < length) {\r", + " result += characters.charAt(Math.floor(Math.random() * charactersLength));\r", + " counter += 1;\r", + " }\r", + " return result;\r", + " }\r", + "\r", + "}" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "baseUrl", + "value": "http://localhost:8080" + }, + { + "key": "userName", + "value": "" + }, + { + "key": "userEmail", + "value": "" + }, + { + "key": "userId", + "value": "1", + "type": "string" + }, + { + "key": "item", + "value": "" + }, + { + "key": "itemName", + "value": "" + }, + { + "key": "itemAvailable", + "value": "" + }, + { + "key": "itemDescription", + "value": "" + }, + { + "key": "itemId", + "value": "" + }, + { + "key": "searchString", + "value": "" + } + ] +} diff --git a/postman_for_shareit_16.json b/postman_for_shareit_15.json similarity index 81% rename from postman_for_shareit_16.json rename to postman_for_shareit_15.json index 6e87b6b..26845fe 100644 --- a/postman_for_shareit_16.json +++ b/postman_for_shareit_15.json @@ -1,10 +1,10 @@ { "info": { - "_postman_id": "7fc26681-0775-4307-885f-fd53560f0317", - "name": "Sprint 16 ShareIt (add-item-requests-and-gateway)", + "_postman_id": "069d256e-037e-4bd9-a5de-be6910726adc", + "name": "Sprint 15 ShareIt (add-bookings)", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", "_exporter_id": "23073145", - "_collection_link": "https://universal-shadow-295426.postman.co/workspace/My-Workspace~4200f6aa-0504-44b1-8a1d-707d0dcbd5ce/collection/13708500-7fc26681-0775-4307-885f-fd53560f0317?action=share&source=collection_link&creator=23073145" + "_collection_link": "https://universal-shadow-295426.postman.co/workspace/My-Workspace~4200f6aa-0504-44b1-8a1d-707d0dcbd5ce/collection/13708500-069d256e-037e-4bd9-a5de-be6910726adc?action=share&source=collection_link&creator=23073145" }, "item": [ { @@ -921,10 +921,10 @@ ] }, { - "name": "Item", + "name": "items", "item": [ { - "name": "Create Item", + "name": "Item create", "event": [ { "listen": "prerequest", @@ -1027,7 +1027,7 @@ "response": [] }, { - "name": "Create Item on request", + "name": "Item create without X-Sharer-User-Id", "event": [ { "listen": "prerequest", @@ -1038,18 +1038,13 @@ " const rnd = new RandomUtils();\r", "\r", " try {\r", - " user1 = await api.addUser(rnd.getUser());\r", - " var request = await api.addRequest(rnd.getRequest(), user1.id);\r", - " pm.collectionVariables.set(\"requestId\", request.id);\r", - " user2 = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user2.id);\r", - "\r", " item = rnd.getItem();\r", " pm.collectionVariables.set(\"item\", item);\r", " pm.collectionVariables.set(\"itemName\", item.name);\r", " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", " pm.collectionVariables.set(\"itemDescription\", item.description);\r", - "\r", + " user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user.id);\r", "\r", " } catch(err) {\r", " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", @@ -1080,25 +1075,10 @@ "listen": "test", "script": { "exec": [ - "pm.test(\"Status code is 200 or 201\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([200,201]);\r", - "});\r", - "pm.test(\"Response have body\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", + "pm.test(\"Status code is 400 or 500\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([500, 400]);\r", "});\r", - "var item = pm.collectionVariables.get(\"item\");\r", - "\r", - "pm.test(\"Response data equal to request\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('id');\r", - " pm.expect(jsonData).to.have.property('name');\r", - " pm.expect(jsonData).to.have.property('description');\r", - " pm.expect(jsonData).to.have.property('available');\r", - " pm.expect(jsonData.name, `\"name\" must be ${item.name}`).to.eql(item.name);\r", - " pm.expect(jsonData.description, `\"description\" must be ${item.description}`).to.eql(item.description);\r", - " pm.expect(jsonData.available.toString(), `\"available\" must be ${item.available}`).to.eql(item.available.toString());\r", - "});" + "" ], "type": "text/javascript", "packages": {} @@ -1114,12 +1094,13 @@ }, { "key": "X-Sharer-User-Id", - "value": "{{userId}}" + "value": "{{userId}}", + "disabled": true } ], "body": { "mode": "raw", - "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}},\n \"requestId\": {{requestId}}\n}" + "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}}\n}" }, "url": { "raw": "localhost:8080/items", @@ -1135,7 +1116,7 @@ "response": [] }, { - "name": "Create Item without name on request", + "name": "Item create with non-existent user", "event": [ { "listen": "prerequest", @@ -1146,18 +1127,13 @@ " const rnd = new RandomUtils();\r", "\r", " try {\r", - " user1 = await api.addUser(rnd.getUser());\r", - " var request = await api.addRequest(rnd.getRequest(), user1.id);\r", - " pm.collectionVariables.set(\"requestId\", request.id);\r", - " user2 = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user2.id);\r", - "\r", " item = rnd.getItem();\r", " pm.collectionVariables.set(\"item\", item);\r", " pm.collectionVariables.set(\"itemName\", item.name);\r", " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", " pm.collectionVariables.set(\"itemDescription\", item.description);\r", - "\r", + " user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user.id + '1');\r", "\r", " } catch(err) {\r", " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", @@ -1188,17 +1164,10 @@ "listen": "test", "script": { "exec": [ - "pm.test(\"Status code is 400\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([400, 500]);\r", - "});\r", - "pm.test(\"Response have body\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", + "pm.test(\"Status code is 404\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([404]);\r", "});\r", - "pm.test(\"Response data have error\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('error');\r", - "});" + "" ], "type": "text/javascript", "packages": {} @@ -1219,7 +1188,7 @@ ], "body": { "mode": "raw", - "raw": "{\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}},\n \"requestId\": {{requestId}}\n}" + "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}}\n}" }, "url": { "raw": "localhost:8080/items", @@ -1235,7 +1204,7 @@ "response": [] }, { - "name": "Create Item without description on request", + "name": "Item create without available field", "event": [ { "listen": "prerequest", @@ -1246,18 +1215,13 @@ " const rnd = new RandomUtils();\r", "\r", " try {\r", - " user1 = await api.addUser(rnd.getUser());\r", - " var request = await api.addRequest(rnd.getRequest(), user1.id);\r", - " pm.collectionVariables.set(\"requestId\", request.id);\r", - " user2 = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user2.id);\r", - "\r", " item = rnd.getItem();\r", " pm.collectionVariables.set(\"item\", item);\r", " pm.collectionVariables.set(\"itemName\", item.name);\r", " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", " pm.collectionVariables.set(\"itemDescription\", item.description);\r", - "\r", + " user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user.id);\r", "\r", " } catch(err) {\r", " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", @@ -1290,14 +1254,6 @@ "exec": [ "pm.test(\"Status code is 400\", function () {\r", " pm.expect(pm.response.code).to.be.oneOf([400, 500]);\r", - "});\r", - "pm.test(\"Response have body\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});\r", - "pm.test(\"Response data have error\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('error');\r", "});" ], "type": "text/javascript", @@ -1319,7 +1275,7 @@ ], "body": { "mode": "raw", - "raw": "{\n \"name\": \"{{itemName}}\",\n \"available\": {{itemAvailable}},\n \"requestId\": {{requestId}}\n}" + "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\"\n}" }, "url": { "raw": "localhost:8080/items", @@ -1335,8 +1291,140 @@ "response": [] }, { - "name": "Create Item without available on request", + "name": "Item create with empty name field", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 400\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([400, 500]);", + "});", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "Accept", + "value": "*/*", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"\",\n \"description\": \"Аккумуляторная отвертка\",\n \"available\": true\n}" + }, + "url": { + "raw": "{{baseUrl}}/items", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "items" + ] + } + }, + "response": [] + }, + { + "name": "Item create with empty description field", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 400\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([400, 500]);", + "});", + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "Accept", + "value": "*/*", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"Отвертка\",\n \"available\": true\n}" + }, + "url": { + "raw": "{{baseUrl}}/items", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "items" + ] + } + }, + "response": [] + }, + { + "name": "Item update", "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.be.ok;", + "});", + "pm.test(\"Response have body\", function () {", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "var item = pm.collectionVariables.get(\"item\");", + "", + "pm.test(\"Response data equal to request\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData).to.have.property('id');", + " pm.expect(jsonData).to.have.property('name');", + " pm.expect(jsonData).to.have.property('description');", + " pm.expect(jsonData).to.have.property('available');", + " pm.expect(jsonData.name, `\"name\" must be ${item.name}`).to.eql(item.name);", + " pm.expect(jsonData.description, `\"description\" must be ${item.description}`).to.eql(item.description);", + " pm.expect(jsonData.available.toString(), `\"available\" must be ${item.available}`).to.eql(item.available.toString());", + "});" + ], + "type": "text/javascript", + "packages": {} + } + }, { "listen": "prerequest", "script": { @@ -1346,19 +1434,17 @@ " const rnd = new RandomUtils();\r", "\r", " try {\r", - " user1 = await api.addUser(rnd.getUser());\r", - " var request = await api.addRequest(rnd.getRequest(), user1.id);\r", - " pm.collectionVariables.set(\"requestId\", request.id);\r", - " user2 = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user2.id);\r", - "\r", + " user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user.id);\r", " item = rnd.getItem();\r", - " pm.collectionVariables.set(\"item\", item);\r", + " var it = await api.addItem(item, user.id)\r", + " item = rnd.getItem();\r", + " pm.collectionVariables.set(\"item\", item); \r", + " pm.collectionVariables.set(\"itemId\", it.id);\r", " pm.collectionVariables.set(\"itemName\", item.name);\r", " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", " pm.collectionVariables.set(\"itemDescription\", item.description);\r", "\r", - "\r", " } catch(err) {\r", " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", " }\r", @@ -1383,65 +1469,694 @@ "type": "text/javascript", "packages": {} } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "Accept", + "value": "*/*", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}}\n}" }, + "url": { + "raw": "{{baseUrl}}/items/{{itemId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "items", + "{{itemId}}" + ] + } + }, + "response": [] + }, + { + "name": "Item update without X-Sharer-User-Id", + "event": [ { "listen": "test", "script": { "exec": [ - "pm.test(\"Status code is 400\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([400, 500]);\r", - "});\r", - "pm.test(\"Response have body\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});\r", - "pm.test(\"Response data have error\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('error');\r", + "pm.test(\"Status code is 500\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([500, 400]);", "});" ], "type": "text/javascript", "packages": {} } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "X-Sharer-User-Id", - "value": "{{userId}}" + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user.id);\r", + " item = rnd.getItem();\r", + " var it = await api.addItem(item, user.id)\r", + " item = rnd.getItem();\r", + " pm.collectionVariables.set(\"item\", item); \r", + " pm.collectionVariables.set(\"itemId\", it.id);\r", + " pm.collectionVariables.set(\"itemName\", item.name);\r", + " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", + " pm.collectionVariables.set(\"itemDescription\", item.description);\r", + "\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text", + "disabled": true + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "Accept", + "value": "*/*", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}}\n}" + }, + "url": { + "raw": "{{baseUrl}}/items/{{itemId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "items", + "{{itemId}}" + ] + } + }, + "response": [] + }, + { + "name": "Item update with other user", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 404\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([404, 403]);", + "});" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user.id + 1);\r", + " item = rnd.getItem();\r", + " var it = await api.addItem(item, user.id)\r", + " item = rnd.getItem();\r", + " pm.collectionVariables.set(\"item\", item); \r", + " pm.collectionVariables.set(\"itemId\", it.id);\r", + " pm.collectionVariables.set(\"itemName\", item.name);\r", + " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", + " pm.collectionVariables.set(\"itemDescription\", item.description);\r", + "\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "Accept", + "value": "*/*", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"available\": {{itemAvailable}}\n}" + }, + "url": { + "raw": "{{baseUrl}}/items/{{itemId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "items", + "{{itemId}}" + ] + } + }, + "response": [] + }, + { + "name": "Item update available field", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.be.ok;", + "});", + "pm.test(\"Response have body\", function () {", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "var item = pm.collectionVariables.get(\"item\");", + "", + "pm.test(\"Response data equal to request\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData).to.have.property('id');", + " pm.expect(jsonData).to.have.property('available');", + " pm.expect(jsonData.available.toString(), `\"available\" must be ${item.available}`).to.eql(item.available.toString());", + "});" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user.id);\r", + " item = rnd.getItem();\r", + " var it = await api.addItem(item, user.id)\r", + " item = rnd.getItem();\r", + " pm.collectionVariables.set(\"item\", item); \r", + " pm.collectionVariables.set(\"itemId\", it.id);\r", + " pm.collectionVariables.set(\"itemName\", item.name);\r", + " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", + " pm.collectionVariables.set(\"itemDescription\", item.description);\r", + "\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "Accept", + "value": "*/*", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"available\": {{itemAvailable}}\n}" + }, + "url": { + "raw": "{{baseUrl}}/items/{{itemId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "items", + "{{itemId}}" + ] + } + }, + "response": [] + }, + { + "name": "Item update description field", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.be.ok;", + "});", + "pm.test(\"Response have body\", function () {", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "var item = pm.collectionVariables.get(\"item\");", + "", + "pm.test(\"Response data equal to request\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData).to.have.property('id');", + " pm.expect(jsonData).to.have.property('name');", + " pm.expect(jsonData).to.have.property('description');", + " pm.expect(jsonData).to.have.property('available');", + " pm.expect(jsonData.description, `\"description\" must be ${item.description}`).to.eql(item.description);", + "});" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user.id);\r", + " item = rnd.getItem();\r", + " var it = await api.addItem(item, user.id)\r", + " item = rnd.getItem();\r", + " pm.collectionVariables.set(\"item\", item); \r", + " pm.collectionVariables.set(\"itemId\", it.id);\r", + " pm.collectionVariables.set(\"itemName\", item.name);\r", + " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", + " pm.collectionVariables.set(\"itemDescription\", item.description);\r", + "\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "Accept", + "value": "*/*", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"description\": \"{{itemDescription}}\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/items/{{itemId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "items", + "{{itemId}}" + ] + } + }, + "response": [] + }, + { + "name": "Item update name field", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.be.ok;", + "});", + "pm.test(\"Response have body\", function () {", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "var item = pm.collectionVariables.get(\"item\");", + "", + "pm.test(\"Response data equal to request\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData).to.have.property('id');", + " pm.expect(jsonData).to.have.property('name');", + " pm.expect(jsonData).to.have.property('description');", + " pm.expect(jsonData).to.have.property('available');", + " pm.expect(jsonData.name, `\"name\" must be ${item.name}`).to.eql(item.name);", + "});" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user.id);\r", + " item = rnd.getItem();\r", + " var it = await api.addItem(item, user.id)\r", + " item = rnd.getItem();\r", + " pm.collectionVariables.set(\"item\", item); \r", + " pm.collectionVariables.set(\"itemId\", it.id);\r", + " pm.collectionVariables.set(\"itemName\", item.name);\r", + " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", + " pm.collectionVariables.set(\"itemDescription\", item.description);\r", + "\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "Accept", + "value": "*/*", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"{{itemName}}\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/items/{{itemId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "items", + "{{itemId}}" + ] + } + }, + "response": [] + }, + { + "name": "Item get", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.be.ok;", + "});", + "pm.test(\"Response have body\", function () {", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + "});", + "var item = pm.collectionVariables.get(\"item\");", + "", + "pm.test(\"Response data equal to request\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData).to.have.property('id');", + " pm.expect(jsonData).to.have.property('name');", + " pm.expect(jsonData).to.have.property('description');", + " pm.expect(jsonData).to.have.property('available');", + " pm.expect(jsonData.name, `\"name\" must be ${item.name}`).to.eql(item.name);", + " pm.expect(jsonData.description, `\"description\" must be ${item.description}`).to.eql(item.description);", + " pm.expect(jsonData.available.toString(), `\"available\" must be ${item.available}`).to.eql(item.available.toString());", + "});" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "const main = async () => {\r", + " const api = new API(pm);\r", + " const rnd = new RandomUtils();\r", + "\r", + " try {\r", + " user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user.id);\r", + " item = await api.addItem(rnd.getItem(), user.id)\r", + " pm.collectionVariables.set(\"item\", item);\r", + " pm.collectionVariables.set(\"itemId\", item.id);\r", + " pm.collectionVariables.set(\"itemName\", item.name);\r", + " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", + " pm.collectionVariables.set(\"itemDescription\", item.description);\r", + " } catch(err) {\r", + " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", + " }\r", + "\r", + "};\r", + "\r", + "const interval = setInterval(() => {}, 1000);\r", + "\r", + "setTimeout(async () => \r", + " {\r", + " try {\r", + " await main();\r", + " } catch (e) {\r", + " console.error(e);\r", + " } finally {\r", + " clearInterval(interval);\r", + " }\r", + " }, \r", + " 100 \r", + ");" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text" + }, + { + "key": "Accept", + "value": "*/*", + "type": "text" } ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"{{itemName}}\",\n \"description\": \"{{itemDescription}}\",\n \"requestId\": {{requestId}}\n}" - }, "url": { - "raw": "localhost:8080/items", + "raw": "{{baseUrl}}/items/{{itemId}}", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "8080", "path": [ - "items" + "items", + "{{itemId}}" ] } }, "response": [] - } - ] - }, - { - "name": "requests", - "item": [ + }, { - "name": "Create request", + "name": "Get all items from user", "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.be.ok;", + "});", + "pm.test(\"Test list item response\", function () {", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.length, 'List length must be 2').to.eql(2);", + "});", + "", + "" + ], + "type": "text/javascript", + "packages": {} + } + }, { "listen": "prerequest", "script": { @@ -1451,11 +2166,10 @@ " const rnd = new RandomUtils();\r", "\r", " try {\r", - " request1 = rnd.getRequest();\r", - " pm.collectionVariables.set(\"requestDescription\", request1.description);\r", " user = await api.addUser(rnd.getUser());\r", " pm.collectionVariables.set(\"userId\", user.id);\r", - "\r", + " await api.addItem(rnd.getItem(), user.id)\r", + " await api.addItem(rnd.getItem(), user.id)\r", " } catch(err) {\r", " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", " }\r", @@ -1480,65 +2194,57 @@ "type": "text/javascript", "packages": {} } - }, - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200 or 201\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([200,201]);\r", - "});\r", - "pm.test(\"Response have body\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});\r", - "\r", - "pm.test(\"Response data equal to request\", function () {\r", - " var description = pm.collectionVariables.get(\"requestDescription\");\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('id');\r", - " pm.expect(jsonData).to.have.property('description');\r", - " pm.expect(jsonData).to.have.property('created');\r", - " pm.expect(jsonData.description, `\"description\" must be ${description}`).to.eql(description);\r", - "});" - ], - "type": "text/javascript", - "packages": {} - } } ], "request": { - "method": "POST", + "method": "GET", "header": [ { - "key": "Content-Type", - "value": "application/json" + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text" }, { - "key": "X-Sharer-User-Id", - "value": "{{userId}}" + "key": "Accept", + "value": "*/*", + "type": "text" } ], - "body": { - "mode": "raw", - "raw": "{ \n \"description\": \"{{requestDescription}}\"\n}" - }, "url": { - "raw": "localhost:8080/requests", + "raw": "{{baseUrl}}/items", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "8080", "path": [ - "requests" + "items" ] } }, "response": [] }, { - "name": "Get user requests", + "name": "Item search", "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.be.ok;", + "});", + "pm.test(\"Test list item response\", function () {", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.length, 'List length must be 1').to.eql(1);", + " pm.expect(jsonData[0].name.toUpperCase(), 'Name should include ' + pm.collectionVariables.get(\"searchString\")).to.eql(pm.collectionVariables.get(\"searchString\"))", + "});", + "" + ], + "type": "text/javascript", + "packages": {} + } + }, { "listen": "prerequest", "script": { @@ -1550,9 +2256,15 @@ " try {\r", " user = await api.addUser(rnd.getUser());\r", " pm.collectionVariables.set(\"userId\", user.id);\r", - " request1 = await api.addRequest(rnd.getRequest(), user.id);\r", - " request2 = await api.addRequest(rnd.getRequest(), user.id);\r", - "\r", + " it = rnd.getItem()\r", + " it.available = true\r", + " item = await api.addItem(it, user.id)\r", + " pm.collectionVariables.set(\"item\", item);\r", + " pm.collectionVariables.set(\"itemId\", item.id);\r", + " pm.collectionVariables.set(\"itemName\", item.name);\r", + " pm.collectionVariables.set(\"searchString\", item.name.toUpperCase());\r", + " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", + " pm.collectionVariables.set(\"itemDescription\", item.description);\r", " } catch(err) {\r", " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", " }\r", @@ -1577,54 +2289,63 @@ "type": "text/javascript", "packages": {} } - }, - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {\r", - " pm.response.to.be.ok;\r", - "});\r", - "pm.test(\"User requests amount\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData.length, 'List length must be 2').to.eql(2);\r", - "});" - ], - "type": "text/javascript", - "packages": {} - } } ], "request": { "method": "GET", "header": [ { - "key": "Content-Type", - "value": "application/json" + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text" }, { - "key": "X-Sharer-User-Id", - "value": "{{userId}}" + "key": "Accept", + "value": "*/*", + "type": "text" } ], "url": { - "raw": "localhost:8080/requests", + "raw": "{{baseUrl}}/items/search?text={{searchString}}", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "8080", "path": [ - "requests" + "items", + "search" + ], + "query": [ + { + "key": "text", + "value": "{{searchString}}" + } ] } }, "response": [] }, { - "name": "Get user request by id", + "name": "Item search unavailable", "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.be.ok;", + "});", + "pm.test(\"Test list item response\", function () {", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.length, 'List length must be 0').to.eql(0);", + "});", + "" + ], + "type": "text/javascript", + "packages": {} + } + }, { "listen": "prerequest", "script": { @@ -1634,13 +2355,17 @@ " const rnd = new RandomUtils();\r", "\r", " try {\r", - " user1 = await api.addUser(rnd.getUser());\r", - " user2 = await api.addUser(rnd.getUser());\r", - " pm.collectionVariables.set(\"userId\", user2.id);\r", - " req = await api.addRequest(rnd.getRequest(), user1.id);\r", - " pm.collectionVariables.set(\"requestId\", req.id);\r", - " item = await api.addItem(rnd.getItemForRequest(req.id), user2.id);\r", + " user = await api.addUser(rnd.getUser());\r", + " pm.collectionVariables.set(\"userId\", user.id);\r", + " it = rnd.getItem()\r", + " it.available = false\r", + " item = await api.addItem(it, user.id)\r", + " pm.collectionVariables.set(\"item\", item);\r", + " pm.collectionVariables.set(\"itemId\", item.id);\r", " pm.collectionVariables.set(\"itemName\", item.name);\r", + " pm.collectionVariables.set(\"searchString\", item.name.toUpperCase());\r", + " pm.collectionVariables.set(\"itemAvailable\", item.available);\r", + " pm.collectionVariables.set(\"itemDescription\", item.description);\r", " } catch(err) {\r", " console.error(\"Ошибка при подготовке тестовых данных.\", err);\r", " }\r", @@ -1665,28 +2390,59 @@ "type": "text/javascript", "packages": {} } - }, + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text" + }, + { + "key": "Accept", + "value": "*/*", + "type": "text" + } + ], + "url": { + "raw": "{{baseUrl}}/items/search?text={{searchString}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "items", + "search" + ], + "query": [ + { + "key": "text", + "value": "{{searchString}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Item search empty", + "event": [ { "listen": "test", "script": { "exec": [ - "pm.test(\"Status code is 200\", function () {\r", - " pm.response.to.be.ok;\r", - "});\r", - "pm.test(\"User requests amount\", function () {\r", - " var name = pm.collectionVariables.get(\"itemName\");\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('id');\r", - " pm.expect(jsonData).to.have.property('description');\r", - " pm.expect(jsonData).to.have.property('created');\r", - " pm.expect(jsonData).to.have.property('items');\r", - " pm.expect(jsonData.items[0].name, `\"item name\" must be ${name}`).to.eql(name);\r", + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.be.ok;", + "});", + "pm.test(\"Test search item response\", function () {", + " pm.response.to.be.withBody;", + " pm.response.to.be.json;", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.length, 'List length must be 0').to.eql(0);", "});" ], - "type": "text/javascript", - "packages": {} + "type": "text/javascript" } } ], @@ -1694,23 +2450,30 @@ "method": "GET", "header": [ { - "key": "Content-Type", - "value": "application/json" + "key": "X-Sharer-User-Id", + "value": "{{userId}}", + "type": "text" }, { - "key": "X-Sharer-User-Id", - "value": "{{userId}}" + "key": "Accept", + "value": "*/*", + "type": "text" } ], "url": { - "raw": "localhost:8080/requests/{{requestId}}", + "raw": "{{baseUrl}}/items/search?text=", "host": [ - "localhost" + "{{baseUrl}}" ], - "port": "8080", "path": [ - "requests", - "{{requestId}}" + "items", + "search" + ], + "query": [ + { + "key": "text", + "value": "" + } ] } }, @@ -3976,6 +4739,10 @@ } ], "variable": [ + { + "key": "baseUrl", + "value": "http://localhost:8080" + }, { "key": "userName", "value": "" @@ -3986,35 +4753,31 @@ }, { "key": "userId", - "value": "1" - }, - { - "key": "itemName", "value": "" }, { - "key": "itemAvailable", + "key": "item", "value": "" }, { - "key": "itemDescription", + "key": "itemName", "value": "" }, { - "key": "item", + "key": "itemAvailable", "value": "" }, { - "key": "requestId", + "key": "itemDescription", "value": "" }, { - "key": "requestDescription", + "key": "itemId", "value": "" }, { - "key": "baseUrl", - "value": "localhost:8080" + "key": "searchString", + "value": "" }, { "key": "start", @@ -4024,10 +4787,6 @@ "key": "end", "value": "" }, - { - "key": "itemId", - "value": "" - }, { "key": "user1", "value": "" @@ -4038,7 +4797,7 @@ }, { "key": "bookingId", - "value": "1" + "value": "" }, { "key": "booking", diff --git a/server/Dockerfile b/server/Dockerfile deleted file mode 100644 index 0ff1817..0000000 --- a/server/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index 566db3e..0000000 --- a/server/pom.xml +++ /dev/null @@ -1,86 +0,0 @@ - - - 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 - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - - - coverage - - - - org.jacoco - jacoco-maven-plugin - - - - - - - diff --git a/server/src/main/java/ru/practicum/shareit/booking/BookingDtoInput.java b/server/src/main/java/ru/practicum/shareit/booking/BookingDtoInput.java deleted file mode 100644 index 382f6a2..0000000 --- a/server/src/main/java/ru/practicum/shareit/booking/BookingDtoInput.java +++ /dev/null @@ -1,20 +0,0 @@ -package ru.practicum.shareit.booking; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.time.LocalDateTime; - -@Data -@AllArgsConstructor -@NoArgsConstructor -public class BookingDtoInput { - - private Long itemId; - - private LocalDateTime start; - - private LocalDateTime end; - -} diff --git a/server/src/main/java/ru/practicum/shareit/exception/ValidationException.java b/server/src/main/java/ru/practicum/shareit/exception/ValidationException.java deleted file mode 100644 index 59043da..0000000 --- a/server/src/main/java/ru/practicum/shareit/exception/ValidationException.java +++ /dev/null @@ -1,7 +0,0 @@ -package ru.practicum.shareit.exception; - -public class ValidationException extends RuntimeException { - public ValidationException(String message) { - super(message); - } -} diff --git a/server/src/main/java/ru/practicum/shareit/item/ItemDto.java b/server/src/main/java/ru/practicum/shareit/item/ItemDto.java deleted file mode 100644 index 4f5f206..0000000 --- a/server/src/main/java/ru/practicum/shareit/item/ItemDto.java +++ /dev/null @@ -1,37 +0,0 @@ -package ru.practicum.shareit.item; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import ru.practicum.shareit.booking.Booking; -import ru.practicum.shareit.request.RequestDto; -import ru.practicum.shareit.user.User; - -import java.util.List; - -@Data -@AllArgsConstructor -@NoArgsConstructor -public class ItemDto { - - private Long id; - - private String name; - - private String description; - - private Boolean available; - - private User owner; - - private RequestDto request; - - private List comments; - - private List bookings; - - private Booking lastBooking; - - private Booking nextBooking; - -} diff --git a/server/src/main/java/ru/practicum/shareit/item/ItemDtoInput.java b/server/src/main/java/ru/practicum/shareit/item/ItemDtoInput.java deleted file mode 100644 index 97209f5..0000000 --- a/server/src/main/java/ru/practicum/shareit/item/ItemDtoInput.java +++ /dev/null @@ -1,20 +0,0 @@ -package ru.practicum.shareit.item; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@AllArgsConstructor -@NoArgsConstructor -public class ItemDtoInput { - - private String name; - - private String description; - - private Boolean available; - - private Long requestId; - -} diff --git a/server/src/main/java/ru/practicum/shareit/item/ItemDtoRequest.java b/server/src/main/java/ru/practicum/shareit/item/ItemDtoRequest.java deleted file mode 100644 index 95ffbee..0000000 --- a/server/src/main/java/ru/practicum/shareit/item/ItemDtoRequest.java +++ /dev/null @@ -1,20 +0,0 @@ -package ru.practicum.shareit.item; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@AllArgsConstructor -@NoArgsConstructor -public class ItemDtoRequest { - - private Long idItem; - - private String name; - - private Long idOwner; - - private String Owner; - -} diff --git a/server/src/main/java/ru/practicum/shareit/request/RequestController.java b/server/src/main/java/ru/practicum/shareit/request/RequestController.java deleted file mode 100644 index d3c49ec..0000000 --- a/server/src/main/java/ru/practicum/shareit/request/RequestController.java +++ /dev/null @@ -1,39 +0,0 @@ -package ru.practicum.shareit.request; - -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -/** - * TODO Sprint add-item-requests. - */ -@RestController -@RequestMapping(path = "/requests") -@RequiredArgsConstructor -public class RequestController { - - private final RequestService requestService; - - @PostMapping - public RequestDto addRequest(@RequestHeader("X-Sharer-User-Id") Long requestorId, - @RequestBody RequestDtoInput requestDto) { - return RequestMapper.toRequestDto(requestService.addRequest(requestorId, requestDto)); - } - - @GetMapping - public List getRequests(@RequestHeader("X-Sharer-User-Id") Long requestorId) { - return requestService.getRequests(requestorId).stream().map(RequestMapper::toRequestDtoItems).toList(); - } - - @GetMapping("/all") - public List getAllRequests(@RequestHeader("X-Sharer-User-Id") Long requestorId) { - return requestService.getAllRequests(requestorId).stream().map(RequestMapper::toRequestDto).toList(); - } - - @GetMapping("/{requestId}") - public RequestDtoItems getRequestsById(@PathVariable Long requestId) { - return RequestMapper.toRequestDtoItems(requestService.getRequestById(requestId)); - } - -} \ No newline at end of file diff --git a/server/src/main/java/ru/practicum/shareit/request/RequestDtoInput.java b/server/src/main/java/ru/practicum/shareit/request/RequestDtoInput.java deleted file mode 100644 index 8d44bc6..0000000 --- a/server/src/main/java/ru/practicum/shareit/request/RequestDtoInput.java +++ /dev/null @@ -1,14 +0,0 @@ -package ru.practicum.shareit.request; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@AllArgsConstructor -@NoArgsConstructor -public class RequestDtoInput { - - private String description; - -} diff --git a/server/src/main/java/ru/practicum/shareit/request/RequestDtoItems.java b/server/src/main/java/ru/practicum/shareit/request/RequestDtoItems.java deleted file mode 100644 index 178918b..0000000 --- a/server/src/main/java/ru/practicum/shareit/request/RequestDtoItems.java +++ /dev/null @@ -1,26 +0,0 @@ -package ru.practicum.shareit.request; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import ru.practicum.shareit.item.ItemDtoRequest; -import ru.practicum.shareit.user.User; - -import java.time.LocalDateTime; -import java.util.List; - -@Data -@AllArgsConstructor -@NoArgsConstructor -public class RequestDtoItems { - - private Long id; - - private String description; - - private User requestor; - - private LocalDateTime created; - - List items; -} diff --git a/server/src/main/java/ru/practicum/shareit/request/RequestMapper.java b/server/src/main/java/ru/practicum/shareit/request/RequestMapper.java deleted file mode 100644 index 9608ce2..0000000 --- a/server/src/main/java/ru/practicum/shareit/request/RequestMapper.java +++ /dev/null @@ -1,62 +0,0 @@ -package ru.practicum.shareit.request; - -import ru.practicum.shareit.item.ItemMapper; - -public class RequestMapper { - - public static RequestDto toRequestDto(Request request) { - if (request == null) { - return null; - } - RequestDto requestDto = new RequestDto(); - - requestDto.setId(request.getId()); - requestDto.setDescription(request.getDescription()); - requestDto.setRequestor(request.getRequestor()); - requestDto.setCreated(request.getCreated()); - - return requestDto; - } - - public static RequestDtoItems toRequestDtoItems(Request request) { - if (request == null) { - return null; - } - RequestDtoItems requestDto = new RequestDtoItems(); - - requestDto.setId(request.getId()); - requestDto.setDescription(request.getDescription()); - requestDto.setRequestor(request.getRequestor()); - requestDto.setCreated(request.getCreated()); - requestDto.setItems(request.getItems().stream().map(ItemMapper::toItemDtoRequest).toList()); - - return requestDto; - } - - - public static Request toRequest(RequestDto requestDto) { - Request request = new Request(); - - if (requestDto.getId() != null) { - if (requestDto.getId() > 0) { - request.setId(requestDto.getId()); - } - } - if (requestDto.getDescription() != null) { - if (!requestDto.getDescription().trim().isEmpty()) { - request.setDescription(requestDto.getDescription().trim()); - } - } - if (requestDto.getRequestor().getId() != null) { - if (requestDto.getRequestor().getId() > 0) { - request.setRequestor(requestDto.getRequestor()); - } - } - if (requestDto.getCreated() != null) { - request.setCreated(requestDto.getCreated()); - } - - return request; - } - -} diff --git a/server/src/main/java/ru/practicum/shareit/request/RequestRepository.java b/server/src/main/java/ru/practicum/shareit/request/RequestRepository.java deleted file mode 100644 index db723d3..0000000 --- a/server/src/main/java/ru/practicum/shareit/request/RequestRepository.java +++ /dev/null @@ -1,17 +0,0 @@ -package ru.practicum.shareit.request; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; -import ru.practicum.shareit.user.User; - -import java.util.List; - -@Repository -public interface RequestRepository extends JpaRepository { - - List findAllByRequestorOrderByCreatedDesc(User requestor); - - List findAllByOrderByCreatedDesc(); - - List findAllByRequestorNotOrderByCreatedDesc(User requestor); -} diff --git a/server/src/main/java/ru/practicum/shareit/request/RequestService.java b/server/src/main/java/ru/practicum/shareit/request/RequestService.java deleted file mode 100644 index 6e3bba3..0000000 --- a/server/src/main/java/ru/practicum/shareit/request/RequestService.java +++ /dev/null @@ -1,15 +0,0 @@ -package ru.practicum.shareit.request; - -import java.util.List; - -public interface RequestService { - - Request addRequest(Long requestorId, RequestDtoInput requestDto); - - List getRequests(Long requestorId); - - List getAllRequests(Long requestorId); - - Request getRequestById(Long requestId); - -} diff --git a/server/src/main/java/ru/practicum/shareit/request/RequestServiceImpl.java b/server/src/main/java/ru/practicum/shareit/request/RequestServiceImpl.java deleted file mode 100644 index 60dae61..0000000 --- a/server/src/main/java/ru/practicum/shareit/request/RequestServiceImpl.java +++ /dev/null @@ -1,107 +0,0 @@ -package ru.practicum.shareit.request; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import ru.practicum.shareit.exception.NotFoundException; -import ru.practicum.shareit.item.ItemRepository; -import ru.practicum.shareit.user.User; -import ru.practicum.shareit.user.UserRepository; - -import java.time.LocalDateTime; -import java.util.List; - -@Slf4j -@Service -@RequiredArgsConstructor -public class RequestServiceImpl implements RequestService { - - private final RequestRepository requestRepository; - private final UserRepository userRepository; - - /** - * Добавляет новый запрос в базу данных. - * - * @param requestorId идентификатор пользователя, который создает запрос - * @param requestDto объект, содержащий данные для создания запроса - * @return созданный запрос - * @throws NotFoundException если пользователь с указанным идентификатором не найден в базе данных - */ - @Override - public Request addRequest(Long requestorId, RequestDtoInput requestDto) { - User requestor = new User(); - Request request = new Request(); - requestor = userRepository.findById(requestorId).orElse(null); - if (requestor == null) { - String error = "Пользователь с id [ " + requestorId + " ] не найден в БД при добавлении запроса."; - log.info(error); - throw new NotFoundException(error); - } - request.setDescription(requestDto.getDescription()); - request.setRequestor(requestor); - request.setCreated(LocalDateTime.now()); - request = requestRepository.save(request); - log.info("Запрос [ {} ] добавлен в БД.",request); - return request; - } - - /** - * Возвращает список запросов, созданных определенным пользователем, отсортированный по дате создания в обратном порядке. - * - * @param requestorId идентификатор пользователя, чьи запросы нужно получить - * @return список запросов, созданных пользователем - */ - @Override - public List getRequests(Long requestorId) { - User requestor = new User(); - requestor = userRepository.findById(requestorId).orElse(null); - if (requestor == null) { - log.info("Пользователь с id [ {} ] не найден в БД при получении своего списка запросов - вернулся пустой список.", requestorId); - return List.of(); - } - List requests = requestRepository.findAllByRequestorOrderByCreatedDesc(requestor); - log.info("Список запросов пользователя [ {} ] получен из БД в количестве [ {} ].", requestorId, requests.size()); - return requests; - } - - /** - * Возвращает список всех запросов, отсортированных по дате создания в обратном порядке. - * Если передан идентификатор пользователя, то возвращаются все запросы, - * кроме тех, которые были созданы этим пользователем. - * - * @param requestorId идентификатор пользователя, чьи запросы нужно исключить из списка (может быть null) - * @return список всех запросов, отсортированных по дате создания в обратном порядке - */ - @Override - public List getAllRequests(Long requestorId) { - User requestor = new User(); - requestor = userRepository.findById(requestorId).orElse(null); - if (requestor == null) { - List requests = requestRepository.findAllByOrderByCreatedDesc(); - log.info("Список доступных запросов получен из БД в количестве [ {} ].", requests.size()); - return requests; - } - List requests = requestRepository.findAllByRequestorNotOrderByCreatedDesc(requestor); - log.info("Список доступных запросов ( кроме запросов пользователя [ {} ] ) получен из БД в количестве [ {} ].", - requestorId, requests.size()); - return requests; - } - - /** - * Возвращает запрос по его идентификатору. - * - * @param requestId идентификатор запроса - * @return запрос с указанным идентификатором - * @throws NotFoundException если запрос с указанным идентификатором не найден в базе данных - */ - @Override - public Request getRequestById(Long requestId) { - Request request = requestRepository.findById(requestId).orElse(null); - if (request == null) { - String error = "Запрос с id [ " + requestId + " ] не найден в БД при получении."; - log.info(error); - throw new NotFoundException(error); - } - return request; - } -} diff --git a/server/src/main/java/ru/practicum/shareit/user/UserDto.java b/server/src/main/java/ru/practicum/shareit/user/UserDto.java deleted file mode 100644 index 924c595..0000000 --- a/server/src/main/java/ru/practicum/shareit/user/UserDto.java +++ /dev/null @@ -1,29 +0,0 @@ -package ru.practicum.shareit.user; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import ru.practicum.shareit.booking.Booking; -import ru.practicum.shareit.item.Comment; -import ru.practicum.shareit.item.Item; - -import java.util.List; - -@Data -@AllArgsConstructor -@NoArgsConstructor -public class UserDto { - - private Long id; - - private String name; - - private String email; - - private List items; - - private List bookings; - - private List comments; - -} diff --git a/server/src/main/resources/application.properties b/server/src/main/resources/application.properties deleted file mode 100644 index 0f5ef57..0000000 --- a/server/src/main/resources/application.properties +++ /dev/null @@ -1,17 +0,0 @@ -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=shareituser -spring.datasource.password=12345678 -#--- -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/server/src/main/java/ru/practicum/shareit/ShareItServer.java b/src/main/java/ru/practicum/shareit/ShareItApp.java similarity index 57% rename from server/src/main/java/ru/practicum/shareit/ShareItServer.java rename to src/main/java/ru/practicum/shareit/ShareItApp.java index 303541d..a10a87d 100644 --- a/server/src/main/java/ru/practicum/shareit/ShareItServer.java +++ b/src/main/java/ru/practicum/shareit/ShareItApp.java @@ -4,10 +4,10 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication -public class ShareItServer { +public class ShareItApp { - 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/server/src/main/java/ru/practicum/shareit/booking/Booking.java b/src/main/java/ru/practicum/shareit/booking/Booking.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/booking/Booking.java rename to src/main/java/ru/practicum/shareit/booking/Booking.java diff --git a/server/src/main/java/ru/practicum/shareit/booking/BookingController.java b/src/main/java/ru/practicum/shareit/booking/BookingController.java similarity index 97% rename from server/src/main/java/ru/practicum/shareit/booking/BookingController.java rename to src/main/java/ru/practicum/shareit/booking/BookingController.java index fd62891..40df0bc 100644 --- a/server/src/main/java/ru/practicum/shareit/booking/BookingController.java +++ b/src/main/java/ru/practicum/shareit/booking/BookingController.java @@ -1,5 +1,6 @@ package ru.practicum.shareit.booking; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; @@ -19,7 +20,7 @@ public class BookingController { */ @PostMapping public BookingDtoOutput addBooking(@RequestHeader("X-Sharer-User-Id") Long bookerId, - @RequestBody BookingDtoInput bookingDto) { + @Valid @RequestBody BookingDtoInput bookingDto) { return BookingMapper.toBookingDtoOutput(bookingService.addBooking(bookerId, bookingDto)); } diff --git a/server/src/main/java/ru/practicum/shareit/booking/BookingDto.java b/src/main/java/ru/practicum/shareit/booking/BookingDto.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/booking/BookingDto.java rename to src/main/java/ru/practicum/shareit/booking/BookingDto.java diff --git a/src/main/java/ru/practicum/shareit/booking/BookingDtoInput.java b/src/main/java/ru/practicum/shareit/booking/BookingDtoInput.java new file mode 100644 index 0000000..b39e330 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/booking/BookingDtoInput.java @@ -0,0 +1,28 @@ +package ru.practicum.shareit.booking; + +import jakarta.validation.constraints.FutureOrPresent; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import ru.practicum.shareit.validation.CreateObject; + +import java.time.LocalDateTime; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class BookingDtoInput { + + @NotNull(groups = {CreateObject.class}, message = "При создании брони должна быть информация о вещи.") + private Long itemId; + + @FutureOrPresent(groups = {CreateObject.class}, message = "Дата не должна быть в прошлом") + @NotNull(groups = {CreateObject.class}, message = "Дата не должна быть пустой") + private LocalDateTime start; + + @FutureOrPresent(groups = {CreateObject.class}, message = "Дата не должна быть в прошлом") + @NotNull(groups = {CreateObject.class}, message = "Дата не должна быть пустой") + private LocalDateTime end; + +} diff --git a/server/src/main/java/ru/practicum/shareit/booking/BookingDtoOutput.java b/src/main/java/ru/practicum/shareit/booking/BookingDtoOutput.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/booking/BookingDtoOutput.java rename to src/main/java/ru/practicum/shareit/booking/BookingDtoOutput.java diff --git a/server/src/main/java/ru/practicum/shareit/booking/BookingDtoShort.java b/src/main/java/ru/practicum/shareit/booking/BookingDtoShort.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/booking/BookingDtoShort.java rename to src/main/java/ru/practicum/shareit/booking/BookingDtoShort.java diff --git a/server/src/main/java/ru/practicum/shareit/booking/BookingMapper.java b/src/main/java/ru/practicum/shareit/booking/BookingMapper.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/booking/BookingMapper.java rename to src/main/java/ru/practicum/shareit/booking/BookingMapper.java diff --git a/server/src/main/java/ru/practicum/shareit/booking/BookingRepository.java b/src/main/java/ru/practicum/shareit/booking/BookingRepository.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/booking/BookingRepository.java rename to src/main/java/ru/practicum/shareit/booking/BookingRepository.java diff --git a/server/src/main/java/ru/practicum/shareit/booking/BookingService.java b/src/main/java/ru/practicum/shareit/booking/BookingService.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/booking/BookingService.java rename to src/main/java/ru/practicum/shareit/booking/BookingService.java diff --git a/server/src/main/java/ru/practicum/shareit/booking/BookingServiceImpl.java b/src/main/java/ru/practicum/shareit/booking/BookingServiceImpl.java similarity index 95% rename from server/src/main/java/ru/practicum/shareit/booking/BookingServiceImpl.java rename to src/main/java/ru/practicum/shareit/booking/BookingServiceImpl.java index d0f22f3..991eba2 100644 --- a/server/src/main/java/ru/practicum/shareit/booking/BookingServiceImpl.java +++ b/src/main/java/ru/practicum/shareit/booking/BookingServiceImpl.java @@ -203,6 +203,7 @@ public List getByOwnerId(Long userId, String state) { switch (bookingState) { case ALL: { result = bookingRepository.findAllByItem_OwnerOrderByStartDesc(bookerFromDb); + System.out.println(result); break; } case CURRENT: { @@ -252,6 +253,18 @@ private void validateBooking(BookingDto bookingDto, Item item, User booker) { throw new ValidationException(message); } + if (bookingDto.getStart().equals(bookingDto.getEnd())) { + String message = "Начало и окончание бронирования не может быть одним и тем же временем."; + log.info(message); + throw new ValidationException(message); + } + + if (bookingDto.getEnd().isBefore(bookingDto.getStart())) { + String message = "Окончание бронирования не может быть раньше его начала."; + log.info(message); + throw new ValidationException(message); + } + List bookings = item.getBookings(); if (!bookings.isEmpty()) { for (Booking b : bookings) { diff --git a/server/src/main/java/ru/practicum/shareit/booking/BookingState.java b/src/main/java/ru/practicum/shareit/booking/BookingState.java similarity index 57% rename from server/src/main/java/ru/practicum/shareit/booking/BookingState.java rename to src/main/java/ru/practicum/shareit/booking/BookingState.java index 76499ce..75be8b4 100644 --- a/server/src/main/java/ru/practicum/shareit/booking/BookingState.java +++ b/src/main/java/ru/practicum/shareit/booking/BookingState.java @@ -1,5 +1,5 @@ package ru.practicum.shareit.booking; public enum BookingState { - ALL, CURRENT, PAST, FUTURE, WAITING, REJECTED + ALL, CURRENT, PAST, FUTURE, WAITING, REJECTED; } diff --git a/server/src/main/java/ru/practicum/shareit/booking/BookingStatus.java b/src/main/java/ru/practicum/shareit/booking/BookingStatus.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/booking/BookingStatus.java rename to src/main/java/ru/practicum/shareit/booking/BookingStatus.java diff --git a/server/src/main/java/ru/practicum/shareit/exception/DataConflictException.java b/src/main/java/ru/practicum/shareit/exception/DataConflictException.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/exception/DataConflictException.java rename to src/main/java/ru/practicum/shareit/exception/DataConflictException.java diff --git a/server/src/main/java/ru/practicum/shareit/exception/ErrorHandler.java b/src/main/java/ru/practicum/shareit/exception/ErrorHandler.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/exception/ErrorHandler.java rename to src/main/java/ru/practicum/shareit/exception/ErrorHandler.java diff --git a/server/src/main/java/ru/practicum/shareit/exception/NotFoundException.java b/src/main/java/ru/practicum/shareit/exception/NotFoundException.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/exception/NotFoundException.java rename to src/main/java/ru/practicum/shareit/exception/NotFoundException.java diff --git a/server/src/main/java/ru/practicum/shareit/exception/RestrictedAccessException.java b/src/main/java/ru/practicum/shareit/exception/RestrictedAccessException.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/exception/RestrictedAccessException.java rename to src/main/java/ru/practicum/shareit/exception/RestrictedAccessException.java diff --git a/gateway/src/main/java/ru/practicum/shareit/exception/ValidationException.java b/src/main/java/ru/practicum/shareit/exception/ValidationException.java similarity index 100% rename from gateway/src/main/java/ru/practicum/shareit/exception/ValidationException.java rename to src/main/java/ru/practicum/shareit/exception/ValidationException.java diff --git a/server/src/main/java/ru/practicum/shareit/item/Comment.java b/src/main/java/ru/practicum/shareit/item/Comment.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/item/Comment.java rename to src/main/java/ru/practicum/shareit/item/Comment.java diff --git a/server/src/main/java/ru/practicum/shareit/item/CommentDto.java b/src/main/java/ru/practicum/shareit/item/CommentDto.java similarity index 51% rename from server/src/main/java/ru/practicum/shareit/item/CommentDto.java rename to src/main/java/ru/practicum/shareit/item/CommentDto.java index fc9956b..bd2daa4 100644 --- a/server/src/main/java/ru/practicum/shareit/item/CommentDto.java +++ b/src/main/java/ru/practicum/shareit/item/CommentDto.java @@ -1,9 +1,12 @@ package ru.practicum.shareit.item; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import ru.practicum.shareit.user.User; +import ru.practicum.shareit.validation.CreateObject; import java.time.LocalDateTime; @@ -14,6 +17,8 @@ public class CommentDto { private Long id; + @NotNull(groups = {CreateObject.class}, message = "комментарий должен быть указан.") + @NotBlank(groups = {CreateObject.class}, message = "Комментарий не может быть пустым.") private String text; private Item item; diff --git a/server/src/main/java/ru/practicum/shareit/item/CommentDtoOutput.java b/src/main/java/ru/practicum/shareit/item/CommentDtoOutput.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/item/CommentDtoOutput.java rename to src/main/java/ru/practicum/shareit/item/CommentDtoOutput.java diff --git a/server/src/main/java/ru/practicum/shareit/item/CommentDtoShort.java b/src/main/java/ru/practicum/shareit/item/CommentDtoShort.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/item/CommentDtoShort.java rename to src/main/java/ru/practicum/shareit/item/CommentDtoShort.java diff --git a/server/src/main/java/ru/practicum/shareit/item/CommentMapper.java b/src/main/java/ru/practicum/shareit/item/CommentMapper.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/item/CommentMapper.java rename to src/main/java/ru/practicum/shareit/item/CommentMapper.java diff --git a/server/src/main/java/ru/practicum/shareit/item/CommentRepository.java b/src/main/java/ru/practicum/shareit/item/CommentRepository.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/item/CommentRepository.java rename to src/main/java/ru/practicum/shareit/item/CommentRepository.java diff --git a/server/src/main/java/ru/practicum/shareit/item/Item.java b/src/main/java/ru/practicum/shareit/item/Item.java similarity index 98% rename from server/src/main/java/ru/practicum/shareit/item/Item.java rename to src/main/java/ru/practicum/shareit/item/Item.java index bd80d79..99e8100 100644 --- a/server/src/main/java/ru/practicum/shareit/item/Item.java +++ b/src/main/java/ru/practicum/shareit/item/Item.java @@ -39,7 +39,7 @@ public class Item { @JoinColumn(name = "owner_id", nullable = false) private User owner; - @ManyToOne + @OneToOne @JoinColumn(name = "request_id") private Request request; diff --git a/server/src/main/java/ru/practicum/shareit/item/ItemController.java b/src/main/java/ru/practicum/shareit/item/ItemController.java similarity index 85% rename from server/src/main/java/ru/practicum/shareit/item/ItemController.java rename to src/main/java/ru/practicum/shareit/item/ItemController.java index c95d869..affabdd 100644 --- a/server/src/main/java/ru/practicum/shareit/item/ItemController.java +++ b/src/main/java/ru/practicum/shareit/item/ItemController.java @@ -2,7 +2,11 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import ru.practicum.shareit.validation.CreateObject; +import ru.practicum.shareit.validation.UpdateObject; + import java.util.List; @RestController @@ -13,14 +17,14 @@ public class ItemController { @PostMapping @ResponseStatus(HttpStatus.CREATED) - public ItemDtoOutput addItem(@RequestBody ItemDtoInput itemDto, + public ItemDtoOutput addItem(@Validated(CreateObject.class) @RequestBody ItemDto itemDto, @RequestHeader(value = "X-Sharer-User-Id") Long idUser) { return ItemMapper.toItemDtoOutput(itemService.addItem(idUser, itemDto), idUser); } @PatchMapping("/{idItem}") public ItemDtoOutput updateItem(@PathVariable Long idItem, - @RequestBody ItemDtoInput itemDto, + @Validated(UpdateObject.class) @RequestBody ItemDto itemDto, @RequestHeader(value = "X-Sharer-User-Id") Long idUser) { return ItemMapper.toItemDtoOutput(itemService.updateItem(idUser, idItem, itemDto), idUser); } @@ -52,8 +56,7 @@ public List searchItemsByText(@RequestParam String text, @PostMapping("/{itemId}/comment") public CommentDtoOutput addCommentToItem(@RequestHeader("X-Sharer-User-Id") Long userId, - @PathVariable Long itemId, - @RequestBody CommentDto commentDto) { + @PathVariable Long itemId, @RequestBody CommentDto commentDto) { return CommentMapper.toCommentDtoOutput((itemService.saveComment(userId, itemId, commentDto))); } } diff --git a/gateway/src/main/java/ru/practicum/shareit/item/ItemDtoInput.java b/src/main/java/ru/practicum/shareit/item/ItemDto.java similarity index 72% rename from gateway/src/main/java/ru/practicum/shareit/item/ItemDtoInput.java rename to src/main/java/ru/practicum/shareit/item/ItemDto.java index 3173be9..2fb9d3e 100644 --- a/gateway/src/main/java/ru/practicum/shareit/item/ItemDtoInput.java +++ b/src/main/java/ru/practicum/shareit/item/ItemDto.java @@ -5,12 +5,19 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import ru.practicum.shareit.booking.Booking; +import ru.practicum.shareit.request.Request; +import ru.practicum.shareit.user.User; import ru.practicum.shareit.validation.CreateObject; +import java.util.List; + @Data @AllArgsConstructor @NoArgsConstructor -public class ItemDtoInput { +public class ItemDto { + + private Long id; @NotNull(groups = {CreateObject.class}, message = "Название вещи должно быть указано.") @NotBlank(groups = {CreateObject.class}, message = "Название вещи не может быть пустым.") @@ -23,6 +30,16 @@ public class ItemDtoInput { @NotNull(groups = {CreateObject.class}, message = "Доступность вещи должна быть указана.") private Boolean available; - private Long requestId; + private User owner; + + private Request request; + + private List comments; + + private List bookings; + + private Booking lastBooking; + + private Booking nextBooking; } diff --git a/server/src/main/java/ru/practicum/shareit/item/ItemDtoOutput.java b/src/main/java/ru/practicum/shareit/item/ItemDtoOutput.java similarity index 88% rename from server/src/main/java/ru/practicum/shareit/item/ItemDtoOutput.java rename to src/main/java/ru/practicum/shareit/item/ItemDtoOutput.java index c68c82f..36ff82c 100644 --- a/server/src/main/java/ru/practicum/shareit/item/ItemDtoOutput.java +++ b/src/main/java/ru/practicum/shareit/item/ItemDtoOutput.java @@ -4,7 +4,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import ru.practicum.shareit.booking.BookingDtoShort; -import ru.practicum.shareit.request.RequestDto; +import ru.practicum.shareit.request.Request; import ru.practicum.shareit.user.UserDtoShort; import java.util.List; @@ -24,7 +24,7 @@ public class ItemDtoOutput { private UserDtoShort owner; - private RequestDto request; + private Request request; private List comments; diff --git a/server/src/main/java/ru/practicum/shareit/item/ItemDtoShort.java b/src/main/java/ru/practicum/shareit/item/ItemDtoShort.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/item/ItemDtoShort.java rename to src/main/java/ru/practicum/shareit/item/ItemDtoShort.java diff --git a/server/src/main/java/ru/practicum/shareit/item/ItemMapper.java b/src/main/java/ru/practicum/shareit/item/ItemMapper.java similarity index 89% rename from server/src/main/java/ru/practicum/shareit/item/ItemMapper.java rename to src/main/java/ru/practicum/shareit/item/ItemMapper.java index 9f81b4e..d076fa1 100644 --- a/server/src/main/java/ru/practicum/shareit/item/ItemMapper.java +++ b/src/main/java/ru/practicum/shareit/item/ItemMapper.java @@ -3,7 +3,6 @@ import ru.practicum.shareit.booking.Booking; import ru.practicum.shareit.booking.BookingMapper; import ru.practicum.shareit.booking.BookingStatus; -import ru.practicum.shareit.request.RequestMapper; import ru.practicum.shareit.user.UserMapper; import java.time.LocalDateTime; @@ -25,7 +24,7 @@ public static ItemDto toItemDto(Item item) { itemDto.setDescription(item.getDescription()); itemDto.setAvailable(item.getAvailable()); itemDto.setOwner(item.getOwner()); - itemDto.setRequest(RequestMapper.toRequestDto(item.getRequest())); + itemDto.setRequest(item.getRequest()); itemDto.setComments(item.getComments()); itemDto.setBookings(item.getBookings()); @@ -43,7 +42,7 @@ public static ItemDtoOutput toItemDtoOutput(Item item, Long userId) { itemDto.setDescription(item.getDescription()); itemDto.setAvailable(item.getAvailable()); itemDto.setOwner(UserMapper.toUserDtoShort(item.getOwner())); - itemDto.setRequest(RequestMapper.toRequestDto(item.getRequest())); + itemDto.setRequest(item.getRequest()); List comments = Optional.ofNullable(item.getComments()).orElse(Collections.emptyList()); if (!comments.isEmpty()) { itemDto.setComments(comments.stream().map(CommentMapper::toCommentDtoShort).toList()); @@ -84,20 +83,6 @@ public static ItemDtoShort toItemDtoShort(Item item) { return itemDto; } - public static ItemDtoRequest toItemDtoRequest(Item item) { - if (item == null) { - return null; - } - ItemDtoRequest itemDto = new ItemDtoRequest(); - - itemDto.setIdItem(item.getId()); - itemDto.setName(item.getName()); - itemDto.setIdOwner(item.getOwner().getId()); - itemDto.setOwner(item.getOwner().getName()); - - return itemDto; - } - public static Item toItem(ItemDto itemDto) { Item item = new Item(); @@ -122,7 +107,7 @@ public static Item toItem(ItemDto itemDto) { } if (itemDto.getRequest() != null) { if (itemDto.getRequest().getId() > 0) { - item.setRequest(RequestMapper.toRequest(itemDto.getRequest())); + item.setRequest(itemDto.getRequest()); } } if (itemDto.getComments() != null) { diff --git a/server/src/main/java/ru/practicum/shareit/item/ItemRepository.java b/src/main/java/ru/practicum/shareit/item/ItemRepository.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/item/ItemRepository.java rename to src/main/java/ru/practicum/shareit/item/ItemRepository.java diff --git a/server/src/main/java/ru/practicum/shareit/item/ItemService.java b/src/main/java/ru/practicum/shareit/item/ItemService.java similarity index 73% rename from server/src/main/java/ru/practicum/shareit/item/ItemService.java rename to src/main/java/ru/practicum/shareit/item/ItemService.java index c72f72e..ba5bf8a 100644 --- a/server/src/main/java/ru/practicum/shareit/item/ItemService.java +++ b/src/main/java/ru/practicum/shareit/item/ItemService.java @@ -4,9 +4,9 @@ public interface ItemService { - Item addItem(Long idUser, ItemDtoInput itemDto); + Item addItem(Long idUser, ItemDto itemDto); - Item updateItem(Long idUser, Long idItem, ItemDtoInput itemDto); + Item updateItem(Long idUser, Long idItem, ItemDto itemDto); Item getItemById(Long idItem); diff --git a/server/src/main/java/ru/practicum/shareit/item/ItemServiceImpl.java b/src/main/java/ru/practicum/shareit/item/ItemServiceImpl.java similarity index 86% rename from server/src/main/java/ru/practicum/shareit/item/ItemServiceImpl.java rename to src/main/java/ru/practicum/shareit/item/ItemServiceImpl.java index e939b0e..edaf54d 100644 --- a/server/src/main/java/ru/practicum/shareit/item/ItemServiceImpl.java +++ b/src/main/java/ru/practicum/shareit/item/ItemServiceImpl.java @@ -1,6 +1,5 @@ package ru.practicum.shareit.item; -import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; @@ -8,8 +7,6 @@ import ru.practicum.shareit.exception.NotFoundException; import ru.practicum.shareit.exception.RestrictedAccessException; import ru.practicum.shareit.exception.ValidationException; -import ru.practicum.shareit.request.RequestMapper; -import ru.practicum.shareit.request.RequestRepository; import ru.practicum.shareit.user.User; import ru.practicum.shareit.user.UserMapper; import ru.practicum.shareit.user.UserRepository; @@ -20,41 +17,35 @@ @Slf4j @Service -@RequiredArgsConstructor public class ItemServiceImpl implements ItemService { private final ItemRepository itemRepository; private final UserRepository userRepository; private final CommentRepository commentRepository; - private final RequestRepository requestRepository; + + public ItemServiceImpl(ItemRepository itemRepository, UserRepository userRepository, CommentRepository commentRepository) { + this.itemRepository = itemRepository; + this.userRepository = userRepository; + this.commentRepository = commentRepository; + } /** * Метод для добавления новой вещи. * * @param idUser идентификатор пользователя - * @param inputItemDto объект ItemDtoInput, содержащий данные новой вещи + * @param itemDto объект ItemDto, содержащий данные новой вещи * @return объект Item, содержащий данные добавленной вещи * @throws ValidationException если идентификатор пользователя не указан * @throws NotFoundException если пользователь с указанным id не найден в БД */ @Override - public Item addItem(Long idUser, ItemDtoInput inputItemDto) { - ItemDto itemDto = new ItemDto(); - User user = userRepository.findById(idUser).orElse(null); - if (user == null) { + public Item addItem(Long idUser, ItemDto itemDto) { + if (userRepository.findById(idUser).isEmpty()) { String error = "Пользователь с id [ " + idUser + " ] не найден в БД при добавлении вещи."; log.info(error); throw new NotFoundException(error); } - itemDto.setOwner(user); - itemDto.setName(inputItemDto.getName()); - itemDto.setDescription(inputItemDto.getDescription()); - itemDto.setAvailable(inputItemDto.getAvailable()); - if (inputItemDto.getRequestId() == null) { - itemDto.setRequest(null); - } else { - itemDto.setRequest(RequestMapper.toRequestDto(requestRepository.findById(inputItemDto.getRequestId()).orElse(null))); - } + itemDto.setOwner(userRepository.findById(idUser).get()); Item result = ItemMapper.toItem(itemDto); itemRepository.save(result); log.info("Добавлена вещь [ {} ] пользователем [ {} ]", result.getId(), idUser); @@ -66,15 +57,14 @@ public Item addItem(Long idUser, ItemDtoInput inputItemDto) { * * @param idUser идентификатор пользователя * @param idItem идентификатор вещи - * @param itemDtoInput объект ItemDtoInput, содержащий новые данные вещи + * @param itemDto объект ItemDto, содержащий новые данные вещи * @return объект Item, содержащий обновленные данные вещи * @throws ValidationException если идентификатор пользователя не указан * @throws NotFoundException если пользователь или вещь с указанным id не найдены в БД * @throws RestrictedAccessException если пользователь не является владельцем вещи */ @Override - public Item updateItem(Long idUser, Long idItem, ItemDtoInput itemDtoInput) { - ItemDto itemDto = new ItemDto(); + public Item updateItem(Long idUser, Long idItem, ItemDto itemDto) { if (userRepository.findById(idUser).isEmpty()) { String error = "Пользователь с id [ " + idUser + " ] не найден в БД при изменение данных вещи."; log.info(error); @@ -93,21 +83,15 @@ public Item updateItem(Long idUser, Long idItem, ItemDtoInput itemDtoInput) { } itemDto.setId(idItem); itemDto.setOwner(oldItem.get().getOwner()); - itemDto.setRequest(RequestMapper.toRequestDto(oldItem.get().getRequest())); - if (itemDtoInput.getName() == null) { + itemDto.setRequest(oldItem.get().getRequest()); + if (itemDto.getName() == null) { itemDto.setName(oldItem.get().getName()); - } else { - itemDto.setName(itemDtoInput.getName()); } - if (itemDtoInput.getDescription() == null) { + if (itemDto.getDescription() == null) { itemDto.setDescription(oldItem.get().getDescription()); - } else { - itemDto.setDescription(itemDtoInput.getDescription()); } - if (itemDtoInput.getAvailable() == null) { + if (itemDto.getAvailable() == null) { itemDto.setAvailable(oldItem.get().getAvailable()); - } else { - itemDto.setAvailable(itemDtoInput.getAvailable()); } Item newItem = ItemMapper.toItem(itemDto); itemRepository.save(newItem); diff --git a/src/main/java/ru/practicum/shareit/request/ItemRequestController.java b/src/main/java/ru/practicum/shareit/request/ItemRequestController.java new file mode 100644 index 0000000..064e2e9 --- /dev/null +++ b/src/main/java/ru/practicum/shareit/request/ItemRequestController.java @@ -0,0 +1,12 @@ +package ru.practicum.shareit.request; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * TODO Sprint add-item-requests. + */ +@RestController +@RequestMapping(path = "/requests") +public class ItemRequestController { +} diff --git a/server/src/main/java/ru/practicum/shareit/request/RequestDto.java b/src/main/java/ru/practicum/shareit/request/ItemRequestDto.java similarity index 87% rename from server/src/main/java/ru/practicum/shareit/request/RequestDto.java rename to src/main/java/ru/practicum/shareit/request/ItemRequestDto.java index a49428d..16d55ee 100644 --- a/server/src/main/java/ru/practicum/shareit/request/RequestDto.java +++ b/src/main/java/ru/practicum/shareit/request/ItemRequestDto.java @@ -10,14 +10,11 @@ @Data @AllArgsConstructor @NoArgsConstructor -public class RequestDto { - - private Long id; +public class ItemRequestDto { private String description; private User requestor; private LocalDateTime created; - } diff --git a/server/src/main/java/ru/practicum/shareit/request/Request.java b/src/main/java/ru/practicum/shareit/request/Request.java similarity index 88% rename from server/src/main/java/ru/practicum/shareit/request/Request.java rename to src/main/java/ru/practicum/shareit/request/Request.java index 5947b30..2e67520 100644 --- a/server/src/main/java/ru/practicum/shareit/request/Request.java +++ b/src/main/java/ru/practicum/shareit/request/Request.java @@ -6,7 +6,6 @@ import ru.practicum.shareit.user.User; import java.time.LocalDateTime; -import java.util.List; @Getter @Setter @@ -28,9 +27,9 @@ public class Request { @JoinColumn(name = "requestor_id", nullable = false) private User requestor; + @OneToOne(mappedBy = "request") + private Item requestItem; + @Column(nullable = false) private LocalDateTime created; - - @OneToMany(mappedBy = "request") - private List items; } diff --git a/server/src/main/java/ru/practicum/shareit/user/User.java b/src/main/java/ru/practicum/shareit/user/User.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/user/User.java rename to src/main/java/ru/practicum/shareit/user/User.java diff --git a/server/src/main/java/ru/practicum/shareit/user/UserController.java b/src/main/java/ru/practicum/shareit/user/UserController.java similarity index 73% rename from server/src/main/java/ru/practicum/shareit/user/UserController.java rename to src/main/java/ru/practicum/shareit/user/UserController.java index 98c0885..38dff38 100644 --- a/server/src/main/java/ru/practicum/shareit/user/UserController.java +++ b/src/main/java/ru/practicum/shareit/user/UserController.java @@ -2,8 +2,10 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; - +import ru.practicum.shareit.validation.CreateObject; +import ru.practicum.shareit.validation.UpdateObject; import java.util.List; @@ -15,13 +17,12 @@ public class UserController { @PostMapping @ResponseStatus(HttpStatus.CREATED) - public UserDtoOutput addUser(@RequestBody UserDto userDto) { + public UserDtoOutput addUser(@Validated(CreateObject.class) @RequestBody UserDto userDto) { return UserMapper.toUserDtoOutput(userService.addUser(userDto)); } @PatchMapping("/{idUser}") - public UserDtoOutput updateUser(@PathVariable Long idUser, - @RequestBody UserDto userDto) { + public UserDtoOutput updateUser(@PathVariable Long idUser, @Validated(UpdateObject.class) @RequestBody UserDto userDto) { return UserMapper.toUserDtoOutput(userService.updateUser(idUser, userDto)); } diff --git a/gateway/src/main/java/ru/practicum/shareit/user/UserDtoInput.java b/src/main/java/ru/practicum/shareit/user/UserDto.java similarity index 59% rename from gateway/src/main/java/ru/practicum/shareit/user/UserDtoInput.java rename to src/main/java/ru/practicum/shareit/user/UserDto.java index 702908a..122a434 100644 --- a/gateway/src/main/java/ru/practicum/shareit/user/UserDtoInput.java +++ b/src/main/java/ru/practicum/shareit/user/UserDto.java @@ -6,19 +6,33 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import ru.practicum.shareit.booking.Booking; +import ru.practicum.shareit.item.Comment; +import ru.practicum.shareit.item.Item; import ru.practicum.shareit.validation.CreateObject; +import ru.practicum.shareit.validation.UpdateObject; + +import java.util.List; @Data @AllArgsConstructor @NoArgsConstructor -public class UserDtoInput { +public class UserDto { + + private Long id; @NotNull(groups = {CreateObject.class}, message = "Имя должно быть указано.") @NotBlank(groups = {CreateObject.class}, message = "Имя не может быть пустым.") private String name; @NotNull(groups = {CreateObject.class}, message = "Email должен быть указан.") - @Email(groups = {CreateObject.class}, message = "Email должен быть указан корректно.") + @Email(groups = {CreateObject.class, UpdateObject.class}, message = "Email должен быть указан корректно.") private String email; + private List items; + + private List bookings; + + private List comments; + } diff --git a/server/src/main/java/ru/practicum/shareit/user/UserDtoOutput.java b/src/main/java/ru/practicum/shareit/user/UserDtoOutput.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/user/UserDtoOutput.java rename to src/main/java/ru/practicum/shareit/user/UserDtoOutput.java diff --git a/server/src/main/java/ru/practicum/shareit/user/UserDtoShort.java b/src/main/java/ru/practicum/shareit/user/UserDtoShort.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/user/UserDtoShort.java rename to src/main/java/ru/practicum/shareit/user/UserDtoShort.java diff --git a/server/src/main/java/ru/practicum/shareit/user/UserMapper.java b/src/main/java/ru/practicum/shareit/user/UserMapper.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/user/UserMapper.java rename to src/main/java/ru/practicum/shareit/user/UserMapper.java diff --git a/server/src/main/java/ru/practicum/shareit/user/UserRepository.java b/src/main/java/ru/practicum/shareit/user/UserRepository.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/user/UserRepository.java rename to src/main/java/ru/practicum/shareit/user/UserRepository.java diff --git a/server/src/main/java/ru/practicum/shareit/user/UserService.java b/src/main/java/ru/practicum/shareit/user/UserService.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/user/UserService.java rename to src/main/java/ru/practicum/shareit/user/UserService.java diff --git a/server/src/main/java/ru/practicum/shareit/user/UserServiceImpl.java b/src/main/java/ru/practicum/shareit/user/UserServiceImpl.java similarity index 100% rename from server/src/main/java/ru/practicum/shareit/user/UserServiceImpl.java rename to src/main/java/ru/practicum/shareit/user/UserServiceImpl.java diff --git a/gateway/src/main/java/ru/practicum/shareit/validation/CreateObject.java b/src/main/java/ru/practicum/shareit/validation/CreateObject.java similarity index 100% rename from gateway/src/main/java/ru/practicum/shareit/validation/CreateObject.java rename to src/main/java/ru/practicum/shareit/validation/CreateObject.java diff --git a/gateway/src/main/java/ru/practicum/shareit/validation/UpdateObject.java b/src/main/java/ru/practicum/shareit/validation/UpdateObject.java similarity index 100% rename from gateway/src/main/java/ru/practicum/shareit/validation/UpdateObject.java rename to src/main/java/ru/practicum/shareit/validation/UpdateObject.java diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml new file mode 100644 index 0000000..faf6257 --- /dev/null +++ b/src/main/resources/application.yaml @@ -0,0 +1,20 @@ +spring: + application.name: shareit + main.banner-mode: off + datasource: + url: jdbc:postgresql://localhost:5432/shareit + driver-class-name: org.postgresql.Driver + username: shareituser + password: 12345678 + jpa: + show-sql: true + hibernate: + ddl-auto: update + properties: + hibernate.jdbc.time_zone: UTC + dialect: org.hibernate.dialect.PostgreSQL95Dialect + format_sql: true + sql: + init: + mode: always + diff --git a/server/src/main/resources/schema.sql b/src/main/resources/schema.sql similarity index 100% rename from server/src/main/resources/schema.sql rename to src/main/resources/schema.sql