start porting model specs into heromodels
This commit is contained in:
5
heromodels/src/models/governance/mod.rs
Normal file
5
heromodels/src/models/governance/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
// heromodels/src/models/governance/mod.rs
|
||||
// This module will contain the Proposal model and related types.
|
||||
pub mod proposal;
|
||||
|
||||
pub use self::proposal::{Proposal, Ballot, VoteOption, ProposalStatus, VoteEventStatus};
|
166
heromodels/src/models/governance/proposal.rs
Normal file
166
heromodels/src/models/governance/proposal.rs
Normal file
@@ -0,0 +1,166 @@
|
||||
// heromodels/src/models/governance/proposal.rs
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use heromodels_derive::model; // For #[model]
|
||||
use rhai_autobind_macros::rhai_model_export;
|
||||
use rhai::{CustomType, TypeBuilder};
|
||||
|
||||
use heromodels_core::BaseModelData;
|
||||
|
||||
// --- Enums ---
|
||||
|
||||
/// ProposalStatus defines the lifecycle status of a governance proposal itself
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum ProposalStatus {
|
||||
Draft, // Proposal is being prepared
|
||||
Active, // Proposal is active
|
||||
Approved, // Proposal has been formally approved
|
||||
Rejected, // Proposal has been formally rejected
|
||||
Cancelled,// Proposal was cancelled
|
||||
}
|
||||
|
||||
impl Default for ProposalStatus {
|
||||
fn default() -> Self {
|
||||
ProposalStatus::Draft
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// VoteEventStatus represents the status of the voting process for a proposal
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum VoteEventStatus {
|
||||
Open, // Voting is currently open
|
||||
Closed, // Voting has finished
|
||||
Cancelled, // The voting event was cancelled
|
||||
}
|
||||
|
||||
impl Default for VoteEventStatus {
|
||||
fn default() -> Self {
|
||||
VoteEventStatus::Open
|
||||
}
|
||||
}
|
||||
|
||||
// --- Structs ---
|
||||
|
||||
/// VoteOption represents a specific choice that can be voted on
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, CustomType)]
|
||||
pub struct VoteOption {
|
||||
pub id: u8, // Simple identifier for this option
|
||||
pub text: String, // Descriptive text of the option
|
||||
pub count: i64, // How many votes this option has received
|
||||
pub min_valid: Option<i64>, // Optional: minimum votes needed
|
||||
}
|
||||
|
||||
impl VoteOption {
|
||||
pub fn new(id: u8, text: impl ToString) -> Self {
|
||||
Self {
|
||||
id,
|
||||
text: text.to_string(),
|
||||
count: 0,
|
||||
min_valid: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Ballot represents an individual vote cast by a user
|
||||
#[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 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
|
||||
}
|
||||
|
||||
impl Ballot {
|
||||
pub fn new(id: u32, user_id: u32, vote_option_id: u8, shares_count: i64) -> Self {
|
||||
Self {
|
||||
base_data: BaseModelData::new(id),
|
||||
user_id,
|
||||
vote_option_id,
|
||||
shares_count,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Proposal represents a governance proposal that can be voted upon.
|
||||
#[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 Proposal {
|
||||
pub base_data: BaseModelData,
|
||||
pub creator_id: String, // User ID of the proposal creator
|
||||
pub title: String,
|
||||
pub description: String,
|
||||
pub status: ProposalStatus,
|
||||
|
||||
// Voting event aspects
|
||||
pub vote_start_date: DateTime<Utc>,
|
||||
pub vote_end_date: DateTime<Utc>,
|
||||
pub vote_status: VoteEventStatus,
|
||||
pub options: Vec<VoteOption>,
|
||||
pub ballots: Vec<Ballot>, // This will store actual Ballot structs
|
||||
pub private_group: Option<Vec<u32>>, // Optional list of eligible user IDs
|
||||
}
|
||||
|
||||
impl Proposal {
|
||||
pub fn new(id: u32, creator_id: impl ToString, title: impl ToString, description: impl ToString, vote_start_date: DateTime<Utc>, vote_end_date: DateTime<Utc>) -> Self {
|
||||
Self {
|
||||
base_data: BaseModelData::new(id),
|
||||
creator_id: creator_id.to_string(),
|
||||
title: title.to_string(),
|
||||
description: description.to_string(),
|
||||
status: ProposalStatus::Draft,
|
||||
vote_start_date,
|
||||
vote_end_date,
|
||||
vote_status: VoteEventStatus::Open, // Default to open when created
|
||||
options: Vec::new(),
|
||||
ballots: Vec::new(),
|
||||
private_group: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_option(mut self, option_id: u8, option_text: impl ToString) -> Self {
|
||||
let new_option = VoteOption::new(option_id, option_text);
|
||||
self.options.push(new_option);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn cast_vote(mut self, ballot_id: u32, user_id: u32, chosen_option_id: u8, shares: i64) -> Self {
|
||||
if self.vote_status != VoteEventStatus::Open {
|
||||
eprintln!("Voting is not open for proposal '{}'", self.title);
|
||||
return self;
|
||||
}
|
||||
if !self.options.iter().any(|opt| opt.id == chosen_option_id) {
|
||||
eprintln!("Chosen option ID {} does not exist for proposal '{}'", chosen_option_id, self.title);
|
||||
return self;
|
||||
}
|
||||
if let Some(group) = &self.private_group {
|
||||
if !group.contains(&user_id) {
|
||||
eprintln!("User {} is not eligible to vote on proposal '{}'", user_id, self.title);
|
||||
return self;
|
||||
}
|
||||
}
|
||||
|
||||
let new_ballot = Ballot::new(ballot_id, user_id, chosen_option_id, shares);
|
||||
self.ballots.push(new_ballot);
|
||||
|
||||
if let Some(option) = self.options.iter_mut().find(|opt| opt.id == chosen_option_id) {
|
||||
option.count += shares;
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn change_proposal_status(mut self, new_status: ProposalStatus) -> Self {
|
||||
self.status = new_status;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn change_vote_event_status(mut self, new_status: VoteEventStatus) -> Self {
|
||||
self.vote_status = new_status;
|
||||
self
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user