1
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
use crate::*;
|
||||
|
||||
const ASSET_HISTORY_MAX_LIMIT: usize = 120;
|
||||
const ASSET_HISTORY_CHARACTER_VISUAL_KIND: &str = "character_visual";
|
||||
const ASSET_HISTORY_SCENE_IMAGE_KIND: &str = "scene_image";
|
||||
|
||||
#[spacetimedb::table(
|
||||
accessor = asset_object,
|
||||
index(accessor = by_bucket_object_key, btree(columns = [bucket, object_key]))
|
||||
@@ -54,6 +58,26 @@ pub fn confirm_asset_object_and_return(
|
||||
}
|
||||
}
|
||||
|
||||
// 历史素材只返回编辑器复用所需的脱敏字段,asset_object 本表继续保持 private。
|
||||
#[spacetimedb::procedure]
|
||||
pub fn list_asset_history_and_return(
|
||||
ctx: &mut ProcedureContext,
|
||||
input: AssetHistoryListInput,
|
||||
) -> AssetHistoryListResult {
|
||||
match ctx.try_with_tx(|tx| list_asset_history(tx, input.clone())) {
|
||||
Ok(entries) => AssetHistoryListResult {
|
||||
ok: true,
|
||||
entries,
|
||||
error_message: None,
|
||||
},
|
||||
Err(message) => AssetHistoryListResult {
|
||||
ok: false,
|
||||
entries: Vec::new(),
|
||||
error_message: Some(message),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn upsert_asset_object(
|
||||
ctx: &ReducerContext,
|
||||
input: AssetObjectUpsertInput,
|
||||
@@ -167,3 +191,52 @@ pub(crate) fn has_asset_object(ctx: &ReducerContext, asset_object_id: &str) -> b
|
||||
.iter()
|
||||
.any(|row| row.asset_object_id == asset_object_id)
|
||||
}
|
||||
|
||||
fn list_asset_history(
|
||||
ctx: &ReducerContext,
|
||||
input: AssetHistoryListInput,
|
||||
) -> Result<Vec<AssetHistoryEntrySnapshot>, String> {
|
||||
let asset_kind = input.asset_kind.trim();
|
||||
if asset_kind != ASSET_HISTORY_CHARACTER_VISUAL_KIND
|
||||
&& asset_kind != ASSET_HISTORY_SCENE_IMAGE_KIND
|
||||
{
|
||||
return Err("历史素材类型只支持 character_visual 或 scene_image".to_string());
|
||||
}
|
||||
|
||||
let limit = usize::try_from(input.limit)
|
||||
.unwrap_or(ASSET_HISTORY_MAX_LIMIT)
|
||||
.clamp(1, ASSET_HISTORY_MAX_LIMIT);
|
||||
let mut entries = ctx
|
||||
.db
|
||||
.asset_object()
|
||||
.iter()
|
||||
.filter(|row| row.asset_kind == asset_kind)
|
||||
.map(|row| AssetHistoryEntrySnapshot {
|
||||
asset_object_id: row.asset_object_id,
|
||||
asset_kind: row.asset_kind,
|
||||
image_src: object_key_to_legacy_image_src(row.object_key.as_str()),
|
||||
owner_user_id: row.owner_user_id,
|
||||
profile_id: row.profile_id,
|
||||
entity_id: row.entity_id,
|
||||
created_at_micros: row.created_at.to_micros_since_unix_epoch(),
|
||||
updated_at_micros: row.updated_at.to_micros_since_unix_epoch(),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
entries.sort_by(|left, right| {
|
||||
right
|
||||
.created_at_micros
|
||||
.cmp(&left.created_at_micros)
|
||||
.then_with(|| right.asset_object_id.cmp(&left.asset_object_id))
|
||||
});
|
||||
entries.truncate(limit);
|
||||
Ok(entries)
|
||||
}
|
||||
|
||||
fn object_key_to_legacy_image_src(object_key: &str) -> String {
|
||||
let normalized = object_key.trim().trim_start_matches('/');
|
||||
if normalized.is_empty() {
|
||||
return String::new();
|
||||
}
|
||||
format!("/{normalized}")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user