From 2e2adef5e03964b172eafefe2ec9066f4a8e3898 Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Fri, 10 Jul 2026 00:19:23 +0200 Subject: [PATCH] fix: profile shows only own reviews, federation display name in community - diary API accepts user_id filter, profile page passes it - movie social feed joins ap_remote_actors for handle resolution - COALESCE prefers actor handle for remote reviews, email for local --- crates/adapters/postgres/src/diary.rs | 10 ++++++---- crates/adapters/sqlite/src/diary.rs | 9 +++++---- crates/api-types/src/diary.rs | 1 + crates/presentation/src/forms.rs | 2 +- crates/presentation/src/tests/forms.rs | 2 ++ spa/src/components/profile-view.tsx | 4 ++-- spa/src/lib/api/diary.ts | 1 + spa/src/routes/_app/profile.tsx | 1 + 8 files changed, 19 insertions(+), 11 deletions(-) diff --git a/crates/adapters/postgres/src/diary.rs b/crates/adapters/postgres/src/diary.rs index 40ae8f6..a949813 100644 --- a/crates/adapters/postgres/src/diary.rs +++ b/crates/adapters/postgres/src/diary.rs @@ -343,7 +343,8 @@ impl DiaryRepository for PostgresDiaryRepository { to_char(r.created_at AT TIME ZONE 'UTC', 'YYYY-MM-DD HH24:MI:SS') AS created_at, r.remote_actor_url, r.watch_medium, - COALESCE(u.email, a.handle, r.remote_actor_url) AS user_email + CASE WHEN r.remote_actor_url IS NOT NULL THEN COALESCE(a.handle, r.remote_actor_url) + ELSE COALESCE(u.email, r.user_id) END AS user_email FROM reviews r INNER JOIN movies m ON m.id = r.movie_id LEFT JOIN users u ON u.id = r.user_id @@ -522,12 +523,13 @@ impl DiaryRepository for PostgresDiaryRepository { to_char(r.watched_at AT TIME ZONE 'UTC', 'YYYY-MM-DD HH24:MI:SS') AS watched_at, to_char(r.created_at AT TIME ZONE 'UTC', 'YYYY-MM-DD HH24:MI:SS') AS created_at, r.remote_actor_url, - CASE WHEN r.remote_actor_url IS NOT NULL THEN r.remote_actor_url - WHEN u.email IS NOT NULL THEN u.email - ELSE r.user_id END AS user_email + r.watch_medium, + CASE WHEN r.remote_actor_url IS NOT NULL THEN COALESCE(a.handle, r.remote_actor_url) + ELSE COALESCE(u.email, r.user_id) END AS user_email FROM reviews r INNER JOIN movies m ON m.id = r.movie_id LEFT JOIN users u ON u.id = r.user_id + LEFT JOIN ap_remote_actors a ON a.url = r.remote_actor_url WHERE r.movie_id = $1 ORDER BY r.watched_at DESC LIMIT $2 OFFSET $3", diff --git a/crates/adapters/sqlite/src/diary.rs b/crates/adapters/sqlite/src/diary.rs index d0b272a..fb3364c 100644 --- a/crates/adapters/sqlite/src/diary.rs +++ b/crates/adapters/sqlite/src/diary.rs @@ -309,7 +309,8 @@ impl DiaryRepository for SqliteDiaryRepository { "SELECT m.id, m.external_metadata_id, m.title, m.release_year, m.director, m.poster_path, r.id AS review_id, r.movie_id, r.user_id, r.rating, r.comment, r.watched_at, r.created_at, r.remote_actor_url, r.watch_medium, - COALESCE(u.email, a.handle, r.remote_actor_url) AS user_email + CASE WHEN r.remote_actor_url IS NOT NULL THEN COALESCE(a.handle, r.remote_actor_url) + ELSE COALESCE(u.email, r.user_id) END AS user_email FROM reviews r INNER JOIN movies m ON m.id = r.movie_id LEFT JOIN users u ON u.id = r.user_id @@ -476,12 +477,12 @@ impl DiaryRepository for SqliteDiaryRepository { "SELECT m.id, m.external_metadata_id, m.title, m.release_year, m.director, m.poster_path, r.id AS review_id, r.movie_id, r.user_id, r.rating, r.comment, r.watched_at, r.created_at, r.remote_actor_url, r.watch_medium, - CASE WHEN r.remote_actor_url IS NOT NULL THEN r.remote_actor_url - WHEN u.email IS NOT NULL THEN u.email - ELSE r.user_id END AS user_email + CASE WHEN r.remote_actor_url IS NOT NULL THEN COALESCE(a.handle, r.remote_actor_url) + ELSE COALESCE(u.email, r.user_id) END AS user_email FROM reviews r INNER JOIN movies m ON m.id = r.movie_id LEFT JOIN users u ON u.id = r.user_id + LEFT JOIN ap_remote_actors a ON a.url = r.remote_actor_url WHERE r.movie_id = ? ORDER BY r.watched_at DESC LIMIT ? OFFSET ?", diff --git a/crates/api-types/src/diary.rs b/crates/api-types/src/diary.rs index 4a83e22..68bc6fe 100644 --- a/crates/api-types/src/diary.rs +++ b/crates/api-types/src/diary.rs @@ -42,6 +42,7 @@ pub struct DiaryQueryParams { pub offset: Option, pub sort_by: Option, pub movie_id: Option, + pub user_id: Option, } #[derive(Debug, Clone, Deserialize, utoipa::IntoParams)] diff --git a/crates/presentation/src/forms.rs b/crates/presentation/src/forms.rs index 78465c3..b99a21e 100644 --- a/crates/presentation/src/forms.rs +++ b/crates/presentation/src/forms.rs @@ -265,7 +265,7 @@ pub fn to_diary_query(p: DiaryQueryParams) -> GetDiaryQuery { _ => SortDirection::Descending, }), movie_id: p.movie_id, - user_id: None, + user_id: p.user_id, } } diff --git a/crates/presentation/src/tests/forms.rs b/crates/presentation/src/tests/forms.rs index 1a59679..048c872 100644 --- a/crates/presentation/src/tests/forms.rs +++ b/crates/presentation/src/tests/forms.rs @@ -84,6 +84,7 @@ fn sort_by_asc_string_becomes_ascending() { limit: None, offset: None, movie_id: None, + user_id: None, }; let query = to_diary_query(params); assert!(matches!( @@ -99,6 +100,7 @@ fn sort_by_other_string_becomes_descending() { limit: None, offset: None, movie_id: None, + user_id: None, }; let query = to_diary_query(params); assert!(matches!( diff --git a/spa/src/components/profile-view.tsx b/spa/src/components/profile-view.tsx index 994299d..d42b07f 100644 --- a/spa/src/components/profile-view.tsx +++ b/spa/src/components/profile-view.tsx @@ -141,10 +141,10 @@ function StatCell({ label, value }: { label: string; value: string | number }) { ) } -function DiaryTab({ sortBy, search }: { sortBy: string; userId?: string; search?: string }) { +function DiaryTab({ sortBy, userId, search }: { sortBy: string; userId?: string; search?: string }) { const { t } = useTranslation() const { data, isPending, hasNextPage, isFetchingNextPage, fetchNextPage } = - useInfiniteDiary({ sort_by: sortBy, movie_id: undefined }) + useInfiniteDiary({ sort_by: sortBy, user_id: userId }) const items = data?.pages.flatMap((p) => p.items) ?? [] const filtered = search ? items.filter((e) => diff --git a/spa/src/lib/api/diary.ts b/spa/src/lib/api/diary.ts index 8d1447c..8c67960 100644 --- a/spa/src/lib/api/diary.ts +++ b/spa/src/lib/api/diary.ts @@ -8,6 +8,7 @@ export const diaryQueryParamsSchema = z.object({ offset: z.number().optional(), sort_by: z.string().optional(), movie_id: z.string().uuid().optional(), + user_id: z.string().uuid().optional(), }) export type DiaryQueryParams = z.infer diff --git a/spa/src/routes/_app/profile.tsx b/spa/src/routes/_app/profile.tsx index 618a289..8679d3f 100644 --- a/spa/src/routes/_app/profile.tsx +++ b/spa/src/routes/_app/profile.tsx @@ -43,6 +43,7 @@ function ProfilePage() {