feat: complete bark battle draft publish flow
This commit is contained in:
@@ -30,6 +30,19 @@ pub enum BarkBattleFinishStatus {
|
||||
Rejected,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BarkBattleReplacementConfig {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub player_character_image_src: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub opponent_character_image_src: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub ui_background_image_src: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub bark_sound_src: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BarkBattleConfigEditorPayload {
|
||||
@@ -39,6 +52,14 @@ pub struct BarkBattleConfigEditorPayload {
|
||||
pub theme_preset: String,
|
||||
pub player_dog_skin_preset: String,
|
||||
pub opponent_dog_skin_preset: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub player_character_image_src: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub opponent_character_image_src: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub ui_background_image_src: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub bark_sound_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub difficulty_preset: BarkBattleDifficultyPreset,
|
||||
pub leaderboard_enabled: bool,
|
||||
@@ -53,6 +74,14 @@ pub struct BarkBattleDraftCreateRequest {
|
||||
pub theme_preset: String,
|
||||
pub player_dog_skin_preset: String,
|
||||
pub opponent_dog_skin_preset: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub player_character_image_src: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub opponent_character_image_src: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub ui_background_image_src: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub bark_sound_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub difficulty_preset: BarkBattleDifficultyPreset,
|
||||
pub leaderboard_enabled: bool,
|
||||
@@ -66,6 +95,10 @@ impl From<BarkBattleDraftCreateRequest> for BarkBattleConfigEditorPayload {
|
||||
theme_preset: value.theme_preset,
|
||||
player_dog_skin_preset: value.player_dog_skin_preset,
|
||||
opponent_dog_skin_preset: value.opponent_dog_skin_preset,
|
||||
player_character_image_src: value.player_character_image_src,
|
||||
opponent_character_image_src: value.opponent_character_image_src,
|
||||
ui_background_image_src: value.ui_background_image_src,
|
||||
bark_sound_src: value.bark_sound_src,
|
||||
difficulty_preset: value.difficulty_preset,
|
||||
leaderboard_enabled: value.leaderboard_enabled,
|
||||
}
|
||||
@@ -86,12 +119,26 @@ pub struct BarkBattleWorkPublishRequest {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BarkBattleDraftConfig {
|
||||
pub draft_id: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub work_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub config_version: Option<u32>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub ruleset_version: Option<String>,
|
||||
pub title: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub description: Option<String>,
|
||||
pub theme_preset: String,
|
||||
pub player_dog_skin_preset: String,
|
||||
pub opponent_dog_skin_preset: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub player_character_image_src: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub opponent_character_image_src: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub ui_background_image_src: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub bark_sound_src: Option<String>,
|
||||
#[serde(default)]
|
||||
pub difficulty_preset: BarkBattleDifficultyPreset,
|
||||
pub leaderboard_enabled: bool,
|
||||
@@ -102,11 +149,18 @@ impl Default for BarkBattleDraftConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
draft_id: String::new(),
|
||||
work_id: None,
|
||||
config_version: None,
|
||||
ruleset_version: None,
|
||||
title: String::new(),
|
||||
description: None,
|
||||
theme_preset: String::new(),
|
||||
player_dog_skin_preset: String::new(),
|
||||
opponent_dog_skin_preset: String::new(),
|
||||
player_character_image_src: None,
|
||||
opponent_character_image_src: None,
|
||||
ui_background_image_src: None,
|
||||
bark_sound_src: None,
|
||||
difficulty_preset: BarkBattleDifficultyPreset::Normal,
|
||||
leaderboard_enabled: true,
|
||||
updated_at: String::new(),
|
||||
@@ -129,6 +183,14 @@ pub struct BarkBattlePublishedConfig {
|
||||
pub theme_preset: String,
|
||||
pub player_dog_skin_preset: String,
|
||||
pub opponent_dog_skin_preset: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub player_character_image_src: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub opponent_character_image_src: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub ui_background_image_src: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub bark_sound_src: Option<String>,
|
||||
pub difficulty_preset: BarkBattleDifficultyPreset,
|
||||
pub leaderboard_enabled: bool,
|
||||
pub updated_at: String,
|
||||
@@ -151,6 +213,14 @@ pub struct BarkBattleRuntimeConfig {
|
||||
pub theme_preset: String,
|
||||
pub player_dog_skin_preset: String,
|
||||
pub opponent_dog_skin_preset: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub player_character_image_src: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub opponent_character_image_src: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub ui_background_image_src: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub bark_sound_src: Option<String>,
|
||||
pub leaderboard_enabled: bool,
|
||||
pub updated_at: String,
|
||||
}
|
||||
@@ -409,7 +479,22 @@ mod tests {
|
||||
fn optional_fields_are_omitted_when_absent() {
|
||||
let draft = BarkBattleDraftConfig::default();
|
||||
let payload = serde_json::to_value(draft).expect("draft should serialize");
|
||||
assert!(!payload.as_object().unwrap().contains_key("workId"));
|
||||
assert!(!payload.as_object().unwrap().contains_key("configVersion"));
|
||||
assert!(!payload.as_object().unwrap().contains_key("rulesetVersion"));
|
||||
assert!(!payload.as_object().unwrap().contains_key("description"));
|
||||
assert!(
|
||||
!payload
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.contains_key("playerCharacterImageSrc")
|
||||
);
|
||||
assert!(
|
||||
!payload
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.contains_key("uiBackgroundImageSrc")
|
||||
);
|
||||
|
||||
let response = BarkBattlePersonalHistoryResponse {
|
||||
work_id: None,
|
||||
@@ -429,6 +514,74 @@ mod tests {
|
||||
assert!(!payload.as_object().unwrap().contains_key("bestSummary"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn draft_config_serializes_persistent_identity_fields() {
|
||||
let draft = BarkBattleDraftConfig {
|
||||
draft_id: "bark-battle-draft-1".to_string(),
|
||||
work_id: Some("bark-battle-work-1".to_string()),
|
||||
config_version: Some(2),
|
||||
ruleset_version: Some("bark-battle-ruleset-v1".to_string()),
|
||||
title: "汪汪测试杯".to_string(),
|
||||
description: None,
|
||||
theme_preset: "sunny-yard".to_string(),
|
||||
player_dog_skin_preset: "主角".to_string(),
|
||||
opponent_dog_skin_preset: "对手".to_string(),
|
||||
player_character_image_src: None,
|
||||
opponent_character_image_src: None,
|
||||
ui_background_image_src: None,
|
||||
bark_sound_src: None,
|
||||
difficulty_preset: BarkBattleDifficultyPreset::Normal,
|
||||
leaderboard_enabled: true,
|
||||
updated_at: "2026-05-14T10:00:00.000Z".to_string(),
|
||||
};
|
||||
|
||||
let payload = serde_json::to_value(draft).expect("draft should serialize");
|
||||
|
||||
assert_eq!(payload["draftId"], json!("bark-battle-draft-1"));
|
||||
assert_eq!(payload["workId"], json!("bark-battle-work-1"));
|
||||
assert_eq!(payload["configVersion"], json!(2));
|
||||
assert_eq!(
|
||||
payload["rulesetVersion"],
|
||||
json!("bark-battle-ruleset-v1")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn replacement_sources_serialize_as_camel_case_config_fields() {
|
||||
let config = BarkBattleConfigEditorPayload {
|
||||
title: "周末狗狗杯".to_string(),
|
||||
description: Some("轻配置草稿".to_string()),
|
||||
theme_preset: "neon-park".to_string(),
|
||||
player_dog_skin_preset: "shiba".to_string(),
|
||||
opponent_dog_skin_preset: "husky".to_string(),
|
||||
player_character_image_src: Some("/generated-bark-battle/player.png".to_string()),
|
||||
opponent_character_image_src: Some("https://example.test/opponent.png".to_string()),
|
||||
ui_background_image_src: Some("/generated-bark-battle/ui.png".to_string()),
|
||||
bark_sound_src: Some("/generated-bark-battle/bark.mp3".to_string()),
|
||||
difficulty_preset: BarkBattleDifficultyPreset::Hard,
|
||||
leaderboard_enabled: true,
|
||||
};
|
||||
|
||||
let payload = serde_json::to_value(config).expect("config should serialize");
|
||||
|
||||
assert_eq!(
|
||||
payload["playerCharacterImageSrc"],
|
||||
json!("/generated-bark-battle/player.png")
|
||||
);
|
||||
assert_eq!(
|
||||
payload["opponentCharacterImageSrc"],
|
||||
json!("https://example.test/opponent.png")
|
||||
);
|
||||
assert_eq!(
|
||||
payload["uiBackgroundImageSrc"],
|
||||
json!("/generated-bark-battle/ui.png")
|
||||
);
|
||||
assert_eq!(
|
||||
payload["barkSoundSrc"],
|
||||
json!("/generated-bark-battle/bark.mp3")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn finish_response_serializes_player_win_and_accepted() {
|
||||
let response = BarkBattleRunFinishResponse {
|
||||
|
||||
Reference in New Issue
Block a user