mirror of
https://codeberg.org/likwid/likwid.git
synced 2026-02-10 05:23:09 +00:00
148 lines
4.8 KiB
Rust
148 lines
4.8 KiB
Rust
|
|
//! Governance Analytics API endpoints.
|
||
|
|
|
||
|
|
use axum::{
|
||
|
|
extract::{Path, Query, State},
|
||
|
|
http::StatusCode,
|
||
|
|
routing::get,
|
||
|
|
Json, Router,
|
||
|
|
};
|
||
|
|
use chrono::NaiveDate;
|
||
|
|
use serde::Deserialize;
|
||
|
|
use serde_json::Value;
|
||
|
|
use sqlx::PgPool;
|
||
|
|
use uuid::Uuid;
|
||
|
|
|
||
|
|
use crate::auth::AuthUser;
|
||
|
|
use crate::plugins::builtin::governance_analytics::{
|
||
|
|
AnalyticsService, GovernanceHealth, ParticipationSnapshot,
|
||
|
|
};
|
||
|
|
|
||
|
|
// ============================================================================
|
||
|
|
// Query Parameters
|
||
|
|
// ============================================================================
|
||
|
|
|
||
|
|
#[derive(Debug, Deserialize)]
|
||
|
|
pub struct TrendsQuery {
|
||
|
|
pub days: Option<i32>,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Deserialize)]
|
||
|
|
pub struct ExportQuery {
|
||
|
|
pub start_date: NaiveDate,
|
||
|
|
pub end_date: NaiveDate,
|
||
|
|
}
|
||
|
|
|
||
|
|
// ============================================================================
|
||
|
|
// Handlers
|
||
|
|
// ============================================================================
|
||
|
|
|
||
|
|
/// Get participation trends for a community
|
||
|
|
async fn get_participation_trends(
|
||
|
|
_auth: AuthUser,
|
||
|
|
Path(community_id): Path<Uuid>,
|
||
|
|
Query(query): Query<TrendsQuery>,
|
||
|
|
State(pool): State<PgPool>,
|
||
|
|
) -> Result<Json<Vec<ParticipationSnapshot>>, (StatusCode, String)> {
|
||
|
|
let days = query.days.unwrap_or(30);
|
||
|
|
let trends = AnalyticsService::get_participation_trends(&pool, community_id, days)
|
||
|
|
.await
|
||
|
|
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||
|
|
|
||
|
|
Ok(Json(trends))
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Get current governance health for a community
|
||
|
|
async fn get_health(
|
||
|
|
_auth: AuthUser,
|
||
|
|
Path(community_id): Path<Uuid>,
|
||
|
|
State(pool): State<PgPool>,
|
||
|
|
) -> Result<Json<Option<GovernanceHealth>>, (StatusCode, String)> {
|
||
|
|
let health = AnalyticsService::get_health(&pool, community_id)
|
||
|
|
.await
|
||
|
|
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||
|
|
|
||
|
|
Ok(Json(health))
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Get delegation analytics for a community
|
||
|
|
async fn get_delegation_analytics(
|
||
|
|
_auth: AuthUser,
|
||
|
|
Path(community_id): Path<Uuid>,
|
||
|
|
State(pool): State<PgPool>,
|
||
|
|
) -> Result<Json<Value>, (StatusCode, String)> {
|
||
|
|
let analytics = AnalyticsService::get_delegation_analytics(&pool, community_id)
|
||
|
|
.await
|
||
|
|
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||
|
|
|
||
|
|
Ok(Json(analytics))
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Get decision load metrics for a community
|
||
|
|
async fn get_decision_load(
|
||
|
|
_auth: AuthUser,
|
||
|
|
Path(community_id): Path<Uuid>,
|
||
|
|
State(pool): State<PgPool>,
|
||
|
|
) -> Result<Json<Value>, (StatusCode, String)> {
|
||
|
|
let load = AnalyticsService::get_decision_load(&pool, community_id)
|
||
|
|
.await
|
||
|
|
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||
|
|
|
||
|
|
Ok(Json(load))
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Get voting method comparison for a community
|
||
|
|
async fn get_voting_method_comparison(
|
||
|
|
_auth: AuthUser,
|
||
|
|
Path(community_id): Path<Uuid>,
|
||
|
|
State(pool): State<PgPool>,
|
||
|
|
) -> Result<Json<Vec<Value>>, (StatusCode, String)> {
|
||
|
|
let comparison = AnalyticsService::get_voting_method_comparison(&pool, community_id)
|
||
|
|
.await
|
||
|
|
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||
|
|
|
||
|
|
Ok(Json(comparison))
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Get full analytics dashboard for a community
|
||
|
|
async fn get_dashboard(
|
||
|
|
_auth: AuthUser,
|
||
|
|
Path(community_id): Path<Uuid>,
|
||
|
|
State(pool): State<PgPool>,
|
||
|
|
) -> Result<Json<Value>, (StatusCode, String)> {
|
||
|
|
let dashboard = AnalyticsService::get_dashboard(&pool, community_id)
|
||
|
|
.await
|
||
|
|
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||
|
|
|
||
|
|
Ok(Json(dashboard))
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Export analytics data for a date range
|
||
|
|
async fn export_data(
|
||
|
|
_auth: AuthUser,
|
||
|
|
Path(community_id): Path<Uuid>,
|
||
|
|
Query(query): Query<ExportQuery>,
|
||
|
|
State(pool): State<PgPool>,
|
||
|
|
) -> Result<Json<Value>, (StatusCode, String)> {
|
||
|
|
let data = AnalyticsService::export_data(&pool, community_id, query.start_date, query.end_date)
|
||
|
|
.await
|
||
|
|
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||
|
|
|
||
|
|
Ok(Json(data))
|
||
|
|
}
|
||
|
|
|
||
|
|
// ============================================================================
|
||
|
|
// Router
|
||
|
|
// ============================================================================
|
||
|
|
|
||
|
|
pub fn router(pool: PgPool) -> Router {
|
||
|
|
Router::new()
|
||
|
|
.route("/api/communities/{community_id}/analytics/dashboard", get(get_dashboard))
|
||
|
|
.route("/api/communities/{community_id}/analytics/health", get(get_health))
|
||
|
|
.route("/api/communities/{community_id}/analytics/participation", get(get_participation_trends))
|
||
|
|
.route("/api/communities/{community_id}/analytics/delegation", get(get_delegation_analytics))
|
||
|
|
.route("/api/communities/{community_id}/analytics/decision-load", get(get_decision_load))
|
||
|
|
.route("/api/communities/{community_id}/analytics/voting-methods", get(get_voting_method_comparison))
|
||
|
|
.route("/api/communities/{community_id}/analytics/export", get(export_data))
|
||
|
|
.with_state(pool)
|
||
|
|
}
|