feat: refresh creation config and visual assets
This commit is contained in:
@@ -8,8 +8,8 @@ use axum::{
|
||||
};
|
||||
use serde_json::{Value, json};
|
||||
|
||||
#[cfg(test)]
|
||||
use module_runtime::build_creation_entry_config_response;
|
||||
use shared_contracts::creation_entry_config::CreationEntryConfigResponse;
|
||||
|
||||
use crate::{
|
||||
api_response::json_success_body, http_error::AppError, request_context::RequestContext,
|
||||
@@ -115,9 +115,8 @@ fn creation_entry_error_response(request_context: &RequestContext, error: AppErr
|
||||
error.into_response_with_context(Some(request_context))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn test_creation_entry_config_response()
|
||||
-> shared_contracts::creation_entry_config::CreationEntryConfigResponse {
|
||||
/// 中文注释:本地 debug 兜底也来自后端领域默认种子,避免前端恢复硬编码入口配置。
|
||||
pub(crate) fn default_creation_entry_config_response() -> CreationEntryConfigResponse {
|
||||
build_creation_entry_config_response(module_runtime::CreationEntryConfigSnapshot {
|
||||
config_id: module_runtime::CREATION_ENTRY_CONFIG_GLOBAL_ID.to_string(),
|
||||
start_card: module_runtime::CreationEntryStartCardSnapshot {
|
||||
@@ -135,6 +134,11 @@ pub(crate) fn test_creation_entry_config_response()
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn test_creation_entry_config_response() -> CreationEntryConfigResponse {
|
||||
default_creation_entry_config_response()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -181,7 +185,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_creation_entry_config_response_keeps_baby_object_match_coming_soon() {
|
||||
fn test_creation_entry_config_response_keeps_baby_object_match_visible() {
|
||||
let config = test_creation_entry_config_response();
|
||||
let baby_object_match = config
|
||||
.creation_types
|
||||
@@ -191,8 +195,8 @@ mod tests {
|
||||
|
||||
assert_eq!(baby_object_match.title, "宝贝识物");
|
||||
assert!(baby_object_match.visible);
|
||||
assert!(!baby_object_match.open);
|
||||
assert_eq!(baby_object_match.badge, "敬请期待");
|
||||
assert!(baby_object_match.open);
|
||||
assert_eq!(baby_object_match.badge, "可创建");
|
||||
assert_eq!(baby_object_match.sort_order, 90);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,6 +383,14 @@ impl AppState {
|
||||
self.cache_test_creation_entry_config(config.clone());
|
||||
Ok(config)
|
||||
}
|
||||
#[cfg(debug_assertions)]
|
||||
Err(error) if is_missing_creation_entry_config_procedure(&error) => {
|
||||
warn!(
|
||||
error = %error,
|
||||
"本地 SpacetimeDB 缺少创作入口配置 procedure,使用后端默认入口配置兜底"
|
||||
);
|
||||
Ok(crate::creation_entry_config::default_creation_entry_config_response())
|
||||
}
|
||||
#[cfg(test)]
|
||||
Err(_) => Ok(self.read_test_creation_entry_config()),
|
||||
#[cfg(not(test))]
|
||||
@@ -1247,12 +1255,37 @@ fn build_admin_runtime(
|
||||
}))
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
fn is_missing_creation_entry_config_procedure(error: &SpacetimeClientError) -> bool {
|
||||
match error {
|
||||
SpacetimeClientError::Procedure(message) => {
|
||||
message.contains("No such procedure")
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use module_ai::{AiTaskKind, generate_ai_task_id};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn detects_missing_creation_entry_config_procedure_for_debug_fallback() {
|
||||
assert!(is_missing_creation_entry_config_procedure(
|
||||
&SpacetimeClientError::Procedure(
|
||||
"No such procedure: get_creation_entry_config".to_string(),
|
||||
),
|
||||
));
|
||||
assert!(is_missing_creation_entry_config_procedure(
|
||||
&SpacetimeClientError::Procedure("No such procedure".to_string()),
|
||||
));
|
||||
assert!(!is_missing_creation_entry_config_procedure(
|
||||
&SpacetimeClientError::Timeout,
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn app_state_exposes_usable_ai_task_service() {
|
||||
let state = AppState::new(AppConfig::default()).expect("state should build");
|
||||
|
||||
@@ -164,10 +164,10 @@ pub fn default_creation_entry_type_snapshots(
|
||||
"baby-object-match",
|
||||
"宝贝识物",
|
||||
"亲子识物分类",
|
||||
"敬请期待",
|
||||
"可创建",
|
||||
"/child-motion-demo/picture-book-grass-stage.png",
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
90,
|
||||
updated_at_micros,
|
||||
),
|
||||
|
||||
@@ -227,8 +227,8 @@ mod tests {
|
||||
assert_eq!(baby_object_match.title, "宝贝识物");
|
||||
assert_eq!(baby_object_match.subtitle, "亲子识物分类");
|
||||
assert!(baby_object_match.visible);
|
||||
assert!(!baby_object_match.open);
|
||||
assert_eq!(baby_object_match.badge, "敬请期待");
|
||||
assert!(baby_object_match.open);
|
||||
assert_eq!(baby_object_match.badge, "可创建");
|
||||
assert_eq!(baby_object_match.sort_order, 90);
|
||||
assert_eq!(
|
||||
baby_object_match.image_src,
|
||||
|
||||
@@ -191,17 +191,7 @@ fn seed_creation_entry_config_if_missing(ctx: &ReducerContext) {
|
||||
sort_order: 85,
|
||||
},
|
||||
);
|
||||
migrate_coming_soon_entry_from_old_open_default(
|
||||
ctx,
|
||||
now,
|
||||
ComingSoonEntryDefault {
|
||||
id: "baby-object-match",
|
||||
title: "宝贝识物",
|
||||
subtitle: "亲子识物分类",
|
||||
image_src: "/child-motion-demo/picture-book-grass-stage.png",
|
||||
sort_order: 90,
|
||||
},
|
||||
);
|
||||
migrate_baby_object_match_entry_from_old_coming_soon_default(ctx, now);
|
||||
}
|
||||
|
||||
fn migrate_visual_novel_entry_from_old_visible_default(ctx: &ReducerContext, now: Timestamp) {
|
||||
@@ -274,6 +264,38 @@ fn migrate_coming_soon_entry_from_old_open_default(
|
||||
});
|
||||
}
|
||||
|
||||
fn migrate_baby_object_match_entry_from_old_coming_soon_default(
|
||||
ctx: &ReducerContext,
|
||||
now: Timestamp,
|
||||
) {
|
||||
let id = "baby-object-match".to_string();
|
||||
let Some(row) = ctx.db.creation_entry_type_config().id().find(&id) else {
|
||||
return;
|
||||
};
|
||||
|
||||
// 中文注释:宝贝识物已接入完整创作发布链路,只纠偏历史默认敬请期待种子。
|
||||
let still_old_coming_soon_default = row.title == "宝贝识物"
|
||||
&& row.subtitle == "亲子识物分类"
|
||||
&& row.badge == "敬请期待"
|
||||
&& row.image_src == "/child-motion-demo/picture-book-grass-stage.png"
|
||||
&& row.visible
|
||||
&& !row.open
|
||||
&& row.sort_order == 90;
|
||||
if !still_old_coming_soon_default {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.db
|
||||
.creation_entry_type_config()
|
||||
.id()
|
||||
.update(CreationEntryTypeConfig {
|
||||
badge: "可创建".to_string(),
|
||||
open: true,
|
||||
updated_at: now,
|
||||
..row
|
||||
});
|
||||
}
|
||||
|
||||
fn default_creation_entry_type_configs(now: Timestamp) -> Vec<CreationEntryTypeConfig> {
|
||||
module_runtime::default_creation_entry_type_snapshots(now.to_micros_since_unix_epoch())
|
||||
.into_iter()
|
||||
|
||||
Reference in New Issue
Block a user