feat: enhance review handling by adding actor URL support across multiple components
All checks were successful
CI / Check / Test (push) Successful in 1h3m53s

This commit is contained in:
2026-06-30 03:34:52 +02:00
parent 9f6ba55afc
commit d7fbf8d9e2
7 changed files with 21 additions and 7 deletions

View File

@@ -322,10 +322,11 @@ 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.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, to_char(r.created_at AT TIME ZONE 'UTC', 'YYYY-MM-DD HH24:MI:SS') AS created_at,
r.remote_actor_url, r.remote_actor_url,
COALESCE(u.email, r.remote_actor_url) AS user_email COALESCE(u.email, a.handle, r.remote_actor_url) AS user_email
FROM reviews r FROM reviews r
INNER JOIN movies m ON m.id = r.movie_id INNER JOIN movies m ON m.id = r.movie_id
LEFT JOIN users u ON u.id = r.user_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 {} WHERE {}
ORDER BY {} ORDER BY {}
LIMIT {} OFFSET {}", LIMIT {} OFFSET {}",

View File

@@ -291,10 +291,11 @@ impl DiaryRepository for SqliteDiaryRepository {
"SELECT m.id, m.external_metadata_id, m.title, m.release_year, m.director, m.poster_path, "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.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.watched_at, r.created_at, r.remote_actor_url,
COALESCE(u.email, r.remote_actor_url) AS user_email COALESCE(u.email, a.handle, r.remote_actor_url) AS user_email
FROM reviews r FROM reviews r
INNER JOIN movies m ON m.id = r.movie_id INNER JOIN movies m ON m.id = r.movie_id
LEFT JOIN users u ON u.id = r.user_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 {} WHERE {}
ORDER BY {} ORDER BY {}
LIMIT ? OFFSET ?", LIMIT ? OFFSET ?",

View File

@@ -55,9 +55,10 @@ pub struct FeedEntryDto {
pub movie: MovieDto, pub movie: MovieDto,
pub review: ReviewDto, pub review: ReviewDto,
pub user_id: Uuid, pub user_id: Uuid,
pub user_email: String,
pub user_display_name: String, pub user_display_name: String,
pub is_federated: bool, pub is_federated: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub actor_url: Option<String>,
} }
#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)] #[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]

View File

@@ -4,12 +4,17 @@ use domain::models::FeedEntry;
use super::movies::{movie_to_dto, review_to_dto}; use super::movies::{movie_to_dto, review_to_dto};
pub fn feed_entry_to_dto(e: &FeedEntry) -> FeedEntryDto { pub fn feed_entry_to_dto(e: &FeedEntry) -> FeedEntryDto {
use domain::models::ReviewSource;
let actor_url = match e.review().source() {
ReviewSource::Remote { actor_url } => Some(actor_url.clone()),
ReviewSource::Local => None,
};
FeedEntryDto { FeedEntryDto {
movie: movie_to_dto(e.movie()), movie: movie_to_dto(e.movie()),
review: review_to_dto(e.review()), review: review_to_dto(e.review()),
user_id: e.review().user_id().value(), user_id: e.review().user_id().value(),
user_email: e.user_email().to_string(),
user_display_name: e.user_display_name().to_string(), user_display_name: e.user_display_name().to_string(),
is_federated: e.review().is_remote(), is_federated: e.review().is_remote(),
actor_url,
} }
} }

View File

@@ -12,9 +12,10 @@ type ReviewCardProps = {
userName?: string userName?: string
userId?: string userId?: string
isFederated?: boolean isFederated?: boolean
actorUrl?: string
} }
export function ReviewCard({ movie, review, userName, userId, isFederated }: ReviewCardProps) { export function ReviewCard({ movie, review, userName, userId, isFederated, actorUrl }: ReviewCardProps) {
return ( return (
<Card size="sm"> <Card size="sm">
<CardContent className="flex gap-3"> <CardContent className="flex gap-3">
@@ -28,6 +29,10 @@ export function ReviewCard({ movie, review, userName, userId, isFederated }: Rev
<Link to="/users/$id" params={{ id: userId }} className="relative z-10 font-semibold text-primary"> <Link to="/users/$id" params={{ id: userId }} className="relative z-10 font-semibold text-primary">
{userName} {userName}
</Link> </Link>
) : actorUrl ? (
<a href={actorUrl} target="_blank" rel="noopener noreferrer" className="relative z-10 font-semibold text-primary">
{userName}
</a>
) : ( ) : (
<span>{userName}</span> <span>{userName}</span>
)} )}

View File

@@ -29,9 +29,9 @@ export const feedEntryDtoSchema = z.object({
movie: movieDtoSchema, movie: movieDtoSchema,
review: reviewDtoSchema, review: reviewDtoSchema,
user_id: z.string().uuid(), user_id: z.string().uuid(),
user_email: z.string(),
user_display_name: z.string(), user_display_name: z.string(),
is_federated: z.boolean(), is_federated: z.boolean(),
actor_url: z.string().optional(),
}) })
export type FeedEntryDto = z.infer<typeof feedEntryDtoSchema> export type FeedEntryDto = z.infer<typeof feedEntryDtoSchema>

View File

@@ -115,8 +115,9 @@ function FeedTab() {
movie={entry.movie} movie={entry.movie}
review={entry.review} review={entry.review}
userName={entry.user_display_name} userName={entry.user_display_name}
userId={entry.user_id} userId={entry.is_federated ? undefined : entry.user_id}
isFederated={entry.is_federated} isFederated={entry.is_federated}
actorUrl={entry.actor_url}
/> />
) )
return entry.user_id === auth?.user_id ? ( return entry.user_id === auth?.user_id ? (