likwid/backend/src/api/conflicts.rs
Marco Allegretti d4bcba405b backend: modify 56 files
Verified changes:
- modify backend/src/api/analytics.rs
- modify backend/src/api/approvals.rs
- modify backend/src/api/auth.rs
- modify backend/src/api/comments.rs
- modify backend/src/api/communities.rs
- modify backend/src/api/conflicts.rs
- modify backend/src/api/delegation.rs
- modify backend/src/api/deliberation.rs
- modify backend/src/api/demo.rs
- modify backend/src/api/exports.rs
- modify backend/src/api/federation.rs
- modify backend/src/api/gitlab.rs
- modify backend/src/api/invitations.rs
- modify backend/src/api/lifecycle.rs
- modify backend/src/api/mod.rs
- modify backend/src/api/moderation.rs
- modify backend/src/api/moderation_ledger.rs
- modify backend/src/api/notifications.rs
- modify backend/src/api/permissions.rs
- modify backend/src/api/plugins.rs
- modify backend/src/api/proposals.rs
- modify backend/src/api/roles.rs
- modify backend/src/api/self_moderation.rs
- modify backend/src/api/settings.rs
- modify backend/src/api/users.rs
- modify backend/src/api/voting_config.rs
- modify backend/src/api/workflows.rs
- modify backend/src/auth/jwt.rs
- modify backend/src/auth/middleware.rs
- modify backend/src/auth/mod.rs
- modify backend/src/demo/mod.rs
- modify backend/src/main.rs
- modify backend/src/models/community.rs
- modify backend/src/models/mod.rs
- modify backend/src/models/proposal.rs
- modify backend/src/models/user.rs
- modify backend/src/plugins/builtin/conflict_resolution.rs
- modify backend/src/plugins/builtin/decision_workflows.rs
- modify backend/src/plugins/builtin/federation.rs
- modify backend/src/plugins/builtin/governance_analytics.rs
- modify backend/src/plugins/builtin/moderation_ledger.rs
- modify backend/src/plugins/builtin/proposal_lifecycle.rs
- modify backend/src/plugins/builtin/public_data_export.rs
- modify backend/src/plugins/builtin/self_moderation.rs
- modify backend/src/plugins/builtin/structured_deliberation.rs
- modify backend/src/plugins/hooks.rs
- modify backend/src/plugins/manager.rs
- modify backend/src/plugins/wasm/host_api.rs
- modify backend/src/plugins/wasm/plugin.rs
- modify backend/src/plugins/wasm/runtime.rs
- modify backend/src/rate_limit.rs
- modify backend/src/voting/mod.rs
- modify backend/src/voting/quadratic.rs
- modify backend/src/voting/ranked_choice.rs
- modify backend/src/voting/schulze.rs
- modify backend/src/voting/star.rs

Diffstat:
- 56 files changed, 2697 insertions(+), 1629 deletions(-)
2026-02-03 17:54:39 +01:00

305 lines
8.2 KiB
Rust

//! Conflict Resolution API endpoints.
use axum::{
extract::{Path, State},
http::StatusCode,
routing::{get, post},
Json, Router,
};
use serde::Deserialize;
use serde_json::{json, Value};
use sqlx::PgPool;
use uuid::Uuid;
use crate::auth::AuthUser;
use crate::plugins::builtin::conflict_resolution::{ConflictCase, ConflictService};
// ============================================================================
// Request Types
// ============================================================================
#[derive(Debug, Deserialize)]
pub struct ReportConflictRequest {
pub conflict_type: String,
pub title: String,
pub description: String,
pub party_a_id: Uuid,
pub party_b_id: Option<Uuid>,
pub anonymous: bool,
pub severity: i32,
}
#[derive(Debug, Deserialize)]
pub struct TransitionStatusRequest {
pub new_status: String,
pub notes: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct ProposeCompromiseRequest {
pub title: String,
pub description: String,
pub proposed_actions: Value,
pub proposed_by_role: String,
}
#[derive(Debug, Deserialize)]
pub struct RespondToCompromiseRequest {
pub party: String,
pub response: String,
pub feedback: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct ScheduleSessionRequest {
pub scheduled_for: chrono::DateTime<chrono::Utc>,
pub duration_minutes: i32,
pub agenda: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct AddNoteRequest {
pub content: String,
pub note_type: String,
pub session_id: Option<Uuid>,
pub is_confidential: bool,
}
#[derive(Debug, Deserialize)]
pub struct AddMediatorRequest {
pub user_id: Uuid,
pub certification_level: Option<String>,
}
// ============================================================================
// Handlers
// ============================================================================
/// Get active conflicts in a community
async fn get_active_conflicts(
_auth: AuthUser,
Path(community_id): Path<Uuid>,
State(pool): State<PgPool>,
) -> Result<Json<Vec<ConflictCase>>, (StatusCode, String)> {
let conflicts = ConflictService::get_active_conflicts(&pool, community_id)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
Ok(Json(conflicts))
}
/// Get a specific conflict
async fn get_conflict(
_auth: AuthUser,
Path(conflict_id): Path<Uuid>,
State(pool): State<PgPool>,
) -> Result<Json<Option<ConflictCase>>, (StatusCode, String)> {
let conflict = ConflictService::get_conflict(&pool, conflict_id)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
Ok(Json(conflict))
}
/// Report a new conflict
async fn report_conflict(
auth: AuthUser,
Path(community_id): Path<Uuid>,
State(pool): State<PgPool>,
Json(req): Json<ReportConflictRequest>,
) -> Result<Json<Value>, (StatusCode, String)> {
let conflict_id = ConflictService::report_conflict(
&pool,
community_id,
&req.title,
&req.description,
&req.conflict_type,
req.party_a_id,
req.party_b_id,
Some(auth.user_id),
req.anonymous,
req.severity,
)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
Ok(Json(json!({"id": conflict_id})))
}
/// Transition conflict status
async fn transition_status(
auth: AuthUser,
Path(conflict_id): Path<Uuid>,
State(pool): State<PgPool>,
Json(req): Json<TransitionStatusRequest>,
) -> Result<Json<Value>, (StatusCode, String)> {
ConflictService::transition_status(
&pool,
conflict_id,
&req.new_status,
auth.user_id,
req.notes.as_deref(),
)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
Ok(Json(json!({"success": true})))
}
/// Propose a compromise
async fn propose_compromise(
auth: AuthUser,
Path(conflict_id): Path<Uuid>,
State(pool): State<PgPool>,
Json(req): Json<ProposeCompromiseRequest>,
) -> Result<Json<Value>, (StatusCode, String)> {
let proposal_id = ConflictService::propose_compromise(
&pool,
conflict_id,
&req.title,
&req.description,
req.proposed_actions,
auth.user_id,
&req.proposed_by_role,
)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
Ok(Json(json!({"id": proposal_id})))
}
/// Respond to a compromise proposal
async fn respond_to_compromise(
_auth: AuthUser,
Path(proposal_id): Path<Uuid>,
State(pool): State<PgPool>,
Json(req): Json<RespondToCompromiseRequest>,
) -> Result<Json<Value>, (StatusCode, String)> {
ConflictService::respond_to_compromise(
&pool,
proposal_id,
&req.party,
&req.response,
req.feedback.as_deref(),
)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
Ok(Json(json!({"success": true})))
}
/// Schedule a mediation session
async fn schedule_session(
_auth: AuthUser,
Path(conflict_id): Path<Uuid>,
State(pool): State<PgPool>,
Json(req): Json<ScheduleSessionRequest>,
) -> Result<Json<Value>, (StatusCode, String)> {
let session_id = ConflictService::schedule_session(
&pool,
conflict_id,
req.scheduled_for,
req.duration_minutes,
req.agenda.as_deref(),
)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
Ok(Json(json!({"id": session_id})))
}
/// Add a note to a conflict
async fn add_note(
auth: AuthUser,
Path(conflict_id): Path<Uuid>,
State(pool): State<PgPool>,
Json(req): Json<AddNoteRequest>,
) -> Result<Json<Value>, (StatusCode, String)> {
let note_id = ConflictService::add_note(
&pool,
conflict_id,
req.session_id,
auth.user_id,
&req.content,
&req.note_type,
req.is_confidential,
)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
Ok(Json(json!({"id": note_id})))
}
/// Get conflict statistics for a community
async fn get_statistics(
_auth: AuthUser,
Path(community_id): Path<Uuid>,
State(pool): State<PgPool>,
) -> Result<Json<Value>, (StatusCode, String)> {
let stats = ConflictService::get_statistics(&pool, community_id)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
Ok(Json(stats))
}
/// Add user to mediator pool
async fn add_to_mediator_pool(
_auth: AuthUser,
Path(community_id): Path<Uuid>,
State(pool): State<PgPool>,
Json(req): Json<AddMediatorRequest>,
) -> Result<Json<Value>, (StatusCode, String)> {
let mediator_id = ConflictService::add_to_mediator_pool(
&pool,
community_id,
req.user_id,
req.certification_level.as_deref(),
)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
Ok(Json(json!({"id": mediator_id})))
}
// ============================================================================
// Router
// ============================================================================
pub fn router(pool: PgPool) -> Router {
Router::new()
// Community conflicts
.route(
"/api/communities/{community_id}/conflicts",
get(get_active_conflicts).post(report_conflict),
)
.route(
"/api/communities/{community_id}/conflicts/stats",
get(get_statistics),
)
.route(
"/api/communities/{community_id}/mediators",
post(add_to_mediator_pool),
)
// Individual conflict operations
.route("/api/conflicts/{conflict_id}", get(get_conflict))
.route(
"/api/conflicts/{conflict_id}/status",
post(transition_status),
)
.route(
"/api/conflicts/{conflict_id}/compromise",
post(propose_compromise),
)
.route(
"/api/conflicts/{conflict_id}/session",
post(schedule_session),
)
.route("/api/conflicts/{conflict_id}/note", post(add_note))
// Compromise responses
.route(
"/api/compromises/{proposal_id}/respond",
post(respond_to_compromise),
)
.with_state(pool)
}