From 79a0dd43c6c0cac9e88f65770dfeb67547eb3ce7 Mon Sep 17 00:00:00 2001 From: Zack Date: Thu, 29 Feb 2024 13:02:27 +0800 Subject: [PATCH] feat: Create workspace (#357) * feat: initialize collab for user after workspace creation * fix: add permission before adding new collab for new workspace * chore: simplify logic --- libs/database/src/workspace.rs | 4 ++-- src/api/workspace.rs | 16 ++++++++++------ src/biz/user.rs | 26 ++++++++++++++------------ src/biz/workspace/ops.rs | 30 +++++++++++++++++++++++++++++- tests/workspace/workspace_crud.rs | 13 ++++++++++++- 5 files changed, 67 insertions(+), 22 deletions(-) diff --git a/libs/database/src/workspace.rs b/libs/database/src/workspace.rs index 84f8dc13..e3793df0 100644 --- a/libs/database/src/workspace.rs +++ b/libs/database/src/workspace.rs @@ -29,7 +29,7 @@ pub async fn delete_from_workspace(pg_pool: &PgPool, workspace_id: &Uuid) -> Res #[inline] pub async fn insert_user_workspace( - pg_pool: &PgPool, + tx: &mut Transaction<'_, sqlx::Postgres>, user_uuid: &Uuid, workspace_name: &str, ) -> Result { @@ -43,7 +43,7 @@ pub async fn insert_user_workspace( user_uuid, workspace_name, ) - .fetch_one(pg_pool) + .fetch_one(tx.deref_mut()) .await?; Ok(workspace) diff --git a/src/api/workspace.rs b/src/api/workspace.rs index 5307aed9..062ac8b6 100644 --- a/src/api/workspace.rs +++ b/src/api/workspace.rs @@ -130,14 +130,18 @@ async fn create_workpace_handler( .into_inner() .workspace_name .unwrap_or_else(|| format!("workspace_{}", chrono::Utc::now().timestamp())); - let new_workspace = - workspace::ops::create_workspace_for_user(&state.pg_pool, &uuid, &workspace_name).await?; let uid = state.users.get_user_uid(&uuid).await?; - state - .workspace_access_control - .insert_workspace_role(&uid, &new_workspace.workspace_id, AFRole::Owner) - .await?; + let new_workspace = workspace::ops::create_workspace_for_user( + &state.pg_pool, + &state.workspace_access_control, + &state.collab_storage, + &uuid, + uid, + &workspace_name, + ) + .await?; + Ok(AppResponse::Ok().with_data(new_workspace).into()) } diff --git a/src/biz/user.rs b/src/biz/user.rs index 637b1046..b8dd4431 100644 --- a/src/biz/user.rs +++ b/src/biz/user.rs @@ -15,11 +15,14 @@ use shared_entity::response::AppResponseError; use sqlx::{types::uuid, PgPool, Transaction}; use std::fmt::{Display, Formatter}; use std::ops::DerefMut; +use std::sync::Arc; use tracing::{debug, event, instrument}; use uuid::Uuid; use workspace_template::document::get_started::GetStartedDocumentTemplate; use workspace_template::{WorkspaceTemplate, WorkspaceTemplateBuilder}; +use super::collab::storage::CollabStorageImpl; + /// Verify the token from the gotrue server and create the user if it is a new user /// Return true if the user is a new user /// @@ -64,12 +67,12 @@ pub async fn verify_token(access_token: &str, state: &AppState) -> Result Result( - new_uid: i64, +pub async fn initialize_workspace_for_user( + uid: i64, workspace_id: &str, txn: &mut Transaction<'_, sqlx::Postgres>, templates: Vec, - state: &AppState, + // state: &AppState, + collab_storage: &Arc, ) -> Result<(), AppError> where T: WorkspaceTemplate + Send + Sync + 'static, { - let templates = WorkspaceTemplateBuilder::new(new_uid, workspace_id) + let templates = WorkspaceTemplateBuilder::new(uid, workspace_id) .with_templates(templates) .build() .await?; - debug!("create {} templates for user:{}", templates.len(), new_uid); + debug!("create {} templates for user:{}", templates.len(), uid); for template in templates { let object_id = template.object_id; let encoded_collab_v1 = template @@ -107,11 +110,10 @@ where .encode_to_bytes() .map_err(|err| AppError::Internal(anyhow::Error::from(err)))?; - state - .collab_storage + collab_storage .upsert_collab_with_transaction( workspace_id, - &new_uid, + &uid, CollabParams { object_id, encoded_collab_v1, diff --git a/src/biz/workspace/ops.rs b/src/biz/workspace/ops.rs index a28c331c..744df46c 100644 --- a/src/biz/workspace/ops.rs +++ b/src/biz/workspace/ops.rs @@ -20,6 +20,13 @@ use std::ops::DerefMut; use std::sync::Arc; use tracing::instrument; use uuid::Uuid; +use workspace_template::document::get_started::GetStartedDocumentTemplate; + +use crate::biz::casbin::WorkspaceAccessControlImpl; +use crate::biz::collab::storage::CollabStorageImpl; +use crate::biz::user::initialize_workspace_for_user; + +use super::access_control::WorkspaceAccessControl; pub async fn delete_workspace_for_user( pg_pool: &PgPool, @@ -50,11 +57,32 @@ pub async fn delete_workspace_for_user( pub async fn create_workspace_for_user( pg_pool: &PgPool, + workspace_access_control: &WorkspaceAccessControlImpl, + collab_storage: &Arc, user_uuid: &Uuid, + user_uid: i64, workspace_name: &str, ) -> Result { - let new_workspace_row = insert_user_workspace(pg_pool, user_uuid, workspace_name).await?; + let mut txn = pg_pool.begin().await?; + + let new_workspace_row = insert_user_workspace(&mut txn, user_uuid, workspace_name).await?; let new_workspace = AFWorkspace::try_from(new_workspace_row)?; + + workspace_access_control + .insert_workspace_role(&user_uid, &new_workspace.workspace_id, AFRole::Owner) + .await?; + + // add create initial collab for user + initialize_workspace_for_user( + user_uid, + new_workspace.workspace_id.to_string().as_str(), + &mut txn, + vec![GetStartedDocumentTemplate], + collab_storage, + ) + .await?; + + txn.commit().await?; Ok(new_workspace) } diff --git a/tests/workspace/workspace_crud.rs b/tests/workspace/workspace_crud.rs index 53495325..ec449720 100644 --- a/tests/workspace/workspace_crud.rs +++ b/tests/workspace/workspace_crud.rs @@ -1,5 +1,7 @@ use client_api_test_util::generate_unique_registered_user_client; +use collab_entity::CollabType; use database_entity::dto::AFRole; +use database_entity::dto::QueryCollabParams; use shared_entity::dto::workspace_dto::CreateWorkspaceMember; use shared_entity::dto::workspace_dto::CreateWorkspaceParam; use shared_entity::dto::workspace_dto::PatchWorkspaceParam; @@ -26,9 +28,18 @@ async fn add_and_delete_workspace_for_user() { }) .unwrap(); - c.delete_workspace(&newly_added_workspace.workspace_id.to_string()) + // Workspace need to have at least one collab + let workspace_id = newly_added_workspace.workspace_id.to_string(); + let _ = c + .get_collab(QueryCollabParams::new( + &workspace_id, + CollabType::Folder, + &workspace_id, + )) .await .unwrap(); + + c.delete_workspace(&workspace_id).await.unwrap(); let workspaces = c.get_workspaces().await.unwrap(); assert_eq!(workspaces.0.len(), 1); }