mirror of
https://codeberg.org/likwid/likwid.git
synced 2026-03-26 19:03:08 +00:00
153 lines
4.7 KiB
Rust
153 lines
4.7 KiB
Rust
//! Demo API endpoints
|
|
|
|
use axum::{
|
|
extract::State,
|
|
http::StatusCode,
|
|
response::IntoResponse,
|
|
routing::{get, post},
|
|
Json, Router,
|
|
};
|
|
use serde_json::json;
|
|
use sqlx::PgPool;
|
|
use std::sync::Arc;
|
|
|
|
use super::permissions::{perms, require_permission};
|
|
use crate::auth::AuthUser;
|
|
use crate::config::Config;
|
|
use crate::demo::{self, DemoResetError, DEMO_ACCOUNTS};
|
|
|
|
/// Combined state for demo endpoints
|
|
#[derive(Clone)]
|
|
pub struct DemoState {
|
|
pub pool: PgPool,
|
|
pub config: Arc<Config>,
|
|
}
|
|
|
|
/// Get demo mode status and available accounts
|
|
async fn get_demo_status(State(state): State<DemoState>) -> impl IntoResponse {
|
|
Json(json!({
|
|
"demo_mode": state.config.is_demo(),
|
|
"accounts": if state.config.is_demo() {
|
|
DEMO_ACCOUNTS.iter().map(|(u, _, d)| json!({
|
|
"username": u,
|
|
"display_name": d,
|
|
"password": "demo123"
|
|
})).collect::<Vec<_>>()
|
|
} else {
|
|
vec![]
|
|
},
|
|
"restrictions": if state.config.is_demo() {
|
|
vec![
|
|
"Cannot delete communities",
|
|
"Cannot delete users",
|
|
"Cannot modify instance settings (except instance theme)",
|
|
"Data resets periodically"
|
|
]
|
|
} else {
|
|
vec![]
|
|
}
|
|
}))
|
|
}
|
|
|
|
/// Reset demo data to initial state (only in demo mode)
|
|
async fn reset_demo(State(state): State<DemoState>, auth: AuthUser) -> impl IntoResponse {
|
|
if !state.config.is_demo() {
|
|
return (
|
|
StatusCode::FORBIDDEN,
|
|
Json(json!({"error": "Demo mode not enabled"})),
|
|
)
|
|
.into_response();
|
|
}
|
|
|
|
if let Err((status, msg)) =
|
|
require_permission(&state.pool, auth.user_id, perms::PLATFORM_ADMIN, None).await
|
|
{
|
|
return (status, Json(json!({"error": msg}))).into_response();
|
|
}
|
|
|
|
match demo::reset_demo_data(&state.pool).await {
|
|
Ok(_) => (
|
|
StatusCode::OK,
|
|
Json(json!({"success": true, "message": "Demo data has been reset to initial state"})),
|
|
)
|
|
.into_response(),
|
|
Err(DemoResetError::Busy) => (
|
|
StatusCode::CONFLICT,
|
|
Json(json!({"error": "Demo reset already in progress"})),
|
|
)
|
|
.into_response(),
|
|
Err(DemoResetError::LockTimeout) => (
|
|
StatusCode::GATEWAY_TIMEOUT,
|
|
Json(json!({"error": "Timed out while acquiring demo reset lock"})),
|
|
)
|
|
.into_response(),
|
|
Err(DemoResetError::Sql(e)) => {
|
|
tracing::error!("Failed to reset demo data: {}", e);
|
|
(
|
|
StatusCode::INTERNAL_SERVER_ERROR,
|
|
Json(json!({"error": "Failed to reset demo data"})),
|
|
)
|
|
.into_response()
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Get demo communities summary
|
|
async fn get_demo_communities(State(state): State<DemoState>) -> impl IntoResponse {
|
|
if !state.config.is_demo() {
|
|
return (StatusCode::OK, Json(json!({"communities": []}))).into_response();
|
|
}
|
|
|
|
let communities = sqlx::query_as::<_, (String, String, String, i64, i64)>(
|
|
r#"
|
|
SELECT
|
|
c.name,
|
|
c.slug,
|
|
COALESCE(c.description, '') as description,
|
|
(SELECT COUNT(*) FROM community_members WHERE community_id = c.id) as member_count,
|
|
(SELECT COUNT(*) FROM proposals WHERE community_id = c.id) as proposal_count
|
|
FROM communities c
|
|
WHERE c.slug IN ('aurora', 'civic-commons', 'makers')
|
|
ORDER BY c.name
|
|
"#,
|
|
)
|
|
.fetch_all(&state.pool)
|
|
.await;
|
|
|
|
match communities {
|
|
Ok(rows) => {
|
|
let communities: Vec<_> = rows
|
|
.iter()
|
|
.map(|(name, slug, desc, members, proposals)| {
|
|
json!({
|
|
"name": name,
|
|
"slug": slug,
|
|
"description": desc,
|
|
"member_count": members,
|
|
"proposal_count": proposals
|
|
})
|
|
})
|
|
.collect();
|
|
|
|
(StatusCode::OK, Json(json!({"communities": communities}))).into_response()
|
|
}
|
|
Err(e) => {
|
|
tracing::error!("Failed to fetch demo communities: {}", e);
|
|
(
|
|
StatusCode::INTERNAL_SERVER_ERROR,
|
|
Json(json!({"error": "Failed to fetch communities"})),
|
|
)
|
|
.into_response()
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn router(pool: PgPool, config: Arc<Config>) -> Router {
|
|
let state = DemoState { pool, config };
|
|
|
|
Router::new()
|
|
.route("/api/demo/status", get(get_demo_status))
|
|
.route("/api/demo/reset", post(reset_demo))
|
|
.route("/api/demo/communities", get(get_demo_communities))
|
|
.with_state(state)
|
|
}
|