Skip to content
Merged
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
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,16 @@
# java-filmorate
Template repository for Filmorate project.

## Схема базы данных

![Схема БД](/img/schema-database.png)

### Таблицы

- **users** — таблица пользователей: `email` - электронная почта, `login` - логин, `name` - имя, `birthday` - день рождения
- **films** — таблица фильмов: `name` - название, `description` - описание, `release_date` - дата релиза, `duration` - продолжительность в минутах, `rating_id` - идентификатор рейтинга
- **friendships** — таблица дружбы между пользователями: `status` - статус заявки (0 - заявка в друзья не принята, 1 - заявка в друзья принята)
- **film_likes** — таблица лайков (пользователь отмечает понравившийся фильм)
- **film_genres** — таблица связей между фильмами и жанрами
- **ratings** — таблица возрастных рейтингов фильма: `name` - название рейтинга
- **genres** — таблица жанров фильмов: `name` - название жанра

Binary file added img/schema-database.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
97 changes: 57 additions & 40 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -1,46 +1,63 @@
<?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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.zalando</groupId>
<artifactId>logbook-spring-boot-starter</artifactId>
<version>3.7.2</version>
</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>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<argLine>-XX:+EnableDynamicAgentLoading</argLine>
</configuration>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@

@SpringBootApplication
public class FilmorateApplication {
public static void main(String[] args) {
SpringApplication.run(FilmorateApplication.class, args);
}

}
public static void main(String[] args) {
SpringApplication.run(FilmorateApplication.class, args);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,52 @@
package ru.yandex.practicum.filmorate.controller;

import org.springframework.web.bind.annotation.RestController;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Positive;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import ru.yandex.practicum.filmorate.service.FilmService;
import ru.yandex.practicum.filmorate.model.Film;

import java.util.Collection;
import java.util.List;

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

private final FilmService filmService;

@GetMapping
public Collection<Film> getFilms() {
return filmService.getFilms();
}

@PostMapping
public Film createFilm(@Valid @RequestBody Film film) {
return filmService.createFilm(film);
}

@PutMapping
public Film updateFilm(@Valid @RequestBody Film film) {
return filmService.updateFilm(film);
}

@PutMapping("/{id}/like/{userId}")
public void addLike(@PathVariable Long id, @PathVariable Long userId) {
filmService.addLike(id, userId);
}

@DeleteMapping("/{id}/like/{userId}")
public void removeLike(@PathVariable Long id, @PathVariable Long userId) {
filmService.removeLike(id, userId);
}

@Validated
@GetMapping("/popular")
public List<Film> getPopularFilms(@Positive @RequestParam(defaultValue = "10") int count) {
return filmService.getPopularFilms(count);
}

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

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import ru.yandex.practicum.filmorate.service.UserService;
import ru.yandex.practicum.filmorate.model.User;

import java.util.Collection;
import java.util.Optional;

@RestController
@RequiredArgsConstructor
@RequestMapping("/users")
public class UserController {

private final UserService userService;

@GetMapping
public Collection<User> getUsers() {
return userService.getUsers();
}

@PostMapping
public User createFilm(@Valid @RequestBody User user) {
return userService.createUser(user);
}

@PutMapping
public User updateUser(@Valid @RequestBody User user) {
return userService.updateUser(user);
}

@PutMapping("/{id}/friends/{friendId}")
public void addFriend(@PathVariable Long id, @PathVariable Long friendId) {
userService.addFriend(id, friendId);
}

@DeleteMapping("/{id}/friends/{friendId}")
public void deleteFriend(@PathVariable Long id, @PathVariable Long friendId) {
userService.removeFriend(id, friendId);
}

@GetMapping("/{id}/friends")
public Collection<User> getFriends(@PathVariable Long id) {
return userService.getFriends(id);
}

@GetMapping("/{id}/friends/common/{otherId}")
public Collection<Optional<User>> getCommonFriends(@PathVariable Long id, @PathVariable Long otherId) {
return userService.getCommonFriends(id, otherId);
}

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

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;

@RestControllerAdvice
public class ApplicationExceptionHandler {

@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorResponse handleIncorrectParameter(final MethodArgumentNotValidException e) {
return new ErrorResponse(
"Ошибка валидации.", e.getMessage()
);
}

@ExceptionHandler(ExceptionNotFound.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorResponse handleObjectNotFound() {
return new ErrorResponse("Запрошенный объект не найден.", "Такой страницы не существует или запрошенный объект не найден.");
}

@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorResponse handleException() {
return new ErrorResponse("Внутренняя ошибка сервера.", "Попробуйте обратиться позже.");
}

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

import lombok.Getter;

@Getter
public class ErrorResponse {
private final String error;
private final String description;

public ErrorResponse(String error, String description) {
this.error = error;
this.description = description;
}

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

public class ExceptionNotFound extends RuntimeException {
public ExceptionNotFound(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package ru.yandex.practicum.filmorate.json;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;

import java.io.IOException;
import java.time.Duration;

public class DeserializerDuration extends JsonDeserializer<Duration> {
@Override
public Duration deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException {
if (jsonParser.getCurrentToken() == JsonToken.VALUE_NULL) {
return null;
}
return Duration.ofMinutes(jsonParser.getLongValue());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package ru.yandex.practicum.filmorate.json;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

import java.io.IOException;
import java.time.Duration;

public class SerializerDuration extends JsonSerializer<Duration> {
@Override
public void serialize(Duration value, JsonGenerator jsonGenerator, SerializerProvider serializers) throws IOException {
if (value == null) {
jsonGenerator.writeNull();
} else {
jsonGenerator.writeNumber(value.toMinutes());
}
}
}
38 changes: 30 additions & 8 deletions src/main/java/ru/yandex/practicum/filmorate/model/Film.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,34 @@
package ru.yandex.practicum.filmorate.model;

import lombok.Getter;
import lombok.Setter;

/**
* Film.
*/
@Getter
@Setter
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import ru.yandex.practicum.filmorate.json.DeserializerDuration;
import ru.yandex.practicum.filmorate.json.SerializerDuration;
import ru.yandex.practicum.filmorate.validation.MinimumDate;
import ru.yandex.practicum.filmorate.validation.PositiveDuration;
import lombok.Data;

import java.time.Duration;
import java.time.LocalDate;
import java.util.HashSet;
import java.util.Set;

@Data
public class Film {

private Long id;
@NotBlank
private String name;
@Size(max = 200)
private String description;
@MinimumDate
private LocalDate releaseDate;
@PositiveDuration
@JsonSerialize(using = SerializerDuration.class)
@JsonDeserialize(using = DeserializerDuration.class)
private Duration duration;
private final Set<Long> likes = new HashSet<>();

}
Loading
Loading