Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?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.4.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>

<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>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
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);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package ru.yandex.practicum.filmorate.controller;

import jakarta.validation.Valid;
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 java.time.LocalDate;
import java.util.*;

@Slf4j
@RestController
@RequestMapping("/films")
public class FilmController {

private final Map<Long, Film> films = new HashMap<>();
private long generatedID = 0;
private static final LocalDate MIN_RELEASE_DATE = LocalDate.of(1895, 12, 28);

@PostMapping
public Film create(@Valid @RequestBody Film film) {

film.setId(++generatedID);
films.put(film.getId(), film);
log.info("Добавлен новый фильм {}", film);
return film;
}

@PutMapping
public Film updateFilm(@Valid @RequestBody Film film) {
if (film.getId() == 0 || !films.containsKey(film.getId())) {
log.warn("Попытка обновления несуществующего фильма с id: {}", film.getId());
throw new ValidationException("Фильм с id " + film.getId() + " не найден");
}

films.put(film.getId(), film);
log.info("Обновлен фильм: {}", film);
return film;
}

@GetMapping
public List<Film> getAllFilms() {
log.info("Получен запрос на получение всех фильмов. Текущее количество: {}", films.size());
return new ArrayList<>(films.values());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package ru.yandex.practicum.filmorate.controller;

import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import ru.yandex.practicum.filmorate.exception.ValidationException;
import ru.yandex.practicum.filmorate.model.User;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping("/users")

public class UserController {

private final Map<Long, User> users = new HashMap<>();
private long generatedID = 0;

@PostMapping
public User createUser(@Valid @RequestBody User user) {
user.setId(++generatedID);

if (user.getName() == null || user.getName().isBlank()) {
user.setName(user.getLogin());
}

users.put(user.getId(), user);
log.info("Добавлен новый пользователь: {}", user);
return user;
}

@PutMapping
public User updateUser(@Valid @RequestBody User user) {
if (user.getId() == 0 || !users.containsKey(user.getId())) {
log.warn("Попытка обновления несуществующего пользователя с id: {}", user.getId());
throw new ValidationException("Пользователь с id " + user.getId() + " не найден");
}

if (user.getName() == null || user.getName().isBlank()) {
user.setName(user.getLogin());
}

users.put(user.getId(), user);
log.info("Обновлен пользователь: {}", user);
return user;
}

@GetMapping
public List<User> getAllUsers() {
log.info("Получен запрос на получение всех пользователей. Текущее количество: {}", users.size());
return new ArrayList<>(users.values());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package ru.yandex.practicum.filmorate.exception;

public class ValidationException extends RuntimeException {
public ValidationException(String message) {
super(message);
}
}
27 changes: 27 additions & 0 deletions src/main/java/ru/yandex/practicum/filmorate/model/Film.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package ru.yandex.practicum.filmorate.model;

import jakarta.validation.constraints.*;
import lombok.*;

import java.time.LocalDate;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Film {

private long id;

@NotBlank
private String name;

@Size(min = 1, max = 200)
private String description;

@NotNull
@PastOrPresent(message = "Дата релиза не может быть в будущем")
public LocalDate releaseDate;

@Min(1)
private long duration;
}
28 changes: 28 additions & 0 deletions src/main/java/ru/yandex/practicum/filmorate/model/User.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package ru.yandex.practicum.filmorate.model;

import jakarta.validation.constraints.*;
import lombok.*;

import java.time.LocalDate;

@Data
@NoArgsConstructor
@AllArgsConstructor

public class User {

private long id;

@NotBlank
@Email(message = "Email должен быть корректным")
private String email;

@NotBlank
@Pattern(regexp = "\\S+", message = "Логин не может содержать пробелы")
private String login;

private String name;

@PastOrPresent(message = "Дата рождения не может быть в будущем")
private LocalDate birthday;
}
1 change: 1 addition & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -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() {
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package ru.yandex.practicum.filmorate.controller;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import ru.yandex.practicum.filmorate.exception.ValidationException;
import ru.yandex.practicum.filmorate.model.Film;

import java.time.LocalDate;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

class FilmControllerTest {

private FilmController filmController;
private Film validFilm;

@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 shouldCreateValidFilm() {
Film createdFilm = filmController.create(validFilm);

assertNotNull(createdFilm);
assertEquals("Test Film", createdFilm.getName());
assertEquals(120, createdFilm.getDuration());
assertTrue(createdFilm.getId() > 0);
}

@Test
void shouldGetAllFilms() {
filmController.create(validFilm);
List<Film> films = filmController.getAllFilms();

assertEquals(1, films.size());
assertTrue(films.stream().anyMatch(f -> f.getName().equals("Test Film")));
}

@Test
void shouldUpdateFilm() {
Film createdFilm = filmController.create(validFilm);

Film updatedFilm = new Film();
updatedFilm.setId(createdFilm.getId());
updatedFilm.setName("Updated Film");
updatedFilm.setDescription("Updated description");
updatedFilm.setReleaseDate(LocalDate.of(2001, 1, 1));
updatedFilm.setDuration(150);

Film result = filmController.updateFilm(updatedFilm);

assertEquals("Updated Film", result.getName());
assertEquals(150, result.getDuration());
assertEquals(createdFilm.getId(), result.getId());
}

@Test
void shouldThrowExceptionWhenUpdatingNonExistentFilm() {
Film nonExistentFilm = new Film();
nonExistentFilm.setId(999);
nonExistentFilm.setName("Non-existent");
nonExistentFilm.setReleaseDate(LocalDate.of(2000, 1, 1));
nonExistentFilm.setDuration(100);

ValidationException exception = assertThrows(ValidationException.class,
() -> filmController.updateFilm(nonExistentFilm));

assertEquals("Фильм с id 999 не найден", exception.getMessage());
}

@Test
void shouldGenerateUniqueIds() {
Film film1 = filmController.create(validFilm);

Film film2 = new Film();
film2.setName("Second Film");
film2.setReleaseDate(LocalDate.of(2001, 1, 1));
film2.setDuration(90);
Film createdFilm2 = filmController.create(film2);

assertNotEquals(film1.getId(), createdFilm2.getId());
assertEquals(2, filmController.getAllFilms().size());
}
}
Loading
Loading