// heromodels/examples/governance_proposal_example/main.rs use chrono::{Utc, Duration}; use heromodels::db::{Collection, Db}; use heromodels::models::governance::{Proposal, ProposalStatus, VoteEventStatus}; fn main() { println!("Governance Proposal Model Example\n"); // Create a new DB instance, reset before every run let db_path = "/tmp/ourdb_governance_proposal_example"; let db = heromodels::db::hero::OurDB::new(db_path, true).expect("Can create DB"); // Create a new proposal with auto-generated ID let mut proposal = Proposal::new( None, // id (auto-generated) "user_creator_123", // creator_id "Community Fund Allocation for Q3", // title "Proposal to allocate funds for community projects in the third quarter.", // description Utc::now(), // vote_start_date Utc::now() + Duration::days(14) // vote_end_date (14 days from now) ); println!("Before saving - Created Proposal: '{}' (ID: {})", proposal.title, proposal.base_data.id); println!("Before saving - Status: {:?}, Vote Status: {:?}", proposal.status, proposal.vote_status); println!("Before saving - Vote Period: {} to {}\n", proposal.vote_start_date, proposal.vote_end_date); // Add vote options proposal = proposal.add_option(1, "Approve Allocation"); proposal = proposal.add_option(2, "Reject Allocation"); proposal = proposal.add_option(3, "Abstain"); println!("Added Vote Options:"); for option in &proposal.options { println!("- Option ID: {}, Text: '{}', Votes: {}", option.id, option.text, option.count); } println!(""); // Save the proposal to the database let collection = db.collection::().expect("can open proposal collection"); let (proposal_id, saved_proposal) = collection.set(&proposal).expect("can save proposal"); println!("After saving - Proposal ID: {}", saved_proposal.base_data.id); println!("After saving - Returned ID: {}", proposal_id); // Use the saved proposal for further operations proposal = saved_proposal; // Simulate casting votes println!("Simulating Votes..."); // User 1 votes for 'Approve Allocation' with 100 shares (with explicit ballot ID) proposal = proposal.cast_vote(Some(101), 1, 1, 100); // User 2 votes for 'Reject Allocation' with 50 shares (with explicit ballot ID) proposal = proposal.cast_vote(Some(102), 2, 2, 50); // User 3 votes for 'Approve Allocation' with 75 shares (with auto-generated ballot ID) proposal = proposal.cast_vote(None, 3, 1, 75); // User 4 abstains with 20 shares (with auto-generated ballot ID) proposal = proposal.cast_vote(None, 4, 3, 20); // User 5 attempts to vote for a non-existent option (should be handled gracefully) proposal = proposal.cast_vote(Some(105), 5, 99, 10); // User 1 tries to vote again (not explicitly prevented by current model, but could be a future enhancement) // proposal = proposal.cast_vote(Some(106), 1, 1, 10); println!("\nVote Counts After Simulation:"); for option in &proposal.options { println!("- Option ID: {}, Text: '{}', Votes: {}", option.id, option.text, option.count); } println!("\nBallots Cast:"); for ballot in &proposal.ballots { println!("- Ballot ID: {}, User ID: {}, Option ID: {}, Shares: {}", ballot.base_data.id, ballot.user_id, ballot.vote_option_id, ballot.shares_count); } println!(""); // Change proposal status proposal = proposal.change_proposal_status(ProposalStatus::Active); println!("Changed Proposal Status to: {:?}", proposal.status); // Simulate closing the vote proposal = proposal.change_vote_event_status(VoteEventStatus::Closed); println!("Changed Vote Event Status to: {:?}", proposal.vote_status); // Attempt to cast a vote after closing (should be handled) println!("\nAttempting to cast vote after voting is closed..."); proposal = proposal.cast_vote(None, 6, 1, 25); // Final proposal state println!("\nFinal Proposal State:"); println!("Title: '{}'", proposal.title); println!("Status: {:?}", proposal.status); println!("Vote Status: {:?}", proposal.vote_status); println!("Options:"); for option in &proposal.options { println!(" - {}: {} (Votes: {})", option.id, option.text, option.count); } println!("Total Ballots: {}", proposal.ballots.len()); // Example of a private proposal (not fully implemented in cast_vote eligibility yet) let mut private_proposal = Proposal::new( None, // auto-generated ID "user_admin_001", "Internal Team Restructure Vote", "Vote on proposed internal team changes.", Utc::now(), Utc::now() + Duration::days(7) ); private_proposal.private_group = Some(vec![10, 20, 30]); // Only users 10, 20, 30 can vote private_proposal = private_proposal.add_option(1, "Accept Restructure"); private_proposal = private_proposal.add_option(2, "Reject Restructure"); println!("\nBefore saving - Created Private Proposal: '{}'", private_proposal.title); println!("Before saving - Eligible Voters (Group): {:?}", private_proposal.private_group); // Save the private proposal to the database let (private_proposal_id, saved_private_proposal) = collection.set(&private_proposal).expect("can save private proposal"); private_proposal = saved_private_proposal; println!("After saving - Private Proposal ID: {}", private_proposal.base_data.id); println!("After saving - Returned ID: {}", private_proposal_id); // User 10 (eligible) votes with explicit ballot ID private_proposal = private_proposal.cast_vote(Some(201), 10, 1, 100); // User 40 (ineligible) tries to vote with auto-generated ballot ID private_proposal = private_proposal.cast_vote(None, 40, 1, 50); println!("Private Proposal Vote Counts:"); for option in &private_proposal.options { println!(" - {}: {} (Votes: {})", option.id, option.text, option.count); } println!("\nExample finished. DB stored at {}", db_path); println!("To clean up, you can manually delete the directory: {}", db_path); }