feat: unify phase one creation flow
This commit is contained in:
@@ -122,6 +122,35 @@ impl SpacetimeClient {
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn mark_wooden_fish_generation_failed(
|
||||
&self,
|
||||
session_id: String,
|
||||
owner_user_id: String,
|
||||
author_display_name: String,
|
||||
) -> Result<WoodenFishSessionSnapshotResponse, SpacetimeClientError> {
|
||||
let current = self
|
||||
.get_wooden_fish_session(session_id.clone(), owner_user_id.clone())
|
||||
.await?;
|
||||
let mut draft = current.draft.clone().unwrap_or_else(default_draft);
|
||||
let profile_id = resolve_wooden_fish_profile_id(
|
||||
&draft,
|
||||
&WoodenFishActionType::CompileDraft,
|
||||
draft.profile_id.as_deref(),
|
||||
)?;
|
||||
draft.profile_id = Some(profile_id.clone());
|
||||
draft.generation_status = WoodenFishGenerationStatus::Failed;
|
||||
let now_micros = current_unix_micros();
|
||||
self.compile_wooden_fish_draft(build_failed_compile_input(
|
||||
¤t,
|
||||
&owner_user_id,
|
||||
&author_display_name,
|
||||
&profile_id,
|
||||
&draft,
|
||||
now_micros,
|
||||
)?)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn compile_wooden_fish_draft(
|
||||
&self,
|
||||
procedure_input: WoodenFishDraftCompileInput,
|
||||
@@ -636,6 +665,52 @@ fn build_compile_input(
|
||||
})
|
||||
}
|
||||
|
||||
fn build_failed_compile_input(
|
||||
current: &WoodenFishSessionSnapshotResponse,
|
||||
owner_user_id: &str,
|
||||
author_display_name: &str,
|
||||
profile_id: &str,
|
||||
draft: &WoodenFishDraftResponse,
|
||||
now_micros: i64,
|
||||
) -> Result<WoodenFishDraftCompileInput, SpacetimeClientError> {
|
||||
Ok(WoodenFishDraftCompileInput {
|
||||
session_id: current.session_id.clone(),
|
||||
owner_user_id: owner_user_id.to_string(),
|
||||
profile_id: profile_id.to_string(),
|
||||
author_display_name: author_display_name.trim().to_string(),
|
||||
work_title: draft.work_title.clone(),
|
||||
work_description: draft.work_description.clone(),
|
||||
theme_tags_json: Some(json_string(&draft.theme_tags)?),
|
||||
hit_object_prompt: draft.hit_object_prompt.clone(),
|
||||
hit_object_reference_image_src: draft.hit_object_reference_image_src.clone(),
|
||||
hit_sound_prompt: draft.hit_sound_prompt.clone(),
|
||||
hit_object_asset_json: draft
|
||||
.hit_object_asset
|
||||
.as_ref()
|
||||
.map(json_string)
|
||||
.transpose()?,
|
||||
background_asset_json: draft
|
||||
.background_asset
|
||||
.as_ref()
|
||||
.map(json_string)
|
||||
.transpose()?,
|
||||
hit_sound_asset_json: draft
|
||||
.hit_sound_asset
|
||||
.as_ref()
|
||||
.map(json_string)
|
||||
.transpose()?,
|
||||
back_button_asset_json: draft
|
||||
.back_button_asset
|
||||
.as_ref()
|
||||
.map(json_string)
|
||||
.transpose()?,
|
||||
floating_words_json: Some(json_string(&draft.floating_words)?),
|
||||
cover_image_src: draft.cover_image_src.clone(),
|
||||
generation_status: Some("failed".to_string()),
|
||||
compiled_at_micros: now_micros,
|
||||
})
|
||||
}
|
||||
|
||||
fn build_update_input(
|
||||
owner_user_id: &str,
|
||||
profile_id: &str,
|
||||
@@ -801,6 +876,7 @@ mod tests {
|
||||
|
||||
const SESSION_ID: &str = "wooden-fish-session-test";
|
||||
const OWNER_USER_ID: &str = "user-test";
|
||||
const AUTHOR_DISPLAY_NAME: &str = "测试玩家";
|
||||
const PROFILE_ID: &str = "wooden-fish-profile-test";
|
||||
const NOW_MICROS: i64 = 1_763_456_789_000_000;
|
||||
|
||||
@@ -813,9 +889,14 @@ mod tests {
|
||||
payload.back_button_asset = Some(generated_back_button_asset("generated-compile-back"));
|
||||
payload.hit_sound_asset = Some(generated_hit_sound_asset("generated-compile-sound"));
|
||||
|
||||
let (plan, draft) =
|
||||
build_wooden_fish_action_plan(&session, OWNER_USER_ID, &payload, NOW_MICROS)
|
||||
.expect("compile-draft should build plan");
|
||||
let (plan, draft) = build_wooden_fish_action_plan(
|
||||
&session,
|
||||
OWNER_USER_ID,
|
||||
AUTHOR_DISPLAY_NAME,
|
||||
&payload,
|
||||
NOW_MICROS,
|
||||
)
|
||||
.expect("compile-draft should build plan");
|
||||
|
||||
let WoodenFishActionProcedure::Compile(input) = plan else {
|
||||
panic!("compile-draft should call compile_wooden_fish_draft");
|
||||
@@ -862,11 +943,16 @@ mod tests {
|
||||
payload.background_asset = Some(generated_background_asset("generated-compile-background"));
|
||||
payload.back_button_asset = Some(generated_back_button_asset("generated-compile-back"));
|
||||
|
||||
let error =
|
||||
match build_wooden_fish_action_plan(&session, OWNER_USER_ID, &payload, NOW_MICROS) {
|
||||
Ok(_) => panic!("compile-draft should not synthesize fake hit sound assets"),
|
||||
Err(error) => error,
|
||||
};
|
||||
let error = match build_wooden_fish_action_plan(
|
||||
&session,
|
||||
OWNER_USER_ID,
|
||||
AUTHOR_DISPLAY_NAME,
|
||||
&payload,
|
||||
NOW_MICROS,
|
||||
) {
|
||||
Ok(_) => panic!("compile-draft should not synthesize fake hit sound assets"),
|
||||
Err(error) => error,
|
||||
};
|
||||
|
||||
assert!(
|
||||
error
|
||||
@@ -883,11 +969,16 @@ mod tests {
|
||||
payload.hit_sound_asset = Some(generated_hit_sound_asset("generated-compile-sound"));
|
||||
payload.back_button_asset = Some(generated_back_button_asset("generated-compile-back"));
|
||||
|
||||
let error =
|
||||
match build_wooden_fish_action_plan(&session, OWNER_USER_ID, &payload, NOW_MICROS) {
|
||||
Ok(_) => panic!("compile-draft should not publish without background asset"),
|
||||
Err(error) => error,
|
||||
};
|
||||
let error = match build_wooden_fish_action_plan(
|
||||
&session,
|
||||
OWNER_USER_ID,
|
||||
AUTHOR_DISPLAY_NAME,
|
||||
&payload,
|
||||
NOW_MICROS,
|
||||
) {
|
||||
Ok(_) => panic!("compile-draft should not publish without background asset"),
|
||||
Err(error) => error,
|
||||
};
|
||||
|
||||
assert!(
|
||||
error
|
||||
@@ -904,11 +995,16 @@ mod tests {
|
||||
payload.background_asset = Some(generated_background_asset("generated-compile-background"));
|
||||
payload.hit_sound_asset = Some(generated_hit_sound_asset("generated-compile-sound"));
|
||||
|
||||
let error =
|
||||
match build_wooden_fish_action_plan(&session, OWNER_USER_ID, &payload, NOW_MICROS) {
|
||||
Ok(_) => panic!("compile-draft should not publish without back button asset"),
|
||||
Err(error) => error,
|
||||
};
|
||||
let error = match build_wooden_fish_action_plan(
|
||||
&session,
|
||||
OWNER_USER_ID,
|
||||
AUTHOR_DISPLAY_NAME,
|
||||
&payload,
|
||||
NOW_MICROS,
|
||||
) {
|
||||
Ok(_) => panic!("compile-draft should not publish without back button asset"),
|
||||
Err(error) => error,
|
||||
};
|
||||
|
||||
assert!(
|
||||
error
|
||||
@@ -926,9 +1022,14 @@ mod tests {
|
||||
payload.background_asset = Some(generated_background_asset("generated-background"));
|
||||
payload.back_button_asset = Some(generated_back_button_asset("generated-back"));
|
||||
|
||||
let (plan, _draft) =
|
||||
build_wooden_fish_action_plan(&session, OWNER_USER_ID, &payload, NOW_MICROS)
|
||||
.expect("regenerate-hit-object should build plan");
|
||||
let (plan, _draft) = build_wooden_fish_action_plan(
|
||||
&session,
|
||||
OWNER_USER_ID,
|
||||
AUTHOR_DISPLAY_NAME,
|
||||
&payload,
|
||||
NOW_MICROS,
|
||||
)
|
||||
.expect("regenerate-hit-object should build plan");
|
||||
|
||||
let WoodenFishActionProcedure::Compile(input) = plan else {
|
||||
panic!("regenerate-hit-object should call compile_wooden_fish_draft");
|
||||
@@ -987,9 +1088,14 @@ mod tests {
|
||||
"健康+1".to_string(),
|
||||
]);
|
||||
|
||||
let (plan, draft) =
|
||||
build_wooden_fish_action_plan(&session, OWNER_USER_ID, &payload, NOW_MICROS)
|
||||
.expect("update-floating-words should build plan");
|
||||
let (plan, draft) = build_wooden_fish_action_plan(
|
||||
&session,
|
||||
OWNER_USER_ID,
|
||||
AUTHOR_DISPLAY_NAME,
|
||||
&payload,
|
||||
NOW_MICROS,
|
||||
)
|
||||
.expect("update-floating-words should build plan");
|
||||
|
||||
let WoodenFishActionProcedure::Update(input) = plan else {
|
||||
panic!("update-floating-words should call update_wooden_fish_work");
|
||||
@@ -1016,6 +1122,31 @@ mod tests {
|
||||
assert!(draft.hit_sound_prompt.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wooden_fish_failed_compile_input_preserves_session_and_marks_failed() {
|
||||
let session = session_with_draft(draft_without_assets());
|
||||
let mut draft = session.draft.clone().expect("draft should exist");
|
||||
draft.profile_id = Some(PROFILE_ID.to_string());
|
||||
draft.generation_status = WoodenFishGenerationStatus::Failed;
|
||||
|
||||
let input = build_failed_compile_input(
|
||||
&session,
|
||||
OWNER_USER_ID,
|
||||
"测试玩家",
|
||||
PROFILE_ID,
|
||||
&draft,
|
||||
NOW_MICROS,
|
||||
)
|
||||
.expect("failed compile input should build");
|
||||
|
||||
assert_eq!(input.session_id, SESSION_ID);
|
||||
assert_eq!(input.profile_id, PROFILE_ID);
|
||||
assert_eq!(input.generation_status.as_deref(), Some("failed"));
|
||||
assert!(input.hit_object_asset_json.is_none());
|
||||
assert!(input.background_asset_json.is_none());
|
||||
assert!(input.back_button_asset_json.is_none());
|
||||
}
|
||||
|
||||
fn action(action_type: WoodenFishActionType) -> WoodenFishActionRequest {
|
||||
WoodenFishActionRequest {
|
||||
action_type,
|
||||
|
||||
Reference in New Issue
Block a user