diff --git a/src/main/java/team7/inplace/influencer/application/InfluencerService.java b/src/main/java/team7/inplace/influencer/application/InfluencerService.java index ca1c0c0b..c1da9fd7 100644 --- a/src/main/java/team7/inplace/influencer/application/InfluencerService.java +++ b/src/main/java/team7/inplace/influencer/application/InfluencerService.java @@ -1,17 +1,30 @@ package team7.inplace.influencer.application; import java.util.List; + import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; +import team7.inplace.global.exception.InplaceException; +import team7.inplace.global.exception.code.AuthorizationErrorCode; import team7.inplace.influencer.application.dto.InfluencerInfo; +import team7.inplace.influencer.domain.Influencer; import team7.inplace.influencer.persistence.InfluencerRepository; +import team7.inplace.influencer.presentation.dto.InfluencerRequestParam; +import team7.inplace.userFavoriteInfluencer.domain.UserFavoriteInfluencer; +import team7.inplace.userFavoriteInfluencer.persistent.UserFavoriteInfluencerRepository; +import team7.inplace.security.util.AuthorizationUtil; +import team7.inplace.user.domain.User; +import team7.inplace.user.persistence.UserRepository; @RequiredArgsConstructor @Service public class InfluencerService { private final InfluencerRepository influencerRepository; + private final UserFavoriteInfluencerRepository favoriteRepository; + private final UserRepository userRepository; @Transactional(readOnly = true) public List getAllInfluencers() { @@ -19,4 +32,18 @@ public List getAllInfluencers() { .map(InfluencerInfo::from) .toList(); } + + public void likeToInfluencer(InfluencerRequestParam param){ + String username = AuthorizationUtil.getUsername(); + if(StringUtils.hasText(username)){ + throw InplaceException.of(AuthorizationErrorCode.TOKEN_IS_EMPTY); + } + + User user = userRepository.findByUsername(username).orElseThrow(); + Influencer influencer = influencerRepository.findById(param.influencerId()).orElseThrow(); + + UserFavoriteInfluencer favorite = new UserFavoriteInfluencer(user, influencer); + favorite.check(param.likes()); + favoriteRepository.save(favorite); + } } diff --git a/src/main/java/team7/inplace/influencer/presentation/InfluencerController.java b/src/main/java/team7/inplace/influencer/presentation/InfluencerController.java index dbe86ed4..586c0220 100644 --- a/src/main/java/team7/inplace/influencer/presentation/InfluencerController.java +++ b/src/main/java/team7/inplace/influencer/presentation/InfluencerController.java @@ -4,20 +4,21 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import team7.inplace.influencer.application.InfluencerService; import team7.inplace.influencer.application.dto.InfluencerInfo; import team7.inplace.influencer.presentation.dto.InfluencerListResponse; +import team7.inplace.influencer.presentation.dto.InfluencerRequestParam; import team7.inplace.influencer.presentation.dto.InfluencerResponse; @RequiredArgsConstructor @RestController +@RequestMapping("/influencers") public class InfluencerController { private final InfluencerService influencerService; - @GetMapping("/influencers") + @GetMapping() public ResponseEntity getAllInfluencers() { List influencersDtoList = influencerService.getAllInfluencers(); List influencers = influencersDtoList.stream() @@ -28,4 +29,11 @@ public ResponseEntity getAllInfluencers() { return new ResponseEntity<>(response, HttpStatus.OK); } + @PostMapping("/likes") + public ResponseEntity likeToInfluencer( + @ModelAttribute InfluencerRequestParam param + ) { + influencerService.likeToInfluencer(param); + return new ResponseEntity<>(HttpStatus.OK); + } } diff --git a/src/main/java/team7/inplace/influencer/presentation/dto/InfluencerRequestParam.java b/src/main/java/team7/inplace/influencer/presentation/dto/InfluencerRequestParam.java new file mode 100644 index 00000000..ba3544f6 --- /dev/null +++ b/src/main/java/team7/inplace/influencer/presentation/dto/InfluencerRequestParam.java @@ -0,0 +1,7 @@ +package team7.inplace.influencer.presentation.dto; + +public record InfluencerRequestParam( + Long influencerId, + Boolean likes +) { +} diff --git a/src/main/java/team7/inplace/user/application/UserService.java b/src/main/java/team7/inplace/user/application/UserService.java index 8edf6daf..ca4c315f 100644 --- a/src/main/java/team7/inplace/user/application/UserService.java +++ b/src/main/java/team7/inplace/user/application/UserService.java @@ -1,19 +1,23 @@ package team7.inplace.user.application; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import team7.inplace.influencer.domain.Influencer; +import team7.inplace.userFavoriteInfluencer.domain.UserFavoriteInfluencer; +import team7.inplace.userFavoriteInfluencer.persistent.UserFavoriteInfluencerRepository; import team7.inplace.user.application.dto.UserCommand; import team7.inplace.user.domain.User; import team7.inplace.user.persistence.UserRepository; +import java.util.List; + @Service +@RequiredArgsConstructor public class UserService { private final UserRepository userRepository; - - public UserService(UserRepository userRepository) { - this.userRepository = userRepository; - } + private final UserFavoriteInfluencerRepository userFavoriteInfluencerRepository; @Transactional public void registerUser(UserCommand.Create userCreate) { @@ -30,4 +34,10 @@ public boolean isExistUser(String username) { public UserCommand.Info getUserByUsername(String username) { return UserCommand.Info.of(userRepository.findByUsername(username).orElseThrow()); } + + @Transactional(readOnly = true) + public List getInfluencerIdsByUsername(Long userId) { + List likes = userFavoriteInfluencerRepository.findByUserId(userId); + return likes.stream().map(UserFavoriteInfluencer::getInfluencer).map(Influencer::getId).toList(); + } } diff --git a/src/main/java/team7/inplace/userFavoriteInfluencer/domain/UserFavoriteInfluencer.java b/src/main/java/team7/inplace/userFavoriteInfluencer/domain/UserFavoriteInfluencer.java new file mode 100644 index 00000000..a69a88fe --- /dev/null +++ b/src/main/java/team7/inplace/userFavoriteInfluencer/domain/UserFavoriteInfluencer.java @@ -0,0 +1,48 @@ +package team7.inplace.userFavoriteInfluencer.domain; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import team7.inplace.influencer.domain.Influencer; +import team7.inplace.user.domain.User; + +import static jakarta.persistence.GenerationType.IDENTITY; +import static lombok.AccessLevel.PROTECTED; + +@Getter +@RequiredArgsConstructor +@NoArgsConstructor(access = PROTECTED) +@Entity +public class UserFavoriteInfluencer { + @Id + @GeneratedValue(strategy = IDENTITY) + private Long id; + @ManyToOne + @NonNull + @JoinColumn(name = "user_id") + private User user; + @ManyToOne + @NonNull + @JoinColumn(name = "influencer_id") + private Influencer influencer; + @Column + private boolean like = false; + + public void check(boolean check) { + if (check) { + like(); + return; + } + dislike(); + } + + private void like() { + this.like = true; + } + + private void dislike() { + this.like = false; + } +} diff --git a/src/main/java/team7/inplace/userFavoriteInfluencer/persistent/UserFavoriteInfluencerRepository.java b/src/main/java/team7/inplace/userFavoriteInfluencer/persistent/UserFavoriteInfluencerRepository.java new file mode 100644 index 00000000..85a36861 --- /dev/null +++ b/src/main/java/team7/inplace/userFavoriteInfluencer/persistent/UserFavoriteInfluencerRepository.java @@ -0,0 +1,11 @@ +package team7.inplace.userFavoriteInfluencer.persistent; + +import org.springframework.data.jpa.repository.JpaRepository; +import team7.inplace.userFavoriteInfluencer.domain.UserFavoriteInfluencer; +import team7.inplace.user.domain.User; + +import java.util.List; + +public interface UserFavoriteInfluencerRepository extends JpaRepository { + List findByUserId(Long userId); +} diff --git a/src/main/java/team7/inplace/video/application/VideoService.java b/src/main/java/team7/inplace/video/application/VideoService.java index 0d78596d..1d4b4647 100644 --- a/src/main/java/team7/inplace/video/application/VideoService.java +++ b/src/main/java/team7/inplace/video/application/VideoService.java @@ -5,11 +5,16 @@ import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; import team7.inplace.global.exception.InplaceException; import team7.inplace.global.exception.code.AuthorizationErrorCode; +import team7.inplace.global.exception.code.VideoErrorCode; import team7.inplace.place.application.dto.PlaceForVideo; import team7.inplace.place.domain.Place; import team7.inplace.place.persistence.PlaceRepository; +import team7.inplace.security.util.AuthorizationUtil; +import team7.inplace.user.application.UserService; import team7.inplace.video.application.dto.VideoInfo; import team7.inplace.video.domain.Video; import team7.inplace.video.persistence.VideoRepository; @@ -24,6 +29,7 @@ public class VideoService { private final VideoRepository videoRepository; private final PlaceRepository placeRepository; + private final UserService userService; public Page getVideosBySurround(VideoSearchParams videoSearchParams, Pageable pageable) { Page places = placeRepository.getPlacesByDistance( @@ -37,7 +43,7 @@ public Page getVideosBySurround(VideoSearchParams videoSearchParams, if (videos.size() == places.getSize()) break; videos.add(videoRepository.findTopByPlaceOrderByIdDesc(place) - .orElseThrow(()-> InplaceException.of(AuthorizationErrorCode.NO_SUCH_VIDEO))); + .orElseThrow(()-> InplaceException.of(VideoErrorCode.NO_SUCH_VIDEO))); } return new PageImpl<>(videos).map(this::videoToInfo); } @@ -50,6 +56,20 @@ public Page getAllVideosDesc(Pageable pageable) { return videos.map(this::videoToInfo); } + public Page getVideosByMyInfluencer(Pageable pageable){ + // User 정보를 쿠키에서 추출 + Long userId = AuthorizationUtil.getUserId(); + // 토큰 정보에 대한 검증 + if(ObjectUtils.isEmpty(userId)) { + throw InplaceException.of(AuthorizationErrorCode.TOKEN_IS_EMPTY); + } + // 유저 정보를 이용하여 유저가 좋아요를 누른 인플루언서 id 리스트를 조회 + List influencerIds = userService.getInfluencerIdsByUsername(userId); + // 인플루언서 id 리스트를 이용하여 해당 인플루언서의 비디오들을 조회 + Page