feat: add visible flag for works
This commit is contained in:
@@ -39,6 +39,8 @@
|
||||
- `sort_time_micros`
|
||||
- `detail_payload_json`
|
||||
|
||||
作品源表新增 `visible` 可见性字段,默认 `true`。`visible` 属于源表 / source view 过滤条件,不作为统一公开契约默认返回字段;当 `visible=false` 时,对应作品不得进入 `public_work_gallery_entry` 和 `public_work_detail_entry`。
|
||||
|
||||
其中 `detail_payload_json` 只承载平台详情页展示扩展,不承载正式 runtime 配置、玩法规则或草稿真相。
|
||||
|
||||
## 来源与兼容
|
||||
@@ -63,6 +65,7 @@
|
||||
- 旧 view 保留,不删除。
|
||||
- 旧 view 退到底层 source / 兼容职责。
|
||||
- 新 `public_work_*` view 是 `api-server` 公开列表 / 详情的统一主读模型。
|
||||
- 各玩法 source view 只暴露 `visible=true` 的已发布作品;旧数据迁移默认补 `visible=true`,避免历史作品被误隐藏。
|
||||
- 旧 `/api/runtime/<play>/gallery` 响应 shape 保持兼容,由 BFF mapper 把统一 cache 再映射回当前 DTO。
|
||||
- 旧详情 / runtime / 点赞 / 游玩 / Remix 仍走玩法专用路径。
|
||||
|
||||
|
||||
@@ -252,6 +252,7 @@ npm run check:server-rs-ddd
|
||||
|
||||
- Rust 结构体:`BarkBattlePublishedConfigRow`
|
||||
- 源码:`server-rs/crates/spacetime-module/src/bark_battle/tables.rs`
|
||||
- 字段变更:`visible` 控制是否进入公开列表 / 详情,默认 `true`;旧迁移数据由 `migration.rs` 补默认值。
|
||||
|
||||
### `bark_battle_runtime_run`
|
||||
|
||||
@@ -288,6 +289,7 @@ npm run check:server-rs-ddd
|
||||
- Rust 结构体:`BigFishCreationSession`
|
||||
- 源码:`server-rs/crates/spacetime-module/src/big_fish/tables.rs`
|
||||
- 索引:`by_big_fish_session_owner_user_id`、`by_big_fish_session_stage`。公开广场 view 使用 `by_big_fish_session_stage` 读取已发布会话,避免扫整表。
|
||||
- 字段变更:`visible` 控制是否进入公开列表 / 详情,默认 `true`;旧迁移数据由 `migration.rs` 补默认值。
|
||||
|
||||
### `big_fish_event`
|
||||
|
||||
@@ -351,11 +353,13 @@ npm run check:server-rs-ddd
|
||||
- Rust 结构体:`CustomWorldGalleryEntry`
|
||||
- 源码:`server-rs/crates/spacetime-module/src/custom_world.rs`
|
||||
- 作用:自定义世界公开 source 读模型。统一公开列表 / 详情主路径通过 `public_work_gallery_entry` / `public_work_detail_entry` 消费该投影并映射成跨玩法契约;`/api/runtime/custom-world-gallery` 保留旧 HTTP shape,并从统一 public cache 映射回旧 DTO。旧 procedure 只用于兼容旧库缺少 gallery 读模型行时的一次性同步兜底。
|
||||
- 字段变更:`visible` 控制是否进入公开列表 / 详情,默认 `true`;旧迁移数据由 `migration.rs` 补默认值。
|
||||
|
||||
### `custom_world_profile`
|
||||
|
||||
- Rust 结构体:`CustomWorldProfile`
|
||||
- 源码:`server-rs/crates/spacetime-module/src/custom_world.rs`
|
||||
- 字段变更:`visible` 控制是否进入公开列表 / 详情,默认 `true`;旧迁移数据由 `migration.rs` 补默认值。
|
||||
|
||||
### `custom_world_session`
|
||||
|
||||
@@ -410,6 +414,7 @@ npm run check:server-rs-ddd
|
||||
- 返回类型:`Vec<JumpHopGalleryViewRow>`
|
||||
- 源码:`server-rs/crates/spacetime-module/src/jump_hop.rs`
|
||||
- 说明:跳一跳公开详情兼容投影,包含作品、路径和素材字段;统一公开详情主路径通过 `public_work_detail_entry` 消费该 view,只保留平台详情页展示摘要。
|
||||
- 字段变更:`visible` 控制是否进入公开列表 / 详情,默认 `true`;旧迁移数据由 `migration.rs` 补默认值。
|
||||
|
||||
### `wooden_fish_agent_session`
|
||||
|
||||
@@ -445,6 +450,7 @@ npm run check:server-rs-ddd
|
||||
- 返回类型:`Vec<WoodenFishGalleryViewRow>`
|
||||
- 源码:`server-rs/crates/spacetime-module/src/wooden_fish.rs`
|
||||
- 说明:敲木鱼公开详情兼容投影,包含敲击物图案、背景环境图、主题返回按钮图、敲击音效和飘字配置;统一公开详情主路径通过 `public_work_detail_entry` 消费该 view,只保留平台详情页展示摘要。
|
||||
- 字段变更:`visible` 控制是否进入公开列表 / 详情,默认 `true`;旧迁移数据由 `migration.rs` 补默认值。
|
||||
|
||||
### `match3d_agent_message`
|
||||
|
||||
@@ -472,6 +478,7 @@ npm run check:server-rs-ddd
|
||||
- 返回类型:`Vec<Match3DGalleryViewRow>`
|
||||
- 源码:`server-rs/crates/spacetime-module/src/match3d.rs`
|
||||
- 说明:抓大鹅公开 source 投影,只暴露 `publication_status = published` 的作品卡片字段;统一公开列表 / 详情主路径通过 `public_work_gallery_entry` / `public_work_detail_entry` 消费该 view 并映射成跨玩法契约。个人作品列表、详情、发布、点赞、游玩记录和 Remix 仍按原有 procedure / reducer 路径处理。
|
||||
- 字段变更:`visible` 控制是否进入公开列表 / 详情,默认 `true`;旧迁移数据由 `migration.rs` 补默认值。
|
||||
|
||||
### `npc_state`
|
||||
|
||||
@@ -658,6 +665,7 @@ RPG 创作入口的配置 ID 是 `rpg`,当前 `visible=true`、`open=true`;
|
||||
结构化创作和 RPG 的 LLM JSON 链路默认不启用 Responses `web_search`;只有在明确需要联网增强时,才通过 `GENARRATIVE_RPG_LLM_WEB_SEARCH_ENABLED` 或 `GENARRATIVE_CREATION_AGENT_LLM_WEB_SEARCH_ENABLED` 显式打开。否则未开通工具的上游会先吐自然语言再返回 `ToolNotOpen`,这类失败要按上游工具不可用处理,不要误判成模型返回结果解析失败。
|
||||
|
||||
统一公开作品 BFF 路由是 `GET /api/public-works` 与 `GET /api/public-works/{publicWorkCode}`,响应契约由 `shared-contracts::public_work` 和 `packages/shared/src/contracts/publicWork.ts` 共同维护。前端首期仍走 BFF HTTP,不直接订阅 SpacetimeDB;后续若允许浏览器直连订阅,也只能订阅 `public_work_gallery_entry` / `public_work_detail_entry` 这类稳定公开 read model,不能订阅 `puzzle_work_profile`、`custom_world_profile` 等源表后自行拼装列表。设计细节见 `docs/technical/【后端架构】统一公开作品ReadModel设计-2026-05-26.md`。
|
||||
- 字段变更:`visible` 控制是否进入公开列表 / 详情,默认 `true`;旧迁移数据由 `migration.rs` 补默认值。
|
||||
|
||||
### `quest_log`
|
||||
|
||||
@@ -710,6 +718,7 @@ RPG 创作入口的配置 ID 是 `rpg`,当前 `visible=true`、`open=true`;
|
||||
- 返回类型:`Vec<SquareHoleGalleryViewRow>`
|
||||
- 源码:`server-rs/crates/spacetime-module/src/square_hole.rs`
|
||||
- 说明:方洞挑战公开 source 投影,只暴露 `publication_status = published` 的作品卡片字段;统一公开列表 / 详情主路径通过 `public_work_gallery_entry` / `public_work_detail_entry` 消费该 view 并映射成跨玩法契约。个人作品列表、详情、发布、点赞、游玩记录和 Remix 仍按原有 procedure / reducer 路径处理。
|
||||
- 字段变更:`visible` 控制是否进入公开列表 / 详情,默认 `true`;旧迁移数据由 `migration.rs` 补默认值。
|
||||
|
||||
### `story_event`
|
||||
|
||||
@@ -785,3 +794,4 @@ RPG 创作入口的配置 ID 是 `rpg`,当前 `visible=true`、`open=true`;
|
||||
- 返回类型:`Vec<VisualNovelGalleryViewRow>`
|
||||
- 源码:`server-rs/crates/spacetime-module/src/visual_novel.rs`
|
||||
- 说明:视觉小说公开 source 投影,只暴露 `publication_status = published` 的作品卡片字段,不把完整 `draft` 暴露给公开列表订阅;统一公开列表 / 详情主路径通过 `public_work_gallery_entry` / `public_work_detail_entry` 消费该 view 并映射成跨玩法契约。个人历史、详情、运行态和发布仍按原有 procedure / reducer 路径处理。
|
||||
- 字段变更:`visible` 控制是否进入公开列表 / 详情,默认 `true`;旧迁移数据由 `migration.rs` 补默认值。
|
||||
|
||||
+3
@@ -19,6 +19,7 @@ pub struct BarkBattlePublishedConfigRow {
|
||||
pub created_at: __sdk::Timestamp,
|
||||
pub updated_at: __sdk::Timestamp,
|
||||
pub published_at: __sdk::Timestamp,
|
||||
pub visible: bool,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for BarkBattlePublishedConfigRow {
|
||||
@@ -41,6 +42,7 @@ pub struct BarkBattlePublishedConfigRowCols {
|
||||
pub created_at: __sdk::__query_builder::Col<BarkBattlePublishedConfigRow, __sdk::Timestamp>,
|
||||
pub updated_at: __sdk::__query_builder::Col<BarkBattlePublishedConfigRow, __sdk::Timestamp>,
|
||||
pub published_at: __sdk::__query_builder::Col<BarkBattlePublishedConfigRow, __sdk::Timestamp>,
|
||||
pub visible: __sdk::__query_builder::Col<BarkBattlePublishedConfigRow, bool>,
|
||||
}
|
||||
|
||||
impl __sdk::__query_builder::HasCols for BarkBattlePublishedConfigRow {
|
||||
@@ -65,6 +67,7 @@ impl __sdk::__query_builder::HasCols for BarkBattlePublishedConfigRow {
|
||||
created_at: __sdk::__query_builder::Col::new(table_name, "created_at"),
|
||||
updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"),
|
||||
published_at: __sdk::__query_builder::Col::new(table_name, "published_at"),
|
||||
visible: __sdk::__query_builder::Col::new(table_name, "visible"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
@@ -26,6 +26,7 @@ pub struct BigFishCreationSession {
|
||||
pub remix_count: u32,
|
||||
pub like_count: u32,
|
||||
pub published_at: Option<__sdk::Timestamp>,
|
||||
pub visible: bool,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for BigFishCreationSession {
|
||||
@@ -53,6 +54,7 @@ pub struct BigFishCreationSessionCols {
|
||||
pub remix_count: __sdk::__query_builder::Col<BigFishCreationSession, u32>,
|
||||
pub like_count: __sdk::__query_builder::Col<BigFishCreationSession, u32>,
|
||||
pub published_at: __sdk::__query_builder::Col<BigFishCreationSession, Option<__sdk::Timestamp>>,
|
||||
pub visible: __sdk::__query_builder::Col<BigFishCreationSession, bool>,
|
||||
}
|
||||
|
||||
impl __sdk::__query_builder::HasCols for BigFishCreationSession {
|
||||
@@ -82,6 +84,7 @@ impl __sdk::__query_builder::HasCols for BigFishCreationSession {
|
||||
remix_count: __sdk::__query_builder::Col::new(table_name, "remix_count"),
|
||||
like_count: __sdk::__query_builder::Col::new(table_name, "like_count"),
|
||||
published_at: __sdk::__query_builder::Col::new(table_name, "published_at"),
|
||||
visible: __sdk::__query_builder::Col::new(table_name, "visible"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
@@ -26,6 +26,7 @@ pub struct CustomWorldGalleryEntry {
|
||||
pub like_count: u32,
|
||||
pub published_at: __sdk::Timestamp,
|
||||
pub updated_at: __sdk::Timestamp,
|
||||
pub visible: bool,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for CustomWorldGalleryEntry {
|
||||
@@ -53,6 +54,7 @@ pub struct CustomWorldGalleryEntryCols {
|
||||
pub like_count: __sdk::__query_builder::Col<CustomWorldGalleryEntry, u32>,
|
||||
pub published_at: __sdk::__query_builder::Col<CustomWorldGalleryEntry, __sdk::Timestamp>,
|
||||
pub updated_at: __sdk::__query_builder::Col<CustomWorldGalleryEntry, __sdk::Timestamp>,
|
||||
pub visible: __sdk::__query_builder::Col<CustomWorldGalleryEntry, bool>,
|
||||
}
|
||||
|
||||
impl __sdk::__query_builder::HasCols for CustomWorldGalleryEntry {
|
||||
@@ -82,6 +84,7 @@ impl __sdk::__query_builder::HasCols for CustomWorldGalleryEntry {
|
||||
like_count: __sdk::__query_builder::Col::new(table_name, "like_count"),
|
||||
published_at: __sdk::__query_builder::Col::new(table_name, "published_at"),
|
||||
updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"),
|
||||
visible: __sdk::__query_builder::Col::new(table_name, "visible"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ pub struct CustomWorldProfile {
|
||||
pub deleted_at: Option<__sdk::Timestamp>,
|
||||
pub created_at: __sdk::Timestamp,
|
||||
pub updated_at: __sdk::Timestamp,
|
||||
pub visible: bool,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for CustomWorldProfile {
|
||||
@@ -65,6 +66,7 @@ pub struct CustomWorldProfileCols {
|
||||
pub deleted_at: __sdk::__query_builder::Col<CustomWorldProfile, Option<__sdk::Timestamp>>,
|
||||
pub created_at: __sdk::__query_builder::Col<CustomWorldProfile, __sdk::Timestamp>,
|
||||
pub updated_at: __sdk::__query_builder::Col<CustomWorldProfile, __sdk::Timestamp>,
|
||||
pub visible: __sdk::__query_builder::Col<CustomWorldProfile, bool>,
|
||||
}
|
||||
|
||||
impl __sdk::__query_builder::HasCols for CustomWorldProfile {
|
||||
@@ -105,6 +107,7 @@ impl __sdk::__query_builder::HasCols for CustomWorldProfile {
|
||||
deleted_at: __sdk::__query_builder::Col::new(table_name, "deleted_at"),
|
||||
created_at: __sdk::__query_builder::Col::new(table_name, "created_at"),
|
||||
updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"),
|
||||
visible: __sdk::__query_builder::Col::new(table_name, "visible"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
@@ -31,6 +31,7 @@ pub struct JumpHopWorkProfileRow {
|
||||
pub play_count: u32,
|
||||
pub updated_at: __sdk::Timestamp,
|
||||
pub published_at: Option<__sdk::Timestamp>,
|
||||
pub visible: bool,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for JumpHopWorkProfileRow {
|
||||
@@ -65,6 +66,7 @@ pub struct JumpHopWorkProfileRowCols {
|
||||
pub play_count: __sdk::__query_builder::Col<JumpHopWorkProfileRow, u32>,
|
||||
pub updated_at: __sdk::__query_builder::Col<JumpHopWorkProfileRow, __sdk::Timestamp>,
|
||||
pub published_at: __sdk::__query_builder::Col<JumpHopWorkProfileRow, Option<__sdk::Timestamp>>,
|
||||
pub visible: __sdk::__query_builder::Col<JumpHopWorkProfileRow, bool>,
|
||||
}
|
||||
|
||||
impl __sdk::__query_builder::HasCols for JumpHopWorkProfileRow {
|
||||
@@ -104,6 +106,7 @@ impl __sdk::__query_builder::HasCols for JumpHopWorkProfileRow {
|
||||
play_count: __sdk::__query_builder::Col::new(table_name, "play_count"),
|
||||
updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"),
|
||||
published_at: __sdk::__query_builder::Col::new(table_name, "published_at"),
|
||||
visible: __sdk::__query_builder::Col::new(table_name, "visible"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
@@ -25,6 +25,7 @@ pub struct Match3DWorkProfileRow {
|
||||
pub updated_at: __sdk::Timestamp,
|
||||
pub published_at: Option<__sdk::Timestamp>,
|
||||
pub generated_item_assets_json: Option<String>,
|
||||
pub visible: bool,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for Match3DWorkProfileRow {
|
||||
@@ -54,6 +55,7 @@ pub struct Match3DWorkProfileRowCols {
|
||||
pub published_at: __sdk::__query_builder::Col<Match3DWorkProfileRow, Option<__sdk::Timestamp>>,
|
||||
pub generated_item_assets_json:
|
||||
__sdk::__query_builder::Col<Match3DWorkProfileRow, Option<String>>,
|
||||
pub visible: __sdk::__query_builder::Col<Match3DWorkProfileRow, bool>,
|
||||
}
|
||||
|
||||
impl __sdk::__query_builder::HasCols for Match3DWorkProfileRow {
|
||||
@@ -84,6 +86,7 @@ impl __sdk::__query_builder::HasCols for Match3DWorkProfileRow {
|
||||
table_name,
|
||||
"generated_item_assets_json",
|
||||
),
|
||||
visible: __sdk::__query_builder::Col::new(table_name, "visible"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ pub struct PuzzleWorkProfileRow {
|
||||
pub like_count: u32,
|
||||
pub point_incentive_total_half_points: u64,
|
||||
pub point_incentive_claimed_points: u64,
|
||||
pub visible: bool,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for PuzzleWorkProfileRow {
|
||||
@@ -68,6 +69,7 @@ pub struct PuzzleWorkProfileRowCols {
|
||||
pub like_count: __sdk::__query_builder::Col<PuzzleWorkProfileRow, u32>,
|
||||
pub point_incentive_total_half_points: __sdk::__query_builder::Col<PuzzleWorkProfileRow, u64>,
|
||||
pub point_incentive_claimed_points: __sdk::__query_builder::Col<PuzzleWorkProfileRow, u64>,
|
||||
pub visible: __sdk::__query_builder::Col<PuzzleWorkProfileRow, bool>,
|
||||
}
|
||||
|
||||
impl __sdk::__query_builder::HasCols for PuzzleWorkProfileRow {
|
||||
@@ -107,6 +109,7 @@ impl __sdk::__query_builder::HasCols for PuzzleWorkProfileRow {
|
||||
table_name,
|
||||
"point_incentive_claimed_points",
|
||||
),
|
||||
visible: __sdk::__query_builder::Col::new(table_name, "visible"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
@@ -25,6 +25,7 @@ pub struct SquareHoleWorkProfileRow {
|
||||
pub play_count: u32,
|
||||
pub updated_at: __sdk::Timestamp,
|
||||
pub published_at: Option<__sdk::Timestamp>,
|
||||
pub visible: bool,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for SquareHoleWorkProfileRow {
|
||||
@@ -54,6 +55,7 @@ pub struct SquareHoleWorkProfileRowCols {
|
||||
pub updated_at: __sdk::__query_builder::Col<SquareHoleWorkProfileRow, __sdk::Timestamp>,
|
||||
pub published_at:
|
||||
__sdk::__query_builder::Col<SquareHoleWorkProfileRow, Option<__sdk::Timestamp>>,
|
||||
pub visible: __sdk::__query_builder::Col<SquareHoleWorkProfileRow, bool>,
|
||||
}
|
||||
|
||||
impl __sdk::__query_builder::HasCols for SquareHoleWorkProfileRow {
|
||||
@@ -81,6 +83,7 @@ impl __sdk::__query_builder::HasCols for SquareHoleWorkProfileRow {
|
||||
play_count: __sdk::__query_builder::Col::new(table_name, "play_count"),
|
||||
updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"),
|
||||
published_at: __sdk::__query_builder::Col::new(table_name, "published_at"),
|
||||
visible: __sdk::__query_builder::Col::new(table_name, "visible"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
@@ -24,6 +24,7 @@ pub struct VisualNovelWorkProfileRow {
|
||||
pub created_at: __sdk::Timestamp,
|
||||
pub updated_at: __sdk::Timestamp,
|
||||
pub published_at: Option<__sdk::Timestamp>,
|
||||
pub visible: bool,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for VisualNovelWorkProfileRow {
|
||||
@@ -52,6 +53,7 @@ pub struct VisualNovelWorkProfileRowCols {
|
||||
pub updated_at: __sdk::__query_builder::Col<VisualNovelWorkProfileRow, __sdk::Timestamp>,
|
||||
pub published_at:
|
||||
__sdk::__query_builder::Col<VisualNovelWorkProfileRow, Option<__sdk::Timestamp>>,
|
||||
pub visible: __sdk::__query_builder::Col<VisualNovelWorkProfileRow, bool>,
|
||||
}
|
||||
|
||||
impl __sdk::__query_builder::HasCols for VisualNovelWorkProfileRow {
|
||||
@@ -81,6 +83,7 @@ impl __sdk::__query_builder::HasCols for VisualNovelWorkProfileRow {
|
||||
created_at: __sdk::__query_builder::Col::new(table_name, "created_at"),
|
||||
updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"),
|
||||
published_at: __sdk::__query_builder::Col::new(table_name, "published_at"),
|
||||
visible: __sdk::__query_builder::Col::new(table_name, "visible"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
@@ -29,6 +29,7 @@ pub struct WoodenFishWorkProfileRow {
|
||||
pub published_at: Option<__sdk::Timestamp>,
|
||||
pub background_asset_json: Option<String>,
|
||||
pub back_button_asset_json: Option<String>,
|
||||
pub visible: bool,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for WoodenFishWorkProfileRow {
|
||||
@@ -65,6 +66,7 @@ pub struct WoodenFishWorkProfileRowCols {
|
||||
__sdk::__query_builder::Col<WoodenFishWorkProfileRow, Option<String>>,
|
||||
pub back_button_asset_json:
|
||||
__sdk::__query_builder::Col<WoodenFishWorkProfileRow, Option<String>>,
|
||||
pub visible: __sdk::__query_builder::Col<WoodenFishWorkProfileRow, bool>,
|
||||
}
|
||||
|
||||
impl __sdk::__query_builder::HasCols for WoodenFishWorkProfileRow {
|
||||
@@ -114,6 +116,7 @@ impl __sdk::__query_builder::HasCols for WoodenFishWorkProfileRow {
|
||||
table_name,
|
||||
"back_button_asset_json",
|
||||
),
|
||||
visible: __sdk::__query_builder::Col::new(table_name, "visible"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ pub fn bark_battle_gallery_view(ctx: &AnonymousViewContext) -> Vec<BarkBattleGal
|
||||
.bark_battle_published_config()
|
||||
.by_bark_battle_published_owner_user_id()
|
||||
.filter(""..)
|
||||
.filter(|row| row.visible)
|
||||
.filter_map(|row| match build_bark_battle_gallery_view_row(ctx, &row) {
|
||||
Ok(item) => Some(item),
|
||||
Err(error) => {
|
||||
@@ -260,6 +261,7 @@ fn publish_bark_battle_work_tx(
|
||||
created_at: published_at,
|
||||
updated_at: published_at,
|
||||
published_at,
|
||||
visible: true,
|
||||
};
|
||||
let mut published = published;
|
||||
match ctx
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use crate::*;
|
||||
|
||||
const WORK_VISIBLE_DEFAULT: bool = true;
|
||||
|
||||
#[spacetimedb::table(
|
||||
accessor = bark_battle_draft_config,
|
||||
index(accessor = by_bark_battle_draft_owner_user_id, btree(columns = [owner_user_id])),
|
||||
@@ -40,6 +42,9 @@ pub struct BarkBattlePublishedConfigRow {
|
||||
pub(crate) created_at: Timestamp,
|
||||
pub(crate) updated_at: Timestamp,
|
||||
pub(crate) published_at: Timestamp,
|
||||
// ???????????????????????????????
|
||||
#[default(WORK_VISIBLE_DEFAULT)]
|
||||
pub(crate) visible: bool,
|
||||
}
|
||||
|
||||
#[spacetimedb::table(
|
||||
|
||||
@@ -129,6 +129,7 @@ pub(crate) fn generate_big_fish_asset_tx(
|
||||
published_at: session.published_at,
|
||||
created_at: session.created_at,
|
||||
updated_at,
|
||||
visible: session.visible,
|
||||
};
|
||||
replace_big_fish_session(ctx, &session, next_session);
|
||||
for event in readiness.events {
|
||||
@@ -200,6 +201,7 @@ pub(crate) fn publish_big_fish_game_tx(
|
||||
published_at: Some(published_at),
|
||||
created_at: session.created_at,
|
||||
updated_at: published_at,
|
||||
visible: session.visible,
|
||||
};
|
||||
replace_big_fish_session(ctx, &session, next_session);
|
||||
for event in readiness.events {
|
||||
|
||||
@@ -23,6 +23,7 @@ pub fn big_fish_gallery_view(ctx: &AnonymousViewContext) -> Vec<BigFishWorkSumma
|
||||
.big_fish_creation_session()
|
||||
.by_big_fish_session_stage()
|
||||
.filter(BigFishCreationStage::Published)
|
||||
.filter(|row| row.visible)
|
||||
.filter_map(|row| match build_big_fish_gallery_view_row(ctx, &row) {
|
||||
Ok(snapshot) => Some(snapshot),
|
||||
Err(error) => {
|
||||
@@ -284,6 +285,7 @@ pub(crate) fn create_big_fish_session_tx(
|
||||
published_at: None,
|
||||
created_at,
|
||||
updated_at: created_at,
|
||||
visible: true,
|
||||
});
|
||||
ctx.db.big_fish_agent_message().insert(BigFishAgentMessage {
|
||||
message_id: input.welcome_message_id,
|
||||
@@ -492,6 +494,7 @@ pub(crate) fn submit_big_fish_message_tx(
|
||||
published_at: session.published_at,
|
||||
created_at: session.created_at,
|
||||
updated_at: submitted_at,
|
||||
visible: session.visible,
|
||||
};
|
||||
replace_big_fish_session(ctx, &session, next_session);
|
||||
|
||||
@@ -542,6 +545,7 @@ pub(crate) fn finalize_big_fish_agent_message_turn_tx(
|
||||
published_at: session.published_at,
|
||||
created_at: session.created_at,
|
||||
updated_at,
|
||||
visible: session.visible,
|
||||
};
|
||||
replace_big_fish_session(ctx, &session, next_session);
|
||||
return Err(error_message.to_string());
|
||||
@@ -600,6 +604,7 @@ pub(crate) fn finalize_big_fish_agent_message_turn_tx(
|
||||
published_at: session.published_at,
|
||||
created_at: session.created_at,
|
||||
updated_at,
|
||||
visible: session.visible,
|
||||
};
|
||||
replace_big_fish_session(ctx, &session, next_session);
|
||||
|
||||
@@ -667,6 +672,7 @@ pub(crate) fn compile_big_fish_draft_tx(
|
||||
published_at: session.published_at,
|
||||
created_at: session.created_at,
|
||||
updated_at: compiled_at,
|
||||
visible: session.visible,
|
||||
};
|
||||
replace_big_fish_session(ctx, &session, next_session);
|
||||
for event in readiness.events {
|
||||
@@ -768,6 +774,7 @@ pub(crate) fn record_big_fish_play_tx(
|
||||
published_at: session.published_at,
|
||||
created_at: session.created_at,
|
||||
updated_at: played_at,
|
||||
visible: session.visible,
|
||||
};
|
||||
replace_big_fish_session(ctx, &session, next_session);
|
||||
|
||||
@@ -821,6 +828,7 @@ pub(crate) fn record_big_fish_like_tx(
|
||||
published_at: session.published_at,
|
||||
created_at: session.created_at,
|
||||
updated_at: liked_at,
|
||||
visible: session.visible,
|
||||
};
|
||||
replace_big_fish_session(ctx, &session, next_session);
|
||||
}
|
||||
@@ -888,6 +896,7 @@ fn remix_big_fish_work_tx(
|
||||
published_at: source.published_at,
|
||||
created_at: source.created_at,
|
||||
updated_at: remixed_at,
|
||||
visible: source.visible,
|
||||
};
|
||||
replace_big_fish_session(ctx, &source, next_source);
|
||||
|
||||
@@ -909,6 +918,7 @@ fn remix_big_fish_work_tx(
|
||||
published_at: None,
|
||||
created_at: remixed_at,
|
||||
updated_at: remixed_at,
|
||||
visible: true,
|
||||
};
|
||||
ctx.db.big_fish_creation_session().insert(target_session);
|
||||
ctx.db.big_fish_agent_message().insert(BigFishAgentMessage {
|
||||
@@ -1238,6 +1248,7 @@ mod tests {
|
||||
},
|
||||
created_at: Timestamp::from_micros_since_unix_epoch(1),
|
||||
updated_at: Timestamp::from_micros_since_unix_epoch(1),
|
||||
visible: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use crate::*;
|
||||
|
||||
const WORK_VISIBLE_DEFAULT: bool = true;
|
||||
|
||||
#[spacetimedb::table(
|
||||
accessor = big_fish_creation_session,
|
||||
index(accessor = by_big_fish_session_owner_user_id, btree(columns = [owner_user_id])),
|
||||
@@ -28,6 +30,9 @@ pub struct BigFishCreationSession {
|
||||
pub(crate) like_count: u32,
|
||||
#[default(None::<Timestamp>)]
|
||||
pub(crate) published_at: Option<Timestamp>,
|
||||
// ???????????????????????????????
|
||||
#[default(WORK_VISIBLE_DEFAULT)]
|
||||
pub(crate) visible: bool,
|
||||
}
|
||||
|
||||
#[spacetimedb::table(
|
||||
|
||||
@@ -2,6 +2,8 @@ use crate::*;
|
||||
use spacetimedb::AnonymousViewContext;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
const WORK_VISIBLE_DEFAULT: bool = true;
|
||||
|
||||
#[spacetimedb::table(
|
||||
accessor = custom_world_profile,
|
||||
index(accessor = by_custom_world_profile_owner_user_id, btree(columns = [owner_user_id])),
|
||||
@@ -42,6 +44,9 @@ pub struct CustomWorldProfile {
|
||||
deleted_at: Option<Timestamp>,
|
||||
created_at: Timestamp,
|
||||
updated_at: Timestamp,
|
||||
// ??????????????????????????
|
||||
#[default(WORK_VISIBLE_DEFAULT)]
|
||||
visible: bool,
|
||||
}
|
||||
|
||||
#[spacetimedb::table(
|
||||
@@ -192,6 +197,9 @@ pub struct CustomWorldGalleryEntry {
|
||||
like_count: u32,
|
||||
published_at: Timestamp,
|
||||
updated_at: Timestamp,
|
||||
// ??????????????????????????
|
||||
#[default(WORK_VISIBLE_DEFAULT)]
|
||||
visible: bool,
|
||||
}
|
||||
// Agent 会话首版只负责把可持久化创作状态落进 SpacetimeDB,LLM 采集与卡片生成后续再接入。
|
||||
#[spacetimedb::procedure]
|
||||
@@ -1229,6 +1237,7 @@ fn upsert_custom_world_profile_record(
|
||||
deleted_at: None,
|
||||
created_at: existing.created_at,
|
||||
updated_at,
|
||||
visible: existing.visible,
|
||||
}
|
||||
}
|
||||
None => CustomWorldProfile {
|
||||
@@ -1254,6 +1263,7 @@ fn upsert_custom_world_profile_record(
|
||||
deleted_at: None,
|
||||
created_at: updated_at,
|
||||
updated_at,
|
||||
visible: true,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1401,6 +1411,7 @@ fn publish_custom_world_profile_record(
|
||||
deleted_at: None,
|
||||
created_at: existing.created_at,
|
||||
updated_at: published_at,
|
||||
visible: existing.visible,
|
||||
};
|
||||
|
||||
let inserted = ctx.db.custom_world_profile().insert(next_row);
|
||||
@@ -1467,6 +1478,7 @@ fn unpublish_custom_world_profile_record(
|
||||
deleted_at: None,
|
||||
created_at: existing.created_at,
|
||||
updated_at,
|
||||
visible: existing.visible,
|
||||
};
|
||||
|
||||
let inserted = ctx.db.custom_world_profile().insert(next_row);
|
||||
@@ -1529,6 +1541,7 @@ fn delete_custom_world_profile_record(
|
||||
deleted_at: Some(deleted_at),
|
||||
created_at: existing.created_at,
|
||||
updated_at: deleted_at,
|
||||
visible: existing.visible,
|
||||
};
|
||||
|
||||
let _ = ctx.db.custom_world_profile().insert(next_row);
|
||||
@@ -1651,6 +1664,7 @@ fn get_custom_world_gallery_detail_record(
|
||||
row.owner_user_id == input.owner_user_id
|
||||
&& row.publication_status == CustomWorldPublicationStatus::Published
|
||||
&& row.deleted_at.is_none()
|
||||
&& row.visible
|
||||
});
|
||||
|
||||
let gallery_entry = ctx
|
||||
@@ -1745,6 +1759,7 @@ fn remix_custom_world_profile_record(
|
||||
.filter(|row| {
|
||||
row.publication_status == CustomWorldPublicationStatus::Published
|
||||
&& row.deleted_at.is_none()
|
||||
&& row.visible
|
||||
&& row.published_at.is_some()
|
||||
})
|
||||
.ok_or_else(|| "custom_world 已发布源作品不存在,无法改编".to_string())?;
|
||||
@@ -1777,6 +1792,7 @@ fn remix_custom_world_profile_record(
|
||||
deleted_at: source.deleted_at,
|
||||
created_at: source.created_at,
|
||||
updated_at: remixed_at,
|
||||
visible: source.visible,
|
||||
};
|
||||
let updated_source = ctx.db.custom_world_profile().insert(next_source);
|
||||
let source_gallery = sync_custom_world_gallery_entry_from_profile(ctx, &updated_source)?;
|
||||
@@ -1805,6 +1821,7 @@ fn remix_custom_world_profile_record(
|
||||
deleted_at: None,
|
||||
created_at: remixed_at,
|
||||
updated_at: remixed_at,
|
||||
visible: true,
|
||||
};
|
||||
|
||||
if let Some(existing_target) = ctx
|
||||
@@ -1845,6 +1862,7 @@ fn record_custom_world_profile_play_record(
|
||||
.filter(|row| {
|
||||
row.publication_status == CustomWorldPublicationStatus::Published
|
||||
&& row.deleted_at.is_none()
|
||||
&& row.visible
|
||||
&& row.published_at.is_some()
|
||||
})
|
||||
.ok_or_else(|| "custom_world 已发布作品不存在,无法记录游玩".to_string())?;
|
||||
@@ -1887,6 +1905,7 @@ fn record_custom_world_profile_play_record(
|
||||
deleted_at: existing.deleted_at,
|
||||
created_at: existing.created_at,
|
||||
updated_at: played_at,
|
||||
visible: existing.visible,
|
||||
};
|
||||
let inserted = ctx.db.custom_world_profile().insert(next_row);
|
||||
let gallery_entry = sync_custom_world_gallery_entry_from_profile(ctx, &inserted)?;
|
||||
@@ -1916,6 +1935,7 @@ fn record_custom_world_profile_like_record(
|
||||
.filter(|row| {
|
||||
row.publication_status == CustomWorldPublicationStatus::Published
|
||||
&& row.deleted_at.is_none()
|
||||
&& row.visible
|
||||
&& row.published_at.is_some()
|
||||
})
|
||||
.ok_or_else(|| "custom_world 已发布作品不存在,无法点赞".to_string())?;
|
||||
@@ -1967,6 +1987,7 @@ fn record_custom_world_profile_like_record(
|
||||
deleted_at: existing.deleted_at,
|
||||
created_at: existing.created_at,
|
||||
updated_at: liked_at,
|
||||
visible: existing.visible,
|
||||
};
|
||||
let inserted = ctx.db.custom_world_profile().insert(next_row);
|
||||
let gallery_entry = sync_custom_world_gallery_entry_from_profile(ctx, &inserted)?;
|
||||
@@ -2582,6 +2603,7 @@ fn is_same_agent_draft_profile_candidate(
|
||||
) -> bool {
|
||||
row.owner_user_id == owner_user_id
|
||||
&& row.deleted_at.is_none()
|
||||
&& row.visible
|
||||
&& row.publication_status == CustomWorldPublicationStatus::Draft
|
||||
&& row.source_agent_session_id.as_deref() == Some(source_agent_session_id)
|
||||
}
|
||||
@@ -4841,6 +4863,7 @@ fn sync_custom_world_gallery_entry_from_profile(
|
||||
like_count: profile.like_count,
|
||||
published_at,
|
||||
updated_at: profile.updated_at,
|
||||
visible: profile.visible,
|
||||
};
|
||||
|
||||
let inserted = ctx.db.custom_world_gallery_entry().insert(row);
|
||||
@@ -4854,7 +4877,7 @@ fn sync_missing_custom_world_gallery_entries(ctx: &ReducerContext) -> Result<(),
|
||||
.custom_world_profile()
|
||||
.by_custom_world_profile_publication_status()
|
||||
.filter(CustomWorldPublicationStatus::Published)
|
||||
.filter(|profile| profile.deleted_at.is_none())
|
||||
.filter(|profile| profile.deleted_at.is_none() && profile.visible)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for profile in published_profiles {
|
||||
@@ -4926,6 +4949,7 @@ fn ensure_custom_world_profile_public_fields(
|
||||
deleted_at: profile.deleted_at,
|
||||
created_at: profile.created_at,
|
||||
updated_at: profile.updated_at,
|
||||
visible: profile.visible,
|
||||
};
|
||||
|
||||
ctx.db.custom_world_profile().insert(next_row)
|
||||
@@ -4955,6 +4979,7 @@ fn build_custom_world_profile_row_copy(profile: &CustomWorldProfile) -> CustomWo
|
||||
deleted_at: profile.deleted_at,
|
||||
created_at: profile.created_at,
|
||||
updated_at: profile.updated_at,
|
||||
visible: profile.visible,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4997,7 +5022,7 @@ pub(crate) fn custom_world_public_profile_snapshots(
|
||||
.custom_world_profile()
|
||||
.by_custom_world_profile_publication_status()
|
||||
.filter(CustomWorldPublicationStatus::Published)
|
||||
.filter(|row| row.deleted_at.is_none())
|
||||
.filter(|row| row.deleted_at.is_none() && row.visible)
|
||||
.map(|row| build_custom_world_profile_snapshot(&row))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@@ -5156,6 +5181,7 @@ pub(crate) fn custom_world_public_gallery_snapshots(
|
||||
.custom_world_gallery_entry()
|
||||
.by_custom_world_gallery_owner_user_id()
|
||||
.filter(""..)
|
||||
.filter(|row| row.visible)
|
||||
.map(|row| {
|
||||
build_custom_world_gallery_entry_snapshot_with_recent_counts(&row, &HashMap::new())
|
||||
})
|
||||
@@ -5377,6 +5403,7 @@ mod tests {
|
||||
deleted_at: None,
|
||||
created_at: Timestamp::from_micros_since_unix_epoch(1),
|
||||
updated_at: Timestamp::from_micros_since_unix_epoch(1),
|
||||
visible: true,
|
||||
};
|
||||
let deleted = CustomWorldProfile {
|
||||
profile_id: "profile-1".to_string(),
|
||||
@@ -5401,6 +5428,7 @@ mod tests {
|
||||
deleted_at: Some(Timestamp::from_micros_since_unix_epoch(2)),
|
||||
created_at: Timestamp::from_micros_since_unix_epoch(1),
|
||||
updated_at: Timestamp::from_micros_since_unix_epoch(1),
|
||||
visible: true,
|
||||
};
|
||||
let published = CustomWorldProfile {
|
||||
profile_id: "profile-1".to_string(),
|
||||
@@ -5425,6 +5453,7 @@ mod tests {
|
||||
deleted_at: None,
|
||||
created_at: Timestamp::from_micros_since_unix_epoch(1),
|
||||
updated_at: Timestamp::from_micros_since_unix_epoch(1),
|
||||
visible: true,
|
||||
};
|
||||
|
||||
assert!(is_same_agent_draft_profile_candidate(
|
||||
@@ -5552,6 +5581,7 @@ mod tests {
|
||||
deleted_at: None,
|
||||
created_at: Timestamp::from_micros_since_unix_epoch(1),
|
||||
updated_at: Timestamp::from_micros_since_unix_epoch(1),
|
||||
visible: true,
|
||||
};
|
||||
let mut active_agent_session_ids = HashSet::new();
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ pub fn jump_hop_gallery_view(ctx: &AnonymousViewContext) -> Vec<JumpHopGalleryVi
|
||||
.jump_hop_work_profile()
|
||||
.by_jump_hop_work_publication_status()
|
||||
.filter(JUMP_HOP_PUBLICATION_PUBLISHED)
|
||||
.filter(|row| row.visible)
|
||||
.filter_map(|row| match build_gallery_view_row(&row) {
|
||||
Ok(item) => Some(item),
|
||||
Err(error) => {
|
||||
@@ -401,6 +402,7 @@ fn compile_jump_hop_draft_tx(
|
||||
play_count: 0,
|
||||
updated_at: compiled_at,
|
||||
published_at: None,
|
||||
visible: true,
|
||||
};
|
||||
upsert_work(ctx, row);
|
||||
replace_session(
|
||||
@@ -1163,6 +1165,7 @@ fn clone_work(row: &JumpHopWorkProfileRow) -> JumpHopWorkProfileRow {
|
||||
play_count: row.play_count,
|
||||
updated_at: row.updated_at,
|
||||
published_at: row.published_at,
|
||||
visible: row.visible,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use crate::*;
|
||||
|
||||
const WORK_VISIBLE_DEFAULT: bool = true;
|
||||
|
||||
#[spacetimedb::table(
|
||||
accessor = jump_hop_agent_session,
|
||||
index(accessor = by_jump_hop_agent_session_owner_user_id, btree(columns = [owner_user_id]))
|
||||
@@ -51,6 +53,9 @@ pub struct JumpHopWorkProfileRow {
|
||||
pub(crate) play_count: u32,
|
||||
pub(crate) updated_at: Timestamp,
|
||||
pub(crate) published_at: Option<Timestamp>,
|
||||
// ???????????????????????????????
|
||||
#[default(WORK_VISIBLE_DEFAULT)]
|
||||
pub(crate) visible: bool,
|
||||
}
|
||||
|
||||
#[spacetimedb::table(
|
||||
|
||||
@@ -32,6 +32,7 @@ pub fn match3d_gallery_view(ctx: &AnonymousViewContext) -> Vec<Match3DGalleryVie
|
||||
.match3d_work_profile()
|
||||
.by_match3d_work_publication_status()
|
||||
.filter(MATCH3D_PUBLICATION_PUBLISHED)
|
||||
.filter(|row| row.visible)
|
||||
.filter_map(|row| match build_gallery_view_row(&row) {
|
||||
Ok(item) => Some(item),
|
||||
Err(error) => {
|
||||
@@ -571,6 +572,7 @@ fn compile_match3d_draft_tx(
|
||||
updated_at: compiled_at,
|
||||
published_at: previous_published_at,
|
||||
generated_item_assets_json,
|
||||
visible: true,
|
||||
};
|
||||
upsert_work(ctx, work);
|
||||
replace_session(
|
||||
@@ -643,6 +645,7 @@ fn build_updated_match3d_work_row(
|
||||
updated_at,
|
||||
published_at: current.published_at,
|
||||
generated_item_assets_json: current.generated_item_assets_json.clone(),
|
||||
visible: current.visible,
|
||||
};
|
||||
Ok(next)
|
||||
}
|
||||
@@ -1330,6 +1333,7 @@ fn clone_work(row: &Match3DWorkProfileRow) -> Match3DWorkProfileRow {
|
||||
updated_at: row.updated_at,
|
||||
published_at: row.published_at,
|
||||
generated_item_assets_json: row.generated_item_assets_json.clone(),
|
||||
visible: row.visible,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1885,6 +1889,7 @@ mod tests {
|
||||
updated_at: Timestamp::from_micros_since_unix_epoch(1),
|
||||
published_at: None,
|
||||
generated_item_assets_json: None,
|
||||
visible: true,
|
||||
};
|
||||
let snapshot = build_initial_run_snapshot("run-1", &work, 10, None);
|
||||
assert_eq!(snapshot.total_item_count, 12);
|
||||
@@ -1924,6 +1929,7 @@ mod tests {
|
||||
r#"[{"itemId":"match3d-item-1","itemName":"草莓","imageSrc":"/generated-match3d-assets/session/profile/items/item/image.png","status":"image_ready"}]"#
|
||||
.to_string(),
|
||||
),
|
||||
visible: true,
|
||||
};
|
||||
|
||||
let snapshot = build_work_snapshot(&work).expect("work snapshot should build");
|
||||
@@ -1969,6 +1975,7 @@ mod tests {
|
||||
r#"[{"itemId":"match3d-item-1","itemName":"草莓","imageSrc":"/generated-match3d-assets/session/profile/items/item/image.png","status":"image_ready"}]"#
|
||||
.to_string(),
|
||||
),
|
||||
visible: true,
|
||||
};
|
||||
|
||||
let preserved =
|
||||
@@ -2038,6 +2045,7 @@ mod tests {
|
||||
r#"[{"itemId":"match3d-item-1","itemName":"草莓","imageSrc":"/generated-match3d-assets/session/profile/items/item/image.png","status":"image_ready"}]"#
|
||||
.to_string(),
|
||||
),
|
||||
visible: true,
|
||||
};
|
||||
let input = Match3DWorkUpdateInput {
|
||||
profile_id: existing.profile_id.clone(),
|
||||
@@ -2097,6 +2105,7 @@ mod tests {
|
||||
r#"[{"itemId":"match3d-item-1","itemName":"草莓","imageSrc":"/generated-match3d-assets/session/profile/items/item/image.png","status":"image_ready"},{"itemId":"match3d-item-2","itemName":"苹果","imageViews":[{"imageSrc":"/v1.png"},{"imageSrc":"/v2.png"},{"imageSrc":"/v3.png"},{"imageSrc":"/v4.png"},{"imageSrc":"/v5.png"}],"status":"model_ready"},{"itemId":"match3d-item-3","itemName":"香蕉","imageViews":[{"imageSrc":"/v1.png"},{"imageSrc":"/v2.png"},{"imageSrc":"/v3.png"},{"imageSrc":"/v4.png"}],"status":"image_ready"}]"#
|
||||
.to_string(),
|
||||
),
|
||||
visible: true,
|
||||
};
|
||||
|
||||
let error = validate_publishable_work(&base_work).unwrap_err();
|
||||
@@ -2156,6 +2165,7 @@ mod tests {
|
||||
updated_at: Timestamp::from_micros_since_unix_epoch(1),
|
||||
published_at: None,
|
||||
generated_item_assets_json: None,
|
||||
visible: true,
|
||||
};
|
||||
|
||||
let input_game_name = None;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use crate::*;
|
||||
|
||||
const WORK_VISIBLE_DEFAULT: bool = true;
|
||||
|
||||
#[spacetimedb::table(
|
||||
accessor = match3d_agent_session,
|
||||
index(accessor = by_match3d_agent_session_owner_user_id, btree(columns = [owner_user_id]))
|
||||
@@ -60,6 +62,9 @@ pub struct Match3DWorkProfileRow {
|
||||
pub(crate) published_at: Option<Timestamp>,
|
||||
#[default(None::<String>)]
|
||||
pub(crate) generated_item_assets_json: Option<String>,
|
||||
// ???????????????????????????????
|
||||
#[default(WORK_VISIBLE_DEFAULT)]
|
||||
pub(crate) visible: bool,
|
||||
}
|
||||
|
||||
#[spacetimedb::table(
|
||||
|
||||
@@ -1257,6 +1257,10 @@ fn normalize_migration_row(table_name: &str, value: &serde_json::Value) -> serde
|
||||
}
|
||||
if table_name == "puzzle_work_profile" {
|
||||
if let Some(object) = next_value.as_object_mut() {
|
||||
// ???????????????????????????????
|
||||
object
|
||||
.entry("visible".to_string())
|
||||
.or_insert_with(|| serde_json::Value::Bool(true));
|
||||
// 中文注释:拼图公开互动计数晚于基础作品表加入,旧迁移包按 0 兼容。
|
||||
object
|
||||
.entry("play_count".to_string())
|
||||
@@ -1294,8 +1298,26 @@ fn normalize_migration_row(table_name: &str, value: &serde_json::Value) -> serde
|
||||
.or_insert(fallback_description);
|
||||
}
|
||||
}
|
||||
if matches!(
|
||||
table_name,
|
||||
"jump_hop_work_profile"
|
||||
| "square_hole_work_profile"
|
||||
| "visual_novel_work_profile"
|
||||
| "bark_battle_published_config"
|
||||
) {
|
||||
if let Some(object) = next_value.as_object_mut() {
|
||||
// ???????????????????????????????
|
||||
object
|
||||
.entry("visible".to_string())
|
||||
.or_insert_with(|| serde_json::Value::Bool(true));
|
||||
}
|
||||
}
|
||||
if table_name == "match3d_work_profile" {
|
||||
if let Some(object) = next_value.as_object_mut() {
|
||||
// ???????????????????????????????
|
||||
object
|
||||
.entry("visible".to_string())
|
||||
.or_insert_with(|| serde_json::Value::Bool(true));
|
||||
// 中文注释:抓大鹅生成素材字段晚于基础作品表加入,旧迁移包按未生成素材兼容。
|
||||
object
|
||||
.entry("generated_item_assets_json".to_string())
|
||||
@@ -1304,6 +1326,10 @@ fn normalize_migration_row(table_name: &str, value: &serde_json::Value) -> serde
|
||||
}
|
||||
if table_name == "wooden_fish_work_profile" {
|
||||
if let Some(object) = next_value.as_object_mut() {
|
||||
// ???????????????????????????????
|
||||
object
|
||||
.entry("visible".to_string())
|
||||
.or_insert_with(|| serde_json::Value::Bool(true));
|
||||
// 中文注释:敲木鱼背景环境图晚于首版作品表加入,旧迁移包按未生成背景兼容。
|
||||
object
|
||||
.entry("background_asset_json".to_string())
|
||||
|
||||
@@ -38,6 +38,7 @@ use spacetimedb::{
|
||||
use crate::auth::user_account;
|
||||
|
||||
const PUZZLE_POINT_INCENTIVE_DEFAULT_U64: u64 = 0;
|
||||
const WORK_VISIBLE_DEFAULT: bool = true;
|
||||
|
||||
/// 拼图 Agent session 真相表。
|
||||
/// 当前只保存结构化字段与 JSON 草稿,不提前拆出更多编辑态子表。
|
||||
@@ -112,6 +113,9 @@ pub struct PuzzleWorkProfileRow {
|
||||
point_incentive_total_half_points: u64,
|
||||
#[default(PUZZLE_POINT_INCENTIVE_DEFAULT_U64)]
|
||||
point_incentive_claimed_points: u64,
|
||||
// ???????????????????????????????
|
||||
#[default(WORK_VISIBLE_DEFAULT)]
|
||||
visible: bool,
|
||||
}
|
||||
|
||||
/// 拼图广场公开详情兼容投影。
|
||||
@@ -125,6 +129,7 @@ pub fn puzzle_gallery_view(ctx: &AnonymousViewContext) -> Vec<PuzzleWorkProfile>
|
||||
.puzzle_work_profile()
|
||||
.by_puzzle_work_publication_status()
|
||||
.filter(PuzzlePublicationStatus::Published)
|
||||
.filter(|row| row.visible)
|
||||
.filter_map(
|
||||
|row| match build_puzzle_work_profile_from_row_without_recent_count(&row) {
|
||||
Ok(profile) => Some(profile),
|
||||
@@ -154,6 +159,7 @@ pub fn puzzle_gallery_card_view(ctx: &AnonymousViewContext) -> Vec<PuzzleGallery
|
||||
.puzzle_work_profile()
|
||||
.by_puzzle_work_publication_status()
|
||||
.filter(PuzzlePublicationStatus::Published)
|
||||
.filter(|row| row.visible)
|
||||
.filter_map(|row| match build_puzzle_gallery_card_view_row(&row) {
|
||||
Ok(item) => Some(item),
|
||||
Err(error) => {
|
||||
@@ -1578,6 +1584,7 @@ fn update_puzzle_work_tx(
|
||||
created_at: row.created_at,
|
||||
updated_at: Timestamp::from_micros_since_unix_epoch(input.updated_at_micros),
|
||||
published_at: row.published_at,
|
||||
visible: row.visible,
|
||||
};
|
||||
replace_puzzle_work_profile(ctx, &row, next_row);
|
||||
sync_puzzle_source_session_draft_from_work(ctx, &row, &preview_draft, input.updated_at_micros)?;
|
||||
@@ -1790,6 +1797,7 @@ fn record_puzzle_work_like_tx(
|
||||
created_at: row.created_at,
|
||||
updated_at: liked_at,
|
||||
published_at: row.published_at,
|
||||
visible: row.visible,
|
||||
};
|
||||
replace_puzzle_work_profile(ctx, &row, next_row);
|
||||
ctx.db
|
||||
@@ -1878,6 +1886,7 @@ fn remix_puzzle_work_tx(
|
||||
created_at: source.created_at,
|
||||
updated_at: remixed_at,
|
||||
published_at: source.published_at,
|
||||
visible: source.visible,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1945,6 +1954,7 @@ fn remix_puzzle_work_tx(
|
||||
created_at: remixed_at,
|
||||
updated_at: remixed_at,
|
||||
published_at: None,
|
||||
visible: true,
|
||||
});
|
||||
|
||||
get_puzzle_agent_session_tx(
|
||||
@@ -2396,6 +2406,7 @@ fn claim_puzzle_work_point_incentive_tx(
|
||||
created_at: row.created_at,
|
||||
updated_at: claimed_at,
|
||||
published_at: row.published_at,
|
||||
visible: row.visible,
|
||||
};
|
||||
replace_puzzle_work_profile(ctx, &row, next_row);
|
||||
|
||||
@@ -3008,6 +3019,7 @@ fn upsert_puzzle_work_profile(ctx: &TxContext, profile: PuzzleWorkProfile) -> Re
|
||||
published_at: profile
|
||||
.published_at_micros
|
||||
.map(Timestamp::from_micros_since_unix_epoch),
|
||||
visible: existing.visible,
|
||||
},
|
||||
);
|
||||
return Ok(());
|
||||
@@ -3040,6 +3052,7 @@ fn upsert_puzzle_work_profile(ctx: &TxContext, profile: PuzzleWorkProfile) -> Re
|
||||
published_at: profile
|
||||
.published_at_micros
|
||||
.map(Timestamp::from_micros_since_unix_epoch),
|
||||
visible: true,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
@@ -3364,6 +3377,7 @@ fn accrue_puzzle_point_incentive(
|
||||
created_at: row.created_at,
|
||||
updated_at: Timestamp::from_micros_since_unix_epoch(updated_at_micros),
|
||||
published_at: row.published_at,
|
||||
visible: row.visible,
|
||||
},
|
||||
);
|
||||
Ok(())
|
||||
@@ -3402,6 +3416,7 @@ fn increment_puzzle_profile_play_count(
|
||||
created_at: row.created_at,
|
||||
updated_at: Timestamp::from_micros_since_unix_epoch(updated_at_micros),
|
||||
published_at: row.published_at,
|
||||
visible: row.visible,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ pub fn square_hole_gallery_view(ctx: &AnonymousViewContext) -> Vec<SquareHoleGal
|
||||
.square_hole_work_profile()
|
||||
.by_square_hole_work_publication_status()
|
||||
.filter(SQUARE_HOLE_PUBLICATION_PUBLISHED)
|
||||
.filter(|row| row.visible)
|
||||
.filter_map(|row| match build_gallery_view_row(&row) {
|
||||
Ok(item) => Some(item),
|
||||
Err(error) => {
|
||||
@@ -537,6 +538,7 @@ fn compile_square_hole_draft_tx(
|
||||
play_count: 0,
|
||||
updated_at: compiled_at,
|
||||
published_at: None,
|
||||
visible: true,
|
||||
};
|
||||
upsert_work(ctx, work);
|
||||
replace_session(
|
||||
@@ -614,6 +616,7 @@ fn update_square_hole_work_tx(
|
||||
play_count: current.play_count,
|
||||
updated_at,
|
||||
published_at: current.published_at,
|
||||
visible: current.visible,
|
||||
};
|
||||
let snapshot = build_work_snapshot(&next)?;
|
||||
replace_work(ctx, ¤t, next);
|
||||
@@ -1141,6 +1144,7 @@ fn clone_work(row: &SquareHoleWorkProfileRow) -> SquareHoleWorkProfileRow {
|
||||
play_count: row.play_count,
|
||||
updated_at: row.updated_at,
|
||||
published_at: row.published_at,
|
||||
visible: row.visible,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user