diff --git a/HELP.md b/HELP.md index 0ca1809..ac035f8 100644 --- a/HELP.md +++ b/HELP.md @@ -1,17 +1,12 @@ -# Read Me First -The following was discovered as part of building this project: - -* The JVM level was changed from '11' to '17', review the [JDK Version Range](https://github.com/spring-projects/spring-framework/wiki/Spring-Framework-Versions#jdk-version-range) on the wiki for more details. - # Getting Started ### Reference Documentation For further reference, please consider the following sections: * [Official Apache Maven documentation](https://maven.apache.org/guides/index.html) -* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/3.1.3/maven-plugin/reference/html/) -* [Create an OCI image](https://docs.spring.io/spring-boot/docs/3.1.3/maven-plugin/reference/html/#build-image) -* [Spring Web](https://docs.spring.io/spring-boot/docs/3.1.3/reference/htmlsingle/index.html#web) +* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.7.13/maven-plugin/reference/html/) +* [Create an OCI image](https://docs.spring.io/spring-boot/docs/2.7.13/maven-plugin/reference/html/#build-image) +* [Spring Web](https://docs.spring.io/spring-boot/docs/2.7.13/reference/htmlsingle/#web) ### Guides The following guides illustrate how to use some features concretely: diff --git a/README.md b/README.md index 2cf454a..43c373b 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,53 @@ # java-filmorate Template repository for Filmorate project. + +![Sheme data base for filmorate](db_filmorate.jpg) + +В таблице User храняться все пльзователи приложения +В таблице Friends храняться все дружественные связи со статусом их подтвреждения + +В таблице Film храняться все фильмы +В талице MPA храняться все рейтинги фильмов, а в Film добавляется только индекс нужного рейтинга +сделано так что бы убрать избыточность +В таблице genre храняться все жанры и так как связь к фильма многие ко многим выделена таблица для связи genre_film +В таблице likes храняться все id пользователе которым понравился фильма + +Запросы + +1.Для получения таблицы всей информации обо всех пользователях +SLECT * +FROM user; + +2.Для получения таблицы всех пользователей и их друзей +SELECT u.name, +f.isApproved, +u2.name +FROM user u +JOIN friend f ON f.id_user1 = u.id; +JOIN user u2 ON u2.id = f.id_user2 + +2.Для получения таблицы конкретного пользователя и его друзей +SELECT u.name, +f.isApproved, +u2.name +FROM user u +JOIN friend f ON f.id_user1 = u.id; +JOIN user u2 ON u2.id = f.id_user2 +WHERE u.id = {id} + +3.Для полученя таблицы всех фильмов и информации о них +SELECT * +FROM film + +4.Для получения таблицы всех пользователе кому понравился конкретный фильма +SELECT likes.id_user +FROM film f +JOIN likes_film likes ON likes.id_film = f.id +WHERE f.id = {id} + +5.Для получения таблицы всех жанров конкретного фильма +SELECT g.name +FROM film f +JOIN genre_film gf ON gf.id_film = film.id +JOIN genre g ON g.id = gf.id_genre +WHERE f.id = {id} \ No newline at end of file diff --git a/db_filmorate.jpg b/db_filmorate.jpg new file mode 100644 index 0000000..2913656 Binary files /dev/null and b/db_filmorate.jpg differ diff --git a/pom.xml b/pom.xml index b576ebc..0da5ac4 100644 --- a/pom.xml +++ b/pom.xml @@ -5,40 +5,58 @@ org.springframework.boot spring-boot-starter-parent - 2.7.15 + 2.7.13 - ru.yandex.practicum.com.example + ru.yandex.practicum filmorate 0.0.1-SNAPSHOT + jar filmorate Demo project for Spring Boot 11 + + org.projectlombok + lombok + 1.18.28 + provided + + org.springframework.boot - spring-boot-starter-web + spring-boot-starter-data-jdbc org.springframework.boot - spring-boot-starter-test - test + spring-boot-starter-data-jpa + - org.projectlombok - lombok - 1.18.20 - compile + com.h2database + h2 + runtime + - junit - junit - test - - + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-validation + + + + org.springframework.boot + spring-boot-starter-test + test + + diff --git a/src/main/java/ru/yandex/practicum/filmorate/FilmorateApplication.java b/src/main/java/ru/yandex/practicum/filmorate/FilmorateApplication.java index 3c12a84..0625195 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/FilmorateApplication.java +++ b/src/main/java/ru/yandex/practicum/filmorate/FilmorateApplication.java @@ -1,9 +1,11 @@ package ru.yandex.practicum.filmorate; import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication +@AutoConfiguration public class FilmorateApplication { public static void main(String[] args) { diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/Controller.java b/src/main/java/ru/yandex/practicum/filmorate/controller/Controller.java new file mode 100644 index 0000000..d80f457 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/Controller.java @@ -0,0 +1,39 @@ +package ru.yandex.practicum.filmorate.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.exception.ValidateException; +import ru.yandex.practicum.filmorate.model.Model; +import ru.yandex.practicum.filmorate.service.Service; + +import java.util.List; + +@RequiredArgsConstructor +public abstract class Controller { + + protected final Service service; + + + public T add(T model) throws ValidateException { + + return service.addModel(model); + } + + + public T update(T model) throws NotFoundException { + service.updateModel(model); + return model; + } + + @GetMapping + public List getModelList() { + return service.getModelList(); + } + + public T get(int id) throws NotFoundException { + T model = service.getModelById(id); + + return model; + } +} 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 294b2fc..1169ed7 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -1,31 +1,36 @@ package ru.yandex.practicum.filmorate.controller; - +import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; -import ru.yandex.practicum.filmorate.manager.FilmManager; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.exception.ValidateException; import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.service.Service; +import javax.validation.Valid; -import java.util.List; +@Slf4j +@RequestMapping("/films") +public class FilmController extends Controller { -@RestController -@RequestMapping ("/films") -public class FilmController { - FilmManager filmManager = new FilmManager(); - @GetMapping - private List getFilm() { - return filmManager.getFilmsList(); + public FilmController(Service service) { + super(service); + } + + @PostMapping + public Film add(@RequestBody @Valid Film model) throws ValidateException { + return super.add(model); } @PutMapping - private Film update(@RequestBody Film film) { - return filmManager.updateFilm(film); + public Film update(@RequestBody @Valid Film model) throws NotFoundException { + return super.update(model); } - @PostMapping - private Film add(@RequestBody Film film) { - return filmManager.addFilm(film); + @GetMapping("/{id}") + public Film get(@PathVariable int id) throws NotFoundException { + return super.get(id); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmLikeController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmLikeController.java new file mode 100644 index 0000000..fe782fe --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmLikeController.java @@ -0,0 +1,38 @@ +package ru.yandex.practicum.filmorate.controller; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.web.bind.annotation.*; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.model.FilmLikes; +import ru.yandex.practicum.filmorate.service.ManageLikeFilmService; +import ru.yandex.practicum.filmorate.service.ServiceFilm; + +import java.util.List; + +@RestController +public class FilmLikeController extends FilmController { + protected static final String USE_SERVICE = "ManageLikeFilmService"; + private final ManageLikeFilmService manageLikeFilmService; + + public FilmLikeController(@Qualifier(USE_SERVICE) ServiceFilm filmService) { + super(filmService); + manageLikeFilmService = (ManageLikeFilmService) filmService; + } + + @PutMapping("/{id}/like/{userId}") + public void setLike(@PathVariable int id, @PathVariable int userId) { + manageLikeFilmService.addLike(new FilmLikes(id, userId)); + } + + @DeleteMapping("/{id}/like/{userId}") + public void deleteLike(@PathVariable int id, @PathVariable int userId) throws NotFoundException { + manageLikeFilmService.deleteLike(new FilmLikes(id, userId)); + } + + @GetMapping("/popular") + public List getFilmsPopular(@RequestParam(defaultValue = "10") int count) { + + return manageLikeFilmService.getFilmsPopular(count); + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/GenresController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/GenresController.java new file mode 100644 index 0000000..878dfc3 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/GenresController.java @@ -0,0 +1,30 @@ +package ru.yandex.practicum.filmorate.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.Genre; +import ru.yandex.practicum.filmorate.service.ServiceFilm; + +import java.util.List; + +@RestController +@RequestMapping("/genres") +@RequiredArgsConstructor +public class GenresController { + private final ServiceFilm filmService; + + @GetMapping("/{id}") + public Genre getGenreByID(@PathVariable int id) throws NotFoundException { + return filmService.getGenre(id); + } + + @GetMapping + public List getGenreList() { + return filmService.getGenreList(); + } + +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/MpaController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/MpaController.java new file mode 100644 index 0000000..ba96ad6 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/MpaController.java @@ -0,0 +1,30 @@ +package ru.yandex.practicum.filmorate.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.Mpa; +import ru.yandex.practicum.filmorate.service.ServiceFilm; + +import java.util.List; + +@RestController +@RequestMapping("/mpa") +@RequiredArgsConstructor +public class MpaController { + private final ServiceFilm filmService; + + @GetMapping + public List getMpaList() { + return filmService.getMpaList(); + } + + @GetMapping("/{id}") + public Mpa getMpaById(@PathVariable int id) throws NotFoundException { + return filmService.getMpa(id); + } + +} 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 57f1346..39ee5fb 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -1,30 +1,38 @@ package ru.yandex.practicum.filmorate.controller; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.web.bind.annotation.*; -import ru.yandex.practicum.filmorate.manager.UserManager; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.exception.ValidateException; import ru.yandex.practicum.filmorate.model.User; +import ru.yandex.practicum.filmorate.service.UserService; +import javax.validation.Valid; -import java.util.List; - -@RestController +@Slf4j @RequestMapping("/users") -public class UserController { - UserManager userManager = new UserManager(); +public class UserController extends Controller { + + private static final String SERVICE = "UserService"; + + public UserController(@Qualifier(SERVICE) UserService service) { + super(service); + } - @GetMapping - private List getUser() { - return userManager.getUserList(); + @PostMapping + public User add(@RequestBody @Valid User model) throws ValidateException { + return super.add(model); } @PutMapping - private User update(@RequestBody User user) { - return userManager.updateUser(user); + public User update(@RequestBody @Valid User model) throws NotFoundException { + return super.update(model); } - @PostMapping - private User add(@RequestBody User user) { - return userManager.addUser(user); + @GetMapping("/{id}") + public User get(@PathVariable int id) throws NotFoundException { + return super.get(id); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/UserLikeController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/UserLikeController.java new file mode 100644 index 0000000..adec0f5 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserLikeController.java @@ -0,0 +1,44 @@ +package ru.yandex.practicum.filmorate.controller; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.web.bind.annotation.*; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.FriendsTo; +import ru.yandex.practicum.filmorate.model.User; +import ru.yandex.practicum.filmorate.service.ManageFriendsUserService; +import ru.yandex.practicum.filmorate.service.UserService; + +import java.util.List; + +@RestController +public class UserLikeController extends UserController { + + private static final String SERVICE = "ManageFriendsUserService"; + private final ManageFriendsUserService manageFriendsUserService; + + public UserLikeController(@Qualifier(SERVICE) UserService filmService) { + super(filmService); + manageFriendsUserService = (ManageFriendsUserService) filmService; + } + + @PutMapping("/{idUser}/friends/{idFriend}") + public void addToFriends(@PathVariable int idUser, @PathVariable int idFriend) throws NotFoundException { + manageFriendsUserService.addToFriends(new FriendsTo(idUser, idFriend)); + } + + @DeleteMapping("/{idUser}/friends/{idFriend}") + public void deleteFromFriends(@PathVariable int idUser, @PathVariable int idFriend) { + manageFriendsUserService.removeFriends(new FriendsTo(idUser, idFriend)); + } + + @GetMapping("/{idUser}/friends") + public List getFriend(@PathVariable Integer idUser) throws NotFoundException { + return manageFriendsUserService.getFriends(idUser); + } + + @GetMapping("/{idUser}/friends/common/{idFriend}") + public List getCommonFriend(@PathVariable int idUser, @PathVariable int idFriend) throws NotFoundException { + return manageFriendsUserService.getCommonFriends(new FriendsTo(idUser, idFriend)); + } + +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/ControllerException.java b/src/main/java/ru/yandex/practicum/filmorate/exception/ControllerException.java new file mode 100644 index 0000000..14de323 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/exception/ControllerException.java @@ -0,0 +1,28 @@ +package ru.yandex.practicum.filmorate.exception; + +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.model.ExceptionEntity; + +@RestControllerAdvice +public class ControllerException { + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ExceptionEntity handlerValidateException(final ValidateException validateException) { + return new ExceptionEntity("validateException", validateException.getMessage()); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.NOT_FOUND) + public ExceptionEntity handlerNotFoundException(final NotFoundException notFoundException) { + return new ExceptionEntity("not found exception", notFoundException.getMessage()); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public ExceptionEntity handlerException(final Exception exception) { + return new ExceptionEntity("exception", exception.getMessage()); + } +} 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..df92130 --- /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 Exception { + public NotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/ValidateException.java b/src/main/java/ru/yandex/practicum/filmorate/exception/ValidateException.java new file mode 100644 index 0000000..4d0b7f3 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/exception/ValidateException.java @@ -0,0 +1,7 @@ +package ru.yandex.practicum.filmorate.exception; + +public class ValidateException extends Exception { + public ValidateException(String message) { + super(message); + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/ValidationException.java b/src/main/java/ru/yandex/practicum/filmorate/exception/ValidationException.java deleted file mode 100644 index 52dc49c..0000000 --- a/src/main/java/ru/yandex/practicum/filmorate/exception/ValidationException.java +++ /dev/null @@ -1,7 +0,0 @@ -package ru.yandex.practicum.filmorate.exception; - -public class ValidationException extends RuntimeException { - public ValidationException(String message) { - super(message); - } -} diff --git a/src/main/java/ru/yandex/practicum/filmorate/manager/FilmManager.java b/src/main/java/ru/yandex/practicum/filmorate/manager/FilmManager.java deleted file mode 100644 index 8875ba2..0000000 --- a/src/main/java/ru/yandex/practicum/filmorate/manager/FilmManager.java +++ /dev/null @@ -1,50 +0,0 @@ -package ru.yandex.practicum.filmorate.manager; - -import lombok.Data; -import lombok.extern.slf4j.Slf4j; - - -import ru.yandex.practicum.filmorate.exception.ValidationException; -import ru.yandex.practicum.filmorate.model.Film; - - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - - -@Slf4j -@Data -public class FilmManager { - private HashMap allFilms = new HashMap<>(); - private int filmId; - - - public Film addFilm(Film film) { - ValidationManager.allFilmExceptions(film.getName(), film.getDescription(), film.getReleaseDate(), film.getDuration()); - createId(film); - allFilms.put(filmId, film); - log.info("Фильм создан", film.getName(), film.getId()); - return film; - } - - public void createId(Film film) { - film.setId(++filmId); - } - - public Film updateFilm(Film film) throws ValidationException { - if (allFilms.containsKey(film.getId())) { - ValidationManager.allFilmExceptions(film.getName(), film.getDescription(), film.getReleaseDate(), film.getDuration()); - allFilms.put(film.getId(), film); - return film; - } else { - throw new ValidationException("Фильма с таким айди нет"); - } - } - - public List getFilmsList() { - List list = new ArrayList<>(allFilms.values()); - return list; - } - -} diff --git a/src/main/java/ru/yandex/practicum/filmorate/manager/UserManager.java b/src/main/java/ru/yandex/practicum/filmorate/manager/UserManager.java deleted file mode 100644 index f5ee8fb..0000000 --- a/src/main/java/ru/yandex/practicum/filmorate/manager/UserManager.java +++ /dev/null @@ -1,51 +0,0 @@ -package ru.yandex.practicum.filmorate.manager; - -import lombok.Data; -import lombok.extern.slf4j.Slf4j; - - -import ru.yandex.practicum.filmorate.exception.ValidationException; -import ru.yandex.practicum.filmorate.model.User; - - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -@Slf4j -@Data -public class UserManager { - private HashMap allUsers = new HashMap<>(); - private int userId; - - - public User addUser(User user) { - if (user.getName() == null || user.getName().isEmpty()) { - user.setName(user.getLogin()); - } - ValidationManager.allUserExceptions(user.getEmail(), user.getLogin(), user.getName(), user); - createId(user); - allUsers.put(userId, user); - log.info("Пользователь создан", user.getName(), user.getId()); - return user; - } - - public void createId(User user) { - user.setId(++userId); - } - - public User updateUser(User user) throws ValidationException { - if (allUsers.containsKey(user.getId())) { - ValidationManager.allUserExceptions(user.getEmail(), user.getLogin(), user.getName(), user); - allUsers.put(user.getId(), user); - return user; - } else { - throw new ValidationException("Пользователя с таким айди нет"); - } - } - - public List getUserList() { - List list = new ArrayList<>(allUsers.values()); - return list; - } -} diff --git a/src/main/java/ru/yandex/practicum/filmorate/manager/ValidationManager.java b/src/main/java/ru/yandex/practicum/filmorate/manager/ValidationManager.java deleted file mode 100644 index 0bae36e..0000000 --- a/src/main/java/ru/yandex/practicum/filmorate/manager/ValidationManager.java +++ /dev/null @@ -1,45 +0,0 @@ -package ru.yandex.practicum.filmorate.manager; - -import ru.yandex.practicum.filmorate.exception.ValidationException; -import ru.yandex.practicum.filmorate.model.User; - -import java.time.LocalDate; - -public class ValidationManager { - - public static void allFilmExceptions(String name, String description, LocalDate date, double time) throws ValidationException { - if (name == null || name.isBlank()) { - throw new ValidationException("Поле name не должно быть пустым"); - } - - if (description.length() > 200 || description.length() == 0) { - throw new ValidationException("Максимальная длина должна быть не больше 200 символов"); - } - - if (date == null || date.isBefore(LocalDate.of(1895, 12, 28))) { - throw new ValidationException("Некорректная дата"); - } - - if (time <= 0) { - throw new ValidationException("Неверная длительность фильма"); - } - } - - public static void allUserExceptions(String email, String login, String name, User user) throws ValidationException { - if (email == null || email.isBlank() || !email.contains("@")) { - throw new ValidationException("Email не должен быть пустым и должен содержать @"); - } - - if (login.isBlank() || login.isEmpty()) { - throw new ValidationException("Логин не может быть пустым и содержать пробелы"); - } - - if (name == null || name.isEmpty()) { - throw new ValidationException("Вместо имени будет использован логин"); - } - - if (user.getBirthday().isAfter(LocalDate.now()) || user.getBirthday() == null) { - throw new ValidationException("Некорректная дата рождения" + user.getId() + "'"); - } - } -} diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/ExceptionEntity.java b/src/main/java/ru/yandex/practicum/filmorate/model/ExceptionEntity.java new file mode 100644 index 0000000..65da990 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/ExceptionEntity.java @@ -0,0 +1,14 @@ +package ru.yandex.practicum.filmorate.model; + +import lombok.AllArgsConstructor; +import lombok.Data; + + +@Data +@AllArgsConstructor +public class ExceptionEntity { + private String error; + private String 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 10c2bd7..515c284 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java @@ -1,19 +1,22 @@ package ru.yandex.practicum.filmorate.model; - -import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import javax.validation.constraints.Positive; import java.time.LocalDate; +import java.util.TreeSet; @Data -@AllArgsConstructor -public class Film { +@Builder +public class Film extends Model { private int id; private String name; private String description; private LocalDate releaseDate; - private double duration; - - + @Positive + private int duration; + private Mpa mpa; + private TreeSet genres = new TreeSet<>(); + private TreeSet likes = new TreeSet<>(); } diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/FilmLikes.java b/src/main/java/ru/yandex/practicum/filmorate/model/FilmLikes.java new file mode 100644 index 0000000..9a46b72 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/FilmLikes.java @@ -0,0 +1,9 @@ +package ru.yandex.practicum.filmorate.model; + + +public class FilmLikes extends FromTo { + + public FilmLikes(Integer filmId, Integer userId) { + super(filmId, userId); + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/FriendsTo.java b/src/main/java/ru/yandex/practicum/filmorate/model/FriendsTo.java new file mode 100644 index 0000000..5d560c4 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/FriendsTo.java @@ -0,0 +1,7 @@ +package ru.yandex.practicum.filmorate.model; + +public class FriendsTo extends FromTo { + public FriendsTo(int idUser, int idFriend) { + super(idUser, idFriend); + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/FromTo.java b/src/main/java/ru/yandex/practicum/filmorate/model/FromTo.java new file mode 100644 index 0000000..204282f --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/FromTo.java @@ -0,0 +1,12 @@ +package ru.yandex.practicum.filmorate.model; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public abstract class FromTo { + protected Integer from; + protected Integer to; + +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Genre.java b/src/main/java/ru/yandex/practicum/filmorate/model/Genre.java new file mode 100644 index 0000000..78d8e62 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Genre.java @@ -0,0 +1,14 @@ +package ru.yandex.practicum.filmorate.model; + + +public class Genre extends Model implements Comparable { + public Genre(int id, String name) { + this.setId(id); + this.setName(name); + } + + @Override + public int compareTo(Genre o) { + return this.getId() - o.id; + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Model.java b/src/main/java/ru/yandex/practicum/filmorate/model/Model.java new file mode 100644 index 0000000..53a595c --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Model.java @@ -0,0 +1,9 @@ +package ru.yandex.practicum.filmorate.model; + +import lombok.Data; + +@Data +public abstract class Model { + protected int id; + protected String name; +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Mpa.java b/src/main/java/ru/yandex/practicum/filmorate/model/Mpa.java new file mode 100644 index 0000000..d294de2 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Mpa.java @@ -0,0 +1,12 @@ +package ru.yandex.practicum.filmorate.model; + +public class Mpa extends Model { + public Mpa(int id, String name) { + setId(id); + setName(name); + } + + public Mpa(int id) { + setId(id); + } +} 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 c73ccdc..8c7a324 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/User.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/User.java @@ -1,17 +1,32 @@ package ru.yandex.practicum.filmorate.model; - import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; import java.time.LocalDate; +import java.util.List; @Data +@Builder @AllArgsConstructor -public class User { +public class User extends Model { private int id; + private String name; + @Email + @NotBlank + @NotNull + @NotEmpty private String email; + @NotNull + @NotBlank + @NotEmpty private String login; - private String name; private LocalDate birthday; + private List friends; + } 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..694ca68 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -0,0 +1,54 @@ +package ru.yandex.practicum.filmorate.service; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.exception.ValidateException; +import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.storage.StorageFilm; + +import java.time.LocalDate; +import java.util.Objects; +import java.util.TreeSet; + +@Service +public class FilmService extends ServiceFilm { + + // protected static final String FILM_STORAGE = "inMemoryFilmStorage"; + protected static final String FILM_STORAGE = "FilmDBStorage"; + protected static final String FILM_NAME_BLANK_EXCEPTION = "Не заполнено название фильма"; + protected static final String FILM_DESCRIPTION_EXCEPTION = "Длинна описания привышает 200 символов"; + protected static final String FILM_DATE_PRODUCE_EXCEPTION = "Дата выпуска не может быть раньше появления самого кино"; + protected static final String FILM_DURATION_EXCEPTION = "Продолжительность не может быть меньше или ровна 0"; + + + public FilmService(@Qualifier(FILM_STORAGE) StorageFilm storage) { + super(storage); + } + + protected void validate(Film film) throws ValidateException { + if (Objects.isNull(film.getGenres())) { + film.setGenres(new TreeSet<>()); + } + + if (Objects.isNull(film.getLikes())) { + film.setLikes(new TreeSet<>()); + } + + if (Objects.isNull(film.getName()) || film.getName().isBlank() || film.getName().isEmpty()) { + throw new ValidateException(FILM_NAME_BLANK_EXCEPTION); + } + + if (film.getDescription().length() > 200) { + throw new ValidateException(FILM_DESCRIPTION_EXCEPTION); + } + final String dateStartFilmEpoch = "1895-12-28"; + if (film.getReleaseDate().isBefore(LocalDate.parse(dateStartFilmEpoch))) { + throw new ValidateException(FILM_DATE_PRODUCE_EXCEPTION); + } + + if (film.getDuration() <= 0) { + throw new ValidateException(FILM_DURATION_EXCEPTION); + } + } + +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ManageFriendsUserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ManageFriendsUserService.java new file mode 100644 index 0000000..6e5fe77 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ManageFriendsUserService.java @@ -0,0 +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.NotFoundException; +import ru.yandex.practicum.filmorate.model.FriendsTo; +import ru.yandex.practicum.filmorate.model.Model; +import ru.yandex.practicum.filmorate.model.User; +import ru.yandex.practicum.filmorate.storage.StorageUser; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + + +@Service("ManageFriendsUserService") +public class ManageFriendsUserService extends UserService { + protected static final String NEGATIVE_ID_EXCEPTION = "Id пользователя не может быть меньше нуля"; + + public ManageFriendsUserService(@Qualifier(UserService.USER_STORAGE) StorageUser storage) { + super(storage); + } + + public void addToFriends(FriendsTo users) throws NotFoundException { + if (users.getFrom() < 1 || users.getTo() < 1) { + throw new NotFoundException(NEGATIVE_ID_EXCEPTION); + } + storage.addToSet(users); + } + + public void removeFriends(FriendsTo user) { + storage.removeIdFromIdSet(user); + } + + public List getCommonFriends(FriendsTo user) throws NotFoundException { + User user1 = super.getModelById(user.getFrom()); + User user2 = super.getModelById(user.getTo()); + List idFriends = user1.getFriends().stream().filter(e -> user2.getFriends().stream() + .anyMatch(e1 -> Objects.equals(e, e1))).collect(Collectors.toList()); + + return idFriends.stream().map(e -> { + Model model; + try { + model = getModelById(e); + } catch (NotFoundException exception) { + return null; + } + return model; + }) + .collect(Collectors.toList()).stream().map(e -> (User) e) + .collect(Collectors.toList()); + } + + public List getFriends(int id) throws NotFoundException { + User user = super.getModelById(id); + List userList = new ArrayList<>(); + + for (int idUser : user.getFriends()) { + userList.add(super.getModelById(idUser)); + } + + return userList; + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ManageLikeFilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/ManageLikeFilmService.java new file mode 100644 index 0000000..6490d93 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ManageLikeFilmService.java @@ -0,0 +1,62 @@ +package ru.yandex.practicum.filmorate.service; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.model.FilmLikes; +import ru.yandex.practicum.filmorate.storage.StorageFilm; +import ru.yandex.practicum.filmorate.storage.StorageUser; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +@Service("ManageLikeFilmService") +public class ManageLikeFilmService extends FilmService { + private final StorageUser storageUser; + + public ManageLikeFilmService(@Qualifier(FilmService.FILM_STORAGE) StorageFilm storage, + @Qualifier(UserService.USER_STORAGE) StorageUser storageUser) { + super(storage); + this.storageUser = storageUser; + } + + public Film addLike(FilmLikes filmLikes) { + return storage.addToSet(filmLikes); + } + + public Film deleteLike(FilmLikes filmLikes) throws NotFoundException { + validateExistUser(filmLikes.getTo()); + + storage.removeIdFromIdSet(filmLikes); + + Film film = (Film) getModelById(filmLikes.getFrom()); + + return film; + } + + public Set getLikes(Integer idFilm) throws NotFoundException { + Film film = (Film) getModelById(idFilm); + Set likes = film.getLikes(); + + return likes; + } + + public List getFilmsPopular(int count) { + List filmList = super.getModelList(); + + return filmList.stream().sorted((e1, e2) -> e2.getLikes().size() - e1.getLikes().size()) + .limit(count).collect(Collectors.toList()); + } + + private boolean validateExistUser(int userId) throws NotFoundException { + try { + storageUser.isExist(userId); + } catch (EmptyResultDataAccessException e) { + throw new NotFoundException(String.format(UserService.NOT_FOUND_ID_EXCEPTION, userId)); + } + return true; + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/Service.java b/src/main/java/ru/yandex/practicum/filmorate/service/Service.java new file mode 100644 index 0000000..f81be5f --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/Service.java @@ -0,0 +1,73 @@ +package ru.yandex.practicum.filmorate.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.dao.EmptyResultDataAccessException; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.exception.ValidateException; +import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.model.Model; +import ru.yandex.practicum.filmorate.storage.Storage; + +import java.util.*; + +@Slf4j +@RequiredArgsConstructor +public abstract class Service { + public static String NOT_FOUND_ID_EXCEPTION = "модель с требуемым id = %d не найдена"; + + protected final Storage storage; + + public T addModel(T model) throws ValidateException { + try { + validate(model); + if (model instanceof Film) { + Film film = (Film) model; + if (Objects.isNull(film.getGenres())) { + film.setGenres(new TreeSet<>()); + } + + if (Objects.isNull(film.getLikes())) { + film.setLikes(new TreeSet<>()); + } + } + return (T) storage.save(model); + } catch (ValidateException ex) { + log.warn(ex.getMessage()); + throw new ValidateException(ex.getMessage()); + } + } + + public T updateModel(T model) throws NotFoundException { + try { + if (storage.isExist(model.getId())) { + validate(model); + storage.update(model); + + } + } catch (EmptyResultDataAccessException exception) { + log.warn(String.format(NOT_FOUND_ID_EXCEPTION, model.getId())); + throw new NotFoundException(String.format(NOT_FOUND_ID_EXCEPTION, model.getId())); + } catch (ValidateException e) { + throw new RuntimeException(e); + } + + return model; + } + + public List getModelList() { + return new ArrayList((Collection) storage.getModelMap().values()); + } + + protected abstract void validate(T model) throws ValidateException; + + public T getModelById(int id) throws NotFoundException { + try { + return storage.get(id); + } catch (EmptyResultDataAccessException exception) { + throw new NotFoundException(String.format(NOT_FOUND_ID_EXCEPTION, id)); + } + } + + +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ServiceFilm.java b/src/main/java/ru/yandex/practicum/filmorate/service/ServiceFilm.java new file mode 100644 index 0000000..1782142 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ServiceFilm.java @@ -0,0 +1,44 @@ +package ru.yandex.practicum.filmorate.service; + +import org.springframework.dao.EmptyResultDataAccessException; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.model.Genre; +import ru.yandex.practicum.filmorate.model.Model; +import ru.yandex.practicum.filmorate.model.Mpa; +import ru.yandex.practicum.filmorate.storage.StorageFilm; + +import java.util.List; + +public abstract class ServiceFilm extends Service { + private static StorageFilm storageFilm; + + public ServiceFilm(StorageFilm storage) { + super(storage); + storageFilm = storage; + } + + public T getGenre(int id) throws NotFoundException { + try { + return storageFilm.getGenreById(id); + } catch (EmptyResultDataAccessException e) { + throw new NotFoundException("Genre не найден"); + } + } + + public List getGenreList() { + return (List) storageFilm.getGenreList(); + } + + public T getMpa(int id) throws NotFoundException { + try { + return storageFilm.getMpa(id); + } catch (EmptyResultDataAccessException e) { + throw new NotFoundException("mpa не айден"); + } + } + + public List getMpaList() { + return (List) storageFilm.getMpaList(); + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/ServiceUser.java b/src/main/java/ru/yandex/practicum/filmorate/service/ServiceUser.java new file mode 100644 index 0000000..c8949c2 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/ServiceUser.java @@ -0,0 +1,16 @@ +package ru.yandex.practicum.filmorate.service; + +import lombok.extern.slf4j.Slf4j; +import ru.yandex.practicum.filmorate.model.User; +import ru.yandex.practicum.filmorate.storage.StorageUser; + +@Slf4j +public abstract class ServiceUser extends Service { + + protected ServiceUser(StorageUser storage) { + super(storage); + NOT_FOUND_ID_EXCEPTION = "Пользователь с требуемым id не найден"; + } + + +} 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..7ae6bf0 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -0,0 +1,39 @@ +package ru.yandex.practicum.filmorate.service; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.exception.ValidateException; +import ru.yandex.practicum.filmorate.model.User; +import ru.yandex.practicum.filmorate.storage.StorageUser; + +import java.time.LocalDate; +import java.util.Objects; + +@Service("UserService") +public class UserService extends ServiceUser { + protected static final String USER_STORAGE = "userDBStorage"; + protected static final String USER_LOGIN_EXCEPTION = "Логин пользователя не может содержать пробелы"; + protected static final String USER_BIRTH_DATE_EXCEPTION = "Дата рождения не может быть в будущем"; + + public UserService(@Qualifier(USER_STORAGE) StorageUser storage) { + super(storage); + } + + @Override + protected void validate(User user) throws ValidateException { + + + if (user.getLogin().contains(" ")) { + throw new ValidateException(USER_LOGIN_EXCEPTION); + } + + if (Objects.isNull(user.getName()) || user.getName().isEmpty() || user.getName().isBlank()) { + user.setName(user.getLogin()); + } + + if (user.getBirthday().isAfter(LocalDate.now())) { + throw new ValidateException(USER_BIRTH_DATE_EXCEPTION); + } + + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/FilmDBStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmDBStorage.java new file mode 100644 index 0000000..b460d97 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmDBStorage.java @@ -0,0 +1,234 @@ +package ru.yandex.practicum.filmorate.storage; + +import lombok.AllArgsConstructor; +import org.springframework.jdbc.core.BatchPreparedStatementSetter; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; +import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.model.*; + +import java.sql.Date; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; + +@Repository("FilmDBStorage") +@AllArgsConstructor +public class FilmDBStorage implements StorageFilm { + private JdbcTemplate jdbcTemplate; + + @Override + public boolean isExist(int id) { + return get(id) != null; + } + + @Override + public void update(Model model) { + Film film = (Film) model; + String sql = "UPDATE film SET title = ?, description = ?, release_date = ?, duration = ?, mpa_id = ? WHERE film_id = ?"; + + jdbcTemplate.update(sql, film.getName(), film.getDescription(), film.getReleaseDate(), film.getDuration(), + film.getMpa().getId(), film.getId()); + updateGenres(film); + updateLikes(film); + } + + @Override + public Model save(Model model) { + Film film = (Film) model; + String sql = "INSERT INTO film (title, description, release_date, duration, mpa_id) VALUES (?,?,?,?,?)"; + KeyHolder keyHolder = new GeneratedKeyHolder(); + + + jdbcTemplate.update(connection -> { + PreparedStatement stm = connection.prepareStatement(sql, new String[]{"film_id"}); + stm.setString(1, film.getName()); + stm.setString(2, film.getDescription()); + stm.setDate(3, Date.valueOf(film.getReleaseDate())); + stm.setInt(4, film.getDuration()); + stm.setInt(5, film.getMpa().getId()); + + return stm; + }, keyHolder); + film.setId(keyHolder.getKey().intValue()); + saveGenres(film); + updateLikes(film); + + + return model; + } + + private void saveGenres(Film film) { + + String sqlGenre = "INSERT INTO genre_film (genre_id, film_id) VALUES (?,?)"; + Iterator iterator = film.getGenres().iterator(); + + jdbcTemplate.batchUpdate(sqlGenre, new BatchPreparedStatementSetter() { + @Override + public void setValues(PreparedStatement ps, int i) throws SQLException { + ps.setInt(2, film.getId()); + ps.setInt(1, iterator.next().getId()); + } + + @Override + public int getBatchSize() { + return film.getGenres().size(); + } + }); + } + + private void updateLikes(Film film) { + String sqlDelGenre = "DELETE FROM likes_film WHERE film_id = ?"; + + jdbcTemplate.update(sqlDelGenre, film.getId()); + + String sqlGenre = "INSERT INTO likes_film (user_id, film_id) VALUES (?,?)"; + Iterator iterator = film.getLikes().iterator(); + jdbcTemplate.batchUpdate(sqlGenre, new BatchPreparedStatementSetter() { + @Override + public void setValues(PreparedStatement ps, int i) throws SQLException { + ps.setInt(2, film.getId()); + ps.setInt(1, iterator.next()); + } + + @Override + public int getBatchSize() { + return film.getLikes().size(); + } + }); + } + + private void updateGenres(Film film) { + String sqlDelGenre = "DELETE FROM genre_film WHERE film_id = ?"; + + jdbcTemplate.update(sqlDelGenre, film.getId()); + + String sqlGenre = "INSERT INTO genre_film (genre_id, film_id) VALUES (?,?)"; + Iterator iterator = film.getGenres().iterator(); + + jdbcTemplate.batchUpdate(sqlGenre, new BatchPreparedStatementSetter() { + @Override + public void setValues(PreparedStatement ps, int i) throws SQLException { + ps.setInt(2, film.getId()); + ps.setInt(1, iterator.next().getId()); + } + + @Override + public int getBatchSize() { + return film.getGenres().size(); + } + }); + } + + @Override + public Film get(int id) { + String sqlNew = "SELECT f.film_id, f.title, f.description, f.release_date, f.duration, f.mpa_id, g.genre_id, g.name, lf.user_id\n" + + "FROM genre as g \n" + + "left JOIN genre_film as gf on gf.genre_id = g.genre_id \n" + + "right JOIN film AS f ON f.film_id = gf.film_id \n" + + "left JOIN likes_film AS lf ON lf.film_id = f.film_id \n" + + "WHERE f.film_id = ?"; + Film film = jdbcTemplate.queryForObject(sqlNew, this::mapRowToFilm, id); + + return film; + } + + private Film mapRowToFilm(ResultSet rs, int rowNum) throws SQLException { + TreeSet filmGenre = new TreeSet<>(); + TreeSet likes = new TreeSet<>(); + + Film film = Film.builder().id(rs.getInt("film_id")) + .name(rs.getString("title")) + .description(rs.getString("description")) + .genres(filmGenre) + .duration(rs.getInt("duration")) + .releaseDate(rs.getDate("release_date").toLocalDate()) + .mpa(getMpa(rs.getInt("mpa_id"))) + .likes(likes).build(); + + do { + if (rs.getInt("genre_id") != 0) { + filmGenre.add(new Genre(rs.getInt("genre_id"), rs.getString("name"))); + } + + if (rs.getInt("user_id") != 0) { + likes.add(rs.getInt("user_id")); + } + + } while (rs.next()); + + return film; + } + + + @Override + public void delete(int id) { + String sql = "DELETE FROM film WHERE film_id = ?"; + + jdbcTemplate.update(sql, id); + } + + @Override + public Map getModelMap() { + String sql1 = "SELECT film_id FROM FILM"; + Map filmMap = new HashMap<>(); + List idsList = jdbcTemplate.query(sql1, (rs, nm) -> rs.getInt("film_id")); + + for (int id : idsList) { + filmMap.put(id, get(id)); + } + + return filmMap; + } + + @Override + public void removeIdFromIdSet(FromTo user) { + String sql = "DELETE FROM likes_film WHERE film_id = ? AND user_id = ?"; + + jdbcTemplate.update(sql, user.getFrom(), user.getTo()); + + } + + @Override + public T addToSet(FromTo filmLikes) { + String sql = "INSERT INTO likes_film (film_id, user_id) VALUES (?,?)"; + + jdbcTemplate.update(sql, filmLikes.getFrom(), filmLikes.getTo()); + + return null; + } + + @Override + public Genre getGenreById(int id) { + String sql = "SELECT * FROM genre WHERE genre_id = ?"; + + return jdbcTemplate.queryForObject(sql, + (rs, rowNum) -> new Genre(rs.getInt("genre_id"), rs.getString("name")), id); + } + + @Override + public List getGenreList() { + String sql = "SELECT * FROM genre "; + + return jdbcTemplate.query(sql, + ((rs, rowNum) -> new Genre(rs.getInt("genre_id"), rs.getString("name")))); + } + + @Override + public Mpa getMpa(int id) { + String sql = "SELECT * FROM MPA WHERE mpa_id = ?"; + + return jdbcTemplate.queryForObject(sql, + (rs, rowNum) -> new Mpa(rs.getInt("mpa_id"), rs.getString("name")), id); + } + + @Override + public List getMpaList() { + String sql = "SELECT * FROM MPA"; + + return jdbcTemplate.query(sql, (rs, rowNum) -> new Mpa(rs.getInt("mpa_id"), + rs.getString("name"))); + } +} 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..224f587 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java @@ -0,0 +1,78 @@ +package ru.yandex.practicum.filmorate.storage; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.model.FromTo; +import ru.yandex.practicum.filmorate.model.Model; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Component("inMemoryFilmStorage") +@RequiredArgsConstructor +public class InMemoryFilmStorage implements StorageFilm { + protected final Map filmMap; + private Integer id = 0; + + public boolean isExist(int id) { + return filmMap.containsKey(id); + } + + public void update(Model model) { + filmMap.put(model.getId(), (Film) model); + } + + public Model save(Model model) { + id++; + model.setId(id); + filmMap.put(id, (Film) model); + return model; + } + + public Film get(int id) { + return filmMap.get(id); + } + + public void delete(int id) { + filmMap.remove(id); + } + + public Map getModelMap() { + return filmMap; + } + + public void removeIdFromIdSet(FromTo films) { + } + + @Override + public T getGenreById(int id) { + return null; + } + + @Override + public List getGenreList() { + return null; + } + + @Override + public T getMpa(int id) { + return null; + } + + @Override + public List getMpaList() { + return null; + } + + @Override + public Film addToSet(FromTo filmLikes) { + Film film = filmMap.get(filmLikes.getFrom()); + Set likes = film.getLikes(); + + likes.add(filmLikes.getTo()); + return film; + } + +} 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..93ba3e0 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java @@ -0,0 +1,70 @@ +package ru.yandex.practicum.filmorate.storage; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.model.FromTo; +import ru.yandex.practicum.filmorate.model.Model; +import ru.yandex.practicum.filmorate.model.User; + +import java.util.List; +import java.util.Map; + +@Component("inMemoryUserStorage") +@RequiredArgsConstructor +public class InMemoryUserStorage implements StorageUser { + private final Map userMap; + private Integer id = 0; + + public boolean isExist(int id) { + return userMap.containsKey(id); + } + + public void update(Model model) { + userMap.put(model.getId(), (User) model); + } + + public Model save(Model model) { + id++; + model.setId(id); + userMap.put(id, (User) model); + + return model; + } + + public User get(int id) { + return userMap.get(id); + } + + public void delete(int id) { + userMap.remove(id); + } + + @Override + public Map getModelMap() { + return userMap; + } + + public void removeIdFromIdSet(FromTo user) { + User user1 = userMap.get(user.getFrom()); + User user2 = userMap.get(user.getTo()); + List userFr1 = user1.getFriends(); + List userFr2 = user2.getFriends(); + + userFr1.remove(user2.getId()); + userFr2.remove(user1.getId()); + + } + + public User addToSet(FromTo user) { + User user1 = userMap.get(user.getFrom()); + User user2 = userMap.get(user.getTo()); + List userFr1 = user1.getFriends(); + List userFr2 = user2.getFriends(); + + userFr1.add(user2.getId()); + userFr2.add(user1.getId()); + + return user1; + } + +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/Storage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/Storage.java new file mode 100644 index 0000000..b3c576d --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/Storage.java @@ -0,0 +1,27 @@ +package ru.yandex.practicum.filmorate.storage; + +import ru.yandex.practicum.filmorate.model.FromTo; +import ru.yandex.practicum.filmorate.model.Model; + +import java.util.Map; + +public interface Storage { + + boolean isExist(int id); + + void update(Model model); + + Model save(Model model); + + T get(int id); + + void delete(int id); + + Map getModelMap(); + + void removeIdFromIdSet(FromTo user); + + T addToSet(FromTo filmLikes); + + +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/StorageFilm.java b/src/main/java/ru/yandex/practicum/filmorate/storage/StorageFilm.java new file mode 100644 index 0000000..151d09d --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/StorageFilm.java @@ -0,0 +1,15 @@ +package ru.yandex.practicum.filmorate.storage; + +import ru.yandex.practicum.filmorate.model.Model; + +import java.util.List; + +public interface StorageFilm extends Storage { + T getGenreById(int id); + + List getGenreList(); + + T getMpa(int id); + + List getMpaList(); +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/StorageUser.java b/src/main/java/ru/yandex/practicum/filmorate/storage/StorageUser.java new file mode 100644 index 0000000..0173ece --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/StorageUser.java @@ -0,0 +1,6 @@ +package ru.yandex.practicum.filmorate.storage; + + +public interface StorageUser extends Storage { + +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/UserDBStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/UserDBStorage.java new file mode 100644 index 0000000..7ddc69a --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/UserDBStorage.java @@ -0,0 +1,122 @@ +package ru.yandex.practicum.filmorate.storage; + +import lombok.AllArgsConstructor; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; +import org.springframework.stereotype.Repository; +import ru.yandex.practicum.filmorate.model.FromTo; +import ru.yandex.practicum.filmorate.model.Model; +import ru.yandex.practicum.filmorate.model.User; + +import java.sql.Date; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Repository("userDBStorage") +@AllArgsConstructor +public class UserDBStorage implements StorageUser { + private JdbcTemplate jdbcTemplate; + + @Override + public boolean isExist(int id) { + return get(id) != null; + } + + @Override + public void update(Model model) { + User user = (User) model; + String sql = "UPDATE users SET name = ?, birth_date = ?, email = ?, login = ? WHERE user_id = ?"; + jdbcTemplate.update(sql, user.getName(), user.getBirthday(), user.getEmail(), user.getLogin(), user.getId()); + } + + @Override + public User save(Model model) { + User user = (User) model; + String sql = ("INSERT INTO users (name, birth_date, email, login) VALUES (?,?,?,?)"); + KeyHolder keyHolder = new GeneratedKeyHolder(); + + jdbcTemplate.update(con -> { + PreparedStatement stmt = con.prepareStatement(sql, new String[]{"user_id"}); + stmt.setString(1, user.getName()); + stmt.setDate(2, Date.valueOf(user.getBirthday())); + stmt.setString(3, user.getEmail()); + stmt.setString(4, user.getLogin()); + return stmt; + }, keyHolder); + user.setId(keyHolder.getKey().intValue()); + return user; + } + + @Override + public User get(int id) { + String sqlUserLikes = "SELECT u.user_id, u.name, u.email, u.login, u.birth_date, fr.friend_id\n" + + "FROM users as u\n" + + "LEFT JOIN friend as fr ON fr.user_id = u.user_id\n" + + "WHERE u.user_id = ?\n"; + ; + User user = jdbcTemplate.queryForObject(sqlUserLikes, this::rowMapperUser, id); + + return user; + + } + + private Integer mapRowToInteger(ResultSet rs, int rowNum) throws SQLException { + return rs.getInt("friend_id"); + } + + private User rowMapperUser(ResultSet rs, int idRow) throws SQLException { + List likes = new ArrayList<>(); + User user = User.builder().id(rs.getInt("user_id")) + .name(rs.getString("name")) + .email(rs.getString("email")) + .login(rs.getString("login")) + .birthday(rs.getDate("birth_date").toLocalDate()) + .friends(likes).build(); + do { + if (rs.getInt("friend_id") != 0) { + likes.add(rs.getInt("friend_id")); + } + } while (rs.next()); + return user; + } + + @Override + public void delete(int id) { + String sql = "DELETE FROM users WHERE user_id = ?"; + jdbcTemplate.update(sql, id); + + } + + @Override + public Map getModelMap() { + String sql = "SELECT user_id FROM users"; + Map mapUsers = new HashMap<>(); + List usersIdList = jdbcTemplate.query(sql, (rs, r) -> rs.getInt("user_id")); + + for (int id : usersIdList) { + mapUsers.put(id, get(id)); + } + + return mapUsers; + } + + @Override + public void removeIdFromIdSet(FromTo user) { + String sql = "DELETE FROM friend WHERE user_id = ? AND friend_id = ?"; + jdbcTemplate.update(sql, user.getFrom(), user.getTo()); + } + + @Override + public Model addToSet(FromTo userFriend) { + String sql = "INSERT INTO friend (user_id, friend_id, IS_APPROVED) VALUES (?,?,?);"; + jdbcTemplate.update(sql, userFriend.getFrom(), userFriend.getTo(), true); + return null; + } + +} diff --git a/src/main/java/sprint.json b/src/main/java/sprint.json deleted file mode 100644 index 541e79a..0000000 --- a/src/main/java/sprint.json +++ /dev/null @@ -1,1047 +0,0 @@ -{ - "info": { - "_postman_id": "e337606f-5df6-47d0-9784-7fa89c1b51fe", - "name": "sprint09/controllers-films-users", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "2036415" - }, - "item": [ - { - "name": "users", - "item": [ - { - "name": "User create", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200 or 201\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([200,201]);\r", - "});\r", - "pm.test(\"Has user create response\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});\r", - "pm.test(\"Test user 'id' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('id');\r", - " pm.expect(jsonData.id, '\"id\" must be 1').to.eql(1);\r", - "});\r", - "pm.test(\"Test user 'email' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('email');\r", - " pm.expect(jsonData.email, '\"email\" must be \"mail@mail.ru\"').to.eql('mail@mail.ru');\r", - "});\r", - "pm.test(\"Test user 'name' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('name');\r", - " pm.expect(jsonData.name, '\"name\" must be \"Nick Name\"').to.eql('Nick Name');\r", - "});\r", - "pm.test(\"Test user 'login' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('login');\r", - " pm.expect(jsonData.login, '\"login\" field must be \"dolore\"').to.eql('dolore'); \r", - "});\r", - "pm.test(\"Test user 'birthday' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('birthday');\r", - " pm.expect(jsonData.birthday, '\"birthday\" field must be \"1946-08-20\"').to.eql('1946-08-20');\r", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "*/*" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"login\": \"dolore\",\n \"name\": \"Nick Name\",\n \"email\": \"mail@mail.ru\",\n \"birthday\": \"1946-08-20\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/users", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "users" - ] - } - }, - "response": [] - }, - { - "name": "User create Fail login", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 500 or 400\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([500,400]);\r", - "});\r", - "pm.test(\"Has error response\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});\r", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "*/*" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"login\": \"dolore ullamco\",\n \"email\": \"yandex@mail.ru\",\n \"birthday\": \"2446-08-20\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/users", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "users" - ] - } - }, - "response": [] - }, - { - "name": "User create Fail email", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 500 or 400\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([500,400]);\r", - "});\r", - "pm.test(\"Has error response\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "*/*" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"login\": \"dolore ullamco\",\n \"name\": \"\",\n \"email\": \"mail.ru\",\n \"birthday\": \"1980-08-20\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/users", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "users" - ] - } - }, - "response": [] - }, - { - "name": "User create Fail birthday", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 500 or 400\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([500,400]);\r", - "});\r", - "pm.test(\"Has error response\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "*/*" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"login\": \"dolore\",\n \"name\": \"\",\n \"email\": \"test@mail.ru\",\n \"birthday\": \"2446-08-20\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/users", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "users" - ] - } - }, - "response": [] - }, - { - "name": "User update", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {\r", - " pm.response.to.be.ok;\r", - "});\r", - "pm.test(\"Has user update response\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});\r", - "pm.test(\"Test user 'id' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('id');\r", - " pm.expect(jsonData.id, '\"id\" must be 1').to.eql(1);\r", - "});\r", - "pm.test(\"Test user 'email' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('email');\r", - " pm.expect(jsonData.email, '\"email\" must be \"mail@yandex.ru\"').to.eql('mail@yandex.ru');\r", - "});\r", - "pm.test(\"Test user 'name' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('name');\r", - " pm.expect(jsonData.name, '\"name\" must be \"est adipisicing\"').to.eql('est adipisicing');\r", - "});\r", - "pm.test(\"Test user 'login' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('login');\r", - " pm.expect(jsonData.login, '\"login\" field must be \"doloreUpdate\"').to.eql('doloreUpdate'); \r", - "});\r", - "pm.test(\"Test user 'birthday' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('birthday');\r", - " pm.expect(jsonData.birthday, '\"birthday\" field must be \"1976-09-20\"').to.eql('1976-09-20');\r", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "PUT", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "*/*" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"login\": \"doloreUpdate\",\n \"name\": \"est adipisicing\",\n \"id\": 1,\n \"email\": \"mail@yandex.ru\",\n \"birthday\": \"1976-09-20\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/users", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "users" - ] - } - }, - "response": [] - }, - { - "name": "User update unknown", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 500\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([500, 404]);\r", - "});\r", - "pm.test(\"Has error response\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "PUT", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "*/*" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"login\": \"doloreUpdate\",\n \"name\": \"est adipisicing\",\n \"id\": 9999,\n \"email\": \"mail@yandex.ru\",\n \"birthday\": \"1976-09-20\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/users", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "users" - ] - } - }, - "response": [] - }, - { - "name": "User get All", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {\r", - " pm.response.to.be.ok;\r", - "});\r", - "pm.test(\"Test list user response\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData.length, 'List length must be 1').to.eql(1);\r", - "});\r", - "pm.test(\"Test user[0] 'id' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData[0]).to.have.property('id');\r", - " pm.expect(jsonData[0].id, '\"id\" must be 1').to.eql(1);\r", - "});\r", - "pm.test(\"Test user[0] 'email' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData[0]).to.have.property('email');\r", - " pm.expect(jsonData[0].email, '\"email\" must be \"mail@yandex.ru\"').to.eql('mail@yandex.ru');\r", - "});\r", - "pm.test(\"Test user[0] 'name' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData[0]).to.have.property('name');\r", - " pm.expect(jsonData[0].name, '\"name\" must be \"est adipisicing\"').to.eql('est adipisicing');\r", - "});\r", - "pm.test(\"Test user[0] 'login' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData[0]).to.have.property('login');\r", - " pm.expect(jsonData[0].login, '\"login\" field must be \"doloreUpdate\"').to.eql('doloreUpdate'); \r", - "});\r", - "pm.test(\"Test user[0] 'birthday' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData[0]).to.have.property('birthday');\r", - " pm.expect(jsonData[0].birthday, '\"birthday\" field must be \"1976-09-20\"').to.eql('1976-09-20');\r", - "});\r", - "\r", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "Accept", - "value": "*/*" - } - ], - "url": { - "raw": "{{baseUrl}}/users", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "users" - ] - } - }, - "response": [] - }, - { - "name": "Create user with empty name", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200 or 201\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([200,201]);\r", - "});\r", - "pm.test(\"Has user create response\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});\r", - "pm.test(\"Test user 'id' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('id');\r", - " pm.expect(jsonData.id, '\"id\" must be 2').to.eql(2);\r", - "});\r", - "pm.test(\"Test user 'email' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('email');\r", - " pm.expect(jsonData.email, '\"email\" must be \"friend@common.ru\"').to.eql('friend@common.ru');\r", - "});\r", - "pm.test(\"Test user 'name' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('name');\r", - " pm.expect(jsonData.name, '\"name\" must be \"common\"').to.eql('common');\r", - "});\r", - "pm.test(\"Test user 'login' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('login');\r", - " pm.expect(jsonData.login, '\"login\" field must be \"common\"').to.eql('common'); \r", - "});\r", - "pm.test(\"Test user 'birthday' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('birthday');\r", - " pm.expect(jsonData.birthday, '\"birthday\" field must be \"2000-08-20\"').to.eql('2000-08-20');\r", - "});\r", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "*/*" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"login\": \"common\",\n \"email\": \"friend@common.ru\",\n \"birthday\": \"2000-08-20\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/users", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "users" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "films", - "item": [ - { - "name": "Film create", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200 or 201\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([200,201]);\r", - "});\r", - "pm.test(\"Has film create response\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});\r", - "pm.test(\"Test film 'id' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('id');\r", - " pm.expect(jsonData.id, '\"id\" must be 1').to.eql(1);\r", - "});\r", - "pm.test(\"Test film 'name' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('name');\r", - " pm.expect(jsonData.name, '\"name\" must be \"nisi eiusmod\"').to.eql('nisi eiusmod');\r", - "});\r", - "pm.test(\"Test film 'description' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('description');\r", - " pm.expect(jsonData.description, '\"description\" must be \"adipisicing\"').to.eql('adipisicing');\r", - "});\r", - "pm.test(\"Test film 'releaseDate' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('releaseDate');\r", - " pm.expect(jsonData.releaseDate, '\"releaseDate\" field must be \"1967-03-25\"').to.eql('1967-03-25');\r", - "});\r", - "pm.test(\"Test film 'duration' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('duration');\r", - " pm.expect(jsonData.duration, '\"duration\" field must be 100').to.eql(100); \r", - "});\r", - "\r", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "*/*" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"nisi eiusmod\",\n \"description\": \"adipisicing\",\n \"releaseDate\": \"1967-03-25\",\n \"duration\": 100\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/films", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "films" - ] - } - }, - "response": [] - }, - { - "name": "Film create Fail name", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 500 or 400\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([500,400]);\r", - "});\r", - "pm.test(\"Has error response\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});\r", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "*/*" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"\",\n \"description\": \"Description\",\n \"releaseDate\": \"1900-03-25\",\n \"duration\": 200\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/films", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "films" - ] - } - }, - "response": [] - }, - { - "name": "Film create Fail description", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 500 or 400\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([500,400]);\r", - "});\r", - "pm.test(\"Has error response\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});\r", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "*/*" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"Film name\",\n \"description\": \"Пятеро друзей ( комик-группа «Шарло»), приезжают в город Бризуль. Здесь они хотят разыскать господина Огюста Куглова, который задолжал им деньги, а именно 20 миллионов. о Куглов, который за время «своего отсутствия», стал кандидатом Коломбани.\",\n \"releaseDate\": \"1900-03-25\",\n \"duration\": 200\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/films", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "films" - ] - } - }, - "response": [] - }, - { - "name": "Film create Fail releaseDate", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 500 or 400\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([500,400]);\r", - "});\r", - "pm.test(\"Has error response\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});\r", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "*/*" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"Name\",\n \"description\": \"Description\",\n \"releaseDate\": \"1890-03-25\",\n \"duration\": 200\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/films", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "films" - ] - } - }, - "response": [] - }, - { - "name": "Film create Fail duration", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 500 or 400\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([500,400]);\r", - "});\r", - "pm.test(\"Has error response\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});\r", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "*/*" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"Name\",\n \"description\": \"Descrition\",\n \"releaseDate\": \"1980-03-25\",\n \"duration\": -200\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/films", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "films" - ] - } - }, - "response": [] - }, - { - "name": "Film update", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {\r", - " pm.response.to.be.ok;\r", - "});\r", - "pm.test(\"Has film update response\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});\r", - "\r", - "pm.test(\"Test film 'id' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('id');\r", - " pm.expect(jsonData.id, '\"id\" must be 1').to.eql(1);\r", - "});\r", - "pm.test(\"Test film 'name' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('name');\r", - " pm.expect(jsonData.name, '\"name\" must be \"Film Updated\"').to.eql('Film Updated');\r", - "});\r", - "pm.test(\"Test film 'description' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('description');\r", - " pm.expect(jsonData.description, '\"description\" must be \"New film update decription\"').to.eql('New film update decription');\r", - "});\r", - "pm.test(\"Test film 'releaseDate' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('releaseDate');\r", - " pm.expect(jsonData.releaseDate, '\"releaseDate\" field must be \"1989-04-17\"').to.eql('1989-04-17');\r", - "});\r", - "pm.test(\"Test film 'duration' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData).to.have.property('duration');\r", - " pm.expect(jsonData.duration, '\"duration\" field must be 190').to.eql(190); \r", - "});\r", - "\r", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "PUT", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "*/*" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"id\": 1,\n \"name\": \"Film Updated\",\n \"releaseDate\": \"1989-04-17\",\n \"description\": \"New film update decription\",\n \"duration\": 190,\n \"rate\": 4\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/films", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "films" - ] - } - }, - "response": [] - }, - { - "name": "Film update unknown", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 500\", function () {\r", - " pm.expect(pm.response.code).to.be.oneOf([500, 404]);\r", - "});\r", - "pm.test(\"Has error response\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - "});\r", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "PUT", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "*/*" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"id\": 9999,\n \"name\": \"Film Updated\",\n \"releaseDate\": \"1989-04-17\",\n \"description\": \"New film update decription\",\n \"duration\": 190,\n \"rate\": 4\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/films", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "films" - ] - } - }, - "response": [] - }, - { - "name": "Film get All", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {\r", - " pm.response.to.be.ok;\r", - "});\r", - "pm.test(\"Test list film response\", function () {\r", - " pm.response.to.be.withBody;\r", - " pm.response.to.be.json;\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData.length, 'List length must be 1').to.eql(1);\r", - "});\r", - "pm.test(\"Test film[0] 'id' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData[0]).to.have.property('id');\r", - " pm.expect(jsonData[0].id, '\"id\" must be 1').to.eql(1);\r", - "});\r", - "pm.test(\"Test film[0] 'name' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData[0]).to.have.property('name');\r", - " pm.expect(jsonData[0].name, '\"name\" must be \"Film Updated\"').to.eql('Film Updated');\r", - "});\r", - "pm.test(\"Test film[0] 'description' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData[0]).to.have.property('description');\r", - " pm.expect(jsonData[0].description, '\"description\" must be \"New film update decription\"').to.eql('New film update decription');\r", - "});\r", - "pm.test(\"Test film[0] 'releaseDate' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData[0]).to.have.property('releaseDate');\r", - " pm.expect(jsonData[0].releaseDate, '\"releaseDate\" field must be \"1989-04-17\"').to.eql('1989-04-17');\r", - "});\r", - "pm.test(\"Test film[0] 'duration' field\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData[0]).to.have.property('duration');\r", - " pm.expect(jsonData[0].duration, '\"duration\" field must be 190').to.eql(190); \r", - "});\r", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "Accept", - "value": "*/*" - } - ], - "url": { - "raw": "{{baseUrl}}/films", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "films" - ] - } - }, - "response": [] - } - ] - } - ], - "event": [ - { - "listen": "prerequest", - "script": { - "type": "text/javascript", - "exec": [ - "" - ] - } - }, - { - "listen": "test", - "script": { - "type": "text/javascript", - "exec": [ - "" - ] - } - } - ], - "variable": [ - { - "key": "baseUrl", - "value": "http://localhost:8080", - "type": "string" - } - ] -} \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 8b13789..939a8c1 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,7 @@ - +spring.h2.console.enabled=true +spring.sql.init.mode=always +# ? jdbc-url ???????, ??? ?????? ????? ????????? ? ???? +spring.datasource.url=jdbc:h2:file:./db/filmorate +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password=password \ No newline at end of file diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql new file mode 100644 index 0000000..2634c74 --- /dev/null +++ b/src/main/resources/data.sql @@ -0,0 +1,12 @@ +INSERT INTO genre (name) VALUES ('Комедия'); +INSERT INTO genre (name) VALUES ('Драма'); +INSERT INTO genre (name) VALUES ('Мультфильм'); +INSERT INTO genre (name) VALUES ('Триллер'); +INSERT INTO genre (name) VALUES ('Документальный'); +INSERT INTO genre (name) VALUES ('Боевик'); + +INSERT INTO MPA (NAME) VALUES ('G'); +INSERT INTO MPA (NAME) VALUES ('PG'); +INSERT INTO MPA (NAME) VALUES ('PG-13'); +INSERT INTO MPA (NAME) VALUES ('R'); +INSERT INTO MPA (NAME) VALUES ('NC-17'); \ No newline at end of file diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql new file mode 100644 index 0000000..8bf0ed5 --- /dev/null +++ b/src/main/resources/schema.sql @@ -0,0 +1,43 @@ +create TABLE IF NOT EXISTS users ( + user_id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name VARCHAR(20), + birth_date DATE, + email VARCHAR(40), + login VARCHAR(20) +); + +create TABLE IF NOT EXISTS MPA ( + mpa_id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name varchar +); + +create TABLE IF NOT EXISTS film ( + film_id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + title varchar(100), + description varchar(255), + release_date date, + duration integer, + mpa_id integer REFERENCES MPA (mpa_id) ON delete CASCADE +); + +create TABLE IF NOT EXISTS friend ( + user_id INTEGER REFERENCES USERS (user_id) ON delete CASCADE, + is_approved BIT, + friend_id INTEGER REFERENCES USERS (user_id) ON delete CASCADE +); + +create TABLE IF NOT EXISTS genre ( + genre_id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name VARCHAR(100) +); + +create TABLE IF NOT EXISTS genre_film ( + genre_id INTEGER REFERENCES genre (genre_id) ON delete CASCADE, + film_id INTEGER REFERENCES film (film_id) ON delete CASCADE +); + +create TABLE IF NOT EXISTS likes_film( + film_id INTEGER REFERENCES film(film_id) ON delete CASCADE, + user_id INTEGER REFERENCES users(user_id) ON delete CASCADE +); + diff --git a/src/test/java/ru/yandex/practicum/filmorate/FilmorateApplicationTests.java b/src/test/java/ru/yandex/practicum/filmorate/FilmorateApplicationTests.java index 660412e..9035f0a 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/FilmorateApplicationTests.java +++ b/src/test/java/ru/yandex/practicum/filmorate/FilmorateApplicationTests.java @@ -1,13 +1,20 @@ package ru.yandex.practicum.filmorate; +import lombok.RequiredArgsConstructor; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.context.SpringBootTest; + @SpringBootTest +@AutoConfigureTestDatabase +@RequiredArgsConstructor(onConstructor_ = @Autowired) class FilmorateApplicationTests { + @Test - void contextLoads() { - } + public void test() { + } } diff --git a/src/test/java/ru/yandex/practicum/filmorate/controller/FilmControllerTest.java b/src/test/java/ru/yandex/practicum/filmorate/controller/FilmControllerTest.java new file mode 100644 index 0000000..4b9c88c --- /dev/null +++ b/src/test/java/ru/yandex/practicum/filmorate/controller/FilmControllerTest.java @@ -0,0 +1,42 @@ +package ru.yandex.practicum.filmorate.controller; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.exception.ValidateException; +import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.service.ManageLikeFilmService; +import ru.yandex.practicum.filmorate.storage.InMemoryFilmStorage; +import ru.yandex.practicum.filmorate.storage.InMemoryUserStorage; + +import java.time.LocalDate; +import java.util.HashMap; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class FilmControllerTest { + private FilmController filmController; + + @BeforeEach + void setUp() { + filmController = new FilmController(new ManageLikeFilmService(new InMemoryFilmStorage(new HashMap<>()), + new InMemoryUserStorage(new HashMap<>()))); + } + + @Test + void add() throws ValidateException, NotFoundException { + Film film = Film.builder() + .description("description") + .duration(60) + .releaseDate(LocalDate.of(2022, 02, 23)).build(); + + assertThrows(ValidateException.class, () -> filmController.add(film)); + film.setName("film1"); + Film film1 = filmController.add(film); + assertEquals(1, filmController.getModelList().size()); + film1.setName("FilmVasya"); + filmController.update(film1); + assertEquals("FilmVasya", ((Film) filmController.getModelList().get(0)).getName()); + } +} \ 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/UserControllerTest.java new file mode 100644 index 0000000..1ae22ee --- /dev/null +++ b/src/test/java/ru/yandex/practicum/filmorate/controller/UserControllerTest.java @@ -0,0 +1,37 @@ +package ru.yandex.practicum.filmorate.controller; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.exception.ValidateException; +import ru.yandex.practicum.filmorate.model.User; +import ru.yandex.practicum.filmorate.service.ManageFriendsUserService; +import ru.yandex.practicum.filmorate.storage.InMemoryUserStorage; + +import java.time.LocalDate; +import java.util.HashMap; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class UserControllerTest { + private UserController userController; + + @BeforeEach + void setUp() { + userController = new UserController(new ManageFriendsUserService(new InMemoryUserStorage(new HashMap<>()))); + } + + @Test + void add() throws ValidateException, NotFoundException { + User user = User.builder() + .email("my@email.ru") + .login("login1") + .birthday(LocalDate.of(1994, 6, 12)).build(); + + User user1 = userController.add(user); + assertEquals(1, userController.getModelList().size()); + user1.setName("Vasya"); + userController.update(user1); + assertEquals("Vasya", ((User) userController.getModelList().get(0)).getName()); + } +} \ No newline at end of file diff --git a/src/test/java/ru/yandex/practicum/filmorate/managerTest/FilmManagerTest.java b/src/test/java/ru/yandex/practicum/filmorate/managerTest/FilmManagerTest.java deleted file mode 100644 index b6e8fd6..0000000 --- a/src/test/java/ru/yandex/practicum/filmorate/managerTest/FilmManagerTest.java +++ /dev/null @@ -1,53 +0,0 @@ -package ru.yandex.practicum.filmorate.managerTest; - -import org.junit.Test; -import org.junit.jupiter.api.Assertions; - - -import ru.yandex.practicum.filmorate.manager.FilmManager; -import ru.yandex.practicum.filmorate.model.Film; - -import java.time.LocalDate; -import java.util.ArrayList; -import java.util.List; - - -public class FilmManagerTest { - FilmManager manager = new FilmManager(); - private final Film film = new Film(1, "Film", "Описание фильма", - LocalDate.of(1995, 2, 2), 120); - private final Film updatedFilm = new Film(2, "Drill", - "Drill этого фильма", - LocalDate.of(2000, 3, 1), 180); - - @Test - public void addFilmTest() { - manager.addFilm(film); - - Assertions.assertEquals(1, manager.getAllFilms().size()); - } - - @Test - public void updateFilmTest() { - manager.addFilm(film); - manager.updateFilm(updatedFilm); - - Assertions.assertEquals("Drill этого фильма", updatedFilm.getDescription()); - Assertions.assertEquals(2, manager.getAllFilms().size()); - } - - @Test - public void testGetFilmsList() { - manager.addFilm(film); - manager.addFilm(updatedFilm); - List expectedList = new ArrayList<>(manager.getAllFilms().values()); - List actualList = new ArrayList<>(); - actualList.add(film); - actualList.add(updatedFilm); - - Assertions.assertEquals(expectedList, actualList); - } -} - - - diff --git a/src/test/java/ru/yandex/practicum/filmorate/managerTest/UserManagerTest.java b/src/test/java/ru/yandex/practicum/filmorate/managerTest/UserManagerTest.java deleted file mode 100644 index f98355a..0000000 --- a/src/test/java/ru/yandex/practicum/filmorate/managerTest/UserManagerTest.java +++ /dev/null @@ -1,45 +0,0 @@ -package ru.yandex.practicum.filmorate.managerTest; - -import org.junit.Test; -import org.junit.jupiter.api.Assertions; -import ru.yandex.practicum.filmorate.manager.UserManager; -import ru.yandex.practicum.filmorate.model.User; - -import java.time.LocalDate; -import java.util.ArrayList; -import java.util.List; - -public class UserManagerTest { - UserManager manager = new UserManager(); - private final User user = new User(1, "di@mail.ru", "balda", "aa", LocalDate.of(1995, 1, 1)); - private final User updatedUser = new User(1, "xi@mail.ru", "nefritoviy", "sterzen", LocalDate.of(2000, 1, 1)); - - @Test - public void addUserTest() { - manager.addUser(user); - - Assertions.assertEquals(1, manager.getAllUsers().size()); - } - - @Test - public void updateFilmTest() { - manager.addUser(user); - manager.updateUser(updatedUser); - - Assertions.assertEquals("xi@mail.ru", updatedUser.getEmail()); - Assertions.assertEquals(user.getId(), updatedUser.getId()); - Assertions.assertEquals(1, manager.getAllUsers().size()); - } - - @Test - public void testGetFilmsList() { - manager.addUser(user); - manager.addUser(updatedUser); - List expectedList = new ArrayList<>(manager.getAllUsers().values()); - List actualList = new ArrayList<>(); - actualList.add(user); - actualList.add(updatedUser); - - Assertions.assertEquals(expectedList, actualList); - } -} diff --git a/src/test/java/ru/yandex/practicum/filmorate/service/FilmServiceTest.java b/src/test/java/ru/yandex/practicum/filmorate/service/FilmServiceTest.java new file mode 100644 index 0000000..0f15249 --- /dev/null +++ b/src/test/java/ru/yandex/practicum/filmorate/service/FilmServiceTest.java @@ -0,0 +1,42 @@ +package ru.yandex.practicum.filmorate.service; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import ru.yandex.practicum.filmorate.exception.ValidateException; +import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.storage.InMemoryFilmStorage; + +import java.time.LocalDate; +import java.util.HashMap; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +class FilmServiceTest { + private FilmService filmService; + + @BeforeEach + void setUp() { + filmService = new FilmService(new InMemoryFilmStorage(new HashMap<>())); + } + + @Test + void addFilm() { + Film film = Film.builder().description("description") + .duration(60) + .releaseDate(LocalDate.of(2022, 02, 23)) + .build(); + + assertThrows(ValidateException.class, () -> filmService.addModel(film)); + film.setName(" "); + assertThrows(ValidateException.class, () -> filmService.addModel(film)); + film.setDescription(" wqeqwrwefsdgsdevygfghdfgsdrthdfhdfgsgsdgdsgdgfdfgdfggggggfdffhljhjlhkjlhiuhiulhjlknjhkjdsafjdfasofuawejflkasjfls;jfiasojfeiajs;fe;kasjdfksjfdiosjfisjfsidhgdfgskdjfksdjfjsif fjs kfj sdkfjas;lfd ;sjfkas"); + film.setName("film1"); + assertThrows(ValidateException.class, () -> filmService.addModel(film)); + film.setDescription("description"); + film.setReleaseDate(LocalDate.of(1895, 12, 25)); + assertThrows(ValidateException.class, () -> filmService.addModel(film)); + film.setReleaseDate(LocalDate.of(2022, 02, 23)); + film.setDuration(-1); + assertThrows(ValidateException.class, () -> filmService.addModel(film)); + } +} \ No newline at end of file diff --git a/src/test/java/ru/yandex/practicum/filmorate/service/ManageFriendsToServiceTest.java b/src/test/java/ru/yandex/practicum/filmorate/service/ManageFriendsToServiceTest.java new file mode 100644 index 0000000..9bc06c2 --- /dev/null +++ b/src/test/java/ru/yandex/practicum/filmorate/service/ManageFriendsToServiceTest.java @@ -0,0 +1,51 @@ +package ru.yandex.practicum.filmorate.service; + +import org.junit.jupiter.api.Test; +import ru.yandex.practicum.filmorate.exception.NotFoundException; +import ru.yandex.practicum.filmorate.exception.ValidateException; +import ru.yandex.practicum.filmorate.model.FriendsTo; +import ru.yandex.practicum.filmorate.model.User; +import ru.yandex.practicum.filmorate.storage.InMemoryUserStorage; +import ru.yandex.practicum.filmorate.storage.StorageUser; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.HashMap; + +public class ManageFriendsToServiceTest { + private final StorageUser userStorage = new InMemoryUserStorage(new HashMap<>()); + private final UserService userService = new UserService(userStorage); + private final ManageFriendsUserService manageFriendsUserService = new ManageFriendsUserService(userStorage); + + @Test + public void addFriend() throws ValidateException, NotFoundException { + User user = User.builder() + .birthday(LocalDate.of(1994, 6, 12)) + .email("my@email.ru") + .login("vasyaPupkin") + .friends(new ArrayList<>()) + .build(); + + User user1 = User.builder() + .birthday(LocalDate.of(1994, 6, 12)) + .email("123my@email.ru") + .login("vasislisaPupkina") + .friends(new ArrayList<>()) + .build(); + + User user3 = User.builder() + .birthday(LocalDate.of(1994, 6, 12)) + .email("123@email.ru") + .login("vasisPupkin") + .friends(new ArrayList<>()) + .build(); + + manageFriendsUserService.addToFriends(new FriendsTo(userService.addModel(user3).getId(), userService.addModel(user).getId())); + manageFriendsUserService.addToFriends(new FriendsTo(userService.addModel(user1).getId(), user3.getId())); + + + manageFriendsUserService.addToFriends(new FriendsTo(userService.addModel(user1).getId(), userService.addModel(user).getId())); + System.out.println(user1.getFriends()); + System.out.println(manageFriendsUserService.getCommonFriends(new FriendsTo(user.getId(), user1.getId()))); + } +} diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDBStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDBStorageTest.java new file mode 100644 index 0000000..ffa3eb6 --- /dev/null +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/FilmDBStorageTest.java @@ -0,0 +1,85 @@ +package ru.yandex.practicum.filmorate.storage; + +import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.dao.EmptyResultDataAccessException; +import ru.yandex.practicum.filmorate.model.*; + +import java.time.LocalDate; +import java.util.Collections; +import java.util.Objects; +import java.util.TreeSet; + +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +@AutoConfigureTestDatabase +@RequiredArgsConstructor(onConstructor_ = @Autowired) +class FilmDBStorageTest { + + private final FilmDBStorage storageFilm; + private final UserDBStorage userDBStorage; + TreeSet genreTreeSet = new TreeSet<>(); + TreeSet likes = new TreeSet<>(); + + User user = User.builder().name("user").email("user@mail.ru").login("userLogin").birthday(LocalDate.of(1993, 2, 12)).build(); + Film film = Film.builder().name("name").genres(genreTreeSet).description("description") + .releaseDate(LocalDate.of(2021, 3, 23)).duration(45).mpa(new Mpa(1)) + .likes(likes).build(); + Film film2 = Film.builder().name("name2").genres(genreTreeSet).description("description2") + .releaseDate(LocalDate.of(2021, 3, 23)).duration(45).mpa(new Mpa(1)) + .likes(likes).build(); + + + @Test + public void save() { + Collections.addAll(genreTreeSet, new Genre(1, null), new Genre(3, null)); + Collections.addAll(likes, 1); + userDBStorage.save(user); + storageFilm.save(film); + storageFilm.save(film2); + + Film filmGet = storageFilm.get(1); + + assertEquals(1, filmGet.getId()); + assertEquals(2, storageFilm.get(2).getId()); + storageFilm.delete(1); + assertThrows(EmptyResultDataAccessException.class, () -> storageFilm.get(1)); + assertTrue(storageFilm.get(2).getLikes().stream().anyMatch(e -> Objects.equals(e, 1))); + storageFilm.removeIdFromIdSet(new FilmLikes(2, 1)); + assertEquals(0, storageFilm.get(2).getLikes().size()); + + } + + @Test + public void update() { + storageFilm.save(film); + + Film updateWithName = Film.builder().name("nameUpdate").genres(genreTreeSet).description("descriptionUpdate") + .releaseDate(LocalDate.of(2021, 3, 23)).duration(45).mpa(new Mpa(1)) + .likes(likes).id(1).build(); + + storageFilm.update(updateWithName); + + Film updateGet = storageFilm.get(1); + + assertEquals(updateGet.getName(), "nameUpdate"); + + Collections.addAll(genreTreeSet, new Genre(2, null)); + + storageFilm.update(updateWithName); + assertTrue(storageFilm.get(1).getGenres().stream().anyMatch(e -> Objects.equals(e.getId(), 2))); + } + + @Test + void getMpaGenres() { + assertEquals(1, storageFilm.getMpa(1).getId()); + assertEquals(5, storageFilm.getMpaList().size()); + assertEquals(1, storageFilm.getGenreById(1).getId()); + assertEquals(6, storageFilm.getGenreList().size()); + + } +} \ No newline at end of file diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/UserDBStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/UserDBStorageTest.java new file mode 100644 index 0000000..b084625 --- /dev/null +++ b/src/test/java/ru/yandex/practicum/filmorate/storage/UserDBStorageTest.java @@ -0,0 +1,55 @@ +package ru.yandex.practicum.filmorate.storage; + +import lombok.RequiredArgsConstructor; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.dao.EmptyResultDataAccessException; +import ru.yandex.practicum.filmorate.model.User; + +import java.time.LocalDate; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@SpringBootTest +@AutoConfigureTestDatabase +@RequiredArgsConstructor(onConstructor_ = @Autowired) +class UserDBStorageTest { + + private final UserDBStorage userStorage; + + @Test + public void save() { + User user1 = User.builder() + .name("test") + .email("testEmail") + .login("testlogin") + .birthday(LocalDate.of(1994, 2, 1)) + .build(); + + userStorage.save(user1); + Optional userOptional = Optional.of(userStorage.get(1)); + + assertThat(userOptional) + .isPresent() + .hasValueSatisfying(user -> + assertThat(user).hasFieldOrPropertyWithValue("id", 1) + ); + + user1.setId(1); + user1.setName("Update"); + userStorage.update(user1); + + User userUp = userStorage.get(1); + assertEquals("Update", userUp.getName()); + + userStorage.delete(1); + assertThrows(EmptyResultDataAccessException.class, () -> userStorage.get(1)); + + } + +} \ No newline at end of file