use crate::error::WebAppError; use crate::session::UserSession; use askama::Template; use axum::extract::{Path, State}; use axum::response::Result; use axum::{response::Html, routing::get, Router}; use gotrue_entity::dto::User; use crate::{templates, AppState}; pub fn router(state: AppState) -> Router { Router::new() .nest_service("/", page_router().with_state(state.clone())) .nest_service("/components", component_router().with_state(state)) } pub fn page_router() -> Router { Router::new() .route("/", get(home_handler)) .route("/login", get(login_handler)) .route("/home", get(home_handler)) .route("/admin/home", get(admin_home_handler)) } pub fn component_router() -> Router { Router::new() // User actions .route("/user/navigate", get(user_navigate_handler)) .route("/user/user", get(user_user_handler)) .route("/user/change_password", get(user_change_password_handler)) .route("/user/invite", get(user_invite_handler)) // Admin actions .route("/admin/navigate", get(admin_navigate_handler)) .route("/admin/users", get(admin_users_handler)) .route("/admin/users/:user_id", get(admin_user_details_handler)) .route("/admin/users/create", get(admin_users_create_handler)) // SSO .route("/admin/sso", get(admin_sso_handler)) .route("/admin/sso/create", get(admin_sso_create_handler)) .route("/admin/sso/:sso_provider_id", get(admin_sso_detail_handler)) } pub async fn admin_sso_detail_handler( State(state): State, session: UserSession, Path(sso_provider_id): Path, ) -> Result, WebAppError> { let sso_provider = state .gotrue_client .admin_get_sso_provider(&session.token.access_token, &sso_provider_id) .await?; let mapping_json = serde_json::to_string_pretty(&sso_provider.saml.attribute_mapping).unwrap_or("".to_owned()); render_template(templates::SsoDetail { sso_provider, mapping_json, }) } pub async fn admin_sso_create_handler() -> Result, WebAppError> { render_template(templates::SsoCreate) } pub async fn admin_sso_handler( State(state): State, session: UserSession, ) -> Result, WebAppError> { let sso_providers = state .gotrue_client .admin_list_sso_providers(&session.token.access_token) .await? .items .unwrap_or_default(); render_template(templates::SsoList { sso_providers }) } pub async fn user_navigate_handler() -> Result, WebAppError> { render_template(templates::Navigate) } pub async fn admin_navigate_handler() -> Result, WebAppError> { render_template(templates::AdminNavigate) } pub async fn user_invite_handler() -> Result, WebAppError> { render_template(templates::Invite) } pub async fn admin_users_create_handler() -> Result, WebAppError> { render_template(templates::CreateUser) } pub async fn user_user_handler( State(state): State, session: UserSession, ) -> Result, WebAppError> { let user = state .gotrue_client .user_info(&session.token.access_token) .await?; render_template(templates::UserDetails { user: &user }) } pub async fn login_handler(State(state): State) -> Result, WebAppError> { let external = state.gotrue_client.settings().await?.external; let oauth_providers = external.oauth_providers(); render_template(templates::Login { oauth_providers }) } pub async fn user_change_password_handler() -> Result, WebAppError> { render_template(templates::ChangePassword) } pub async fn home_handler( State(state): State, session: UserSession, ) -> Result, WebAppError> { let user = state .gotrue_client .user_info(&session.token.access_token) .await?; render_template(templates::Home { user: &user, is_admin: is_admin(&user), }) } pub async fn admin_home_handler( State(state): State, session: UserSession, ) -> Result, WebAppError> { let user = state .gotrue_client .user_info(&session.token.access_token) .await?; render_template(templates::AdminHome { user: &user }) } pub async fn admin_users_handler( State(state): State, session: UserSession, ) -> Result, WebAppError> { let users = state .gotrue_client .admin_list_user(&session.token.access_token) .await .map_or_else( |err| { tracing::error!("Error getting user list: {:?}", err); vec![] }, |r| r.users, ) .into_iter() .filter(|user| user.deleted_at.is_none()) .collect::>(); render_template(templates::AdminUsers { users: &users }) } pub async fn admin_user_details_handler( State(state): State, session: UserSession, Path(user_id): Path, ) -> Result, WebAppError> { let user = state .gotrue_client .admin_user_details(&session.token.access_token, &user_id) .await .unwrap(); // TODO: handle error render_template(templates::AdminUserDetails { user: &user }) } fn render_template(x: T) -> Result, WebAppError> where T: Template, { let s = x.render()?; Ok(Html(s)) } fn is_admin(user: &User) -> bool { user.role == "supabase_admin" }