Repository: n00bertb/java-filmorate
Pull request #2: первая попытка сдать финальное задание 10го спринта
Author: login: n00bertb
Created: 2025-03-09T10:39:50Z | Merged: 2025-03-12T11:44:52Z

первая попытка сдать финальное задание 10го спринта


Diff:
diff --git a/.idea/.gitignore b/.idea/.gitignore
deleted file mode 100644
index 26d3352..0000000
--- a/.idea/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
deleted file mode 100644
index 1147447..0000000
--- a/.idea/compiler.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="CompilerConfiguration">
-    <annotationProcessing>
-      <profile default="true" name="Default" enabled="true" />
-      <profile name="Maven default annotation processors profile" enabled="true">
-        <sourceOutputDir name="target/generated-sources/annotations" />
-        <sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
-        <outputRelativeToContentRoot value="true" />
-        <module name="filmorate" />
-      </profile>
-    </annotationProcessing>
-  </component>
-  <component name="JavacSettings">
-    <option name="ADDITIONAL_OPTIONS_OVERRIDE">
-      <module name="filmorate" options="-parameters" />
-    </option>
-  </component>
-</project>
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
deleted file mode 100644
index 63e9001..0000000
--- a/.idea/encodings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="Encoding">
-    <file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
-  </component>
-</project>
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
deleted file mode 100644
index 712ab9d..0000000
--- a/.idea/jarRepositories.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="RemoteRepositoriesConfiguration">
-    <remote-repository>
-      <option name="id" value="central" />
-      <option name="name" value="Central Repository" />
-      <option name="url" value="https://repo.maven.apache.org/maven2" />
-    </remote-repository>
-    <remote-repository>
-      <option name="id" value="central" />
-      <option name="name" value="Maven Central repository" />
-      <option name="url" value="https://repo1.maven.org/maven2" />
-    </remote-repository>
-    <remote-repository>
-      <option name="id" value="jboss.community" />
-      <option name="name" value="JBoss Community repository" />
-      <option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
-    </remote-repository>
-  </component>
-</project>
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index 5ed0e80..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="ExternalStorageConfigurationManager" enabled="true" />
-  <component name="MavenProjectsManager">
-    <option name="originalFiles">
-      <list>
-        <option value="$PROJECT_DIR$/pom.xml" />
-      </list>
-    </option>
-  </component>
-  <component name="ProjectRootManager" version="2" project-jdk-name="corretto-21" project-jdk-type="JavaSDK" />
-</project>
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 94a25f7..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="VcsDirectoryMappings">
-    <mapping directory="$PROJECT_DIR$" vcs="Git" />
-  </component>
-</project>
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 0cad031..b733dbd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,46 +1,55 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-		 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
-	<modelVersion>4.0.0</modelVersion>
-	<parent>
-		<groupId>org.springframework.boot</groupId>
-		<artifactId>spring-boot-starter-parent</artifactId>
-		<version>3.2.4</version>
-		<relativePath/> <!-- lookup parent from repository -->
-	</parent>
-	<groupId>ru.yandex.practicum</groupId>
-	<artifactId>filmorate</artifactId>
-	<version>0.0.1-SNAPSHOT</version>
-	<name>filmorate</name>
-	<description>filmorate</description>
-	<properties>
-		<java.version>21</java.version>
-	</properties>
-	<dependencies>
-		<dependency>
-			<groupId>org.springframework.boot</groupId>
-			<artifactId>spring-boot-starter-web</artifactId>
-		</dependency>
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>3.2.4</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+    <groupId>ru.yandex.practicum</groupId>
+    <artifactId>filmorate</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <name>filmorate</name>
+    <description>filmorate</description>
+    <properties>
+        <java.version>21</java.version>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
 
-		<dependency>
-			<groupId>org.projectlombok</groupId>
-			<artifactId>lombok</artifactId>
-			<scope>provided</scope>
-		</dependency>
-		<dependency>
-			<groupId>org.springframework.boot</groupId>
-			<artifactId>spring-boot-starter-test</artifactId>
-			<scope>test</scope>
-		</dependency>
-	</dependencies>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>jakarta.validation</groupId>
+            <artifactId>jakarta.validation-api</artifactId>
+            <version>3.0.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+    </dependencies>
 
-	<build>
-		<plugins>
-			<plugin>
-				<groupId>org.springframework.boot</groupId>
-				<artifactId>spring-boot-maven-plugin</artifactId>
-			</plugin>
-		</plugins>
-	</build>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
 
-</project>
+</project>
\ No newline at end of file
diff --git a/src/main/java/ru/yandex/practicum/filmorate/FilmorateApplication.java b/src/main/java/ru/yandex/practicum/filmorate/FilmorateApplication.java
index dca451b..e58f423 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/FilmorateApplication.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/FilmorateApplication.java
@@ -9,4 +9,4 @@ public static void main(String[] args) {
 		SpringApplication.run(FilmorateApplication.class, args);
 	}
 
-}
+}
\ No newline at end of file
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 e69de29..2849fe0 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java
@@ -0,0 +1,63 @@
+package ru.yandex.practicum.filmorate.controller;
+
+import lombok.extern.slf4j.Slf4j;
+import jakarta.validation.Valid;
+import org.springframework.web.bind.annotation.*;
+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.HashMap;
+import java.util.Map;
+
+@RestController
+@Slf4j
+@RequestMapping("/films")
+public class FilmController {
+    private final LocalDate filmBirthday = LocalDate.of(1895, 12, 28);
+    private final Map<Integer, Film> films = new HashMap();
+    private int current = 0;
+
+    @GetMapping
+    public Collection<Film> getAllUsers() {
+        return films.values();
+    }
+
+    @PostMapping
+    public Film create(@RequestBody @Valid Film film) {
+        if (film.getReleaseDate().isBefore(filmBirthday)) {
+            log.error("Ошибка создания сущности {}", film);
+            throw new ValidationException("Дата релиза — не раньше 28 декабря 1895 года!");
+        } else {
+            film.setId(++current);
+            films.put(film.getId(), film);
+            log.info("Сущность успешно создана: id {}", film.getId());
+            log.debug("film: {}", film);
+            return film;
+        }
+    }
+
+    @PutMapping
+    public Film update(@RequestBody @Valid Film newFilm) {
+        if (films.containsKey(newFilm.getId())) {
+            if (newFilm.getReleaseDate().isBefore(filmBirthday)) {
+                log.error("Ошибка обновления сущности:{}", newFilm);
+                throw new ValidationException("Дата релиза — не раньше 28 декабря 1895 года!");
+            } else {
+                Film oldFilm = films.get(newFilm.getId());
+                oldFilm.setName(newFilm.getName());
+                oldFilm.setDescription(newFilm.getDescription());
+                oldFilm.setReleaseDate(newFilm.getReleaseDate());
+                oldFilm.setDuration(newFilm.getDuration());
+                films.put(oldFilm.getId(), oldFilm);
+                log.info("Сущность успешно обновлена: id={}", oldFilm.getId());
+                log.debug("film: {}", oldFilm);
+                return oldFilm;
+            }
+        } else {
+            throw new ValidationException("Такого фильма нет в списке!");
+        }
+    }
+}
\ No newline at end of file
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 e69de29..3396de5 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java
@@ -0,0 +1,60 @@
+package ru.yandex.practicum.filmorate.controller;
+
+import lombok.extern.slf4j.Slf4j;
+import jakarta.validation.Valid;
+import org.springframework.web.bind.annotation.*;
+import ru.yandex.practicum.filmorate.exception.ValidationException;
+import ru.yandex.practicum.filmorate.model.User;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+@RestController
+@Slf4j
+@RequestMapping("/users")
+public class UserController {
+    private final Map<Integer, User> users = new HashMap();
+    private int current = 0;
+
+    @GetMapping
+    public Collection<User> getAllUsers() {
+        return users.values();
+    }
+
+    @PostMapping
+    public User create(@RequestBody @Valid User user) {
+        user.setId(++current);
+        if (user.getName() == null) {
+            user.setName(user.getLogin());
+        }
+
+        users.put(user.getId(), user);
+        log.info("Сущность успешно создана: id {}", user.getId());
+        log.debug("user: {}", user);
+        return user;
+    }
+
+    @PutMapping
+    public User update(@RequestBody @Valid User newUser) {
+        if (users.containsKey(newUser.getId())) {
+            User oldUser = users.get(newUser.getId());
+            if (newUser.getName() == null) {
+                newUser.setName(newUser.getLogin());
+                oldUser.setName(newUser.getName());
+            } else {
+                oldUser.setName(newUser.getName());
+            }
+
+            oldUser.setEmail(newUser.getEmail());
+            oldUser.setLogin(newUser.getLogin());
+            oldUser.setBirthday(newUser.getBirthday());
+            users.put(oldUser.getId(), oldUser);
+            log.info("Сущность успешно обновлена: id {}", oldUser.getId());
+            log.debug("user: {}", oldUser);
+            return oldUser;
+        } else {
+            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
index e69de29..532f9bd 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/exception/ValidationException.java
+++ 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);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java
index e69de29..6336f5a 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java
@@ -0,0 +1,26 @@
+package ru.yandex.practicum.filmorate.model;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Positive;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.time.LocalDate;
+
+@Data
+public class Film {
+    @EqualsAndHashCode.Include
+    private int id;
+    @NotBlank(message = "Название не может быть пустым!")
+    @EqualsAndHashCode.Exclude
+    private String name;
+    @Size(max = 200, message = "Максимальная длина описания — 200 символов!")
+    @EqualsAndHashCode.Exclude
+    private String description;
+    @EqualsAndHashCode.Exclude
+    private LocalDate releaseDate;
+    @Positive(message = "Продолжительность фильма должна быть положительным числом!")
+    @EqualsAndHashCode.Exclude
+    private int duration;
+}
\ No newline at end of file
diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/User.java b/src/main/java/ru/yandex/practicum/filmorate/model/User.java
index e69de29..1b70f84 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/model/User.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/model/User.java
@@ -0,0 +1,27 @@
+package ru.yandex.practicum.filmorate.model;
+
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Past;
+import java.time.LocalDate;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Data
+public class User {
+    @EqualsAndHashCode.Include
+    private int id;
+    @NotBlank(message = "Электронная почта не может быть пустой!")
+    @Email(message = "Введенный email не соответствует формату email-адресов!")
+    @EqualsAndHashCode.Exclude
+    private String email;
+    @NotBlank(message = "Логин не может быть пустым и содержать пробелы!")
+    @EqualsAndHashCode.Exclude
+    private String login;
+    @EqualsAndHashCode.Exclude
+    private String name;
+    @Past(message = "Дата рождения не может быть в будущем!")
+    @EqualsAndHashCode.Exclude
+    private LocalDate birthday;
+}
\ No newline at end of file
diff --git a/src/test/java/ru/yandex/practicum/filmorate/FilmControllerValidationTests.java b/src/test/java/ru/yandex/practicum/filmorate/FilmControllerValidationTests.java
index e69de29..ee552e6 100644
--- a/src/test/java/ru/yandex/practicum/filmorate/FilmControllerValidationTests.java
+++ b/src/test/java/ru/yandex/practicum/filmorate/FilmControllerValidationTests.java
@@ -0,0 +1,167 @@
+package ru.yandex.practicum.filmorate;
+
+import jakarta.validation.ConstraintViolation;
+import jakarta.validation.Validation;
+import jakarta.validation.Validator;
+import jakarta.validation.ValidatorFactory;
+import java.util.Set;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import ru.yandex.practicum.filmorate.controller.FilmController;
+import ru.yandex.practicum.filmorate.exception.ValidationException;
+import ru.yandex.practicum.filmorate.model.Film;
+import java.time.LocalDate;
+
+
+@SpringBootTest
+class FilmControllerValidationTests {
+
+    private FilmController filmController;
+    private Film validFilm;
+    private static final LocalDate FILM_BIRTHDAY = LocalDate.of(1895, 12, 28);
+    private final ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
+    private final Validator validator = factory.getValidator();
+
+    @BeforeEach
+    void setUp() {
+        filmController = new FilmController();
+        validFilm = new Film();
+        validFilm.setName("Test Film");
+        validFilm.setDescription("Test Description");
+        validFilm.setReleaseDate(LocalDate.of(2000, 1, 1));
+        validFilm.setDuration(120);
+    }
+
+    @Test
+    void createValidFilm() {
+        Film createdFilm = filmController.create(validFilm);
+        Assertions.assertNotNull(createdFilm.getId());
+        Assertions.assertEquals(validFilm.getName(), createdFilm.getName());
+    }
+
+    @Test
+    void createFilmWhenNameIsBlank() {
+        validFilm.setName(" ");
+        Set<ConstraintViolation<Film>> violations = validator.validate(validFilm);
+        Assertions.assertFalse(violations.isEmpty(), "Фильм с пустым именем не должен создаваться");
+    }
+
+    @Test
+    void createFilmWhenNameIsNull() {
+        validFilm.setName(null);
+        Set<ConstraintViolation<Film>> violations = validator.validate(validFilm);
+        Assertions.assertFalse(violations.isEmpty(), "Фильм с пустым именем не должен создаваться");
+    }
+
+    @Test
+    void createFilmWhenDescriptionIsTooLong() {
+        validFilm.setDescription("a".repeat(201));
+        Set<ConstraintViolation<Film>> violations = validator.validate(validFilm);
+        Assertions.assertFalse(violations.isEmpty(), "Превышена длинна описания в 200 символов");
+    }
+
+    @Test
+    void createFilmWhenReleaseDateIsBeforeFilmBirthday() {
+        validFilm.setReleaseDate(FILM_BIRTHDAY.minusDays(1L));
+        Assertions.assertThrows(ValidationException.class, () -> {
+            filmController.create(validFilm);
+        });
+    }
+
+    @Test
+    void createFilmWhenReleaseDateIsFilmBirthday() {
+        validFilm.setReleaseDate(FILM_BIRTHDAY);
+        Film createdFilm = filmController.create(validFilm);
+        Assertions.assertNotNull(createdFilm.getId());
+        Assertions.assertEquals(validFilm.getReleaseDate(), createdFilm.getReleaseDate());
+    }
+
+    @Test
+    void createFilmWhenDurationIsNegative() {
+        validFilm.setDuration(-1);
+        Set<ConstraintViolation<Film>> violations = validator.validate(validFilm);
+        Assertions.assertFalse(violations.isEmpty(), "Продолжительность фильма отрицательное число");
+    }
+
+    @Test
+    void createFilmWhenDurationIsZero() {
+        validFilm.setDuration(0);
+        Set<ConstraintViolation<Film>> violations = validator.validate(validFilm);
+        Assertions.assertFalse(violations.isEmpty(), "Продолжительность фильма равна нулю");
+    }
+
+    @Test
+    void updateFilmWhenFilmIsValid() {
+        Film createdFilm = filmController.create(validFilm);
+        createdFilm.setName("Updated Film Name");
+        Film updatedFilm = filmController.update(createdFilm);
+        Assertions.assertEquals("Updated Film Name", updatedFilm.getName());
+    }
+
+    @Test
+    void updateFilmWhenIdIsInvalid() {
+        validFilm.setId(9999);
+        Assertions.assertThrows(ValidationException.class, () -> {
+            filmController.update(validFilm);
+        });
+    }
+
+    @Test
+    void updateFilmWhenNameIsBlank() {
+        Film createdFilm = filmController.create(validFilm);
+        createdFilm.setName(" ");
+        Set<ConstraintViolation<Film>> violations = validator.validate(createdFilm);
+        Assertions.assertFalse(violations.isEmpty(), "Пустое имя фильма при обновлении");
+    }
+
+    @Test
+    void updateFilmWhenNameIsNull() {
+        Film createdFilm = filmController.create(validFilm);
+        createdFilm.setName(null);
+        Set<ConstraintViolation<Film>> violations = validator.validate(createdFilm);
+        Assertions.assertFalse(violations.isEmpty(), "Пустое имя фильма при обновлении");
+    }
+
+    @Test
+    void updateFilmWhenDescriptionIsTooLong() {
+        Film createdFilm = filmController.create(validFilm);
+        createdFilm.setDescription("a".repeat(201));
+        Set<ConstraintViolation<Film>> violations = validator.validate(createdFilm);
+        Assertions.assertFalse(violations.isEmpty(), "Превышена длинна описания в 200 символов при обновлении фильма");
+    }
+
+    @Test
+    void updateFilmWhenDescriptionIs200Char() {
+        Film createdFilm = filmController.create(validFilm);
+        createdFilm.setDescription("a".repeat(200));
+        Film updatedFilm = filmController.update(createdFilm);
+        Assertions.assertEquals(createdFilm.getDescription(), updatedFilm.getDescription());
+    }
+
+    @Test
+    void updateFilmWhenReleaseDateIsBeforeFilmBirthday() {
+        Film createdFilm = filmController.create(validFilm);
+        createdFilm.setReleaseDate(FILM_BIRTHDAY.minusDays(1L));
+        Assertions.assertThrows(ValidationException.class, () -> {
+            filmController.update(createdFilm);
+        });
+    }
+
+    @Test
+    void updateFilmWhenDurationIsNegative() {
+        Film createdFilm = filmController.create(validFilm);
+        createdFilm.setDuration(-1);
+        Set<ConstraintViolation<Film>> violations = validator.validate(createdFilm);
+        Assertions.assertFalse(violations.isEmpty(), "Продолжительность фильма отрицательное число при обновлении");
+    }
+
+    @Test
+    void updateFilmWhenDurationIsZero() {
+        Film createdFilm = filmController.create(validFilm);
+        createdFilm.setDuration(0);
+        Set<ConstraintViolation<Film>> violations = validator.validate(validFilm);
+        Assertions.assertFalse(violations.isEmpty(), "Продолжительность фильма равна нулю при обновлении");
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/ru/yandex/practicum/filmorate/FilmorateApplicationTests.java b/src/test/java/ru/yandex/practicum/filmorate/FilmorateApplicationTests.java
index 660412e..48dd76e 100644
--- a/src/test/java/ru/yandex/practicum/filmorate/FilmorateApplicationTests.java
+++ b/src/test/java/ru/yandex/practicum/filmorate/FilmorateApplicationTests.java
@@ -10,4 +10,4 @@ class FilmorateApplicationTests {
 	void contextLoads() {
 	}
 
-}
+}
\ No newline at end of file
diff --git a/src/test/java/ru/yandex/practicum/filmorate/UserControllerValidationTests.java b/src/test/java/ru/yandex/practicum/filmorate/UserControllerValidationTests.java
index e69de29..4966865 100644
--- a/src/test/java/ru/yandex/practicum/filmorate/UserControllerValidationTests.java
+++ b/src/test/java/ru/yandex/practicum/filmorate/UserControllerValidationTests.java
@@ -0,0 +1,116 @@
+package ru.yandex.practicum.filmorate;
+
+import jakarta.validation.ConstraintViolation;
+import jakarta.validation.Validation;
+import jakarta.validation.Validator;
+import jakarta.validation.ValidatorFactory;
+import java.time.LocalDate;
+import java.util.Set;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import ru.yandex.practicum.filmorate.controller.UserController;
+import ru.yandex.practicum.filmorate.exception.ValidationException;
+import ru.yandex.practicum.filmorate.model.User;
+
+
+@SpringBootTest
+class UserControllerValidationTests {
+
+    private UserController userController;
+    private User validUser;
+    private final ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
+    private final Validator validator = factory.getValidator();
+
+    @BeforeEach
+    void setUp() {
+        userController = new UserController();
+        validUser = new User();
+        validUser.setEmail("test@example.com");
+        validUser.setLogin("testLogin");
+        validUser.setName("Test User");
+        validUser.setBirthday(LocalDate.of(2000, 1, 1));
+    }
+
+    @Test
+    void createValidUser() {
+        User createdUser = userController.create(validUser);
+        Assertions.assertNotNull(createdUser.getId());
+        Assertions.assertEquals(validUser.getEmail(), createdUser.getEmail());
+    }
+
+    @Test
+    void createUserInvalidEmail() {
+        validUser.setEmail("invalid-email");
+        Set<ConstraintViolation<User>> violations = validator.validate(validUser);
+        Assertions.assertFalse(violations.isEmpty(), "Невалидный email при создании пользователя");
+    }
+
+    @Test
+    void createUserBlankEmail() {
+        validUser.setEmail(" ");
+        Set<ConstraintViolation<User>> violations = validator.validate(validUser);
+        Assertions.assertFalse(violations.isEmpty(), "Пустой email при создании пользователя");
+    }
+
+    @Test
+    void createUserNullEmail() {
+        validUser.setEmail(null);
+        Set<ConstraintViolation<User>> violations = validator.validate(validUser);
+        Assertions.assertFalse(violations.isEmpty(), "Пустой email при создании пользователя");
+    }
+
+    @Test
+    void createUserBlankLogin() {
+        validUser.setLogin(" ");
+        Set<ConstraintViolation<User>> violations = validator.validate(validUser);
+        Assertions.assertFalse(violations.isEmpty(), "Пустой логин пользователя");
+    }
+
+    @Test
+    void createUserNullLogin() {
+        validUser.setLogin(null);
+        Set<ConstraintViolation<User>> violations = validator.validate(validUser);
+        Assertions.assertFalse(violations.isEmpty(), "Пустой логин пользователя");
+    }
+
+    @Test
+    void createUserFutureBirthday() {
+        validUser.setBirthday(LocalDate.now().plusDays(1L));
+        Set<ConstraintViolation<User>> violations = validator.validate(validUser);
+        Assertions.assertFalse(violations.isEmpty(), "День рождения пользователя в будущем");
+    }
+
+    @Test
+    void updateUserValidUser() {
+        User createdUser = userController.create(validUser);
+        createdUser.setName("Updated Name");
+        User updatedUser = userController.update(createdUser);
+        Assertions.assertEquals("Updated Name", updatedUser.getName());
+    }
+
+    @Test
+    void updateUserInvalidEmail() {
+        User createdUser = userController.create(validUser);
+        createdUser.setEmail("invalid-email");
+        Set<ConstraintViolation<User>> violations = validator.validate(createdUser);
+        Assertions.assertFalse(violations.isEmpty(), "Невалидный email при обновлении пользователя");
+    }
+
+    @Test
+    void updateUserInvalidId() {
+        validUser.setId(9999);
+        Assertions.assertThrows(ValidationException.class, () -> {
+            userController.update(validUser);
+        });
+    }
+
+    @Test
+    void updateUserFutureBirthday() {
+        User createdUser = userController.create(validUser);
+        createdUser.setBirthday(LocalDate.now().plusDays(1L));
+        Set<ConstraintViolation<User>> violations = validator.validate(createdUser);
+        Assertions.assertFalse(violations.isEmpty(), "День рождения пользователя в будущем при обновлении");
+    }
+}
\ No newline at end of file
diff --git a/target/classes/application.properties b/target/classes/application.properties
deleted file mode 100644
index 8b13789..0000000
--- a/target/classes/application.properties
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/target/classes/ru/yandex/practicum/filmorate/FilmorateApplication.class b/target/classes/ru/yandex/practicum/filmorate/FilmorateApplication.class
deleted file mode 100644
index b8979b4..0000000
Binary files a/target/classes/ru/yandex/practicum/filmorate/FilmorateApplication.class and /dev/null differ
diff --git a/target/classes/ru/yandex/practicum/filmorate/controller/FilmController.class b/target/classes/ru/yandex/practicum/filmorate/controller/FilmController.class
deleted file mode 100644
index a28616d..0000000
Binary files a/target/classes/ru/yandex/practicum/filmorate/controller/FilmController.class and /dev/null differ
diff --git a/target/classes/ru/yandex/practicum/filmorate/controller/UserController.class b/target/classes/ru/yandex/practicum/filmorate/controller/UserController.class
deleted file mode 100644
index 1b33260..0000000
Binary files a/target/classes/ru/yandex/practicum/filmorate/controller/UserController.class and /dev/null differ
diff --git a/target/classes/ru/yandex/practicum/filmorate/exception/ValidationException.class b/target/classes/ru/yandex/practicum/filmorate/exception/ValidationException.class
deleted file mode 100644
index 8d7e669..0000000
Binary files a/target/classes/ru/yandex/practicum/filmorate/exception/ValidationException.class and /dev/null differ
diff --git a/target/classes/ru/yandex/practicum/filmorate/model/Film.class b/target/classes/ru/yandex/practicum/filmorate/model/Film.class
deleted file mode 100644
index 367da22..0000000
Binary files a/target/classes/ru/yandex/practicum/filmorate/model/Film.class and /dev/null differ
diff --git a/target/classes/ru/yandex/practicum/filmorate/model/User.class b/target/classes/ru/yandex/practicum/filmorate/model/User.class
deleted file mode 100644
index 6e779b2..0000000
Binary files a/target/classes/ru/yandex/practicum/filmorate/model/User.class and /dev/null differ
diff --git a/target/test-classes/ru/yandex/practicum/filmorate/FilmControllerValidationTests.class b/target/test-classes/ru/yandex/practicum/filmorate/FilmControllerValidationTests.class
deleted file mode 100644
index 937b35d..0000000
Binary files a/target/test-classes/ru/yandex/practicum/filmorate/FilmControllerValidationTests.class and /dev/null differ
diff --git a/target/test-classes/ru/yandex/practicum/filmorate/FilmorateApplicationTests.class b/target/test-classes/ru/yandex/practicum/filmorate/FilmorateApplicationTests.class
deleted file mode 100644
index 2a36018..0000000
Binary files a/target/test-classes/ru/yandex/practicum/filmorate/FilmorateApplicationTests.class and /dev/null differ
diff --git a/target/test-classes/ru/yandex/practicum/filmorate/UserControllerValidationTests.class b/target/test-classes/ru/yandex/practicum/filmorate/UserControllerValidationTests.class
deleted file mode 100644
index bbf8ce5..0000000
Binary files a/target/test-classes/ru/yandex/practicum/filmorate/UserControllerValidationTests.class and /dev/null differ


Reviews:
user: login: mikita95
body: Из вашего сообщения я понял, что вы случайно закоммитили изменения в main. Сейчас сложно будет проверить эти изменения. Вы можете откатить (revert) комитет в main, задушить этот откат и создать пулл реквест ещё раз. Если не совсем понятно, то можно обратиться к наставнику или написать мне :)
state: CHANGES_REQUESTED
author_association: NONE
submitted_at: 2025-03-10T08:55:34Z
user: login: mikita95
body: Все сделано хорошо :) Оставил пару рекомендаций 
state: CHANGES_REQUESTED
author_association: NONE
submitted_at: 2025-03-11T08:28:47Z
user: login: mikita95
body: Можно мержить :) Все отлично :)
Единственное, что сборка не проходит. Стоит использовать.
state: APPROVED
author_association: NONE
submitted_at: 2025-03-12T09:24:46Z

Review comments:
diff_hunk: @@ -0,0 +1,65 @@
+package ru.yandex.practicum.filmorate.controller;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+import ru.yandex.practicum.filmorate.exception.ValidationException;
+import ru.yandex.practicum.filmorate.model.Film;
+import org.springframework.util.StringUtils;
+
+import java.time.LocalDate;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+@RestController
+@Slf4j
+@RequestMapping("/films")
+public class FilmController {
+    private final LocalDate filmBirthday = LocalDate.of(1895, 12, 28);
+    private final Map<Integer, Film> films = new HashMap<>();
path: src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java
user: login: mikita95
body: Лучше было бы вынести логику хранения данных в отдельный класс - так было бы аккуратнее и проще поддерживать 
created_at: 2025-03-11T08:27:17Z
author_association: NONE
diff_hunk: @@ -0,0 +1,65 @@
+package ru.yandex.practicum.filmorate.controller;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+import ru.yandex.practicum.filmorate.exception.ValidationException;
+import ru.yandex.practicum.filmorate.model.Film;
+import org.springframework.util.StringUtils;
+
+import java.time.LocalDate;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+@RestController
+@Slf4j
+@RequestMapping("/films")
+public class FilmController {
+    private final LocalDate filmBirthday = LocalDate.of(1895, 12, 28);
+    private final Map<Integer, Film> films = new HashMap<>();
+    private int current = 0;
+
+    @GetMapping
+    public Collection<Film> getAllUsers() {
+        return films.values();
+    }
+
+    @PostMapping
+    public Film create(@RequestBody Film film) {
+        if (!StringUtils.hasText(film.getName())
path: src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java
user: login: mikita95
body: Валидацию можно было бы вынести с отдельные методы - так код было бы более читаемым
created_at: 2025-03-11T08:28:27Z
author_association: NONE

PR comments:
user: login: n00bertb
created_at: 2025-03-09T10:54:03Z
body: У меня из-за смены пароля возникла проблема при создании пул реквеста с последующим мержем в main.
Ловил сообщеньку при попытке открыть пул реквест There isn’t anything to compare. main and master are entirely different commit histories.
В итоге по мануалам что-то нахимичил и по новой сделал пулреквест, но придется разворачивать все файлы т.к. я посути пробелы закомитил во всех файлах.

author_association: OWNER
user: login: n00bertb
created_at: 2025-03-10T10:00:29Z
body: Так я приболел и реально туплю,
Собственно последний комит [11ccc1d](https://github.com/n00bertb/java-filmorate/pull/2/commits/11ccc1d0cb9872dee4d4762c116438b9f7bb8d6c) посути содержит мои изменения в рамках задания, так норм будет?

Посути не нужно будет реверт делать и вот это вот все.
author_association: OWNER
user: login: n00bertb
created_at: 2025-03-10T12:03:07Z
body: и можно просто на Ты, а то я кринжую) когда ко мне на Вы обращаются и просто чувствую себя старым дедом
author_association: OWNER
user: login: n00bertb
created_at: 2025-03-11T15:54:16Z
body: Я тут сделал какую то дичь и теперь не понимаю как мне ее пофиксить( нужна помощь
Проверка жалуется на то что мне нужно удалить двоичные файлы которые я по ошибке закомитил ранее в https://github.com/n00bertb/java-filmorate/pull/2/commits/aa038392139192e6565aac26c501b592b9a5ed03.
Pull request содержит двоичные файлы. Удалите их (*.class, *.jar, *.DS_Store ...) из PR
Сами правки по ревью находятся в комите https://github.com/n00bertb/java-filmorate/pull/2/commits/84140836d72caad31fad4188ddcf0230e742dd5c

Я нагуглил что можно сделать еще красивее и валидировать сами поля непосредственно и тем самым избавиться от стремного ифа.
Про хранение данных не соглашусь в тексте задания было явно:
![изображение](https://github.com/user-attachments/assets/a40f32e8-15a8-4b95-859b-e252fea0f241)
Я так понял твоя отсылка к следующей теме про внедренние зависимостей?

author_association: OWNER
user: login: mikita95
created_at: 2025-03-12T09:27:26Z
body: > Я тут сделал какую то дичь и теперь не понимаю как мне ее пофиксить( нужна помощь Проверка жалуется на то что мне нужно удалить двоичные файлы которые я по ошибке закомитил ранее в [aa03839](https://github.com/n00bertb/java-filmorate/commit/aa038392139192e6565aac26c501b592b9a5ed03). Pull request содержит двоичные файлы. Удалите их (*.class, *.jar, *.DS_Store ...) из PR Сами правки по ревью находятся в комите [8414083](https://github.com/n00bertb/java-filmorate/commit/84140836d72caad31fad4188ddcf0230e742dd5c)
> 
> Я нагуглил что можно сделать еще красивее и валидировать сами поля непосредственно и тем самым избавиться от стремного ифа. Про хранение данных не соглашусь в тексте задания было явно: ![изображение](https://private-user-images.githubusercontent.com/53352025/421459188-a40f32e8-15a8-4b95-859b-e252fea0f241.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NDE3NzE3ODcsIm5iZiI6MTc0MTc3MTQ4NywicGF0aCI6Ii81MzM1MjAyNS80MjE0NTkxODgtYTQwZjMyZTgtMTVhOC00Yjk1LTg1OWItZTI1MmZlYTBmMjQxLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAzMTIlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMzEyVDA5MjQ0N1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWEzZWU0MzA3MzZmMWNkM2U5YjJlNmQ2MTY2YWJhOTJiOWQxMzQyMjJiYmY3Mzc5OGJkZjJlZjVmNDU4MTBlMTAmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.KcD6xDaJuHPNwRcRJ24pJEhZu2eyKdBB0Xg7mPNaByw) Я так понял твоя отсылка к следующей теме про внедренние зависимостей?



> Я тут сделал какую то дичь и теперь не понимаю как мне ее пофиксить( нужна помощь Проверка жалуется на то что мне нужно удалить двоичные файлы которые я по ошибке закомитил ранее в [aa03839](https://github.com/n00bertb/java-filmorate/commit/aa038392139192e6565aac26c501b592b9a5ed03). Pull request содержит двоичные файлы. Удалите их (*.class, *.jar, *.DS_Store ...) из PR Сами правки по ревью находятся в комите [8414083](https://github.com/n00bertb/java-filmorate/commit/84140836d72caad31fad4188ddcf0230e742dd5c)
> 
> Я нагуглил что можно сделать еще красивее и валидировать сами поля непосредственно и тем самым избавиться от стремного ифа. Про хранение данных не соглашусь в тексте задания было явно: ![изображение](https://private-user-images.githubusercontent.com/53352025/421459188-a40f32e8-15a8-4b95-859b-e252fea0f241.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NDE3NzE3ODcsIm5iZiI6MTc0MTc3MTQ4NywicGF0aCI6Ii81MzM1MjAyNS80MjE0NTkxODgtYTQwZjMyZTgtMTVhOC00Yjk1LTg1OWItZTI1MmZlYTBmMjQxLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAzMTIlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMzEyVDA5MjQ0N1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWEzZWU0MzA3MzZmMWNkM2U5YjJlNmQ2MTY2YWJhOTJiOWQxMzQyMjJiYmY3Mzc5OGJkZjJlZjVmNDU4MTBlMTAmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.KcD6xDaJuHPNwRcRJ24pJEhZu2eyKdBB0Xg7mPNaByw) Я так понял твоя отсылка к следующей теме про внедренние зависимостей?

Да :) Это скорее была рекомендация
author_association: NONE
user: login: mikita95
created_at: 2025-03-12T09:30:45Z
body: > Я тут сделал какую то дичь и теперь не понимаю как мне ее пофиксить( нужна помощь Проверка жалуется на то что мне нужно удалить двоичные файлы которые я по ошибке закомитил ранее в [aa03839](https://github.com/n00bertb/java-filmorate/commit/aa038392139192e6565aac26c501b592b9a5ed03). Pull request содержит двоичные файлы. Удалите их (*.class, *.jar, *.DS_Store ...) из PR Сами правки по ревью находятся в комите [8414083](https://github.com/n00bertb/java-filmorate/commit/84140836d72caad31fad4188ddcf0230e742dd5c)
> 
> Я нагуглил что можно сделать еще красивее и валидировать сами поля непосредственно и тем самым избавиться от стремного ифа. Про хранение данных не соглашусь в тексте задания было явно: ![изображение](https://private-user-images.githubusercontent.com/53352025/421459188-a40f32e8-15a8-4b95-859b-e252fea0f241.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NDE3NzIwNjQsIm5iZiI6MTc0MTc3MTc2NCwicGF0aCI6Ii81MzM1MjAyNS80MjE0NTkxODgtYTQwZjMyZTgtMTVhOC00Yjk1LTg1OWItZTI1MmZlYTBmMjQxLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAzMTIlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMzEyVDA5MjkyNFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTQzM2IyNzJjMGNkYzAwNTYwMTgwMWMwMzBmODg3ZTk3MjdlMzliNzIwOTEzMjY2OTBlOGNiNzI4MTIyNWQ3NWUmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.cfBNNAvg45jslR-FTr5gtT0VkMsI7zEBXQ0SR_zuWkY) Я так понял твоя отсылка к следующей теме про внедренние зависимостей?

Можно просто удалить папки .idea и target - они в публичном репозитории не нужны :) Можно их добавить в gitignore 
author_association: NONE
user: login: n00bertb
created_at: 2025-03-12T15:47:36Z
body: Я дропнул папки сборка все равно падала. 
Я прожал мерж т.к. посути на следующее задание это не должно будет повлиять?
Я же отведу там новую ветку и в рамках следующего PR такой оказии произойти не должно будет -_-

Можно в практикуме нажать волшебную кнопку?) чтобы я получил доступ к следующему финальному заданию?)
author_association: OWNER