Merge remote-tracking branch 'origin/master' into codex/wooden-fish-template
This commit is contained in:
@@ -2562,6 +2562,18 @@ fn upsert_nested_result_profile_id(
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_publish_world_setting_text(
|
||||
payload: &JsonMap<String, JsonValue>,
|
||||
draft_profile: &JsonMap<String, JsonValue>,
|
||||
session: &CustomWorldAgentSession,
|
||||
) -> String {
|
||||
module_custom_world::resolve_custom_world_publish_setting_text(
|
||||
payload,
|
||||
draft_profile,
|
||||
&session.seed_text,
|
||||
)
|
||||
}
|
||||
|
||||
fn is_same_agent_draft_profile_candidate(
|
||||
row: &CustomWorldProfile,
|
||||
owner_user_id: &str,
|
||||
@@ -2581,13 +2593,10 @@ fn execute_publish_world_action(
|
||||
) -> Result<CustomWorldAgentOperationSnapshot, String> {
|
||||
ensure_publishable_stage(session.stage, "publish_world")?;
|
||||
|
||||
let draft_profile =
|
||||
if let Some(explicit) = payload.get("draftProfile").and_then(JsonValue::as_object) {
|
||||
explicit.clone()
|
||||
} else {
|
||||
parse_optional_session_object(session.draft_profile_json.as_deref())
|
||||
.ok_or_else(|| "publish_world requires draft_profile_json".to_string())?
|
||||
};
|
||||
// 中文注释:发布动作不再信任前端携带的 draftProfile。
|
||||
// 点击发布前,结果页 profile 必须先通过 sync_result_profile 写回
|
||||
// custom_world_agent_session.draft_profile_json;正式发布只读取这份会话真相。
|
||||
let draft_profile = read_publish_world_draft_profile_from_session(session)?;
|
||||
let gate = summarize_publish_gate_from_json(
|
||||
&session.session_id,
|
||||
session.stage,
|
||||
@@ -2601,24 +2610,9 @@ fn execute_publish_world_action(
|
||||
));
|
||||
}
|
||||
|
||||
let profile_id = payload
|
||||
.get("profileId")
|
||||
.and_then(JsonValue::as_str)
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
.map(ToOwned::to_owned)
|
||||
.unwrap_or_else(|| gate.profile_id.clone());
|
||||
let setting_text = payload
|
||||
.get("settingText")
|
||||
.and_then(JsonValue::as_str)
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
.map(ToOwned::to_owned)
|
||||
.unwrap_or_else(|| session.seed_text.clone());
|
||||
let legacy_result_profile_json = payload
|
||||
.get("legacyResultProfile")
|
||||
.map(serialize_json_value)
|
||||
.transpose()?;
|
||||
let profile_id = gate.profile_id.clone();
|
||||
let setting_text = resolve_publish_world_setting_text(payload, &draft_profile, session);
|
||||
let legacy_result_profile_json = None;
|
||||
let author_public_user_code = read_optional_text_field(payload, &["authorPublicUserCode"])
|
||||
.unwrap_or_else(|| build_public_user_code_from_owner_user_id(&session.owner_user_id));
|
||||
let author_display_name = read_optional_text_field(payload, &["authorDisplayName"])
|
||||
@@ -2663,6 +2657,13 @@ fn execute_publish_world_action(
|
||||
Ok(build_custom_world_agent_operation_snapshot(&operation))
|
||||
}
|
||||
|
||||
fn read_publish_world_draft_profile_from_session(
|
||||
session: &CustomWorldAgentSession,
|
||||
) -> Result<JsonMap<String, JsonValue>, String> {
|
||||
parse_optional_session_object(session.draft_profile_json.as_deref())
|
||||
.ok_or_else(|| "publish_world requires draft_profile_json".to_string())
|
||||
}
|
||||
|
||||
fn execute_revert_checkpoint_action(
|
||||
ctx: &ReducerContext,
|
||||
session: &CustomWorldAgentSession,
|
||||
@@ -5250,6 +5251,26 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn publish_world_draft_profile_comes_from_session_not_payload() {
|
||||
let session = build_test_custom_world_agent_session(
|
||||
"seed",
|
||||
RpgAgentStage::ReadyToPublish,
|
||||
Some(r#"{"id":"saved-profile","name":"已保存草稿"}"#),
|
||||
);
|
||||
let draft_profile =
|
||||
read_publish_world_draft_profile_from_session(&session).expect("session draft exists");
|
||||
|
||||
assert_eq!(
|
||||
draft_profile.get("id").and_then(JsonValue::as_str),
|
||||
Some("saved-profile")
|
||||
);
|
||||
assert_eq!(
|
||||
draft_profile.get("name").and_then(JsonValue::as_str),
|
||||
Some("已保存草稿")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn custom_world_agent_session_direct_work_content_ignores_empty_created_session() {
|
||||
let empty_session =
|
||||
|
||||
@@ -1293,6 +1293,12 @@ fn select_puzzle_cover_image_tx(
|
||||
ui_background_prompt: target_level.ui_background_prompt,
|
||||
ui_background_image_src: target_level.ui_background_image_src,
|
||||
ui_background_image_object_key: target_level.ui_background_image_object_key,
|
||||
level_scene_image_src: target_level.level_scene_image_src,
|
||||
level_scene_image_object_key: target_level.level_scene_image_object_key,
|
||||
ui_spritesheet_image_src: target_level.ui_spritesheet_image_src,
|
||||
ui_spritesheet_image_object_key: target_level.ui_spritesheet_image_object_key,
|
||||
level_background_image_src: target_level.level_background_image_src,
|
||||
level_background_image_object_key: target_level.level_background_image_object_key,
|
||||
background_music: target_level.background_music,
|
||||
candidates: selected_level_draft.candidates,
|
||||
selected_candidate_id: selected_level_draft.selected_candidate_id,
|
||||
@@ -2636,6 +2642,12 @@ fn build_profile_levels_from_row(
|
||||
ui_background_prompt: None,
|
||||
ui_background_image_src: None,
|
||||
ui_background_image_object_key: None,
|
||||
level_scene_image_src: None,
|
||||
level_scene_image_object_key: None,
|
||||
ui_spritesheet_image_src: None,
|
||||
ui_spritesheet_image_object_key: None,
|
||||
level_background_image_src: None,
|
||||
level_background_image_object_key: None,
|
||||
background_music: None,
|
||||
candidates: Vec::new(),
|
||||
selected_candidate_id: None,
|
||||
|
||||
@@ -179,6 +179,7 @@ fn seed_creation_entry_config_if_missing(ctx: &ReducerContext) {
|
||||
}
|
||||
}
|
||||
|
||||
migrate_rpg_entry_from_old_hidden_default(ctx, now);
|
||||
migrate_visual_novel_entry_from_old_visible_default(ctx, now);
|
||||
migrate_coming_soon_entry_from_old_open_default(
|
||||
ctx,
|
||||
@@ -195,6 +196,36 @@ fn seed_creation_entry_config_if_missing(ctx: &ReducerContext) {
|
||||
migrate_wooden_fish_entry_from_old_puzzle_image_default(ctx, now);
|
||||
}
|
||||
|
||||
fn migrate_rpg_entry_from_old_hidden_default(ctx: &ReducerContext, now: Timestamp) {
|
||||
let id = "rpg".to_string();
|
||||
let Some(row) = ctx.db.creation_entry_type_config().id().find(&id) else {
|
||||
return;
|
||||
};
|
||||
|
||||
// 中文注释:只开放历史默认隐藏的 RPG 入口,不覆盖后台入口开关后续手动配置。
|
||||
let still_old_hidden_default = row.title == "文字冒险"
|
||||
&& row.subtitle == "经典 RPG 体验"
|
||||
&& row.badge == "内测"
|
||||
&& row.image_src == "/creation-type-references/rpg.webp"
|
||||
&& !row.visible
|
||||
&& row.open
|
||||
&& row.sort_order == 10;
|
||||
if !still_old_hidden_default {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.db
|
||||
.creation_entry_type_config()
|
||||
.id()
|
||||
.update(CreationEntryTypeConfig {
|
||||
badge: "可创建".to_string(),
|
||||
visible: true,
|
||||
open: true,
|
||||
updated_at: now,
|
||||
..row
|
||||
});
|
||||
}
|
||||
|
||||
fn migrate_visual_novel_entry_from_old_visible_default(ctx: &ReducerContext, now: Timestamp) {
|
||||
let id = "visual-novel".to_string();
|
||||
let Some(row) = ctx.db.creation_entry_type_config().id().find(&id) else {
|
||||
|
||||
Reference in New Issue
Block a user