From 7c95f6556a08cf31b25df7a92b74d0b124be2432 Mon Sep 17 00:00:00 2001 From: Fu Zi Xiang Date: Tue, 23 Jan 2024 14:48:25 +0800 Subject: [PATCH] feat: added test case and use triggers --- ...d6182040e714499adc0b58937c226c5993a80.json | 25 ------------------- ...fb1e2e0aab6f3a1ac9c2fc99b4cdee9e58cbe.json | 25 +++++++++++++++++++ ...e590420f1b1285d024f5554cc02c375d6476.json} | 4 +-- libs/client-api/src/http.rs | 13 ++++++++++ libs/database/src/pg_row.rs | 2 +- libs/database/src/user.rs | 13 +++------- ...20240123140707_workspace_owner_trigger.sql | 20 +++++++++++++++ src/api/workspace.rs | 4 +-- src/biz/casbin/access_control.rs | 1 + tests/workspace/workspace_crud.rs | 16 ++++++++++++ 10 files changed, 84 insertions(+), 39 deletions(-) delete mode 100644 .sqlx/query-4775e2efabeb435663e9de51b21d6182040e714499adc0b58937c226c5993a80.json create mode 100644 .sqlx/query-b4fa2e732c975fbb23c346981c4fb1e2e0aab6f3a1ac9c2fc99b4cdee9e58cbe.json rename .sqlx/{query-c95a9130eb573498248beab702f0fd3d173b6456d079466683be78f1c9bb4f76.json => query-d61523de25986b47a382d36a1f18e590420f1b1285d024f5554cc02c375d6476.json} (57%) create mode 100644 migrations/20240123140707_workspace_owner_trigger.sql diff --git a/.sqlx/query-4775e2efabeb435663e9de51b21d6182040e714499adc0b58937c226c5993a80.json b/.sqlx/query-4775e2efabeb435663e9de51b21d6182040e714499adc0b58937c226c5993a80.json deleted file mode 100644 index 7a24ac2e..00000000 --- a/.sqlx/query-4775e2efabeb435663e9de51b21d6182040e714499adc0b58937c226c5993a80.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n WITH ins_user AS (\n INSERT INTO af_user (uid, uuid, email, name)\n VALUES ($1, $2, $3, $4) \n ON CONFLICT(email) DO NOTHING\n RETURNING uid\n ),\n owner_role AS (\n SELECT id FROM af_roles WHERE name = 'Owner'\n ),\n ins_workspace AS (\n INSERT INTO af_workspace (owner_uid)\n SELECT uid FROM ins_user\n RETURNING workspace_id, owner_uid\n ),\n ins_collab_member AS (\n INSERT INTO af_collab_member (uid, oid, permission_id)\n SELECT ins_workspace.owner_uid,\n ins_workspace.workspace_id::TEXT, \n (SELECT permission_id FROM af_role_permissions WHERE role_id = owner_role.id)\n FROM ins_workspace, owner_role\n ),\n ins_workspace_member AS (\n INSERT INTO af_workspace_member (uid, role_id, workspace_id)\n SELECT ins_workspace.owner_uid, owner_role.id, ins_workspace.workspace_id\n FROM ins_workspace, owner_role\n )\n SELECT workspace_id FROM ins_workspace;\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "workspace_id", - "type_info": "Uuid" - } - ], - "parameters": { - "Left": [ - "Int8", - "Uuid", - "Text", - "Text" - ] - }, - "nullable": [ - false - ] - }, - "hash": "4775e2efabeb435663e9de51b21d6182040e714499adc0b58937c226c5993a80" -} diff --git a/.sqlx/query-b4fa2e732c975fbb23c346981c4fb1e2e0aab6f3a1ac9c2fc99b4cdee9e58cbe.json b/.sqlx/query-b4fa2e732c975fbb23c346981c4fb1e2e0aab6f3a1ac9c2fc99b4cdee9e58cbe.json new file mode 100644 index 00000000..437a2167 --- /dev/null +++ b/.sqlx/query-b4fa2e732c975fbb23c346981c4fb1e2e0aab6f3a1ac9c2fc99b4cdee9e58cbe.json @@ -0,0 +1,25 @@ +{ + "db_name": "PostgreSQL", + "query": "\n WITH ins_user AS (\n INSERT INTO af_user (uid, uuid, email, name)\n VALUES ($1, $2, $3, $4)\n ON CONFLICT(email) DO NOTHING\n RETURNING uid\n ),\n owner_role AS (\n SELECT id FROM af_roles WHERE name = 'Owner'\n ),\n ins_workspace AS (\n INSERT INTO af_workspace (owner_uid)\n SELECT uid FROM ins_user\n RETURNING workspace_id, owner_uid\n ),\n ins_collab_member AS (\n INSERT INTO af_collab_member (uid, oid, permission_id)\n SELECT ins_workspace.owner_uid,\n ins_workspace.workspace_id::TEXT,\n (SELECT permission_id FROM af_role_permissions WHERE role_id = owner_role.id)\n FROM ins_workspace, owner_role\n )\n SELECT workspace_id FROM ins_workspace;\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "workspace_id", + "type_info": "Uuid" + } + ], + "parameters": { + "Left": [ + "Int8", + "Uuid", + "Text", + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "b4fa2e732c975fbb23c346981c4fb1e2e0aab6f3a1ac9c2fc99b4cdee9e58cbe" +} diff --git a/.sqlx/query-c95a9130eb573498248beab702f0fd3d173b6456d079466683be78f1c9bb4f76.json b/.sqlx/query-d61523de25986b47a382d36a1f18e590420f1b1285d024f5554cc02c375d6476.json similarity index 57% rename from .sqlx/query-c95a9130eb573498248beab702f0fd3d173b6456d079466683be78f1c9bb4f76.json rename to .sqlx/query-d61523de25986b47a382d36a1f18e590420f1b1285d024f5554cc02c375d6476.json index d7253146..4acc25d4 100644 --- a/.sqlx/query-c95a9130eb573498248beab702f0fd3d173b6456d079466683be78f1c9bb4f76.json +++ b/.sqlx/query-d61523de25986b47a382d36a1f18e590420f1b1285d024f5554cc02c375d6476.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT EXISTS(\n SELECT 1 \n FROM af_user \n WHERE uuid = $1\n ) AS user_exists;\n ", + "query": "\n SELECT EXISTS(\n SELECT 1\n FROM af_user\n WHERE uuid = $1\n ) AS user_exists;\n ", "describe": { "columns": [ { @@ -18,5 +18,5 @@ null ] }, - "hash": "c95a9130eb573498248beab702f0fd3d173b6456d079466683be78f1c9bb4f76" + "hash": "d61523de25986b47a382d36a1f18e590420f1b1285d024f5554cc02c375d6476" } diff --git a/libs/client-api/src/http.rs b/libs/client-api/src/http.rs index ad361c61..2babfd20 100644 --- a/libs/client-api/src/http.rs +++ b/libs/client-api/src/http.rs @@ -489,6 +489,19 @@ impl Client { .into_data() } + #[instrument(level = "debug", skip_all, err)] + pub async fn delete_workspace(&self, workspace_id: &str) -> Result<(), AppResponseError> { + let url = format!("{}/api/workspace/{}", self.base_url, workspace_id); + let resp = self + .http_client_with_auth(Method::DELETE, &url) + .await? + .send() + .await?; + log_request_id(&resp); + AppResponse::<()>::from_response(resp).await?.into_error()?; + Ok(()) + } + #[instrument(level = "debug", skip_all, err)] pub async fn add_workspace(&self) -> Result { let url = format!("{}/api/workspace", self.base_url); diff --git a/libs/database/src/pg_row.rs b/libs/database/src/pg_row.rs index f57de682..060c8b96 100644 --- a/libs/database/src/pg_row.rs +++ b/libs/database/src/pg_row.rs @@ -108,7 +108,7 @@ pub struct AFWorkspaceMemberPermRow { pub workspace_id: Uuid, } -#[derive(FromRow, Serialize, Deserialize)] +#[derive(Debug, FromRow, Serialize, Deserialize)] pub struct AFWorkspaceMemberRow { pub uid: i64, pub name: String, diff --git a/libs/database/src/user.rs b/libs/database/src/user.rs index ed7c5ab8..545e03a8 100644 --- a/libs/database/src/user.rs +++ b/libs/database/src/user.rs @@ -93,7 +93,7 @@ pub async fn create_user<'a, E: Executor<'a, Database = Postgres>>( r#" WITH ins_user AS ( INSERT INTO af_user (uid, uuid, email, name) - VALUES ($1, $2, $3, $4) + VALUES ($1, $2, $3, $4) ON CONFLICT(email) DO NOTHING RETURNING uid ), @@ -108,14 +108,9 @@ pub async fn create_user<'a, E: Executor<'a, Database = Postgres>>( ins_collab_member AS ( INSERT INTO af_collab_member (uid, oid, permission_id) SELECT ins_workspace.owner_uid, - ins_workspace.workspace_id::TEXT, + ins_workspace.workspace_id::TEXT, (SELECT permission_id FROM af_role_permissions WHERE role_id = owner_role.id) FROM ins_workspace, owner_role - ), - ins_workspace_member AS ( - INSERT INTO af_workspace_member (uid, role_id, workspace_id) - SELECT ins_workspace.owner_uid, owner_role.id, ins_workspace.workspace_id - FROM ins_workspace, owner_role ) SELECT workspace_id FROM ins_workspace; "#, @@ -173,8 +168,8 @@ pub async fn is_user_exist<'a, E: Executor<'a, Database = Postgres>>( let exists = sqlx::query_scalar!( r#" SELECT EXISTS( - SELECT 1 - FROM af_user + SELECT 1 + FROM af_user WHERE uuid = $1 ) AS user_exists; "#, diff --git a/migrations/20240123140707_workspace_owner_trigger.sql b/migrations/20240123140707_workspace_owner_trigger.sql new file mode 100644 index 00000000..3ae74b50 --- /dev/null +++ b/migrations/20240123140707_workspace_owner_trigger.sql @@ -0,0 +1,20 @@ +CREATE OR REPLACE FUNCTION af_workspace_insert_trigger() +RETURNS TRIGGER AS $$ +BEGIN + -- Insert a record into af_workspace_member + INSERT INTO public.af_workspace_member ( + uid, role_id, + workspace_id, created_at, updated_at) + VALUES ( + NEW.owner_uid, (SELECT id FROM public.af_roles WHERE name = 'Owner'), + NEW.workspace_id, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); + + -- Return the new record to complete the insert operation + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER af_workspace_after_insert +AFTER INSERT ON public.af_workspace +FOR EACH ROW +EXECUTE FUNCTION af_workspace_insert_trigger(); diff --git a/src/api/workspace.rs b/src/api/workspace.rs index 525391b1..e7cd2fd9 100644 --- a/src/api/workspace.rs +++ b/src/api/workspace.rs @@ -40,10 +40,10 @@ pub const COLLAB_OBJECT_ID_PATH: &str = "object_id"; pub fn workspace_scope() -> Scope { web::scope("/api/workspace") - // deprecated, use `/` instead + // deprecated, use the api below instead .service(web::resource("/list").route(web::get().to(list_workspace_handler))) - .service(web::resource("/") + .service(web::resource("") .route(web::get().to(list_workspace_handler)) .route(web::post().to(add_workpace_handler)) ) diff --git a/src/biz/casbin/access_control.rs b/src/biz/casbin/access_control.rs index fc527f92..2262b9dd 100644 --- a/src/biz/casbin/access_control.rs +++ b/src/biz/casbin/access_control.rs @@ -398,6 +398,7 @@ impl WorkspaceAccessControl for CasbinWorkspaceAccessControl { .await?; self.get_role_from_uid(&uid, workspace_id).await } + async fn get_role_from_uid(&self, uid: &i64, workspace_id: &Uuid) -> Result { let policies = self .casbin_access_control diff --git a/tests/workspace/workspace_crud.rs b/tests/workspace/workspace_crud.rs index 8b137891..305f447d 100644 --- a/tests/workspace/workspace_crud.rs +++ b/tests/workspace/workspace_crud.rs @@ -1 +1,17 @@ +use crate::user::utils::generate_unique_registered_user_client; +#[tokio::test] +async fn add_and_delete_workspace_for_user() { + let (c, _user) = generate_unique_registered_user_client().await; + let workspaces = c.get_workspaces().await.unwrap(); + assert_eq!(workspaces.0.len(), 1); + let newly_addad_workspace = c.add_workspace().await.unwrap(); + let workspaces = c.get_workspaces().await.unwrap(); + assert_eq!(workspaces.0.len(), 2); + + c.delete_workspace(&newly_addad_workspace.workspace_id.to_string()) + .await + .unwrap(); + let workspaces = c.get_workspaces().await.unwrap(); + assert_eq!(workspaces.0.len(), 1); +}