mirror of
https://github.com/lldap/lldap.git
synced 2024-11-25 09:06:03 +00:00
graphql: Add a method to update a user
This commit is contained in:
parent
0ac9e134de
commit
2954109d96
7 changed files with 101 additions and 8 deletions
|
@ -1,4 +1,4 @@
|
|||
mutation CreateUser($user: UserInput!) {
|
||||
mutation CreateUser($user: CreateUserInput!) {
|
||||
createUser(user: $user) {
|
||||
id
|
||||
creationDate
|
||||
|
|
|
@ -46,7 +46,7 @@ impl CreateUserForm {
|
|||
match msg {
|
||||
Msg::SubmitForm => {
|
||||
let req = create_user::Variables {
|
||||
user: create_user::UserInput {
|
||||
user: create_user::CreateUserInput {
|
||||
id: get_element("username")
|
||||
.filter(not_empty)
|
||||
.ok_or_else(|| anyhow!("Missing username"))?,
|
||||
|
|
|
@ -4,7 +4,8 @@ input EqualityConstraint {
|
|||
}
|
||||
|
||||
type Mutation {
|
||||
createUser(user: UserInput!): User!
|
||||
createUser(user: CreateUserInput!): User!
|
||||
updateUser(user: UpdateUserInput!): Success!
|
||||
}
|
||||
|
||||
type Group {
|
||||
|
@ -28,7 +29,7 @@ input RequestFilter {
|
|||
scalar DateTimeUtc
|
||||
|
||||
"The details required to create a user."
|
||||
input UserInput {
|
||||
input CreateUserInput {
|
||||
id: String!
|
||||
email: String!
|
||||
displayName: String
|
||||
|
@ -53,6 +54,19 @@ type User {
|
|||
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 {
|
||||
query: Query
|
||||
mutation: Mutation
|
||||
|
|
|
@ -59,6 +59,16 @@ pub struct CreateUserRequest {
|
|||
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]
|
||||
pub trait LoginHandler: Clone + Send {
|
||||
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 get_user_details(&self, user_id: &str) -> Result<User>;
|
||||
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 create_group(&self, group_name: &str) -> Result<GroupId>;
|
||||
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 get_user_details(&self, user_id: &str) -> Result<User>;
|
||||
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 create_group(&self, group_name: &str) -> Result<GroupId>;
|
||||
async fn get_user_groups(&self, user: &str) -> Result<HashSet<String>>;
|
||||
|
|
|
@ -193,6 +193,31 @@ impl BackendHandler for SqlBackendHandler {
|
|||
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<()> {
|
||||
let delete_query = Query::delete()
|
||||
.from_table(Users::Table)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::domain::handler::{BackendHandler, CreateUserRequest};
|
||||
use juniper::{graphql_object, FieldResult, GraphQLInputObject};
|
||||
use crate::domain::handler::{BackendHandler, CreateUserRequest, UpdateUserRequest};
|
||||
use juniper::{graphql_object, FieldResult, GraphQLInputObject, GraphQLObject};
|
||||
|
||||
use super::api::Context;
|
||||
|
||||
|
@ -19,7 +19,7 @@ impl<Handler: BackendHandler> Mutation<Handler> {
|
|||
|
||||
#[derive(PartialEq, Eq, Debug, GraphQLInputObject)]
|
||||
/// The details required to create a user.
|
||||
pub struct UserInput {
|
||||
pub struct CreateUserInput {
|
||||
id: String,
|
||||
email: String,
|
||||
display_name: Option<String>,
|
||||
|
@ -27,11 +27,32 @@ pub struct UserInput {
|
|||
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>)]
|
||||
impl<Handler: BackendHandler + Sync> Mutation<Handler> {
|
||||
async fn create_user(
|
||||
context: &Context<Handler>,
|
||||
user: UserInput,
|
||||
user: CreateUserInput,
|
||||
) -> FieldResult<super::query::User<Handler>> {
|
||||
if !context.validation_result.is_admin {
|
||||
return Err("Unauthorized user creation".into());
|
||||
|
@ -52,4 +73,24 @@ impl<Handler: BackendHandler + Sync> Mutation<Handler> {
|
|||
.await
|
||||
.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_groups(&self, user: &str) -> DomainResult<HashSet<String>>;
|
||||
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 create_group(&self, group_name: &str) -> DomainResult<GroupId>;
|
||||
async fn add_user_to_group(&self, user_id: &str, group_id: GroupId) -> DomainResult<()>;
|
||||
|
|
Loading…
Reference in a new issue