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()); + } + } +} + +