graphql: add an endpoint to create a user

This commit is contained in:
Valentin Tolmer 2021-08-30 09:28:27 +02:00 committed by nitnelave
parent dd7e9c9283
commit 459f1eba19
5 changed files with 77 additions and 10 deletions

View File

@ -3,6 +3,10 @@ input EqualityConstraint {
value: String! value: String!
} }
type Mutation {
createUser(user: UserInput!): User!
}
type Group { type Group {
id: String! id: String!
"The groups to which this user belongs." "The groups to which this user belongs."
@ -23,6 +27,15 @@ input RequestFilter {
"DateTime" "DateTime"
scalar DateTimeUtc scalar DateTimeUtc
"The details required to create a user."
input UserInput {
id: String!
email: String!
displayName: String
firstName: String
lastName: String
}
type Query { type Query {
apiVersion: String! apiVersion: String!
user(userId: String!): User! user(userId: String!): User!
@ -42,4 +55,5 @@ type User {
schema { schema {
query: Query query: Query
mutation: Mutation
} }

View File

@ -8,10 +8,10 @@ use crate::{
}; };
use actix_web::{web, Error, HttpResponse}; use actix_web::{web, Error, HttpResponse};
use actix_web_httpauth::extractors::bearer::BearerAuth; use actix_web_httpauth::extractors::bearer::BearerAuth;
use juniper::{EmptyMutation, EmptySubscription, RootNode}; use juniper::{EmptySubscription, RootNode};
use juniper_actix::{graphiql_handler, graphql_handler, playground_handler}; use juniper_actix::{graphiql_handler, graphql_handler, playground_handler};
use super::query::Query; use super::{mutation::Mutation, query::Query};
pub struct Context<Handler: BackendHandler> { pub struct Context<Handler: BackendHandler> {
pub handler: Box<Handler>, pub handler: Box<Handler>,
@ -20,17 +20,13 @@ pub struct Context<Handler: BackendHandler> {
impl<Handler: BackendHandler> juniper::Context for Context<Handler> {} impl<Handler: BackendHandler> juniper::Context for Context<Handler> {}
type Schema<Handler> = RootNode< type Schema<Handler> =
'static, RootNode<'static, Query<Handler>, Mutation<Handler>, EmptySubscription<Context<Handler>>>;
Query<Handler>,
EmptyMutation<Context<Handler>>,
EmptySubscription<Context<Handler>>,
>;
fn schema<Handler: BackendHandler + Sync>() -> Schema<Handler> { fn schema<Handler: BackendHandler + Sync>() -> Schema<Handler> {
Schema::new( Schema::new(
Query::<Handler>::new(), Query::<Handler>::new(),
EmptyMutation::<Context<Handler>>::new(), Mutation::<Handler>::new(),
EmptySubscription::<Context<Handler>>::new(), EmptySubscription::<Context<Handler>>::new(),
) )
} }

View File

@ -1,2 +1,3 @@
pub mod api; pub mod api;
pub mod mutation;
pub mod query; pub mod query;

View File

@ -0,0 +1,56 @@
use crate::domain::handler::BackendHandler;
use juniper::{graphql_object, FieldResult, GraphQLInputObject};
use lldap_model::UserDetailsRequest;
use super::api::Context;
#[derive(PartialEq, Eq, Debug)]
/// The top-level GraphQL mutation type.
pub struct Mutation<Handler: BackendHandler> {
_phantom: std::marker::PhantomData<Box<Handler>>,
}
impl<Handler: BackendHandler> Mutation<Handler> {
pub fn new() -> Self {
Self {
_phantom: std::marker::PhantomData,
}
}
}
#[derive(PartialEq, Eq, Debug, GraphQLInputObject)]
/// The details required to create a user.
pub struct UserInput {
id: String,
email: String,
display_name: Option<String>,
first_name: Option<String>,
last_name: Option<String>,
}
#[graphql_object(context = Context<Handler>)]
impl<Handler: BackendHandler + Sync> Mutation<Handler> {
async fn create_user(
context: &Context<Handler>,
user: UserInput,
) -> FieldResult<super::query::User<Handler>> {
if !context.validation_result.is_admin {
return Err("Unauthorized user creation".into());
}
context
.handler
.create_user(lldap_model::CreateUserRequest {
user_id: user.id.clone(),
email: user.email,
display_name: user.display_name,
first_name: user.first_name,
last_name: user.last_name,
})
.await?;
Ok(context
.handler
.get_user_details(UserDetailsRequest { user_id: user.id })
.await
.map(Into::into)?)
}
}

View File

@ -88,7 +88,7 @@ impl<Handler: BackendHandler + Sync> Query<Handler> {
"1.0" "1.0"
} }
async fn user(context: &Context<Handler>, user_id: String) -> FieldResult<User<Handler>> { pub async fn user(context: &Context<Handler>, user_id: String) -> FieldResult<User<Handler>> {
if !context.validation_result.can_access(&user_id) { if !context.validation_result.can_access(&user_id) {
return Err("Unauthorized access to user data".into()); return Err("Unauthorized access to user data".into());
} }