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
This commit is contained in:
Zack 2024-02-29 13:02:27 +08:00 committed by GitHub
parent 1cb2620ec7
commit 79a0dd43c6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 67 additions and 22 deletions

View File

@ -29,7 +29,7 @@ pub async fn delete_from_workspace(pg_pool: &PgPool, workspace_id: &Uuid) -> Res
#[inline] #[inline]
pub async fn insert_user_workspace( pub async fn insert_user_workspace(
pg_pool: &PgPool, tx: &mut Transaction<'_, sqlx::Postgres>,
user_uuid: &Uuid, user_uuid: &Uuid,
workspace_name: &str, workspace_name: &str,
) -> Result<AFWorkspaceRow, AppError> { ) -> Result<AFWorkspaceRow, AppError> {
@ -43,7 +43,7 @@ pub async fn insert_user_workspace(
user_uuid, user_uuid,
workspace_name, workspace_name,
) )
.fetch_one(pg_pool) .fetch_one(tx.deref_mut())
.await?; .await?;
Ok(workspace) Ok(workspace)

View File

@ -130,14 +130,18 @@ async fn create_workpace_handler(
.into_inner() .into_inner()
.workspace_name .workspace_name
.unwrap_or_else(|| format!("workspace_{}", chrono::Utc::now().timestamp())); .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?; let uid = state.users.get_user_uid(&uuid).await?;
state let new_workspace = workspace::ops::create_workspace_for_user(
.workspace_access_control &state.pg_pool,
.insert_workspace_role(&uid, &new_workspace.workspace_id, AFRole::Owner) &state.workspace_access_control,
.await?; &state.collab_storage,
&uuid,
uid,
&workspace_name,
)
.await?;
Ok(AppResponse::Ok().with_data(new_workspace).into()) Ok(AppResponse::Ok().with_data(new_workspace).into())
} }

View File

@ -15,11 +15,14 @@ use shared_entity::response::AppResponseError;
use sqlx::{types::uuid, PgPool, Transaction}; use sqlx::{types::uuid, PgPool, Transaction};
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::ops::DerefMut; use std::ops::DerefMut;
use std::sync::Arc;
use tracing::{debug, event, instrument}; use tracing::{debug, event, instrument};
use uuid::Uuid; use uuid::Uuid;
use workspace_template::document::get_started::GetStartedDocumentTemplate; use workspace_template::document::get_started::GetStartedDocumentTemplate;
use workspace_template::{WorkspaceTemplate, WorkspaceTemplateBuilder}; 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 /// 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 /// Return true if the user is a new user
/// ///
@ -64,12 +67,12 @@ pub async fn verify_token(access_token: &str, state: &AppState) -> Result<bool,
.await?; .await?;
// Create a workspace with the GetStarted template // Create a workspace with the GetStarted template
create_workspace_for_user( initialize_workspace_for_user(
new_uid, new_uid,
&workspace_id, &workspace_id,
&mut txn, &mut txn,
vec![GetStartedDocumentTemplate], vec![GetStartedDocumentTemplate],
state, &state.collab_storage,
) )
.await?; .await?;
} }
@ -80,26 +83,26 @@ pub async fn verify_token(access_token: &str, state: &AppState) -> Result<bool,
Ok(is_new) Ok(is_new)
} }
/// Create a workspace for a user. /// This function generates templates for a workspace and stores them in the database.
/// This function generates a workspace along with its templates and stores them in the database.
/// Each template is stored as an individual collaborative object. /// Each template is stored as an individual collaborative object.
#[instrument(level = "debug", skip_all, err)] #[instrument(level = "debug", skip_all, err)]
async fn create_workspace_for_user<T>( pub async fn initialize_workspace_for_user<T>(
new_uid: i64, uid: i64,
workspace_id: &str, workspace_id: &str,
txn: &mut Transaction<'_, sqlx::Postgres>, txn: &mut Transaction<'_, sqlx::Postgres>,
templates: Vec<T>, templates: Vec<T>,
state: &AppState, // state: &AppState,
collab_storage: &Arc<CollabStorageImpl>,
) -> Result<(), AppError> ) -> Result<(), AppError>
where where
T: WorkspaceTemplate + Send + Sync + 'static, T: WorkspaceTemplate + Send + Sync + 'static,
{ {
let templates = WorkspaceTemplateBuilder::new(new_uid, workspace_id) let templates = WorkspaceTemplateBuilder::new(uid, workspace_id)
.with_templates(templates) .with_templates(templates)
.build() .build()
.await?; .await?;
debug!("create {} templates for user:{}", templates.len(), new_uid); debug!("create {} templates for user:{}", templates.len(), uid);
for template in templates { for template in templates {
let object_id = template.object_id; let object_id = template.object_id;
let encoded_collab_v1 = template let encoded_collab_v1 = template
@ -107,11 +110,10 @@ where
.encode_to_bytes() .encode_to_bytes()
.map_err(|err| AppError::Internal(anyhow::Error::from(err)))?; .map_err(|err| AppError::Internal(anyhow::Error::from(err)))?;
state collab_storage
.collab_storage
.upsert_collab_with_transaction( .upsert_collab_with_transaction(
workspace_id, workspace_id,
&new_uid, &uid,
CollabParams { CollabParams {
object_id, object_id,
encoded_collab_v1, encoded_collab_v1,

View File

@ -20,6 +20,13 @@ use std::ops::DerefMut;
use std::sync::Arc; use std::sync::Arc;
use tracing::instrument; use tracing::instrument;
use uuid::Uuid; 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( pub async fn delete_workspace_for_user(
pg_pool: &PgPool, pg_pool: &PgPool,
@ -50,11 +57,32 @@ pub async fn delete_workspace_for_user(
pub async fn create_workspace_for_user( pub async fn create_workspace_for_user(
pg_pool: &PgPool, pg_pool: &PgPool,
workspace_access_control: &WorkspaceAccessControlImpl,
collab_storage: &Arc<CollabStorageImpl>,
user_uuid: &Uuid, user_uuid: &Uuid,
user_uid: i64,
workspace_name: &str, workspace_name: &str,
) -> Result<AFWorkspace, AppResponseError> { ) -> Result<AFWorkspace, AppResponseError> {
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)?; 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) Ok(new_workspace)
} }

View File

@ -1,5 +1,7 @@
use client_api_test_util::generate_unique_registered_user_client; use client_api_test_util::generate_unique_registered_user_client;
use collab_entity::CollabType;
use database_entity::dto::AFRole; use database_entity::dto::AFRole;
use database_entity::dto::QueryCollabParams;
use shared_entity::dto::workspace_dto::CreateWorkspaceMember; use shared_entity::dto::workspace_dto::CreateWorkspaceMember;
use shared_entity::dto::workspace_dto::CreateWorkspaceParam; use shared_entity::dto::workspace_dto::CreateWorkspaceParam;
use shared_entity::dto::workspace_dto::PatchWorkspaceParam; use shared_entity::dto::workspace_dto::PatchWorkspaceParam;
@ -26,9 +28,18 @@ async fn add_and_delete_workspace_for_user() {
}) })
.unwrap(); .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 .await
.unwrap(); .unwrap();
c.delete_workspace(&workspace_id).await.unwrap();
let workspaces = c.get_workspaces().await.unwrap(); let workspaces = c.get_workspaces().await.unwrap();
assert_eq!(workspaces.0.len(), 1); assert_eq!(workspaces.0.len(), 1);
} }