//! Permission checking utilities for API endpoints. //! //! Provides reusable functions to check user permissions against the role system. use axum::http::StatusCode; use sqlx::PgPool; use uuid::Uuid; /// Check if a user has a specific permission, optionally within a community scope. pub async fn user_has_permission( pool: &PgPool, user_id: Uuid, permission: &str, community_id: Option, ) -> Result { let has_perm = sqlx::query_scalar!( "SELECT user_has_permission($1, $2, $3)", user_id, permission, community_id ) .fetch_one(pool) .await .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))? .unwrap_or(false); Ok(has_perm) } /// Require a permission, returning Forbidden error if not granted. pub async fn require_permission( pool: &PgPool, user_id: Uuid, permission: &str, community_id: Option, ) -> Result<(), (StatusCode, String)> { if !user_has_permission(pool, user_id, permission, community_id).await? { return Err(( StatusCode::FORBIDDEN, format!("Permission '{}' required", permission), )); } Ok(()) } /// Require any of the given permissions. pub async fn require_any_permission( pool: &PgPool, user_id: Uuid, permissions: &[&str], community_id: Option, ) -> Result<(), (StatusCode, String)> { for perm in permissions { if user_has_permission(pool, user_id, perm, community_id).await? { return Ok(()); } } Err(( StatusCode::FORBIDDEN, format!("One of these permissions required: {}", permissions.join(", ")), )) } /// Check if user is a platform admin (has platform.admin permission). #[allow(dead_code)] pub async fn is_platform_admin( pool: &PgPool, user_id: Uuid, ) -> Result { user_has_permission(pool, user_id, "platform.admin", None).await } /// Require platform admin access. #[allow(dead_code)] pub async fn require_platform_admin( pool: &PgPool, user_id: Uuid, ) -> Result<(), (StatusCode, String)> { require_permission(pool, user_id, "platform.admin", None).await } /// Check if user is a community admin or moderator. #[allow(dead_code)] pub async fn is_community_staff( pool: &PgPool, user_id: Uuid, community_id: Uuid, ) -> Result { let is_admin = user_has_permission(pool, user_id, "community.admin", Some(community_id)).await?; if is_admin { return Ok(true); } user_has_permission(pool, user_id, "community.moderate", Some(community_id)).await } /// Permission constants for common operations. /// Used throughout API handlers for authorization. pub mod perms { // Platform-level pub const PLATFORM_ADMIN: &str = "platform.admin"; pub const PLATFORM_SETTINGS: &str = "platform.settings"; pub const PLATFORM_PLUGINS: &str = "platform.plugins"; // Community-level pub const COMMUNITY_CREATE: &str = "community.create"; pub const COMMUNITY_ADMIN: &str = "community.admin"; pub const COMMUNITY_SETTINGS: &str = "community.settings"; pub const COMMUNITY_MODERATE: &str = "community.moderate"; // Proposals pub const PROPOSAL_CREATE: &str = "proposal.create"; pub const PROPOSAL_EDIT_OWN: &str = "proposal.edit_own"; pub const PROPOSAL_EDIT_ANY: &str = "proposal.edit_any"; pub const PROPOSAL_DELETE_OWN: &str = "proposal.delete_own"; pub const PROPOSAL_DELETE_ANY: &str = "proposal.delete_any"; pub const PROPOSAL_MANAGE_STATUS: &str = "proposal.manage_status"; // Voting pub const VOTE_CAST: &str = "vote.cast"; pub const VOTE_VIEW_RESULTS: &str = "vote.view_results"; pub const VOTING_CONFIG: &str = "voting.configure"; // Moderation pub const MOD_BAN_USERS: &str = "moderation.ban_users"; pub const MOD_REMOVE_CONTENT: &str = "moderation.remove_content"; pub const MOD_VIEW_REPORTS: &str = "moderation.view_reports"; // Users pub const USER_MANAGE: &str = "users.manage"; pub const USER_INVITE: &str = "users.invite"; }