diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..02d3f75 --- /dev/null +++ b/pom.xml @@ -0,0 +1,53 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.7.5 + + + ru.yandex.practicum + filmorate + 0.0.1-SNAPSHOT + filmorate + Кинопоиск для друзей + + 11 + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.junit.jupiter + junit-jupiter-api + 5.9.0 + test + + + + org.projectlombok + lombok + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/src/main/java/ru/yandex/practicum/filmorate/FilmorateApplication.java b/src/main/java/ru/yandex/practicum/filmorate/FilmorateApplication.java new file mode 100644 index 0000000..3c12a84 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/FilmorateApplication.java @@ -0,0 +1,13 @@ +package ru.yandex.practicum.filmorate; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class FilmorateApplication { + + public static void main(String[] args) { + SpringApplication.run(FilmorateApplication.class, args); + } + +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java new file mode 100644 index 0000000..6acb9a4 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java @@ -0,0 +1,73 @@ +package ru.yandex.practicum.filmorate.controller; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; +import ru.yandex.practicum.filmorate.exception.ValidationException; +import ru.yandex.practicum.filmorate.model.Film; + +import java.time.LocalDate; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +@Slf4j +@RestController +@RequestMapping("/films") +public class FilmController { + private final Set filmSet = new HashSet<>(); + private int id = 0; + + public int idGenerate() { + return ++id; + } + + @GetMapping + public Collection getFilms() { + return filmSet; + } + + @PostMapping + public Film create(@RequestBody Film film) { + validate(film); + film.setId(idGenerate()); + log.info("Фильм создан {}", film.toString()); + filmSet.add(film); + return film; + } + + @PutMapping + public Film updateFilm(@RequestBody Film film) { + validate(film); + for (Film films : filmSet) { + if (film.getId() == films.getId()) { + filmSet.remove(films); + filmSet.add(film); + log.info("Фильм обновлен {}", film.toString()); + } else { + throw new ResponseStatusException(HttpStatus.NOT_FOUND); + } + } + return film; + } + + private void validate(Film film) { + if (film.getName().isBlank()) { + log.info("Отсутствует название фильма {}", film.toString()); + throw new ValidationException("Название не может быть пустым"); + } + if (film.getDescription().length() > 200) { + log.info("Максимальная длина описания больше 200 символов {}", film.toString()); + throw new ValidationException("Максимальная длина описания — 200 символов"); + } + if (film.getReleaseDate().isBefore(LocalDate.of(1895, 12, 28))) { + log.info("Дата релиза 28 декабря 1895 года {}", film.toString()); + throw new ValidationException("Дата релиза не может быть раньше 28 декабря 1895 года"); + } + if (film.getDuration() < 0) { + log.info("Введена отрицательная продолжительсность фильма {}", film.toString()); + throw new ValidationException("Продолжительность фильма должна быть положительной"); + } + } +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java new file mode 100644 index 0000000..85ff7af --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java @@ -0,0 +1,72 @@ +package ru.yandex.practicum.filmorate.controller; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; +import ru.yandex.practicum.filmorate.exception.ValidationException; +import ru.yandex.practicum.filmorate.model.User; + +import java.time.LocalDate; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +@Slf4j +@RestController +@RequestMapping("/users") +public class UserController { + private Set userSet = new HashSet<>(); + private int id = 0; + + public int idGenerate() { + return ++id; + } + + @GetMapping + public Collection users() { + return userSet; + } + + @PostMapping + public User newUser(@RequestBody User user) { + validate(user); + if (user.getName() == null || user.getName().isEmpty() || user.getName().isBlank()) { + user.setName(user.getLogin()); + } + user.setId(idGenerate()); + userSet.add(user); + log.info("Пользователь {} создан.", user.toString()); + return user; + } + + @PutMapping + public User updateUser(@RequestBody User user) { + validate(user); + for (User users : userSet) { + if (user.getId() == users.getId()) { + userSet.remove(users); + userSet.add(user); + log.info("Пользователь {} обновлен.", user.toString()); + } else { + throw new ResponseStatusException(HttpStatus.NOT_FOUND); + } + } + return user; + } + + public void validate(User user) { + if (user.getEmail().isBlank() || !user.getEmail().contains("@")) { + log.info("Отсутствует электронная почта {}", user.toString()); + throw new ValidationException("Электронная почта не может быть пустой или должна содержать символ @"); + } + if (user.getLogin().isBlank() || user.getLogin().contains(" ")) { + log.info("Отсутствует логин {}", user.toString()); + throw new ValidationException("Логин не может быть пустым и содержать пробелы"); + } + if (user.getBirthday().isAfter(LocalDate.now())) { + log.info("Введена не корректная дата рождения {}", user.toString()); + throw new ValidationException("Дата рождения не может быть в будущем"); + } + } +} \ No newline at end of file diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/ValidationException.java b/src/main/java/ru/yandex/practicum/filmorate/exception/ValidationException.java new file mode 100644 index 0000000..52dc49c --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/exception/ValidationException.java @@ -0,0 +1,7 @@ +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/model/Film.java b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java new file mode 100644 index 0000000..9b15e99 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java @@ -0,0 +1,18 @@ +package ru.yandex.practicum.filmorate.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NonNull; + +import java.time.LocalDate; + +@Data +@AllArgsConstructor +public class Film { + private Integer id; + @NonNull + private String name; + private String description; + private LocalDate releaseDate; + private Integer duration; +} diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/User.java b/src/main/java/ru/yandex/practicum/filmorate/model/User.java new file mode 100644 index 0000000..45c2d91 --- /dev/null +++ b/src/main/java/ru/yandex/practicum/filmorate/model/User.java @@ -0,0 +1,16 @@ +package ru.yandex.practicum.filmorate.model; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.time.LocalDate; + +@Data +@AllArgsConstructor +public class User { + private Integer id; + private String email; + private String login; + private String name; + private LocalDate birthday; +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1 @@ + diff --git a/src/test/java/ru/yandex/practicum/filmorate/FilmorateApplicationTests.java b/src/test/java/ru/yandex/practicum/filmorate/FilmorateApplicationTests.java new file mode 100644 index 0000000..dc5cfdf --- /dev/null +++ b/src/test/java/ru/yandex/practicum/filmorate/FilmorateApplicationTests.java @@ -0,0 +1,13 @@ +package ru.yandex.practicum.filmorate; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class FilmorateApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/src/test/java/ru/yandex/practicum/filmorate/ValidateTest.java b/src/test/java/ru/yandex/practicum/filmorate/ValidateTest.java new file mode 100644 index 0000000..641a2ea --- /dev/null +++ b/src/test/java/ru/yandex/practicum/filmorate/ValidateTest.java @@ -0,0 +1,156 @@ +package ru.yandex.practicum.filmorate; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.function.Executable; +import ru.yandex.practicum.filmorate.controller.FilmController; +import ru.yandex.practicum.filmorate.controller.UserController; +import ru.yandex.practicum.filmorate.exception.ValidationException; +import ru.yandex.practicum.filmorate.model.Film; +import ru.yandex.practicum.filmorate.model.User; + +import java.time.LocalDate; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class ValidateTest { + + @Test + public void createdFilmTest() { + final FilmController film = new FilmController(); + Film fm = new Film(1, "Я Легенда", "Фильм про зомби", LocalDate.of(2010, 12, + 24), 90); + film.create(fm); + assertEquals(1, film.getFilms().size(), "Фильм не создан"); + } + + @Test + public void notNameFilmTest() { + final FilmController film = new FilmController(); + Film fm = new Film(1, "", "Фильм про зомби", LocalDate.of(2010, 12, 24), + 90); + final ValidationException ex = assertThrows(ValidationException.class, + new Executable() { + @Override + public void execute() throws Throwable { + film.create(fm); + } + }); + assertEquals("Название не может быть пустым", ex.getMessage()); + } + + @Test + public void maxSimFilmTest() { + final FilmController film = new FilmController(); + Film fm = new Film(1, "Я Легенда", + "Фильм про зомбииииииииииииииииииииииииииииииииииииииииииииииииииииииииииииии" + + "ииииииииииииииииииииииииииииииииииииииииииииииииииииииииииииииииииииииииииииииии" + + "иииииииииииииииииииииииииииииииииииииииииииииииииииииииииииииииии", + LocalDate.of(2010, 12, 24), 90); + final ValidationException ex = assertThrows(ValidationException.class, + new Executable() { + @Override + public void execute() throws Throwable { + film.create(fm); + } + }); + assertEquals("Максимальная длина описания — 200 символов", ex.getMessage()); + } + + @Test + public void dataFilmTest() { + final FilmController film = new FilmController(); + Film fm = new Film(1, "Я Легенда", "Фильм про зомби", LocalDate.of(1800, 12, 24), + 90); + final ValidationException ex = assertThrows(ValidationException.class, + new Executable() { + @Override + public void execute() throws Throwable { + film.create(fm); + } + }); + assertEquals("Дата релиза не может быть раньше 28 декабря 1895 года", ex.getMessage()); + } + + @Test + public void durationFilmTest() { + final FilmController film = new FilmController(); + Film fm = new Film(1, "Я Легенда", "Фильм про зомби", LocalDate.of(2010, 12, 24), + -1); + final ValidationException ex = assertThrows(ValidationException.class, + new Executable() { + @Override + public void execute() throws Throwable { + film.create(fm); + } + }); + assertEquals("Продолжительность фильма должна быть положительной", ex.getMessage()); + } + + @Test + public void createdUserTest() { + UserController uc = new UserController(); + User user = new User(1, "maks@yandex.ru", "maks_1992", "Maksim", + LocalDate.of(1992, 12, 24)); + uc.newUser(user); + assertEquals(1, uc.users().size(), "Пользователь не создан"); + } + + @Test + public void mailUserTest() { + UserController uc = new UserController(); + User user = new User(1, "maksyandex.ru", "maks_1992", "Maksim", + LocalDate.of(1992, 12, 24)); + final ValidationException ex = assertThrows(ValidationException.class, + new Executable() { + @Override + public void execute() throws Throwable { + uc.newUser(user); + } + }); + assertEquals("Электронная почта не может быть пустой или должна содержать символ @", + ex.getMessage()); + } + + @Test + public void loginUserTest() { + UserController uc = new UserController(); + User user = new User(1, "maks@yandex.ru", "", "Maksim", + LocalDate.of(1992, 12, 24)); + final ValidationException ex = assertThrows(ValidationException.class, + new Executable() { + @Override + public void execute() throws Throwable { + uc.newUser(user); + } + }); + assertEquals("Логин не может быть пустым и содержать пробелы", + ex.getMessage()); + } + + @Test + public void bdUserTest() { + UserController uc = new UserController(); + User user = new User(1, "maks@yandex.ru", "maks_1992", "Maksim", + LocalDate.of(2025, 12, 24)); + final ValidationException ex = assertThrows(ValidationException.class, + new Executable() { + @Override + public void execute() throws Throwable { + uc.newUser(user); + } + }); + assertEquals("Дата рождения не может быть в будущем", + ex.getMessage()); + } + + @Test + public void createdUserNotNameTest() { + UserController uc = new UserController(); + User user = new User(1, "maks@yandex.ru", "maks_1992", "", + LocalDate.of(1992, 12, 24)); + uc.newUser(user); + assertEquals("maks_1992", user.getName(), "Не назначено имя"); + } +} +