//! Realm API handlers for user UI (READ-ONLY). use axum::{ extract::{Path, Query, State}, Json, }; use serde::{Deserialize, Serialize}; use sqlx::PgPool; use chattyness_db::{ models::{RealmSummary, RealmWithUserRole}, queries::{memberships, realms}, }; use chattyness_error::AppError; use crate::auth::OptionalAuthUser; /// List query params. #[derive(Debug, Deserialize)] pub struct ListParams { pub include_nsfw: Option, pub page: Option, pub limit: Option, } /// List response. #[derive(Debug, Serialize)] pub struct ListResponse { pub realms: Vec, } /// List public realms. pub async fn list_realms( State(pool): State, Query(params): Query, ) -> Result, AppError> { let limit = params.limit.unwrap_or(20).min(100); let offset = params.page.unwrap_or(0) * limit; let include_nsfw = params.include_nsfw.unwrap_or(false); let realm_list = realms::list_public_realms(&pool, include_nsfw, limit, offset).await?; Ok(Json(ListResponse { realms: realm_list })) } /// Get a realm by slug with user role. pub async fn get_realm( State(pool): State, OptionalAuthUser(maybe_user): OptionalAuthUser, Path(slug): Path, ) -> Result, AppError> { let realm = realms::get_realm_by_slug(&pool, &slug) .await? .ok_or_else(|| AppError::NotFound(format!("Realm '{}' not found", slug)))?; // Get the user's role if authenticated let user_role = if let Some(user) = maybe_user { let membership = memberships::get_user_membership(&pool, user.id, realm.id).await?; membership.map(|m| m.role) } else { None }; Ok(Json(RealmWithUserRole { realm, user_role })) } /// Check slug availability response. #[derive(Debug, Serialize)] pub struct SlugAvailableResponse { pub available: bool, } /// Check if a realm slug is available. pub async fn check_slug_available( State(pool): State, Path(slug): Path, ) -> Result, AppError> { let available = realms::is_slug_available(&pool, &slug).await?; Ok(Json(SlugAvailableResponse { available })) }