likwid/backend/src/api/permissions.rs
Marco Allegretti cf0e4ed302 backend: modify 20 files
Verified changes:
- modify backend/src/api/approvals.rs
- modify backend/src/api/auth.rs
- modify backend/src/api/communities.rs
- modify backend/src/api/delegation.rs
- modify backend/src/api/demo.rs
- modify backend/src/api/moderation.rs
- modify backend/src/api/permissions.rs
- modify backend/src/api/plugins.rs
- modify backend/src/api/settings.rs
- modify backend/src/auth/middleware.rs
- modify backend/src/config/mod.rs
- modify backend/src/demo/mod.rs
- modify backend/src/main.rs
- modify backend/src/plugins/builtin/conflict_resolution.rs
- modify backend/src/plugins/builtin/moderation_ledger.rs
- modify backend/src/plugins/manager.rs
- modify backend/src/plugins/wasm/host_api.rs
- modify backend/src/voting/mod.rs
- modify backend/src/voting/ranked_choice.rs
- modify backend/src/voting/star.rs

Diffstat:
- 20 files changed, 800 insertions(+), 127 deletions(-)
2026-01-29 00:46:43 +01:00

131 lines
4.1 KiB
Rust

//! 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<Uuid>,
) -> Result<bool, (StatusCode, String)> {
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<Uuid>,
) -> 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<Uuid>,
) -> 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<bool, (StatusCode, String)> {
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<bool, (StatusCode, String)> {
let is_admin = user_has_permission(pool, user_id, "community.settings", Some(community_id)).await?;
if is_admin {
return Ok(true);
}
user_has_permission(pool, user_id, "moderation.users.warn", 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 = "plugins.configure";
// Community-level
pub const COMMUNITY_CREATE: &str = "community.create";
pub const COMMUNITY_ADMIN: &str = "community.settings";
pub const COMMUNITY_SETTINGS: &str = "community.settings";
pub const COMMUNITY_MODERATE: &str = "moderation.users.warn";
// Proposals
pub const PROPOSAL_CREATE: &str = "proposals.create";
pub const PROPOSAL_EDIT_OWN: &str = "proposals.edit.own";
pub const PROPOSAL_EDIT_ANY: &str = "proposals.edit.any";
pub const PROPOSAL_DELETE_OWN: &str = "proposals.delete.own";
pub const PROPOSAL_DELETE_ANY: &str = "proposals.delete.any";
pub const PROPOSAL_MANAGE_STATUS: &str = "proposals.moderate";
// Voting
pub const VOTE_CAST: &str = "voting.vote";
pub const VOTE_VIEW_RESULTS: &str = "voting.results.view";
pub const VOTING_CONFIG: &str = "voting.configure";
// Moderation
pub const MOD_BAN_USERS: &str = "platform.users.ban";
pub const MOD_REMOVE_CONTENT: &str = "moderation.comments.delete";
pub const MOD_VIEW_REPORTS: &str = "moderation.log.view";
// Users
pub const USER_MANAGE: &str = "platform.users.manage";
pub const USER_INVITE: &str = "community.members.invite";
}