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
3,016 changes: 3,016 additions & 0 deletions PostmanSprint11_add-friends-likes.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
_java-filmorate_

# Рейтинг фильмов
### Согласно задания спринта № 10
### Согласно задания спринта № 11
## выполнено Филипповских Сергеем

_**Когорта-53**_

в файле PostmanSprint11_add-friends-likes.json находится скрипт для проверки API
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@
<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.9.0</version>
</dependency>

</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

@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
@@ -0,0 +1,64 @@
package ru.yandex.practicum.filmorate.controller;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
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;
import ru.yandex.practicum.filmorate.exception.NotFoundException;
import ru.yandex.practicum.filmorate.exception.ValidationException;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@RestControllerAdvice
public class ErrorHandler {
@ExceptionHandler
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorResponse handleValidationException(final ValidationException e) {
log.error(HttpStatus.BAD_REQUEST + " - " + e.getMessage());
return new ErrorResponse(e.getMessage());
}

@ExceptionHandler
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorResponse handleMethodArgumentNotValidException(final MethodArgumentNotValidException e) {
BindingResult bindingResult = e.getBindingResult();
List<ObjectError> allErrors = bindingResult.getAllErrors();
String defaultMessage = allErrors.stream()
.map(error -> Objects.requireNonNull(error.getDefaultMessage()))
.collect(Collectors.joining(", "));
log.error(HttpStatus.BAD_REQUEST + " - " + defaultMessage);
return new ErrorResponse(defaultMessage);
}

@ExceptionHandler
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorResponse handleNotFoundException(final NotFoundException e) {
log.error(HttpStatus.NOT_FOUND + " - " + e.getMessage());
return new ErrorResponse(e.getMessage());
}

@ExceptionHandler
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorResponse handleRunTimeException(final RuntimeException e) {
log.error(HttpStatus.INTERNAL_SERVER_ERROR + " - " + e.getMessage());
return new ErrorResponse(e.getMessage());
}

@Getter
private static class ErrorResponse {
private final String error;

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

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

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import ru.yandex.practicum.filmorate.exception.ValidationException;
import ru.yandex.practicum.filmorate.model.Film;
import ru.yandex.practicum.filmorate.service.FilmService;

import java.time.LocalDate;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.List;

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

private final Map<Long, Film> films = new HashMap<>();

// получаем список фильмов
@GetMapping
public Collection<Film> findAll() {
return films.values();
}
private final FilmService filmService;

// добавляем фильм
@ResponseStatus(HttpStatus.CREATED)
@PostMapping
public Film create(@RequestBody @Valid Film film) {
// проверяем выполнение необходимых условий
checkFilm(film);
// формируем дополнительные данные
film.setId(getNextId());
// сохраняем данные фильма
films.put(film.getId(), film);
filmService.create(film);
return film;
}

// вспомогательный метод для генерации идентификатора фильма
private long getNextId() {
long currentMaxId = films.keySet()
.stream()
.mapToLong(id -> id)
.max()
.orElse(0);
return ++currentMaxId;
}

// обновляем данные о фильме
@PutMapping
public Film update(@RequestBody @Valid Film newFilm) {
// проверяем необходимые условия
if (newFilm.getId() == null) {
throw new ValidationException("Id фильма должен быть указан");
}
if (films.containsKey(newFilm.getId())) {
checkFilm(newFilm);
// если фильм с таким id найден и все условия соблюдены, обновляем его содержимое
films.put(newFilm.getId(), newFilm);
return newFilm;
}
throw new ValidationException("Фильм с id = " + newFilm.getId() + " не найден");
public Film update(@RequestBody @Valid Film film) {
filmService.update(film);
return film;
}

// получаем список фильмов
@GetMapping
public List<Film> findAll() {
return filmService.findAll();
}

// Получаем фильм по id
@GetMapping("/{filmId}")
public Film getFilmById(@PathVariable Integer filmId) {
return filmService.getById(filmId);
}

// вспомогательный метод для проверки условий фильма
private void checkFilm(Film newFilm) {
if (newFilm.getName() == null || newFilm.getName().isBlank()) {
throw new ValidationException("Название фильма не может быть пустым");
}
if (newFilm.getDescription().length() > 200) {
throw new ValidationException("Максимальная длина описания фильма - 200 символов");
}
if (newFilm.getDuration() < 1) {
throw new ValidationException("Продолжительность фильма должна быть больше 1 секунды");
}
if (newFilm.getReleaseDate().isBefore(LocalDate.parse("1895-12-28"))) {
throw new ValidationException("Минимальная дата выхода фильма 28.12.1895");
}
// Добавляем like пользователя userId к фильму filmId
@PutMapping("/{filmId}/like/{userId}")
public Film addLike(@PathVariable Integer filmId, @PathVariable Integer userId) {
filmService.addLike(filmId, userId);
return filmService.getById(filmId);
}

// Удаляем like пользователя userId к фильму filmId
@DeleteMapping("/{filmId}/like/{userId}")
public Film deleteLike(@PathVariable Integer filmId, @PathVariable Integer userId) {
filmService.deleteLike(filmId, userId);
return filmService.getById(filmId);
}

@GetMapping("/popular")
public List<Film> getListBestFilms(@RequestParam(defaultValue = "10") Integer count) {
return filmService.listBestFilms(count);
}

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

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

import java.time.LocalDate;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.List;

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

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

//Получаем список всех пользователей
@GetMapping
public Collection<User> findAll() {
return users.values();
}
private final UserService userService;

// Добавляем пользователя
@ResponseStatus(HttpStatus.CREATED)
@PostMapping
public User create(@RequestBody @Valid User user) {
// проверяем выполнение необходимых условий
if (users.values().stream()
.anyMatch(u -> u.getEmail().equals(user.getEmail()))) {
throw new ValidationException("Этот email уже используется");
}
checkUser(user);
// формируем дополнительные данные
if (user.getName() == null || user.getName().isBlank()) {
user.setName(user.getLogin());
}
user.setId(getNextId());
// сохраняем нового пользователя
users.put(user.getId(), user);
userService.create(user);
return user;
}

// Обновляем данные пользователя
@PutMapping
public User update(@RequestBody @Valid User user) {
userService.update(user);
return user;
}

// Получаем список всех пользователей
@GetMapping
public List<User> findAll() {
return userService.findAll();
}

// вспомогательный метод для генерации идентификатора нового пользователя
private long getNextId() {
long currentMaxId = users.keySet()
.stream()
.mapToLong(id -> id)
.max()
.orElse(0);
return ++currentMaxId;
// Получаем пользователя по id
@GetMapping("/{userId}")
public User getUserById(@PathVariable Integer userId) {
return userService.getById(userId);
}

// Обновляем данные пользователя
@PutMapping
public User update(@RequestBody @Valid User newUser) {
// проверяем необходимые условия
if (newUser.getId() == null) {
throw new ValidationException("Id пользователя должен быть указан");
}
if (users.containsKey(newUser.getId())) {
User oldUser = users.get(newUser.getId());
checkUser(newUser);
if (!oldUser.getEmail().equals(newUser.getEmail())) {
if (users.values().stream()
.anyMatch(u -> u.getEmail().equals(newUser.getEmail()))) {
throw new ValidationException("Этот email уже используется");
}
}
if (newUser.getName() == null || newUser.getName().isBlank()) {
newUser.setName(newUser.getLogin());
}
users.put(newUser.getId(), newUser);
return newUser;
}
throw new ValidationException("Пользователь с id = " + newUser.getId() + " не найден");
// Добавляем друга friendId для пользователя userId
@PutMapping("/{userId}/friends/{friendId}")
public User addFriend(@PathVariable Integer userId, @PathVariable Integer friendId) {
userService.addFriend(userId, friendId);
return userService.getById(userId);
}

// Удаляем друга friendId у пользователя userId
@DeleteMapping("/{userId}/friends/{friendId}")
public User deleteFriend(@PathVariable Integer userId, @PathVariable Integer friendId) {
userService.deleteFriend(userId, friendId);
return userService.getById(userId);
}

// Получаем список друзей пользователя userId
@GetMapping("/{userId}/friends")
public List<User> getUserFriends(@PathVariable Integer userId) {
return userService.userFriends(userId);
}

// вспомогательный метод для проверки данных условий пользователя
private void checkUser(User user) {
if (user.getEmail() == null || user.getEmail().isBlank() || !user.getEmail().contains("@")) {
throw new ValidationException("Email должен быть указан корректно");
}
if (user.getLogin() == null || user.getLogin().isBlank() || user.getLogin().contains(" ")) {
throw new ValidationException("Логин должен быть задан и без пробелов");
}
if (user.getBirthday().isAfter(LocalDate.now())) {
throw new ValidationException("День рождения не должен быть позже текущей даты");
}
// Получаем общий список друзей пользователя userId и и пользователя otherUserId
@GetMapping("/{userId}/friends/common/{otherUserId}")
public List<User> getCrossingFriends(@PathVariable Integer userId, @PathVariable Integer otherUserId) {
return userService.crossingFriends(userId, otherUserId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package ru.yandex.practicum.filmorate.exception;

public class NotFoundException extends RuntimeException {
public NotFoundException(String message) {
super(message);
}
}
Loading
Loading