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:
parent
1cb2620ec7
commit
79a0dd43c6
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue