-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
✨ follow user #431
base: be/dev
Are you sure you want to change the base?
✨ follow user #431
Changes from all commits
650cd90
f3b4963
6d279bc
445864c
56d5e0a
f9df833
d9751a5
d92c465
f2618a4
1d45b50
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package net.pengcook.user.domain; | ||
|
||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.GenerationType; | ||
import jakarta.persistence.Id; | ||
import jakarta.persistence.JoinColumn; | ||
import jakarta.persistence.ManyToOne; | ||
import jakarta.persistence.Table; | ||
import jakarta.persistence.UniqueConstraint; | ||
import lombok.AccessLevel; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Entity | ||
@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"follower_id", "followee_id"})}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
@AllArgsConstructor(access = AccessLevel.PRIVATE) | ||
@Getter | ||
public class UserFollow { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private long id; | ||
|
||
@ManyToOne | ||
@JoinColumn(name = "follower_id") | ||
private User follower; | ||
|
||
@ManyToOne | ||
@JoinColumn(name = "followee_id") | ||
private User followee; | ||
|
||
public UserFollow(User follower, User followee) { | ||
this(0L, follower, followee); | ||
} | ||
Comment on lines
+35
to
+37
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 좋네요. �유니크 키가 있긴 하지만 validate 함수를 만들어 검사하는것이 빠르게 예외를 발생시킬 방법인것 같아요 |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,8 +24,8 @@ public ProfileResponse(User user, long recipeCount) { | |
user.getImage(), | ||
user.getRegion(), | ||
"hello world", | ||
0, | ||
0, | ||
user.getUserFollowerCount(), | ||
user.getUserFolloweeCount(), | ||
Comment on lines
-27
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 팔로우 여부를 필드로 추가해야 하겠어요! |
||
recipeCount | ||
); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package net.pengcook.user.dto; | ||
|
||
import jakarta.validation.constraints.NotNull; | ||
|
||
public record UserFollowRequest(@NotNull long targetId) { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package net.pengcook.user.dto; | ||
|
||
import net.pengcook.user.domain.UserFollow; | ||
|
||
public record UserFollowResponse( | ||
long followerId, | ||
long followeeId | ||
) { | ||
public UserFollowResponse(UserFollow userFollow) { | ||
this( | ||
userFollow.getFollower().getId(), | ||
userFollow.getFollowee().getId() | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package net.pengcook.user.repository; | ||
|
||
import java.util.List; | ||
import java.util.Optional; | ||
import net.pengcook.user.domain.UserFollow; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface UserFollowRepository extends JpaRepository<UserFollow, Long> { | ||
|
||
Optional<UserFollow> findByFollowerIdAndFolloweeId(Long followerId, Long followeeId); | ||
|
||
List<UserFollow> findAllByFollowerId(long followerId); | ||
|
||
List<UserFollow> findAllByFolloweeId(long followeeId); | ||
Comment on lines
+10
to
+14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
또는 차단 했을때 팔로우를 지울지도 고민이 필요해보여요. 이 부분은 정책 회의때 이야기 해봐야 할것 같네요. |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,18 +12,21 @@ | |
import net.pengcook.user.domain.BlockedUserGroup; | ||
import net.pengcook.user.domain.User; | ||
import net.pengcook.user.domain.UserBlock; | ||
import net.pengcook.user.domain.UserFollow; | ||
import net.pengcook.user.domain.UserReport; | ||
import net.pengcook.user.dto.ProfileResponse; | ||
import net.pengcook.user.dto.ReportRequest; | ||
import net.pengcook.user.dto.ReportResponse; | ||
import net.pengcook.user.dto.UpdateProfileRequest; | ||
import net.pengcook.user.dto.UpdateProfileResponse; | ||
import net.pengcook.user.dto.UserBlockResponse; | ||
import net.pengcook.user.dto.UserFollowResponse; | ||
import net.pengcook.user.dto.UserResponse; | ||
import net.pengcook.user.dto.UsernameCheckResponse; | ||
import net.pengcook.user.exception.NotFoundException; | ||
import net.pengcook.user.exception.UserNotFoundException; | ||
import net.pengcook.user.repository.UserBlockRepository; | ||
import net.pengcook.user.repository.UserFollowRepository; | ||
import net.pengcook.user.repository.UserReportRepository; | ||
import net.pengcook.user.repository.UserRepository; | ||
import org.springframework.stereotype.Service; | ||
|
@@ -42,6 +45,7 @@ public class UserService { | |
private final UserBlockRepository userBlockRepository; | ||
private final UserReportRepository userReportRepository; | ||
private final ImageClientService imageClientService; | ||
private final UserFollowRepository userFollowRepository; | ||
|
||
@Transactional(readOnly = true) | ||
public ProfileResponse getUserById(long userId) { | ||
|
@@ -127,11 +131,49 @@ public void deleteUser(UserInfo userInfo) { | |
userBlockRepository.deleteByBlockeeId(userInfo.getId()); | ||
userReportRepository.deleteByReporterId(userInfo.getId()); | ||
userReportRepository.deleteByReporteeId(userInfo.getId()); | ||
|
||
List<Long> userRecipes = recipeRepository.findRecipeIdsByUserId(userInfo.getId()); | ||
for (Long recipeId : userRecipes) { | ||
recipeService.deleteRecipe(userInfo, recipeId); | ||
} | ||
|
||
List<UserFollow> followings = userFollowRepository.findAllByFollowerId(userInfo.getId()); | ||
for (UserFollow userFollow : followings) { | ||
userFollow.getFollowee().decreaseUserFollowerCount(); | ||
userFollowRepository.delete(userFollow); | ||
} | ||
List<UserFollow> followers = userFollowRepository.findAllByFolloweeId(userInfo.getId()); | ||
for (UserFollow userFollow : followers) { | ||
userFollow.getFollower().decreaseUserFolloweeCount(); | ||
userFollowRepository.delete(userFollow); | ||
} | ||
Comment on lines
+139
to
+148
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 생각해보니 유저가 탈퇴했을 때 좋아요 개수는 변하지 않지만 팔로우 개수는 변하는군요...!!! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 제가 보기에는 팔로우 수가 줄어드는게 맞는것 같아요. 👍 |
||
userRepository.delete(user); | ||
} | ||
|
||
@Transactional | ||
public UserFollowResponse followUser(long followerId, long followeeId) { | ||
User follower = userRepository.findById(followerId) | ||
.orElseThrow(() -> new NotFoundException("팔로워 정보를 조회할 수 없습니다.")); | ||
Comment on lines
+152
to
+155
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 서비스 메서드가 재사용 가능하게 잘 만들어진것 같아요. |
||
User followee = userRepository.findById(followeeId) | ||
.orElseThrow(() -> new NotFoundException("팔로이 정보를 조회할 수 없습니다.")); | ||
UserFollow userFollow = new UserFollow(follower, followee); | ||
|
||
userFollowRepository.save(userFollow); | ||
follower.increaseUserFolloweeCount(); | ||
followee.increaseUserFollowerCount(); | ||
return new UserFollowResponse(userFollow); | ||
} | ||
|
||
@Transactional | ||
public void unfollowUser(long followerId, long followeeId) { | ||
User follower = userRepository.findById(followerId) | ||
.orElseThrow(() -> new NotFoundException("팔로워 정보를 조회할 수 없습니다.")); | ||
User followee = userRepository.findById(followeeId) | ||
.orElseThrow(() -> new NotFoundException("팔로이 정보를 조회할 수 없습니다.")); | ||
UserFollow userFollow = userFollowRepository.findByFollowerIdAndFolloweeId(followerId, followeeId) | ||
.orElseThrow(() -> new NotFoundException("팔로우 관계를 찾을 수 없습니다.")); | ||
|
||
userFollowRepository.delete(userFollow); | ||
follower.decreaseUserFolloweeCount(); | ||
followee.decreaseUserFollowerCount(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,7 @@ | |
import net.pengcook.user.dto.UpdateProfileRequest; | ||
import net.pengcook.user.dto.UpdateProfileResponse; | ||
import net.pengcook.user.dto.UserBlockRequest; | ||
import net.pengcook.user.dto.UserFollowRequest; | ||
import net.pengcook.user.repository.UserRepository; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
|
@@ -224,7 +225,7 @@ void checkUsernameWhenDuplicateUsername() { | |
} | ||
|
||
@Test | ||
@WithLoginUser | ||
@WithLoginUser(email = "[email protected]") | ||
@DisplayName("레시피 또는 사용자 또는 댓글을 신고한다.") | ||
void report() { | ||
ReportRequest spamReportRequest = new ReportRequest( | ||
|
@@ -263,7 +264,7 @@ void report() { | |
.then().log().all() | ||
.statusCode(201) | ||
.body("reportId", is(1)) | ||
.body("reporterId", is(9)) | ||
.body("reporterId", is(5)) | ||
.body("reporteeId", is(1)) | ||
.body("reason", is(Reason.SPAM_CONTENT.name())) | ||
.body("type", is(Type.RECIPE.name())) | ||
|
@@ -338,7 +339,7 @@ void blockUser() { | |
} | ||
|
||
@Test | ||
@WithLoginUser(email = "[email protected]") | ||
@WithLoginUser | ||
@DisplayName("사용자를 삭제한다.") | ||
void deleteUser() { | ||
RestAssured.given(spec).log().all() | ||
|
@@ -351,8 +352,73 @@ void deleteUser() { | |
.then().log().all() | ||
.statusCode(204); | ||
|
||
boolean exists = userRepository.existsByEmail("loki@pengcook.net"); | ||
boolean exists = userRepository.existsByEmail("tester@pengcook.net"); | ||
|
||
assertThat(exists).isFalse(); | ||
} | ||
|
||
@Test | ||
@WithLoginUser(email = "[email protected]") | ||
@DisplayName("사용자를 팔로우한다.") | ||
void follow() { | ||
UserFollowRequest userFollowRequest = new UserFollowRequest(3); | ||
|
||
RestAssured.given(spec).log().all() | ||
.filter(document(DEFAULT_RESTDOCS_PATH, | ||
"사용자를 팔로우한다.", | ||
"팔로우 API", | ||
requestFields( | ||
fieldWithPath("targetId").description("팔로이 id") | ||
), | ||
responseFields( | ||
fieldWithPath("followerId").description("팔로워 id"), | ||
fieldWithPath("followeeId").description("팔로이 id") | ||
))) | ||
.contentType(ContentType.JSON) | ||
.when() | ||
.body(userFollowRequest) | ||
.post("/user/follow") | ||
.then().log().all() | ||
.statusCode(201) | ||
.body("followerId", is(5)) | ||
.body("followeeId", is(3)); | ||
} | ||
|
||
@Test | ||
@WithLoginUser(email = "[email protected]") | ||
@DisplayName("사용자를 언팔로우한다.") | ||
void unfollow() { | ||
UserFollowRequest userFollowRequest = new UserFollowRequest(4); | ||
|
||
RestAssured.given(spec).log().all() | ||
.filter(document(DEFAULT_RESTDOCS_PATH, | ||
"사용자를 언팔로우한다.", | ||
"언팔로우 API" | ||
)) | ||
.contentType(ContentType.JSON) | ||
.when() | ||
.body(userFollowRequest) | ||
.delete("/user/follow") | ||
.then().log().all() | ||
.statusCode(204); | ||
} | ||
|
||
@Test | ||
@WithLoginUser(email = "[email protected]") | ||
@DisplayName("팔로워를 삭제한다.") | ||
void removeFollower() { | ||
UserFollowRequest userFollowRequest = new UserFollowRequest(4); | ||
|
||
RestAssured.given(spec).log().all() | ||
.filter(document(DEFAULT_RESTDOCS_PATH, | ||
"팔로워를 삭제한다.", | ||
"팔로워 삭제 API" | ||
)) | ||
.contentType(ContentType.JSON) | ||
.when() | ||
.body(userFollowRequest) | ||
.delete("/user/follower") | ||
.then().log().all() | ||
.statusCode(204); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,8 +10,8 @@ class BlockedUserGroupTest { | |
|
||
@Test | ||
void isBlocked() { | ||
User loki = new User(1L, "[email protected]", "loki", "로키", "loki.jpg", "KOREA"); | ||
User pond = new User(2L, "[email protected]", "pond", "폰드", "pond.jpg", "KOREA"); | ||
User loki = new User(1L, "[email protected]", "loki", "로키", "loki.jpg", "KOREA", 0, 0); | ||
User pond = new User(2L, "[email protected]", "pond", "폰드", "pond.jpg", "KOREA", 0, 0); | ||
|
||
BlockedUserGroup blockedUserGroup = new BlockedUserGroup(Set.of(pond)); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,8 +13,8 @@ class UserBlockTest { | |
@Test | ||
@DisplayName("UserBlock 객체를 생성한다.") | ||
void create() { | ||
User user_loki = new User(1L, "[email protected]", "loki", "로키", "loki.jpg", "KOREA"); | ||
User user_pond = new User(2L, "[email protected]", "pond", "폰드", "pond.jpg", "KOREA"); | ||
User user_loki = new User(1L, "[email protected]", "loki", "로키", "loki.jpg", "KOREA", 0, 0); | ||
User user_pond = new User(2L, "[email protected]", "pond", "폰드", "pond.jpg", "KOREA", 0, 0); | ||
|
||
UserBlock userBlock = new UserBlock(user_loki, user_pond); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
변수명 앞에 user는 빼도 되지 않을까요???
+) 저희 DB 수정도 필요하겠네요....!!