fix: tighten public work type routing

This commit is contained in:
2026-06-07 14:49:36 +08:00
parent 8f460feb41
commit 8131894bb5
21 changed files with 611 additions and 228 deletions

View File

@@ -1662,9 +1662,7 @@ fn get_custom_world_gallery_detail_record(
.find(&input.profile_id)
.filter(|row| {
row.owner_user_id == input.owner_user_id
&& row.publication_status == CustomWorldPublicationStatus::Published
&& row.deleted_at.is_none()
&& row.visible
&& is_custom_world_profile_publicly_interactive(row)
});
let gallery_entry = ctx
@@ -1712,8 +1710,7 @@ fn get_custom_world_gallery_detail_record_by_code(
.find(&row.profile_id)
.filter(|profile_row| {
profile_row.owner_user_id == row.owner_user_id
&& profile_row.publication_status == CustomWorldPublicationStatus::Published
&& profile_row.deleted_at.is_none()
&& is_custom_world_profile_publicly_interactive(profile_row)
})
});
@@ -1756,12 +1753,7 @@ fn remix_custom_world_profile_record(
.profile_id()
.find(&source_profile_id.to_string())
.filter(|row| row.owner_user_id == source_owner_user_id)
.filter(|row| {
row.publication_status == CustomWorldPublicationStatus::Published
&& row.deleted_at.is_none()
&& row.visible
&& row.published_at.is_some()
})
.filter(is_custom_world_profile_publicly_interactive)
.ok_or_else(|| "custom_world 已发布源作品不存在,无法改编".to_string())?;
let remixed_at = Timestamp::from_micros_since_unix_epoch(input.remixed_at_micros);
@@ -1859,12 +1851,7 @@ fn record_custom_world_profile_play_record(
.profile_id()
.find(&profile_id.to_string())
.filter(|row| row.owner_user_id == owner_user_id)
.filter(|row| {
row.publication_status == CustomWorldPublicationStatus::Published
&& row.deleted_at.is_none()
&& row.visible
&& row.published_at.is_some()
})
.filter(is_custom_world_profile_publicly_interactive)
.ok_or_else(|| "custom_world 已发布作品不存在,无法记录游玩".to_string())?;
let played_at = Timestamp::from_micros_since_unix_epoch(input.played_at_micros);
@@ -1932,12 +1919,7 @@ fn record_custom_world_profile_like_record(
.profile_id()
.find(&profile_id.to_string())
.filter(|row| row.owner_user_id == owner_user_id)
.filter(|row| {
row.publication_status == CustomWorldPublicationStatus::Published
&& row.deleted_at.is_none()
&& row.visible
&& row.published_at.is_some()
})
.filter(is_custom_world_profile_publicly_interactive)
.ok_or_else(|| "custom_world 已发布作品不存在,无法点赞".to_string())?;
let liked_at = Timestamp::from_micros_since_unix_epoch(input.liked_at_micros);
@@ -1998,6 +1980,18 @@ fn record_custom_world_profile_like_record(
))
}
fn is_custom_world_profile_publicly_interactive(row: &CustomWorldProfile) -> bool {
// 历史公开作品可能缺少 published_at公开互动只按发布、未删除、可见判断。
row.publication_status == CustomWorldPublicationStatus::Published
&& row.deleted_at.is_none()
&& row.visible
}
fn resolve_custom_world_published_at(row: &CustomWorldProfile) -> Timestamp {
// gallery 展示与同步兼容旧数据,用 updated_at 兜底公开时间。
row.published_at.unwrap_or(row.updated_at)
}
fn list_custom_world_work_snapshots(
ctx: &ReducerContext,
input: CustomWorldWorksListInput,
@@ -4832,9 +4826,10 @@ fn sync_custom_world_gallery_entry_from_profile(
ctx: &ReducerContext,
profile: &CustomWorldProfile,
) -> Result<CustomWorldGalleryEntrySnapshot, String> {
let published_at = profile
.published_at
.ok_or_else(|| "published profile 缺少 published_at无法同步 gallery".to_string())?;
if profile.publication_status != CustomWorldPublicationStatus::Published {
return Err("custom_world profile 未发布,无法同步 gallery".to_string());
}
let published_at = resolve_custom_world_published_at(profile);
ctx.db
.custom_world_gallery_entry()
@@ -4881,10 +4876,6 @@ fn sync_missing_custom_world_gallery_entries(ctx: &ReducerContext) -> Result<(),
.collect::<Vec<_>>();
for profile in published_profiles {
if profile.published_at.is_none() {
continue;
}
let existing_gallery_entry = ctx
.db
.custom_world_gallery_entry()
@@ -5483,6 +5474,78 @@ mod tests {
));
}
#[test]
fn custom_world_public_interactions_accept_legacy_missing_published_at() {
fn build_profile(
publication_status: CustomWorldPublicationStatus,
published_at: Option<Timestamp>,
deleted_at: Option<Timestamp>,
visible: bool,
) -> CustomWorldProfile {
CustomWorldProfile {
profile_id: "profile-legacy".to_string(),
owner_user_id: "user-legacy".to_string(),
public_work_code: Some("CW-3A9EC89B".to_string()),
author_public_user_code: Some("SY-00000001".to_string()),
source_agent_session_id: Some("session-legacy".to_string()),
publication_status,
world_name: "旧公开世界".to_string(),
subtitle: String::new(),
summary_text: String::new(),
theme_mode: CustomWorldThemeMode::Mythic,
cover_image_src: None,
profile_payload_json: "{}".to_string(),
playable_npc_count: 0,
landmark_count: 0,
play_count: 0,
remix_count: 0,
like_count: 0,
author_display_name: "玩家".to_string(),
published_at,
deleted_at,
created_at: Timestamp::from_micros_since_unix_epoch(1),
updated_at: Timestamp::from_micros_since_unix_epoch(20),
visible,
}
}
let legacy_published =
build_profile(CustomWorldPublicationStatus::Published, None, None, true);
assert!(is_custom_world_profile_publicly_interactive(
&legacy_published
));
assert_eq!(
resolve_custom_world_published_at(&legacy_published).to_micros_since_unix_epoch(),
20
);
let current_published = build_profile(
CustomWorldPublicationStatus::Published,
Some(Timestamp::from_micros_since_unix_epoch(10)),
None,
true,
);
assert_eq!(
resolve_custom_world_published_at(&current_published).to_micros_since_unix_epoch(),
10
);
assert!(!is_custom_world_profile_publicly_interactive(
&build_profile(CustomWorldPublicationStatus::Draft, None, None, true,)
));
assert!(!is_custom_world_profile_publicly_interactive(
&build_profile(
CustomWorldPublicationStatus::Published,
None,
Some(Timestamp::from_micros_since_unix_epoch(30)),
true,
)
));
assert!(!is_custom_world_profile_publicly_interactive(
&build_profile(CustomWorldPublicationStatus::Published, None, None, false,)
));
}
#[test]
fn custom_world_works_hides_compiled_draft_profile_when_agent_session_is_active() {
fn build_test_custom_world_profile(

View File

@@ -1573,11 +1573,6 @@ mod tests {
5, 1_000, &existing
));
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn jump_hop_delete_input_carries_owner_and_profile() {