Skip to content

Commit

Permalink
[refactor #86] 상호작용 비즈니스 로직 리팩토링 (#87)
Browse files Browse the repository at this point in the history
* [feat] : 에러 코드 네이밍 변경 및 추가

* [style] : 상호작용 mapper 메서드 네이밍 변경

* [refactor] : 상호작용 비즈니스 로직 리팩토링

* [test] : 상호작용 비즈니스 로직 리팩토링 테스트 반영

* [chore] : 임시로 cd 조건 수정

* [chore] : cd.yml 원복

* [refactor] : 반환된 엔티티 필드 반환
  • Loading branch information
hyun2371 authored Aug 26, 2024
1 parent f245437 commit 082a887
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public int increaseCount() {

public int decreaseCount() {
if (count == 0) {
throw new ValidationException(InteractionErrorCode.UNINTERACTION_NOT_ALLOWED);
throw new ValidationException(InteractionErrorCode.INTERACTION_UNDO_NOT_ALLOWED);
}
return --count;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,22 @@
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class InteractionMapper {

public static Interaction toPostInteraction(Long questionPostId, Long memberId, InteractionType type) {
public static Interaction toInteraction(Long questionPostId, Long memberId, InteractionType type) {
return Interaction.of(
type,
memberId,
questionPostId
);
}

public static InteractionCount toPostInteractionCount(Long questionPostId, InteractionType type) {
public static InteractionCount toInteractionCount(Long questionPostId, InteractionType type) {
return InteractionCount.of(
type,
questionPostId
);
}

public static InteractionResponse toPostInteractionResponse(int count, InteractionType type) {
public static InteractionResponse toInteractionResponse(int count, InteractionType type) {
return new InteractionResponse(
count, type.getLabel()
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
@RequiredArgsConstructor
public enum InteractionErrorCode implements ErrorCode {

NOT_FOUND_POST_INTERACTION("상호작용 이력이 존재하지 않습니다.", "PI_001"),
ALREADY_INTERACTED("이미 해당 작업을 수행했습니다.", "PI_002"),
UNINTERACTION_NOT_ALLOWED("상호작용 수가 0이하가 될 수 없습니다.", "PI_003"),
INTERACTION_NOT_ALLOWED("본인 게시물은 상호작용할 수 없습니다", "PI_004"),
NOT_FOUND_TYPE("북마크와 추천 중 하나를 입력해주세요", "PI_005");
NOT_FOUND_INTERACTION("상호작용 이력이 존재하지 않습니다.", "PI_001"),
NOT_FOUND_INTERACTION_COUNT("상호작용 수 이력이 존재하지 않습니다.", "PI_002"),

ALREADY_INTERACTED("이미 해당 작업을 수행했습니다.", "PI_003"),
INTERACTION_UNDO_NOT_ALLOWED("상호작용 수가 0이하가 될 수 없습니다.", "PI_004"),
INTERACTION_NOT_ALLOWED("본인 게시물은 상호작용할 수 없습니다", "PI_005"),
NOT_FOUND_TYPE("북마크와 추천 중 하나를 입력해주세요", "PI_006");

private final String message;
private final String code;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,47 +33,37 @@ public InteractionResponse activateInteraction(
Long memberId,
InteractionType type // 북마크, 추천
) {
int count;
if (!interactionRepository.existsByQuestionPostIdAndMemberIdAndType // 상호 작용 존재x -> 저장
(questionPostId, memberId, type)
) {
count = createInteraction(questionPostId, memberId, type);
} else { // 존재 -> 값 업데이트
count = updateInteractionAndCount(questionPostId, memberId, type, true);
}
return InteractionMapper.toPostInteractionResponse(
count, type
);
validateIfPostExistsAndNotQuestioner(questionPostId, memberId);

interactionRepository
.findByQuestionPostIdAndMemberIdAndType(questionPostId, memberId, type)
.ifPresentOrElse(
interaction -> interaction.updateIsInteracted(true),
() -> interactionRepository.save(
InteractionMapper.toInteraction(questionPostId, memberId, type)
)
);

int count = interactionCountRepository
.findByQuestionPostIdAndType(questionPostId, type)
.map(InteractionCount::increaseCount)
.orElseGet(() -> interactionCountRepository.save(
InteractionMapper.toInteractionCount(questionPostId, type)
).getCount());
return InteractionMapper.toInteractionResponse(count, type);
}

@Transactional
public InteractionResponse inactivateInteraction(
Long questionPostId,
Long memberId,
InteractionType type
) {
int count = updateInteractionAndCount(questionPostId, memberId, type, false);
return InteractionMapper.toPostInteractionResponse(
count, type
);
}

private int createInteraction(
Long questionPostId,
Long memberId,
InteractionType type
InteractionType type // 북마크, 추천
) {
validateIfPostExistsAndNotQuestioner(questionPostId, memberId);
interactionRepository.save(
InteractionMapper.toPostInteraction(questionPostId, memberId, type)
);
return interactionCountRepository // 게시글 상호작용이 없어도 타 회원에 인해 게시글 상호작용 수가 있을 수 있음
.findByQuestionPostIdAndType(questionPostId, type)
.orElseGet(
() -> interactionCountRepository
.save(InteractionMapper.toPostInteractionCount(questionPostId, type)) // 생성 시 count 1로 초기화
)
.getCount();
getPostInteraction(questionPostId, memberId, type)
.updateIsInteracted(false);
int count = getPostInteractionCount(questionPostId, type)
.decreaseCount();
return InteractionMapper.toInteractionResponse(count, type);
}

private void validateIfPostExistsAndNotQuestioner(
Expand All @@ -87,35 +77,15 @@ private void validateIfPostExistsAndNotQuestioner(
}
}

private int updateInteractionAndCount(
Long questionPostId,
Long memberId,
InteractionType type,
boolean isActivate
) {
int count;
Interaction interaction = getPostInteraction(questionPostId, memberId, type);
InteractionCount interactionCount = getPostInteractionCount(questionPostId, type);

if (isActivate) { //활성화
interaction.updateIsInteracted(true);
count = interactionCount.increaseCount();
} else { // 비활성화
interaction.updateIsInteracted(false);
count = interactionCount.decreaseCount();
}
return count;
}

private Interaction getPostInteraction(Long questionPostId, Long memberId, InteractionType type) {
return interactionRepository.findByQuestionPostIdAndMemberIdAndType(
questionPostId, memberId, type
).orElseThrow(() -> new NotFoundException(InteractionErrorCode.NOT_FOUND_POST_INTERACTION));
).orElseThrow(() -> new NotFoundException(InteractionErrorCode.NOT_FOUND_INTERACTION));
}

private InteractionCount getPostInteractionCount(Long questionPostId, InteractionType type) {
return interactionCountRepository
.findByQuestionPostIdAndType(questionPostId, type)
.orElseThrow();
.orElseThrow(() -> new NotFoundException(InteractionErrorCode.NOT_FOUND_INTERACTION_COUNT));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class InteractionServiceTest {

private final Member questioner = MemberFixture.member(1L);
private final Member interactor = MemberFixture.member(2L);
private final InteractionType type = InteractionType.RECOMMEND;

@Mock
private InteractionRepository interactionRepository;
Expand All @@ -46,28 +47,27 @@ class InteractionServiceTest {
@InjectMocks
private InteractionService interactionService;

@DisplayName("[상호작용을 새로 활성화한다. 기존에 게시글 상호작용 수가 저장되어 있다.]")
@DisplayName("[게시글에 최초로 추천을 한다.]")
@Test
void activateInteraction_create1() {
//given
InteractionType type = InteractionType.RECOMMEND;
QuestionPost questionPost = QuestionPostFixture.questionPost(1L, questioner);
Interaction interaction = Interaction.of(type, interactor.getId(), questionPost.getId());
InteractionCount interactionCount = InteractionCount.of(type, interactor.getId());

given(interactionRepository.existsByQuestionPostIdAndMemberIdAndType(
questionPost.getId(), interactor.getId(), type
)).willReturn(false); // 생성
given(questionPostRepository.findById(questionPost.getId()))
.willReturn(Optional.of(questionPost));
given(interactionRepository.save(any(Interaction.class)))
.willReturn(interaction);
given(interactionCountRepository.findByQuestionPostIdAndType(
questionPost.getId(), type)).willReturn(Optional.of(interactionCount));
questionPost.getId(), type)
).willReturn(Optional.empty());
given(interactionCountRepository.save(any(InteractionCount.class)))
.willReturn(interactionCount);

//when
InteractionResponse response = interactionService.activateInteraction(1L, 2L,
type);
InteractionResponse response
= interactionService.activateInteraction(1L, interactor.getId(), type);

//then
assertAll(
Expand All @@ -76,43 +76,37 @@ void activateInteraction_create1() {
);
}

@DisplayName("[상호작용을 새로 활성화한다. 기존에 게시글 상호작용 수가 저장되어있지 않다.]")
@DisplayName("[다른 사람이 추천했던 게시글에 대해 추천한다.]")
@Test
void activateInteraction_create2() {
//given
InteractionType type = InteractionType.RECOMMEND;
QuestionPost questionPost = QuestionPostFixture.questionPost(1L, questioner);
Interaction interaction = Interaction.of(type, interactor.getId(), questionPost.getId());
InteractionCount interactionCount = InteractionCount.of(type, interactor.getId());

given(interactionRepository.existsByQuestionPostIdAndMemberIdAndType(
questionPost.getId(), interactor.getId(), type
)).willReturn(false); // 생성
given(questionPostRepository.findById(questionPost.getId()))
.willReturn(Optional.of(questionPost));
given(interactionRepository.save(any(Interaction.class)))
.willReturn(interaction);
given(interactionCountRepository.findByQuestionPostIdAndType(
questionPost.getId(), type)).willReturn(Optional.empty());
given(interactionCountRepository.save(any(InteractionCount.class)))
.willReturn(interactionCount);
questionPost.getId(), type)
).willReturn(Optional.of(interactionCount));

//when
InteractionResponse response
= interactionService.activateInteraction(1L, 2L, type);
InteractionResponse response = interactionService
.activateInteraction(1L, interactor.getId(), type);

//then
assertAll(
() -> assertThat(response.count()).isEqualTo(1),
() -> assertThat(response.count()).isEqualTo(2),
() -> assertThat(response.interactionType()).isEqualTo(type.getLabel())
);
}

@DisplayName("[비활성화된 상호작용을 재활성화한다.]")
@DisplayName("[기존에 추천 취소했던 게시글을 재추천한다.]")
@Test
void activateInteraction_update() {
//given
InteractionType type = InteractionType.RECOMMEND;
QuestionPost questionPost = QuestionPostFixture.questionPost(1L, questioner);
Interaction interaction = InteractionFixture.interaction(1L, type, interactor.getId(),
questionPost.getId());
Expand All @@ -121,21 +115,22 @@ void activateInteraction_update() {
interaction.updateIsInteracted(false);
interactionCount.decreaseCount();

given(interactionRepository.existsByQuestionPostIdAndMemberIdAndType(
questionPost.getId(), interactor.getId(), type
)).willReturn(true); // 업데이트
given(questionPostRepository.findById(questionPost.getId()))
.willReturn(Optional.of(questionPost));

given(interactionRepository.findByQuestionPostIdAndMemberIdAndType(
questionPost.getId(),
interactor.getId(),
type
)).willReturn(Optional.of(interaction));

given(interactionCountRepository.findByQuestionPostIdAndType(
interactionCount.getId(), type))
.willReturn(Optional.of(interactionCount));

//when
InteractionResponse response = interactionService.activateInteraction(1L, 2L,
type);
InteractionResponse response =
interactionService.activateInteraction(1L, interactor.getId(), type);

//then
assertAll(
Expand All @@ -144,29 +139,30 @@ void activateInteraction_update() {
);
}

@DisplayName("[활성화된 상호작용을 비활성화한다.]")
@DisplayName("[게시글 추천을 취소한다.]")
@Test
void inactivateInteraction() {
//given
InteractionType type = InteractionType.RECOMMEND;
QuestionPost questionPost = QuestionPostFixture.questionPost(1L, questioner);
Interaction interaction = InteractionFixture.interaction(1L, type, interactor.getId(),
questionPost.getId());
InteractionCount interactionCount = InteractionCountFixture.interactionCount(1L, type,
interactor.getId());
Interaction interaction = InteractionFixture.interaction(
1L, type, interactor.getId(), questionPost.getId()
);
InteractionCount interactionCount =
InteractionCountFixture.interactionCount(1L, type, interactor.getId());

given(interactionRepository.findByQuestionPostIdAndMemberIdAndType(
questionPost.getId(),
interactor.getId(),
type
)).willReturn(Optional.of(interaction));

given(interactionCountRepository.findByQuestionPostIdAndType(
interactionCount.getId(), type))
.willReturn(Optional.of(interactionCount));
interactionCount.getId(), type)
).willReturn(Optional.of(interactionCount));

//when
InteractionResponse response = interactionService.inactivateInteraction(1L, 2L,
type);
InteractionResponse response = interactionService
.inactivateInteraction(1L, interactor.getId(), type);

//then
assertAll(
Expand Down

0 comments on commit 082a887

Please sign in to comment.