From c624b1e99eebcfe281eb4dc7049a0d68259d5a20 Mon Sep 17 00:00:00 2001 From: Denis Panasyuk Date: Thu, 30 Oct 2025 12:53:55 +0300 Subject: [PATCH 1/7] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=BE=D1=81=D0=BD=D0=BE=D0=B2=D0=BD=D1=8B=D0=B5?= =?UTF-8?q?=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D1=8B=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D1=82=D0=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ExceptionHandler.java | 17 ++++ .../filmorate/controller/FilmController.java | 64 +++----------- .../filmorate/controller/UserController.java | 60 ++----------- .../filmorate/model/ErrorResponse.java | 13 +++ .../filmorate/service/FilmService.java | 14 ++++ .../filmorate/service/UserService.java | 14 ++++ .../filmorate/storage/FilmStorage.java | 14 ++++ .../storage/InMemoryFilmStorage.java | 84 +++++++++++++++++++ .../storage/InMemoryUserStorage.java | 80 ++++++++++++++++++ .../filmorate/storage/UserStorage.java | 14 ++++ .../controller/FilmControllerTest.java | 6 +- .../controller/UserControllerTest.java | 4 +- 12 files changed, 276 insertions(+), 108 deletions(-) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/controller/ExceptionHandler.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/model/ErrorResponse.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/service/UserService.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java create mode 100644 src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ExceptionHandler.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ExceptionHandler.java new file mode 100644 index 0000000..7555e65 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ExceptionHandler.java @@ -0,0 +1,17 @@ +package ru.yandex.practicum.filmorate.controller; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import ru.yandex.practicum.filmorate.exception.ValidationException; +import ru.yandex.practicum.filmorate.model.ErrorResponse; + +@RestControllerAdvice +public class ExceptionHandler { + + @org.springframework.web.bind.annotation.ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ErrorResponse handleValidationException(final ValidationException e) { + return new ErrorResponse(e.getMessage()); + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index 4116f66..9ab4726 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -5,6 +5,7 @@ import org.springframework.web.bind.annotation.*; import ru.yandex.practicum.filmorate.model.Film; import jakarta.validation.ValidationException; +import ru.yandex.practicum.filmorate.storage.InMemoryFilmStorage; import java.time.LocalDate; import java.util.Collection; @@ -16,70 +17,25 @@ @RequestMapping("/films") public class FilmController { - private final Map films = new HashMap<>(); + private final InMemoryFilmStorage inMemoryFilmStorage; - @GetMapping - public Collection findAll() { - log.info("Список фильмов выведен"); - return films.values(); + public FilmController(InMemoryFilmStorage inMemoryFilmStorage) { + this.inMemoryFilmStorage = inMemoryFilmStorage; } - private int getNextId() { - int currentMaxId = films.keySet() - .stream() - .mapToInt(id -> id) - .max() - .orElse(0); - return ++currentMaxId; + + @GetMapping + public Collection findAll() { + return inMemoryFilmStorage.findAll(); } @PostMapping public Film create(@Valid @RequestBody Film film) { - validateFilm(film); - film.setId(getNextId()); - films.put(film.getId(), film); - log.info("Фильм: {} добавлен в базу", film); - return film; + return inMemoryFilmStorage.create(film); } @PutMapping public Film update(@Valid @RequestBody Film newFilm) { - if (newFilm.getId() == null) { - log.warn("Не указан id"); - throw new ValidationException("Id должен быть указан"); - } - if (!films.containsKey(newFilm.getId())) { - log.warn("Фильм с указанным id не найден"); - throw new ValidationException("Фильм с id = " + newFilm.getId() + " не найден"); - } - validateFilm(newFilm); - Film oldFilm = films.get(newFilm.getId()); - oldFilm.setDescription(newFilm.getDescription()); - oldFilm.setDuration(newFilm.getDuration()); - oldFilm.setName(newFilm.getName()); - oldFilm.setReleaseDate(newFilm.getReleaseDate()); - log.info("Данные о фильме: {} обновлены", oldFilm); - return oldFilm; - } - - private void validateFilm(Film film) { - if (film.getDescription().length() > 200) { - log.warn("Ошибка лимита"); - throw new ValidationException("Описание превышает 200 символов"); - } - if (film.getReleaseDate().isBefore(LocalDate.of(1895, 12, 28))) { - log.warn("Ошибка даты"); - throw new ValidationException("Неверная дата релиза"); - } - - if (film.getName() == null || film.getName().isBlank()) { - log.warn("Пустое название фильма"); - throw new ValidationException("Название не может быть пустым"); - } - - if (film.getDuration() < 1) { - log.warn("Ошибка длительности"); - throw new ValidationException("Длительность не может быть меньше 1"); - } + return inMemoryFilmStorage.update(newFilm); } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java index 915a2df..29dfd30 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -4,6 +4,7 @@ import org.springframework.web.bind.annotation.*; import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.User; +import ru.yandex.practicum.filmorate.storage.InMemoryUserStorage; import java.time.LocalDate; import java.util.Collection; @@ -15,68 +16,25 @@ @RequestMapping("/users") public class UserController { - private final Map users = new HashMap<>(); + private final InMemoryUserStorage inMemoryUserStorage; + + public UserController(InMemoryUserStorage inMemoryUserStorage) { + this.inMemoryUserStorage = inMemoryUserStorage; + } @GetMapping public Collection findAll() { log.info("Список фильмов выведен"); - return users.values(); - } - - private int getNextId() { - int currentMaxId = users.keySet() - .stream() - .mapToInt(id -> id) - .max() - .orElse(0); - return ++currentMaxId; + return inMemoryUserStorage.findAll(); } @PostMapping public User create(@RequestBody User user) { - validateUser(user); - user.setId(getNextId()); - users.put(user.getId(), user); - log.info("Пользователь: {} добавлен в базу", user); - return user; + return inMemoryUserStorage.create(user); } @PutMapping public User update(@RequestBody User newUser) { - if (newUser.getId() == null) { - log.warn("Не указан id"); - throw new ValidationException("Id должен быть указан"); - } - if (!users.containsKey(newUser.getId())) { - log.warn("Пользователь с указанным id не найден"); - throw new ValidationException("Пользователь с id = " + newUser.getId() + " не найден"); - } - validateUser(newUser); - User oldUser = users.get(newUser.getId()); - oldUser.setEmail(newUser.getEmail()); - oldUser.setName(newUser.getName()); - oldUser.setLogin(newUser.getLogin()); - oldUser.setBirthday(newUser.getBirthday()); - log.info("Данные о пользователе: {} обновлены", oldUser); - return oldUser; - } - - private void validateUser(User user) { - if (!user.getEmail().contains("@")) { - log.warn("Ошибка в формате почты"); - throw new ValidationException("Неверная почта"); - } - if (user.getBirthday().isAfter(LocalDate.now())) { - log.warn("Ошибка в дате рождения"); - throw new ValidationException("Неверная дата рождения"); - } - if (user.getLogin().contains(" ")) { - log.warn("Ошибка в формате логина"); - throw new ValidationException("Неправильный формат логина"); - } - if (user.getName() == null || user.getName().trim().isEmpty()) { - log.info("Пустое имя пользователя заменено на логин"); - user.setName(user.getLogin()); - } + return inMemoryUserStorage.update(newUser); } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/ErrorResponse.java b/src/main/java/ru/yandex/practicum/filmorate/model/ErrorResponse.java new file mode 100644 index 0000000..6a9e1f5 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/ErrorResponse.java @@ -0,0 +1,13 @@ +package ru.yandex.practicum.filmorate.model; + +public class ErrorResponse { + String error; + + public ErrorResponse(String error) { + this.error = error; + } + + public String getError() { + return error; + } +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java new file mode 100644 index 0000000..fa18191 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -0,0 +1,14 @@ +package ru.yandex.practicum.filmorate.service; + +import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.storage.FilmStorage; + +@Service +public class FilmService { + + private final FilmStorage filmStorage; + + public FilmService(FilmStorage filmStorage) { + this.filmStorage = filmStorage; + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java new file mode 100644 index 0000000..8b83717 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -0,0 +1,14 @@ +package ru.yandex.practicum.filmorate.service; + +import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.storage.UserStorage; + +@Service +public class UserService { + + private final UserStorage userStorage; + + public UserService(UserStorage userStorage) { + this.userStorage = userStorage; + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java new file mode 100644 index 0000000..df2f19d --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java @@ -0,0 +1,14 @@ +package ru.yandex.practicum.filmorate.storage; + +import ru.yandex.practicum.filmorate.model.Film; + +import java.util.Collection; + +public interface FilmStorage { + + Collection findAll(); + + Film create(Film film); + + Film update(Film newFilm); +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java new file mode 100644 index 0000000..384be4b --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java @@ -0,0 +1,84 @@ +package ru.yandex.practicum.filmorate.storage; + +import jakarta.validation.ValidationException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.model.Film; + +import java.time.LocalDate; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Slf4j +@Component +public class InMemoryFilmStorage implements FilmStorage { + + private final Map films = new HashMap<>(); + + @Override + public Collection findAll() { + log.info("Список фильмов выведен"); + return films.values(); + } + + @Override + public Film create(Film film) { + validateFilm(film); + film.setId(getNextId()); + films.put(film.getId(), film); + log.info("Фильм: {} добавлен в базу", film); + return film; + } + + @Override + public Film update(Film newFilm) { + if (newFilm.getId() == null) { + log.warn("Не указан id"); + throw new ValidationException("Id должен быть указан"); + } + if (!films.containsKey(newFilm.getId())) { + log.warn("Фильм с указанным id не найден"); + throw new ValidationException("Фильм с id = " + newFilm.getId() + " не найден"); + } + validateFilm(newFilm); + Film oldFilm = films.get(newFilm.getId()); + oldFilm.setDescription(newFilm.getDescription()); + oldFilm.setDuration(newFilm.getDuration()); + oldFilm.setName(newFilm.getName()); + oldFilm.setReleaseDate(newFilm.getReleaseDate()); + log.info("Данные о фильме: {} обновлены", oldFilm); + return oldFilm; + } + + private int getNextId() { + int currentMaxId = films.keySet() + .stream() + .mapToInt(id -> id) + .max() + .orElse(0); + return ++currentMaxId; + } + + private void validateFilm(Film film) { + if (film.getDescription().length() > 200) { + log.warn("Ошибка лимита"); + throw new ValidationException("Описание превышает 200 символов"); + } + if (film.getReleaseDate().isBefore(LocalDate.of(1895, 12, 28))) { + log.warn("Ошибка даты"); + throw new ValidationException("Неверная дата релиза"); + } + + if (film.getName() == null || film.getName().isBlank()) { + log.warn("Пустое название фильма"); + throw new ValidationException("Название не может быть пустым"); + } + + if (film.getDuration() < 1) { + log.warn("Ошибка длительности"); + throw new ValidationException("Длительность не может быть меньше 1"); + } + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java new file mode 100644 index 0000000..c07870b --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java @@ -0,0 +1,80 @@ +package ru.yandex.practicum.filmorate.storage; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.exception.ValidationException; +import ru.yandex.practicum.filmorate.model.User; + +import java.time.LocalDate; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@Component +public class InMemoryUserStorage implements UserStorage { + + private final Map users = new HashMap<>(); + + @Override + public Collection findAll() { + log.info("Список фильмов выведен"); + return users.values(); + } + + @Override + public User create(User user) { + validateUser(user); + user.setId(getNextId()); + users.put(user.getId(), user); + return user; + } + + @Override + public User update(User newUser) { + if (newUser.getId() == null) { + log.warn("Не указан id"); + throw new ValidationException("Id должен быть указан"); + } + if (!users.containsKey(newUser.getId())) { + log.warn("Пользователь с указанным id не найден"); + throw new ValidationException("Пользователь с id = " + newUser.getId() + " не найден"); + } + validateUser(newUser); + User oldUser = users.get(newUser.getId()); + oldUser.setEmail(newUser.getEmail()); + oldUser.setName(newUser.getName()); + oldUser.setLogin(newUser.getLogin()); + oldUser.setBirthday(newUser.getBirthday()); + log.info("Данные о пользователе: {} обновлены", oldUser); + return oldUser; + } + + private int getNextId() { + int currentMaxId = users.keySet() + .stream() + .mapToInt(id -> id) + .max() + .orElse(0); + return ++currentMaxId; + } + + private void validateUser(User user) { + if (!user.getEmail().contains("@")) { + log.warn("Ошибка в формате почты"); + throw new ValidationException("Неверная почта"); + } + if (user.getBirthday().isAfter(LocalDate.now())) { + log.warn("Ошибка в дате рождения"); + throw new ValidationException("Неверная дата рождения"); + } + if (user.getLogin().contains(" ")) { + log.warn("Ошибка в формате логина"); + throw new ValidationException("Неправильный формат логина"); + } + if (user.getName() == null || user.getName().trim().isEmpty()) { + log.info("Пустое имя пользователя заменено на логин"); + user.setName(user.getLogin()); + } + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java new file mode 100644 index 0000000..88ced28 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java @@ -0,0 +1,14 @@ +package ru.yandex.practicum.filmorate.storage; + +import ru.yandex.practicum.filmorate.model.User; + +import java.util.Collection; + +public interface UserStorage { + + Collection findAll(); + + User create(User user); + + User update(User newUser); +} diff --git a/src/test/java/ru/yandex/practicum/filmorate/controller/FilmControllerTest.java b/src/test/java/ru/yandex/practicum/filmorate/controller/FilmControllerTest.java index 7bb1ead..0d0a70d 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/controller/FilmControllerTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/controller/FilmControllerTest.java @@ -3,13 +3,15 @@ import jakarta.validation.ValidationException; import org.junit.jupiter.api.Test; import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.storage.InMemoryFilmStorage; + import static org.junit.jupiter.api.Assertions.*; import java.time.LocalDate; public class FilmControllerTest { - - FilmController filmController = new FilmController(); + InMemoryFilmStorage inMemoryFilmStorage; + FilmController filmController = new FilmController(inMemoryFilmStorage); @Test void getFilmTest() { diff --git a/src/test/java/ru/yandex/practicum/filmorate/controller/UserControllerTest.java b/src/test/java/ru/yandex/practicum/filmorate/controller/UserControllerTest.java index f2af4a7..224b1fc 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/controller/UserControllerTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/controller/UserControllerTest.java @@ -3,6 +3,7 @@ import org.junit.jupiter.api.Test; import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.User; +import ru.yandex.practicum.filmorate.storage.InMemoryUserStorage; import java.time.LocalDate; @@ -10,7 +11,8 @@ import static org.junit.jupiter.api.Assertions.assertThrows; public class UserControllerTest { - UserController userController = new UserController(); + InMemoryUserStorage inMemoryUserStorage; + UserController userController = new UserController(inMemoryUserStorage); @Test void getFilmTest() { From 6d89c5f34295bc824ebd87b720b1464dff25b80c Mon Sep 17 00:00:00 2001 From: Denis Panasyuk Date: Sun, 2 Nov 2025 22:56:59 +0300 Subject: [PATCH 2/7] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=BE?= =?UTF-8?q?=D0=BD=D0=B0=D0=BB=20=D1=81=D0=BE=D0=B3=D0=BB=D0=B0=D1=81=D0=BD?= =?UTF-8?q?=D0=BE=20=D0=A2=D0=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...xceptionHandler.java => ErrorHandler.java} | 12 ++++- .../filmorate/controller/FilmController.java | 41 ++++++++++---- .../filmorate/controller/UserController.java | 32 ++++++++++- .../exception/NotFoundException.java | 7 +++ .../practicum/filmorate/model/Film.java | 11 ++-- .../practicum/filmorate/model/User.java | 3 ++ .../filmorate/service/FilmService.java | 39 +++++++++++++- .../filmorate/service/UserService.java | 53 ++++++++++++++++++- .../filmorate/storage/FilmStorage.java | 3 ++ .../storage/InMemoryFilmStorage.java | 24 +++++---- .../storage/InMemoryUserStorage.java | 14 +++-- .../filmorate/storage/UserStorage.java | 2 + .../controller/FilmControllerTest.java | 5 +- .../controller/UserControllerTest.java | 4 +- 14 files changed, 217 insertions(+), 33 deletions(-) rename src/main/java/ru/yandex/practicum/filmorate/controller/{ExceptionHandler.java => ErrorHandler.java} (59%) create mode 100644 src/main/java/ru/yandex/practicum/filmorate/exception/NotFoundException.java diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ExceptionHandler.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ErrorHandler.java similarity index 59% rename from src/main/java/ru/yandex/practicum/filmorate/controller/ExceptionHandler.java rename to src/main/java/ru/yandex/practicum/filmorate/controller/ErrorHandler.java index 7555e65..7a2babd 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ExceptionHandler.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ErrorHandler.java @@ -1,17 +1,25 @@ package ru.yandex.practicum.filmorate.controller; import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; +import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.ErrorResponse; @RestControllerAdvice -public class ExceptionHandler { +public class ErrorHandler { - @org.springframework.web.bind.annotation.ExceptionHandler + @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) public ErrorResponse handleValidationException(final ValidationException e) { return new ErrorResponse(e.getMessage()); } + + @ExceptionHandler + @ResponseStatus(HttpStatus.NOT_FOUND) + public ErrorResponse handleNotFoundException(final NotFoundException e) { + return new ErrorResponse(e.getMessage()); + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index 9ab4726..b5fc102 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -1,41 +1,60 @@ package ru.yandex.practicum.filmorate.controller; -import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import ru.yandex.practicum.filmorate.model.Film; -import jakarta.validation.ValidationException; -import ru.yandex.practicum.filmorate.storage.InMemoryFilmStorage; +import ru.yandex.practicum.filmorate.service.FilmService; +import ru.yandex.practicum.filmorate.storage.FilmStorage; -import java.time.LocalDate; import java.util.Collection; -import java.util.HashMap; -import java.util.Map; @Slf4j @RestController @RequestMapping("/films") public class FilmController { - private final InMemoryFilmStorage inMemoryFilmStorage; + private final FilmStorage inMemoryFilmStorage; + private final FilmService filmService; - public FilmController(InMemoryFilmStorage inMemoryFilmStorage) { + @Autowired + public FilmController(FilmStorage inMemoryFilmStorage, FilmService filmService) { this.inMemoryFilmStorage = inMemoryFilmStorage; + this.filmService = filmService; } - @GetMapping public Collection findAll() { return inMemoryFilmStorage.findAll(); } + @GetMapping("/{id}") + public Film findById(@PathVariable("id") int filmId) { + return inMemoryFilmStorage.findFilmById(filmId); + } + + @GetMapping("/popular") + public Collection getPopular(@RequestParam(defaultValue = "10") int count) { + return filmService.getPopular(count); + } + @PostMapping - public Film create(@Valid @RequestBody Film film) { + public Film create(@RequestBody Film film) { return inMemoryFilmStorage.create(film); } @PutMapping - public Film update(@Valid @RequestBody Film newFilm) { + public Film update(@RequestBody Film newFilm) { return inMemoryFilmStorage.update(newFilm); } + + @PutMapping("/{id}/like/{userId}") + public void addLike(@PathVariable int id, @PathVariable int userId) { + filmService.addLike(id, userId); + } + + @DeleteMapping("/{id}/like/{userId}") + public void deleteLike(@PathVariable int id, @PathVariable int userId) { + filmService.deleteLike(id, userId); + } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java index 29dfd30..a439dcd 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -3,13 +3,16 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; import ru.yandex.practicum.filmorate.exception.ValidationException; +import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.User; +import ru.yandex.practicum.filmorate.service.UserService; import ru.yandex.practicum.filmorate.storage.InMemoryUserStorage; import java.time.LocalDate; import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.Optional; @Slf4j @RestController @@ -17,9 +20,11 @@ public class UserController { private final InMemoryUserStorage inMemoryUserStorage; + private final UserService userService; - public UserController(InMemoryUserStorage inMemoryUserStorage) { + public UserController(InMemoryUserStorage inMemoryUserStorage, UserService userService) { this.inMemoryUserStorage = inMemoryUserStorage; + this.userService = userService; } @GetMapping @@ -28,6 +33,21 @@ public Collection findAll() { return inMemoryUserStorage.findAll(); } + @GetMapping("/{id}") + public User findUserById(@PathVariable("id") int userId) { + return inMemoryUserStorage.findUserById(userId); + } + + @GetMapping("/{id}/friends") + public Collection findAllFriends(@PathVariable("id") int userId) { + return userService.getFriendList(userId); + } + + @GetMapping("/{id}/friends/common/{otherId}") + public Collection findAllCommonFriends(@PathVariable int id, @PathVariable int otherId) { + return userService.getCommonFriendList(id, otherId); + } + @PostMapping public User create(@RequestBody User user) { return inMemoryUserStorage.create(user); @@ -37,4 +57,14 @@ public User create(@RequestBody User user) { public User update(@RequestBody User newUser) { return inMemoryUserStorage.update(newUser); } + + @PutMapping("/{id}/friends/{friendId}") + public void addFriend(@PathVariable("id") int userId, @PathVariable int friendId) { + userService.addFriend(userId, friendId); + } + + @DeleteMapping("/{id}/friends/{friendId}") + public void deleteFriend(@PathVariable("id") int userId, @PathVariable int friendId) { + userService.deleteFriend(userId, friendId); + } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/NotFoundException.java b/src/main/java/ru/yandex/practicum/filmorate/exception/NotFoundException.java new file mode 100644 index 0000000..dd8d262 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/exception/NotFoundException.java @@ -0,0 +1,7 @@ +package ru.yandex.practicum.filmorate.exception; + +public class NotFoundException extends RuntimeException { + public NotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java index b9e156e..bae7127 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java @@ -3,9 +3,12 @@ import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.Data; import java.time.LocalDate; +import java.util.HashSet; +import java.util.Set; /** * Film. @@ -13,11 +16,13 @@ @Data public class Film { private Integer id; - @NotBlank private String name; private String description; - @NotNull private LocalDate releaseDate; - @Min(1) private int duration; + public Set likes = new HashSet<>(); + + public int getRating() { + return likes.size(); + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/User.java b/src/main/java/ru/yandex/practicum/filmorate/model/User.java index 0060c62..e06c2d7 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/User.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/User.java @@ -3,6 +3,8 @@ import lombok.Data; import java.time.LocalDate; +import java.util.HashSet; +import java.util.Set; @Data public class User { @@ -11,4 +13,5 @@ public class User { private String login; private String name; private LocalDate birthday; + private Set friends = new HashSet<>(); } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index fa18191..23f5ed5 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -1,14 +1,51 @@ package ru.yandex.practicum.filmorate.service; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.storage.FilmStorage; +import ru.yandex.practicum.filmorate.storage.UserStorage; +import java.util.Collection; +import java.util.Comparator; +import java.util.stream.Collectors; + +@Slf4j @Service public class FilmService { private final FilmStorage filmStorage; + private final UserStorage userStorage; - public FilmService(FilmStorage filmStorage) { + @Autowired + public FilmService(@Qualifier("inMemoryFilmStorage") FilmStorage filmStorage, + @Qualifier("inMemoryUserStorage") UserStorage userStorage) { this.filmStorage = filmStorage; + this.userStorage = userStorage; + } + + public void addLike(int id, int userId) { + log.info("Добавление лайка фильму ID: {} от пользователя ID: {}", id, userId); + Film film = filmStorage.findFilmById(id); + userStorage.findUserById(userId); + film.likes.add(userId); + log.info("Лайк добавлен фильму '{}' от пользователя ID: {}", film.getName(), userId); + } + + public void deleteLike(int id, int userId) { + Film film = filmStorage.findFilmById(id); + userStorage.findUserById(userId); + film.likes.remove(userId); + } + + public Collection getPopular(int count) { + return filmStorage.findAll().stream() + .sorted(comporator) + .limit(count) + .collect(Collectors.toList()); } + + public static final Comparator comporator = Comparator.comparingInt(Film::getRating).reversed(); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java index 8b83717..1cd4430 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -1,14 +1,65 @@ package ru.yandex.practicum.filmorate.service; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.exception.ValidationException; +import ru.yandex.practicum.filmorate.model.User; import ru.yandex.practicum.filmorate.storage.UserStorage; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + @Service public class UserService { private final UserStorage userStorage; - public UserService(UserStorage userStorage) { + public UserService(@Qualifier("inMemoryUserStorage") UserStorage userStorage) { this.userStorage = userStorage; } + + public void addFriend(int userId, int friendId) { + if (userId == friendId) { + throw new ValidationException("Пользователь не может добавить сам себя в друзья"); + } + User user = userStorage.findUserById(userId); + User usersFriend = userStorage.findUserById(friendId); + if (user.getFriends().contains(friendId)) { + throw new ValidationException("Пользователь уже добавлен в друзья"); + } + user.getFriends().add(friendId); + usersFriend.getFriends().add(userId); + } + + public void deleteFriend(int userId, int friendId) { + if (userId == friendId) { + throw new ValidationException("Пользователь не может добавить сам себя в друзья"); + } + User user = userStorage.findUserById(userId); + User usersFriend = userStorage.findUserById(friendId); + user.getFriends().remove(friendId); + usersFriend.getFriends().remove(userId); + } + + public Collection getFriendList(int userId) { + User user = userStorage.findUserById(userId); + List list = new ArrayList<>(); + for (Integer id : user.getFriends()) { + list.add(userStorage.findUserById(id)); + } + return list; + } + + public Collection getCommonFriendList(int id, int otherId) { + User user1 = userStorage.findUserById(id); + User user2= userStorage.findUserById(otherId); + List list = new ArrayList<>(); + for (Integer userid : user1.getFriends()) { + if (user2.getFriends().contains(userid)) { + list.add(userStorage.findUserById(userid)); + } + } + return list; + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java index df2f19d..419bf02 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java @@ -3,6 +3,7 @@ import ru.yandex.practicum.filmorate.model.Film; import java.util.Collection; +import java.util.Optional; public interface FilmStorage { @@ -11,4 +12,6 @@ public interface FilmStorage { Film create(Film film); Film update(Film newFilm); + + Film findFilmById(int id); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java index 384be4b..121fd66 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java @@ -1,18 +1,16 @@ package ru.yandex.practicum.filmorate.storage; -import jakarta.validation.ValidationException; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.exception.ValidationException; +import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.model.Film; import java.time.LocalDate; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; @Slf4j -@Component +@Component("inMemoryFilmStorage") public class InMemoryFilmStorage implements FilmStorage { private final Map films = new HashMap<>(); @@ -40,7 +38,7 @@ public Film update(Film newFilm) { } if (!films.containsKey(newFilm.getId())) { log.warn("Фильм с указанным id не найден"); - throw new ValidationException("Фильм с id = " + newFilm.getId() + " не найден"); + throw new NotFoundException("Фильм с id = " + newFilm.getId() + " не найден"); } validateFilm(newFilm); Film oldFilm = films.get(newFilm.getId()); @@ -52,6 +50,14 @@ public Film update(Film newFilm) { return oldFilm; } + @Override + public Film findFilmById(int id) { + if (!films.containsKey(id)) { + throw new NotFoundException("Фильма с таким id не найдено"); + } + return films.get(id); + } + private int getNextId() { int currentMaxId = films.keySet() .stream() @@ -62,7 +68,7 @@ private int getNextId() { } private void validateFilm(Film film) { - if (film.getDescription().length() > 200) { + if (film.getDescription() != null && film.getDescription().length() > 200) { log.warn("Ошибка лимита"); throw new ValidationException("Описание превышает 200 символов"); } @@ -81,4 +87,4 @@ private void validateFilm(Film film) { throw new ValidationException("Длительность не может быть меньше 1"); } } -} +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java index c07870b..da5bbd9 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java @@ -2,6 +2,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.exception.NotFoundException; import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.User; @@ -11,14 +12,14 @@ import java.util.Map; @Slf4j -@Component +@Component("inMemoryUserStorage") public class InMemoryUserStorage implements UserStorage { private final Map users = new HashMap<>(); @Override public Collection findAll() { - log.info("Список фильмов выведен"); + log.info("Список пользователей выведен"); return users.values(); } @@ -38,7 +39,7 @@ public User update(User newUser) { } if (!users.containsKey(newUser.getId())) { log.warn("Пользователь с указанным id не найден"); - throw new ValidationException("Пользователь с id = " + newUser.getId() + " не найден"); + throw new NotFoundException("Пользователь с id = " + newUser.getId() + " не найден"); } validateUser(newUser); User oldUser = users.get(newUser.getId()); @@ -59,6 +60,13 @@ private int getNextId() { return ++currentMaxId; } + public User findUserById(int userId) { + if (!users.containsKey(userId)) { + throw new NotFoundException("Пользователя с таким id не найдено"); + } + return users.get(userId); + } + private void validateUser(User user) { if (!user.getEmail().contains("@")) { log.warn("Ошибка в формате почты"); diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java index 88ced28..55f87a7 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java @@ -11,4 +11,6 @@ public interface UserStorage { User create(User user); User update(User newUser); + + User findUserById(int id); } diff --git a/src/test/java/ru/yandex/practicum/filmorate/controller/FilmControllerTest.java b/src/test/java/ru/yandex/practicum/filmorate/controller/FilmControllerTest.java index 0d0a70d..7d1840e 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/controller/FilmControllerTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/controller/FilmControllerTest.java @@ -3,6 +3,8 @@ import jakarta.validation.ValidationException; import org.junit.jupiter.api.Test; import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.service.FilmService; +import ru.yandex.practicum.filmorate.storage.FilmStorage; import ru.yandex.practicum.filmorate.storage.InMemoryFilmStorage; import static org.junit.jupiter.api.Assertions.*; @@ -11,7 +13,8 @@ public class FilmControllerTest { InMemoryFilmStorage inMemoryFilmStorage; - FilmController filmController = new FilmController(inMemoryFilmStorage); + FilmService filmService; + FilmController filmController = new FilmController(inMemoryFilmStorage, filmService); @Test void getFilmTest() { diff --git a/src/test/java/ru/yandex/practicum/filmorate/controller/UserControllerTest.java b/src/test/java/ru/yandex/practicum/filmorate/controller/UserControllerTest.java index 224b1fc..1db69f2 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/controller/UserControllerTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/controller/UserControllerTest.java @@ -3,6 +3,7 @@ import org.junit.jupiter.api.Test; import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.User; +import ru.yandex.practicum.filmorate.service.UserService; import ru.yandex.practicum.filmorate.storage.InMemoryUserStorage; import java.time.LocalDate; @@ -12,7 +13,8 @@ public class UserControllerTest { InMemoryUserStorage inMemoryUserStorage; - UserController userController = new UserController(inMemoryUserStorage); + UserService userService; + UserController userController = new UserController(inMemoryUserStorage, userService); @Test void getFilmTest() { From b9a700755c83bdd19eaf60bc1b6c9d31093b9529 Mon Sep 17 00:00:00 2001 From: Denis Panasyuk Date: Tue, 4 Nov 2025 13:21:16 +0300 Subject: [PATCH 3/7] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=BE?= =?UTF-8?q?=D0=BD=D0=B0=D0=BB=20=D1=81=D0=BE=D0=B3=D0=BB=D0=B0=D1=81=D0=BD?= =?UTF-8?q?=D0=BE=20=D0=A2=D0=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 6 ++++++ .../filmorate/FilmorateApplication.java | 2 +- .../filmorate/controller/ErrorHandler.java | 2 +- .../filmorate/controller/FilmController.java | 7 +++++++ .../filmorate/controller/UserController.java | 15 ++++++------- .../exception/NotFoundException.java | 2 +- .../exception/ValidationException.java | 2 +- .../practicum/filmorate/model/Film.java | 8 ++----- .../filmorate/service/FilmService.java | 21 ++++++++++++------- .../filmorate/service/UserService.java | 9 ++++++-- .../filmorate/storage/FilmStorage.java | 2 +- .../storage/InMemoryFilmStorage.java | 3 --- .../storage/InMemoryUserStorage.java | 5 ++--- .../filmorate/storage/UserStorage.java | 2 +- src/main/resources/application.properties | 1 + 15 files changed, 53 insertions(+), 34 deletions(-) diff --git a/pom.xml b/pom.xml index 8439ff4..7cd7b4c 100644 --- a/pom.xml +++ b/pom.xml @@ -43,6 +43,12 @@ org.slf4j slf4j-api + + + org.zalando + logbook-spring-boot-starter + 3.7.2 + diff --git a/src/main/java/ru/yandex/practicum/filmorate/FilmorateApplication.java b/src/main/java/ru/yandex/practicum/filmorate/FilmorateApplication.java index e55e710..8f860a2 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/FilmorateApplication.java +++ b/src/main/java/ru/yandex/practicum/filmorate/FilmorateApplication.java @@ -8,4 +8,4 @@ public class FilmorateApplication { public static void main(String[] args) { SpringApplication.run(FilmorateApplication.class, args); } -} +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ErrorHandler.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ErrorHandler.java index 7a2babd..b4b521c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ErrorHandler.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ErrorHandler.java @@ -22,4 +22,4 @@ public ErrorResponse handleValidationException(final ValidationException e) { public ErrorResponse handleNotFoundException(final NotFoundException e) { return new ErrorResponse(e.getMessage()); } -} +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java index b5fc102..6f50e3c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -25,36 +25,43 @@ public FilmController(FilmStorage inMemoryFilmStorage, FilmService filmService) @GetMapping public Collection findAll() { + log.info("Список фильмов выведен"); return inMemoryFilmStorage.findAll(); } @GetMapping("/{id}") public Film findById(@PathVariable("id") int filmId) { + log.info("Фильм с id: {} выведен", filmId); return inMemoryFilmStorage.findFilmById(filmId); } @GetMapping("/popular") public Collection getPopular(@RequestParam(defaultValue = "10") int count) { + log.info("Список популярных фильмов выведен"); return filmService.getPopular(count); } @PostMapping public Film create(@RequestBody Film film) { + log.info("Фильм: {} добавлен в базу", film); return inMemoryFilmStorage.create(film); } @PutMapping public Film update(@RequestBody Film newFilm) { + log.info("Данные о фильме: {} обновлены", newFilm); return inMemoryFilmStorage.update(newFilm); } @PutMapping("/{id}/like/{userId}") public void addLike(@PathVariable int id, @PathVariable int userId) { + log.info("Фильму с id: {} поставил лайк пользователь с id: {}", id, userId); filmService.addLike(id, userId); } @DeleteMapping("/{id}/like/{userId}") public void deleteLike(@PathVariable int id, @PathVariable int userId) { + log.info("У фильма с id: {} убрал лайк пользователь с id: {}", id, userId); filmService.deleteLike(id, userId); } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java index a439dcd..c134492 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -2,17 +2,11 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; -import ru.yandex.practicum.filmorate.exception.ValidationException; -import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.model.User; import ru.yandex.practicum.filmorate.service.UserService; import ru.yandex.practicum.filmorate.storage.InMemoryUserStorage; -import java.time.LocalDate; import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; @Slf4j @RestController @@ -29,42 +23,49 @@ public UserController(InMemoryUserStorage inMemoryUserStorage, UserService userS @GetMapping public Collection findAll() { - log.info("Список фильмов выведен"); + log.info("Список пользователей выведен"); return inMemoryUserStorage.findAll(); } @GetMapping("/{id}") public User findUserById(@PathVariable("id") int userId) { + log.info("Пользователь с id: {} выведен", userId); return inMemoryUserStorage.findUserById(userId); } @GetMapping("/{id}/friends") public Collection findAllFriends(@PathVariable("id") int userId) { + log.info("Список друзей пользователя с id: {} выведен", userId); return userService.getFriendList(userId); } @GetMapping("/{id}/friends/common/{otherId}") public Collection findAllCommonFriends(@PathVariable int id, @PathVariable int otherId) { + log.info("Список общих друзей пользователей с id: {} и {} выведен", id, otherId); return userService.getCommonFriendList(id, otherId); } @PostMapping public User create(@RequestBody User user) { + log.info("Пользоввтель: {} создан и добавлен", user); return inMemoryUserStorage.create(user); } @PutMapping public User update(@RequestBody User newUser) { + log.info("Данные о пользователе: {} обновлены", newUser); return inMemoryUserStorage.update(newUser); } @PutMapping("/{id}/friends/{friendId}") public void addFriend(@PathVariable("id") int userId, @PathVariable int friendId) { + log.info("Пользователь с id: {} добавил пользователя с id: {} в друзья", userId, friendId); userService.addFriend(userId, friendId); } @DeleteMapping("/{id}/friends/{friendId}") public void deleteFriend(@PathVariable("id") int userId, @PathVariable int friendId) { + log.info("Пользователь с id: {} удалил пользователя с id: {} из друзей", userId, friendId); userService.deleteFriend(userId, friendId); } } \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/NotFoundException.java b/src/main/java/ru/yandex/practicum/filmorate/exception/NotFoundException.java index dd8d262..82e3f72 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/exception/NotFoundException.java +++ b/src/main/java/ru/yandex/practicum/filmorate/exception/NotFoundException.java @@ -4,4 +4,4 @@ public class NotFoundException extends RuntimeException { public NotFoundException(String message) { super(message); } -} +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/ValidationException.java b/src/main/java/ru/yandex/practicum/filmorate/exception/ValidationException.java index 52dc49c..532f9bd 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/exception/ValidationException.java +++ b/src/main/java/ru/yandex/practicum/filmorate/exception/ValidationException.java @@ -4,4 +4,4 @@ public class ValidationException extends RuntimeException { public ValidationException(String message) { super(message); } -} +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java index bae7127..6fbe6f5 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java @@ -1,9 +1,5 @@ package ru.yandex.practicum.filmorate.model; -import jakarta.validation.constraints.Min; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; import lombok.Data; import java.time.LocalDate; @@ -20,9 +16,9 @@ public class Film { private String description; private LocalDate releaseDate; private int duration; - public Set likes = new HashSet<>(); + private Set likes = new HashSet<>(); public int getRating() { return likes.size(); } -} +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index 23f5ed5..4ea7853 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -4,6 +4,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.Film; import ru.yandex.practicum.filmorate.storage.FilmStorage; import ru.yandex.practicum.filmorate.storage.UserStorage; @@ -27,25 +28,31 @@ public FilmService(@Qualifier("inMemoryFilmStorage") FilmStorage filmStorage, } public void addLike(int id, int userId) { - log.info("Добавление лайка фильму ID: {} от пользователя ID: {}", id, userId); Film film = filmStorage.findFilmById(id); userStorage.findUserById(userId); - film.likes.add(userId); - log.info("Лайк добавлен фильму '{}' от пользователя ID: {}", film.getName(), userId); + if (film.getLikes().contains(userId)) { + log.warn("Ошибка добавления лайка"); + throw new ValidationException("Лайк от этого пользователя уже стоит"); + } + film.getLikes().add(userId); } public void deleteLike(int id, int userId) { Film film = filmStorage.findFilmById(id); userStorage.findUserById(userId); - film.likes.remove(userId); + if (!film.getLikes().contains(userId)) { + log.warn("Ошибка удаления лайка"); + throw new ValidationException("У фильма нет лайка от этого пользователя"); + } + film.getLikes().remove(userId); } public Collection getPopular(int count) { return filmStorage.findAll().stream() - .sorted(comporator) + .sorted(comparator) .limit(count) .collect(Collectors.toList()); } - public static final Comparator comporator = Comparator.comparingInt(Film::getRating).reversed(); -} + public static final Comparator comparator = Comparator.comparingInt(Film::getRating).reversed(); +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java index 1cd4430..d45051d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -1,5 +1,6 @@ package ru.yandex.practicum.filmorate.service; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import ru.yandex.practicum.filmorate.exception.ValidationException; @@ -10,6 +11,7 @@ import java.util.Collection; import java.util.List; +@Slf4j @Service public class UserService { @@ -21,11 +23,13 @@ public UserService(@Qualifier("inMemoryUserStorage") UserStorage userStorage) { public void addFriend(int userId, int friendId) { if (userId == friendId) { + log.warn("Ошибка добавления в друзья"); throw new ValidationException("Пользователь не может добавить сам себя в друзья"); } User user = userStorage.findUserById(userId); User usersFriend = userStorage.findUserById(friendId); if (user.getFriends().contains(friendId)) { + log.warn("Ошибка добавления в друзья"); throw new ValidationException("Пользователь уже добавлен в друзья"); } user.getFriends().add(friendId); @@ -34,7 +38,8 @@ public void addFriend(int userId, int friendId) { public void deleteFriend(int userId, int friendId) { if (userId == friendId) { - throw new ValidationException("Пользователь не может добавить сам себя в друзья"); + log.warn("Ошибка удаления из друзей"); + throw new ValidationException("Пользователь не может удалить сам себя"); } User user = userStorage.findUserById(userId); User usersFriend = userStorage.findUserById(friendId); @@ -62,4 +67,4 @@ public Collection getCommonFriendList(int id, int otherId) { } return list; } -} +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java index 419bf02..01562e2 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java @@ -14,4 +14,4 @@ public interface FilmStorage { Film update(Film newFilm); Film findFilmById(int id); -} +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java index 121fd66..b6b340a 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java @@ -17,7 +17,6 @@ public class InMemoryFilmStorage implements FilmStorage { @Override public Collection findAll() { - log.info("Список фильмов выведен"); return films.values(); } @@ -26,7 +25,6 @@ public Film create(Film film) { validateFilm(film); film.setId(getNextId()); films.put(film.getId(), film); - log.info("Фильм: {} добавлен в базу", film); return film; } @@ -46,7 +44,6 @@ public Film update(Film newFilm) { oldFilm.setDuration(newFilm.getDuration()); oldFilm.setName(newFilm.getName()); oldFilm.setReleaseDate(newFilm.getReleaseDate()); - log.info("Данные о фильме: {} обновлены", oldFilm); return oldFilm; } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java index da5bbd9..d9468af 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java @@ -19,7 +19,6 @@ public class InMemoryUserStorage implements UserStorage { @Override public Collection findAll() { - log.info("Список пользователей выведен"); return users.values(); } @@ -47,7 +46,6 @@ public User update(User newUser) { oldUser.setName(newUser.getName()); oldUser.setLogin(newUser.getLogin()); oldUser.setBirthday(newUser.getBirthday()); - log.info("Данные о пользователе: {} обновлены", oldUser); return oldUser; } @@ -62,6 +60,7 @@ private int getNextId() { public User findUserById(int userId) { if (!users.containsKey(userId)) { + log.warn("Пользователь не найден"); throw new NotFoundException("Пользователя с таким id не найдено"); } return users.get(userId); @@ -85,4 +84,4 @@ private void validateUser(User user) { user.setName(user.getLogin()); } } -} +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java index 55f87a7..04935d0 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java @@ -13,4 +13,4 @@ public interface UserStorage { User update(User newUser); User findUserById(int id); -} +} \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 4c00e40..4a23bbc 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,2 @@ server.port=8080 +logging.level.org.zalando.logbook=TRACE \ No newline at end of file From 29b606b683d0132a36637c582bbe2bd8fb0025ef Mon Sep 17 00:00:00 2001 From: Denis Panasyuk Date: Tue, 4 Nov 2025 13:35:20 +0300 Subject: [PATCH 4/7] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=BE?= =?UTF-8?q?=D0=BD=D0=B0=D0=BB=20=D1=81=D0=BE=D0=B3=D0=BB=D0=B0=D1=81=D0=BD?= =?UTF-8?q?=D0=BE=20=D0=A2=D0=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...Test.java => InMemoryFilmStorageTest.java} | 20 ++++++++----------- ...Test.java => InMemoryUserStorageTest.java} | 17 +++++++--------- 2 files changed, 15 insertions(+), 22 deletions(-) rename src/test/java/ru/yandex/practicum/filmorate/controller/{FilmControllerTest.java => InMemoryFilmStorageTest.java} (53%) rename src/test/java/ru/yandex/practicum/filmorate/controller/{UserControllerTest.java => InMemoryUserStorageTest.java} (62%) diff --git a/src/test/java/ru/yandex/practicum/filmorate/controller/FilmControllerTest.java b/src/test/java/ru/yandex/practicum/filmorate/controller/InMemoryFilmStorageTest.java similarity index 53% rename from src/test/java/ru/yandex/practicum/filmorate/controller/FilmControllerTest.java rename to src/test/java/ru/yandex/practicum/filmorate/controller/InMemoryFilmStorageTest.java index 7d1840e..875d090 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/controller/FilmControllerTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/controller/InMemoryFilmStorageTest.java @@ -1,20 +1,16 @@ package ru.yandex.practicum.filmorate.controller; -import jakarta.validation.ValidationException; import org.junit.jupiter.api.Test; +import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.Film; -import ru.yandex.practicum.filmorate.service.FilmService; -import ru.yandex.practicum.filmorate.storage.FilmStorage; import ru.yandex.practicum.filmorate.storage.InMemoryFilmStorage; import static org.junit.jupiter.api.Assertions.*; import java.time.LocalDate; -public class FilmControllerTest { - InMemoryFilmStorage inMemoryFilmStorage; - FilmService filmService; - FilmController filmController = new FilmController(inMemoryFilmStorage, filmService); +public class InMemoryFilmStorageTest { + InMemoryFilmStorage inMemoryFilmStorage = new InMemoryFilmStorage(); @Test void getFilmTest() { @@ -23,18 +19,18 @@ void getFilmTest() { film.setDuration(100); film.setName("test"); film.setDescription("t"); - filmController.create(film); + inMemoryFilmStorage.create(film); film.setName(" "); - assertThrows(ValidationException.class, () -> filmController.update(film)); + assertThrows(ValidationException.class, () -> inMemoryFilmStorage.update(film)); film.setName("test"); String description200 = "A".repeat(200); film.setDescription(film.getDescription() + description200); - assertThrows(ValidationException.class, () -> filmController.update(film)); + assertThrows(ValidationException.class, () -> inMemoryFilmStorage.update(film)); film.setDescription("t"); film.setReleaseDate(LocalDate.of(1895, 12, 27)); - assertThrows(ValidationException.class, () -> filmController.update(film)); + assertThrows(ValidationException.class, () -> inMemoryFilmStorage.update(film)); film.setReleaseDate(LocalDate.now()); film.setDuration(0); - assertThrows(ValidationException.class, () -> filmController.update(film)); + assertThrows(ValidationException.class, () -> inMemoryFilmStorage.update(film)); } } \ No newline at end of file diff --git a/src/test/java/ru/yandex/practicum/filmorate/controller/UserControllerTest.java b/src/test/java/ru/yandex/practicum/filmorate/controller/InMemoryUserStorageTest.java similarity index 62% rename from src/test/java/ru/yandex/practicum/filmorate/controller/UserControllerTest.java rename to src/test/java/ru/yandex/practicum/filmorate/controller/InMemoryUserStorageTest.java index 1db69f2..3174a9a 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/controller/UserControllerTest.java +++ b/src/test/java/ru/yandex/practicum/filmorate/controller/InMemoryUserStorageTest.java @@ -3,7 +3,6 @@ import org.junit.jupiter.api.Test; import ru.yandex.practicum.filmorate.exception.ValidationException; import ru.yandex.practicum.filmorate.model.User; -import ru.yandex.practicum.filmorate.service.UserService; import ru.yandex.practicum.filmorate.storage.InMemoryUserStorage; import java.time.LocalDate; @@ -11,10 +10,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -public class UserControllerTest { - InMemoryUserStorage inMemoryUserStorage; - UserService userService; - UserController userController = new UserController(inMemoryUserStorage, userService); +public class InMemoryUserStorageTest { + InMemoryUserStorage inMemoryUserStorage = new InMemoryUserStorage(); @Test void getFilmTest() { @@ -23,17 +20,17 @@ void getFilmTest() { user.setLogin("test2"); user.setBirthday(LocalDate.of(2000, 12, 27)); user.setEmail("test@"); - userController.create(user); + inMemoryUserStorage.create(user); user.setEmail(" "); - assertThrows(ValidationException.class, () -> userController.update(user)); + assertThrows(ValidationException.class, () -> inMemoryUserStorage.update(user)); user.setEmail("test2@"); user.setLogin("TEST ETS"); - assertThrows(ValidationException.class, () -> userController.update(user)); + assertThrows(ValidationException.class, () -> inMemoryUserStorage.update(user)); user.setLogin("test2"); user.setName(" "); - userController.update(user); + inMemoryUserStorage.update(user); assertEquals(user.getLogin(), user.getName(), "Имя совпадает с логином"); user.setBirthday(LocalDate.of(2200, 12, 27)); - assertThrows(ValidationException.class, () -> userController.update(user)); + assertThrows(ValidationException.class, () -> inMemoryUserStorage.update(user)); } } \ No newline at end of file From ece15f161b9425da7f0a636d6dceb143a16ac7f6 Mon Sep 17 00:00:00 2001 From: Denis Panasyuk Date: Tue, 4 Nov 2025 13:46:34 +0300 Subject: [PATCH 5/7] =?UTF-8?q?=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20check=20style?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ru/yandex/practicum/filmorate/service/UserService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java index d45051d..e03525e 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -58,7 +58,7 @@ public Collection getFriendList(int userId) { public Collection getCommonFriendList(int id, int otherId) { User user1 = userStorage.findUserById(id); - User user2= userStorage.findUserById(otherId); + User user2 = userStorage.findUserById(otherId); List list = new ArrayList<>(); for (Integer userid : user1.getFriends()) { if (user2.getFriends().contains(userid)) { From 41df520058b44e33a740e7b0bb3cd20c10fffe81 Mon Sep 17 00:00:00 2001 From: Denis Panasyuk Date: Tue, 4 Nov 2025 13:48:07 +0300 Subject: [PATCH 6/7] =?UTF-8?q?=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20check=20style?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ru/yandex/practicum/filmorate/storage/FilmStorage.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java index 01562e2..0b380f8 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java @@ -3,7 +3,6 @@ import ru.yandex.practicum.filmorate.model.Film; import java.util.Collection; -import java.util.Optional; public interface FilmStorage { From db63eedd85afb441951b9677a5b6e2fdf31d6610 Mon Sep 17 00:00:00 2001 From: Denis Panasyuk Date: Tue, 4 Nov 2025 17:41:16 +0300 Subject: [PATCH 7/7] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B8=20=D0=B2?= =?UTF-8?q?=D1=81=D0=B5=D1=85=20=D0=BE=D1=81=D1=82=D0=B0=D0=B2=D1=88=D0=B8?= =?UTF-8?q?=D1=85=D1=81=D1=8F=20=D0=B8=D1=81=D0=BA=D0=BB=D1=8E=D1=87=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yandex/practicum/filmorate/controller/ErrorHandler.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ErrorHandler.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ErrorHandler.java index b4b521c..aaf6f71 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/ErrorHandler.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ErrorHandler.java @@ -22,4 +22,10 @@ public ErrorResponse handleValidationException(final ValidationException e) { public ErrorResponse handleNotFoundException(final NotFoundException e) { return new ErrorResponse(e.getMessage()); } + + @ExceptionHandler + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public ErrorResponse handleAllOtherExceptions(Throwable e) { + return new ErrorResponse(e.getMessage()); + } } \ No newline at end of file