From 459f1eba19c8bc8f766aa85a3d2492402c9b5a4a Mon Sep 17 00:00:00 2001 From: Valentin Tolmer Date: Mon, 30 Aug 2021 09:28:27 +0200 Subject: [PATCH] graphql: add an endpoint to create a user --- schema.graphql | 14 +++++++++ src/infra/graphql/api.rs | 14 ++++----- src/infra/graphql/mod.rs | 1 + src/infra/graphql/mutation.rs | 56 +++++++++++++++++++++++++++++++++++ src/infra/graphql/query.rs | 2 +- 5 files changed, 77 insertions(+), 10 deletions(-) create mode 100644 src/infra/graphql/mutation.rs diff --git a/schema.graphql b/schema.graphql index eea8f9f..36bcf11 100644 --- a/schema.graphql +++ b/schema.graphql @@ -3,6 +3,10 @@ input EqualityConstraint { value: String! } +type Mutation { + createUser(user: UserInput!): User! +} + type Group { id: String! "The groups to which this user belongs." @@ -23,6 +27,15 @@ input RequestFilter { "DateTime" scalar DateTimeUtc +"The details required to create a user." +input UserInput { + id: String! + email: String! + displayName: String + firstName: String + lastName: String +} + type Query { apiVersion: String! user(userId: String!): User! @@ -42,4 +55,5 @@ type User { schema { query: Query + mutation: Mutation } diff --git a/src/infra/graphql/api.rs b/src/infra/graphql/api.rs index 3396c68..f42c081 100644 --- a/src/infra/graphql/api.rs +++ b/src/infra/graphql/api.rs @@ -8,10 +8,10 @@ use crate::{ }; use actix_web::{web, Error, HttpResponse}; 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 super::query::Query; +use super::{mutation::Mutation, query::Query}; pub struct Context { pub handler: Box, @@ -20,17 +20,13 @@ pub struct Context { impl juniper::Context for Context {} -type Schema = RootNode< - 'static, - Query, - EmptyMutation>, - EmptySubscription>, ->; +type Schema = + RootNode<'static, Query, Mutation, EmptySubscription>>; fn schema() -> Schema { Schema::new( Query::::new(), - EmptyMutation::>::new(), + Mutation::::new(), EmptySubscription::>::new(), ) } diff --git a/src/infra/graphql/mod.rs b/src/infra/graphql/mod.rs index 1ff2efd..2e39989 100644 --- a/src/infra/graphql/mod.rs +++ b/src/infra/graphql/mod.rs @@ -1,2 +1,3 @@ pub mod api; +pub mod mutation; pub mod query; diff --git a/src/infra/graphql/mutation.rs b/src/infra/graphql/mutation.rs new file mode 100644 index 0000000..717c72e --- /dev/null +++ b/src/infra/graphql/mutation.rs @@ -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 { + _phantom: std::marker::PhantomData>, +} + +impl Mutation { + 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, + first_name: Option, + last_name: Option, +} + +#[graphql_object(context = Context)] +impl Mutation { + async fn create_user( + context: &Context, + user: UserInput, + ) -> FieldResult> { + 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)?) + } +} diff --git a/src/infra/graphql/query.rs b/src/infra/graphql/query.rs index 5ea5c78..870f53b 100644 --- a/src/infra/graphql/query.rs +++ b/src/infra/graphql/query.rs @@ -88,7 +88,7 @@ impl Query { "1.0" } - async fn user(context: &Context, user_id: String) -> FieldResult> { + pub async fn user(context: &Context, user_id: String) -> FieldResult> { if !context.validation_result.can_access(&user_id) { return Err("Unauthorized access to user data".into()); }