新增图片画布项目页
新增 /project 项目页和我的页项目入口 补齐图片画布工程列表、重命名和删除 API 支持 /editor/canvas 按 projectid 加载指定工程 更新图片画布文档、TRACKING 和对应测试
This commit is contained in:
@@ -94,6 +94,25 @@ pub struct EditorProjectGetRecentInput {
|
||||
pub owner_user_id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
|
||||
pub struct EditorProjectListInput {
|
||||
pub owner_user_id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
|
||||
pub struct EditorProjectRenameInput {
|
||||
pub project_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub title: String,
|
||||
pub updated_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
|
||||
pub struct EditorProjectDeleteInput {
|
||||
pub project_id: String,
|
||||
pub owner_user_id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, SpacetimeType)]
|
||||
pub struct EditorProjectLayoutSaveInput {
|
||||
pub project_id: String,
|
||||
@@ -172,6 +191,20 @@ pub struct EditorProjectProcedureResult {
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, SpacetimeType)]
|
||||
pub struct EditorProjectListProcedureResult {
|
||||
pub ok: bool,
|
||||
pub projects: Vec<EditorProjectSnapshot>,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
|
||||
pub struct EditorProjectDeleteProcedureResult {
|
||||
pub ok: bool,
|
||||
pub deleted_project_id: Option<String>,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, SpacetimeType)]
|
||||
pub struct EditorProjectResourceProcedureResult {
|
||||
pub ok: bool,
|
||||
@@ -201,6 +234,25 @@ pub fn get_recent_editor_project_and_return(
|
||||
}
|
||||
}
|
||||
|
||||
#[spacetimedb::procedure]
|
||||
pub fn list_editor_projects_and_return(
|
||||
ctx: &mut ProcedureContext,
|
||||
input: EditorProjectListInput,
|
||||
) -> EditorProjectListProcedureResult {
|
||||
match ctx.try_with_tx(|tx| list_editor_projects(tx, input.clone())) {
|
||||
Ok(projects) => EditorProjectListProcedureResult {
|
||||
ok: true,
|
||||
projects,
|
||||
error_message: None,
|
||||
},
|
||||
Err(message) => EditorProjectListProcedureResult {
|
||||
ok: false,
|
||||
projects: Vec::new(),
|
||||
error_message: Some(message),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[spacetimedb::procedure]
|
||||
pub fn get_editor_project_and_return(
|
||||
ctx: &mut ProcedureContext,
|
||||
@@ -223,6 +275,36 @@ pub fn save_editor_project_layout_and_return(
|
||||
}
|
||||
}
|
||||
|
||||
#[spacetimedb::procedure]
|
||||
pub fn rename_editor_project_and_return(
|
||||
ctx: &mut ProcedureContext,
|
||||
input: EditorProjectRenameInput,
|
||||
) -> EditorProjectProcedureResult {
|
||||
match ctx.try_with_tx(|tx| rename_editor_project(tx, input.clone())) {
|
||||
Ok(project) => editor_project_ok(Some(project)),
|
||||
Err(message) => editor_project_error(message),
|
||||
}
|
||||
}
|
||||
|
||||
#[spacetimedb::procedure]
|
||||
pub fn delete_editor_project_and_return(
|
||||
ctx: &mut ProcedureContext,
|
||||
input: EditorProjectDeleteInput,
|
||||
) -> EditorProjectDeleteProcedureResult {
|
||||
match ctx.try_with_tx(|tx| delete_editor_project(tx, input.clone())) {
|
||||
Ok(project_id) => EditorProjectDeleteProcedureResult {
|
||||
ok: true,
|
||||
deleted_project_id: Some(project_id),
|
||||
error_message: None,
|
||||
},
|
||||
Err(message) => EditorProjectDeleteProcedureResult {
|
||||
ok: false,
|
||||
deleted_project_id: None,
|
||||
error_message: Some(message),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[spacetimedb::procedure]
|
||||
pub fn create_editor_project_resource_and_return(
|
||||
ctx: &mut ProcedureContext,
|
||||
@@ -309,6 +391,32 @@ fn get_recent_editor_project(
|
||||
.transpose()
|
||||
}
|
||||
|
||||
fn list_editor_projects(
|
||||
ctx: &ReducerContext,
|
||||
input: EditorProjectListInput,
|
||||
) -> Result<Vec<EditorProjectSnapshot>, String> {
|
||||
let owner_user_id = normalize_required(&input.owner_user_id, "editor_project.owner_user_id")?;
|
||||
let mut projects = ctx
|
||||
.db
|
||||
.editor_project()
|
||||
.by_editor_project_owner_user_id()
|
||||
.filter(&owner_user_id)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
projects.sort_by(|left, right| {
|
||||
right
|
||||
.updated_at
|
||||
.to_micros_since_unix_epoch()
|
||||
.cmp(&left.updated_at.to_micros_since_unix_epoch())
|
||||
.then_with(|| right.project_id.cmp(&left.project_id))
|
||||
});
|
||||
|
||||
projects
|
||||
.into_iter()
|
||||
.map(|project| build_project_snapshot(ctx, project.project_id.as_str()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_editor_project(
|
||||
ctx: &ReducerContext,
|
||||
input: EditorProjectGetInput,
|
||||
@@ -319,6 +427,68 @@ fn get_editor_project(
|
||||
build_project_snapshot(ctx, project.project_id.as_str())
|
||||
}
|
||||
|
||||
fn rename_editor_project(
|
||||
ctx: &ReducerContext,
|
||||
input: EditorProjectRenameInput,
|
||||
) -> Result<EditorProjectSnapshot, String> {
|
||||
let project_id = normalize_required(&input.project_id, "editor_project.project_id")?;
|
||||
let owner_user_id = normalize_required(&input.owner_user_id, "editor_project.owner_user_id")?;
|
||||
let project = require_owned_project(ctx, project_id.as_str(), owner_user_id.as_str())?;
|
||||
let now = Timestamp::from_micros_since_unix_epoch(input.updated_at_micros);
|
||||
|
||||
ctx.db.editor_project().project_id().delete(&project_id);
|
||||
ctx.db.editor_project().insert(EditorProject {
|
||||
project_id: project.project_id.clone(),
|
||||
owner_user_id: project.owner_user_id,
|
||||
title: normalize_title(&input.title),
|
||||
viewport_x: project.viewport_x,
|
||||
viewport_y: project.viewport_y,
|
||||
viewport_scale: project.viewport_scale,
|
||||
layers_json: project.layers_json,
|
||||
created_at: project.created_at,
|
||||
updated_at: now,
|
||||
});
|
||||
|
||||
build_project_snapshot(ctx, project_id.as_str())
|
||||
}
|
||||
|
||||
fn delete_editor_project(
|
||||
ctx: &ReducerContext,
|
||||
input: EditorProjectDeleteInput,
|
||||
) -> Result<String, String> {
|
||||
let project_id = normalize_required(&input.project_id, "editor_project.project_id")?;
|
||||
let owner_user_id = normalize_required(&input.owner_user_id, "editor_project.owner_user_id")?;
|
||||
require_owned_project(ctx, project_id.as_str(), owner_user_id.as_str())?;
|
||||
let project_key = project_id.clone();
|
||||
let canvas_ids = ctx
|
||||
.db
|
||||
.editor_canvas()
|
||||
.by_editor_canvas_project_id()
|
||||
.filter(&project_key)
|
||||
.map(|canvas| canvas.canvas_id)
|
||||
.collect::<Vec<_>>();
|
||||
let resource_ids = ctx
|
||||
.db
|
||||
.editor_project_resource()
|
||||
.by_editor_project_resource_project_id()
|
||||
.filter(&project_key)
|
||||
.map(|resource| resource.resource_id)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for canvas_id in canvas_ids {
|
||||
ctx.db.editor_canvas().canvas_id().delete(&canvas_id);
|
||||
}
|
||||
for resource_id in resource_ids {
|
||||
ctx.db
|
||||
.editor_project_resource()
|
||||
.resource_id()
|
||||
.delete(&resource_id);
|
||||
}
|
||||
ctx.db.editor_project().project_id().delete(&project_id);
|
||||
|
||||
Ok(project_id)
|
||||
}
|
||||
|
||||
fn save_editor_project_layout(
|
||||
ctx: &ReducerContext,
|
||||
input: EditorProjectLayoutSaveInput,
|
||||
|
||||
Reference in New Issue
Block a user