mirror of
https://codeberg.org/likwid/likwid.git
synced 2026-06-25 07:27:42 +00:00
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(-)
305 lines
8.2 KiB
Rust
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)
|
|
}
|