Skip to content
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

[refactor #86] 상호작용 비즈니스 로직 리팩토링 #87

Merged
merged 8 commits into from
Aug 26, 2024
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,40 @@ 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)
);
return 1;
hyun2371 marked this conversation as resolved.
Show resolved Hide resolved
});
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 +80,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
Loading