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
0ac9e134de
commit
2954109d96
@ -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