feat: Load voting

This commit is contained in:
Mahmoud-Emad 2025-05-21 15:04:45 +03:00
parent 5d9eaac1f8
commit 916f435dbc
2 changed files with 115 additions and 8 deletions

View File

@ -130,8 +130,8 @@ impl GovernanceController {
if let Ok(Some(proposal)) = proposal { if let Ok(Some(proposal)) = proposal {
ctx.insert("proposal", &proposal); ctx.insert("proposal", &proposal);
// Get mock votes for this proposal // Extract votes directly from the proposal
let votes = Self::get_mock_votes_for_proposal(&proposal_id); let votes = Self::extract_votes_from_proposal(&proposal);
ctx.insert("votes", &votes); ctx.insert("votes", &votes);
// Calculate voting results directly from the proposal // Calculate voting results directly from the proposal
@ -301,14 +301,14 @@ impl GovernanceController {
user_id, user_id,
&form.vote_type, &form.vote_type,
1, // Default to 1 share 1, // Default to 1 share
form.comment.as_ref().map(|s| s.to_string()), // Pass the comment from the form
) { ) {
Ok(updated_proposal) => { Ok(updated_proposal) => {
ctx.insert("proposal", &updated_proposal); ctx.insert("proposal", &updated_proposal);
ctx.insert("success", "Your vote has been recorded!"); ctx.insert("success", "Your vote has been recorded!");
// Get votes for this proposal // Extract votes directly from the updated proposal
// For now, we'll still use mock votes until we implement a function to extract votes from the proposal let votes = Self::extract_votes_from_proposal(&updated_proposal);
let votes = Self::get_mock_votes_for_proposal(&proposal_id);
ctx.insert("votes", &votes); ctx.insert("votes", &votes);
// Calculate voting results directly from the updated proposal // Calculate voting results directly from the updated proposal
@ -639,6 +639,95 @@ impl GovernanceController {
results results
} }
/// Extract votes from a proposal's ballots
fn extract_votes_from_proposal(proposal: &Proposal) -> Vec<Vote> {
let mut votes = Vec::new();
// Debug: Print proposal ID and number of ballots
println!(
"Extracting votes from proposal ID: {}",
proposal.base_data.id
);
println!("Number of ballots in proposal: {}", proposal.ballots.len());
// If there are no ballots, create some mock votes for testing
if proposal.ballots.is_empty() {
println!("No ballots found in proposal, creating mock votes for testing");
// Create mock votes based on the option counts
for option in &proposal.options {
if option.count > 0 {
let vote_type = match option.id {
1 => VoteType::Yes,
2 => VoteType::No,
3 => VoteType::Abstain,
_ => continue,
};
// Create a mock vote for each count
for i in 0..option.count {
let vote = Vote::new(
proposal.base_data.id.to_string(),
i as i32 + 1,
format!("User {}", i + 1),
vote_type.clone(),
option.comment.clone(),
);
votes.push(vote);
}
}
}
println!("Created {} mock votes", votes.len());
return votes;
}
// Convert each ballot to a Vote
for (i, ballot) in proposal.ballots.iter().enumerate() {
println!(
"Processing ballot {}: user_id={}, option_id={}, shares={}",
i, ballot.user_id, ballot.vote_option_id, ballot.shares_count
);
// Map option_id to VoteType
let vote_type = match ballot.vote_option_id {
1 => VoteType::Yes,
2 => VoteType::No,
3 => VoteType::Abstain,
_ => {
println!(
"Unknown option_id: {}, defaulting to Abstain",
ballot.vote_option_id
);
VoteType::Abstain // Default to Abstain for unknown options
}
};
// Convert user_id from u32 to i32 safely
let voter_id = match i32::try_from(ballot.user_id) {
Ok(id) => id,
Err(e) => {
println!("Failed to convert user_id {} to i32: {}", ballot.user_id, e);
continue; // Skip this ballot if conversion fails
}
};
// Create a Vote from the ballot
let vote = Vote::new(
proposal.base_data.id.to_string(),
voter_id,
format!("User {}", voter_id),
vote_type,
ballot.comment.clone(), // Use the comment from the ballot
);
votes.push(vote);
}
println!("Extracted {} votes from proposal", votes.len());
votes
}
/// Generate mock statistics for the governance dashboard /// Generate mock statistics for the governance dashboard
fn get_mock_statistics() -> GovernanceStats { fn get_mock_statistics() -> GovernanceStats {
GovernanceStats { GovernanceStats {

View File

@ -4,11 +4,11 @@ use chrono::{Duration, Utc};
use heromodels::db::hero::OurDB; use heromodels::db::hero::OurDB;
use heromodels::{ use heromodels::{
db::{Collection, Db}, db::{Collection, Db},
models::governance::{Proposal, ProposalStatus, VoteEventStatus}, models::governance::{Proposal, ProposalStatus},
}; };
/// The path to the database file. Change this as needed for your environment. /// The path to the database file. Change this as needed for your environment.
pub const DB_PATH: &str = "/tmp/ourdb_governance3"; pub const DB_PATH: &str = "/tmp/ourdb_governance6";
/// Returns a shared OurDB instance for the given path. You can wrap this in Arc/Mutex for concurrent access if needed. /// Returns a shared OurDB instance for the given path. You can wrap this in Arc/Mutex for concurrent access if needed.
pub fn get_db(db_path: &str) -> Result<OurDB, String> { pub fn get_db(db_path: &str) -> Result<OurDB, String> {
@ -97,6 +97,7 @@ pub fn submit_vote_on_proposal(
user_id: i32, user_id: i32,
vote_type: &str, vote_type: &str,
shares_count: u32, // Default to 1 if not specified shares_count: u32, // Default to 1 if not specified
comment: Option<String>,
) -> Result<Proposal, String> { ) -> Result<Proposal, String> {
// Get the proposal from the database // Get the proposal from the database
let db = get_db(DB_PATH).map_err(|e| format!("DB error: {}", e))?; let db = get_db(DB_PATH).map_err(|e| format!("DB error: {}", e))?;
@ -173,6 +174,23 @@ pub fn submit_vote_on_proposal(
ballot_id, user_id, option_id, shares_count ballot_id, user_id, option_id, shares_count
); );
// Create a new ballot and add it to the proposal's ballots
use heromodels::models::governance::Ballot;
// Use the Ballot::new constructor which handles the BaseModelData creation
let mut ballot = Ballot::new(
Some(ballot_id),
user_id as u32,
option_id,
shares_count as i64,
);
// Set the comment if provided
ballot.comment = comment;
// Add the ballot to the proposal's ballots
proposal.ballots.push(ballot);
// Update the proposal's updated_at timestamp // Update the proposal's updated_at timestamp
proposal.updated_at = Utc::now(); proposal.updated_at = Utc::now();