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]
pub async fn insert_user_workspace(
pg_pool: &PgPool,
tx: &mut Transaction<'_, sqlx::Postgres>,
user_uuid: &Uuid,
workspace_name: &str,
) -> Result<AFWorkspaceRow, AppError> {
@ -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)

View File

@ -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())
}

View File

@ -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<bool,
.await?;
// Create a workspace with the GetStarted template
create_workspace_for_user(
initialize_workspace_for_user(
new_uid,
&workspace_id,
&mut txn,
vec![GetStartedDocumentTemplate],
state,
&state.collab_storage,
)
.await?;
}
@ -80,26 +83,26 @@ pub async fn verify_token(access_token: &str, state: &AppState) -> Result<bool,
Ok(is_new)
}
/// Create a workspace for a user.
/// This function generates a workspace along with its templates and stores them in the database.
/// This function generates templates for a workspace and stores them in the database.
/// Each template is stored as an individual collaborative object.
#[instrument(level = "debug", skip_all, err)]
async fn create_workspace_for_user<T>(
new_uid: i64,
pub async fn initialize_workspace_for_user<T>(
uid: i64,
workspace_id: &str,
txn: &mut Transaction<'_, sqlx::Postgres>,
templates: Vec<T>,
state: &AppState,
// state: &AppState,
collab_storage: &Arc<CollabStorageImpl>,
) -> 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,

View File

@ -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<CollabStorageImpl>,
user_uuid: &Uuid,
user_uid: i64,
workspace_name: &str,
) -> 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)?;
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)
}

View File

@ -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);
}