Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,12 @@
private final AiSummaryService aiSummaryService;
private final ContentViewLogService contentViewLogService;
private final SimilarContentClient similarContentClient;
private final RecommendService recommendService;
private final StringRedisTemplate redisTemplate;
private final ObjectMapper objectMapper;

@Transactional(readOnly = true)
public ContentListResponse getFeed(UUID userId, Pageable pageable) {

Check failure on line 82 in src/main/java/com/devpick/domain/content/service/ContentService.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this method to reduce its Cognitive Complexity from 20 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=Devpick-Org_devpick-backend&issues=AZ5iq0Njcewz58IZfuy0&open=AZ5iq0Njcewz58IZfuy0&pullRequest=174
boolean loggedIn = userId != null;

String cacheKey = publicFeedCacheKey(userId, pageable);
Expand Down Expand Up @@ -110,7 +111,7 @@
}

List<UUID> tagIds = loggedIn
? feedTagIds(userId, profileUser.map(User::getJob).orElse(null))
? resolveTagIds(userId, profileUser.map(User::getJob).orElse(null))
: List.of();

Page<Content> page;
Expand Down Expand Up @@ -189,6 +190,14 @@
+ ":sort:" + pageable.getSort();
}

private List<UUID> resolveTagIds(UUID userId, Job job) {
List<UUID> historyTagIds = recommendService.getOrCacheTagIds(userId);
if (!historyTagIds.isEmpty()) {
return historyTagIds;
}
return feedTagIds(userId, job);
}

private List<UUID> feedTagIds(UUID userId, Job job) {
List<UUID> tagIds = new ArrayList<>(userTagRepository.findByUser_Id(userId).stream()
.map(ut -> ut.getTag().getId())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ class ContentServiceTest {
private ContentViewLogService contentViewLogService;
@Mock
private com.devpick.domain.content.client.SimilarContentClient similarContentClient;
@Mock
private RecommendService recommendService;

private UUID userId;
private UUID contentId;
Expand Down Expand Up @@ -111,6 +113,7 @@ void setUp() {
.build();
lenient().when(userRepository.findByIdAndIsActiveTrue(userId)).thenReturn(Optional.of(user));
lenient().when(tagRepository.findByNameIgnoreCaseIn(any())).thenReturn(List.of());
lenient().when(recommendService.getOrCacheTagIds(any())).thenReturn(List.of());
}

@Test
Expand Down Expand Up @@ -646,6 +649,48 @@ void getDetail_viewLogThrows_stillReturnsDetail() {
assertThat(response.title()).isEqualTo("Spring Boot 가이드");
}

// ── getFeed 학습 이력 기반 개인화 ─────────────────────────────────────────

@Test
@DisplayName("getFeed — 학습 이력 태그 있으면 이력 기반 태그로 랭킹, userTagRepository 미조회")
void getFeed_withHistoryTags_usesHistoryTagsForRanking() {
UUID historyTagId = UUID.randomUUID();
given(recommendService.getOrCacheTagIds(userId)).willReturn(List.of(historyTagId));
given(contentRepository.findAllRankedByTagIds(any(), any()))
.willReturn(new PageImpl<>(List.of(content)));
given(scrapRepository.findScrappedContentIds(any(), any())).willReturn(List.of());
given(likeRepository.findLikedContentIds(any(), any())).willReturn(List.of());
given(aiSummaryService.findCachedCoreSummaries(any(), any())).willReturn(Map.of());

ContentListResponse response = contentService.getFeed(userId, PageRequest.of(0, 20));

assertThat(response.contents()).hasSize(1);
verify(contentRepository).findAllRankedByTagIds(any(), any());
verify(userTagRepository, never()).findByUser_Id(any());
}

@Test
@DisplayName("getFeed — 학습 이력 태그 없으면 회원가입 태그로 폴백하여 랭킹")
void getFeed_historyTagsEmpty_fallsBackToUserTags() {
given(recommendService.getOrCacheTagIds(userId)).willReturn(List.of());
UserTag userTag = UserTag.builder()
.user(user)
.tag(Tag.builder().name("Java").build())
.build();
given(userTagRepository.findByUser_Id(userId)).willReturn(List.of(userTag));
given(contentRepository.findAllRankedByTagIds(any(), any()))
.willReturn(new PageImpl<>(List.of(content)));
given(scrapRepository.findScrappedContentIds(any(), any())).willReturn(List.of());
given(likeRepository.findLikedContentIds(any(), any())).willReturn(List.of());
given(aiSummaryService.findCachedCoreSummaries(any(), any())).willReturn(Map.of());

ContentListResponse response = contentService.getFeed(userId, PageRequest.of(0, 20));

assertThat(response.contents()).hasSize(1);
verify(contentRepository).findAllRankedByTagIds(any(), any());
verify(userTagRepository).findByUser_Id(userId);
}

// ── getFeed 플랜 제한 ────────────────────────────────────────────────────

@Test
Expand Down
Loading