Skip to content

Commit

Permalink
Merge pull request #466 from tukcomCD2024/feat/friend_invite_delete-B…
Browse files Browse the repository at this point in the history
…-#457

feat : 친구 초대 삭제 API 추가 및 기존 API 동시성 제어, 검증 추가 #457
  • Loading branch information
seokho-1116 authored Jun 6, 2024
2 parents 384c8d4 + 241838e commit 60e9bfc
Show file tree
Hide file tree
Showing 21 changed files with 590 additions and 118 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,32 @@ ResponseEntity<ApiSpec<String>> acceptFriendRequest(
Long friendId
);

@Operation(
summary = "소셜 친구 요청 삭제",
description = "사용자가 보낸 소셜 친구 요청을 삭제한다.",
security = {@SecurityRequirement(name = "user_token")},
tags = {"friend"}
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "처리 완료"
),
@ApiResponse(
responseCode = "400",
description = """
잘못된 요청 파라미터 또는 존재하지 않는 사용자로 요청하거나 존재하지 않는 친구에게 친구 요청을 보낼 경우 발생
""",
content = @Content(schema = @Schema(implementation = ErrorResponse.class))
)
})
ResponseEntity<ApiSpec<String>> deleteSendingFriendInvite(
Long memberId,

@Parameter(in = ParameterIn.PATH, required = true, schema = @Schema())
Long friendId
);

@Operation(
summary = "소셜 친구 삭제",
description = "사용자의 소셜 친구를 삭제한다.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.springframework.web.bind.annotation.RestController;
import site.timecapsulearchive.core.domain.friend.data.request.SendFriendRequest;
import site.timecapsulearchive.core.domain.friend.service.command.FriendCommandService;
import site.timecapsulearchive.core.domain.member.service.MemberService;
import site.timecapsulearchive.core.global.common.response.ApiSpec;
import site.timecapsulearchive.core.global.common.response.SuccessCode;

Expand All @@ -20,6 +21,7 @@
public class FriendCommandApiController implements FriendCommandApi {

private final FriendCommandService friendCommandService;
private final MemberService memberService;

@DeleteMapping(value = "/{friend_id}")
@Override
Expand All @@ -36,6 +38,22 @@ public ResponseEntity<ApiSpec<String>> deleteFriend(
);
}

@DeleteMapping("/{friend_id}/sending-invites")
@Override
public ResponseEntity<ApiSpec<String>> deleteSendingFriendInvite(
@AuthenticationPrincipal final Long memberId,
@PathVariable("friend_id") final Long friendId
) {
friendCommandService.deleteSendingFriendInvite(memberId, friendId);

return ResponseEntity.ok(
ApiSpec.empty(
SuccessCode.SUCCESS
)
);
}


@DeleteMapping("/{friend_id}/deny-request")
@Override
public ResponseEntity<ApiSpec<String>> denyFriendRequest(
Expand Down Expand Up @@ -95,6 +113,4 @@ public ResponseEntity<ApiSpec<String>> acceptFriendRequest(
)
);
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package site.timecapsulearchive.core.domain.friend.data.dto;

public record FriendInviteMemberIdsDto(
Long ownerId,
Long friendId
) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package site.timecapsulearchive.core.domain.friend.data.dto;

import java.util.List;

public record FriendInviteNotificationDto(
String nickname,
String profileUrl,
List<Long> foundFriendIds
) {

public static FriendInviteNotificationDto create(
final String nickname,
final String profileUrl,
final List<Long> foundFriendIds
) {
return new FriendInviteNotificationDto(nickname, profileUrl, foundFriendIds);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package site.timecapsulearchive.core.domain.friend.entity;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package site.timecapsulearchive.core.domain.friend.exception;

import site.timecapsulearchive.core.global.error.ErrorCode;
import site.timecapsulearchive.core.global.error.exception.BusinessException;

public class FriendInviteDuplicateException extends BusinessException {

public FriendInviteDuplicateException() {
super(ErrorCode.FRIEND_INVITE_DUPLICATE_ERROR);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import site.timecapsulearchive.core.global.error.ErrorCode;
import site.timecapsulearchive.core.global.error.exception.BusinessException;

public class FriendDuplicateIdException extends BusinessException {
public class SelfFriendOperationException extends BusinessException {

public FriendDuplicateIdException() {
super(ErrorCode.FRIEND_DUPLICATE_ID_ERROR);
public SelfFriendOperationException() {
super(ErrorCode.SELF_FRIEND_OPERATION_ERROR);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import java.time.ZonedDateTime;
import java.util.List;
import java.util.Optional;
import org.springframework.data.domain.Slice;
import site.timecapsulearchive.core.domain.friend.data.dto.FriendInviteMemberIdsDto;
import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto;

public interface FriendInviteQueryRepository {
Expand All @@ -21,4 +23,10 @@ Slice<FriendSummaryDto> findFriendSendingInvitesSlice(
final int size,
final ZonedDateTime createdAt
);

List<FriendInviteMemberIdsDto> findFriendInviteMemberIdsDtoByMemberIdsAndFriendId(
List<Long> memberIds, Long friendId);

Optional<FriendInviteMemberIdsDto> findFriendInviteMemberIdsDtoByMemberIdAndFriendId(
Long memberId, Long friendId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static site.timecapsulearchive.core.domain.friend.entity.QFriendInvite.friendInvite;
import static site.timecapsulearchive.core.domain.member.entity.QMember.member;

import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.sql.PreparedStatement;
Expand All @@ -11,13 +12,13 @@
import java.sql.Types;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.SliceImpl;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import site.timecapsulearchive.core.domain.friend.data.dto.FriendInviteMemberIdsDto;
import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto;
import site.timecapsulearchive.core.global.util.SliceUtil;

Expand Down Expand Up @@ -107,4 +108,49 @@ public Slice<FriendSummaryDto> findFriendSendingInvitesSlice(

return SliceUtil.makeSlice(size, friends);
}

@Override
public List<FriendInviteMemberIdsDto> findFriendInviteMemberIdsDtoByMemberIdsAndFriendId(
List<Long> memberIds, Long friendId) {
BooleanBuilder multipleColumnsInCondition = new BooleanBuilder();
for (Long memberId : memberIds) {
multipleColumnsInCondition.or(friendInvite.owner.id.eq(memberId)
.and(friendInvite.friend.id.eq(friendId)));

multipleColumnsInCondition.or(friendInvite.owner.id.eq(friendId)
.and(friendInvite.friend.id.eq(memberId)));
}

return jpaQueryFactory
.select(
Projections.constructor(
FriendInviteMemberIdsDto.class,
friendInvite.owner.id,
friendInvite.friend.id
)
)
.from(friendInvite)
.where(multipleColumnsInCondition)
.fetch();
}

@Override
public Optional<FriendInviteMemberIdsDto> findFriendInviteMemberIdsDtoByMemberIdAndFriendId(
Long memberId, Long friendId) {
return Optional.ofNullable(
jpaQueryFactory
.select(
Projections.constructor(
FriendInviteMemberIdsDto.class,
friendInvite.owner.id,
friendInvite.friend.id
)
)
.from(friendInvite)
.where(friendInvite.owner.id.eq(memberId).and(friendInvite.friend.id.eq(friendId))
.or(friendInvite.owner.id.eq(friendId)
.and(friendInvite.friend.id.eq(memberId))))
.fetchOne()
);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package site.timecapsulearchive.core.domain.friend.repository.friend_invite;

import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.Repository;
Expand All @@ -12,21 +11,21 @@ public interface FriendInviteRepository extends Repository<FriendInvite, Long>,

void save(FriendInvite friendInvite);

@Query(value = "select fi "
+ "from FriendInvite fi "
+ "join fetch fi.owner "
+ "join fetch fi.friend "
+ "where (fi.owner.id =:friendId and fi.friend.id =:memberId) "
+ "or (fi.owner.id =: memberId and fi.friend.id =: friendId)")
List<FriendInvite> findFriendInviteWithMembersByOwnerIdAndFriendId(
@Param(value = "memberId") Long memberId,
void delete(FriendInvite friendInvite);

Optional<FriendInvite> findFriendSendingInviteForUpdateByOwnerIdAndFriendId(Long memberId,
Long friendId);

@Query(value = """
select fi
from FriendInvite fi
join fetch fi.owner
join fetch fi.friend
where fi.owner.id =:ownerId and fi.friend.id =:friendId
""")
Optional<FriendInvite> findFriendReceivingInviteForUpdateByOwnerIdAndFriendId(
@Param(value = "ownerId") Long ownerId,
@Param(value = "friendId") Long friendId
);

Optional<FriendInvite> findFriendInviteByOwnerIdAndFriendId(Long memberId, Long targetId);

int deleteFriendInviteByOwnerIdAndFriendId(Long memberId, Long targetId);

void delete(FriendInvite friendInvite);
}

Loading

0 comments on commit 60e9bfc

Please sign in to comment.