From f3010febdc3f3e566af1866a6bdef733ea14ccb0 Mon Sep 17 00:00:00 2001 From: Dreaded_X Date: Wed, 19 Mar 2025 01:39:33 +0100 Subject: [PATCH] Improved get/create user --- queries/src/lib.rs | 48 ++++++++++++------- ...ueries__tests__create_user_gql_output.snap | 3 ++ .../queries__tests__get_user_gql_output.snap | 12 +++++ ...queries__tests__list_users_gql_output.snap | 9 ---- src/lldap.rs | 32 ++++++------- src/resources.rs | 24 +++++++--- 6 files changed, 78 insertions(+), 50 deletions(-) create mode 100644 queries/src/snapshots/queries__tests__get_user_gql_output.snap delete mode 100644 queries/src/snapshots/queries__tests__list_users_gql_output.snap diff --git a/queries/src/lib.rs b/queries/src/lib.rs index b235a35..3c3ccf6 100644 --- a/queries/src/lib.rs +++ b/queries/src/lib.rs @@ -1,17 +1,6 @@ #[cynic::schema("lldap")] pub(crate) mod schema {} -#[derive(cynic::QueryFragment, Debug)] -#[cynic(graphql_type = "Query")] -pub struct ListUsers { - pub users: Vec, -} - -#[derive(cynic::QueryFragment, Debug)] -pub struct User { - pub id: String, -} - #[derive(cynic::QueryVariables, Debug)] pub struct DeleteUserVariables<'a> { pub id: &'a str, @@ -54,19 +43,35 @@ pub struct AddUserToGroup { pub add_user_to_group: Success, } +#[derive(cynic::QueryVariables, Debug)] +pub struct GetUserVariables<'a> { + pub id: &'a str, +} + +#[derive(cynic::QueryFragment, Debug)] +#[cynic(graphql_type = "Query", variables = "GetUserVariables")] +pub struct GetUser { + #[arguments(userId: $id)] + pub user: User, +} + +#[derive(cynic::QueryFragment, Debug)] +pub struct User { + pub id: String, + pub groups: Vec, +} + +#[derive(cynic::QueryFragment, Debug)] +pub struct Group { + pub id: i32, +} + #[cfg(test)] mod tests { use super::*; use cynic::MutationBuilder; use cynic::QueryBuilder; - #[test] - fn list_users_gql_output() { - let operation = ListUsers::build(()); - - insta::assert_snapshot!(operation.query); - } - #[test] fn delete_user_gql_output() { let operation = DeleteUser::build(DeleteUserVariables { id: "user" }); @@ -90,4 +95,11 @@ mod tests { insta::assert_snapshot!(operation.query); } + + #[test] + fn get_user_gql_output() { + let operation = GetUser::build(GetUserVariables { id: "user" }); + + insta::assert_snapshot!(operation.query); + } } diff --git a/queries/src/snapshots/queries__tests__create_user_gql_output.snap b/queries/src/snapshots/queries__tests__create_user_gql_output.snap index dc0ac01..8d48eb3 100644 --- a/queries/src/snapshots/queries__tests__create_user_gql_output.snap +++ b/queries/src/snapshots/queries__tests__create_user_gql_output.snap @@ -5,5 +5,8 @@ expression: operation.query mutation CreateUser($id: String!) { createUser(user: {email: $id, id: $id}) { id + groups { + id + } } } diff --git a/queries/src/snapshots/queries__tests__get_user_gql_output.snap b/queries/src/snapshots/queries__tests__get_user_gql_output.snap new file mode 100644 index 0000000..8344680 --- /dev/null +++ b/queries/src/snapshots/queries__tests__get_user_gql_output.snap @@ -0,0 +1,12 @@ +--- +source: queries/src/lib.rs +expression: operation.query +--- +query GetUser($id: String!) { + user(userId: $id) { + id + groups { + id + } + } +} diff --git a/queries/src/snapshots/queries__tests__list_users_gql_output.snap b/queries/src/snapshots/queries__tests__list_users_gql_output.snap deleted file mode 100644 index 16b8585..0000000 --- a/queries/src/snapshots/queries__tests__list_users_gql_output.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: queries/src/lib.rs -expression: operation.query ---- -query ListUsers { - users { - id - } -} diff --git a/src/lldap.rs b/src/lldap.rs index f6918ad..81704d4 100644 --- a/src/lldap.rs +++ b/src/lldap.rs @@ -9,7 +9,10 @@ use tracing::debug; use cynic::http::{CynicReqwestError, ReqwestExt}; use cynic::{GraphQlError, GraphQlResponse, MutationBuilder, QueryBuilder}; use lldap_auth::login::{ClientSimpleLoginRequest, ServerLoginResponse}; -use queries::{CreateUser, CreateUserVariables, DeleteUser, DeleteUserVariables, ListUsers}; +use queries::{ + CreateUser, CreateUserVariables, DeleteUser, DeleteUserVariables, GetUser, GetUserVariables, + User, +}; #[derive(thiserror::Error, Debug)] pub enum Error { @@ -25,14 +28,16 @@ pub enum Error { pub type Result = std::result::Result; -fn check_graphql_errors(response: &GraphQlResponse) -> Result<()> { +fn check_graphql_errors(response: GraphQlResponse) -> Result { if let Some(errors) = &response.errors { if !errors.is_empty() { Err(errors.first().expect("Should not be empty").clone())?; } } - Ok(()) + Ok(response + .data + .expect("Data should be valid if there are no error")) } pub struct LldapConfig { @@ -95,25 +100,18 @@ pub struct LldapClient { } impl LldapClient { - pub async fn list_users(&self) -> Result> { - let operation = ListUsers::build(()); + pub async fn get_user(&self, username: &str) -> Result { + let operation = GetUser::build(GetUserVariables { id: username }); let response = self .client .post(format!("{}/api/graphql", self.url)) .run_graphql(operation) .await?; - check_graphql_errors(&response)?; - - Ok(response - .data - .expect("Data should be valid if there are no error") - .users - .into_iter() - .map(|user| user.id)) + Ok(check_graphql_errors(response)?.user) } - pub async fn create_user(&self, username: &str) -> Result<()> { + pub async fn create_user(&self, username: &str) -> Result { let operation = CreateUser::build(CreateUserVariables { id: username }); let response = self @@ -122,7 +120,7 @@ impl LldapClient { .run_graphql(operation) .await?; - check_graphql_errors(&response) + Ok(check_graphql_errors(response)?.create_user) } pub async fn delete_user(&self, username: &str) -> Result<()> { @@ -134,7 +132,9 @@ impl LldapClient { .run_graphql(operation) .await?; - check_graphql_errors(&response) + check_graphql_errors(response)?; + + Ok(()) } pub async fn update_password(&self, username: &str, password: &str) -> Result<()> { diff --git a/src/resources.rs b/src/resources.rs index 4a90ca4..904b9e9 100644 --- a/src/resources.rs +++ b/src/resources.rs @@ -199,14 +199,24 @@ impl Reconcile for ServiceUser { let lldap_client = ctx.lldap_config.build_client().await?; trace!(name, "Creating user if needed"); - if lldap_client.list_users().await?.any(|id| id == username) { - debug!(name, username, "User already exists"); - } else { - debug!(name, username, "Creating new user"); + let _user = match lldap_client.get_user(&username).await { + Err(lldap::Error::GraphQl(err)) + if err.message == format!("Entity not found: `{username}`") => + { + debug!(name, username, "Creating new user"); - lldap_client.create_user(&username).await?; - ctx.recorder.user_created(self.as_ref(), &username).await?; - } + let user = lldap_client.create_user(&username).await?; + ctx.recorder.user_created(self.as_ref(), &username).await?; + + Ok(user) + } + Ok(user) => { + debug!(name, username, "User already exists"); + + Ok(user) + } + Err(err) => Err(err), + }?; trace!(name, "Updating password"); let password = secret.get().data.as_ref().unwrap().get("password").unwrap();