From 14562461f16d80f1fddeb1d654cfc32ac6349073 Mon Sep 17 00:00:00 2001
From: Karat120 <140876935+Karat120@users.noreply.github.com>
Date: Mon, 23 Feb 2026 12:08:12 +0700
Subject: [PATCH 1/3] Initial commit
---
.github/workflows/api-tests.yml | 8 +
.gitignore | 33 +++
README.md | 2 +
checkstyle.xml | 257 ++++++++++++++++++
lombok.config | 4 +
pom.xml | 247 +++++++++++++++++
.../java/ru/practicum/shareit/ShareItApp.java | 13 +
.../ru/practicum/shareit/booking/Booking.java | 7 +
.../shareit/booking/BookingController.java | 12 +
.../shareit/booking/dto/BookingDto.java | 7 +
.../shareit/item/ItemController.java | 12 +
.../practicum/shareit/item/dto/ItemDto.java | 7 +
.../ru/practicum/shareit/item/model/Item.java | 7 +
.../shareit/request/ItemRequest.java | 7 +
.../request/ItemRequestController.java | 12 +
.../shareit/request/dto/ItemRequestDto.java | 7 +
.../java/ru/practicum/shareit/user/User.java | 7 +
.../shareit/user/UserController.java | 12 +
.../resources/application-test.properties | 13 +
src/main/resources/application.properties | 14 +
.../ru/practicum/shareit/ShareItTests.java | 13 +
suppressions.xml | 7 +
22 files changed, 708 insertions(+)
create mode 100644 .github/workflows/api-tests.yml
create mode 100644 .gitignore
create mode 100644 README.md
create mode 100644 checkstyle.xml
create mode 100644 lombok.config
create mode 100644 pom.xml
create mode 100644 src/main/java/ru/practicum/shareit/ShareItApp.java
create mode 100644 src/main/java/ru/practicum/shareit/booking/Booking.java
create mode 100644 src/main/java/ru/practicum/shareit/booking/BookingController.java
create mode 100644 src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java
create mode 100644 src/main/java/ru/practicum/shareit/item/ItemController.java
create mode 100644 src/main/java/ru/practicum/shareit/item/dto/ItemDto.java
create mode 100644 src/main/java/ru/practicum/shareit/item/model/Item.java
create mode 100644 src/main/java/ru/practicum/shareit/request/ItemRequest.java
create mode 100644 src/main/java/ru/practicum/shareit/request/ItemRequestController.java
create mode 100644 src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java
create mode 100644 src/main/java/ru/practicum/shareit/user/User.java
create mode 100644 src/main/java/ru/practicum/shareit/user/UserController.java
create mode 100644 src/main/resources/application-test.properties
create mode 100644 src/main/resources/application.properties
create mode 100644 src/test/java/ru/practicum/shareit/ShareItTests.java
create mode 100644 suppressions.xml
diff --git a/.github/workflows/api-tests.yml b/.github/workflows/api-tests.yml
new file mode 100644
index 00000000..51c3d8b3
--- /dev/null
+++ b/.github/workflows/api-tests.yml
@@ -0,0 +1,8 @@
+name: ShareIt API Tests
+
+on:
+ pull_request:
+
+jobs:
+ build:
+ uses: yandex-praktikum/java-shareit/.github/workflows/api-tests.yml@ci
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..549e00a2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..47a75f04
--- /dev/null
+++ b/README.md
@@ -0,0 +1,2 @@
+# java-shareit
+Template repository for Shareit project.
diff --git a/checkstyle.xml b/checkstyle.xml
new file mode 100644
index 00000000..c28a0d3c
--- /dev/null
+++ b/checkstyle.xml
@@ -0,0 +1,257 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lombok.config b/lombok.config
new file mode 100644
index 00000000..b0056c11
--- /dev/null
+++ b/lombok.config
@@ -0,0 +1,4 @@
+config.stopBubbling = true
+lombok.anyconstructor.addconstructorproperties = false
+lombok.addLombokGeneratedAnnotation = true
+lombok.addSuppressWarnings = false
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 00000000..2db888c5
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,247 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.3.2
+
+
+
+ ru.practicum
+ shareit
+ 0.0.1-SNAPSHOT
+
+ ShareIt
+
+
+ 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
+ runtime
+
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+ com.h2database
+ h2
+ test
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+
+
+
+
+ src/main/resources
+ true
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ test
+
+
+
+
+ org.apache.maven.plugins
+ maven-checkstyle-plugin
+ 3.1.2
+
+ checkstyle.xml
+ true
+ true
+ true
+
+
+
+
+ check
+
+ compile
+
+
+
+
+ com.puppycrawl.tools
+ checkstyle
+ 10.3
+
+
+
+
+ com.github.spotbugs
+ spotbugs-maven-plugin
+ 4.8.5.0
+
+ Max
+ High
+
+
+
+
+ check
+
+
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+ 0.8.12
+
+
+
+
+
+ jacoco-initialize
+
+ prepare-agent
+
+
+
+ jacoco-check
+
+ check
+
+
+
+
+ BUNDLE
+
+
+ INSTRUCTION
+ COVEREDRATIO
+ 0.01
+
+
+ LINE
+ COVEREDRATIO
+ 0.9
+
+
+ BRANCH
+ COVEREDRATIO
+ 0.6
+
+
+ COMPLEXITY
+ COVEREDRATIO
+ 0.6
+
+
+ METHOD
+ COVEREDRATIO
+ 0.7
+
+
+ CLASS
+ MISSEDCOUNT
+ 1
+
+
+
+
+
+
+
+ jacoco-report
+ test
+
+ report
+
+
+
+
+
+
+
+
+
+ check
+
+
+
+ org.apache.maven.plugins
+ maven-checkstyle-plugin
+
+
+ com.github.spotbugs
+ spotbugs-maven-plugin
+
+
+
+
+
+
+ com.github.spotbugs
+ spotbugs-maven-plugin
+
+
+
+
+
+ coverage
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+
+
+
+
+
+
+
diff --git a/src/main/java/ru/practicum/shareit/ShareItApp.java b/src/main/java/ru/practicum/shareit/ShareItApp.java
new file mode 100644
index 00000000..a00ad567
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/ShareItApp.java
@@ -0,0 +1,13 @@
+package ru.practicum.shareit;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class ShareItApp {
+
+ public static void main(String[] args) {
+ SpringApplication.run(ShareItApp.class, args);
+ }
+
+}
diff --git a/src/main/java/ru/practicum/shareit/booking/Booking.java b/src/main/java/ru/practicum/shareit/booking/Booking.java
new file mode 100644
index 00000000..2d9c6668
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/booking/Booking.java
@@ -0,0 +1,7 @@
+package ru.practicum.shareit.booking;
+
+/**
+ * TODO Sprint add-bookings.
+ */
+public class Booking {
+}
diff --git a/src/main/java/ru/practicum/shareit/booking/BookingController.java b/src/main/java/ru/practicum/shareit/booking/BookingController.java
new file mode 100644
index 00000000..b94493d4
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/booking/BookingController.java
@@ -0,0 +1,12 @@
+package ru.practicum.shareit.booking;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * TODO Sprint add-bookings.
+ */
+@RestController
+@RequestMapping(path = "/bookings")
+public class BookingController {
+}
diff --git a/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java b/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java
new file mode 100644
index 00000000..861de9e0
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/booking/dto/BookingDto.java
@@ -0,0 +1,7 @@
+package ru.practicum.shareit.booking.dto;
+
+/**
+ * TODO Sprint add-bookings.
+ */
+public class BookingDto {
+}
diff --git a/src/main/java/ru/practicum/shareit/item/ItemController.java b/src/main/java/ru/practicum/shareit/item/ItemController.java
new file mode 100644
index 00000000..bb17668b
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/item/ItemController.java
@@ -0,0 +1,12 @@
+package ru.practicum.shareit.item;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * TODO Sprint add-controllers.
+ */
+@RestController
+@RequestMapping("/items")
+public class ItemController {
+}
diff --git a/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java b/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java
new file mode 100644
index 00000000..9319d7d7
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java
@@ -0,0 +1,7 @@
+package ru.practicum.shareit.item.dto;
+
+/**
+ * TODO Sprint add-controllers.
+ */
+public class ItemDto {
+}
diff --git a/src/main/java/ru/practicum/shareit/item/model/Item.java b/src/main/java/ru/practicum/shareit/item/model/Item.java
new file mode 100644
index 00000000..44eb73dd
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/item/model/Item.java
@@ -0,0 +1,7 @@
+package ru.practicum.shareit.item.model;
+
+/**
+ * TODO Sprint add-controllers.
+ */
+public class Item {
+}
diff --git a/src/main/java/ru/practicum/shareit/request/ItemRequest.java b/src/main/java/ru/practicum/shareit/request/ItemRequest.java
new file mode 100644
index 00000000..95d6f23c
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/request/ItemRequest.java
@@ -0,0 +1,7 @@
+package ru.practicum.shareit.request;
+
+/**
+ * TODO Sprint add-item-requests.
+ */
+public class ItemRequest {
+}
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 00000000..064e2e9c
--- /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/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java b/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java
new file mode 100644
index 00000000..7b3ed544
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/request/dto/ItemRequestDto.java
@@ -0,0 +1,7 @@
+package ru.practicum.shareit.request.dto;
+
+/**
+ * TODO Sprint add-item-requests.
+ */
+public class ItemRequestDto {
+}
diff --git a/src/main/java/ru/practicum/shareit/user/User.java b/src/main/java/ru/practicum/shareit/user/User.java
new file mode 100644
index 00000000..ae6e7f33
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/user/User.java
@@ -0,0 +1,7 @@
+package ru.practicum.shareit.user;
+
+/**
+ * TODO Sprint add-controllers.
+ */
+public class User {
+}
diff --git a/src/main/java/ru/practicum/shareit/user/UserController.java b/src/main/java/ru/practicum/shareit/user/UserController.java
new file mode 100644
index 00000000..03039b9d
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/user/UserController.java
@@ -0,0 +1,12 @@
+package ru.practicum.shareit.user;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * TODO Sprint add-controllers.
+ */
+@RestController
+@RequestMapping(path = "/users")
+public class UserController {
+}
diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties
new file mode 100644
index 00000000..9e9bc4b6
--- /dev/null
+++ b/src/main/resources/application-test.properties
@@ -0,0 +1,13 @@
+spring.jpa.hibernate.ddl-auto=none
+spring.jpa.properties.hibernate.format_sql=true
+spring.sql.init.mode=always
+logging.level.org.springframework.orm.jpa=INFO
+logging.level.org.springframework.transaction=INFO
+logging.level.org.springframework.transaction.interceptor=TRACE
+logging.level.org.springframework.orm.jpa.JpaTransactionManager=DEBUG
+
+# TODO Append connection to H2 DB
+#spring.datasource.driverClassName
+#spring.datasource.url
+#spring.datasource.username
+#spring.datasource.password
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
new file mode 100644
index 00000000..51c51801
--- /dev/null
+++ b/src/main/resources/application.properties
@@ -0,0 +1,14 @@
+spring.jpa.hibernate.ddl-auto=none
+spring.jpa.properties.hibernate.format_sql=true
+spring.sql.init.mode=always
+
+logging.level.org.springframework.orm.jpa=INFO
+logging.level.org.springframework.transaction=INFO
+logging.level.org.springframework.transaction.interceptor=TRACE
+logging.level.org.springframework.orm.jpa.JpaTransactionManager=DEBUG
+
+# TODO Append connection to Postgres DB
+#spring.datasource.driverClassName
+#spring.datasource.url
+#spring.datasource.username
+#spring.datasource.password
diff --git a/src/test/java/ru/practicum/shareit/ShareItTests.java b/src/test/java/ru/practicum/shareit/ShareItTests.java
new file mode 100644
index 00000000..4d79052f
--- /dev/null
+++ b/src/test/java/ru/practicum/shareit/ShareItTests.java
@@ -0,0 +1,13 @@
+package ru.practicum.shareit;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class ShareItTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}
diff --git a/suppressions.xml b/suppressions.xml
new file mode 100644
index 00000000..b2c6822f
--- /dev/null
+++ b/suppressions.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
From eb2df7480c7fad0b0ddb93f953cc7395f5447c77 Mon Sep 17 00:00:00 2001
From: Karat120
Date: Sun, 15 Mar 2026 15:12:13 +0500
Subject: [PATCH 2/3] add-controllers
---
.../shareit/exception/ConflictException.java | 7 ++
.../shareit/exception/ErrorHandler.java | 41 ++++++++
.../shareit/exception/NotFoundException.java | 7 ++
.../exception/ValidationException.java | 7 ++
.../shareit/item/ItemController.java | 52 ++++++++--
.../ru/practicum/shareit/item/ItemMapper.java | 25 +++++
.../practicum/shareit/item/ItemService.java | 16 +++
.../shareit/item/ItemServiceImpl.java | 97 +++++++++++++++++++
.../practicum/shareit/item/dto/ItemDto.java | 20 +++-
.../ru/practicum/shareit/item/model/Item.java | 21 +++-
.../java/ru/practicum/shareit/user/User.java | 17 +++-
.../shareit/user/UserController.java | 49 ++++++++--
.../ru/practicum/shareit/user/UserMapper.java | 21 ++++
.../practicum/shareit/user/UserService.java | 16 +++
.../shareit/user/UserServiceImpl.java | 80 +++++++++++++++
.../practicum/shareit/user/dto/UserDto.java | 17 ++++
16 files changed, 468 insertions(+), 25 deletions(-)
create mode 100644 src/main/java/ru/practicum/shareit/exception/ConflictException.java
create mode 100644 src/main/java/ru/practicum/shareit/exception/ErrorHandler.java
create mode 100644 src/main/java/ru/practicum/shareit/exception/NotFoundException.java
create mode 100644 src/main/java/ru/practicum/shareit/exception/ValidationException.java
create mode 100644 src/main/java/ru/practicum/shareit/item/ItemMapper.java
create mode 100644 src/main/java/ru/practicum/shareit/item/ItemService.java
create mode 100644 src/main/java/ru/practicum/shareit/item/ItemServiceImpl.java
create mode 100644 src/main/java/ru/practicum/shareit/user/UserMapper.java
create mode 100644 src/main/java/ru/practicum/shareit/user/UserService.java
create mode 100644 src/main/java/ru/practicum/shareit/user/UserServiceImpl.java
create mode 100644 src/main/java/ru/practicum/shareit/user/dto/UserDto.java
diff --git a/src/main/java/ru/practicum/shareit/exception/ConflictException.java b/src/main/java/ru/practicum/shareit/exception/ConflictException.java
new file mode 100644
index 00000000..78851230
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/exception/ConflictException.java
@@ -0,0 +1,7 @@
+package ru.practicum.shareit.exception;
+
+public class ConflictException extends RuntimeException {
+ public ConflictException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/ru/practicum/shareit/exception/ErrorHandler.java b/src/main/java/ru/practicum/shareit/exception/ErrorHandler.java
new file mode 100644
index 00000000..7c5bb444
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/exception/ErrorHandler.java
@@ -0,0 +1,41 @@
+package ru.practicum.shareit.exception;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+@Slf4j
+@RestControllerAdvice
+public class ErrorHandler {
+
+ @ExceptionHandler(Exception.class)
+ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+ public Map catchAllExceptions(Exception ex) {
+ log.error("500: ", ex);
+ return Map.of("error", "Произошла ошибка");
+ }
+
+ @ExceptionHandler({ValidationException.class, MethodArgumentNotValidException.class})
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ public Map catchValidationErrors(Exception ex) {
+ log.error("400: {}", ex.getMessage());
+ return Map.of("error", "Ошибка валидации");
+ }
+
+ @ExceptionHandler(ConflictException.class)
+ @ResponseStatus(HttpStatus.CONFLICT)
+ public Map catchConflictStatus(ConflictException ex) {
+ log.error("409: {}", ex.getMessage());
+ return Map.of("error", ex.getMessage());
+ }
+
+ @ExceptionHandler(NotFoundException.class)
+ @ResponseStatus(HttpStatus.NOT_FOUND)
+ public Map catchNotFoundStatus(NotFoundException ex) {
+ log.error("404: {}", ex.getMessage());
+ return Map.of("error", ex.getMessage());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ru/practicum/shareit/exception/NotFoundException.java b/src/main/java/ru/practicum/shareit/exception/NotFoundException.java
new file mode 100644
index 00000000..508b5456
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/exception/NotFoundException.java
@@ -0,0 +1,7 @@
+package ru.practicum.shareit.exception;
+
+public class NotFoundException extends RuntimeException {
+ public NotFoundException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/ru/practicum/shareit/exception/ValidationException.java b/src/main/java/ru/practicum/shareit/exception/ValidationException.java
new file mode 100644
index 00000000..59043da1
--- /dev/null
+++ b/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/ItemController.java b/src/main/java/ru/practicum/shareit/item/ItemController.java
index bb17668b..853d3444 100644
--- a/src/main/java/ru/practicum/shareit/item/ItemController.java
+++ b/src/main/java/ru/practicum/shareit/item/ItemController.java
@@ -1,12 +1,52 @@
package ru.practicum.shareit.item;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import jakarta.validation.Valid;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+import ru.practicum.shareit.item.dto.ItemDto;
-/**
- * TODO Sprint add-controllers.
- */
+import java.util.List;
+
+@Slf4j
@RestController
@RequestMapping("/items")
+@RequiredArgsConstructor
public class ItemController {
-}
+
+ private final ItemService itemService;
+ private static final String USER_ID_HEADER = "X-Sharer-User-Id";
+
+ @GetMapping
+ public List fetchAllUserItems(@RequestHeader(USER_ID_HEADER) Long ownerId) {
+ log.info("GET /items (владелец id={})", ownerId);
+ return itemService.getByOwner(ownerId);
+ }
+
+ @GetMapping("/search")
+ public List findItems(@RequestParam(name = "text") String query) {
+ log.info("GET /items/search?text={}", query);
+ return itemService.search(query);
+ }
+
+ @PatchMapping("/{itemId}")
+ public ItemDto modifyItem(@RequestHeader(USER_ID_HEADER) Long requesterId,
+ @PathVariable(name = "itemId") Long id,
+ @RequestBody ItemDto payload) {
+ log.info("PATCH /items/{} от пользователя id={}", id, requesterId);
+ return itemService.update(requesterId, id, payload);
+ }
+
+ @PostMapping
+ public ItemDto addNewItem(@RequestHeader(USER_ID_HEADER) Long creatorId,
+ @Valid @RequestBody ItemDto payload) {
+ log.info("POST /items от пользователя id={}", creatorId);
+ return itemService.create(creatorId, payload);
+ }
+
+ @GetMapping("/{itemId}")
+ public ItemDto fetchItemById(@PathVariable(name = "itemId") Long id) {
+ log.info("GET /items/{}", id);
+ return itemService.getById(id);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ru/practicum/shareit/item/ItemMapper.java b/src/main/java/ru/practicum/shareit/item/ItemMapper.java
new file mode 100644
index 00000000..11e611bf
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/item/ItemMapper.java
@@ -0,0 +1,25 @@
+package ru.practicum.shareit.item;
+
+import ru.practicum.shareit.item.dto.ItemDto;
+import ru.practicum.shareit.item.model.Item;
+
+public class ItemMapper {
+ public static Item toItem(ItemDto dto) {
+ return Item.builder()
+ .available(dto.getAvailable())
+ .description(dto.getDescription())
+ .name(dto.getName())
+ .id(dto.getId())
+ .build();
+ }
+
+ public static ItemDto toItemDto(Item entity) {
+ return ItemDto.builder()
+ .requestId(entity.getRequestId())
+ .available(entity.getAvailable())
+ .description(entity.getDescription())
+ .name(entity.getName())
+ .id(entity.getId())
+ .build();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ru/practicum/shareit/item/ItemService.java b/src/main/java/ru/practicum/shareit/item/ItemService.java
new file mode 100644
index 00000000..1b308318
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/item/ItemService.java
@@ -0,0 +1,16 @@
+package ru.practicum.shareit.item;
+
+import ru.practicum.shareit.item.dto.ItemDto;
+import java.util.List;
+
+public interface ItemService {
+ ItemDto update(Long userId, Long itemId, ItemDto itemDto);
+
+ List search(String text);
+
+ ItemDto getById(Long itemId);
+
+ ItemDto create(Long userId, ItemDto itemDto);
+
+ List getByOwner(Long userId);
+}
\ No newline at end of file
diff --git a/src/main/java/ru/practicum/shareit/item/ItemServiceImpl.java b/src/main/java/ru/practicum/shareit/item/ItemServiceImpl.java
new file mode 100644
index 00000000..cd6c86ff
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/item/ItemServiceImpl.java
@@ -0,0 +1,97 @@
+package ru.practicum.shareit.item;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import ru.practicum.shareit.exception.NotFoundException;
+import ru.practicum.shareit.item.dto.ItemDto;
+import ru.practicum.shareit.item.model.Item;
+import ru.practicum.shareit.user.User;
+import ru.practicum.shareit.user.UserService;
+import ru.practicum.shareit.user.UserMapper;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class ItemServiceImpl implements ItemService {
+
+ private final Map repository = new HashMap<>();
+ private final UserService userService;
+ private Long lastGeneratedId = 1L;
+
+ @Override
+ public List search(String searchStr) {
+ if (searchStr == null || searchStr.isBlank()) {
+ return Collections.emptyList();
+ }
+
+ String lowerCaseQuery = searchStr.toLowerCase();
+ return repository.values().stream()
+ .filter(Item::getAvailable)
+ .filter(item -> item.getName().toLowerCase().contains(lowerCaseQuery)
+ || item.getDescription().toLowerCase().contains(lowerCaseQuery))
+ .map(ItemMapper::toItemDto)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public ItemDto getById(Long id) {
+ Item found = repository.get(id);
+ if (found == null) {
+ throw new NotFoundException("Объект с идентификатором " + id + " не существует");
+ }
+ return ItemMapper.toItemDto(found);
+ }
+
+ @Override
+ public List getByOwner(Long ownerId) {
+ userService.getById(ownerId);
+
+ return repository.values().stream()
+ .filter(obj -> obj.getOwner().getId().equals(ownerId))
+ .map(ItemMapper::toItemDto)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public ItemDto update(Long userId, Long itemId, ItemDto dto) {
+ Item target = repository.get(itemId);
+
+ if (Objects.isNull(target)) {
+ throw new NotFoundException("Вещь с id " + itemId + " не найдена");
+ }
+
+ if (!Objects.equals(target.getOwner().getId(), userId)) {
+ throw new NotFoundException("Доступ запрещен: редактировать может только владелец");
+ }
+
+ if (dto.getName() != null && !dto.getName().trim().isEmpty()) {
+ target.setName(dto.getName());
+ }
+ if (dto.getDescription() != null && !dto.getDescription().trim().isEmpty()) {
+ target.setDescription(dto.getDescription());
+ }
+ if (dto.getAvailable() != null) {
+ target.setAvailable(dto.getAvailable());
+ }
+
+ return ItemMapper.toItemDto(target);
+ }
+
+ @Override
+ public ItemDto create(Long userId, ItemDto itemDto) {
+ User creator = UserMapper.toUser(userService.getById(userId));
+ Item newEntry = ItemMapper.toItem(itemDto);
+
+ newEntry.setId(lastGeneratedId++);
+ newEntry.setOwner(creator);
+
+ repository.put(newEntry.getId(), newEntry);
+ log.info("Сохранена новая вещь с ID: {}", newEntry.getId());
+
+ return ItemMapper.toItemDto(newEntry);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java b/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java
index 9319d7d7..1098f215 100644
--- a/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java
+++ b/src/main/java/ru/practicum/shareit/item/dto/ItemDto.java
@@ -1,7 +1,19 @@
package ru.practicum.shareit.item.dto;
-/**
- * TODO Sprint add-controllers.
- */
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder
public class ItemDto {
-}
+ private Long id;
+ @NotBlank
+ private String name;
+ @NotBlank
+ private String description;
+ @NotNull
+ private Boolean available;
+ private Long requestId;
+}
\ No newline at end of file
diff --git a/src/main/java/ru/practicum/shareit/item/model/Item.java b/src/main/java/ru/practicum/shareit/item/model/Item.java
index 44eb73dd..dbb28048 100644
--- a/src/main/java/ru/practicum/shareit/item/model/Item.java
+++ b/src/main/java/ru/practicum/shareit/item/model/Item.java
@@ -1,7 +1,20 @@
package ru.practicum.shareit.item.model;
-/**
- * TODO Sprint add-controllers.
- */
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import ru.practicum.shareit.user.User;
+
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
public class Item {
-}
+ private Long id;
+ private String name;
+ private String description;
+ private Boolean available;
+ private User owner;
+ private Long requestId;
+}
\ No newline at end of file
diff --git a/src/main/java/ru/practicum/shareit/user/User.java b/src/main/java/ru/practicum/shareit/user/User.java
index ae6e7f33..69127b15 100644
--- a/src/main/java/ru/practicum/shareit/user/User.java
+++ b/src/main/java/ru/practicum/shareit/user/User.java
@@ -1,7 +1,16 @@
package ru.practicum.shareit.user;
-/**
- * TODO Sprint add-controllers.
- */
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
public class User {
-}
+ private String email;
+ private String name;
+ private Long id;
+}
\ No newline at end of file
diff --git a/src/main/java/ru/practicum/shareit/user/UserController.java b/src/main/java/ru/practicum/shareit/user/UserController.java
index 03039b9d..1391acf0 100644
--- a/src/main/java/ru/practicum/shareit/user/UserController.java
+++ b/src/main/java/ru/practicum/shareit/user/UserController.java
@@ -1,12 +1,47 @@
package ru.practicum.shareit.user;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import jakarta.validation.Valid;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+import ru.practicum.shareit.user.dto.UserDto;
-/**
- * TODO Sprint add-controllers.
- */
+import java.util.List;
+
+@Slf4j
@RestController
-@RequestMapping(path = "/users")
+@RequestMapping("/users")
+@RequiredArgsConstructor
public class UserController {
-}
+ private final UserService userService;
+
+ @DeleteMapping("/{id}")
+ public void removeUser(@PathVariable Long id) {
+ log.info("DELETE request for user ID: {}", id);
+ userService.delete(id);
+ }
+
+ @GetMapping
+ public List getAllUsers() {
+ log.info("GET request for all users");
+ return userService.findAll();
+ }
+
+ @PatchMapping("/{id}")
+ public UserDto patchUser(@PathVariable Long id, @RequestBody UserDto dto) {
+ log.info("PATCH request for user ID: {}", id);
+ return userService.update(id, dto);
+ }
+
+ @GetMapping("/{id}")
+ public UserDto getUser(@PathVariable Long id) {
+ log.info("GET request for user ID: {}", id);
+ return userService.getById(id);
+ }
+
+ @PostMapping
+ public UserDto saveUser(@Valid @RequestBody UserDto dto) {
+ log.info("POST request to create user: {}", dto.getEmail());
+ return userService.create(dto);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ru/practicum/shareit/user/UserMapper.java b/src/main/java/ru/practicum/shareit/user/UserMapper.java
new file mode 100644
index 00000000..a4620b17
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/user/UserMapper.java
@@ -0,0 +1,21 @@
+package ru.practicum.shareit.user;
+
+import ru.practicum.shareit.user.dto.UserDto;
+
+public class UserMapper {
+ public static User toUser(UserDto dto) {
+ return User.builder()
+ .email(dto.getEmail())
+ .name(dto.getName())
+ .id(dto.getId())
+ .build();
+ }
+
+ public static UserDto toUserDto(User model) {
+ return UserDto.builder()
+ .name(model.getName())
+ .email(model.getEmail())
+ .id(model.getId())
+ .build();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ru/practicum/shareit/user/UserService.java b/src/main/java/ru/practicum/shareit/user/UserService.java
new file mode 100644
index 00000000..f92f2f6c
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/user/UserService.java
@@ -0,0 +1,16 @@
+package ru.practicum.shareit.user;
+
+import ru.practicum.shareit.user.dto.UserDto;
+import java.util.List;
+
+public interface UserService {
+ void delete(Long id);
+
+ List findAll();
+
+ UserDto update(Long id, UserDto userDto);
+
+ UserDto getById(Long id);
+
+ UserDto create(UserDto userDto);
+}
\ No newline at end of file
diff --git a/src/main/java/ru/practicum/shareit/user/UserServiceImpl.java b/src/main/java/ru/practicum/shareit/user/UserServiceImpl.java
new file mode 100644
index 00000000..fb9aa035
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/user/UserServiceImpl.java
@@ -0,0 +1,80 @@
+package ru.practicum.shareit.user;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import ru.practicum.shareit.exception.ConflictException;
+import ru.practicum.shareit.exception.NotFoundException;
+import ru.practicum.shareit.exception.ValidationException;
+import ru.practicum.shareit.user.dto.UserDto;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class UserServiceImpl implements UserService {
+ private final Map dataStorage = new HashMap<>();
+ private Long sequenceId = 1L;
+
+ @Override
+ public void delete(Long id) {
+ dataStorage.remove(id);
+ }
+
+ @Override
+ public List findAll() {
+ return dataStorage.values().stream()
+ .map(UserMapper::toUserDto)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public UserDto getById(Long id) {
+ User user = dataStorage.get(id);
+ if (user == null) {
+ throw new NotFoundException("Пользователь не найден: " + id);
+ }
+ return UserMapper.toUserDto(user);
+ }
+
+ @Override
+ public UserDto update(Long id, UserDto dto) {
+ User existingUser = dataStorage.get(id);
+ if (existingUser == null) {
+ throw new NotFoundException("Невозможно обновить: пользователь " + id + " не существует");
+ }
+
+ if (dto.getEmail() != null && !dto.getEmail().equalsIgnoreCase(existingUser.getEmail())) {
+ if (!dto.getEmail().contains("@")) {
+ throw new ValidationException("Некорректный формат email");
+ }
+ validateEmailUniqueness(dto.getEmail(), id);
+ existingUser.setEmail(dto.getEmail());
+ }
+
+ if (dto.getName() != null && !dto.getName().trim().isEmpty()) {
+ existingUser.setName(dto.getName());
+ }
+
+ return UserMapper.toUserDto(existingUser);
+ }
+
+ @Override
+ public UserDto create(UserDto dto) {
+ validateEmailUniqueness(dto.getEmail(), null);
+ User newUser = UserMapper.toUser(dto);
+ newUser.setId(sequenceId++);
+ dataStorage.put(newUser.getId(), newUser);
+ return UserMapper.toUserDto(newUser);
+ }
+
+ private void validateEmailUniqueness(String email, Long currentUserId) {
+ boolean isDuplicate = dataStorage.values().stream()
+ .anyMatch(u -> u.getEmail().equalsIgnoreCase(email) && !u.getId().equals(currentUserId));
+ if (isDuplicate) {
+ throw new ConflictException("Электронная почта " + email + " уже используется");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ru/practicum/shareit/user/dto/UserDto.java b/src/main/java/ru/practicum/shareit/user/dto/UserDto.java
new file mode 100644
index 00000000..e2ec0803
--- /dev/null
+++ b/src/main/java/ru/practicum/shareit/user/dto/UserDto.java
@@ -0,0 +1,17 @@
+package ru.practicum.shareit.user.dto;
+
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotBlank;
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder
+public class UserDto {
+ @NotBlank
+ @Email
+ private String email;
+ @NotBlank
+ private String name;
+ private Long id;
+}
\ No newline at end of file
From c2399d9a860412a2ba633a9c99809ef61fd9e06e Mon Sep 17 00:00:00 2001
From: Evgeniy
Date: Mon, 16 Mar 2026 22:02:13 +0700
Subject: [PATCH 3/3] shareIT14
---
shareIt14 | 1 +
1 file changed, 1 insertion(+)
create mode 160000 shareIt14
diff --git a/shareIt14 b/shareIt14
new file mode 160000
index 00000000..14562461
--- /dev/null
+++ b/shareIt14
@@ -0,0 +1 @@
+Subproject commit 14562461f16d80f1fddeb1d654cfc32ac6349073