feat: Enhance governance proposal model with activity tracking
- Add `Activity` model to track proposal creation and voting. - Include `ActivityType` enum for different activity types. - Improve `Proposal` model to record voting with comments. - Refactor `models/governance` module for better organization.
This commit is contained in:
		@@ -2,4 +2,6 @@
 | 
			
		||||
// This module will contain the Proposal model and related types.
 | 
			
		||||
pub mod proposal;
 | 
			
		||||
 | 
			
		||||
pub use self::proposal::{Proposal, Ballot, VoteOption, ProposalStatus, VoteEventStatus};
 | 
			
		||||
pub use self::proposal::{
 | 
			
		||||
    Activity, ActivityType, Ballot, Proposal, ProposalStatus, VoteEventStatus, VoteOption,
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -70,9 +70,9 @@ impl VoteOption {
 | 
			
		||||
#[model] // Has base.Base in V spec
 | 
			
		||||
pub struct Ballot {
 | 
			
		||||
    pub base_data: BaseModelData,
 | 
			
		||||
    pub user_id: u32,       // The ID of the user who cast this ballot
 | 
			
		||||
    pub vote_option_id: u8, // The 'id' of the VoteOption chosen
 | 
			
		||||
    pub shares_count: i64,  // Number of shares/tokens/voting power
 | 
			
		||||
    pub user_id: u32,            // The ID of the user who cast this ballot
 | 
			
		||||
    pub vote_option_id: u8,      // The 'id' of the VoteOption chosen
 | 
			
		||||
    pub shares_count: i64,       // Number of shares/tokens/voting power
 | 
			
		||||
    pub comment: Option<String>, // Optional comment from the voter
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -253,7 +253,7 @@ impl Proposal {
 | 
			
		||||
            eprintln!("Voting is not open for proposal '{}'", self.title);
 | 
			
		||||
            return self;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        // Check if the option exists
 | 
			
		||||
        if !self.options.iter().any(|opt| opt.id == chosen_option_id) {
 | 
			
		||||
            eprintln!(
 | 
			
		||||
@@ -262,7 +262,7 @@ impl Proposal {
 | 
			
		||||
            );
 | 
			
		||||
            return self;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        // Check eligibility for private proposals
 | 
			
		||||
        if let Some(group) = &self.private_group {
 | 
			
		||||
            if !group.contains(&user_id) {
 | 
			
		||||
@@ -273,14 +273,14 @@ impl Proposal {
 | 
			
		||||
                return self;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        // Create a new ballot with the comment
 | 
			
		||||
        let mut new_ballot = Ballot::new(ballot_id, user_id, chosen_option_id, shares);
 | 
			
		||||
        new_ballot.comment = Some(comment.to_string());
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        // Add the ballot to the proposal
 | 
			
		||||
        self.ballots.push(new_ballot);
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        // Update the vote count for the chosen option
 | 
			
		||||
        if let Some(option) = self
 | 
			
		||||
            .options
 | 
			
		||||
@@ -289,7 +289,146 @@ impl Proposal {
 | 
			
		||||
        {
 | 
			
		||||
            option.count += shares;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub enum ActivityType {
 | 
			
		||||
    ProposalCreated,
 | 
			
		||||
    VoteCast,
 | 
			
		||||
    VotingStarted,
 | 
			
		||||
    VotingEnded,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ToString for ActivityType {
 | 
			
		||||
    fn to_string(&self) -> String {
 | 
			
		||||
        match self {
 | 
			
		||||
            ActivityType::ProposalCreated => "proposal_created",
 | 
			
		||||
            ActivityType::VoteCast => "vote_cast",
 | 
			
		||||
            ActivityType::VotingStarted => "voting_started",
 | 
			
		||||
            ActivityType::VotingEnded => "voting_ended",
 | 
			
		||||
        }
 | 
			
		||||
        .to_string()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Represents a governance activity in the system
 | 
			
		||||
#[derive(Debug, Clone, Serialize, Deserialize, CustomType)]
 | 
			
		||||
#[rhai_model_export(db_type = "std::sync::Arc<crate::db::hero::OurDB>")]
 | 
			
		||||
#[model] // Has base.Base in V spec
 | 
			
		||||
pub struct Activity {
 | 
			
		||||
    /// Base model data
 | 
			
		||||
    pub base_data: BaseModelData,
 | 
			
		||||
    /// Type of activity (proposal_created, vote_cast, etc.)
 | 
			
		||||
    pub activity_type: String,
 | 
			
		||||
    /// ID of the related proposal
 | 
			
		||||
    pub proposal_id: u32,
 | 
			
		||||
    /// Title of the related proposal
 | 
			
		||||
    pub proposal_title: String,
 | 
			
		||||
    /// Name of the user who performed the action
 | 
			
		||||
    pub creator_name: String,
 | 
			
		||||
    /// Description of the activity
 | 
			
		||||
    pub description: String,
 | 
			
		||||
    /// Date and time when the activity was last updated
 | 
			
		||||
    pub updated_at: DateTime<Utc>,
 | 
			
		||||
    /// Date and time when the activity was created
 | 
			
		||||
    pub created_at: DateTime<Utc>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Activity {
 | 
			
		||||
    /// Create a default instance
 | 
			
		||||
    pub fn default() -> Self {
 | 
			
		||||
        let base_data = BaseModelData::new();
 | 
			
		||||
        let created_at = Utc::now();
 | 
			
		||||
        let updated_at = created_at;
 | 
			
		||||
 | 
			
		||||
        Self {
 | 
			
		||||
            base_data,
 | 
			
		||||
            activity_type: String::new(),
 | 
			
		||||
            proposal_id: 0,
 | 
			
		||||
            proposal_title: String::new(),
 | 
			
		||||
            creator_name: String::new(),
 | 
			
		||||
            description: String::new(),
 | 
			
		||||
            updated_at,
 | 
			
		||||
            created_at,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Creates a new governance activity
 | 
			
		||||
    pub fn new(
 | 
			
		||||
        id: Option<u32>,
 | 
			
		||||
        activity_type: &str,
 | 
			
		||||
        proposal_id: u32,
 | 
			
		||||
        proposal_title: &str,
 | 
			
		||||
        creator_name: &str,
 | 
			
		||||
        description: &str,
 | 
			
		||||
    ) -> Self {
 | 
			
		||||
        let mut base_data = BaseModelData::new();
 | 
			
		||||
        if let Some(id) = id {
 | 
			
		||||
            base_data.update_id(id);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let created_at = Utc::now();
 | 
			
		||||
        let updated_at = created_at;
 | 
			
		||||
 | 
			
		||||
        Self {
 | 
			
		||||
            base_data,
 | 
			
		||||
            activity_type: activity_type.to_string(),
 | 
			
		||||
            proposal_id,
 | 
			
		||||
            proposal_title: proposal_title.to_string(),
 | 
			
		||||
            creator_name: creator_name.to_string(),
 | 
			
		||||
            description: description.to_string(),
 | 
			
		||||
            updated_at,
 | 
			
		||||
            created_at,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Creates a proposal creation activity
 | 
			
		||||
    pub fn proposal_created(proposal_id: u32, proposal_title: &str, creator_name: &str) -> Self {
 | 
			
		||||
        Self::new(
 | 
			
		||||
            None,
 | 
			
		||||
            &ActivityType::ProposalCreated.to_string(),
 | 
			
		||||
            proposal_id,
 | 
			
		||||
            proposal_title,
 | 
			
		||||
            creator_name,
 | 
			
		||||
            &format!("Proposal '{}' created by {}", proposal_title, creator_name),
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Creates a vote cast activity
 | 
			
		||||
    pub fn vote_cast(proposal_id: u32, proposal_title: &str, voter_name: &str) -> Self {
 | 
			
		||||
        Self::new(
 | 
			
		||||
            None,
 | 
			
		||||
            &ActivityType::VoteCast.to_string(),
 | 
			
		||||
            proposal_id,
 | 
			
		||||
            proposal_title,
 | 
			
		||||
            voter_name,
 | 
			
		||||
            &format!("{} voted on proposal '{}'", voter_name, proposal_title),
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Create voting start activity
 | 
			
		||||
    pub fn voting_started(proposal_id: u32, proposal_title: &str) -> Self {
 | 
			
		||||
        Self::new(
 | 
			
		||||
            None,
 | 
			
		||||
            &ActivityType::VotingStarted.to_string(),
 | 
			
		||||
            proposal_id,
 | 
			
		||||
            proposal_title,
 | 
			
		||||
            "System",
 | 
			
		||||
            &format!("Voting started for proposal '{}'", proposal_title),
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Create voting ended activity
 | 
			
		||||
    pub fn voting_ended(proposal_id: u32, proposal_title: &str) -> Self {
 | 
			
		||||
        Self::new(
 | 
			
		||||
            None,
 | 
			
		||||
            &ActivityType::VotingEnded.to_string(),
 | 
			
		||||
            proposal_id,
 | 
			
		||||
            proposal_title,
 | 
			
		||||
            "System",
 | 
			
		||||
            &format!("Voting ended for proposal '{}'", proposal_title),
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,30 +2,32 @@
 | 
			
		||||
pub mod core;
 | 
			
		||||
pub mod userexample;
 | 
			
		||||
// pub mod productexample; // Temporarily remove as files are missing
 | 
			
		||||
pub mod calendar;
 | 
			
		||||
pub mod governance;
 | 
			
		||||
pub mod finance;
 | 
			
		||||
pub mod legal;
 | 
			
		||||
pub mod flow;
 | 
			
		||||
pub mod biz;
 | 
			
		||||
pub mod calendar;
 | 
			
		||||
pub mod finance;
 | 
			
		||||
pub mod flow;
 | 
			
		||||
pub mod governance;
 | 
			
		||||
pub mod legal;
 | 
			
		||||
pub mod projects;
 | 
			
		||||
 | 
			
		||||
// Re-export key types for convenience
 | 
			
		||||
pub use core::Comment;
 | 
			
		||||
pub use userexample::User;
 | 
			
		||||
// pub use productexample::Product; // Temporarily remove
 | 
			
		||||
pub use calendar::{Calendar, Event, Attendee, AttendanceStatus};
 | 
			
		||||
pub use governance::{Proposal, ProposalStatus, VoteEventStatus, Ballot, VoteOption};
 | 
			
		||||
pub use finance::{Account, Asset, AssetType};
 | 
			
		||||
pub use finance::marketplace::{Listing, ListingStatus, ListingType, Bid, BidStatus};
 | 
			
		||||
pub use legal::{Contract, ContractRevision, ContractSigner, ContractStatus, SignerStatus};
 | 
			
		||||
pub use flow::{Flow, FlowStep, SignatureRequirement};
 | 
			
		||||
pub use biz::{Sale, SaleItem, SaleStatus};
 | 
			
		||||
pub use calendar::{AttendanceStatus, Attendee, Calendar, Event};
 | 
			
		||||
pub use finance::marketplace::{Bid, BidStatus, Listing, ListingStatus, ListingType};
 | 
			
		||||
pub use finance::{Account, Asset, AssetType};
 | 
			
		||||
pub use flow::{Flow, FlowStep, SignatureRequirement};
 | 
			
		||||
pub use governance::{
 | 
			
		||||
    Activity, ActivityType, Ballot, Proposal, ProposalStatus, VoteEventStatus, VoteOption,
 | 
			
		||||
};
 | 
			
		||||
pub use legal::{Contract, ContractRevision, ContractSigner, ContractStatus, SignerStatus};
 | 
			
		||||
 | 
			
		||||
pub use flow::register_flow_rhai_module;
 | 
			
		||||
pub use calendar::register_calendar_rhai_module;
 | 
			
		||||
pub use legal::register_legal_rhai_module;
 | 
			
		||||
#[cfg(feature = "rhai")]
 | 
			
		||||
pub use biz::register_biz_rhai_module;
 | 
			
		||||
pub use calendar::register_calendar_rhai_module;
 | 
			
		||||
pub use flow::register_flow_rhai_module;
 | 
			
		||||
pub use legal::register_legal_rhai_module;
 | 
			
		||||
#[cfg(feature = "rhai")]
 | 
			
		||||
pub use projects::register_projects_rhai_module;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user