use anyhow::Context as _;
use async_graphql::{Context, Object, ID};
use chrono::{DateTime, Utc};
use mas_storage::{upstream_oauth2::UpstreamOAuthProviderRepository, user::UserRepository};
use super::{NodeType, User};
use crate::graphql::state::ContextExt;
#[derive(Debug, Clone)]
pub struct UpstreamOAuth2Provider {
provider: mas_data_model::UpstreamOAuthProvider,
}
impl UpstreamOAuth2Provider {
#[must_use]
pub const fn new(provider: mas_data_model::UpstreamOAuthProvider) -> Self {
Self { provider }
}
}
#[Object]
impl UpstreamOAuth2Provider {
pub async fn id(&self) -> ID {
NodeType::UpstreamOAuth2Provider.id(self.provider.id)
}
pub async fn created_at(&self) -> DateTime<Utc> {
self.provider.created_at
}
pub async fn issuer(&self) -> &str {
&self.provider.issuer
}
pub async fn client_id(&self) -> &str {
&self.provider.client_id
}
}
impl UpstreamOAuth2Link {
#[must_use]
pub const fn new(link: mas_data_model::UpstreamOAuthLink) -> Self {
Self {
link,
provider: None,
user: None,
}
}
}
#[derive(Debug, Clone)]
pub struct UpstreamOAuth2Link {
link: mas_data_model::UpstreamOAuthLink,
provider: Option<mas_data_model::UpstreamOAuthProvider>,
user: Option<mas_data_model::User>,
}
#[Object]
impl UpstreamOAuth2Link {
pub async fn id(&self) -> ID {
NodeType::UpstreamOAuth2Link.id(self.link.id)
}
pub async fn created_at(&self) -> DateTime<Utc> {
self.link.created_at
}
pub async fn subject(&self) -> &str {
&self.link.subject
}
pub async fn provider(
&self,
ctx: &Context<'_>,
) -> Result<UpstreamOAuth2Provider, async_graphql::Error> {
let state = ctx.state();
let provider = if let Some(provider) = &self.provider {
provider.clone()
} else {
let mut repo = state.repository().await?;
let provider = repo
.upstream_oauth_provider()
.lookup(self.link.provider_id)
.await?
.context("Upstream OAuth 2.0 provider not found")?;
repo.cancel().await?;
provider
};
Ok(UpstreamOAuth2Provider::new(provider))
}
pub async fn user(&self, ctx: &Context<'_>) -> Result<Option<User>, async_graphql::Error> {
let state = ctx.state();
let user = if let Some(user) = &self.user {
user.clone()
} else if let Some(user_id) = &self.link.user_id {
let mut repo = state.repository().await?;
let user = repo
.user()
.lookup(*user_id)
.await?
.context("User not found")?;
repo.cancel().await?;
user
} else {
return Ok(None);
};
Ok(Some(User(user)))
}
}