1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-08-09 04:22:45 +03:00

Merge the mas_graphql crate into the mas_handlers crate (#2783)

This commit is contained in:
reivilibre
2024-05-17 17:22:34 +01:00
committed by GitHub
parent 37a10aea96
commit 206d45bb31
35 changed files with 199 additions and 278 deletions

26
Cargo.lock generated
View File

@@ -3018,7 +3018,6 @@ dependencies = [
"mas-config", "mas-config",
"mas-data-model", "mas-data-model",
"mas-email", "mas-email",
"mas-graphql",
"mas-handlers", "mas-handlers",
"mas-http", "mas-http",
"mas-i18n", "mas-i18n",
@@ -3125,29 +3124,6 @@ dependencies = [
"tracing", "tracing",
] ]
[[package]]
name = "mas-graphql"
version = "0.9.0"
dependencies = [
"anyhow",
"async-graphql",
"async-trait",
"chrono",
"lettre",
"mas-data-model",
"mas-matrix",
"mas-policy",
"mas-storage",
"oauth2-types",
"serde",
"thiserror",
"tokio",
"tower",
"tracing",
"ulid",
"url",
]
[[package]] [[package]]
name = "mas-handlers" name = "mas-handlers"
version = "0.9.0" version = "0.9.0"
@@ -3155,6 +3131,7 @@ dependencies = [
"anyhow", "anyhow",
"argon2", "argon2",
"async-graphql", "async-graphql",
"async-trait",
"axum", "axum",
"axum-extra", "axum-extra",
"axum-macros", "axum-macros",
@@ -3170,7 +3147,6 @@ dependencies = [
"lettre", "lettre",
"mas-axum-utils", "mas-axum-utils",
"mas-data-model", "mas-data-model",
"mas-graphql",
"mas-http", "mas-http",
"mas-i18n", "mas-i18n",
"mas-iana", "mas-iana",

View File

@@ -57,7 +57,6 @@ sentry-tower = { version = "0.31.8", features = ["http"] }
mas-config.workspace = true mas-config.workspace = true
mas-data-model.workspace = true mas-data-model.workspace = true
mas-email.workspace = true mas-email.workspace = true
mas-graphql.workspace = true
mas-handlers = { workspace = true } mas-handlers = { workspace = true }
mas-http = { workspace = true, features = ["client"] } mas-http = { workspace = true, features = ["client"] }
mas-i18n.workspace = true mas-i18n.workspace = true

View File

@@ -22,7 +22,7 @@ use ipnetwork::IpNetwork;
use mas_data_model::SiteConfig; use mas_data_model::SiteConfig;
use mas_handlers::{ use mas_handlers::{
passwords::PasswordManager, ActivityTracker, BoundActivityTracker, CookieManager, ErrorWrapper, passwords::PasswordManager, ActivityTracker, BoundActivityTracker, CookieManager, ErrorWrapper,
HttpClientFactory, MetadataCache, GraphQLSchema, HttpClientFactory, MetadataCache,
}; };
use mas_i18n::Translator; use mas_i18n::Translator;
use mas_keystore::{Encrypter, Keystore}; use mas_keystore::{Encrypter, Keystore};
@@ -50,7 +50,7 @@ pub struct AppState {
pub url_builder: UrlBuilder, pub url_builder: UrlBuilder,
pub homeserver_connection: SynapseConnection, pub homeserver_connection: SynapseConnection,
pub policy_factory: Arc<PolicyFactory>, pub policy_factory: Arc<PolicyFactory>,
pub graphql_schema: mas_graphql::Schema, pub graphql_schema: GraphQLSchema,
pub http_client_factory: HttpClientFactory, pub http_client_factory: HttpClientFactory,
pub password_manager: PasswordManager, pub password_manager: PasswordManager,
pub metadata_cache: MetadataCache, pub metadata_cache: MetadataCache,
@@ -144,7 +144,7 @@ impl FromRef<AppState> for PgPool {
} }
} }
impl FromRef<AppState> for mas_graphql::Schema { impl FromRef<AppState> for GraphQLSchema {
fn from_ref(input: &AppState) -> Self { fn from_ref(input: &AppState) -> Self {
input.graphql_schema.clone() input.graphql_schema.clone()
} }

View File

@@ -1,36 +0,0 @@
[package]
name = "mas-graphql"
version.workspace = true
authors.workspace = true
edition.workspace = true
license.workspace = true
homepage.workspace = true
repository.workspace = true
publish = false
[lints]
workspace = true
[dependencies]
anyhow.workspace = true
async-graphql.workspace = true
async-trait.workspace = true
chrono.workspace = true
lettre.workspace = true
serde.workspace = true
thiserror.workspace = true
tokio.workspace = true
tracing.workspace = true
tower.workspace = true
ulid.workspace = true
url.workspace = true
oauth2-types.workspace = true
mas-data-model.workspace = true
mas-matrix.workspace = true
mas-policy.workspace = true
mas-storage.workspace = true
[[bin]]
name = "schema"
doc = false

View File

@@ -1,174 +0,0 @@
// Copyright 2022-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.
#![deny(clippy::future_not_send)]
#![allow(clippy::module_name_repetitions, clippy::unused_async)]
use async_graphql::EmptySubscription;
use mas_data_model::{BrowserSession, Session, User};
use ulid::Ulid;
mod model;
mod mutations;
mod query;
mod state;
pub use self::{
model::{CreationEvent, Node},
mutations::Mutation,
query::Query,
state::{BoxState, State},
};
pub type Schema = async_graphql::Schema<Query, Mutation, EmptySubscription>;
pub type SchemaBuilder = async_graphql::SchemaBuilder<Query, Mutation, EmptySubscription>;
#[must_use]
pub fn schema_builder() -> SchemaBuilder {
async_graphql::Schema::build(Query::new(), Mutation::new(), EmptySubscription)
.register_output_type::<Node>()
.register_output_type::<CreationEvent>()
}
/// The identity of the requester.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub enum Requester {
/// The requester presented no authentication information.
#[default]
Anonymous,
/// The requester is a browser session, stored in a cookie.
BrowserSession(Box<BrowserSession>),
/// The requester is a `OAuth2` session, with an access token.
OAuth2Session(Box<(Session, Option<User>)>),
}
trait OwnerId {
fn owner_id(&self) -> Option<Ulid>;
}
impl OwnerId for User {
fn owner_id(&self) -> Option<Ulid> {
Some(self.id)
}
}
impl OwnerId for BrowserSession {
fn owner_id(&self) -> Option<Ulid> {
Some(self.user.id)
}
}
impl OwnerId for mas_data_model::UserEmail {
fn owner_id(&self) -> Option<Ulid> {
Some(self.user_id)
}
}
impl OwnerId for Session {
fn owner_id(&self) -> Option<Ulid> {
self.user_id
}
}
impl OwnerId for mas_data_model::CompatSession {
fn owner_id(&self) -> Option<Ulid> {
Some(self.user_id)
}
}
impl OwnerId for mas_data_model::UpstreamOAuthLink {
fn owner_id(&self) -> Option<Ulid> {
self.user_id
}
}
/// A dumb wrapper around a `Ulid` to implement `OwnerId` for it.
pub struct UserId(Ulid);
impl OwnerId for UserId {
fn owner_id(&self) -> Option<Ulid> {
Some(self.0)
}
}
impl Requester {
fn browser_session(&self) -> Option<&BrowserSession> {
match self {
Self::BrowserSession(session) => Some(session),
Self::OAuth2Session(_) | Self::Anonymous => None,
}
}
fn user(&self) -> Option<&User> {
match self {
Self::BrowserSession(session) => Some(&session.user),
Self::OAuth2Session(tuple) => tuple.1.as_ref(),
Self::Anonymous => None,
}
}
fn oauth2_session(&self) -> Option<&Session> {
match self {
Self::OAuth2Session(tuple) => Some(&tuple.0),
Self::BrowserSession(_) | Self::Anonymous => None,
}
}
/// Returns true if the requester can access the resource.
fn is_owner_or_admin(&self, resource: &impl OwnerId) -> bool {
// If the requester is an admin, they can do anything.
if self.is_admin() {
return true;
}
// Otherwise, they must be the owner of the resource.
let Some(owner_id) = resource.owner_id() else {
return false;
};
let Some(user) = self.user() else {
return false;
};
user.id == owner_id
}
fn is_admin(&self) -> bool {
match self {
Self::OAuth2Session(tuple) => {
// TODO: is this the right scope?
// This has to be in sync with the policy
tuple.0.scope.contains("urn:mas:admin")
}
Self::BrowserSession(_) | Self::Anonymous => false,
}
}
}
impl From<BrowserSession> for Requester {
fn from(session: BrowserSession) -> Self {
Self::BrowserSession(Box::new(session))
}
}
impl<T> From<Option<T>> for Requester
where
T: Into<Requester>,
{
fn from(session: Option<T>) -> Self {
session.map(Into::into).unwrap_or_default()
}
}

View File

@@ -15,6 +15,7 @@ workspace = true
# Async runtime # Async runtime
tokio.workspace = true tokio.workspace = true
futures-util = "0.3.30" futures-util = "0.3.30"
async-trait.workspace = true
# Logging and tracing # Logging and tracing
tracing.workspace = true tracing.workspace = true
@@ -70,7 +71,6 @@ ulid.workspace = true
mas-axum-utils.workspace = true mas-axum-utils.workspace = true
mas-data-model.workspace = true mas-data-model.workspace = true
mas-graphql.workspace = true
mas-http.workspace = true mas-http.workspace = true
mas-i18n.workspace = true mas-i18n.workspace = true
mas-iana.workspace = true mas-iana.workspace = true

View File

@@ -22,6 +22,6 @@
#![warn(clippy::pedantic)] #![warn(clippy::pedantic)]
fn main() { fn main() {
let schema = mas_graphql::schema_builder().finish(); let schema = mas_handlers::graphql_schema_builder().finish();
println!("{}", schema.sdl()); println!("{}", schema.sdl());
} }

View File

@@ -12,15 +12,18 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#![allow(clippy::module_name_repetitions)]
use std::sync::Arc; use std::sync::Arc;
use async_graphql::{ use async_graphql::{
extensions::Tracing, extensions::Tracing,
http::{playground_source, GraphQLPlaygroundConfig, MultipartOptions}, http::{playground_source, GraphQLPlaygroundConfig, MultipartOptions},
EmptySubscription,
}; };
use axum::{ use axum::{
async_trait, async_trait,
extract::{BodyStream, RawQuery, State}, extract::{BodyStream, RawQuery, State as AxumState},
http::StatusCode, http::StatusCode,
response::{Html, IntoResponse, Response}, response::{Html, IntoResponse, Response},
Json, TypedHeader, Json, TypedHeader,
@@ -31,8 +34,7 @@ use hyper::header::CACHE_CONTROL;
use mas_axum_utils::{ use mas_axum_utils::{
cookies::CookieJar, sentry::SentryEventID, FancyError, SessionInfo, SessionInfoExt, cookies::CookieJar, sentry::SentryEventID, FancyError, SessionInfo, SessionInfoExt,
}; };
use mas_data_model::{SiteConfig, User}; use mas_data_model::{BrowserSession, Session, SiteConfig, User};
use mas_graphql::{Requester, Schema};
use mas_matrix::HomeserverConnection; use mas_matrix::HomeserverConnection;
use mas_policy::{InstantiateError, Policy, PolicyFactory}; use mas_policy::{InstantiateError, Policy, PolicyFactory};
use mas_storage::{ use mas_storage::{
@@ -44,7 +46,19 @@ use rand::{thread_rng, SeedableRng};
use rand_chacha::ChaChaRng; use rand_chacha::ChaChaRng;
use sqlx::PgPool; use sqlx::PgPool;
use tracing::{info_span, Instrument}; use tracing::{info_span, Instrument};
use ulid::Ulid;
mod model;
mod mutations;
mod query;
mod state;
pub use self::state::{BoxState, State};
use self::{
model::{CreationEvent, Node},
mutations::Mutation,
query::Query,
};
use crate::{impl_from_error_for_route, BoundActivityTracker}; use crate::{impl_from_error_for_route, BoundActivityTracker};
#[cfg(test)] #[cfg(test)]
@@ -58,7 +72,7 @@ struct GraphQLState {
} }
#[async_trait] #[async_trait]
impl mas_graphql::State for GraphQLState { impl state::State for GraphQLState {
async fn repository(&self) -> Result<BoxRepository, RepositoryError> { async fn repository(&self) -> Result<BoxRepository, RepositoryError> {
let repo = PgRepository::from_pool(&self.pool) let repo = PgRepository::from_pool(&self.pool)
.await .await
@@ -106,12 +120,9 @@ pub fn schema(
homeserver_connection: Arc::new(homeserver_connection), homeserver_connection: Arc::new(homeserver_connection),
site_config, site_config,
}; };
let state: mas_graphql::BoxState = Box::new(state); let state: BoxState = Box::new(state);
mas_graphql::schema_builder() schema_builder().extension(Tracing).data(state).finish()
.extension(Tracing)
.data(state)
.finish()
} }
fn span_for_graphql_request(request: &async_graphql::Request) -> tracing::Span { fn span_for_graphql_request(request: &async_graphql::Request) -> tracing::Span {
@@ -261,7 +272,7 @@ async fn get_requester(
} }
pub async fn post( pub async fn post(
State(schema): State<Schema>, AxumState(schema): AxumState<Schema>,
clock: BoxClock, clock: BoxClock,
repo: BoxRepository, repo: BoxRepository,
activity_tracker: BoundActivityTracker, activity_tracker: BoundActivityTracker,
@@ -302,7 +313,7 @@ pub async fn post(
} }
pub async fn get( pub async fn get(
State(schema): State<Schema>, AxumState(schema): AxumState<Schema>,
clock: BoxClock, clock: BoxClock,
repo: BoxRepository, repo: BoxRepository,
activity_tracker: BoundActivityTracker, activity_tracker: BoundActivityTracker,
@@ -338,3 +349,145 @@ pub async fn playground() -> impl IntoResponse {
GraphQLPlaygroundConfig::new("/graphql").with_setting("request.credentials", "include"), GraphQLPlaygroundConfig::new("/graphql").with_setting("request.credentials", "include"),
)) ))
} }
pub type Schema = async_graphql::Schema<Query, Mutation, EmptySubscription>;
pub type SchemaBuilder = async_graphql::SchemaBuilder<Query, Mutation, EmptySubscription>;
#[must_use]
pub fn schema_builder() -> SchemaBuilder {
async_graphql::Schema::build(Query::new(), Mutation::new(), EmptySubscription)
.register_output_type::<Node>()
.register_output_type::<CreationEvent>()
}
/// The identity of the requester.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub enum Requester {
/// The requester presented no authentication information.
#[default]
Anonymous,
/// The requester is a browser session, stored in a cookie.
BrowserSession(Box<BrowserSession>),
/// The requester is a `OAuth2` session, with an access token.
OAuth2Session(Box<(Session, Option<User>)>),
}
trait OwnerId {
fn owner_id(&self) -> Option<Ulid>;
}
impl OwnerId for User {
fn owner_id(&self) -> Option<Ulid> {
Some(self.id)
}
}
impl OwnerId for BrowserSession {
fn owner_id(&self) -> Option<Ulid> {
Some(self.user.id)
}
}
impl OwnerId for mas_data_model::UserEmail {
fn owner_id(&self) -> Option<Ulid> {
Some(self.user_id)
}
}
impl OwnerId for Session {
fn owner_id(&self) -> Option<Ulid> {
self.user_id
}
}
impl OwnerId for mas_data_model::CompatSession {
fn owner_id(&self) -> Option<Ulid> {
Some(self.user_id)
}
}
impl OwnerId for mas_data_model::UpstreamOAuthLink {
fn owner_id(&self) -> Option<Ulid> {
self.user_id
}
}
/// A dumb wrapper around a `Ulid` to implement `OwnerId` for it.
pub struct UserId(Ulid);
impl OwnerId for UserId {
fn owner_id(&self) -> Option<Ulid> {
Some(self.0)
}
}
impl Requester {
fn browser_session(&self) -> Option<&BrowserSession> {
match self {
Self::BrowserSession(session) => Some(session),
Self::OAuth2Session(_) | Self::Anonymous => None,
}
}
fn user(&self) -> Option<&User> {
match self {
Self::BrowserSession(session) => Some(&session.user),
Self::OAuth2Session(tuple) => tuple.1.as_ref(),
Self::Anonymous => None,
}
}
fn oauth2_session(&self) -> Option<&Session> {
match self {
Self::OAuth2Session(tuple) => Some(&tuple.0),
Self::BrowserSession(_) | Self::Anonymous => None,
}
}
/// Returns true if the requester can access the resource.
fn is_owner_or_admin(&self, resource: &impl OwnerId) -> bool {
// If the requester is an admin, they can do anything.
if self.is_admin() {
return true;
}
// Otherwise, they must be the owner of the resource.
let Some(owner_id) = resource.owner_id() else {
return false;
};
let Some(user) = self.user() else {
return false;
};
user.id == owner_id
}
fn is_admin(&self) -> bool {
match self {
Self::OAuth2Session(tuple) => {
// TODO: is this the right scope?
// This has to be in sync with the policy
tuple.0.scope.contains("urn:mas:admin")
}
Self::BrowserSession(_) | Self::Anonymous => false,
}
}
}
impl From<BrowserSession> for Requester {
fn from(session: BrowserSession) -> Self {
Self::BrowserSession(Box::new(session))
}
}
impl<T> From<Option<T>> for Requester
where
T: Into<Requester>,
{
fn from(session: Option<T>) -> Self {
session.map(Into::into).unwrap_or_default()
}
}

View File

@@ -26,7 +26,7 @@ use super::{
AppSession, CompatSession, Cursor, NodeCursor, NodeType, OAuth2Session, PreloadedTotalCount, AppSession, CompatSession, Cursor, NodeCursor, NodeType, OAuth2Session, PreloadedTotalCount,
SessionState, User, UserAgent, SessionState, User, UserAgent,
}; };
use crate::state::ContextExt; use crate::graphql::state::ContextExt;
/// A browser session represents a logged in user in a browser. /// A browser session represents a logged in user in a browser.
#[derive(Description)] #[derive(Description)]

View File

@@ -19,7 +19,7 @@ use mas_storage::{compat::CompatSessionRepository, user::UserRepository};
use url::Url; use url::Url;
use super::{BrowserSession, NodeType, SessionState, User, UserAgent}; use super::{BrowserSession, NodeType, SessionState, User, UserAgent};
use crate::state::ContextExt; use crate::graphql::state::ContextExt;
/// Lazy-loaded reverse reference. /// Lazy-loaded reverse reference.
/// ///

View File

@@ -21,7 +21,7 @@ use ulid::Ulid;
use url::Url; use url::Url;
use super::{BrowserSession, NodeType, SessionState, User, UserAgent}; use super::{BrowserSession, NodeType, SessionState, User, UserAgent};
use crate::{state::ContextExt, UserId}; use crate::graphql::{state::ContextExt, UserId};
/// An OAuth 2.0 session represents a client session which used the OAuth APIs /// An OAuth 2.0 session represents a client session which used the OAuth APIs
/// to login. /// to login.

View File

@@ -18,7 +18,7 @@ use chrono::{DateTime, Utc};
use mas_storage::{upstream_oauth2::UpstreamOAuthProviderRepository, user::UserRepository}; use mas_storage::{upstream_oauth2::UpstreamOAuthProviderRepository, user::UserRepository};
use super::{NodeType, User}; use super::{NodeType, User};
use crate::state::ContextExt; use crate::graphql::state::ContextExt;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct UpstreamOAuth2Provider { pub struct UpstreamOAuth2Provider {

View File

@@ -34,7 +34,7 @@ use super::{
BrowserSession, CompatSession, Cursor, NodeCursor, NodeType, OAuth2Session, BrowserSession, CompatSession, Cursor, NodeCursor, NodeType, OAuth2Session,
PreloadedTotalCount, SessionState, UpstreamOAuth2Link, PreloadedTotalCount, SessionState, UpstreamOAuth2Link,
}; };
use crate::state::ContextExt; use crate::graphql::state::ContextExt;
#[derive(Description)] #[derive(Description)]
/// A user is an individual's account. /// A user is an individual's account.

View File

@@ -14,7 +14,7 @@
use async_graphql::Union; use async_graphql::Union;
use crate::model::{BrowserSession, OAuth2Session, User}; use crate::graphql::model::{BrowserSession, OAuth2Session, User};
mod anonymous; mod anonymous;
pub use self::anonymous::Anonymous; pub use self::anonymous::Anonymous;

View File

@@ -15,7 +15,7 @@
use async_graphql::{Context, Enum, InputObject, Object, ID}; use async_graphql::{Context, Enum, InputObject, Object, ID};
use mas_storage::RepositoryAccess; use mas_storage::RepositoryAccess;
use crate::{ use crate::graphql::{
model::{BrowserSession, NodeType}, model::{BrowserSession, NodeType},
state::ContextExt, state::ContextExt,
}; };

View File

@@ -20,7 +20,7 @@ use mas_storage::{
RepositoryAccess, RepositoryAccess,
}; };
use crate::{ use crate::graphql::{
model::{CompatSession, NodeType}, model::{CompatSession, NodeType},
state::ContextExt, state::ContextExt,
}; };

View File

@@ -15,7 +15,7 @@
use anyhow::Context as _; use anyhow::Context as _;
use async_graphql::{Context, Description, Enum, InputObject, Object, ID}; use async_graphql::{Context, Description, Enum, InputObject, Object, ID};
use crate::{ use crate::graphql::{
model::{NodeType, User}, model::{NodeType, User},
state::ContextExt, state::ContextExt,
UserId, UserId,

View File

@@ -27,7 +27,7 @@ use mas_storage::{
}; };
use oauth2_types::scope::Scope; use oauth2_types::scope::Scope;
use crate::{ use crate::graphql::{
model::{NodeType, OAuth2Session}, model::{NodeType, OAuth2Session},
state::ContextExt, state::ContextExt,
}; };

View File

@@ -20,7 +20,7 @@ use mas_storage::{
}; };
use tracing::{info, warn}; use tracing::{info, warn};
use crate::{ use crate::graphql::{
model::{NodeType, User}, model::{NodeType, User},
state::ContextExt, state::ContextExt,
UserId, UserId,

View File

@@ -20,7 +20,7 @@ use mas_storage::{
RepositoryAccess, RepositoryAccess,
}; };
use crate::{ use crate::graphql::{
model::{NodeType, User, UserEmail}, model::{NodeType, User, UserEmail},
state::ContextExt, state::ContextExt,
UserId, UserId,

View File

@@ -15,7 +15,7 @@
use async_graphql::{Context, MergedObject, Object, ID}; use async_graphql::{Context, MergedObject, Object, ID};
use mas_storage::user::UserRepository; use mas_storage::user::UserRepository;
use crate::{ use crate::graphql::{
model::{ model::{
Anonymous, BrowserSession, CompatSession, Node, NodeType, OAuth2Client, OAuth2Session, Anonymous, BrowserSession, CompatSession, Node, NodeType, OAuth2Client, OAuth2Session,
SiteConfig, User, UserEmail, SiteConfig, User, UserEmail,
@@ -234,7 +234,7 @@ impl BaseQuery {
return Ok(Some(Node::Anonymous(Box::new(Anonymous)))); return Ok(Some(Node::Anonymous(Box::new(Anonymous))));
} }
if id.as_str() == crate::model::SITE_CONFIG_ID { if id.as_str() == crate::graphql::model::SITE_CONFIG_ID {
return Ok(Some(Node::SiteConfig(Box::new(SiteConfig::new( return Ok(Some(Node::SiteConfig(Box::new(SiteConfig::new(
ctx.state().site_config(), ctx.state().site_config(),
))))); )))));

View File

@@ -21,7 +21,7 @@ use mas_storage::{
}; };
use oauth2_types::scope::Scope; use oauth2_types::scope::Scope;
use crate::{ use crate::graphql::{
model::{CompatSession, NodeType, OAuth2Session}, model::{CompatSession, NodeType, OAuth2Session},
state::ContextExt, state::ContextExt,
UserId, UserId,

View File

@@ -18,7 +18,7 @@ use async_graphql::{
}; };
use mas_storage::{upstream_oauth2::UpstreamOAuthProviderFilter, Pagination, RepositoryAccess}; use mas_storage::{upstream_oauth2::UpstreamOAuthProviderFilter, Pagination, RepositoryAccess};
use crate::{ use crate::graphql::{
model::{ model::{
Cursor, NodeCursor, NodeType, PreloadedTotalCount, UpstreamOAuth2Link, Cursor, NodeCursor, NodeType, PreloadedTotalCount, UpstreamOAuth2Link,
UpstreamOAuth2Provider, UpstreamOAuth2Provider,

View File

@@ -14,7 +14,7 @@
use async_graphql::{Context, Object}; use async_graphql::{Context, Object};
use crate::{ use crate::graphql::{
model::{Viewer, ViewerSession}, model::{Viewer, ViewerSession},
state::ContextExt, state::ContextExt,
Requester, Requester,

View File

@@ -17,7 +17,7 @@ use mas_matrix::HomeserverConnection;
use mas_policy::Policy; use mas_policy::Policy;
use mas_storage::{BoxClock, BoxRepository, BoxRng, RepositoryError}; use mas_storage::{BoxClock, BoxRepository, BoxRng, RepositoryError};
use crate::Requester; use crate::graphql::Requester;
#[async_trait::async_trait] #[async_trait::async_trait]
pub trait State { pub trait State {

View File

@@ -90,7 +90,9 @@ pub use mas_axum_utils::{
pub use self::{ pub use self::{
activity_tracker::{ActivityTracker, Bound as BoundActivityTracker}, activity_tracker::{ActivityTracker, Bound as BoundActivityTracker},
graphql::schema as graphql_schema, graphql::{
schema as graphql_schema, schema_builder as graphql_schema_builder, Schema as GraphQLSchema,
},
preferred_language::PreferredLanguage, preferred_language::PreferredLanguage,
upstream_oauth2::cache::MetadataCache, upstream_oauth2::cache::MetadataCache,
}; };
@@ -110,7 +112,7 @@ where
<B as HttpBody>::Data: Into<Bytes>, <B as HttpBody>::Data: Into<Bytes>,
<B as HttpBody>::Error: std::error::Error + Send + Sync, <B as HttpBody>::Error: std::error::Error + Send + Sync,
S: Clone + Send + Sync + 'static, S: Clone + Send + Sync + 'static,
mas_graphql::Schema: FromRef<S>, graphql::Schema: FromRef<S>,
BoundActivityTracker: FromRequestParts<S>, BoundActivityTracker: FromRequestParts<S>,
BoxRepository: FromRequestParts<S>, BoxRepository: FromRequestParts<S>,
BoxClock: FromRequestParts<S>, BoxClock: FromRequestParts<S>,

View File

@@ -54,6 +54,7 @@ use tower::{Layer, Service, ServiceExt};
use url::Url; use url::Url;
use crate::{ use crate::{
graphql,
passwords::{Hasher, PasswordManager}, passwords::{Hasher, PasswordManager},
upstream_oauth2::cache::MetadataCache, upstream_oauth2::cache::MetadataCache,
ActivityTracker, BoundActivityTracker, ActivityTracker, BoundActivityTracker,
@@ -102,7 +103,7 @@ pub(crate) struct TestState {
pub url_builder: UrlBuilder, pub url_builder: UrlBuilder,
pub homeserver_connection: Arc<MockHomeserverConnection>, pub homeserver_connection: Arc<MockHomeserverConnection>,
pub policy_factory: Arc<PolicyFactory>, pub policy_factory: Arc<PolicyFactory>,
pub graphql_schema: mas_graphql::Schema, pub graphql_schema: graphql::Schema,
pub http_client_factory: HttpClientFactory, pub http_client_factory: HttpClientFactory,
pub password_manager: PasswordManager, pub password_manager: PasswordManager,
pub site_config: SiteConfig, pub site_config: SiteConfig,
@@ -198,9 +199,9 @@ impl TestState {
rng: Arc::clone(&rng), rng: Arc::clone(&rng),
clock: Arc::clone(&clock), clock: Arc::clone(&clock),
}; };
let state: mas_graphql::BoxState = Box::new(graphql_state); let state: crate::graphql::BoxState = Box::new(graphql_state);
let graphql_schema = mas_graphql::schema_builder().data(state).finish(); let graphql_schema = graphql::schema_builder().data(state).finish();
let activity_tracker = let activity_tracker =
ActivityTracker::new(pool.clone(), std::time::Duration::from_secs(1)); ActivityTracker::new(pool.clone(), std::time::Duration::from_secs(1));
@@ -316,7 +317,7 @@ struct TestGraphQLState {
} }
#[async_trait] #[async_trait]
impl mas_graphql::State for TestGraphQLState { impl graphql::State for TestGraphQLState {
async fn repository(&self) -> Result<BoxRepository, mas_storage::RepositoryError> { async fn repository(&self) -> Result<BoxRepository, mas_storage::RepositoryError> {
let repo = PgRepository::from_pool(&self.pool) let repo = PgRepository::from_pool(&self.pool)
.await .await
@@ -356,7 +357,7 @@ impl FromRef<TestState> for PgPool {
} }
} }
impl FromRef<TestState> for mas_graphql::Schema { impl FromRef<TestState> for graphql::Schema {
fn from_ref(input: &TestState) -> Self { fn from_ref(input: &TestState) -> Self {
input.graphql_schema.clone() input.graphql_schema.clone()
} }

View File

@@ -10,7 +10,7 @@ POLICIES_SCHEMA="${BASE_DIR}/policies/schema/"
set -x set -x
cargo run -p mas-config > "${CONFIG_SCHEMA}" cargo run -p mas-config > "${CONFIG_SCHEMA}"
cargo run -p mas-graphql > "${GRAPHQL_SCHEMA}" cargo run -p mas-handlers --bin graphql-schema > "${GRAPHQL_SCHEMA}"
cargo run -p mas-i18n-scan -- --update "${BASE_DIR}/templates/" "${BASE_DIR}/translations/en.json" cargo run -p mas-i18n-scan -- --update "${BASE_DIR}/templates/" "${BASE_DIR}/translations/en.json"
OUT_DIR="${POLICIES_SCHEMA}" cargo run -p mas-policy --features jsonschema OUT_DIR="${POLICIES_SCHEMA}" cargo run -p mas-policy --features jsonschema