From 463296c358bf7848fa3dfff5087d729e1e195c2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=91=D0=B0=D0=BA=D0=B0?= =?UTF-8?q?=D0=BB=D1=8C=D1=81=D0=BA=D0=B0=D1=8F?= Date: Thu, 20 Jun 2024 02:06:02 +0400 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD?= =?UTF-8?q?=D0=BE=20=D0=BD=D0=B0=D1=87=D0=B0=D0=BB=D0=BE=20=D0=B2=D1=8B?= =?UTF-8?q?=D0=B1=D0=BE=D1=80=D1=83=20=D0=B2=20=D0=B8=D0=B7=D0=B1=D1=80?= =?UTF-8?q?=D0=B0=D0=BD=D0=BD=D0=BE=D0=B5=20=D0=B4=D0=BB=D1=8F=20=D1=84?= =?UTF-8?q?=D0=B8=D0=BB=D1=8C=D0=BC=D0=BE=D1=8B=20=D0=BF=D1=80=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D0=BE=20=D0=B2=20=D0=BA=D0=B0=D1=82=D0=B0=D0=BB=D0=BE?= =?UTF-8?q?=D0=B3=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/backend/BackendApplication.java | 12 ++- .../repository/FavoriteRepository.java | 3 + .../favorites/service/FavoriteService.java | 6 ++ .../movies/api/MovieUserController.java | 38 ++++++- .../users/repository/UserRepository.java | 2 + .../backend/users/service/UserService.java | 12 +++ .../main/resources/templates/movie-edit.html | 2 + .../src/main/resources/templates/movies.html | 99 +++++++++++++----- data.mv.db | Bin 237568 -> 274432 bytes 9 files changed, 144 insertions(+), 30 deletions(-) diff --git a/backend/src/main/java/com/example/backend/BackendApplication.java b/backend/src/main/java/com/example/backend/BackendApplication.java index 0b18e99..183ad5a 100644 --- a/backend/src/main/java/com/example/backend/BackendApplication.java +++ b/backend/src/main/java/com/example/backend/BackendApplication.java @@ -8,6 +8,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import com.example.backend.categories.model.CategorieEntity; import com.example.backend.categories.service.CategorieService; +import com.example.backend.favorites.model.FavoriteEntity; +import com.example.backend.favorites.service.FavoriteService; import com.example.backend.movies.model.MovieEntity; import com.example.backend.movies.service.MovieService; import com.example.backend.users.service.UserService; @@ -21,12 +23,15 @@ public class BackendApplication implements CommandLineRunner { private final UserService userService; private final CategorieService categorieService; private final MovieService movieService; + private final FavoriteService favoriyService; public BackendApplication(UserService userService, CategorieService categorieService, - MovieService movieService) { + MovieService movieService, + FavoriteService favoriyService) { this.userService = userService; this.categorieService = categorieService; + this.favoriyService = favoriyService; this.movieService = movieService; } @@ -84,6 +89,11 @@ public class BackendApplication implements CommandLineRunner { // categorieService.create(cat4); // categorieService.create(cat5); // movieService.create(mov1); + favoriyService.create(new FavoriteEntity(null, userService.get(2), movieService.get(98))); + // movieService.get(98)); + // for (var fav : favoriyService.getAll(2)) { + // favoriyService.delete(fav.getId()); + // } _logger.info("The program is started"); } diff --git a/backend/src/main/java/com/example/backend/favorites/repository/FavoriteRepository.java b/backend/src/main/java/com/example/backend/favorites/repository/FavoriteRepository.java index 52b6636..81c27fe 100644 --- a/backend/src/main/java/com/example/backend/favorites/repository/FavoriteRepository.java +++ b/backend/src/main/java/com/example/backend/favorites/repository/FavoriteRepository.java @@ -7,7 +7,10 @@ import org.springframework.data.repository.CrudRepository; import com.example.backend.favorites.model.FavoriteEntity; public interface FavoriteRepository extends CrudRepository { + List findByUserId(Integer userId); + List findByUserIdAndMovieId(Integer userId, Integer movieId); + Optional findOneByUserIdAndId(Integer userId, Integer id); } diff --git a/backend/src/main/java/com/example/backend/favorites/service/FavoriteService.java b/backend/src/main/java/com/example/backend/favorites/service/FavoriteService.java index 4058ae6..7849d62 100644 --- a/backend/src/main/java/com/example/backend/favorites/service/FavoriteService.java +++ b/backend/src/main/java/com/example/backend/favorites/service/FavoriteService.java @@ -31,6 +31,12 @@ public class FavoriteService { return repository.findById(id).orElseThrow(() -> new NotFoundException(FavoriteEntity.class, id)); } + // @Transactional(readOnly = true) + // public List getForAddToFavorite(Integer userId, Integer + // movieId) { + // return repository.findByUserIdAndMovieId(userId, movieId); + // } + @Transactional public FavoriteEntity create(FavoriteEntity entity) { return repository.save(entity); diff --git a/backend/src/main/java/com/example/backend/movies/api/MovieUserController.java b/backend/src/main/java/com/example/backend/movies/api/MovieUserController.java index 7b2cf16..c4ae309 100644 --- a/backend/src/main/java/com/example/backend/movies/api/MovieUserController.java +++ b/backend/src/main/java/com/example/backend/movies/api/MovieUserController.java @@ -1,19 +1,26 @@ package com.example.backend.movies.api; +import java.util.List; + import org.modelmapper.ModelMapper; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import com.example.backend.categories.service.CategorieService; import com.example.backend.core.configurations.Constants; +import com.example.backend.favorites.model.FavoriteEntity; +import com.example.backend.favorites.service.FavoriteService; import com.example.backend.movies.model.MovieEntity; import com.example.backend.movies.service.MovieService; +import com.example.backend.users.service.UserService; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; +import org.springframework.security.core.Authentication; import jakarta.validation.Valid; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; @@ -34,12 +41,21 @@ public class MovieUserController { private final MovieService movieService; private final CategorieService categorieService; + private final UserService userService; + private final FavoriteService favoriteService; + private final ModelMapper modelMapper; - public MovieUserController(MovieService movieService, CategorieService categorieService, ModelMapper modelMapper) { + public MovieUserController(MovieService movieService, + CategorieService categorieService, + ModelMapper modelMapper, + UserService userService, + FavoriteService favoriteService) { this.modelMapper = modelMapper; this.categorieService = categorieService; this.movieService = movieService; + this.userService = userService; + this.favoriteService = favoriteService; } private MovieDTO toDto(MovieEntity entity) { @@ -60,9 +76,15 @@ public class MovieUserController { .stream() .map(this::toDto) .toList()); + model.addAttribute(CATEGORIEID_ATTRIBUTE, model); model.addAttribute("categories", categorieService.getAll()); - model.addAttribute(PAGE_ATTRIBUTE, page); + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + Integer currentUserId = userService.getCurrentUserId(authentication.getName()); + + List favs = favoriteService.getAll(currentUserId); + + model.addAttribute("favorites", favs); model.addAttribute(CATEGORIEID_ATTRIBUTE, 0); return MOVIE_VIEW; } @@ -76,13 +98,25 @@ public class MovieUserController { .stream() .map(this::toDto) .toList()); + model.addAttribute("categories", categorieService.getAll()); + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + Integer currentUserId = userService.getCurrentUserId(authentication.getName()); + + List favs = favoriteService.getAll(currentUserId); + + model.addAttribute("favorites", favs); model.addAttribute(PAGE_ATTRIBUTE, page); model.addAttribute(CATEGORIEID_ATTRIBUTE, categorieId); return MOVIE_VIEW; } + @GetMapping("/addToFavorite/{id}") + public String changeStatusForFavorite() { + return Constants.REDIRECT_VIEW + URL; + } + @GetMapping("/countView") public Integer countView(@RequestParam(name = "movieId", defaultValue = "0") Integer movieId) { return movieService.countView(movieId); diff --git a/backend/src/main/java/com/example/backend/users/repository/UserRepository.java b/backend/src/main/java/com/example/backend/users/repository/UserRepository.java index fd63fff..1a9b14c 100644 --- a/backend/src/main/java/com/example/backend/users/repository/UserRepository.java +++ b/backend/src/main/java/com/example/backend/users/repository/UserRepository.java @@ -9,4 +9,6 @@ import com.example.backend.users.model.UserEntity; public interface UserRepository extends CrudRepository, PagingAndSortingRepository { Optional findByLoginIgnoreCase(String login); + + Integer getIdByLoginIgnoreCase(String login); } diff --git a/backend/src/main/java/com/example/backend/users/service/UserService.java b/backend/src/main/java/com/example/backend/users/service/UserService.java index ea0a889..900e891 100644 --- a/backend/src/main/java/com/example/backend/users/service/UserService.java +++ b/backend/src/main/java/com/example/backend/users/service/UserService.java @@ -8,6 +8,7 @@ import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.core.Authentication; import org.springframework.stereotype.Service; import org.springframework.data.domain.Page; import org.springframework.data.domain.Sort; @@ -26,6 +27,7 @@ import com.example.backend.users.repository.UserRepository; @Service public class UserService implements UserDetailsService { + private final UserRepository repository; private final PasswordEncoder passwordEncoder; @@ -96,10 +98,20 @@ public class UserService implements UserDetailsService { return existsentity; } + @Transactional + public Integer getCurrentUserId(String name) { + final Optional user = repository.findByLoginIgnoreCase(name); + if (user.isEmpty()) { + throw new IllegalArgumentException(); + } + return user.get().getId(); + } + @Override @Transactional(readOnly = true) public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { final UserEntity existUser = getByUsername(username); return new UserPrincipal(existUser); } + } diff --git a/backend/src/main/resources/templates/movie-edit.html b/backend/src/main/resources/templates/movie-edit.html index 713b614..f657b9c 100644 --- a/backend/src/main/resources/templates/movie-edit.html +++ b/backend/src/main/resources/templates/movie-edit.html @@ -30,6 +30,7 @@
+
- - - - - - + + +
+ + +

+ д етить колотить +

+ + +
+ + + + +
+
+
-
- + + - --> + + + + + + + + currentPage=${currentPage}) }"> + + + diff --git a/data.mv.db b/data.mv.db index 235d3e17d1927d572d8895f893875a29e663312e..c9d04f602ceea05f495efb337e9c8df5241de63b 100644 GIT binary patch delta 18343 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 delta 16011 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