diff --git a/pom.xml b/pom.xml
index 4eed7f0..33ec9a6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -55,6 +55,11 @@
org.springframework.boot
spring-boot-starter-validation
+
+ org.zalando
+ logbook-spring-boot-starter
+ 3.7.2
+
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 f16ce6b..14b89ce 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java
@@ -1,78 +1,66 @@
package ru.yandex.practicum.filmorate.controller;
-import org.springframework.http.HttpStatus;
-import ru.yandex.practicum.filmorate.exceptions.UserNotFoundException;
-import ru.yandex.practicum.filmorate.exceptions.ValidationException;
-
+import jakarta.validation.Valid;
+import lombok.RequiredArgsConstructor;
+import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
import ru.yandex.practicum.filmorate.model.Film;
-import org.slf4j.Logger;
-
-import jakarta.validation.Valid;
+import ru.yandex.practicum.filmorate.service.FilmService;
-import java.util.ArrayList;
import java.util.List;
-import java.util.HashMap;
-import java.util.Map;
-import java.time.LocalDate;
@RestController
@RequestMapping("/films")
+@RequiredArgsConstructor
public class FilmController {
-
- private final Map films = new HashMap<>();
- private final LocalDate dayOfCreationCinema = LocalDate.of(1895, 12, 28);
+ private final FilmService filmService;
private static final Logger log = LoggerFactory.getLogger(FilmController.class);
- private Long getNextId() {
- long currentMaxId = films.keySet()
- .stream()
- .mapToLong(id -> id)
- .max()
- .orElse(0);
- return ++currentMaxId;
- }
-
@GetMapping
public List findAll() {
- return new ArrayList<>(films.values());
+ return filmService.getAllFilms();
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Film createFilm(@Valid @RequestBody Film film) {
log.debug("Получен фильм для добавления: {}", film);
- film.setId(getNextId());
-
- films.put(film.getId(), film);
- log.info("Фильм {} успешно добавлен", film);
-
- return film;
+ return filmService.addFilm(film);
}
@PutMapping
- @ResponseStatus(HttpStatus.OK)
public Film updateFilm(@Valid @RequestBody Film film) {
- if (film.getId() == null) {
- log.error("Не введен Id фильма");
- throw new ValidationException("id фильма не может быть пустым");
- }
- if (films.containsKey(film.getId())) {
- Film oldFilm = films.get(film.getId());
+ return filmService.updateFilm(film);
+ }
+
+ @PutMapping("/{id}/like/{userId}")
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ public void addLike(@PathVariable Long id, @PathVariable Long userId) {
+ filmService.addLike(userId, id);
+ log.info("Добавлен лайк пользователем с id: {} к фильму с id: {}", userId, id);
+ }
- oldFilm.setName(film.getName());
- log.info("Название фильма {} изменено", oldFilm);
- oldFilm.setDescription(film.getDescription());
- log.info("Описание фильма {} изменено", oldFilm);
- oldFilm.setReleaseDate(film.getReleaseDate());
- log.info("Дата выхода фильма {} изменена", oldFilm);
- oldFilm.setDuration(film.getDuration());
- log.info("Длительность фильма {} изменена", oldFilm);
+ @DeleteMapping("/{id}/like/{userId}")
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ public void deleteLike(@PathVariable Long id, @PathVariable Long userId) {
+ filmService.deleteLike(userId, id);
+ log.info("Удален лайк пользователем с id: {} к фильму с id: {}", userId, id);
+ }
- return oldFilm;
- }
- log.error("Фильм с id = {} не найден", film.getId());
- throw new UserNotFoundException("Фильм с id = " + film.getId() + " не найден");
+ @GetMapping("/popular")
+ public List getPopularFilms(@RequestParam(required = false, defaultValue = "10") Integer count) {
+ log.info("Получен список популярных фильмов");
+ return filmService.getPopularFilms(count);
}
}
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 e4c632a..df77734 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java
@@ -1,95 +1,66 @@
package ru.yandex.practicum.filmorate.controller;
-import org.springframework.http.HttpStatus;
-import ru.yandex.practicum.filmorate.exceptions.UserNotFoundException;
-import ru.yandex.practicum.filmorate.exceptions.ValidationException;
-import org.slf4j.LoggerFactory;
+import jakarta.validation.Valid;
+import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
-import org.springframework.web.bind.annotation.*;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
import ru.yandex.practicum.filmorate.model.User;
+import ru.yandex.practicum.filmorate.service.UserService;
-import jakarta.validation.Valid;
-
-import java.util.*;
+import java.util.List;
@RestController
@RequestMapping("/users")
+@RequiredArgsConstructor
public class UserController {
- private final Map users = new HashMap<>();
- private final Set emails = new HashSet<>();
- private final Set logins = new HashSet<>();
+ private final UserService userService;
private static final Logger log = LoggerFactory.getLogger(UserController.class);
- private Long getNextId() {
- long currentMaxId = users.keySet()
- .stream()
- .mapToLong(id -> id)
- .max()
- .orElse(0);
- return ++currentMaxId;
- }
-
@GetMapping
public List findAll() {
- return new ArrayList<>(users.values());
+ return userService.getAllUsers();
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public User addUser(@Valid @RequestBody User user) {
- user.setId(getNextId());
-
- if (logins.contains(user.getLogin())) {
- log.error("Попытка добавить пользователя с существующим логином: {}", user.getLogin());
- throw new ValidationException("Ошибка. Попытка добавить логин, который уже существует");
- }
-
- if (emails.contains(user.getEmail())) {
- log.error("Попытка добавить пользователя с существующим email: {}", user.getEmail());
- throw new ValidationException("Ошибка. Email уже существует");
- }
-
- users.put(user.getId(), user);
- emails.add(user.getEmail());
- logins.add(user.getLogin());
- log.info("Пользователь добавлен");
- return user;
+ return userService.addUser(user);
}
@PutMapping
- public User updateUser(@Valid @RequestBody User newUser) {
- if (newUser.getId() == null) {
- log.error("Не введен id пользователя при изменении");
- throw new ValidationException("id пользователя должен быть указан");
- }
-
- if (users.containsKey(newUser.getId())) {
- User oldUser = users.get(newUser.getId());
-
- // Удаляем старый адрес электронной почты и логин из наборов
- emails.remove(oldUser.getEmail());
- logins.remove(oldUser.getLogin());
+ public User updateUser(@Valid @RequestBody User user) {
+ return userService.updateUser(user);
+ }
- // Проверяем, не конфликтуют ли новые адрес электронной почты и логин
- if (emails.contains(newUser.getEmail())) {
- throw new ValidationException("Email уже существует");
- }
- if (logins.contains(newUser.getLogin())) {
- throw new ValidationException("Логин уже существует");
- }
+ @PutMapping("/{id}/friends/{friendId}")
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ public void addFriend(@PathVariable Long id, @PathVariable Long friendId) {
+ userService.addFriend(id, friendId);
+ }
- oldUser.setEmail(newUser.getEmail());
- oldUser.setLogin(newUser.getLogin());
- oldUser.setName(newUser.getName());
- oldUser.setBirthday(newUser.getBirthday());
+ @DeleteMapping("/{id}/friends/{friendId}")
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ public void deleteFriend(@PathVariable Long id, @PathVariable Long friendId) {
+ userService.deleteFriend(id, friendId);
+ }
- // Добавляем новый Email и Логин
- emails.add(newUser.getEmail());
- logins.add(newUser.getLogin());
+ @GetMapping("/{id}/friends")
+ public List getFriends(@PathVariable Long id) {
+ return userService.allIdFriends(id);
+ }
- return oldUser;
- }
- log.error("Пользователь с id {} не найден", newUser.getId());
- throw new UserNotFoundException("Пользователь с id =" + newUser.getId() + " не найден");
+ @GetMapping("/{id}/friends/common/{otherId}")
+ public List getCommonFriends(@PathVariable Long id, @PathVariable Long otherId) {
+ return userService.generalFriends(id, otherId);
}
}
\ 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 211690c..28969cd 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java
@@ -1,27 +1,32 @@
package ru.yandex.practicum.filmorate.model;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.PositiveOrZero;
+import jakarta.validation.constraints.Size;
import lombok.Data;
-import jakarta.validation.constraints.*;
import ru.yandex.practicum.filmorate.validation.ReleaseDateValidation;
import java.time.LocalDate;
+import java.util.HashSet;
+import java.util.Set;
@Data
public class Film {
private Long id;
- @NotBlank(message = "Название фильма не может быть пустым")
+ @NotBlank
private String name;
- @NotBlank(message = "Описание фильма не может быть пустым")
- @Size(max = 200, message = "Максимальная длина описания — 200 символов")
+ @NotBlank
+ @Size(max = 200)
private String description;
- @NotNull(message = "Дата выхода не может быть пустой")
- @ReleaseDateValidation // Кастомная аннотация валидации
+ @NotNull
+ @ReleaseDateValidation(message = "Release date cannot be earlier than December 28, 1895")
private LocalDate releaseDate;
- @NotNull(message = "Длительность не может быть пустой")
@PositiveOrZero(message = "Длительность фильма должна быть больше или равна нулю")
private Integer duration;
+ private Set idUserLikes = new HashSet<>();
}
\ No newline at end of file
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 04fcecb..d9de9e2 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/model/User.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/model/User.java
@@ -1,36 +1,37 @@
package ru.yandex.practicum.filmorate.model;
-import jakarta.validation.constraints.*;
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.PastOrPresent;
+import jakarta.validation.constraints.Pattern;
import lombok.Data;
import java.time.LocalDate;
+import java.util.HashSet;
+import java.util.Set;
@Data
public class User {
private Long id;
- @NotBlank(message = "Email не может быть пустым")
- @Email(message = "Email должен соответствовать формату")
+ @NotBlank
+ @Email
private String email;
- @NotBlank(message = "Login не может быть пустым")
- @Pattern(regexp = "^[^\\s]+$", message = "Login не должен содержать пробелы")
+ @NotBlank
+ @Pattern(regexp = "^\\S+$")
private String login;
private String name;
- @NotNull(message = "Дата рождения не может быть пустой")
- @PastOrPresent(message = "Дата рождения не может быть в будущем")
+ @NotNull
+ @PastOrPresent
private LocalDate birthday;
- public User() {
- }
+ private Set friends = new HashSet<>();
- public void setLogin(String login) {
- this.login = login;
- // Устанавливаем name, если он не задан
- if (this.name == null || this.name.isBlank()) {
- this.name = login; // Или любое другое значение по умолчанию
- }
+ public void setName(String name) {
+ this.name = (name == null || name.isBlank()) ? this.login : name;
}
}
\ 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..cf8362f
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java
@@ -0,0 +1,74 @@
+package ru.yandex.practicum.filmorate.service;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import ru.yandex.practicum.filmorate.exceptions.UserNotFoundException;
+import ru.yandex.practicum.filmorate.model.Film;
+import ru.yandex.practicum.filmorate.model.User;
+import ru.yandex.practicum.filmorate.storage.FilmStorage;
+import ru.yandex.practicum.filmorate.storage.UserStorage;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class FilmService {
+
+ private final FilmStorage filmStorage;
+ private final UserStorage userStorage;
+
+ public List getAllFilms() {
+ return filmStorage.getAllFilms();
+ }
+
+ public Film addFilm(Film postFilm) {
+ return filmStorage.addFilm(postFilm);
+ }
+
+ public Film updateFilm(Film film) {
+ filmStorage.getFilm(film.getId()); // проверяем наличие фильма
+ return filmStorage.updateFilm(film);
+ }
+
+ private void validateFilmAndUser(Long filmId, Long userId) {
+ Film film = filmStorage.getFilm(filmId);
+ if (film == null) {
+ log.error("Фильм с id: {} не найден", filmId);
+ throw new UserNotFoundException("Фильм с id: " + filmId + " не найден");
+ }
+
+ User user = userStorage.getUser(userId);
+ if (user == null) {
+ log.error("Пользователь с id: {} не найден", userId);
+ throw new UserNotFoundException("Пользователь с id: " + userId + " не найден");
+ }
+ }
+
+ public void addLike(Long userId, Long id) {
+ validateFilmAndUser(id, userId);
+ Film film = filmStorage.getFilm(id);
+ film.getIdUserLikes().add(userId);
+ filmStorage.updateFilm(film);
+ log.info("Пользователь с id: {} добавил лайк фильму {}", userId, id);
+ }
+
+ public void deleteLike(Long userId, Long id) {
+ validateFilmAndUser(id, userId);
+ Film film = filmStorage.getFilm(id);
+ film.getIdUserLikes().remove(userId);
+ filmStorage.updateFilm(film);
+ log.info("Пользователь c id: {} удалил лайк у фильма id: {}", userId, id);
+ }
+
+ public List getPopularFilms(int count) {
+ List films = new ArrayList<>(filmStorage.getAllFilms());
+ films.sort((film, filmToCompare) -> Integer.compare(
+ filmToCompare.getIdUserLikes().size(),
+ film.getIdUserLikes().size()
+ ));
+ return films.subList(0, Math.min(count, films.size()));
+ }
+}
\ 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
new file mode 100644
index 0000000..07d9887
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java
@@ -0,0 +1,108 @@
+package ru.yandex.practicum.filmorate.service;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import ru.yandex.practicum.filmorate.exceptions.UserNotFoundException;
+import ru.yandex.practicum.filmorate.exceptions.ValidationException;
+import ru.yandex.practicum.filmorate.model.User;
+import ru.yandex.practicum.filmorate.storage.UserStorage;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class UserService {
+
+ private final UserStorage userStorage;
+
+ public List getAllUsers() {
+ return userStorage.getAllUsers();
+ }
+
+ public User addUser(User postUser) {
+ return userStorage.addUser(postUser);
+ }
+
+ public User updateUser(User user) {
+ userStorage.getUser(user.getId());
+ return userStorage.updateUser(user);
+ }
+
+ public void addFriend(Long id, Long friendId) {
+ if (id.equals(friendId)) {
+ log.error("Id пользователя и id друга совпадают");
+ throw new ValidationException("Id пользователя и id друга совпадают");
+ }
+ User user = userStorage.getUser(id);
+ if (user == null) {
+ log.error("Пользователь с id {} не найден", id);
+ throw new UserNotFoundException("Пользователь с id " + id + " не найден");
+ }
+
+ User friend = userStorage.getUser(friendId);
+ if (friend == null) {
+ log.error("Пользователь с id {} не найден", friendId);
+ throw new UserNotFoundException("Пользователь с id " + friendId + " не найден");
+ }
+
+ user.getFriends().add(friendId);
+ friend.getFriends().add(id);
+
+ userStorage.updateUser(user);
+ userStorage.updateUser(friend);
+ log.info("Друг добавлен с id: " + friendId);
+ }
+
+ public void deleteFriend(Long id, Long friendId) {
+ User user = userStorage.getUser(id);
+ User friend = userStorage.getUser(friendId);
+
+ if (user == null || friend == null) {
+ throw new UserNotFoundException("Пользователь не найден");
+ }
+
+ user.getFriends().remove(friendId);
+ friend.getFriends().remove(id);
+
+ userStorage.updateUser(user);
+ userStorage.updateUser(friend);
+ log.info("Друг удален с id: " + friendId);
+ }
+
+ public List allIdFriends(Long id) {
+ User user = userStorage.getUser(id);
+ if (user == null) {
+ log.error("Пользователь с id {} не найден", id);
+ throw new UserNotFoundException("Пользователь с id " + id + " не найден");
+ }
+
+ return user.getFriends().stream()
+ .map(userStorage::getUser)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
+
+
+ public List generalFriends(Long id, Long otherId) {
+ User user = userStorage.getUser(id);
+ User otherUser = userStorage.getUser(otherId);
+
+ if (user == null || otherUser == null) {
+ throw new UserNotFoundException("Пользователь не найден");
+ }
+
+ Set commonFriendIds = new HashSet<>(user.getFriends());
+ commonFriendIds.retainAll(otherUser.getFriends());
+
+ return commonFriendIds.stream()
+ .map(userStorage::getUser)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
+}
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..c2c122d
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java
@@ -0,0 +1,15 @@
+package ru.yandex.practicum.filmorate.storage;
+
+import ru.yandex.practicum.filmorate.model.Film;
+
+import java.util.List;
+
+public interface FilmStorage {
+ List getAllFilms();
+
+ Film addFilm(Film postFilm);
+
+ Film updateFilm(Film putFilm);
+
+ Film getFilm(Long 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
new file mode 100644
index 0000000..0a0beb6
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java
@@ -0,0 +1,60 @@
+package ru.yandex.practicum.filmorate.storage;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import ru.yandex.practicum.filmorate.exceptions.UserNotFoundException;
+import ru.yandex.practicum.filmorate.model.Film;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class InMemoryFilmStorage implements FilmStorage {
+
+ private final Map allFilms = new HashMap<>();
+
+ @Override
+ public List getAllFilms() {
+ return new ArrayList<>(allFilms.values());
+ }
+
+ @Override
+ public Film addFilm(Film postFilm) {
+ long id = getNextId();
+ postFilm.setId(id);
+ allFilms.put(postFilm.getId(), postFilm);
+ log.info("Фильм добавлен в коллекцию: " + postFilm);
+ return postFilm;
+ }
+
+ @Override
+ public Film updateFilm(Film putFilm) {
+ allFilms.put(putFilm.getId(), putFilm);
+ log.info("Фильм обновлен в коллекции: " + putFilm);
+ return putFilm;
+ }
+
+ private long getNextId() {
+ long currentMaxId = allFilms.keySet()
+ .stream()
+ .mapToLong(id -> id)
+ .max()
+ .orElse(0);
+ return ++currentMaxId;
+ }
+
+ @Override
+ public Film getFilm(Long id) {
+ Film film = allFilms.get(id);
+ if (film == null) {
+ log.info("Нет фильма с таким id: " + id);
+ throw new UserNotFoundException("Нет фильма с таким id: " + id);
+ }
+ return film;
+ }
+}
\ 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
new file mode 100644
index 0000000..bb46e80
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java
@@ -0,0 +1,57 @@
+package ru.yandex.practicum.filmorate.storage;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import ru.yandex.practicum.filmorate.exceptions.UserNotFoundException;
+import ru.yandex.practicum.filmorate.model.User;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class InMemoryUserStorage implements UserStorage {
+
+ private final Map allUsers = new HashMap<>();
+
+ @Override
+ public List getAllUsers() {
+ return new ArrayList<>(allUsers.values());
+ }
+
+ @Override
+ public User addUser(User postUser) {
+ long id = getNextId();
+ postUser.setId(id);
+ allUsers.put(postUser.getId(), postUser);
+ log.info("Юзер добавлен в коллекцию: " + postUser);
+ return postUser;
+ }
+
+ @Override
+ public User updateUser(User putUser) {
+ allUsers.put(putUser.getId(), putUser);
+ return putUser;
+ }
+
+ @Override
+ public User getUser(long id) {
+ User user = allUsers.get(id);
+ if (user == null) {
+ throw new UserNotFoundException("Пользователь с id " + id + " не найден");
+ }
+ return user;
+ }
+
+ private long getNextId() {
+ long currentMaxId = allUsers.keySet().stream()
+ .mapToLong(id -> id)
+ .max()
+ .orElse(0);
+ return ++currentMaxId;
+ }
+}
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..c05d240
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java
@@ -0,0 +1,15 @@
+package ru.yandex.practicum.filmorate.storage;
+
+import ru.yandex.practicum.filmorate.model.User;
+
+import java.util.List;
+
+public interface UserStorage {
+ List getAllUsers();
+
+ User addUser(User postUser);
+
+ User updateUser(User putUser);
+
+ User getUser(long id);
+}
\ No newline at end of file
diff --git a/src/main/java/ru/yandex/practicum/filmorate/validation/ReleaseDateValidation.java b/src/main/java/ru/yandex/practicum/filmorate/validation/ReleaseDateValidation.java
index 16ed8b0..748e145 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/validation/ReleaseDateValidation.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/validation/ReleaseDateValidation.java
@@ -2,7 +2,12 @@
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
-import java.lang.annotation.*;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 8b13789..d5df4e3 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1 +1 @@
-
+logging.level.org.zalando.logbook:TRACE
\ No newline at end of file
diff --git a/src/test/java/ru/yandex/practicum/filmorate/ValidationTests.java b/src/test/java/ru/yandex/practicum/filmorate/ValidationTests.java
new file mode 100644
index 0000000..96c6d33
--- /dev/null
+++ b/src/test/java/ru/yandex/practicum/filmorate/ValidationTests.java
@@ -0,0 +1,51 @@
+package ru.yandex.practicum.filmorate;
+
+import jakarta.validation.ConstraintViolation;
+import jakarta.validation.Validation;
+import jakarta.validation.Validator;
+import jakarta.validation.ValidatorFactory;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import ru.yandex.practicum.filmorate.model.Film;
+import ru.yandex.practicum.filmorate.model.User;
+
+import java.time.LocalDate;
+import java.util.Set;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+@SpringBootTest
+public class ValidationTests {
+
+ private Validator validator;
+
+ @BeforeEach
+ public void setUp() {
+ ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
+ validator = factory.getValidator();
+ }
+
+ @Test
+ void testFilmValidation() {
+ Film film = new Film();
+ film.setName("");
+ film.setDescription("Test description");
+ film.setReleaseDate(LocalDate.now());
+ film.setDuration(-1);
+
+ Set> violations = validator.validate(film);
+ assertEquals(2, violations.size());
+ }
+
+ @Test
+ void testUserValidation() {
+ User user = new User();
+ user.setEmail("invalid-email");
+ user.setLogin("");
+ user.setBirthday(LocalDate.now().plusDays(1));
+
+ Set> violations = validator.validate(user);
+ assertEquals(4, violations.size());
+ }
+}
diff --git a/src/test/java/ru/yandex/practicum/filmorate/FilmControllerTests.java b/src/test/java/ru/yandex/practicum/filmorate/controller/FilmControllerTests.java
similarity index 95%
rename from src/test/java/ru/yandex/practicum/filmorate/FilmControllerTests.java
rename to src/test/java/ru/yandex/practicum/filmorate/controller/FilmControllerTests.java
index bb85000..96a1350 100644
--- a/src/test/java/ru/yandex/practicum/filmorate/FilmControllerTests.java
+++ b/src/test/java/ru/yandex/practicum/filmorate/controller/FilmControllerTests.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.filmorate;
+package ru.yandex.practicum.filmorate.controller;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validator;
@@ -18,7 +18,10 @@
import java.time.LocalDate;
import java.util.Set;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class FilmControllerTests {
@@ -40,6 +43,7 @@ public class FilmControllerTests {
@BeforeEach
void setUp() {
film = new Film();
+ film.setId(1L); // ID может быть любым
film.setName("film");
film.setDescription(correctDescription);
film.setReleaseDate(LocalDate.of(1985, 12, 28));
diff --git a/src/test/java/ru/yandex/practicum/filmorate/UserControllerTests.java b/src/test/java/ru/yandex/practicum/filmorate/controller/UserControllerTests.java
similarity index 93%
rename from src/test/java/ru/yandex/practicum/filmorate/UserControllerTests.java
rename to src/test/java/ru/yandex/practicum/filmorate/controller/UserControllerTests.java
index 845c748..cbbb174 100644
--- a/src/test/java/ru/yandex/practicum/filmorate/UserControllerTests.java
+++ b/src/test/java/ru/yandex/practicum/filmorate/controller/UserControllerTests.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.filmorate;
+package ru.yandex.practicum.filmorate.controller;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validator;
@@ -12,7 +12,8 @@
import java.time.LocalDate;
import java.util.Set;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
@SpringBootTest
public class UserControllerTests {
@@ -25,6 +26,7 @@ public class UserControllerTests {
@BeforeEach
void setUp() {
user = new User();
+ user.setId(1L); // ID может быть любым
user.setName("name");
user.setEmail("user@mail.ru");
user.setLogin("login");
diff --git a/src/test/java/ru/yandex/practicum/filmorate/service/ServiceTests.java b/src/test/java/ru/yandex/practicum/filmorate/service/ServiceTests.java
new file mode 100644
index 0000000..f5a80ac
--- /dev/null
+++ b/src/test/java/ru/yandex/practicum/filmorate/service/ServiceTests.java
@@ -0,0 +1,138 @@
+package ru.yandex.practicum.filmorate.service;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import ru.yandex.practicum.filmorate.model.Film;
+import ru.yandex.practicum.filmorate.model.User;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@SpringBootTest
+public class ServiceTests {
+ @Autowired
+ private UserService userService;
+ @Autowired
+ private FilmService filmService;
+
+ @Nested
+ class FriendshipTests {
+ @Test
+ // Тесты для работы с друзьями
+ void testFriendshipOperations() {
+ User user1 = new User();
+ user1.setEmail("user1@mail.com");
+ user1.setLogin("user1");
+ user1.setName("User 1");
+ user1.setBirthday(LocalDate.of(1990, 1, 1));
+
+ User user2 = new User();
+ user2.setEmail("user2@mail.com");
+ user2.setLogin("user2");
+ user2.setName("User 2");
+ user2.setBirthday(LocalDate.of(1990, 1, 2));
+
+ user1 = userService.addUser(user1);
+ user2 = userService.addUser(user2);
+
+ userService.addFriend(user1.getId(), user2.getId());
+ assertTrue(userService.allIdFriends(user1.getId()).contains(user2));
+
+ userService.deleteFriend(user1.getId(), user2.getId());
+ assertFalse(userService.allIdFriends(user1.getId()).contains(user2));
+ }
+
+ @Test
+ // Тесты для работы с общими друзьями
+ void testCommonFriends() {
+ User user1 = new User();
+ user1.setEmail("user1@mail.com");
+ user1.setLogin("user1");
+ user1.setName("User 1");
+ user1.setBirthday(LocalDate.of(1990, 1, 1));
+
+ User user2 = new User();
+ user2.setEmail("user2@mail.com");
+ user2.setLogin("user2");
+ user2.setName("User 2");
+ user2.setBirthday(LocalDate.of(1990, 1, 2));
+
+ User user3 = new User();
+ user3.setEmail("user3@mail.com");
+ user3.setLogin("user3");
+ user3.setName("User 3");
+ user3.setBirthday(LocalDate.of(1990, 1, 3));
+
+ user1 = userService.addUser(user1);
+ user2 = userService.addUser(user2);
+ user3 = userService.addUser(user3);
+
+ userService.addFriend(user1.getId(), user3.getId());
+ userService.addFriend(user2.getId(), user3.getId());
+
+ Collection commonFriends = userService.generalFriends(user1.getId(), user2.getId());
+ assertTrue(commonFriends.contains(user3));
+ }
+ }
+
+ @Nested
+ class FilmLikesTests {
+ private Film film;
+ private User user;
+
+ @BeforeEach
+ void setUp() {
+ film = new Film();
+ film.setName("Test Film");
+ film.setDescription("Test Description");
+ film.setReleaseDate(LocalDate.of(2000, 1, 1));
+ film.setDuration(120);
+
+ user = new User();
+ user.setEmail("user@mail.com");
+ user.setLogin("user");
+ user.setName("User");
+ user.setBirthday(LocalDate.of(1990, 1, 1));
+
+ film = filmService.addFilm(film);
+ user = userService.addUser(user);
+ }
+
+ @Test
+ // Тесты для работы с лайками
+ void testLikeOperations() {
+ filmService.addLike(user.getId(), film.getId());
+ assertTrue(film.getIdUserLikes().contains(user.getId()));
+
+ filmService.deleteLike(user.getId(), film.getId());
+ assertFalse(film.getIdUserLikes().contains(user.getId()));
+ }
+
+ @Test
+ // Тесты для работы с популярными фильмами
+ void testPopularFilms() {
+ Film film2 = new Film();
+ film2.setName("Film 2");
+ film2.setDescription("Description 2");
+ film2.setReleaseDate(LocalDate.of(2000, 1, 2));
+ film2.setDuration(120);
+ film2 = filmService.addFilm(film2);
+
+ filmService.addLike(user.getId(), film.getId());
+
+ List popularFilms = new ArrayList<>(filmService.getPopularFilms(10));
+ assertEquals(film.getId(), popularFilms.get(0).getId());
+ }
+ }
+}
+
+