use crate::casts::{Cast, EncryptedString};
use crate::sql::Auto;
#[derive(crate::Model, Debug, Clone)]
#[rustango(
table = "rustango_sso_providers",
admin(
list_display = "slug, label, kind, enabled, sort_order",
ordering = "sort_order",
readonly_fields = "created_at, updated_at",
)
)]
#[allow(dead_code)]
pub struct SsoProvider {
#[rustango(primary_key)]
pub id: Auto<i64>,
#[rustango(max_length = 64, unique)]
pub slug: String,
#[rustango(max_length = 150)]
pub label: String,
#[rustango(max_length = 32)]
pub kind: String,
#[rustango(max_length = 255)]
pub issuer_url: Option<String>,
#[rustango(max_length = 255)]
pub client_id: String,
#[rustango(max_length = 1024)]
pub client_secret: Cast<EncryptedString>,
#[rustango(default = "true")]
pub enabled: bool,
#[rustango(default = "0")]
pub sort_order: i32,
#[rustango(max_length = 255)]
pub scopes: Option<String>,
#[rustango(auto_now_add)]
pub created_at: Auto<chrono::DateTime<chrono::Utc>>,
#[rustango(auto_now)]
pub updated_at: Auto<chrono::DateTime<chrono::Utc>>,
}
use super::sso::{parse_scopes, ProviderButton, ResolvedSso, SsoError};
use crate::sql::Pool;
pub async fn list_enabled(pool: &Pool, login_base: &str) -> Vec<ProviderButton> {
use crate::sql::FetcherPool as _;
let mut rows: Vec<SsoProvider> = SsoProvider::objects().fetch(pool).await.unwrap_or_default();
rows.retain(|r| r.enabled);
rows.sort_by_key(|r| r.sort_order);
rows.into_iter()
.map(|r| ProviderButton {
login_url: format!("{login_base}/sso/{}", r.slug),
slug: r.slug,
label: r.label,
})
.collect()
}
pub async fn resolve_by_slug(
pool: &Pool,
slug: &str,
redirect_uri: String,
) -> Result<Option<ResolvedSso>, SsoError> {
use crate::sql::FetcherPool as _;
let row = SsoProvider::objects()
.filter("slug", slug.to_owned())
.fetch(pool)
.await
.map_err(|e| SsoError::Config(format!("db: {e}")))?
.into_iter()
.find(|r| r.enabled);
let Some(r) = row else {
return Ok(None);
};
let client_secret = r.client_secret.clone().into_inner();
Ok(Some(ResolvedSso {
provider: r.kind,
issuer_url: r.issuer_url,
client_id: r.client_id,
client_secret,
redirect_uri,
scopes: parse_scopes(r.scopes.as_deref()),
}))
}