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
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.zalando</groupId>
<artifactId>logbook-spring-boot-starter</artifactId>
<version>3.7.2</version>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,4 @@ public class FilmorateApplication {
public static void main(String[] args) {
SpringApplication.run(FilmorateApplication.class, args);
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,72 +3,59 @@
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import ru.yandex.practicum.filmorate.exception.NotFoundException;
import ru.yandex.practicum.filmorate.exception.ValidationException;
import ru.yandex.practicum.filmorate.model.Film;
import ru.yandex.practicum.filmorate.service.FilmService;
import ru.yandex.practicum.filmorate.storage.FilmStorage;

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

@Slf4j
@RestController
@RequestMapping("/films")
public class FilmController {
private final Map<Long, Film> films = new HashMap<>();
private final FilmStorage filmStorage;
private final FilmService filmService;

public FilmController(FilmStorage filmStorage, FilmService filmService) {
this.filmStorage = filmStorage;
this.filmService = filmService;
}

@GetMapping
public Collection<Film> findAll() {
return films.values();
return filmStorage.findAll();
}

@PostMapping
public Film create(@Valid @RequestBody Film film) {
log.info("Попытка добавления нового фильма в коллекцию: {}", film.getName());
if (film.getId() != null && films.containsKey(film.getId())) {
log.error("Ошибка добавления: Фильм уже имеется в коллекции");
throw new ValidationException("Фильм уже имеется в коллекции");
}
film.setId(getNextId());
films.put(film.getId(), film);
log.info("Фильм: '{}', успешно добавлен в коллекцию", film.getName());
return film;
@GetMapping("/{id}")
public Film getFilmById(@PathVariable Long id) {
return filmStorage.getFilmById(id);
}

@PutMapping
public Film update(@Valid @RequestBody Film filmWithNewData) {
if (filmWithNewData.getId() == null || filmWithNewData.getId() == 0) {
throw new ValidationException("id должен быть указан");
}
log.info("Попытка обновления данных о фильме: '{}'", filmWithNewData.getName());
@PutMapping("/{id}/like/{userId}")
public void addLike(@PathVariable Long id,
@PathVariable Long userId) {
filmService.addLike(id, userId);
}

Film filmWithOldData = films.get(filmWithNewData.getId());
if (filmWithOldData == null) {
log.error("Ошибка обновления: фильм не найден");
throw new NotFoundException("Фильм не найден");
}
// меняем релиз-дату
if (filmWithNewData.isValidReleaseDate()) {
filmWithOldData.setReleaseDate(filmWithNewData.getReleaseDate());
}
// меняем название
filmWithOldData.setName(filmWithNewData.getName());
@DeleteMapping("/{id}/like/{userId}")
public void deleteLike(@PathVariable Long id,
@PathVariable Long userId) {
filmService.deleteLike(id, userId);
}

//меняем описание
filmWithOldData.setDescription(filmWithNewData.getDescription());
@PostMapping
public Film create(@Valid @RequestBody Film film) {
return filmStorage.create(film);
}

//меняем продолжительность фильма
filmWithOldData.setDuration(filmWithNewData.getDuration());
log.info("Данные о фильме '{}' успешно обновлены", filmWithOldData.getName());
return filmWithOldData;
@GetMapping("/popular")
public List<Film> getTopFilms(@RequestParam(name = "count", defaultValue = "10") int count) {
return filmService.getTopFilms(count);
}

private long getNextId() {
long currentMaxId = films.keySet()
.stream()
.mapToLong(id -> id)
.max()
.orElse(0);
return ++currentMaxId;
@PutMapping
public Film update(@Valid @RequestBody Film filmWithNewData) {
return filmStorage.update(filmWithNewData);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,104 +2,68 @@

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

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

@Slf4j
@RestController
@RequestMapping("/users")
public class UserController {
// для пользователей по id
private final Map<Long, User> users = new HashMap<>();
// для быстрой проверки уникальности email
private final Map<String, User> usersByEmail = new HashMap<>();
// для быстрой проверки уникальности login
private final Map<String, User> usersByLogin = new HashMap<>();
private final UserStorage userStorage;
private final UserService userService;

public UserController(UserStorage userStorage, UserService userService) {
this.userStorage = userStorage;
this.userService = userService;
}

@GetMapping
public Collection<User> findAll() {
return users.values();
return userStorage.findAll();
}

@PostMapping
public User create(@Valid @RequestBody User user) {
log.info("Попытка создания пользователя с email: {} и login: {}", user.getEmail(), user.getLogin());
if (users.containsKey(user.getId())) {
log.error("Ошибка создания пользователя: id {} уже используется", user.getId());
throw new ValidationException("Пользователь уже зарегистрирован");
}
if (usersByEmail.containsKey(user.getEmail())) {
log.error("Ошибка создания пользователя: email {} уже используется", user.getEmail());
throw new ValidationException("Данный email уже используется");
}
if (usersByLogin.containsKey(user.getLogin())) {
log.error("Ошибка создания пользователя: login {} уже используется", user.getLogin());
throw new ValidationException("Данный логин занят");
}
user.setId(getNextId());
users.put(user.getId(), user);
usersByEmail.put(user.getEmail(), user);
usersByLogin.put(user.getLogin(), user);
log.info("Пользователь успешно создан с id: {}, email: {}, login: {}",
user.getId(), user.getEmail(), user.getLogin());
return user;
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
return userStorage.getUserById(id);
}

@PutMapping
public User update(@Valid @RequestBody User userWithNewData) {
if (userWithNewData.getId() == null || userWithNewData.getId() == 0) {
throw new ValidationException("id должен быть указан");
}
log.info("Попытка обновления пользователя с id: {}", userWithNewData.getId());

User userWithOldData = users.get(userWithNewData.getId());
if (userWithOldData == null) {
log.error("Пользователь не найден");
throw new NotFoundException("Пользователь не найден");
}
if (!userWithNewData.getEmail().equals(userWithOldData.getEmail()) &&
usersByEmail.containsKey(userWithNewData.getEmail())) {
log.error("Ошибка обновления: email {} уже используется", userWithNewData.getEmail());
throw new ValidationException("Этот e-mail уже используется");
}
@PutMapping("/{id}/friends/{friendId}")
public void addFriend(@PathVariable Long id,
@PathVariable Long friendId) {
userService.addFriend(id, friendId);
}

// обновляем e-mail
usersByEmail.remove(userWithOldData.getEmail());
userWithOldData.setEmail(userWithNewData.getEmail());
usersByEmail.put(userWithOldData.getEmail(), userWithOldData);
@DeleteMapping("/{id}/friends/{friendId}")
public void deleteFriend(@PathVariable Long id,
@PathVariable Long friendId) {
userService.deleteFriend(id, friendId);
}

// обновляем логин
if (!userWithNewData.getLogin().equals(userWithOldData.getLogin()) &&
usersByLogin.containsKey(userWithNewData.getLogin())) {
log.error("Ошибка обновления: login {} уже используется", userWithNewData.getLogin());
throw new ValidationException("Этот логин уже используется");
}
usersByLogin.remove(userWithOldData.getLogin());
userWithOldData.setLogin(userWithNewData.getLogin());
usersByLogin.put(userWithOldData.getLogin(),userWithOldData);
@GetMapping("/{id}/friends")
public List<User> getUserFriends(@PathVariable Long id) {
return userService.getFriends(id);
}

// обновляем имя
userWithOldData.setName(userWithNewData.getName());
@GetMapping("/{id}/friends/common/{friendId}")
public List<User> getCommonFriends(@PathVariable Long id,
@PathVariable Long friendId) {
return userService.getCommonFriends(id, friendId);
}

// обновляем дату рождения
userWithOldData.setBirthday(userWithNewData.getBirthday());
log.info("Пользователь с id {} успешно обновлён", userWithOldData.getId());
return userWithOldData;
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public User create(@Valid @RequestBody User user) {
return userStorage.create(user);
}

private long getNextId() {
long currentMaxId = users.keySet()
.stream()
.mapToLong(id -> id)
.max()
.orElse(0);
return ++currentMaxId;
@PutMapping
public User update(@Valid @RequestBody User userWithNewData) {
return userStorage.update(userWithNewData);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package ru.yandex.practicum.filmorate.exception;

public class ConditionsNotMetException extends RuntimeException {
public ConditionsNotMetException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import ru.yandex.practicum.filmorate.dto.ErrorResponse;
Expand All @@ -26,8 +27,9 @@ public ResponseEntity<ErrorResponse> handleNotFound(NotFoundException e, HttpSer
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorResponse);
}

@ExceptionHandler(ValidationException.class)
public ResponseEntity<ErrorResponse> handleValidation(ValidationException e, HttpServletRequest request) {
@ExceptionHandler({ValidationException.class, MethodArgumentNotValidException.class})
public ResponseEntity<ErrorResponse> handleValidation(
ValidationException e, HttpServletRequest request) {
ErrorResponse errorResponse = new ErrorResponse(
LocalDateTime.now(),
HttpStatus.BAD_REQUEST.value(),
Expand All @@ -49,4 +51,4 @@ public ResponseEntity<ErrorResponse> handleOtherExceptions(Exception e, HttpServ
);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
}
}
}
15 changes: 14 additions & 1 deletion src/main/java/ru/yandex/practicum/filmorate/model/Film.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,25 @@

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

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

@Data
@RequiredArgsConstructor
public class Film {
private Long id;
private Set<Long> likes = new HashSet<>();

public Film(Long id, LocalDate releaseDate, String name, String description, int duration) {
this.id = id;
this.releaseDate = releaseDate;
this.name = name;
this.description = description;
this.duration = duration;
}

@NotNull
private LocalDate releaseDate;
Expand All @@ -28,4 +41,4 @@ public boolean isValidReleaseDate() {
LocalDate minReleaseDate = LocalDate.of(1895,12,28);
return !releaseDate.isBefore(minReleaseDate);
}
}
}
9 changes: 6 additions & 3 deletions src/main/java/ru/yandex/practicum/filmorate/model/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.*;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;

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

@Data
@NoArgsConstructor
@RequiredArgsConstructor
public class User {
private Long id;
private Set<Long> friends = new HashSet<>();

@NotBlank(message = "Электронная почта не может быть пустой")
@Email(message = "Электронная почта должна быть корректной и содержать символ '@'")
Expand Down Expand Up @@ -43,4 +46,4 @@ public User(@JsonProperty("id") Long id,
public void setName(String name) {
this.name = (name == null || name.isBlank()) ? this.login : name;
}
}
}
Loading