From 1fbf60bf5db209ff1d1d925f9f1251465ad5c305 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Wed, 19 Apr 2023 17:12:39 +0200 Subject: [PATCH] WIP: start GraphQL mutations --- Cargo.lock | 1 + crates/graphql/Cargo.toml | 1 + crates/graphql/src/lib.rs | 1 + crates/graphql/src/mutations.rs | 68 +++++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+) create mode 100644 crates/graphql/src/mutations.rs diff --git a/Cargo.lock b/Cargo.lock index 6a7a54d4..0aa63eab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3256,6 +3256,7 @@ dependencies = [ "mas-data-model", "mas-storage", "oauth2-types", + "rand_chacha 0.3.1", "serde", "thiserror", "tokio", diff --git a/crates/graphql/Cargo.toml b/crates/graphql/Cargo.toml index 74aa5a0a..6823e104 100644 --- a/crates/graphql/Cargo.toml +++ b/crates/graphql/Cargo.toml @@ -15,6 +15,7 @@ thiserror = "1.0.40" tracing = "0.1.37" ulid = "1.0.0" url = "2.3.1" +rand_chacha = "0.3.1" oauth2-types = { path = "../oauth2-types" } mas-data-model = { path = "../data-model" } diff --git a/crates/graphql/src/lib.rs b/crates/graphql/src/lib.rs index ca374565..90ce84e9 100644 --- a/crates/graphql/src/lib.rs +++ b/crates/graphql/src/lib.rs @@ -45,6 +45,7 @@ use self::model::{ }; mod model; +mod mutations; pub type Schema = async_graphql::Schema; pub type SchemaBuilder = async_graphql::SchemaBuilder; diff --git a/crates/graphql/src/mutations.rs b/crates/graphql/src/mutations.rs new file mode 100644 index 00000000..b84e3a48 --- /dev/null +++ b/crates/graphql/src/mutations.rs @@ -0,0 +1,68 @@ +// Copyright 2023 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use async_graphql::{Context, Object, ID}; +use mas_storage::{ + job::{JobRepositoryExt, VerifyEmailJob}, + user::UserEmailRepository, + BoxClock, BoxRepository, BoxRng, RepositoryAccess, SystemClock, +}; +use rand_chacha::{rand_core::SeedableRng, ChaChaRng}; +use tokio::sync::Mutex; + +use crate::model::{NodeType, UserEmail}; + +struct RootMutations; + +fn clock_and_rng() -> (BoxClock, BoxRng) { + // XXX: this should be moved somewhere else + let clock = SystemClock::default(); + let rng = ChaChaRng::from_entropy(); + (Box::new(clock), Box::new(rng)) +} + +#[Object] +impl RootMutations { + async fn add_email( + &self, + ctx: &Context<'_>, + email: String, + user_id: ID, + ) -> Result { + let id = NodeType::User.extract_ulid(&user_id)?; + let session = ctx.data_opt::().cloned(); + let (clock, mut rng) = clock_and_rng(); + let mut repo = ctx.data::>()?.lock().await; + + let Some(session) = session else { + return Err(async_graphql::Error::new("Unauthorized")); + }; + + if session.user.id != id { + return Err(async_graphql::Error::new("Unauthorized")); + } + + let user_email = repo + .user_email() + .add(&mut rng, &clock, &session.user, email) + .await?; + + repo.job() + .schedule_job(VerifyEmailJob::new(&user_email)) + .await?; + // TODO: how do we save the transaction here? + + Ok(UserEmail(user_email)) + } +}