use anyhow::Context; use app_error::AppError; use database::collab::upsert_collab_member_with_txn; use database::pg_row::{AFWorkspaceMemberRow, AFWorkspaceRow}; use database::user::select_uid_from_email; use database::workspace::{ delete_from_workspace, delete_workspace_members, insert_user_workspace, insert_workspace_member_with_txn, select_all_user_workspaces, select_workspace, select_workspace_member_list, update_updated_at_of_workspace, upsert_workspace_member, }; use database_entity::dto::{AFAccessLevel, AFRole, AFWorkspace}; use shared_entity::dto::workspace_dto::{CreateWorkspaceMember, WorkspaceMemberChangeset}; use shared_entity::response::AppResponseError; use sqlx::{types::uuid, PgPool}; use std::collections::HashMap; use std::ops::DerefMut; use tracing::instrument; use uuid::Uuid; pub async fn delete_workspace_for_user( pg_pool: &PgPool, workspace_id: &Uuid, ) -> Result<(), AppResponseError> { delete_from_workspace(pg_pool, workspace_id).await?; Ok(()) } pub async fn create_workspace_for_user( pg_pool: &PgPool, user_uuid: &Uuid, workspace_name: &str, ) -> Result { let new_workspace_row = insert_user_workspace(pg_pool, user_uuid, workspace_name).await?; let new_workspace = AFWorkspace::try_from(new_workspace_row)?; Ok(new_workspace) } pub async fn get_all_user_workspaces( pg_pool: &PgPool, user_uuid: &Uuid, ) -> Result, AppResponseError> { let workspaces = select_all_user_workspaces(pg_pool, user_uuid).await?; Ok(workspaces) } /// Returns the workspace with the given workspace_id and update the updated_at field of the /// workspace. pub async fn open_workspace( pg_pool: &PgPool, user_uuid: &Uuid, workspace_id: &Uuid, ) -> Result { let mut txn = pg_pool .begin() .await .context("Begin transaction to open workspace")?; let row = select_workspace(txn.deref_mut(), workspace_id).await?; update_updated_at_of_workspace(txn.deref_mut(), user_uuid, workspace_id).await?; txn .commit() .await .context("Commit transaction to open workspace")?; let workspace = AFWorkspace::try_from(row)?; Ok(workspace) } /// Returns the list of uid of members that are added to the workspace. /// Adds members to a workspace. /// /// This function is responsible for adding a list of members to a specified workspace. /// Each member is associated with a role, which determines their access level within the workspace. /// The function performs the following operations: /// 1. Begins a database transaction. /// 2. For each member: /// - Determines the access level based on the member's role. /// - If the member exists (based on their email), inserts them into the workspace and updates their collaboration access level. /// 3. Commits the database transaction. /// /// # Returns /// - A `Result` containing a `HashMap` where the key is the user ID (`uid`) and the value is the role (`AFRole`) assigned to the user in the workspace. /// If there's an error during the operation, an `AppError` is returned. /// #[instrument(level = "debug", skip_all, err)] pub async fn add_workspace_members( pg_pool: &PgPool, _user_uuid: &Uuid, workspace_id: &Uuid, members: Vec, ) -> Result, AppError> { let mut txn = pg_pool .begin() .await .context("Begin transaction to insert workspace members")?; let mut role_by_uid = HashMap::new(); for member in members.into_iter() { let access_level = match &member.role { AFRole::Owner => AFAccessLevel::FullAccess, AFRole::Member => AFAccessLevel::ReadAndWrite, AFRole::Guest => AFAccessLevel::ReadOnly, }; let uid = select_uid_from_email(txn.deref_mut(), &member.email).await?; // .context(format!( // "Failed to get uid from email {} when adding workspace members", // member.email // ))?; insert_workspace_member_with_txn(&mut txn, workspace_id, &member.email, member.role.clone()) .await?; upsert_collab_member_with_txn(uid, workspace_id.to_string(), &access_level, &mut txn).await?; role_by_uid.insert(uid, member.role); } txn .commit() .await .context("Commit transaction to insert workspace members")?; Ok(role_by_uid) } pub async fn remove_workspace_members( user_uuid: &Uuid, pg_pool: &PgPool, workspace_id: &Uuid, member_emails: &[String], ) -> Result<(), AppResponseError> { let mut txn = pg_pool .begin() .await .context("Begin transaction to delete workspace members")?; for email in member_emails { delete_workspace_members(user_uuid, &mut txn, workspace_id, email.as_str()).await?; } txn .commit() .await .context("Commit transaction to delete workspace members")?; Ok(()) } pub async fn get_workspace_members( pg_pool: &PgPool, _user_uuid: &Uuid, workspace_id: &Uuid, ) -> Result, AppResponseError> { Ok(select_workspace_member_list(pg_pool, workspace_id).await?) } pub async fn update_workspace_member( pg_pool: &PgPool, workspace_id: &Uuid, changeset: &WorkspaceMemberChangeset, ) -> Result<(), AppError> { upsert_workspace_member( pg_pool, workspace_id, &changeset.email, changeset.role.clone(), ) .await?; Ok(()) }