新增图片画布项目页
新增 /project 项目页和我的页项目入口 补齐图片画布工程列表、重命名和删除 API 支持 /editor/canvas 按 projectid 加载指定工程 更新图片画布文档、TRACKING 和对应测试
This commit is contained in:
@@ -9,7 +9,8 @@ use serde_json::{Value, json};
|
||||
use shared_kernel::build_prefixed_uuid_id;
|
||||
use spacetime_client::{
|
||||
EditorCanvasRecord, EditorCanvasViewportRecord, EditorProjectCreateRecordInput,
|
||||
EditorProjectGetRecordInput, EditorProjectLayoutSaveRecordInput, EditorProjectRecord,
|
||||
EditorProjectDeleteRecordInput, EditorProjectGetRecordInput,
|
||||
EditorProjectLayoutSaveRecordInput, EditorProjectRecord, EditorProjectRenameRecordInput,
|
||||
EditorProjectResourceCreateRecordInput, EditorProjectResourceRecord, SpacetimeClientError,
|
||||
};
|
||||
|
||||
@@ -53,6 +54,12 @@ pub struct EditorProjectLayoutSaveRequest {
|
||||
layers: Value,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EditorProjectRenameRequest {
|
||||
title: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EditorProjectResourceCreateRequest {
|
||||
@@ -95,6 +102,18 @@ pub struct EditorProjectRecentResponse {
|
||||
project: Option<EditorProjectPayload>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EditorProjectListResponse {
|
||||
projects: Vec<EditorProjectPayload>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EditorProjectDeleteResponse {
|
||||
deleted_project_id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EditorProjectResourceResponse {
|
||||
@@ -179,6 +198,27 @@ pub async fn load_recent_editor_project(
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn list_editor_projects(
|
||||
State(state): State<AppState>,
|
||||
Extension(request_context): Extension<RequestContext>,
|
||||
Extension(authenticated): Extension<AuthenticatedAccessToken>,
|
||||
) -> Result<Json<Value>, AppError> {
|
||||
let owner_user_id = authenticated.claims().user_id().to_string();
|
||||
let projects = state
|
||||
.spacetime_client()
|
||||
.list_editor_projects(owner_user_id)
|
||||
.await
|
||||
.map_err(map_editor_project_error)?
|
||||
.into_iter()
|
||||
.map(editor_project_payload_from_record)
|
||||
.collect();
|
||||
|
||||
Ok(json_success_body(
|
||||
Some(&request_context),
|
||||
EditorProjectListResponse { projects },
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn create_editor_project(
|
||||
State(state): State<AppState>,
|
||||
Extension(request_context): Extension<RequestContext>,
|
||||
@@ -261,6 +301,53 @@ pub async fn save_editor_project_layout(
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn rename_editor_project(
|
||||
State(state): State<AppState>,
|
||||
Path(project_id): Path<String>,
|
||||
Extension(request_context): Extension<RequestContext>,
|
||||
Extension(authenticated): Extension<AuthenticatedAccessToken>,
|
||||
Json(payload): Json<EditorProjectRenameRequest>,
|
||||
) -> Result<Json<Value>, AppError> {
|
||||
let project = state
|
||||
.spacetime_client()
|
||||
.rename_editor_project(EditorProjectRenameRecordInput {
|
||||
project_id,
|
||||
owner_user_id: authenticated.claims().user_id().to_string(),
|
||||
title: payload.title,
|
||||
updated_at_micros: current_utc_micros(),
|
||||
})
|
||||
.await
|
||||
.map_err(map_editor_project_error)?;
|
||||
|
||||
Ok(json_success_body(
|
||||
Some(&request_context),
|
||||
EditorProjectResponse {
|
||||
project: editor_project_payload_from_record(project),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn delete_editor_project(
|
||||
State(state): State<AppState>,
|
||||
Path(project_id): Path<String>,
|
||||
Extension(request_context): Extension<RequestContext>,
|
||||
Extension(authenticated): Extension<AuthenticatedAccessToken>,
|
||||
) -> Result<Json<Value>, AppError> {
|
||||
let deleted_project_id = state
|
||||
.spacetime_client()
|
||||
.delete_editor_project(EditorProjectDeleteRecordInput {
|
||||
project_id,
|
||||
owner_user_id: authenticated.claims().user_id().to_string(),
|
||||
})
|
||||
.await
|
||||
.map_err(map_editor_project_error)?;
|
||||
|
||||
Ok(json_success_body(
|
||||
Some(&request_context),
|
||||
EditorProjectDeleteResponse { deleted_project_id },
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn create_editor_project_resource(
|
||||
State(state): State<AppState>,
|
||||
Path(project_id): Path<String>,
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
use axum::{
|
||||
Router, middleware,
|
||||
routing::{get, post},
|
||||
routing::{get, patch, post},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
auth::require_bearer_auth,
|
||||
editor_project::{
|
||||
create_editor_project, create_editor_project_resource, edit_editor_image,
|
||||
generate_editor_image, get_editor_project, load_recent_editor_project,
|
||||
save_editor_project_layout,
|
||||
create_editor_project, create_editor_project_resource, delete_editor_project,
|
||||
edit_editor_image, generate_editor_image, get_editor_project, list_editor_projects,
|
||||
load_recent_editor_project, rename_editor_project, save_editor_project_layout,
|
||||
},
|
||||
state::AppState,
|
||||
};
|
||||
@@ -24,20 +24,30 @@ pub fn router(state: AppState) -> Router<AppState> {
|
||||
)
|
||||
.route(
|
||||
"/api/editor/projects",
|
||||
post(create_editor_project).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
get(list_editor_projects)
|
||||
.post(create_editor_project)
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/editor/projects/{project_id}",
|
||||
get(get_editor_project)
|
||||
.patch(save_editor_project_layout)
|
||||
.delete(delete_editor_project)
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/editor/projects/{project_id}/metadata",
|
||||
patch(rename_editor_project).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/editor/projects/{project_id}/resources",
|
||||
post(create_editor_project_resource).route_layer(middleware::from_fn_with_state(
|
||||
|
||||
Reference in New Issue
Block a user