diff --git a/pom.xml b/pom.xml index 50a2ff5..e3ee927 100644 --- a/pom.xml +++ b/pom.xml @@ -39,6 +39,16 @@ commons-lang3 + + org.springframework.boot + spring-boot-starter-data-jdbc + + + com.h2database + h2 + runtime + + org.springframework.boot spring-boot-starter-test 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 4b970a0..7643b28 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -39,13 +39,13 @@ public Film getById(@PathVariable Integer id) { } @PutMapping("/{id}/like/{userId}") - public Film addLike(@PathVariable Integer id, @PathVariable Integer userId) { - return filmService.addLike(id, userId); + public void addLike(@PathVariable Integer id, @PathVariable Integer userId) { + filmService.addLike(id, userId); } @DeleteMapping("/{id}/like/{userId}") - public Film removeLike(@PathVariable Integer id, @PathVariable Integer userId) { - return filmService.removeLike(id, userId); + public void removeLike(@PathVariable Integer id, @PathVariable Integer userId) { + filmService.removeLike(id, userId); } @GetMapping("/popular") diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java new file mode 100644 index 0000000..f86f18e --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/GenreController.java @@ -0,0 +1,29 @@ +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.service.GenreService; +import ru.yandex.practicum.filmorate.model.Genres; + +import java.util.List; + +@RequestMapping("/genres") +@RestController +@RequiredArgsConstructor +public class GenreController { + + private final GenreService genreService; + + @GetMapping() + public List findAllGenres() { + return genreService.findAll(); + } + + @GetMapping("/{id}") + public Genres getGenresById(@PathVariable Integer id) { + return genreService.findById(id); + } +} 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..56eec6c --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/MPAController.java @@ -0,0 +1,29 @@ +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.model.MPA; +import ru.yandex.practicum.filmorate.service.MpaService; + +import java.util.List; + +@RequestMapping("/mpa") +@RestController +@RequiredArgsConstructor +public class MPAController { + + private final MpaService mpaService; + + @GetMapping() + public List findAllMpa() { + return mpaService.findAll(); + } + + @GetMapping("/{id}") + public MPA getByIdMpa(@PathVariable Integer id) { + return mpaService.findById(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 855edd8..825b121 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -40,13 +40,13 @@ public User findById(@PathVariable Integer id) { } @PutMapping("/{id}/friends/{friendId}") - public User addToFriends(@PathVariable Integer id, @PathVariable Integer friendId) { - return userService.addToFriends(id, friendId); + public void addToFriends(@PathVariable Integer id, @PathVariable Integer friendId) { + userService.addToFriends(id, friendId); } @DeleteMapping("/{id}/friends/{friendId}") - public User removeToFriends(@PathVariable Integer id, @PathVariable Integer friendId) { - return userService.removeToFriends(id, friendId); + public void removeToFriends(@PathVariable Integer id, @PathVariable Integer friendId) { + userService.removeToFriends(id, friendId); } @GetMapping("/{id}/friends") diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/FriendsDao.java b/src/main/java/ru/yandex/practicum/filmorate/dao/FriendsDao.java new file mode 100644 index 0000000..59ccb44 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/FriendsDao.java @@ -0,0 +1,9 @@ +package ru.yandex.practicum.filmorate.dao; + +public interface FriendsDao { + + int addToFriends(int idUser, int idFriend); + + int removeToFriends(int idUser, int idFriend); + +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/LikesDao.java b/src/main/java/ru/yandex/practicum/filmorate/dao/LikesDao.java new file mode 100644 index 0000000..19e7358 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/LikesDao.java @@ -0,0 +1,8 @@ +package ru.yandex.practicum.filmorate.dao; + +public interface LikesDao { + int addLike(int idFilm, int idUser); + + int removeLike(int idFilm, int idUser); + +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FriendsDaoImpl.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FriendsDaoImpl.java new file mode 100644 index 0000000..8856af6 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/FriendsDaoImpl.java @@ -0,0 +1,30 @@ +package ru.yandex.practicum.filmorate.dao.impl; + +import lombok.AllArgsConstructor; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.dao.FriendsDao; + + +@Component +@AllArgsConstructor +public class FriendsDaoImpl implements FriendsDao { + + private final JdbcTemplate jdbcTemplate; + + @Override + public int addToFriends(int idUser, int idFriend) { + + return jdbcTemplate.update("INSERT INTO friends (id_user,id_friend) VALUES (?,?)", idUser, idFriend); + + } + + @Override + public int removeToFriends(int idUser, int idFriend) { + + return jdbcTemplate.update("DELETE FROM friends WHERE id_user = ? AND id_friend = ?", idUser, idFriend); + + + } + +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/impl/LikesDaoImpl.java b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/LikesDaoImpl.java new file mode 100644 index 0000000..2c7198b --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/impl/LikesDaoImpl.java @@ -0,0 +1,35 @@ +package ru.yandex.practicum.filmorate.dao.impl; + +import lombok.AllArgsConstructor; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.dao.LikesDao; + +@Component +@AllArgsConstructor +public class LikesDaoImpl implements LikesDao { + + private final JdbcTemplate jdbcTemplate; + + + @Override + public int addLike(int idFilm, int idUser) { + + int result = jdbcTemplate.update("INSERT INTO likes (id_user,id_film) VALUES (?,?)", idUser, idFilm); + if (result != 0) upDateLikesFromFilm(idFilm); + return result; + } + + @Override + public int removeLike(int idFilm, int idUser) { + + int result = jdbcTemplate.update("DELETE FROM likes WHERE id_user = ? AND id_film = ?", idUser, idFilm); + if (result != 0) upDateLikesFromFilm(idFilm); + return result; + } + + private void upDateLikesFromFilm(int idFilm) { + String sqlQuery = "UPDATE films SET likes = (SELECT COUNT (id_user) FROM likes WHERE id_film = ?) where id = ?"; + jdbcTemplate.update(sqlQuery, idFilm, idFilm); + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/storageimpl/FilmDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/storageimpl/FilmDbStorage.java new file mode 100644 index 0000000..0240f10 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/storageimpl/FilmDbStorage.java @@ -0,0 +1,170 @@ +package ru.yandex.practicum.filmorate.dao.storageimpl; + +import lombok.AllArgsConstructor; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.ResultSetExtractor; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.rowset.SqlRowSet; +import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.model.Genres; +import ru.yandex.practicum.filmorate.model.MPA; +import ru.yandex.practicum.filmorate.storage.FilmStorage; + +import java.sql.Date; +import java.sql.PreparedStatement; +import java.util.*; + +@Component +@AllArgsConstructor +public class FilmDbStorage implements FilmStorage { + + private final JdbcTemplate jdbcTemplate; + + private final String sq = "SELECT fgm.id,fgm.name,fgm.description,fgm.release_date,fgm.duration,fgm.likes," + + "fgm.mpa,m.name_mpa,fgm.id_genre,fgm.name_genre " + + "FROM mpa AS m RIGHT JOIN (SELECT * FROM films AS f LEFT JOIN " + + "(SELECT fg.id_film,fg.id_genre,g.name_genre " + + "FROM films_genres AS fg LEFT JOIN genres AS g " + + "ON g.id=fg.id_genre) " + + "ON f.id=id_film) AS fgm ON m.id=mpa "; + + @Override + public List getAll() { + return new ArrayList<>(jdbcTemplate.query(sq, extractor()).values()); + } + + @Override + public Film create(Film film) { + + String sqlQuery = "INSERT INTO films (name," + + "description," + + "release_date," + + "duration," + + "likes," + + "mpa) " + + "VALUES (?,?,?,?,?,?)"; + + GeneratedKeyHolder keyHolder = new GeneratedKeyHolder(); + jdbcTemplate.update(connection -> { + PreparedStatement psst = connection.prepareStatement(sqlQuery, new String[]{"id"}); + psst.setString(1, film.getName()); + psst.setString(2, film.getDescription()); + psst.setDate(3, Date.valueOf(film.getReleaseDate())); + psst.setInt(4, film.getDuration()); + psst.setInt(5, film.getLikes()); + psst.setInt(6, film.getMpa().getId()); + return psst; + }, keyHolder); + + film.setId(keyHolder.getKey().intValue()); + + if (!film.getGenres().isEmpty()) { + for (Genres gen : film.getGenres()) { + String sQuery = "INSERT INTO films_genres (id_film,id_genre) " + + "VALUES (?,?)"; + + jdbcTemplate.update(sQuery, + film.getId(), + gen.getId()); + } + } + return film; + } + + @Override + public int upDate(Film film) { + String sqlQuery = "UPDATE films SET name = ?," + + "description = ?," + + "release_date = ?," + + "duration = ?," + + "likes = ?," + + "mpa = ?" + + " WHERE id = ?"; + + int result = jdbcTemplate.update(sqlQuery, + film.getName(), + film.getDescription(), + film.getReleaseDate(), + film.getDuration(), + film.getLikes(), + film.getMpa().getId(), + film.getId()); + + if (result == 0) { + return result; + } + + jdbcTemplate.update("DELETE FROM films_genres WHERE id_film = ?", film.getId()); + + if (!film.getGenres().isEmpty()) { + for (Genres gen : film.getGenres()) { + String sQuery = "INSERT INTO films_genres (id_film,id_genre) " + + "VALUES (?,?)"; + + jdbcTemplate.update(sQuery, + film.getId(), + gen.getId()); + } + } + return result; + } + + @Override + public boolean contains(int id) { + SqlRowSet filmRows = jdbcTemplate.queryForRowSet("select 1 from films where id = ?", id); + return filmRows.next(); + } + + @Override + public List getTopFilms(int limit) { + String sqlQuery = sq + "ORDER BY likes DESC LIMIT ?"; + return new ArrayList<>(jdbcTemplate.query(sqlQuery, extractor(), limit).values()); + } + + @Override + public Film getById(int id) { + String sqq = "SELECT fgm.id,fgm.name,fgm.description,fgm.release_date,fgm.duration,fgm.likes," + + "fgm.mpa,m.name_mpa,fgm.id_genre,fgm.name_genre " + + "FROM mpa AS m RIGHT JOIN (SELECT * FROM films AS f LEFT JOIN " + + "(SELECT fg.id_film,fg.id_genre,g.name_genre " + + "FROM films_genres AS fg LEFT JOIN genres AS g " + + "ON g.id=fg.id_genre ) " + + "ON f.id=id_film where f.id = ?) AS fgm ON m.id=mpa "; + Film film = jdbcTemplate.query(sqq, extractor(), id).get(id); + return film; + } + + private ResultSetExtractor> extractor() { + return rs -> { + + Map films = new HashMap<>(); + while (rs.next()) { + int id = rs.getInt("id"); + int idGenre = rs.getInt("id_genre"); + String nameGenre = rs.getString("name_genre"); + if (films.containsKey(id)) { + if (idGenre != 0) films.get(id).getGenres().add(new Genres(idGenre, nameGenre)); + } else { + Film film = new Film(); + films.put(id, film); + film.setId(id); + film.setName(rs.getString("name")); + film.setDescription(rs.getString("description")); + film.setReleaseDate(rs.getDate("release_date").toLocalDate()); + film.setDuration(rs.getInt("duration")); + film.setLikes(rs.getInt("likes")); + + if (idGenre != 0) films.get(id).getGenres().add(new Genres(idGenre, nameGenre)); + + int idMpa = rs.getInt("mpa"); + String nameMpa = rs.getString("name_mpa"); + + film.setMpa(new MPA(idMpa, nameMpa)); + + } + } + return films; + }; + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/storageimpl/GenreDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/storageimpl/GenreDbStorage.java new file mode 100644 index 0000000..d36427d --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/storageimpl/GenreDbStorage.java @@ -0,0 +1,42 @@ +package ru.yandex.practicum.filmorate.dao.storageimpl; + +import lombok.AllArgsConstructor; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.support.rowset.SqlRowSet; +import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.storage.GenreStorage; +import ru.yandex.practicum.filmorate.model.Genres; + +import java.util.List; + +@Component +@AllArgsConstructor +public class GenreDbStorage implements GenreStorage { + private final JdbcTemplate jdbcTemplate; + + @Override + public List getAll() { + String sq = "SELECT * FROM genres"; + return jdbcTemplate.query(sq, genreRowMapper()); + } + + @Override + public Genres getById(int id) { + + String sq = "SELECT * FROM genres WHERE id = ?"; + return jdbcTemplate.queryForObject(sq, genreRowMapper(), id); + + } + + @Override + public boolean contains(int id) { + SqlRowSet filmRows = jdbcTemplate.queryForRowSet("select * from genres where id = ?", id); + return filmRows.next(); + } + + private RowMapper genreRowMapper() { + return (rs, rowNum) -> new Genres(rs.getInt("id"), + rs.getString("name_genre")); + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/storageimpl/MpaDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/storageimpl/MpaDbStorage.java new file mode 100644 index 0000000..7587df8 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/storageimpl/MpaDbStorage.java @@ -0,0 +1,42 @@ +package ru.yandex.practicum.filmorate.dao.storageimpl; + +import lombok.AllArgsConstructor; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.support.rowset.SqlRowSet; +import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.storage.MpaStorage; +import ru.yandex.practicum.filmorate.model.MPA; + +import java.util.List; + +@Component +@AllArgsConstructor +public class MpaDbStorage implements MpaStorage { + + private final JdbcTemplate jdbcTemplate; + + @Override + public List getAll() { + String sq = "SELECT * FROM mpa"; + return jdbcTemplate.query(sq, mpaRowMapper()); + } + + @Override + public MPA getById(int id) { + String sq = "SELECT * FROM mpa WHERE id = ?"; + return jdbcTemplate.queryForObject(sq, mpaRowMapper(), id); + + } + + @Override + public boolean contains(int id) { + SqlRowSet filmRows = jdbcTemplate.queryForRowSet("select * from mpa where id = ?", id); + return filmRows.next(); + } + + private RowMapper mpaRowMapper() { + return (rs, rowNum) -> new MPA(rs.getInt("id"), + rs.getString("name_mpa")); + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/dao/storageimpl/UserDbStorage.java b/src/main/java/ru/yandex/practicum/filmorate/dao/storageimpl/UserDbStorage.java new file mode 100644 index 0000000..faa8782 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/dao/storageimpl/UserDbStorage.java @@ -0,0 +1,115 @@ +package ru.yandex.practicum.filmorate.dao.storageimpl; + +import lombok.AllArgsConstructor; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.rowset.SqlRowSet; +import org.springframework.stereotype.Component; +import ru.yandex.practicum.filmorate.model.User; +import ru.yandex.practicum.filmorate.storage.UserStorage; + +import java.sql.Date; +import java.sql.PreparedStatement; +import java.util.*; + +@Component +@AllArgsConstructor +public class UserDbStorage implements UserStorage { + + private final JdbcTemplate jdbcTemplate; + + @Override + public List getAll() { + return jdbcTemplate.query("SELECT * FROM mov_users", userRowMapper()); + } + + @Override + public User create(User user) { + + String sqlQuery = "INSERT INTO mov_users (email," + + "login," + + "name," + + "birthday) " + + "VALUES (?,?,?,?)"; + + GeneratedKeyHolder keyHolder = new GeneratedKeyHolder(); + jdbcTemplate.update(connection -> { + PreparedStatement psst = connection.prepareStatement(sqlQuery, new String[]{"id"}); + psst.setString(1, user.getEmail()); + psst.setString(2, user.getLogin()); + psst.setString(3, user.getName()); + psst.setDate(4, Date.valueOf(user.getBirthday())); + return psst; + }, keyHolder); + + user.setId(keyHolder.getKey().intValue()); + + return user; + } + + @Override + public int upDate(User user) { + String sqlQuery = "UPDATE mov_users SET " + + "email = ?," + + "login = ?," + + "name = ?," + + "birthday = ?" + + " WHERE id = ?"; + + int result = jdbcTemplate.update(sqlQuery, + user.getEmail(), + user.getLogin(), + user.getName(), + user.getBirthday(), + user.getId()); + return result; + } + + + @Override + public User getById(int id) { + String sql = "SELECT * FROM mov_users WHERE id = ?"; + User user = jdbcTemplate.queryForObject(sql, userRowMapper(), id); + return user; + + } + + @Override + public boolean contains(int id) { + SqlRowSet userRows = jdbcTemplate.queryForRowSet("select 1 from mov_users where id = ?", id); + return userRows.next(); + } + + @Override + public List getAllFriends(int id) { + + String sql = "SELECT * FROM mov_users WHERE id IN (SELECT id_friend FROM friends WHERE id_user = ?)"; + + return jdbcTemplate.query(sql, userRowMapper(), id); + } + + @Override + public List getMutualFriends(int idUser, int otherIdUser) { + + String sqlQuery = "SELECT * FROM mov_users WHERE id IN (SELECT id_friend FROM friends " + + "WHERE id_user=" + otherIdUser + " AND id_friend IN (SELECT id_friend " + + "FROM friends " + + "WHERE id_user =" + idUser + "))"; + + return jdbcTemplate.query(sqlQuery, userRowMapper()); + } + + private RowMapper userRowMapper() { + return (rs, rowNum) -> { + User user = new User(); + user.setId(rs.getInt("id")); + user.setEmail(rs.getString("email")); + user.setLogin(rs.getString("login")); + user.setName(rs.getString("name")); + user.setBirthday(rs.getDate("birthday").toLocalDate()); + + return user; + }; + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/EntityNotFoundException.java b/src/main/java/ru/yandex/practicum/filmorate/exception/EntityNotFoundException.java new file mode 100644 index 0000000..669fae7 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/exception/EntityNotFoundException.java @@ -0,0 +1,14 @@ +package ru.yandex.practicum.filmorate.exception; + +public class EntityNotFoundException extends RuntimeException { + private Class clazz; + + public EntityNotFoundException(Class clazz) { + this.clazz = clazz; + } + + @Override + public String getMessage() { + return clazz.getName(); + } +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/FilmAndUserExceptionHandler.java b/src/main/java/ru/yandex/practicum/filmorate/exception/FilmAndUserExceptionHandler.java index c12dcc4..4b8f8c4 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/exception/FilmAndUserExceptionHandler.java +++ b/src/main/java/ru/yandex/practicum/filmorate/exception/FilmAndUserExceptionHandler.java @@ -1,6 +1,8 @@ package ru.yandex.practicum.filmorate.exception; +import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; +import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; @@ -8,36 +10,42 @@ import javax.validation.ValidationException; import java.util.Map; +@Slf4j @RestControllerAdvice("ru.yandex.practicum.filmorate.controller") public class FilmAndUserExceptionHandler { @ExceptionHandler @ResponseStatus(HttpStatus.NOT_FOUND) - public Map handleFilmNotFound(FilmNotFoundException e) { + public Map handleFilmNotFound(EntityNotFoundException e) { + log.warn("Получен статус 404 Not found {}", e.getMessage(), e); return Map.of("message", e.getMessage()); } @ExceptionHandler - @ResponseStatus(HttpStatus.NOT_FOUND) - public Map handleUserNotFound(UserNotFoundException e) { + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Map handleValidation(MethodArgumentNotValidException e) { + log.warn("Получен статус 400 Bad request {}", e.getMessage(), e); return Map.of("message", e.getMessage()); } @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) public Map handleValidation(ValidationException e) { + log.warn("Получен статус 400 Bad request {}", e.getMessage(), e); return Map.of("message", e.getMessage()); } @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) public Map handleIncorrectArguments(IncorrectArgumentsException e) { + log.warn("Получен статус 400 Bad request {}", e.getMessage(), e); return Map.of("message", e.getMessage()); } @ExceptionHandler @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) - public Map handleIncorrectArguments(RuntimeException e) { + public Map handleIncorrectArguments(Throwable e) { + log.warn("Получен статус 500 Internal Server Error {}", e.getMessage(), e); return Map.of("message", e.getMessage()); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/FilmNotFoundException.java b/src/main/java/ru/yandex/practicum/filmorate/exception/FilmNotFoundException.java deleted file mode 100644 index ffa6980..0000000 --- a/src/main/java/ru/yandex/practicum/filmorate/exception/FilmNotFoundException.java +++ /dev/null @@ -1,14 +0,0 @@ -package ru.yandex.practicum.filmorate.exception; - -public class FilmNotFoundException extends RuntimeException { - - String message; - - public FilmNotFoundException(String message) { - this.message = message; - } - - public String getMessage() { - return message; - } -} diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/IncorrectArgumentsException.java b/src/main/java/ru/yandex/practicum/filmorate/exception/IncorrectArgumentsException.java index 15676df..697cfe7 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/exception/IncorrectArgumentsException.java +++ b/src/main/java/ru/yandex/practicum/filmorate/exception/IncorrectArgumentsException.java @@ -2,13 +2,13 @@ public class IncorrectArgumentsException extends RuntimeException { - String message; + private Class clazz; - public IncorrectArgumentsException(String message) { - this.message = message; + public IncorrectArgumentsException(Class clazz) { + this.clazz = clazz; } public String getMessage() { - return message; + return clazz.getName(); } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/UserNotFoundException.java b/src/main/java/ru/yandex/practicum/filmorate/exception/UserNotFoundException.java deleted file mode 100644 index 7fc17a7..0000000 --- a/src/main/java/ru/yandex/practicum/filmorate/exception/UserNotFoundException.java +++ /dev/null @@ -1,14 +0,0 @@ -package ru.yandex.practicum.filmorate.exception; - -public class UserNotFoundException extends RuntimeException { - - String message; - - public UserNotFoundException(String message) { - this.message = message; - } - - public String getMessage() { - return 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 c9c5417..4306f1c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java @@ -1,21 +1,20 @@ package ru.yandex.practicum.filmorate.model; import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; import ru.yandex.practicum.filmorate.validators.timevalidator.TimeAfterDate; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import javax.validation.constraints.*; import java.time.LocalDate; +import java.util.*; @Data public class Film { private int id; - @NotEmpty + @NotBlank private String name; @NotNull @@ -27,10 +26,15 @@ public class Film { @JsonFormat(pattern = "yyyy-MM-dd") private LocalDate releaseDate; - @NotNull @Min(value = 1) - int duration; + private int duration; + + @JsonIgnore + private int likes; - int likes; + private Set genres = new TreeSet<>(); + + @NotNull + private MPA mpa; } diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Genres.java b/src/main/java/ru/yandex/practicum/filmorate/model/Genres.java new file mode 100644 index 0000000..3a48688 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Genres.java @@ -0,0 +1,34 @@ +package ru.yandex.practicum.filmorate.model; + +import lombok.*; + +import java.util.Objects; + + +@Getter +@Setter +@AllArgsConstructor +public class Genres implements Comparable { + + private int id; + private String name; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Genres genres = (Genres) o; + return id == genres.id; + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + + @Override + public int compareTo(Genres g) { + return this.getId() - g.getId(); + } +} + 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..9959e8f --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/MPA.java @@ -0,0 +1,11 @@ +package ru.yandex.practicum.filmorate.model; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class MPA { + private int id; + private String name; +} 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 b31c45f..12bfc29 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/model/User.java +++ b/src/main/java/ru/yandex/practicum/filmorate/model/User.java @@ -3,31 +3,27 @@ import com.fasterxml.jackson.annotation.JsonFormat; import lombok.*; -import javax.validation.constraints.Email; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Past; +import javax.validation.constraints.*; import java.time.LocalDate; -import java.util.HashSet; -import java.util.Set; @Data public class User { + private int id; + @NotEmpty @Email private String email; @NotBlank + @Pattern(regexp = "^[a-zA-Z0-9!@#$%^&*]{6,12}$") private String login; private String name; + @NotNull @JsonFormat(pattern = "yyyy-MM-dd") - @Past + @PastOrPresent private LocalDate birthday; - private Set friends = new HashSet<>(); - - private Set likes = new HashSet<>(); - } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java index 401b855..02a5ca1 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java @@ -3,15 +3,13 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import ru.yandex.practicum.filmorate.exception.FilmNotFoundException; +import ru.yandex.practicum.filmorate.dao.LikesDao; +import ru.yandex.practicum.filmorate.exception.EntityNotFoundException; import ru.yandex.practicum.filmorate.exception.IncorrectArgumentsException; -import ru.yandex.practicum.filmorate.exception.UserNotFoundException; import ru.yandex.practicum.filmorate.model.Film; -import ru.yandex.practicum.filmorate.model.User; import ru.yandex.practicum.filmorate.storage.FilmStorage; import ru.yandex.practicum.filmorate.storage.UserStorage; -import java.util.ArrayList; import java.util.List; @Slf4j @@ -20,76 +18,62 @@ public class FilmService { private final FilmStorage filmStorage; + private final UserStorage userStorage; + private final LikesDao likesDao; + public List findAll() { - return new ArrayList(filmStorage.getAll().values()); + log.info("Список фильмов получен"); + return filmStorage.getAll(); } - public Film findById(Integer id) { - return filmStorage.getById(id); + public Film findById(int id) { + if (filmStorage.contains(id)) { + log.info("Фильм с id={} получен", id); + return filmStorage.getById(id); + } else { + throw new EntityNotFoundException(FilmService.class); + } } public List findTopFilms(int limit) { + log.info("Получены {} наиболее популярных фильмов", limit); return filmStorage.getTopFilms(limit); } public Film create(Film film) { - return filmStorage.create (film); + log.info("Фильм с id={} успешно добавлен", film.getId()); + return filmStorage.create(film); } public Film upDate(Film film) { - return filmStorage.upDate(film); - } - - public Film addLike(Integer idFilm, Integer idUser) { - - if (!userStorage.contains(idUser)) { - log.warn("Пользватель с id " + idUser + " отсутствует"); - throw new UserNotFoundException("Пользватель с id " + idUser + " отсутствует"); + int result = filmStorage.upDate(film); + if (result == 0) { + throw new EntityNotFoundException(FilmService.class); + } else { + log.info("Фильм с id={} успешно изменен", film.getId()); + return film; } - if (!filmStorage.contains(idFilm)) { - log.warn("Фильм с id " + idFilm + " отсутствует"); - throw new FilmNotFoundException("Фильм с id " + idFilm + " отсутствует"); - } - - User user = userStorage.getById(idUser); - Film film = findById(idFilm); - - if (user.getLikes().contains(film.getId())) { - log.warn("Пользователь " + idUser + " уже оценивал фильм " + idFilm); - throw new IncorrectArgumentsException("Пользователь " + idUser + " уже оценивал фильм " + idFilm); - } - - user.getLikes().add(film.getId()); - film.setLikes(film.getLikes() + 1); - log.info("Пользователь " + idUser + " оценил фильм " + idFilm); - return filmStorage.getById(idFilm); - } - public Film removeLike(Integer idFilm, Integer idUser) { - if (!userStorage.contains(idUser)) { - log.warn("Пользватель с id " + idUser + " отсутствует"); - throw new UserNotFoundException("Пользватель с id " + idUser + " отсутствует"); + public void addLike(int idFilm, int idUser) { + int result = likesDao.addLike(idFilm, idUser); + if (result == 0) { + throw new IncorrectArgumentsException(FilmService.class); } - if (!filmStorage.contains(idFilm)) { - log.warn("Фильм с id " + idFilm + " отсутствует"); - throw new FilmNotFoundException("Фильм с id " + idFilm + " отсутствует"); + if (!filmStorage.contains(idFilm) || !userStorage.contains(idUser)) { + throw new EntityNotFoundException(FilmService.class); } + log.info("Пользователь c id={} оценил фильм c id={}", idUser, idFilm); + } - User user = userStorage.getById(idUser); - Film film = findById(idFilm); - - if (!user.getLikes().contains(idFilm)) { - log.warn("Пользватель " + idUser + " еще не оценивал фильм " + idFilm); - throw new IncorrectArgumentsException("Пользватель " + idUser + " еще не оценивал фильм " + idFilm); + public void removeLike(int idFilm, int idUser) { + int result = likesDao.removeLike(idFilm, idUser); + if (!userStorage.contains(idUser) || !filmStorage.contains(idFilm) || result == 0) { + throw new EntityNotFoundException(FilmService.class); } - film.setLikes(film.getLikes() - 1); - user.getLikes().remove(film.getId()); - log.info("Пользователь " + idUser + " удалил оценку с фильма " + idFilm); - return film; + log.info("Пользователь c id={} удалил оценку с фильма c id={}", idUser, idFilm); } - } diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java b/src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java new file mode 100644 index 0000000..c88eb92 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/GenreService.java @@ -0,0 +1,32 @@ +package ru.yandex.practicum.filmorate.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.storage.GenreStorage; +import ru.yandex.practicum.filmorate.exception.EntityNotFoundException; +import ru.yandex.practicum.filmorate.model.Genres; + +import java.util.List; + +@Slf4j +@Service +@RequiredArgsConstructor +public class GenreService { + + private final GenreStorage genreStorage; + + public List findAll() { + log.info("Список жанров получен"); + return genreStorage.getAll(); + } + + public Genres findById(int id) { + if (genreStorage.contains(id)) { + log.info("Жанр с id={} получен", id); + return genreStorage.getById(id); + } else { + throw new EntityNotFoundException(GenreService.class); + } + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java b/src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java new file mode 100644 index 0000000..f087fec --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/service/MpaService.java @@ -0,0 +1,31 @@ +package ru.yandex.practicum.filmorate.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.storage.MpaStorage; +import ru.yandex.practicum.filmorate.exception.EntityNotFoundException; +import ru.yandex.practicum.filmorate.model.MPA; + +import java.util.List; + +@Slf4j +@Service +@RequiredArgsConstructor +public class MpaService { + private final MpaStorage mpaStorage; + + public List findAll() { + log.info("Список возрастных рейтингов получен"); + return mpaStorage.getAll(); + } + + public MPA findById(int id) { + if (mpaStorage.contains(id)) { + log.info("Возрастной рейтинг с id={} получен", id); + return mpaStorage.getById(id); + } else { + throw new EntityNotFoundException(MpaService.class); + } + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java index 6435fae..bdf302c 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java +++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java @@ -4,8 +4,10 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; +import ru.yandex.practicum.filmorate.dao.FriendsDao; +import ru.yandex.practicum.filmorate.dao.storageimpl.UserDbStorage; +import ru.yandex.practicum.filmorate.exception.EntityNotFoundException; import ru.yandex.practicum.filmorate.exception.IncorrectArgumentsException; -import ru.yandex.practicum.filmorate.exception.UserNotFoundException; import ru.yandex.practicum.filmorate.model.User; import ru.yandex.practicum.filmorate.storage.UserStorage; @@ -16,66 +18,82 @@ @RequiredArgsConstructor public class UserService { + private final UserStorage userStorage; + private final FriendsDao friendsDao; public List findAll() { - return new ArrayList(userStorage.getAll().values()); - } - - public User findById(Integer id) { - - return userStorage.getById(id); + log.info("Список пользователей получен"); + return userStorage.getAll(); } - public List findAllFriends(Integer id) { - return userStorage.getAllFriends(id); + public User findById(int id) { + if (userStorage.contains(id)) { + log.info("Пользователь с id={} получен", id); + return userStorage.getById(id); + } else { + throw new EntityNotFoundException(UserDbStorage.class); + } } - public List findMutualFriends(Integer idUser, Integer otherIdUser) { - return userStorage.getMutualFriends(idUser, otherIdUser); + public List findAllFriends(int id) { + if (userStorage.contains(id)) { + log.info("Список друзей пользователя c id={} получен", id); + return userStorage.getAllFriends(id); + } else { + throw new EntityNotFoundException(UserDbStorage.class); + } } - public User addToFriends(Integer idUser, Integer idFriend) { - if (idUser.equals(idFriend)) { - log.warn("Значения не должны быть одинаковыми"); - throw new IncorrectArgumentsException("Значения не должны быть одинаковыми"); + public List findMutualFriends(int idUser, int otherIdUser) { + if (idUser == otherIdUser) { + throw new IncorrectArgumentsException(UserService.class); } if (!userStorage.contains(idUser)) { - log.warn("Пользователь с id " + idUser + " отсутствует"); - throw new UserNotFoundException("Пользователь с id " + idUser + " отсутствует"); + throw new EntityNotFoundException(UserService.class); } - if (!userStorage.contains(idFriend)) { - log.warn("Пользователь с id " + idUser + " отсутствует"); - throw new UserNotFoundException("Пользователь с id " + idFriend + " отсутствует"); + if (!userStorage.contains(otherIdUser)) { + throw new EntityNotFoundException(UserService.class); } - findById(idUser).getFriends().add(idFriend); - findById(idFriend).getFriends().add(idUser); + log.info("Список общих друзей пользователей c id={} и c id={} получен", idUser, otherIdUser); + return userStorage.getMutualFriends(idUser, otherIdUser); + } - log.info("Пользователь успешно добавлен в друзья"); + public void addToFriends(int idUser, int idFriend) { + if (!userStorage.contains(idUser) || !userStorage.contains(idFriend)) { + throw new EntityNotFoundException(UserService.class); + } - return findById(idUser); - } + int result = friendsDao.addToFriends(idUser, idFriend); + + if (idUser == idFriend || result == 0) { + throw new IncorrectArgumentsException(UserService.class); + } - public User removeToFriends(Integer idUser, Integer idFriend) { - if (findById(idUser).getFriends().contains(idFriend)) { - findById(idFriend).getFriends().remove(idUser); - findById(idUser).getFriends().remove(idFriend); + log.info("Пользователь c id={} успешно добавлен в друзья пользователю c id={}", idFriend, idUser); + } - log.info("Пользователь успешно удален из друзей"); + public void removeToFriends(int idUser, int idFriend) { - return findById(idUser); - } else { + if (!userStorage.contains(idUser) || !userStorage.contains(idFriend)) { + throw new EntityNotFoundException(UserService.class); + } - log.warn("Пользователь с id " + idFriend + " отсутствует"); + int result = friendsDao.removeToFriends(idUser, idFriend); - throw new UserNotFoundException("Пользователь с id " + idFriend + " отсутствует"); + if (idUser == idFriend || result == 0) { + throw new IncorrectArgumentsException(UserService.class); } + + log.info("Пользователь c id={} успешно удален из друзей пользователя c id={}", idFriend, idUser); + } public User create(User user) { if (StringUtils.isEmpty(user.getName())) { user.setName(user.getLogin()); } + log.info("Пользователь с id={} добавлен", user.getId()); return userStorage.create(user); } @@ -83,8 +101,13 @@ public User upDate(User user) { if (StringUtils.isEmpty(user.getName())) { user.setName(user.getLogin()); } - return userStorage.upDate(user); - } + int result = userStorage.upDate(user); + if (result == 0) { + throw new EntityNotFoundException(UserService.class); + } + log.info("Пользователь c id={} успешно изменен", user.getId()); + return user; + } } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java index 39c090a..4c913aa 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java @@ -2,21 +2,22 @@ import ru.yandex.practicum.filmorate.model.Film; + import java.util.List; -import java.util.Map; public interface FilmStorage { - Map getAll(); + List getAll(); - Film create (Film film); + Film create(Film film); - Film upDate (Film film); + int upDate(Film film); - boolean contains(Integer id); + boolean contains(int id); List getTopFilms(int limit); - Film getById(Integer id); + Film getById(int id); + } diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/GenreStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/GenreStorage.java new file mode 100644 index 0000000..4912a49 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/GenreStorage.java @@ -0,0 +1,13 @@ +package ru.yandex.practicum.filmorate.storage; + +import ru.yandex.practicum.filmorate.model.Genres; + +import java.util.List; + +public interface GenreStorage { + List getAll(); + + Genres getById(int id); + + boolean contains(int id); +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java deleted file mode 100644 index 36bf3c1..0000000 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java +++ /dev/null @@ -1,77 +0,0 @@ -package ru.yandex.practicum.filmorate.storage; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; -import ru.yandex.practicum.filmorate.exception.FilmNotFoundException; -import ru.yandex.practicum.filmorate.model.Film; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -@Slf4j -@Component -public class InMemoryFilmStorage implements FilmStorage { - - private int idGenerator = 0; - - private final Map films = new HashMap<>(); - - - @Override - public Map getAll() { - log.info("Список фильмов получен"); - return films; - } - - @Override - public Film create (Film film){ - idGenerator++; - film.setId(idGenerator); - films.put(idGenerator, film); - log.info("Фильм успешно добавлен"); - return film; - } - - @Override - public Film upDate (Film film){ - if (contains(film.getId())) { - films.put(film.getId(), film); - } else { - log.warn("Фильм с id " + film.getId() + " отсутствует"); - throw new FilmNotFoundException("Фильм с id " + film.getId() + " отсутствует"); - } - log.info("Фильм успешно изменен"); - return film; - } - - @Override - public List getTopFilms(int limit) { - log.info("Получены " + limit + " наиболее популярных фильмов"); - return films.values().stream().sorted((f1, f2) -> { - return -1 * (f1.getLikes() - f2.getLikes()); - }) - .limit(limit) - .collect(Collectors.toList()); - } - - - @Override - public boolean contains(Integer id) { - return films.containsKey(id); - } - - @Override - public Film getById(Integer id) { - if (films.containsKey(id)) { - log.info("Фильм с id " + id + " получен"); - return films.get(id); - } else { - log.warn("Фильм с id " + id + " отсутствует"); - throw new FilmNotFoundException("Фильм с id " + id + " отсутствует"); - } - } - - -} diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java deleted file mode 100644 index cd4817c..0000000 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java +++ /dev/null @@ -1,109 +0,0 @@ -package ru.yandex.practicum.filmorate.storage; - -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.springframework.stereotype.Component; -import ru.yandex.practicum.filmorate.exception.IncorrectArgumentsException; -import ru.yandex.practicum.filmorate.exception.UserNotFoundException; -import ru.yandex.practicum.filmorate.model.User; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@Slf4j -@Component -public class InMemoryUserStorage implements UserStorage { - - private int idGenerator = 0; - private final Map users = new HashMap<>(); - - @Override - public Map getAll() { - log.info("Вывод списка пользователей"); - return users; - } - - @Override - public User create (User user) { - idGenerator++; - user.setId(idGenerator); - users.put(idGenerator, user); - log.info("Пользователь добавлен"); - return user; - } - - @Override - public User upDate (User user){ - if (contains(user.getId())) { - users.put(user.getId(), user); - log.info("Пользователь изменен"); - } else { - log.warn("Пользователь с id " + user.getId() + " отсутствует"); - throw new UserNotFoundException("Пользватель с id " + user.getId() + " отсутствует"); - } - return user; - } - - @Override - public boolean contains(Integer id) { - return users.containsKey(id); - } - - @Override - public User getById(Integer id) { - if (contains(id)) { - log.info("Пользователь с id " + id + " получен"); - return users.get(id); - } else { - log.warn("Пользователь с id " + id + " отсутствует"); - throw new UserNotFoundException("Пользователь с id " + id + " отсутствует"); - } - } - - @Override - public List getAllFriends(Integer id) { - if (contains(id)) { - ArrayList allFriends = new ArrayList<>(); - for (Integer idFriends : getById(id).getFriends()) { - allFriends.add(getById(idFriends)); - } - - log.info("Список друзей пользователя " + id + " получен"); - - return allFriends; - } else { - - log.warn("Пользователь с id " + id + " отсутствует"); - - throw new UserNotFoundException("Пользователь с id " + id + " отсутствует"); - } - } - - @Override - public List getMutualFriends(Integer idUser, Integer otherIdUser) { - if (idUser.equals(otherIdUser)) { - log.warn("Значения не должны быть одинаковыми"); - throw new IncorrectArgumentsException("Значения не должны быть одинаковыми"); - } - if (!contains(idUser)) { - log.warn("Пользователь с id " + idUser + " отсутствует"); - throw new UserNotFoundException("Пользователь с id " + idUser + " отсутствует"); - } - if (!contains(otherIdUser)) { - log.warn("Пользователь с id " + otherIdUser + " отсутствует"); - throw new UserNotFoundException("Пользователь с id " + otherIdUser + " отсутствует"); - } - - ArrayList mutualFriends = new ArrayList<>(); - for (Integer id : getById(idUser).getFriends()) { - if (getById(otherIdUser).getFriends().contains(id)) { - mutualFriends.add(getById(id)); - } - } - log.info("Список общих друзей пользователей получен"); - return mutualFriends; - } -} - diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/MpaStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/MpaStorage.java new file mode 100644 index 0000000..65cc92b --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/MpaStorage.java @@ -0,0 +1,14 @@ +package ru.yandex.practicum.filmorate.storage; + +import ru.yandex.practicum.filmorate.model.MPA; + +import java.util.List; + +public interface MpaStorage { + + List getAll(); + + MPA getById(int id); + + boolean contains(int id); +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java index a26f9fb..37bc22d 100644 --- a/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java +++ b/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java @@ -3,21 +3,20 @@ import ru.yandex.practicum.filmorate.model.User; import java.util.List; -import java.util.Map; public interface UserStorage { - Map getAll(); + List getAll(); - User create (User user); + User create(User user); - User upDate (User user); + int upDate(User user); - User getById(Integer id); + User getById(int id); - boolean contains (Integer id); + boolean contains(int id); - List getAllFriends(Integer id); + List getAllFriends(int id); - List getMutualFriends(Integer idUser, Integer otherIdUser); + List getMutualFriends(int idUser, int otherIdUser); } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 72f5316..73d861b 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,6 @@ -logging.level.ru.yandex.practicum.filmorate.controller=info +logging.level.ru.yandex.practicum.filmorate.controller=debug +spring.sql.init.mode=always +spring.datasource.url=jdbc:h2:file:./db/filmorate +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password=password diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql new file mode 100644 index 0000000..e890c49 --- /dev/null +++ b/src/main/resources/data.sql @@ -0,0 +1,15 @@ +INSERT INTO genres (id, name_genre) +VALUES (1, 'Комедия'), + (2, 'Драма'), + (3, 'Мультфильм'), + (4, 'Триллер'), + (5, 'Документальный'), + (6, 'Боевик'); + +INSERT INTO mpa (id, name_mpa) +VALUES (1, 'G'), + (2, 'PG'), + (3, 'PG-13'), + (4, 'R'), + (5, 'NC-17'); + diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql new file mode 100644 index 0000000..6b2e947 --- /dev/null +++ b/src/main/resources/schema.sql @@ -0,0 +1,61 @@ +drop table if exists FILMS cascade; +drop table if exists mov_users cascade; +drop table if exists mpa cascade; +drop table if exists likes cascade; +drop table if exists genres cascade; +drop table if exists friends cascade; +drop table if exists films_genres cascade; + +CREATE TABLE IF NOT EXISTS genres +( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name_genre varchar NOT NULL +); + +CREATE TABLE IF NOT EXISTS mpa +( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name_mpa varchar NOT NULL +); + +CREATE TABLE IF NOT EXISTS films +( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name varchar NOT NULL, + description varchar NOT NULL, + release_date date, + duration integer, + likes integer, + mpa integer REFERENCES mpa (id) +); + +CREATE TABLE IF NOT EXISTS films_genres +( + id_film integer REFERENCES films (id), + id_genre integer REFERENCES genres (id), + CONSTRAINT film_genre PRIMARY KEY (id_film,id_genre) +); + +CREATE TABLE IF NOT EXISTS mov_users +( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + email varchar NOT NULL UNIQUE, + login varchar NOT NULL UNIQUE, + name varchar, + birthday date +); + +CREATE TABLE IF NOT EXISTS friends +( + id_user integer REFERENCES mov_users (id), + id_friend integer REFERENCES mov_users (id), + CONSTRAINT user_friend PRIMARY KEY (id_user,id_friend) +); + +CREATE TABLE IF NOT EXISTS likes +( + id_user integer REFERENCES mov_users (id), + id_film integer REFERENCES films (id), + CONSTRAINT user_film PRIMARY KEY (id_user,id_film) +); + diff --git a/src/test/java/ru/yandex/practicum/filmorate/FilmorateApplicationTests.java b/src/test/java/ru/yandex/practicum/filmorate/FilmorateApplicationTests.java index 660412e..84f8470 100644 --- a/src/test/java/ru/yandex/practicum/filmorate/FilmorateApplicationTests.java +++ b/src/test/java/ru/yandex/practicum/filmorate/FilmorateApplicationTests.java @@ -1,13 +1,333 @@ 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; +import org.springframework.test.annotation.DirtiesContext; +import ru.yandex.practicum.filmorate.storage.GenreStorage; +import ru.yandex.practicum.filmorate.storage.MpaStorage; +import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.model.Genres; +import ru.yandex.practicum.filmorate.model.MPA; +import ru.yandex.practicum.filmorate.model.User; +import ru.yandex.practicum.filmorate.service.FilmService; +import ru.yandex.practicum.filmorate.service.UserService; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; @SpringBootTest +@AutoConfigureTestDatabase +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) class FilmorateApplicationTests { - @Test - void contextLoads() { - } + private final UserService userService; + private final FilmService filmService; + + private final GenreStorage genreDao; + + private final MpaStorage mpaDao; + + private User newUser(Integer n) { + User user = new User(); + user.setEmail("email@email" + n + ".ru"); + user.setLogin("login" + n); + user.setName("name" + n); + user.setBirthday(LocalDate.of(2000, 12, 15)); + return user; + } + + @Test + public void testFindUserById() { + + userService.create(newUser(1)); + userService.create(newUser(2)); + userService.create(newUser(3)); + + User resultUser1 = userService.findById(1); + User resultUser2 = userService.findById(2); + User resultUser3 = userService.findById(3); + + assertThat(resultUser1).isNotNull(); + assertThat(resultUser1.getId()).isEqualTo(1); + assertThat(resultUser1.getName()).isEqualTo("name1"); + assertThat(resultUser2.getId()).isEqualTo(2); + assertThat(resultUser3.getId()).isEqualTo(3); + } + + @Test + public void testFindAllUser() { + + userService.create(newUser(1)); + userService.create(newUser(2)); + userService.create(newUser(3)); + + List users = userService.findAll(); + + assertThat(users.size()).isEqualTo(3); + } + + @Test + public void testUpdateUser() { + userService.create(newUser(1)); + userService.create(newUser(2)); + userService.create(newUser(3)); + + User updateUser = newUser(4); + updateUser.setId(2); + + User resultUser = userService.upDate(updateUser); + + assertThat(resultUser).isNotNull(); + assertThat(resultUser.getId()).isEqualTo(2); + assertThat(resultUser.getName()).isEqualTo("name4"); + assertThat(resultUser.getLogin()).isEqualTo("login4"); + assertThat(resultUser.getEmail()).isEqualTo("email@email4.ru"); + } + + @Test + public void testGetAllFriends() { + User user = newUser(1); + User friend1 = newUser(2); + User friend2 = newUser(3); + User friend3 = newUser(4); + + userService.create(user); + userService.create(friend1); + userService.create(friend2); + userService.create(friend3); + + userService.addToFriends(1, 2); + userService.addToFriends(1, 3); + userService.addToFriends(1, 4); + + List friends = userService.findAllFriends(1); + assertThat(friends.size()).isEqualTo(3); + + userService.removeToFriends(1, 4); + friends = userService.findAllFriends(1); + assertThat(friends.size()).isEqualTo(2); + + List idFriend = new ArrayList<>(); + for (User userr : friends) { + idFriend.add(userr.getId()); + } + assertThat(idFriend.contains(3)).isTrue(); + assertThat(idFriend.contains(2)).isTrue(); + } + + @Test + public void testGetMutualFriends() { + User user1 = newUser(1); + User user2 = newUser(2); + User friend1 = newUser(3); + User friend2 = newUser(4); + User friend3 = newUser(5); + + userService.create(user1); + userService.create(user2); + userService.create(friend1); + userService.create(friend2); + userService.create(friend3); + + userService.addToFriends(1, 3); + userService.addToFriends(1, 4); + userService.addToFriends(1, 5); + userService.addToFriends(2, 3); + userService.addToFriends(2, 5); + + List friends = userService.findMutualFriends(1, 2); + assertThat(friends.size()).isEqualTo(2); + + List idFriend = new ArrayList<>(); + for (User user : friends) { + idFriend.add(user.getId()); + } + assertThat(idFriend.contains(3)).isTrue(); + assertThat(idFriend.contains(5)).isTrue(); + } + + private Film newFilm(Integer num) { + Film film = new Film(); + film.setName("name" + num); + film.setDescription("description" + num); + film.setReleaseDate(LocalDate.of(2005, 12, 15)); + film.setDuration(150); + film.setMpa(new MPA(1, "PG")); + return film; + } + + @Test + public void testFindAllFilms() { + filmService.create(newFilm(1)); + filmService.create(newFilm(2)); + filmService.create(newFilm(3)); + + List films = filmService.findAll(); + assertThat(films.size()).isEqualTo(3); + } + + @Test + public void testFindFilmById() { + filmService.create(newFilm(1)); + filmService.create(newFilm(2)); + filmService.create(newFilm(3)); + + Film resultFilm = filmService.findById(3); + + assertThat(resultFilm.getId()).isEqualTo(3); + assertThat(resultFilm.getName()).isEqualTo("name3"); + } + + @Test + public void testUpdateFilm() { + filmService.create(newFilm(1)); + filmService.create(newFilm(2)); + filmService.create(newFilm(3)); + + Film upDateFilm = newFilm(4); + upDateFilm.setId(2); + + filmService.upDate(upDateFilm); + + assertThat(upDateFilm.getName()).isEqualTo("name4"); + assertThat(upDateFilm.getDescription()).isEqualTo("description4"); + assertThat(upDateFilm.getLikes()).isEqualTo(0); + } + + @Test + public void testAddLikes() { + filmService.create(newFilm(1)); + userService.create(newUser(1)); + userService.create(newUser(2)); + userService.create(newUser(3)); + + filmService.addLike(1, 1); + filmService.addLike(1, 2); + filmService.addLike(1, 3); + + Film filmWithLikes = filmService.findById(1); + User userWithLikes = userService.findById(2); + + assertThat(filmWithLikes.getLikes()).isEqualTo(3); + } + + @Test + public void testRemoveLike() { + filmService.create(newFilm(1)); + userService.create(newUser(1)); + userService.create(newUser(2)); + userService.create(newUser(3)); + + filmService.addLike(1, 1); + filmService.addLike(1, 2); + filmService.addLike(1, 3); + + filmService.removeLike(1, 2); + + Film filmWithoutLikes = filmService.findById(1); + User userWithoutLikes = userService.findById(2); + + assertThat(filmWithoutLikes.getLikes()).isEqualTo(2); + } + + @Test + public void testFindTopFilms() { + filmService.create(newFilm(1)); + filmService.create(newFilm(2)); + filmService.create(newFilm(3)); + filmService.create(newFilm(4)); + filmService.create(newFilm(5)); + + userService.create(newUser(1)); + userService.create(newUser(2)); + userService.create(newUser(3)); + userService.create(newUser(4)); + userService.create(newUser(5)); + userService.create(newUser(6)); + + filmService.addLike(1, 1); + filmService.addLike(1, 2); + filmService.addLike(1, 3); + filmService.addLike(1, 4); + filmService.addLike(1, 5); + filmService.addLike(1, 6); + + filmService.addLike(4, 1); + filmService.addLike(4, 2); + filmService.addLike(4, 3); + filmService.addLike(4, 4); + filmService.addLike(4, 5); + + List top = filmService.findTopFilms(2); + assertThat(top.size()).isEqualTo(2); + + ArrayList idTop = new ArrayList<>(); + for (Film film : top) { + idTop.add(film.getId()); + } + + assertThat(idTop.contains(1)).isTrue(); + assertThat(idTop.contains(4)).isTrue(); + } + + @Test + public void testGetAllGenres() { + List genres = genreDao.getAll(); + + ArrayList idGenres = new ArrayList<>(); + ArrayList namesGenres = new ArrayList<>(); + for (Genres genre : genres) { + idGenres.add(genre.getId()); + namesGenres.add(genre.getName()); + } + assertThat(idGenres.size()).isEqualTo(6); + assertThat(idGenres.contains(1)).isTrue(); + assertThat(idGenres.contains(6)).isTrue(); + assertThat(idGenres.contains(7)).isFalse(); + assertThat(namesGenres.contains("Комедия")).isTrue(); + assertThat(namesGenres.contains("Триллер")).isTrue(); + assertThat(namesGenres.contains("Пуп")).isFalse(); + } + + @Test + public void testGetGenreById() { + Genres genre = genreDao.getById(3); + + assertThat(genre.getId()).isEqualTo(3); + assertThat(genre.getName()).isEqualTo("Мультфильм"); + } + + @Test + public void testGetAllMPA() { + List mpa = mpaDao.getAll(); + + ArrayList idMpa = new ArrayList<>(); + ArrayList namesMpa = new ArrayList<>(); + for (MPA mp : mpa) { + idMpa.add(mp.getId()); + namesMpa.add(mp.getName()); + } + assertThat(idMpa.size()).isEqualTo(5); + assertThat(idMpa.contains(1)).isTrue(); + assertThat(idMpa.contains(5)).isTrue(); + assertThat(idMpa.contains(6)).isFalse(); + assertThat(namesMpa.contains("PG")).isTrue(); + assertThat(namesMpa.contains("G")).isTrue(); + assertThat(namesMpa.contains("PGG")).isFalse(); + } + + @Test + public void testGetMPAById() { + MPA mpa = mpaDao.getById(1); + assertThat(mpa.getId()).isEqualTo(1); + assertThat(mpa.getName()).isEqualTo("G"); + } }