Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
238 changes: 161 additions & 77 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,78 +1,162 @@
# ShareIt

ShareIt — учебный сервис для шеринга вещей.

## Возможности

### Реализовано
- CRUD пользователей
- CRUD вещей
- Поиск доступных вещей по тексту

## Архитектура

Слои приложения:
- Controller: REST API
- Service: бизнес-логика
- Repository: слой хранения ( in-memory реализации)

Обработка ошибок централизована через `@RestControllerAdvice`.

## REST API

Ниже перечислены основные endpoints текущей версии.

### Пользователи: `/users`

| Метод | Endpoint | Описание |
| --- | --- | --- |
| `POST` | `/users` | Создать пользователя |
| `PATCH` | `/users/{userId}` | Обновить пользователя (частично) |
| `GET` | `/users/{userId}` | Получить пользователя по id |
| `GET` | `/users` | Получить список пользователей |
| `DELETE` | `/users/{userId}` | Удалить пользователя |

### Вещи: `/items`

Для методов, работающих от имени пользователя, используется заголовок:
- `X-Sharer-User-Id: <userId>`

| Метод | Endpoint | Описание |
| --- | --- | --- |
| `POST` | `/items` | Создать вещь |
| `PATCH` | `/items/{itemId}` | Обновить вещь (только владелец) |
| `GET` | `/items/{itemId}` | Получить вещь по id |
| `GET` | `/items` | Получить вещи владельца |
| `GET` | `/items/search?text=...` | Поиск доступных вещей |

## Технологии

- Java 21
- Spring Boot
- Maven
- Lombok
- Jakarta Validation
- JUnit 5, Spring Boot Test, MockMvc

## Как запустить

### Требования
- JDK 21
- Maven 3.9+

### Сборка и тесты
```bash
mvn test
```

### Запуск приложения
```bash
mvn spring-boot:run
```

## Качество кода

### Checkstyle (если включён)
```bash
mvn checkstyle:check
```

ShareIt — учебный сервис для шеринга вещей: пользователи добавляют вещи, ищут доступные, бронируют на даты и оставляют комментарии после аренды.

## Возможности

### Реализовано
- CRUD пользователей
- CRUD вещей
- Поиск доступных вещей по тексту
- Бронирования вещей:
- создание бронирования
- подтверждение/отклонение владельцем
- просмотр бронирования
- списки бронирований (для арендатора и владельца) с фильтрами по состоянию
- Комментарии к вещам (после завершённой аренды)

## Архитектура

Слои приложения:
- Controller: REST API
- Service: бизнес-логика
- Repository: Spring Data JPA (PostgreSQL / H2 для тестов)

Обработка ошибок централизована через `@RestControllerAdvice`.

## REST API

Для методов, работающих от имени пользователя, используется заголовок:
- `X-Sharer-User-Id: <userId>`

Ниже перечислены основные endpoints текущей версии.

### Пользователи: `/users`

| Метод | Endpoint | Описание |
| --- | --- | --- |
| `POST` | `/users` | Создать пользователя |
| `PATCH` | `/users/{userId}` | Обновить пользователя (частично) |
| `GET` | `/users/{userId}` | Получить пользователя по id |
| `GET` | `/users` | Получить список пользователей |
| `DELETE` | `/users/{userId}` | Удалить пользователя |

### Вещи: `/items`

| Метод | Endpoint | Описание |
| --- | --- | --- |
| `POST` | `/items` | Создать вещь |
| `PATCH` | `/items/{itemId}` | Обновить вещь (только владелец) |
| `GET` | `/items/{itemId}` | Получить вещь по id (с комментариями; для владельца — с last/next booking) |
| `GET` | `/items` | Получить вещи владельца (с last/next booking и комментариями) |
| `GET` | `/items/search?text=...` | Поиск доступных вещей |
| `POST` | `/items/{itemId}/comment` | Добавить комментарий к вещи |

### Бронирования: `/bookings`

| Метод | Endpoint | Описание |
| --- | --- | --- |
| `POST` | `/bookings` | Создать бронирование |
| `PATCH` | `/bookings/{bookingId}?approved={true\|false}` | Подтвердить/отклонить бронирование (только владелец) |
| `GET` | `/bookings/{bookingId}` | Получить бронирование (владелец или автор) |
| `GET` | `/bookings?state={state}` | Список бронирований текущего пользователя (арендатора) |
| `GET` | `/bookings/owner?state={state}` | Список бронирований для вещей текущего пользователя (владельца) |

`state` — фильтр по состоянию бронирования:
- `ALL` (по умолчанию) — все бронирования
- `CURRENT` — текущие (start <= now <= end)
- `PAST` — завершённые (end < now)
- `FUTURE` — будущие (start > now)
- `WAITING` — ожидают подтверждения владельцем
- `REJECTED` — отклонены владельцем

## Технологии

- Java 21
- Spring Boot
- Spring Data JPA (Hibernate)
- PostgreSQL (основная БД)
- H2 (тестовая БД)
- Maven
- Lombok
- Jakarta Validation
- JUnit 5, Spring Boot Test, MockMvc

## Как запустить

### Требования
- JDK 21
- Maven 3.9+
- PostgreSQL 14+

### Подготовка PostgreSQL

По умолчанию приложение ожидает настройки из `src/main/resources/application.properties`:
- URL: `jdbc:postgresql://localhost:5432/shareit`
- user: `shareit`
- password: `shareit`

База данных поднимается через Docker Compose (см. `compose.yaml`).

Запуск PostgreSQL:

```bash
docker compose up -d
```

Проверка, что PostgreSQL поднялся:

```bash
docker compose ps
```

Ожидаемое состояние сервиса `db`:
- статус `running`
- healthcheck `healthy`

Посмотреть логи:

```bash
docker logs -f shareit-db
```

Остановка PostgreSQL:

```bash
docker compose down
```

Таблицы создаются автоматически при старте приложения из `src/main/resources/schema.sql`.

### Сборка и тесты

Тесты используют H2 (настройки в `src/main/resources/application-test.properties`).

```bash
mvn test
```

H2-консоль включена в тестовом профиле:
- если запустить приложение с профилем `test`, будет доступна по пути `/h2-console`

Примечание: при `mvn test` используется H2, но веб-сервер не поднимается, поэтому H2 Console в браузере недоступна.

Пример запуска приложения с профилем `test` (для доступа к H2 Console):

```bash
mvn spring-boot:run -Dspring-boot.run.profiles=test
```

### Запуск приложения

```bash
mvn spring-boot:run
```

## Качество кода

### Checkstyle (если включён)

```bash
mvn checkstyle:check
```
15 changes: 15 additions & 0 deletions compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
services:
db:
image: postgres:16-alpine
container_name: shareit-db
ports:
- "5432:5432"
environment:
POSTGRES_DB: shareit
POSTGRES_USER: shareit
POSTGRES_PASSWORD: shareit
healthcheck:
test: ["CMD-SHELL", "pg_isready -U shareit -d shareit"]
interval: 5s
timeout: 5s
retries: 10
17 changes: 16 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
Expand All @@ -49,7 +53,6 @@
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
Expand All @@ -70,6 +73,18 @@
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
Expand Down
21 changes: 0 additions & 21 deletions src/main/java/ru/practicum/shareit/booking/Booking.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,12 +1,69 @@
package ru.practicum.shareit.booking;

import jakarta.validation.Valid;

import java.util.List;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.GetMapping;

import ru.practicum.shareit.booking.dto.BookingCreateDto;
import ru.practicum.shareit.booking.dto.BookingDto;
import ru.practicum.shareit.booking.model.BookingState;
import ru.practicum.shareit.booking.service.BookingService;

/**
* TODO Sprint add-bookings.
* REST-контроллер для операций с бронированиями.
*/
@RestController
@RequestMapping(path = "/bookings")
@RequiredArgsConstructor
@Slf4j
public class BookingController {
private final BookingService bookingService;

@PostMapping
public BookingDto create(@RequestHeader("X-Sharer-User-Id") Long userId,
@Valid @RequestBody BookingCreateDto bookingCreateDto) {
log.debug("POST /bookings userId={}", userId);
return bookingService.create(userId, bookingCreateDto);
}

@PatchMapping("/{bookingId}")
public BookingDto approve(@RequestHeader("X-Sharer-User-Id") Long userId,
@PathVariable Long bookingId,
@RequestParam boolean approved) {
log.debug("PATCH /bookings/{} userId={} approved={}", bookingId, userId, approved);
return bookingService.approve(userId, bookingId, approved);
}

@GetMapping("/{bookingId}")
public BookingDto getById(@RequestHeader("X-Sharer-User-Id") Long userId,
@PathVariable Long bookingId) {
log.debug("GET /bookings/{} userId={}", bookingId, userId);
return bookingService.getById(userId, bookingId);
}

@GetMapping
public List<BookingDto> getAllByBooker(@RequestHeader("X-Sharer-User-Id") Long userId,
@RequestParam(defaultValue = "ALL") BookingState state) {
log.debug("GET /bookings userId={} state={}", userId, state);
return bookingService.getAllByBooker(userId, state);
}

@GetMapping("/owner")
public List<BookingDto> getAllByOwner(@RequestHeader("X-Sharer-User-Id") Long userId,
@RequestParam(defaultValue = "ALL") BookingState state) {
log.debug("GET /bookings/owner userId={} state={}", userId, state);
return bookingService.getAllByOwner(userId, state);
}
}
Loading