diff --git a/module-domain/src/main/java/com/depromeet/friend/port/in/command/DeleteFollowCommand.java b/module-domain/src/main/java/com/depromeet/friend/port/in/command/DeleteFollowCommand.java new file mode 100644 index 00000000..6f9a4594 --- /dev/null +++ b/module-domain/src/main/java/com/depromeet/friend/port/in/command/DeleteFollowCommand.java @@ -0,0 +1,3 @@ +package com.depromeet.friend.port.in.command; + +public record DeleteFollowCommand(Long requesterId, Long blackMemberId) {} diff --git a/module-domain/src/main/java/com/depromeet/friend/port/in/FollowUseCase.java b/module-domain/src/main/java/com/depromeet/friend/port/in/usecase/FollowUseCase.java similarity index 79% rename from module-domain/src/main/java/com/depromeet/friend/port/in/FollowUseCase.java rename to module-domain/src/main/java/com/depromeet/friend/port/in/usecase/FollowUseCase.java index 44718dfa..fca8ea79 100644 --- a/module-domain/src/main/java/com/depromeet/friend/port/in/FollowUseCase.java +++ b/module-domain/src/main/java/com/depromeet/friend/port/in/usecase/FollowUseCase.java @@ -1,6 +1,7 @@ -package com.depromeet.friend.port.in; +package com.depromeet.friend.port.in.usecase; import com.depromeet.friend.domain.vo.*; +import com.depromeet.friend.port.in.command.DeleteFollowCommand; import com.depromeet.member.domain.Member; import java.util.List; @@ -22,4 +23,6 @@ public interface FollowUseCase { void deleteByMemberId(Long memberId); List checkFollowingState(Long memberId, List targetIds); + + void deleteBlackMemberInFollowList(DeleteFollowCommand deleteFollowCommand); } diff --git a/module-domain/src/main/java/com/depromeet/friend/port/out/persistence/FriendPersistencePort.java b/module-domain/src/main/java/com/depromeet/friend/port/out/persistence/FriendPersistencePort.java index f16c76c1..8827fcab 100644 --- a/module-domain/src/main/java/com/depromeet/friend/port/out/persistence/FriendPersistencePort.java +++ b/module-domain/src/main/java/com/depromeet/friend/port/out/persistence/FriendPersistencePort.java @@ -14,6 +14,8 @@ public interface FriendPersistencePort { void deleteByMemberIdAndFollowingId(Long memberId, Long followingId); + void deleteFollowerFollowingByMemberIdAndFollowingId(Long memberId, Long followingId); + List findFollowingsByMemberIdAndCursorId(Long memberId, Long cursorId); List findFollowersByMemberIdAndCursorId(Long memberId, Long cursorId); diff --git a/module-domain/src/main/java/com/depromeet/friend/service/FollowService.java b/module-domain/src/main/java/com/depromeet/friend/service/FollowService.java index 67e37db5..7c318846 100644 --- a/module-domain/src/main/java/com/depromeet/friend/service/FollowService.java +++ b/module-domain/src/main/java/com/depromeet/friend/service/FollowService.java @@ -3,7 +3,8 @@ import com.depromeet.exception.BadRequestException; import com.depromeet.friend.domain.Friend; import com.depromeet.friend.domain.vo.*; -import com.depromeet.friend.port.in.FollowUseCase; +import com.depromeet.friend.port.in.command.DeleteFollowCommand; +import com.depromeet.friend.port.in.usecase.FollowUseCase; import com.depromeet.friend.port.out.persistence.FriendPersistencePort; import com.depromeet.member.domain.Member; import com.depromeet.type.friend.FollowErrorType; @@ -12,7 +13,10 @@ import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.event.TransactionPhase; +import org.springframework.transaction.event.TransactionalEventListener; @Service @RequiredArgsConstructor @@ -107,4 +111,14 @@ public void deleteByMemberId(Long memberId) { public List checkFollowingState(Long memberId, List targetIds) { return friendPersistencePort.findByMemberIdAndFollowingIds(memberId, targetIds); } + + @Transactional(propagation = Propagation.REQUIRES_NEW) + @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) + public void deleteBlackMemberInFollowList(DeleteFollowCommand deleteFollowCommand) { + Long requesterId = deleteFollowCommand.requesterId(); + Long blackMemberId = deleteFollowCommand.blackMemberId(); + + friendPersistencePort.deleteFollowerFollowingByMemberIdAndFollowingId( + requesterId, blackMemberId); + } } diff --git a/module-domain/src/test/java/com/depromeet/mock/friend/FakeFriendRepository.java b/module-domain/src/test/java/com/depromeet/mock/friend/FakeFriendRepository.java index dbe16811..c0e56ddd 100644 --- a/module-domain/src/test/java/com/depromeet/mock/friend/FakeFriendRepository.java +++ b/module-domain/src/test/java/com/depromeet/mock/friend/FakeFriendRepository.java @@ -80,6 +80,9 @@ public void deleteByMemberIdAndFollowingId(Long memberId, Long followingId) { && item.getFollowing().getId().equals(followingId)); } + @Override + public void deleteFollowerFollowingByMemberIdAndFollowingId(Long memberId, Long followingId) {} + @Override public List findFollowingsByMemberIdAndCursorId(Long memberId, Long cursorId) { return friends.stream() diff --git a/module-independent/src/main/java/com/depromeet/type/friend/FollowErrorType.java b/module-independent/src/main/java/com/depromeet/type/friend/FollowErrorType.java index b21f802d..f9ee9efa 100644 --- a/module-independent/src/main/java/com/depromeet/type/friend/FollowErrorType.java +++ b/module-independent/src/main/java/com/depromeet/type/friend/FollowErrorType.java @@ -5,7 +5,9 @@ public enum FollowErrorType implements ErrorType { NOT_FOUND("FOLLOW_1", "팔로잉 유저를 찾을 수 없습니다"), SELF_FOLLOWING_NOT_ALLOWED("FOLLOW_2", "자기 자신을 팔로잉 할 수 없습니다"), - INVALID_FOLLOW_TYPE("FOLLOW_3", "올바르지 않은 팔로우 타입입니다"); + INVALID_FOLLOW_TYPE("FOLLOW_3", "올바르지 않은 팔로우 타입입니다"), + CANNOT_FOLLOW_BLACK("FOLLOW_4", "차단한 사람을 팔로우할 수 없습니다"), + CANNOT_FOLLOW_MEMBER_WHO_BLOCKED_YOU("FOLLOW_5", "본인을 차단한 사람을 팔로우할 수 없습니다"); private final String code; private final String message; diff --git a/module-infrastructure/persistence-database/src/main/java/com/depromeet/friend/repository/FriendRepository.java b/module-infrastructure/persistence-database/src/main/java/com/depromeet/friend/repository/FriendRepository.java index 5a1ebd5b..9e730b3a 100644 --- a/module-infrastructure/persistence-database/src/main/java/com/depromeet/friend/repository/FriendRepository.java +++ b/module-infrastructure/persistence-database/src/main/java/com/depromeet/friend/repository/FriendRepository.java @@ -69,6 +69,18 @@ public void deleteByMemberIdAndFollowingId(Long memberId, Long followingId) { .execute(); } + @Override + public void deleteFollowerFollowingByMemberIdAndFollowingId(Long memberId, Long followingId) { + queryFactory + .delete(friend) + .where(checkFollow(memberId, followingId).or(checkFollow(followingId, memberId))) + .execute(); + } + + private BooleanExpression checkFollow(Long memberId, Long followingId) { + return friend.member.id.eq(memberId).and(friend.following.id.eq(followingId)); + } + @Override public List findFollowingsByMemberIdAndCursorId(Long memberId, Long cursorId) { return queryFactory diff --git a/module-presentation/src/main/java/com/depromeet/auth/facade/AuthFacade.java b/module-presentation/src/main/java/com/depromeet/auth/facade/AuthFacade.java index 159ba604..ad022531 100644 --- a/module-presentation/src/main/java/com/depromeet/auth/facade/AuthFacade.java +++ b/module-presentation/src/main/java/com/depromeet/auth/facade/AuthFacade.java @@ -14,7 +14,7 @@ import com.depromeet.dto.auth.AccountProfileResponse; import com.depromeet.exception.NotFoundException; import com.depromeet.followinglog.port.in.FollowingMemoryLogUseCase; -import com.depromeet.friend.port.in.FollowUseCase; +import com.depromeet.friend.port.in.usecase.FollowUseCase; import com.depromeet.image.port.in.ImageUpdateUseCase; import com.depromeet.member.domain.Member; import com.depromeet.member.mapper.MemberMapper; diff --git a/module-presentation/src/main/java/com/depromeet/blacklist/facade/BlacklistFacade.java b/module-presentation/src/main/java/com/depromeet/blacklist/facade/BlacklistFacade.java index df74d671..3c78691e 100644 --- a/module-presentation/src/main/java/com/depromeet/blacklist/facade/BlacklistFacade.java +++ b/module-presentation/src/main/java/com/depromeet/blacklist/facade/BlacklistFacade.java @@ -6,9 +6,11 @@ import com.depromeet.blacklist.port.in.usecase.BlacklistCommandUseCase; import com.depromeet.blacklist.port.in.usecase.BlacklistQueryUseCase; import com.depromeet.exception.BadRequestException; +import com.depromeet.friend.port.in.command.DeleteFollowCommand; import com.depromeet.type.blacklist.BlacklistErrorType; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -16,6 +18,7 @@ @Transactional @RequiredArgsConstructor public class BlacklistFacade { + private final ApplicationEventPublisher eventPublisher; private final BlacklistQueryUseCase blacklistQueryUseCase; private final BlacklistCommandUseCase blacklistCommandUseCase; @@ -34,6 +37,7 @@ public void blackMember(Long memberId, BlackMemberRequest request) { } blacklistCommandUseCase.blackMember(memberId, blackMemberId); + eventPublisher.publishEvent(new DeleteFollowCommand(memberId, blackMemberId)); } public void unblackMember(Long memberId, Long blackMemberId) { diff --git a/module-presentation/src/main/java/com/depromeet/friend/facade/FollowFacade.java b/module-presentation/src/main/java/com/depromeet/friend/facade/FollowFacade.java index f1325f8f..c0458d6f 100644 --- a/module-presentation/src/main/java/com/depromeet/friend/facade/FollowFacade.java +++ b/module-presentation/src/main/java/com/depromeet/friend/facade/FollowFacade.java @@ -1,16 +1,18 @@ package com.depromeet.friend.facade; import com.depromeet.blacklist.port.in.usecase.BlacklistQueryUseCase; +import com.depromeet.exception.BadRequestException; import com.depromeet.friend.domain.vo.FollowCheck; import com.depromeet.friend.domain.vo.FollowSlice; import com.depromeet.friend.domain.vo.Follower; import com.depromeet.friend.domain.vo.Following; import com.depromeet.friend.dto.request.FollowRequest; import com.depromeet.friend.dto.response.*; -import com.depromeet.friend.port.in.FollowUseCase; +import com.depromeet.friend.port.in.usecase.FollowUseCase; import com.depromeet.member.domain.Member; import com.depromeet.member.port.in.usecase.MemberUseCase; import com.depromeet.notification.event.FollowLogEvent; +import com.depromeet.type.friend.FollowErrorType; import java.util.List; import java.util.Set; import lombok.RequiredArgsConstructor; @@ -34,6 +36,14 @@ public class FollowFacade { public boolean addOrDeleteFollow(Long memberId, FollowRequest followRequest) { Member member = memberUseCase.findById(memberId); Member following = memberUseCase.findById(followRequest.followingId()); + + if (blacklistQueryUseCase.checkBlackMember(member.getId(), following.getId())) { + throw new BadRequestException(FollowErrorType.CANNOT_FOLLOW_BLACK); + } + if (blacklistQueryUseCase.checkBlackMember(following.getId(), member.getId())) { + throw new BadRequestException(FollowErrorType.CANNOT_FOLLOW_MEMBER_WHO_BLOCKED_YOU); + } + boolean isAdd = followUseCase.addOrDeleteFollow(member, following); eventPublisher.publishEvent(FollowLogEvent.of(following, member)); diff --git a/module-presentation/src/main/java/com/depromeet/member/facade/MemberFacade.java b/module-presentation/src/main/java/com/depromeet/member/facade/MemberFacade.java index 021326ab..d0f96ccb 100644 --- a/module-presentation/src/main/java/com/depromeet/member/facade/MemberFacade.java +++ b/module-presentation/src/main/java/com/depromeet/member/facade/MemberFacade.java @@ -5,7 +5,7 @@ import com.depromeet.blacklist.port.in.usecase.BlacklistQueryUseCase; import com.depromeet.exception.ForbiddenException; import com.depromeet.friend.domain.vo.FriendCount; -import com.depromeet.friend.port.in.FollowUseCase; +import com.depromeet.friend.port.in.usecase.FollowUseCase; import com.depromeet.member.domain.Member; import com.depromeet.member.domain.MemberGender; import com.depromeet.member.domain.vo.MemberSearchInfo;