mirror of
				https://github.com/nitnelave/lldap.git
				synced 2023-04-12 14:25:13 +00:00 
			
		
		
		
	graphql: Add a method to update a user
This commit is contained in:
		
							parent
							
								
									10312cdc6f
								
							
						
					
					
						commit
						900836fbdb
					
				@ -1,4 +1,4 @@
 | 
				
			|||||||
mutation CreateUser($user: UserInput!) {
 | 
					mutation CreateUser($user: CreateUserInput!) {
 | 
				
			||||||
  createUser(user: $user) {
 | 
					  createUser(user: $user) {
 | 
				
			||||||
    id
 | 
					    id
 | 
				
			||||||
    creationDate
 | 
					    creationDate
 | 
				
			||||||
 | 
				
			|||||||
@ -46,7 +46,7 @@ impl CreateUserForm {
 | 
				
			|||||||
        match msg {
 | 
					        match msg {
 | 
				
			||||||
            Msg::SubmitForm => {
 | 
					            Msg::SubmitForm => {
 | 
				
			||||||
                let req = create_user::Variables {
 | 
					                let req = create_user::Variables {
 | 
				
			||||||
                    user: create_user::UserInput {
 | 
					                    user: create_user::CreateUserInput {
 | 
				
			||||||
                        id: get_element("username")
 | 
					                        id: get_element("username")
 | 
				
			||||||
                            .filter(not_empty)
 | 
					                            .filter(not_empty)
 | 
				
			||||||
                            .ok_or_else(|| anyhow!("Missing username"))?,
 | 
					                            .ok_or_else(|| anyhow!("Missing username"))?,
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,8 @@ input EqualityConstraint {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Mutation {
 | 
					type Mutation {
 | 
				
			||||||
  createUser(user: UserInput!): User!
 | 
					  createUser(user: CreateUserInput!): User!
 | 
				
			||||||
 | 
					  updateUser(user: UpdateUserInput!): Success!
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Group {
 | 
					type Group {
 | 
				
			||||||
@ -28,7 +29,7 @@ input RequestFilter {
 | 
				
			|||||||
scalar DateTimeUtc
 | 
					scalar DateTimeUtc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"The details required to create a user."
 | 
					"The details required to create a user."
 | 
				
			||||||
input UserInput {
 | 
					input CreateUserInput {
 | 
				
			||||||
  id: String!
 | 
					  id: String!
 | 
				
			||||||
  email: String!
 | 
					  email: String!
 | 
				
			||||||
  displayName: String
 | 
					  displayName: String
 | 
				
			||||||
@ -53,6 +54,19 @@ type User {
 | 
				
			|||||||
  groups: [Group!]!
 | 
					  groups: [Group!]!
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Success {
 | 
				
			||||||
 | 
					  ok: Boolean!
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"The fields that can be updated for a user."
 | 
				
			||||||
 | 
					input UpdateUserInput {
 | 
				
			||||||
 | 
					  id: String!
 | 
				
			||||||
 | 
					  email: String
 | 
				
			||||||
 | 
					  displayName: String
 | 
				
			||||||
 | 
					  firstName: String
 | 
				
			||||||
 | 
					  lastName: String
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
schema {
 | 
					schema {
 | 
				
			||||||
  query: Query
 | 
					  query: Query
 | 
				
			||||||
  mutation: Mutation
 | 
					  mutation: Mutation
 | 
				
			||||||
 | 
				
			|||||||
@ -59,6 +59,16 @@ pub struct CreateUserRequest {
 | 
				
			|||||||
    pub last_name: Option<String>,
 | 
					    pub last_name: Option<String>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone, Default)]
 | 
				
			||||||
 | 
					pub struct UpdateUserRequest {
 | 
				
			||||||
 | 
					    // Same fields as CreateUserRequest, but no with an extra layer of Option.
 | 
				
			||||||
 | 
					    pub user_id: String,
 | 
				
			||||||
 | 
					    pub email: Option<String>,
 | 
				
			||||||
 | 
					    pub display_name: Option<String>,
 | 
				
			||||||
 | 
					    pub first_name: Option<String>,
 | 
				
			||||||
 | 
					    pub last_name: Option<String>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[async_trait]
 | 
					#[async_trait]
 | 
				
			||||||
pub trait LoginHandler: Clone + Send {
 | 
					pub trait LoginHandler: Clone + Send {
 | 
				
			||||||
    async fn bind(&self, request: BindRequest) -> Result<()>;
 | 
					    async fn bind(&self, request: BindRequest) -> Result<()>;
 | 
				
			||||||
@ -73,6 +83,7 @@ pub trait BackendHandler: Clone + Send {
 | 
				
			|||||||
    async fn list_groups(&self) -> Result<Vec<Group>>;
 | 
					    async fn list_groups(&self) -> Result<Vec<Group>>;
 | 
				
			||||||
    async fn get_user_details(&self, user_id: &str) -> Result<User>;
 | 
					    async fn get_user_details(&self, user_id: &str) -> Result<User>;
 | 
				
			||||||
    async fn create_user(&self, request: CreateUserRequest) -> Result<()>;
 | 
					    async fn create_user(&self, request: CreateUserRequest) -> Result<()>;
 | 
				
			||||||
 | 
					    async fn update_user(&self, request: UpdateUserRequest) -> Result<()>;
 | 
				
			||||||
    async fn delete_user(&self, user_id: &str) -> Result<()>;
 | 
					    async fn delete_user(&self, user_id: &str) -> Result<()>;
 | 
				
			||||||
    async fn create_group(&self, group_name: &str) -> Result<GroupId>;
 | 
					    async fn create_group(&self, group_name: &str) -> Result<GroupId>;
 | 
				
			||||||
    async fn add_user_to_group(&self, user_id: &str, group_id: GroupId) -> Result<()>;
 | 
					    async fn add_user_to_group(&self, user_id: &str, group_id: GroupId) -> Result<()>;
 | 
				
			||||||
@ -91,6 +102,7 @@ mockall::mock! {
 | 
				
			|||||||
        async fn list_groups(&self) -> Result<Vec<Group>>;
 | 
					        async fn list_groups(&self) -> Result<Vec<Group>>;
 | 
				
			||||||
        async fn get_user_details(&self, user_id: &str) -> Result<User>;
 | 
					        async fn get_user_details(&self, user_id: &str) -> Result<User>;
 | 
				
			||||||
        async fn create_user(&self, request: CreateUserRequest) -> Result<()>;
 | 
					        async fn create_user(&self, request: CreateUserRequest) -> Result<()>;
 | 
				
			||||||
 | 
					        async fn update_user(&self, request: UpdateUserRequest) -> Result<()>;
 | 
				
			||||||
        async fn delete_user(&self, user_id: &str) -> Result<()>;
 | 
					        async fn delete_user(&self, user_id: &str) -> Result<()>;
 | 
				
			||||||
        async fn create_group(&self, group_name: &str) -> Result<GroupId>;
 | 
					        async fn create_group(&self, group_name: &str) -> Result<GroupId>;
 | 
				
			||||||
        async fn get_user_groups(&self, user: &str) -> Result<HashSet<String>>;
 | 
					        async fn get_user_groups(&self, user: &str) -> Result<HashSet<String>>;
 | 
				
			||||||
 | 
				
			|||||||
@ -193,6 +193,31 @@ impl BackendHandler for SqlBackendHandler {
 | 
				
			|||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async fn update_user(&self, request: UpdateUserRequest) -> Result<()> {
 | 
				
			||||||
 | 
					        let mut values = Vec::new();
 | 
				
			||||||
 | 
					        if let Some(email) = request.email {
 | 
				
			||||||
 | 
					            values.push((Users::Email, email.into()));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if let Some(display_name) = request.display_name {
 | 
				
			||||||
 | 
					            values.push((Users::DisplayName, display_name.into()));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if let Some(first_name) = request.first_name {
 | 
				
			||||||
 | 
					            values.push((Users::FirstName, first_name.into()));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if let Some(last_name) = request.last_name {
 | 
				
			||||||
 | 
					            values.push((Users::LastName, last_name.into()));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if values.is_empty() {
 | 
				
			||||||
 | 
					            return Ok(());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        let query = Query::update()
 | 
				
			||||||
 | 
					            .table(Users::Table)
 | 
				
			||||||
 | 
					            .values(values)
 | 
				
			||||||
 | 
					            .to_string(DbQueryBuilder {});
 | 
				
			||||||
 | 
					        sqlx::query(&query).execute(&self.sql_pool).await?;
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async fn delete_user(&self, user_id: &str) -> Result<()> {
 | 
					    async fn delete_user(&self, user_id: &str) -> Result<()> {
 | 
				
			||||||
        let delete_query = Query::delete()
 | 
					        let delete_query = Query::delete()
 | 
				
			||||||
            .from_table(Users::Table)
 | 
					            .from_table(Users::Table)
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
use crate::domain::handler::{BackendHandler, CreateUserRequest};
 | 
					use crate::domain::handler::{BackendHandler, CreateUserRequest, UpdateUserRequest};
 | 
				
			||||||
use juniper::{graphql_object, FieldResult, GraphQLInputObject};
 | 
					use juniper::{graphql_object, FieldResult, GraphQLInputObject, GraphQLObject};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::api::Context;
 | 
					use super::api::Context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -19,7 +19,7 @@ impl<Handler: BackendHandler> Mutation<Handler> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[derive(PartialEq, Eq, Debug, GraphQLInputObject)]
 | 
					#[derive(PartialEq, Eq, Debug, GraphQLInputObject)]
 | 
				
			||||||
/// The details required to create a user.
 | 
					/// The details required to create a user.
 | 
				
			||||||
pub struct UserInput {
 | 
					pub struct CreateUserInput {
 | 
				
			||||||
    id: String,
 | 
					    id: String,
 | 
				
			||||||
    email: String,
 | 
					    email: String,
 | 
				
			||||||
    display_name: Option<String>,
 | 
					    display_name: Option<String>,
 | 
				
			||||||
@ -27,11 +27,32 @@ pub struct UserInput {
 | 
				
			|||||||
    last_name: Option<String>,
 | 
					    last_name: Option<String>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(PartialEq, Eq, Debug, GraphQLInputObject)]
 | 
				
			||||||
 | 
					/// The fields that can be updated for a user.
 | 
				
			||||||
 | 
					pub struct UpdateUserInput {
 | 
				
			||||||
 | 
					    id: String,
 | 
				
			||||||
 | 
					    email: Option<String>,
 | 
				
			||||||
 | 
					    display_name: Option<String>,
 | 
				
			||||||
 | 
					    first_name: Option<String>,
 | 
				
			||||||
 | 
					    last_name: Option<String>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(PartialEq, Eq, Debug, GraphQLObject)]
 | 
				
			||||||
 | 
					pub struct Success {
 | 
				
			||||||
 | 
					    ok: bool,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Success {
 | 
				
			||||||
 | 
					    fn new() -> Self {
 | 
				
			||||||
 | 
					        Self { ok: true }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[graphql_object(context = Context<Handler>)]
 | 
					#[graphql_object(context = Context<Handler>)]
 | 
				
			||||||
impl<Handler: BackendHandler + Sync> Mutation<Handler> {
 | 
					impl<Handler: BackendHandler + Sync> Mutation<Handler> {
 | 
				
			||||||
    async fn create_user(
 | 
					    async fn create_user(
 | 
				
			||||||
        context: &Context<Handler>,
 | 
					        context: &Context<Handler>,
 | 
				
			||||||
        user: UserInput,
 | 
					        user: CreateUserInput,
 | 
				
			||||||
    ) -> FieldResult<super::query::User<Handler>> {
 | 
					    ) -> FieldResult<super::query::User<Handler>> {
 | 
				
			||||||
        if !context.validation_result.is_admin {
 | 
					        if !context.validation_result.is_admin {
 | 
				
			||||||
            return Err("Unauthorized user creation".into());
 | 
					            return Err("Unauthorized user creation".into());
 | 
				
			||||||
@ -52,4 +73,24 @@ impl<Handler: BackendHandler + Sync> Mutation<Handler> {
 | 
				
			|||||||
            .await
 | 
					            .await
 | 
				
			||||||
            .map(Into::into)?)
 | 
					            .map(Into::into)?)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async fn update_user(
 | 
				
			||||||
 | 
					        context: &Context<Handler>,
 | 
				
			||||||
 | 
					        user: UpdateUserInput,
 | 
				
			||||||
 | 
					    ) -> FieldResult<Success> {
 | 
				
			||||||
 | 
					        if !context.validation_result.can_access(&user.id) {
 | 
				
			||||||
 | 
					            return Err("Unauthorized user update".into());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        context
 | 
				
			||||||
 | 
					            .handler
 | 
				
			||||||
 | 
					            .update_user(UpdateUserRequest {
 | 
				
			||||||
 | 
					                user_id: user.id,
 | 
				
			||||||
 | 
					                email: user.email,
 | 
				
			||||||
 | 
					                display_name: user.display_name,
 | 
				
			||||||
 | 
					                first_name: user.first_name,
 | 
				
			||||||
 | 
					                last_name: user.last_name,
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .await?;
 | 
				
			||||||
 | 
					        Ok(Success::new())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -31,6 +31,7 @@ mockall::mock! {
 | 
				
			|||||||
        async fn get_user_details(&self, user_id: &str) -> DomainResult<User>;
 | 
					        async fn get_user_details(&self, user_id: &str) -> DomainResult<User>;
 | 
				
			||||||
        async fn get_user_groups(&self, user: &str) -> DomainResult<HashSet<String>>;
 | 
					        async fn get_user_groups(&self, user: &str) -> DomainResult<HashSet<String>>;
 | 
				
			||||||
        async fn create_user(&self, request: CreateUserRequest) -> DomainResult<()>;
 | 
					        async fn create_user(&self, request: CreateUserRequest) -> DomainResult<()>;
 | 
				
			||||||
 | 
					        async fn update_user(&self, request: UpdateUserRequest) -> DomainResult<()>;
 | 
				
			||||||
        async fn delete_user(&self, user_id: &str) -> DomainResult<()>;
 | 
					        async fn delete_user(&self, user_id: &str) -> DomainResult<()>;
 | 
				
			||||||
        async fn create_group(&self, group_name: &str) -> DomainResult<GroupId>;
 | 
					        async fn create_group(&self, group_name: &str) -> DomainResult<GroupId>;
 | 
				
			||||||
        async fn add_user_to_group(&self, user_id: &str, group_id: GroupId) -> DomainResult<()>;
 | 
					        async fn add_user_to_group(&self, user_id: &str, group_id: GroupId) -> DomainResult<()>;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user