diff --git a/pom.xml b/pom.xml
index d9cee64..2e002aa 100644
--- a/pom.xml
+++ b/pom.xml
@@ -66,6 +66,11 @@
3.3.3
test
+
+ org.zalando
+ logbook-spring-boot-starter
+ 3.7.2
+
diff --git a/src/main/java/ru/yandex/practicum/filmorate/FilmorateApplication.java b/src/main/java/ru/yandex/practicum/filmorate/FilmorateApplication.java
index 8616407..3f2baca 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/FilmorateApplication.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/FilmorateApplication.java
@@ -1,6 +1,5 @@
package ru.yandex.practicum.filmorate;
-
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
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 f8170bd..b77547a 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/controller/FilmController.java
@@ -1,72 +1,84 @@
package ru.yandex.practicum.filmorate.controller;
import jakarta.validation.Valid;
-import jakarta.validation.ValidationException;
+import jakarta.validation.constraints.Positive;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
+import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import ru.yandex.practicum.filmorate.model.Film;
+import ru.yandex.practicum.filmorate.service.FilmService;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
+@Validated
@RestController
@RequestMapping("/films")
public class FilmController {
- private final ValidateController validateController = new ValidateController();
- private final Map films = new HashMap<>();
- private final Logger log = LoggerFactory.getLogger(FilmController.class);
+ private final Logger logger = LoggerFactory.getLogger(FilmController.class);
+ private final FilmService filmService;
+
+ @Autowired
+ public FilmController(FilmService filmService) {
+ this.filmService = filmService;
+ }
+
+ @GetMapping("/{id}")
+ @ResponseStatus(HttpStatus.OK)
+
+ public Film getFilmId(@Positive(message = "неверное значение") @PathVariable long id) {
+ logger.info("вывод фильма по ID");
+ return filmService.getFilmId(id);
+ }
@GetMapping
- public ResponseEntity> filmAll() {
- log.info("вывод списка фильмов");
- return ResponseEntity.ok(films.values());
+ @ResponseStatus(HttpStatus.OK)
+ public Collection getFilmAll() {
+ logger.info("вывод списка фильмов");
+ return filmService.getAll();
}
@PostMapping
- public ResponseEntity> create(@Valid @RequestBody Film film) {
- validateController.validateFilm(film);
- film.setId(getNextId());
- films.put(film.getId(), film);
- log.info("фильм добавлен id: " + film.getId());
- return ResponseEntity.status(HttpStatus.CREATED).body(film);
+ @ResponseStatus(HttpStatus.CREATED)
+ public Film create(@Valid @RequestBody Film film) {
+ logger.info("Фильм добавлен");
+ return filmService.create(film);
+ }
+
+ @DeleteMapping("/{id}")
+ @ResponseStatus(HttpStatus.OK)
+ public void delete(@Positive(message = "неверное значение") @PathVariable long id) {
+ logger.info("Удаление id=" + id);
+ filmService.delete(id);
}
@PutMapping
- public ResponseEntity> update(@Valid @RequestBody Film newFilm) {
- if (newFilm.getId() == null) {
- log.warn("ID пустой");
- throw new ValidationException("пользователь с таким ID не найден");
- // изначально сделал чтоб в теле была ошибка, но не прошло тесты в Postman
- // return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("ID пустой");
- }
- if (!films.containsKey(newFilm.getId())) {
- log.warn("пользователь с таким ID не найден");
- // изначально сделал чтоб в теле была ошибка, но не прошло тесты в Postman
- // return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("пользователь с таким ID не найден");
- throw new ValidationException("пользователь с таким ID не найден");
- }
- validateController.validateFilm(newFilm);
- Film oldFilm = films.get(newFilm.getId());
- oldFilm.setName(newFilm.getName());
- oldFilm.setDescription(newFilm.getDescription());
- oldFilm.setReleaseDate(newFilm.getReleaseDate());
- oldFilm.setDuration(newFilm.getDuration());
- log.info("запись фильма обновлена");
- return ResponseEntity.ok(oldFilm);
+ @ResponseStatus(HttpStatus.OK)
+ public Film update(@RequestBody Film newFilm) {
+ logger.info("запись фильма обновлена");
+ return filmService.update(newFilm);
}
- private long getNextId() {
- long currentMaxId = films.keySet()
- .stream()
- .mapToLong(id -> id)
- .max()
- .orElse(0);
- return ++currentMaxId;
+ @PutMapping("/{id}/like/{userId}")
+ @ResponseStatus(HttpStatus.OK)
+ public Collection likeAdd(@Positive(message = "неверное значение") @PathVariable long id,
+ @Positive(message = "неверное значение") @PathVariable long userId) {
+ return filmService.likeAdd(id, userId);
+ }
+
+ @DeleteMapping("/{id}/like/{userId}")
+ @ResponseStatus(HttpStatus.OK)
+ public Collection likeDelete(@Positive(message = "неверное значение") @PathVariable long id,
+ @Positive(message = "неверное значение") @PathVariable long userId) {
+ return filmService.likeDelete(id, userId);
+ }
+ @GetMapping("/popular")
+ @ResponseStatus(HttpStatus.OK)
+ public Collection getPopular(@Positive(message = "неверное значение") @RequestParam(defaultValue = "10") int count) {
+ return filmService.getPopular(count);
}
}
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 8b30820..938f2b8 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/controller/UserController.java
@@ -2,80 +2,95 @@
import jakarta.validation.Valid;
-import jakarta.validation.ValidationException;
+import jakarta.validation.constraints.Positive;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-
+import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import ru.yandex.practicum.filmorate.model.User;
+import ru.yandex.practicum.filmorate.service.UserService;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
+@Validated
@RestController
@RequestMapping("/users")
public class UserController {
- private final ValidateController validate = new ValidateController();
- private final Map users = new HashMap<>();
+ private final UserService userService;
+
+ private final Logger logger = LoggerFactory.getLogger(UserController.class);
+
+ @Autowired
+ public UserController(UserService userService) {
+ this.userService = userService;
+ }
- private final Logger log = LoggerFactory.getLogger(UserController.class);
+ @GetMapping("/{id}")
+ @ResponseStatus(HttpStatus.OK)
+ public User getUserId(@Positive(message = "неверное значение") @PathVariable long id) {
+ logger.info("вывод пользователя по ID");
+ return userService.getUserId(id);
+ }
- @GetMapping //запрос всех пользователей
- public ResponseEntity> usersAll() {
+ @GetMapping
+ @ResponseStatus(HttpStatus.OK)
+ public Collection userAll() {
+ logger.info("вывод списка пользователей");
+ return userService.getAll();
+ }
- log.info("вывод списка пользователей");
- return ResponseEntity.ok(users.values());
+ @PostMapping
+ @ResponseStatus(HttpStatus.CREATED)
+ public User create(@Valid @RequestBody User user) {
+ logger.info("Пользователь добавлен");
+ return userService.create(user);
}
- @PostMapping //добавление нового пользователя
- public ResponseEntity> create(@Valid @RequestBody User user) {
- validate.validateUser(user);
-
- if (users.containsValue(user)) {
- log.warn("ошибка добавления пользователя, такой пользователь уже есть");
- return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("ошибка добавления пользователя, такой пользователь уже есть");
- }
- user.setId(getNextId());
- users.put(user.getId(), user);
- log.info("пользователь создан id: " + user.getId());
- return ResponseEntity.status(HttpStatus.CREATED).body(user); //отрпавляем ответ с статусом и телом
+ @DeleteMapping("/{id}")
+ @ResponseStatus(HttpStatus.OK)
+ public void delete(@Positive(message = "неверное значение") @PathVariable long id) {
+ logger.info("Удаление id=" + id);
+ userService.delete(id);
}
- @PutMapping //обновление пользователя
- public ResponseEntity> update(@Valid @RequestBody User newUser) {
- if (newUser.getId() == null) {
- log.warn("ID пустой");
- throw new ValidationException(" ID пустой");
- // изначально сделал чтоб в теле была ошибка, но не прошло тесты в Postman
- // return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("ID пустой");
- }
- if (!users.containsKey(newUser.getId())) {
- log.warn("пользователь с таким ID не найден");
- throw new ValidationException("пользователь с таким ID не найден");
- // изначально сделал чтоб в теле была ошибка, но не прошло тесты в Postman
- // return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("пользователь с таким ID не найден");
- }
- validate.validateUser(newUser);
- User oldUser = users.get(newUser.getId());
- oldUser.setEmail(newUser.getEmail());
- oldUser.setLogin(newUser.getLogin());
- oldUser.setBirthday(newUser.getBirthday());
- oldUser.setName(newUser.getName());
- log.info("пользователь изменен");
- return ResponseEntity.ok(oldUser);
+ @PutMapping
+ @ResponseStatus(HttpStatus.OK)
+ public User update(@RequestBody User newUser) {
+ logger.info("запись пользователя обновлена");
+ return userService.update(newUser);
}
- private long getNextId() {
- long currentMaxId = users.keySet()
- .stream()
- .mapToLong(id -> id)
- .max()
- .orElse(0);
- return ++currentMaxId;
+ @PutMapping("/{id}/friends/{friendsId}")
+ @ResponseStatus(HttpStatus.OK)
+ public Collection friendsAdd(@Positive(message = "неверное значение") @PathVariable long id,
+ @Positive(message = "неверное значение") @PathVariable long friendsId) {
+ logger.info("добавили в друзья");
+ return userService.friendsAdd(id, friendsId);
+ }
+
+ @DeleteMapping("/{id}/friends/{friendsId}")
+ @ResponseStatus(HttpStatus.OK)
+ public Collection friendsDelete(@Positive(message = "неверное значение") @PathVariable long id,
+ @Positive(message = "неверное значение") @PathVariable long friendsId) {
+ logger.info("удалили из друзей");
+ return userService.friendsDelete(id, friendsId);
+ }
+
+ @GetMapping("/{id}/friends")
+ @ResponseStatus(HttpStatus.OK)
+ public Collection friendsGetList(@Positive(message = "неверное значение") @PathVariable long id) {
+ logger.info("показывает список друзей");
+ return userService.friendsGetList(id);
+ }
+ @GetMapping("/{id}/friends/common/{otherId}")
+ @ResponseStatus(HttpStatus.OK)
+ public Collection friendsGetCommonList(@Positive(message = "неверное значение") @PathVariable long id,
+ @Positive(message = "неверное значение") @PathVariable long otherId) {
+ logger.info("показывает список друзей");
+ return userService.friendsGetCommonList(id, otherId);
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/ru/yandex/practicum/filmorate/controller/ValidateController.java b/src/main/java/ru/yandex/practicum/filmorate/controller/ValidateController.java
index 2f427cc..8c4d32f 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/controller/ValidateController.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/controller/ValidateController.java
@@ -2,6 +2,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
import ru.yandex.practicum.filmorate.exception.ValidationException;
import ru.yandex.practicum.filmorate.exception.ValidationNullException;
import ru.yandex.practicum.filmorate.model.Film;
@@ -9,6 +10,7 @@
import java.time.LocalDate;
+@Component
public class ValidateController {
private final Logger log = LoggerFactory.getLogger(ValidateController.class);
@@ -96,7 +98,6 @@ public void validateUser(User user) {
log.warn("введена дата из будущего");
throw new ValidationException("введена дата из будущего");
}
-
}
}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/ErrorHandler.java b/src/main/java/ru/yandex/practicum/filmorate/exception/ErrorHandler.java
index 2503b8f..a8404af 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/exception/ErrorHandler.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/exception/ErrorHandler.java
@@ -5,34 +5,58 @@
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MethodArgumentNotValidException;
-import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
-import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.List;
import java.util.stream.Collectors;
-/// взято с просторов интернета вывод сообщений при ошибки
-@ControllerAdvice
+@RestControllerAdvice
public class ErrorHandler {
+ private final Logger logger = LoggerFactory.getLogger(ErrorHandler.class);
- private final Logger log = LoggerFactory.getLogger(ErrorHandler.class);
+ @ExceptionHandler
+ @ResponseStatus(HttpStatus.NOT_FOUND)
+ public ErrorResponse handlerIsNull(final ErrorIsNull e) {
+ logger.warn(e.getMessage());
+ return new ErrorResponse("error", e.getMessage());
+ }
+
+ @ExceptionHandler
+ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+ public ErrorResponse handleThrowbla(final Throwable e) {
+ logger.warn(e.getMessage());
+ return new ErrorResponse("error", "Произошла непредвиденная ошибка.");
+ }
+
+ @ExceptionHandler
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ public ErrorResponse handlerValidationException(final ValidationException e) {
+ logger.warn(e.getMessage());
+ return new ErrorResponse("error", e.getMessage());
+ }
+
+ @ExceptionHandler
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ public ErrorResponse handlerValidationNullException(final ValidationNullException e) {
+ logger.warn(e.getMessage());
+ return new ErrorResponse("error", e.getMessage());
+ }
- @ResponseBody
@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ValidationErrorResponse onConstraintValidationException(
ConstraintViolationException e
) {
- final List violations = e.getConstraintViolations().stream()
+ final List violations = e.getConstraintViolations().stream()
.map(
- violation -> new Violation(
- violation.getPropertyPath().toString(),
- violation.getMessage()
+ error -> new ErrorResponse(
+ error.getPropertyPath().toString(),
+ error.getMessage()
)
)
- .peek(violation -> log.warn(violation.getMessage()))
+ .peek(error -> logger.warn(error.getDescription()))
.collect(Collectors.toList());
return new ValidationErrorResponse(violations);
@@ -40,13 +64,12 @@ public ValidationErrorResponse onConstraintValidationException(
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
- @ResponseBody
public ValidationErrorResponse onMethodArgumentNotValidException(
MethodArgumentNotValidException e
) {
- final List violations = e.getBindingResult().getFieldErrors().stream()
- .map(error -> new Violation(error.getField(), error.getDefaultMessage()))
- .peek(error -> log.warn(error.getFieldName() + " = " + error.getMessage()))
+ final List violations = e.getBindingResult().getFieldErrors().stream()
+ .map(error -> new ErrorResponse(error.getField(), error.getDefaultMessage()))
+ .peek(error -> logger.warn(error.getError() + " = " + error.getDescription()))
.collect(Collectors.toList());
return new ValidationErrorResponse(violations);
}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/ErrorIsNull.java b/src/main/java/ru/yandex/practicum/filmorate/exception/ErrorIsNull.java
new file mode 100644
index 0000000..6692ef0
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/exception/ErrorIsNull.java
@@ -0,0 +1,8 @@
+package ru.yandex.practicum.filmorate.exception;
+
+public class ErrorIsNull extends NullPointerException {
+
+ public ErrorIsNull(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/ErrorResponse.java b/src/main/java/ru/yandex/practicum/filmorate/exception/ErrorResponse.java
new file mode 100644
index 0000000..9d8ec03
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/exception/ErrorResponse.java
@@ -0,0 +1,16 @@
+package ru.yandex.practicum.filmorate.exception;
+
+import lombok.Getter;
+
+@Getter
+public class ErrorResponse {
+
+ String error;
+
+ String description;
+
+ public ErrorResponse(String error, String description) {
+ this.error = error;
+ this.description = description;
+ }
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/ValidationErrorResponse.java b/src/main/java/ru/yandex/practicum/filmorate/exception/ValidationErrorResponse.java
index 81443f2..4615672 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/exception/ValidationErrorResponse.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/exception/ValidationErrorResponse.java
@@ -5,11 +5,10 @@
import java.util.List;
-// взято с просторов интернета вывод сообщений при ошибки
@Getter
@RequiredArgsConstructor
public class ValidationErrorResponse {
- private final List violations;
+ private final List violations;
}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/exception/Violation.java b/src/main/java/ru/yandex/practicum/filmorate/exception/Violation.java
deleted file mode 100644
index 3455b04..0000000
--- a/src/main/java/ru/yandex/practicum/filmorate/exception/Violation.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package ru.yandex.practicum.filmorate.exception;
-
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-// взято с просторов интернета вывод сообщений при ошибки
-
-@Getter
-@RequiredArgsConstructor
-public class Violation {
- private final String fieldName;
- private final String message;
-
-}
\ No newline at end of file
diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/DataModel.java b/src/main/java/ru/yandex/practicum/filmorate/model/DataModel.java
new file mode 100644
index 0000000..14c6581
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/model/DataModel.java
@@ -0,0 +1,8 @@
+package ru.yandex.practicum.filmorate.model;
+
+public class DataModel {
+ private Long id;
+
+ private String name;
+
+}
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 63c7732..297ba77 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/model/Film.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/model/Film.java
@@ -5,6 +5,7 @@
import lombok.*;
import java.time.LocalDate;
+import java.util.Set;
/**
* Film.
@@ -13,7 +14,7 @@
@Setter
@ToString
@AllArgsConstructor
-public class Film {
+public class Film extends DataModel implements Comparable {
private Long id;
@@ -32,4 +33,14 @@ public class Film {
@Positive(message = "неверное значение")
@Min(1)
private int duration;
+
+ private Set likesId;
+
+ @Override
+ public int compareTo(Film o) {
+ if (o.getLikesId() == null) {
+ return 0;
+ }
+ return o.getLikesId().size() - this.getLikesId().size();
+ }
}
\ 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 4ffa7ed..c8dd66e 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/model/User.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/model/User.java
@@ -5,13 +5,14 @@
import lombok.*;
import java.time.LocalDate;
+import java.util.Set;
@Setter
@Getter
@ToString
@AllArgsConstructor
-@EqualsAndHashCode(exclude = {"id", "name", "birthday"})
-public class User {
+@EqualsAndHashCode(exclude = {"id", "name", "birthday"}, callSuper = false)
+public class User extends DataModel {
private Long id;
@@ -19,7 +20,6 @@ public class User {
@Email(message = "email не соотвествует формату")
private String email;
-
@NotNull(message = "логин не заполнен")
private String login;
@@ -29,4 +29,8 @@ public class User {
@Past(message = "дата из будущего")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private LocalDate birthday;
+
+ private Set friendsId;
+
+
}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java
new file mode 100644
index 0000000..e9aea22
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/service/FilmService.java
@@ -0,0 +1,105 @@
+package ru.yandex.practicum.filmorate.service;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import org.springframework.stereotype.Service;
+import ru.yandex.practicum.filmorate.controller.ValidateController;
+import ru.yandex.practicum.filmorate.exception.ErrorIsNull;
+import ru.yandex.practicum.filmorate.exception.ValidationException;
+import ru.yandex.practicum.filmorate.model.Film;
+import ru.yandex.practicum.filmorate.model.User;
+import ru.yandex.practicum.filmorate.storage.FilmStorage;
+import ru.yandex.practicum.filmorate.storage.UserStorage;
+
+import java.util.Collection;
+import java.util.stream.Collectors;
+
+@Service
+public class FilmService {
+
+ private final FilmStorage filmStorage;
+
+ private final UserStorage userStorage;
+ private final ValidateController validateController;
+ private final Logger logger = LoggerFactory.getLogger(FilmService.class);
+
+ @Autowired
+ public FilmService(FilmStorage filmStorage, UserStorage userStorage, ValidateController validateController) {
+ this.filmStorage = filmStorage;
+ this.userStorage = userStorage;
+ this.validateController = validateController;
+
+ }
+
+ public Film create(Film film) {
+ validateController.validateFilm(film);
+ Film returnFilm = filmStorage.create(film);
+ logger.info("Фильм добавлен id: " + returnFilm.getId());
+ return returnFilm;
+ }
+
+ public Film getFilmId(long id) {
+ Film getFilm = filmStorage.getId(id);
+ if (getFilm == null) {
+ throw new ErrorIsNull("нет такого id");
+ }
+ logger.info("поиск по id=" + id);
+ return getFilm;
+ }
+
+ public Collection getAll() {
+ logger.info("Вернули список");
+ Collection returnAll = filmStorage.getAll();
+ if (returnAll.isEmpty()) {
+ throw new ErrorIsNull("список пуст");
+ }
+ return returnAll;
+ }
+
+ public void delete(long id) {
+ Film delFilm = filmStorage.delete(id);
+ if (delFilm == null) {
+ throw new ErrorIsNull("нет такого id");
+ }
+ logger.info("удаление id=" + id);
+ }
+
+ public Film update(Film newFilm) {
+
+ if (newFilm.getId() == null) {
+ logger.warn("ID пустой");
+ throw new ValidationException("ID фильма пустой");
+ }
+ Film oldFilm = filmStorage.getId(newFilm.getId());
+
+ if (oldFilm == null) {
+ logger.warn("фильм с таким ID не найден");
+ throw new ErrorIsNull("фильм с таким ID не найден");
+ }
+ validateController.validateFilm(newFilm);
+ logger.info("запись фильма обновлена");
+ return filmStorage.update(newFilm);
+ }
+
+ public Collection likeAdd(long id, long userId) {
+ getFilmId(id);
+ userStorage.getId(userId);
+ return filmStorage.setLikeId(id, userId);
+ }
+
+ public Collection likeDelete(long id, long userId) {
+ getFilmId(id);
+ userStorage.getId(userId);
+ return filmStorage.delLikesId(id, userId);
+ }
+
+ public Collection getPopular(int count) {
+
+ return getAll().stream()
+ .sorted(Film::compareTo)
+ .limit(count)
+ .collect(Collectors.toList());
+ }
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java
new file mode 100644
index 0000000..1ecaa82
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/service/UserService.java
@@ -0,0 +1,104 @@
+package ru.yandex.practicum.filmorate.service;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import ru.yandex.practicum.filmorate.controller.ValidateController;
+import ru.yandex.practicum.filmorate.exception.ErrorIsNull;
+import ru.yandex.practicum.filmorate.exception.ValidationException;
+import ru.yandex.practicum.filmorate.model.User;
+import ru.yandex.practicum.filmorate.storage.UserStorage;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+public class UserService {
+
+ private final UserStorage userStorage;
+ private final ValidateController validateController;
+ private final Logger logger = LoggerFactory.getLogger(FilmService.class);
+
+ @Autowired
+ public UserService(UserStorage userStorage, ValidateController validateController) {
+ this.userStorage = userStorage;
+ this.validateController = validateController;
+ }
+
+ public Collection friendsAdd(long id, long friendsId) {
+ getUserId(id);
+ getUserId(friendsId);
+ return userStorage.setFriendId(id, friendsId);
+
+ }
+
+ public Collection friendsDelete(long id, long friendsId) {
+ getUserId(id);
+ getUserId(friendsId);
+ return userStorage.delFriendId(id, friendsId);
+ }
+
+ public Collection friendsGetList(long id) {
+ getUserId(id);
+
+ return userStorage.getFriendId(id).stream().map(this::getUserId).collect(Collectors.toList());
+ }
+
+ public User create(User user) {
+ validateController.validateUser(user);
+ User returnUser = userStorage.create(user);
+ logger.info("пользователь добавлен id: " + returnUser.getId());
+ return returnUser;
+ }
+
+ public Collection getAll() {
+ logger.info("Вернули список");
+ Collection returnAll = userStorage.getAll();
+ if (returnAll.isEmpty()) {
+ throw new ErrorIsNull("список пуст");
+ }
+ return returnAll;
+ }
+
+ public User getUserId(long id) {
+ User getUser = userStorage.getId(id);
+ if (getUser == null) {
+ throw new ErrorIsNull("нет такого id");
+ }
+ logger.info("поиск по id=" + id);
+ return getUser;
+ }
+
+ public void delete(long id) {
+ User delUser = userStorage.delete(id);
+ if (delUser == null) {
+ throw new ErrorIsNull("нет такого id");
+ }
+ logger.info("удаление id=" + id);
+ }
+
+ public User update(User newUser) {
+
+ if (newUser.getId() == null) {
+ logger.warn("ID пустой");
+ throw new ValidationException("ID пользователя пустой");
+ }
+ User oldUser = userStorage.getId(newUser.getId());
+
+ if (oldUser == null) {
+ logger.warn("пользователь с таким ID не найден");
+ throw new ErrorIsNull("пользователь с таким ID не найден");
+ }
+ validateController.validateUser(newUser);
+ logger.info("запись пользователя обновлена");
+ return userStorage.update(newUser);
+ }
+
+ public List friendsGetCommonList(long id, long otherId) {
+ Collection userList1 = friendsGetList(id);
+ Collection userList2 = friendsGetList(otherId);
+ return userList1.stream().filter(userList2::contains).collect(Collectors.toList());
+ }
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java
new file mode 100644
index 0000000..38ac22e
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/FilmStorage.java
@@ -0,0 +1,24 @@
+package ru.yandex.practicum.filmorate.storage;
+
+import ru.yandex.practicum.filmorate.model.DataModel;
+
+import java.util.Collection;
+
+public interface FilmStorage {
+
+ T create(T data);
+
+ T update(T data);
+
+ T delete(long id);
+
+ T getId(long id);
+
+ Collection getAll();
+
+ Collection getLikeId(long id);
+
+ Collection setLikeId(long id, long userId);
+
+ Collection delLikesId(long id, long userId);
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java
new file mode 100644
index 0000000..a625616
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryFilmStorage.java
@@ -0,0 +1,73 @@
+package ru.yandex.practicum.filmorate.storage;
+
+import org.springframework.stereotype.Repository;
+import ru.yandex.practicum.filmorate.model.Film;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+@Repository
+public class InMemoryFilmStorage extends Storage implements FilmStorage {
+
+ @Override
+ public Film create(Film film) {
+ film.setId(getNextId());
+ if (film.getLikesId() == null) {
+ film.setLikesId(new HashSet<>() {
+ });
+ }
+ dataMap.put(film.getId(), film);
+ logger.info("Фильм добавлен id: " + film.getId());
+ return film;
+ }
+
+ @Override
+ public Film update(Film newFilm) {
+ Film oldFilm = dataMap.get(newFilm.getId());
+ oldFilm.setName(newFilm.getName());
+ oldFilm.setDescription(newFilm.getDescription());
+ oldFilm.setReleaseDate(newFilm.getReleaseDate());
+ oldFilm.setDuration(newFilm.getDuration());
+
+ if (newFilm.getLikesId() == null) {
+ newFilm.setLikesId(new HashSet<>() {
+ });
+ }
+ oldFilm.setLikesId(newFilm.getLikesId());
+ logger.info("Запись фильма обновлена");
+ return oldFilm;
+ }
+
+ @Override
+ public Collection getLikeId(long id) {
+ Film getLikes = dataMap.get(id);
+ return getLikes.getLikesId();
+ }
+
+ @Override
+ public Collection setLikeId(long id, long userId) {
+ Film getLikes = dataMap.get(id);
+ getLikes.getLikesId().add(userId);
+ return getLikes.getLikesId();
+ }
+
+ @Override
+ public Collection delLikesId(long id, long userId) {
+ Film getLikes = dataMap.get(id);
+ Set newLikesList = getLikes.getLikesId();
+ newLikesList.remove(id);
+ getLikes.setLikesId(newLikesList);
+ return newLikesList;
+ }
+
+ private long getNextId() {
+ long currentMaxId = dataMap.keySet()
+ .stream()
+ .mapToLong(id -> id)
+ .max()
+ .orElse(0);
+ return ++currentMaxId;
+
+ }
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java
new file mode 100644
index 0000000..3fc2128
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/InMemoryUserStorage.java
@@ -0,0 +1,78 @@
+package ru.yandex.practicum.filmorate.storage;
+
+import org.springframework.stereotype.Repository;
+import ru.yandex.practicum.filmorate.model.User;
+
+import java.util.*;
+
+@Repository
+public class InMemoryUserStorage extends Storage implements UserStorage {
+
+ @Override
+ public User create(User user) {
+ user.setId(getNextId());
+ if (user.getFriendsId() == null) {
+ user.setFriendsId(new HashSet<>() {
+ });
+ }
+ dataMap.put(user.getId(), user);
+ logger.info("Пользователь добавлен id: " + user.getId());
+ return user;
+ }
+
+ @Override
+ public User update(User newUser) {
+ User oldUser = dataMap.get(newUser.getId());
+ oldUser.setName(newUser.getName());
+ oldUser.setEmail(newUser.getEmail());
+ oldUser.setLogin(newUser.getLogin());
+ oldUser.setBirthday(newUser.getBirthday());
+ oldUser.setFriendsId(newUser.getFriendsId());
+ logger.info("Запись пользователя обновлена");
+ return oldUser;
+ }
+
+ @Override
+ public Collection getFriendId(long id) {
+ User getFriends = dataMap.get(id);
+ return getFriends.getFriendsId();
+ }
+
+ @Override
+ public Collection setFriendId(long id, long friendsId) {
+ User getFriends = dataMap.get(id); //добавление в друзья
+ Set newFriendsList = getFriends.getFriendsId();
+ newFriendsList.add(friendsId);
+ getFriends.setFriendsId(newFriendsList);
+
+ User getFriendsTo = dataMap.get(friendsId); //зеркальное добавление в друзья
+ Set newFriendsListTo = getFriendsTo.getFriendsId();
+ newFriendsListTo.add(id);
+ getFriendsTo.setFriendsId(newFriendsListTo);
+ return newFriendsList;
+ }
+
+ @Override
+ public Collection delFriendId(long id, long friendsId) {
+ User getFriends = dataMap.get(id); //удаление из друзей
+ Set newFriendsList = getFriends.getFriendsId();
+ newFriendsList.remove(friendsId);
+ getFriends.setFriendsId(newFriendsList);
+
+ User getFriendsTo = dataMap.get(friendsId); //удаление из друзей
+ Set newFriendsListTo = getFriendsTo.getFriendsId();
+ newFriendsListTo.remove(id);
+ getFriendsTo.setFriendsId(newFriendsListTo);
+
+ return newFriendsList;
+ }
+
+ private long getNextId() {
+ long currentMaxId = dataMap.keySet()
+ .stream()
+ .mapToLong(id -> id)
+ .max()
+ .orElse(0);
+ return ++currentMaxId;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/Storage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/Storage.java
new file mode 100644
index 0000000..1be99fc
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/Storage.java
@@ -0,0 +1,33 @@
+package ru.yandex.practicum.filmorate.storage;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import ru.yandex.practicum.filmorate.exception.ErrorIsNull;
+import ru.yandex.practicum.filmorate.model.DataModel;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+public class Storage {
+ protected final Map dataMap = new HashMap<>();
+
+ protected final Logger logger = LoggerFactory.getLogger(Storage.class);
+
+ public T delete(long id) {
+ return dataMap.remove(id);
+ }
+
+ public T getId(long id) {
+ if (!dataMap.containsKey(id)) {
+ throw new ErrorIsNull("нет такого id");
+ }
+ logger.info("Вернули по id=" + id);
+ return dataMap.get(id);
+ }
+
+ public Collection getAll() {
+ logger.info("Вернули список");
+ return dataMap.values();
+ }
+}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java b/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java
new file mode 100644
index 0000000..3cb17a4
--- /dev/null
+++ b/src/main/java/ru/yandex/practicum/filmorate/storage/UserStorage.java
@@ -0,0 +1,24 @@
+package ru.yandex.practicum.filmorate.storage;
+
+import ru.yandex.practicum.filmorate.model.DataModel;
+
+import java.util.Collection;
+
+public interface UserStorage {
+
+ T create(T data);
+
+ T update(T data);
+
+ T delete(long id);
+
+ T getId(long id);
+
+ Collection getAll();
+
+ Collection getFriendId(long id);
+
+ Collection setFriendId(long id, long userId);
+
+ Collection delFriendId(long id, long userId);
+}
diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml
new file mode 100644
index 0000000..94c6c3e
--- /dev/null
+++ b/src/main/resources/application.yaml
@@ -0,0 +1,5 @@
+logging:
+ level:
+ org:
+ zalando:
+ logbook: TRACE
\ No newline at end of file
diff --git a/src/test/java/ru/yandex/practicum/filmorate/FilmControllerTest.java b/src/test/java/ru/yandex/practicum/filmorate/FilmControllerTest.java
index cf7b4b2..78fce0a 100644
--- a/src/test/java/ru/yandex/practicum/filmorate/FilmControllerTest.java
+++ b/src/test/java/ru/yandex/practicum/filmorate/FilmControllerTest.java
@@ -10,16 +10,20 @@
import ru.yandex.practicum.filmorate.model.Film;
import java.time.LocalDate;
+import java.util.HashSet;
+import java.util.Set;
public class FilmControllerTest {
Exception exception;
private final ValidateController validate = new ValidateController();
- Film film;
+ private Film film;
+ Set testList = new HashSet<>() {
+ };
@BeforeEach
void setUp() {
- film = new Film(1L, "name", "описание ", LocalDate.now().minusYears(3), 20);
+ film = new Film(1L, "name", "описание ", LocalDate.now().minusYears(3), 20, testList);
}
@Test
@@ -98,5 +102,4 @@ public void filmIs0Duration() {
Assertions.assertEquals("продолжительность <= 0", exception.getMessage());
}
-
}
diff --git a/src/test/java/ru/yandex/practicum/filmorate/UserControllerTest.java b/src/test/java/ru/yandex/practicum/filmorate/UserControllerTest.java
index 973cfa7..1f633f6 100644
--- a/src/test/java/ru/yandex/practicum/filmorate/UserControllerTest.java
+++ b/src/test/java/ru/yandex/practicum/filmorate/UserControllerTest.java
@@ -9,17 +9,21 @@
import ru.yandex.practicum.filmorate.model.User;
import java.time.LocalDate;
+import java.util.HashSet;
+import java.util.Set;
public class UserControllerTest {
Exception exception;
private final ValidateController validate = new ValidateController();
- User user;
+ private User user;
+ Set testList = new HashSet<>() {
+ };
@BeforeEach
void setUp() {
- user = new User(1L, "ya@yandex.ru", "login", "name", LocalDate.now().minusYears(3));
+ user = new User(1L, "ya@yandex.ru", "login", "name", LocalDate.now().minusYears(3), testList);
}
@Test
@@ -92,4 +96,11 @@ public void userFutureBirthday() {
Assertions.assertEquals("введена дата из будущего", exception.getMessage());
}
+ @Test
+ public void userFriends() {
+ User user1 = new User(1L, "ya1@yandex.ru", "login1", "name1", LocalDate.now().minusYears(3), testList);
+ User user2 = new User(2L, "ya2@yandex.ru", "login2", "name2", LocalDate.now().minusYears(3), testList);
+ user1.getFriendsId().add(2L);
+ Assertions.assertEquals(2, user1.getFriendsId().stream().toList().get(0));
+ }
}
diff --git a/src/test/java/ru/yandex/practicum/filmorate/ValidateTest.java b/src/test/java/ru/yandex/practicum/filmorate/ValidateTest.java
index de8c47f..a37520e 100644
--- a/src/test/java/ru/yandex/practicum/filmorate/ValidateTest.java
+++ b/src/test/java/ru/yandex/practicum/filmorate/ValidateTest.java
@@ -10,6 +10,7 @@
import ru.yandex.practicum.filmorate.model.User;
import java.time.LocalDate;
+import java.util.HashSet;
import java.util.Set;
import static org.assertj.core.api.Assertions.assertThat;
@@ -19,6 +20,8 @@
public class ValidateTest {
private Validator validator;
+ Set testList = new HashSet<>() {
+ };
@BeforeEach
void setUp() {
@@ -27,14 +30,14 @@ void setUp() {
@Test
void validatorUserOk() {
- User user = new User(1L, "name@yabex.ru", "log", "name", LocalDate.now().minusYears(3));
+ User user = new User(1L, "name@yabex.ru", "log", "name", LocalDate.now().minusYears(3), testList);
Set> violations = validator.validate(user);
assertTrue(violations.isEmpty());
}
@Test
void validatorUserTest() {
- User user = new User(1L, "nameyabex.ru", "log", "name", LocalDate.now().plusYears(3));
+ User user = new User(1L, "nameyabex.ru", "log", "name", LocalDate.now().plusYears(3), testList);
Set> violations = validator.validate(user);
assertFalse(violations.isEmpty());
assertThat(violations).hasSize(2);
@@ -44,7 +47,7 @@ void validatorUserTest() {
@Test
void validatorUserNotNull() {
- User user = new User(1L, null, null, "name", null);
+ User user = new User(1L, null, null, "name", null, testList);
Set> violations = validator.validate(user);
assertFalse(violations.isEmpty());
assertThat(violations).hasSize(3);
@@ -54,7 +57,7 @@ void validatorUserNotNull() {
@Test
void validatorFilmOk() {
- Film film = new Film(1L, "kino", "kino o kine", LocalDate.of(1990, 02, 22), 25);
+ Film film = new Film(1L, "kino", "kino o kine", LocalDate.of(1990, 02, 22), 25, testList);
Set> violations = validator.validate(film);
assertTrue(violations.isEmpty());
}
@@ -62,7 +65,7 @@ void validatorFilmOk() {
@Test
void validatorFilmTest() {
Film film = new Film(1L, "kino", Strings.repeat("*", 220),
- LocalDate.now().plusYears(3), 2);
+ LocalDate.now().plusYears(3), 2, testList);
Set> violations = validator.validate(film);
assertFalse(violations.isEmpty());
assertThat(violations).hasSize(2);
@@ -73,7 +76,7 @@ void validatorFilmTest() {
@Test
void validatorFilmNotNull() {
Film film = new Film(1L, null, null,
- null, 2);
+ null, 2, testList);
Set> violations = validator.validate(film);
assertFalse(violations.isEmpty());
assertThat(violations).hasSize(3);