From e066277065b721a093bffc7304fbf1f2f04d3eef Mon Sep 17 00:00:00 2001 From: dongmucat <1127093059@qq.com> Date: Tue, 28 Jul 2026 10:57:52 +0800 Subject: [PATCH] fix(search): require published portal results Signed-off-by: dongmucat <1127093059@qq.com> --- .../PostgresFullTextQueryService.java | 8 ++--- .../PostgresFullTextQueryServiceTest.java | 35 +++++++++++++++++++ 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/server/skillhub-search/src/main/java/com/iflytek/skillhub/search/postgres/PostgresFullTextQueryService.java b/server/skillhub-search/src/main/java/com/iflytek/skillhub/search/postgres/PostgresFullTextQueryService.java index 64015844..1e79f041 100644 --- a/server/skillhub-search/src/main/java/com/iflytek/skillhub/search/postgres/PostgresFullTextQueryService.java +++ b/server/skillhub-search/src/main/java/com/iflytek/skillhub/search/postgres/PostgresFullTextQueryService.java @@ -107,9 +107,7 @@ public class PostgresFullTextQueryService implements SearchQueryService { sql.append("FROM skill_search_document d "); sql.append("JOIN skill s ON s.id = d.skill_id "); sql.append("JOIN namespace n ON n.id = d.namespace_id "); - if (query.requireInstallableLatest()) { - sql.append("JOIN skill_version latest ON latest.id = s.latest_version_id "); - } + sql.append("JOIN skill_version latest ON latest.id = s.latest_version_id "); sql.append("WHERE 1=1 "); // Visibility filtering @@ -123,10 +121,10 @@ public class PostgresFullTextQueryService implements SearchQueryService { sql.append("AND d.status = 'ACTIVE' "); sql.append("AND s.status = 'ACTIVE' "); sql.append("AND s.hidden = FALSE "); + sql.append("AND latest.status = 'PUBLISHED' "); + sql.append("AND latest.yanked_at IS NULL "); if (query.requireInstallableLatest()) { - sql.append("AND latest.status = 'PUBLISHED' "); sql.append("AND latest.download_ready = TRUE "); - sql.append("AND latest.yanked_at IS NULL "); } sql.append("AND (n.status <> 'ARCHIVED' "); if (query.visibilityScope().userId() != null) { diff --git a/server/skillhub-search/src/test/java/com/iflytek/skillhub/search/postgres/PostgresFullTextQueryServiceTest.java b/server/skillhub-search/src/test/java/com/iflytek/skillhub/search/postgres/PostgresFullTextQueryServiceTest.java index c84c6cbd..cf73ba74 100644 --- a/server/skillhub-search/src/test/java/com/iflytek/skillhub/search/postgres/PostgresFullTextQueryServiceTest.java +++ b/server/skillhub-search/src/test/java/com/iflytek/skillhub/search/postgres/PostgresFullTextQueryServiceTest.java @@ -400,6 +400,41 @@ class PostgresFullTextQueryServiceTest { verify(countQuery, never()).setParameter(org.mockito.ArgumentMatchers.eq("memberNamespaceIds"), org.mockito.ArgumentMatchers.any()); } + @Test + void portalSearchShouldRequirePublishedNonYankedLatestWithoutDownloadReadiness() { + EntityManager entityManager = mock(EntityManager.class); + Query nativeQuery = mock(Query.class); + Query countQuery = mock(Query.class); + when(entityManager.createNativeQuery(anyString())) + .thenReturn(nativeQuery) + .thenReturn(countQuery); + when(nativeQuery.setParameter(anyString(), org.mockito.ArgumentMatchers.any())).thenReturn(nativeQuery); + when(countQuery.setParameter(anyString(), org.mockito.ArgumentMatchers.any())).thenReturn(countQuery); + when(nativeQuery.getResultList()).thenReturn(List.of()); + when(countQuery.getSingleResult()).thenReturn(0L); + + PostgresFullTextQueryService service = new PostgresFullTextQueryService(entityManager); + + service.search(new SearchQuery( + "demo", + null, + SearchVisibilityScope.anonymous(), + "newest", + 0, + 12, + List.of(), + false + )); + + ArgumentCaptor sqlCaptor = ArgumentCaptor.forClass(String.class); + verify(entityManager, org.mockito.Mockito.times(2)).createNativeQuery(sqlCaptor.capture()); + assertThat(sqlCaptor.getAllValues()).allSatisfy(sql -> assertThat(sql) + .contains("JOIN skill_version latest ON latest.id = s.latest_version_id") + .contains("AND latest.status = 'PUBLISHED'") + .contains("AND latest.yanked_at IS NULL") + .doesNotContain("latest.download_ready = TRUE")); + } + @Test void installableLatestFilterShouldApplyToSearchAndCountQueries() { EntityManager entityManager = mock(EntityManager.class);