From f25066f51f770e38cb01ed1b3c01c4929c4a6ceb Mon Sep 17 00:00:00 2001 From: Zack Fu Zi Xiang Date: Thu, 12 Sep 2024 15:10:48 +0800 Subject: [PATCH] feat: add get invitation by id --- ...e111d06e327edd9f3a98a4b0636bfe8fd6319.json | 59 +++++++++++++++++++ libs/client-api/src/http_member.rs | 16 ++++- libs/database/src/workspace.rs | 27 +++++++++ src/api/workspace.rs | 15 +++++ src/biz/workspace/ops.rs | 9 +++ tests/workspace/invitation_crud.rs | 17 ++++-- 6 files changed, 136 insertions(+), 7 deletions(-) create mode 100644 .sqlx/query-6dd7f6db2d364cc37b1b46c611fe111d06e327edd9f3a98a4b0636bfe8fd6319.json diff --git a/.sqlx/query-6dd7f6db2d364cc37b1b46c611fe111d06e327edd9f3a98a4b0636bfe8fd6319.json b/.sqlx/query-6dd7f6db2d364cc37b1b46c611fe111d06e327edd9f3a98a4b0636bfe8fd6319.json new file mode 100644 index 00000000..6c269e95 --- /dev/null +++ b/.sqlx/query-6dd7f6db2d364cc37b1b46c611fe111d06e327edd9f3a98a4b0636bfe8fd6319.json @@ -0,0 +1,59 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n id AS invite_id,\n workspace_id,\n (SELECT workspace_name FROM public.af_workspace WHERE workspace_id = af_workspace_invitation.workspace_id),\n (SELECT email FROM public.af_user WHERE uid = af_workspace_invitation.inviter) AS inviter_email,\n (SELECT name FROM public.af_user WHERE uid = af_workspace_invitation.inviter) AS inviter_name,\n status,\n updated_at\n FROM public.af_workspace_invitation\n WHERE af_workspace_invitation.invitee_email = (SELECT email FROM public.af_user WHERE uuid = $1)\n AND id = $2\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "invite_id", + "type_info": "Uuid" + }, + { + "ordinal": 1, + "name": "workspace_id", + "type_info": "Uuid" + }, + { + "ordinal": 2, + "name": "workspace_name", + "type_info": "Text" + }, + { + "ordinal": 3, + "name": "inviter_email", + "type_info": "Text" + }, + { + "ordinal": 4, + "name": "inviter_name", + "type_info": "Text" + }, + { + "ordinal": 5, + "name": "status", + "type_info": "Int2" + }, + { + "ordinal": 6, + "name": "updated_at", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "Uuid", + "Uuid" + ] + }, + "nullable": [ + false, + false, + null, + null, + null, + false, + false + ] + }, + "hash": "6dd7f6db2d364cc37b1b46c611fe111d06e327edd9f3a98a4b0636bfe8fd6319" +} diff --git a/libs/client-api/src/http_member.rs b/libs/client-api/src/http_member.rs index b198e9bf..350b1070 100644 --- a/libs/client-api/src/http_member.rs +++ b/libs/client-api/src/http_member.rs @@ -65,7 +65,6 @@ impl Client { Ok(()) } - #[instrument(level = "info", skip_all, err)] pub async fn list_workspace_invitations( &self, status: Option, @@ -81,6 +80,21 @@ impl Client { res.into_data() } + pub async fn get_workspace_invitation( + &self, + invite_uuid: &str, + ) -> Result { + let url = format!("{}/api/workspace/invite/{}", self.base_url, invite_uuid); + let resp = self + .http_client_with_auth(Method::GET, &url) + .await? + .send() + .await?; + log_request_id(&resp); + let res: AppResponse = AppResponse::from_response(resp).await?; + res.into_data() + } + pub async fn accept_workspace_invitation( &self, invitation_id: &str, diff --git a/libs/database/src/workspace.rs b/libs/database/src/workspace.rs index 8b0d5427..85d2e692 100644 --- a/libs/database/src/workspace.rs +++ b/libs/database/src/workspace.rs @@ -428,6 +428,33 @@ pub async fn select_workspace_invitations_for_user( Ok(res) } +#[inline] +pub async fn select_workspace_invitation_for_user( + pg_pool: &PgPool, + invitee_uuid: &Uuid, + invite_id: &Uuid, +) -> Result { + let res = sqlx::query_as!( + AFWorkspaceInvitation, + r#" + SELECT + id AS invite_id, + workspace_id, + (SELECT workspace_name FROM public.af_workspace WHERE workspace_id = af_workspace_invitation.workspace_id), + (SELECT email FROM public.af_user WHERE uid = af_workspace_invitation.inviter) AS inviter_email, + (SELECT name FROM public.af_user WHERE uid = af_workspace_invitation.inviter) AS inviter_name, + status, + updated_at + FROM public.af_workspace_invitation + WHERE af_workspace_invitation.invitee_email = (SELECT email FROM public.af_user WHERE uuid = $1) + AND id = $2 + "#, + invitee_uuid, + invite_id, + ).fetch_one(pg_pool).await?; + Ok(res) +} + #[inline] #[instrument(level = "trace", skip(pool, email, role), err)] pub async fn upsert_workspace_member( diff --git a/src/api/workspace.rs b/src/api/workspace.rs index 08655e1d..c0088970 100644 --- a/src/api/workspace.rs +++ b/src/api/workspace.rs @@ -74,6 +74,9 @@ pub fn workspace_scope() -> Scope { .service( web::resource("/invite").route(web::get().to(get_workspace_invite_handler)), // show invites for user ) + .service( + web::resource("/invite/{invite_id}").route(web::get().to(get_workspace_invite_by_id_handler)), + ) .service( web::resource("/accept-invite/{invite_id}") .route(web::post().to(post_accept_workspace_invite_handler)), // accept invitation to workspace @@ -308,6 +311,18 @@ async fn get_workspace_invite_handler( Ok(AppResponse::Ok().with_data(res).into()) } +async fn get_workspace_invite_by_id_handler( + user_uuid: UserUuid, + state: Data, + invite_id: web::Path, +) -> Result> { + let invite_id = invite_id.into_inner(); + let res = + workspace::ops::get_workspace_invitations_for_user(&state.pg_pool, &user_uuid, &invite_id) + .await?; + Ok(AppResponse::Ok().with_data(res).into()) +} + async fn post_accept_workspace_invite_handler( user_uuid: UserUuid, invite_id: web::Path, diff --git a/src/biz/workspace/ops.rs b/src/biz/workspace/ops.rs index d3f4b804..e4d01ea6 100644 --- a/src/biz/workspace/ops.rs +++ b/src/biz/workspace/ops.rs @@ -450,6 +450,15 @@ pub async fn list_workspace_invitations_for_user( Ok(invis) } +pub async fn get_workspace_invitations_for_user( + pg_pool: &PgPool, + user_uuid: &Uuid, + invite_id: &Uuid, +) -> Result { + let invitation = select_workspace_invitation_for_user(pg_pool, user_uuid, invite_id).await?; + Ok(invitation) +} + // use in tests only pub async fn add_workspace_members_db_only( pg_pool: &PgPool, diff --git a/tests/workspace/invitation_crud.rs b/tests/workspace/invitation_crud.rs index 73a832a9..ee78293a 100644 --- a/tests/workspace/invitation_crud.rs +++ b/tests/workspace/invitation_crud.rs @@ -4,7 +4,7 @@ use shared_entity::dto::workspace_dto::{QueryWorkspaceParam, WorkspaceMemberInvi #[tokio::test] async fn invite_workspace_crud() { - let (alice_client, _alice) = generate_unique_registered_user_client().await; + let (alice_client, alice) = generate_unique_registered_user_client().await; let alice_workspace_id = alice_client .get_workspaces() .await @@ -49,14 +49,19 @@ async fn invite_workspace_crud() { .await .unwrap(); assert_eq!(pending_invs.len(), 1); + let invite_id = pending_invs.first().unwrap().invite_id.to_string(); - // accept invitation - let target_invite = pending_invs - .iter() - .find(|i| i.workspace_id == alice_workspace_id) + // get invitation by id + let invitation = bob_client + .get_workspace_invitation(&invite_id) + .await .unwrap(); + + assert_eq!(invitation.workspace_id, alice_workspace_id); + assert_eq!(invitation.inviter_email, Some(alice.email)); + bob_client - .accept_workspace_invitation(target_invite.invite_id.to_string().as_str()) + .accept_workspace_invitation(&invite_id) .await .unwrap();