feat: Refactor governance models and views
- Moved governance models (`Vote`, `VoteType`, `VotingResults`) from `models/governance.rs` to `controllers/governance.rs` for better organization and to avoid circular dependencies. This improves maintainability and reduces complexity. - Updated governance views to use the new model locations. - Added a limit to the number of recent activities displayed on the dashboard for performance optimization.
This commit is contained in:
parent
9802d51acc
commit
7e95391a9c
@ -2,7 +2,7 @@ use crate::db::governance::{
|
||||
self, create_activity, get_all_activities, get_proposal_by_id, get_proposals,
|
||||
get_recent_activities,
|
||||
};
|
||||
use crate::models::governance::{Vote, VoteType, VotingResults};
|
||||
// Note: Now using heromodels directly instead of local governance models
|
||||
use crate::utils::render_template;
|
||||
use actix_session::Session;
|
||||
use actix_web::{HttpResponse, Responder, Result, web};
|
||||
@ -15,6 +15,71 @@ use tera::Tera;
|
||||
|
||||
use chrono::prelude::*;
|
||||
|
||||
/// Simple vote type for UI display
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum VoteType {
|
||||
Yes,
|
||||
No,
|
||||
Abstain,
|
||||
}
|
||||
|
||||
/// Simple vote structure for UI display
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Vote {
|
||||
pub id: String,
|
||||
pub proposal_id: String,
|
||||
pub voter_id: i32,
|
||||
pub voter_name: String,
|
||||
pub vote_type: VoteType,
|
||||
pub comment: Option<String>,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
impl Vote {
|
||||
pub fn new(
|
||||
proposal_id: String,
|
||||
voter_id: i32,
|
||||
voter_name: String,
|
||||
vote_type: VoteType,
|
||||
comment: Option<String>,
|
||||
) -> Self {
|
||||
let now = Utc::now();
|
||||
Self {
|
||||
id: uuid::Uuid::new_v4().to_string(),
|
||||
proposal_id,
|
||||
voter_id,
|
||||
voter_name,
|
||||
vote_type,
|
||||
comment,
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Simple voting results structure for UI display
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct VotingResults {
|
||||
pub proposal_id: String,
|
||||
pub yes_count: usize,
|
||||
pub no_count: usize,
|
||||
pub abstain_count: usize,
|
||||
pub total_votes: usize,
|
||||
}
|
||||
|
||||
impl VotingResults {
|
||||
pub fn new(proposal_id: String) -> Self {
|
||||
Self {
|
||||
proposal_id,
|
||||
yes_count: 0,
|
||||
no_count: 0,
|
||||
abstain_count: 0,
|
||||
total_votes: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Controller for handling governance-related routes
|
||||
pub struct GovernanceController;
|
||||
|
||||
@ -153,9 +218,9 @@ impl GovernanceController {
|
||||
let stats = Self::calculate_statistics_from_database(&proposals_for_stats);
|
||||
ctx.insert("stats", &stats);
|
||||
|
||||
// Get recent governance activities from our tracker
|
||||
// Get recent governance activities from our tracker (limit to 4 for dashboard)
|
||||
let recent_activity = match Self::get_recent_governance_activities() {
|
||||
Ok(activities) => activities,
|
||||
Ok(activities) => activities.into_iter().take(4).collect::<Vec<_>>(),
|
||||
Err(e) => {
|
||||
eprintln!("Failed to load recent activities: {}", e);
|
||||
Vec::new()
|
||||
|
@ -1,222 +0,0 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
/// Represents the status of a governance proposal
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum ProposalStatus {
|
||||
/// Proposal is in draft status, not yet open for voting
|
||||
Draft,
|
||||
/// Proposal is active and open for voting
|
||||
Active,
|
||||
/// Proposal has been approved by the community
|
||||
Approved,
|
||||
/// Proposal has been rejected by the community
|
||||
Rejected,
|
||||
/// Proposal has been cancelled by the creator
|
||||
Cancelled,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ProposalStatus {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
ProposalStatus::Draft => write!(f, "Draft"),
|
||||
ProposalStatus::Active => write!(f, "Active"),
|
||||
ProposalStatus::Approved => write!(f, "Approved"),
|
||||
ProposalStatus::Rejected => write!(f, "Rejected"),
|
||||
ProposalStatus::Cancelled => write!(f, "Cancelled"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a vote on a governance proposal
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum VoteType {
|
||||
/// Vote in favor of the proposal
|
||||
Yes,
|
||||
/// Vote against the proposal
|
||||
No,
|
||||
/// Abstain from voting on the proposal
|
||||
Abstain,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for VoteType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
VoteType::Yes => write!(f, "Yes"),
|
||||
VoteType::No => write!(f, "No"),
|
||||
VoteType::Abstain => write!(f, "Abstain"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a governance proposal in the system
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Proposal {
|
||||
/// Unique identifier for the proposal
|
||||
pub id: String,
|
||||
/// User ID of the proposal creator
|
||||
pub creator_id: i32,
|
||||
/// Name of the proposal creator
|
||||
pub creator_name: String,
|
||||
/// Title of the proposal
|
||||
pub title: String,
|
||||
/// Detailed description of the proposal
|
||||
pub description: String,
|
||||
/// Current status of the proposal
|
||||
pub status: ProposalStatus,
|
||||
/// Date and time when the proposal was created
|
||||
pub created_at: DateTime<Utc>,
|
||||
/// Date and time when the proposal was last updated
|
||||
pub updated_at: DateTime<Utc>,
|
||||
/// Date and time when voting starts
|
||||
pub voting_starts_at: Option<DateTime<Utc>>,
|
||||
/// Date and time when voting ends
|
||||
pub voting_ends_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl Proposal {
|
||||
/// Creates a new proposal
|
||||
pub fn new(creator_id: i32, creator_name: String, title: String, description: String) -> Self {
|
||||
let now = Utc::now();
|
||||
Self {
|
||||
id: Uuid::new_v4().to_string(),
|
||||
creator_id,
|
||||
creator_name,
|
||||
title,
|
||||
description,
|
||||
status: ProposalStatus::Draft,
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
voting_starts_at: None,
|
||||
voting_ends_at: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates the proposal status
|
||||
pub fn update_status(&mut self, status: ProposalStatus) {
|
||||
self.status = status;
|
||||
self.updated_at = Utc::now();
|
||||
}
|
||||
|
||||
/// Sets the voting period for the proposal
|
||||
pub fn set_voting_period(&mut self, starts_at: DateTime<Utc>, ends_at: DateTime<Utc>) {
|
||||
self.voting_starts_at = Some(starts_at);
|
||||
self.voting_ends_at = Some(ends_at);
|
||||
self.updated_at = Utc::now();
|
||||
}
|
||||
|
||||
/// Activates the proposal for voting
|
||||
pub fn activate(&mut self) {
|
||||
self.status = ProposalStatus::Active;
|
||||
self.updated_at = Utc::now();
|
||||
}
|
||||
|
||||
/// Cancels the proposal
|
||||
pub fn cancel(&mut self) {
|
||||
self.status = ProposalStatus::Cancelled;
|
||||
self.updated_at = Utc::now();
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a vote cast on a proposal
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Vote {
|
||||
/// Unique identifier for the vote
|
||||
pub id: String,
|
||||
/// ID of the proposal being voted on
|
||||
pub proposal_id: String,
|
||||
/// User ID of the voter
|
||||
pub voter_id: i32,
|
||||
/// Name of the voter
|
||||
pub voter_name: String,
|
||||
/// Type of vote cast
|
||||
pub vote_type: VoteType,
|
||||
/// Optional comment explaining the vote
|
||||
pub comment: Option<String>,
|
||||
/// Date and time when the vote was cast
|
||||
pub created_at: DateTime<Utc>,
|
||||
/// Date and time when the vote was last updated
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl Vote {
|
||||
/// Creates a new vote
|
||||
pub fn new(
|
||||
proposal_id: String,
|
||||
voter_id: i32,
|
||||
voter_name: String,
|
||||
vote_type: VoteType,
|
||||
comment: Option<String>,
|
||||
) -> Self {
|
||||
let now = Utc::now();
|
||||
Self {
|
||||
id: Uuid::new_v4().to_string(),
|
||||
proposal_id,
|
||||
voter_id,
|
||||
voter_name,
|
||||
vote_type,
|
||||
comment,
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates the vote type
|
||||
pub fn update_vote(&mut self, vote_type: VoteType, comment: Option<String>) {
|
||||
self.vote_type = vote_type;
|
||||
self.comment = comment;
|
||||
self.updated_at = Utc::now();
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a filter for searching proposals
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ProposalFilter {
|
||||
/// Filter by proposal status
|
||||
pub status: Option<String>,
|
||||
/// Filter by creator ID
|
||||
pub creator_id: Option<i32>,
|
||||
/// Search term for title and description
|
||||
pub search: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for ProposalFilter {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
status: None,
|
||||
creator_id: None,
|
||||
search: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the voting results for a proposal
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct VotingResults {
|
||||
/// Proposal ID
|
||||
pub proposal_id: String,
|
||||
/// Number of yes votes
|
||||
pub yes_count: usize,
|
||||
/// Number of no votes
|
||||
pub no_count: usize,
|
||||
/// Number of abstain votes
|
||||
pub abstain_count: usize,
|
||||
/// Total number of votes
|
||||
pub total_votes: usize,
|
||||
}
|
||||
|
||||
impl VotingResults {
|
||||
/// Creates a new VotingResults instance
|
||||
pub fn new(proposal_id: String) -> Self {
|
||||
Self {
|
||||
proposal_id,
|
||||
yes_count: 0,
|
||||
no_count: 0,
|
||||
abstain_count: 0,
|
||||
total_votes: 0,
|
||||
}
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ pub mod calendar;
|
||||
pub mod contract;
|
||||
pub mod defi;
|
||||
pub mod flow;
|
||||
pub mod governance;
|
||||
|
||||
pub mod marketplace;
|
||||
pub mod ticket;
|
||||
pub mod user;
|
||||
|
@ -87,15 +87,16 @@
|
||||
|
||||
<div class="mb-4">
|
||||
<h5 class="mb-3">Cast Your Vote</h5>
|
||||
<form>
|
||||
<form action="/governance/proposals/{{ nearest_proposal.base_data.id }}/vote" method="post">
|
||||
<div class="mb-3">
|
||||
<input type="text" class="form-control" placeholder="Optional comment on your vote"
|
||||
aria-label="Vote comment">
|
||||
<input type="text" class="form-control" name="comment"
|
||||
placeholder="Optional comment on your vote" aria-label="Vote comment">
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<button type="submit" name="vote" value="yes" class="btn btn-success">Vote Yes</button>
|
||||
<button type="submit" name="vote" value="no" class="btn btn-danger">Vote No</button>
|
||||
<button type="submit" name="vote" value="abstain" class="btn btn-secondary">Abstain</button>
|
||||
<button type="submit" name="vote_type" value="Yes" class="btn btn-success">Vote Yes</button>
|
||||
<button type="submit" name="vote_type" value="No" class="btn btn-danger">Vote No</button>
|
||||
<button type="submit" name="vote_type" value="Abstain"
|
||||
class="btn btn-secondary">Abstain</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user