291 lines
9.3 KiB
Rust
291 lines
9.3 KiB
Rust
use chrono::{Duration, Utc};
|
|
use heromodels::db::hero::OurDB;
|
|
use heromodels::models::governance::{
|
|
Ballot, Proposal, ProposalStatus, VoteEventStatus, VoteOption,
|
|
};
|
|
use rhai::Engine;
|
|
use rhai_wrapper::wrap_vec_return;
|
|
use std::sync::Arc;
|
|
use std::{fs, path::Path};
|
|
|
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
// Initialize Rhai engine
|
|
let mut engine = Engine::new();
|
|
|
|
// Initialize database
|
|
let db = Arc::new(OurDB::new("temp_governance_db", true).expect("Failed to create database"));
|
|
|
|
// Register the Proposal type with Rhai
|
|
// This function is generated by the #[rhai_model_export] attribute
|
|
Proposal::register_rhai_bindings_for_proposal(&mut engine, db.clone());
|
|
|
|
// Register the Ballot type with Rhai
|
|
Ballot::register_rhai_bindings_for_ballot(&mut engine, db.clone());
|
|
|
|
// Register a function to get the database instance
|
|
engine.register_fn("get_db", move || db.clone());
|
|
|
|
// Register builder functions for Proposal and related types
|
|
engine.register_fn(
|
|
"create_proposal",
|
|
|id: i64, creator_id: String, creator_name: String, title: String, description: String| {
|
|
let start_date = Utc::now();
|
|
let end_date = start_date + Duration::days(14);
|
|
let id_option = if id <= 0 { None } else { Some(id as u32) };
|
|
Proposal::new(
|
|
id_option,
|
|
creator_id,
|
|
creator_name,
|
|
title,
|
|
description,
|
|
ProposalStatus::Draft,
|
|
Utc::now(),
|
|
Utc::now(),
|
|
start_date,
|
|
end_date,
|
|
)
|
|
},
|
|
);
|
|
|
|
engine.register_fn("create_vote_option", |id: i64, text: String| {
|
|
VoteOption::new(id as u8, text, Some("This is an optional comment"))
|
|
});
|
|
|
|
engine.register_fn(
|
|
"create_ballot",
|
|
|id: i64, user_id: i64, vote_option_id: i64, shares_count: i64| {
|
|
let id_option = if id <= 0 { None } else { Some(id as u32) };
|
|
Ballot::new(
|
|
id_option,
|
|
user_id as u32,
|
|
vote_option_id as u8,
|
|
shares_count,
|
|
)
|
|
},
|
|
);
|
|
|
|
// Register getter and setter methods for Proposal properties
|
|
engine.register_fn("get_title", |proposal: Proposal| -> String {
|
|
proposal.title.clone()
|
|
});
|
|
|
|
engine.register_fn("get_description", |proposal: Proposal| -> String {
|
|
proposal.description.clone()
|
|
});
|
|
|
|
engine.register_fn("get_creator_id", |proposal: Proposal| -> String {
|
|
proposal.creator_id.clone()
|
|
});
|
|
|
|
engine.register_fn("get_id", |proposal: Proposal| -> i64 {
|
|
proposal.base_data.id as i64
|
|
});
|
|
|
|
engine.register_fn("get_status", |proposal: Proposal| -> String {
|
|
format!("{:?}", proposal.status)
|
|
});
|
|
|
|
engine.register_fn("get_vote_status", |proposal: Proposal| -> String {
|
|
format!("{:?}", proposal.vote_status)
|
|
});
|
|
|
|
// Register methods for proposal operations
|
|
engine.register_fn(
|
|
"add_option_to_proposal",
|
|
|mut proposal: Proposal, option_id: i64, option_text: String| -> Proposal {
|
|
proposal.add_option(
|
|
option_id as u8,
|
|
option_text,
|
|
Some("This is an optional comment".to_string()),
|
|
)
|
|
},
|
|
);
|
|
|
|
engine.register_fn(
|
|
"cast_vote_on_proposal",
|
|
|mut proposal: Proposal,
|
|
ballot_id: i64,
|
|
user_id: i64,
|
|
option_id: i64,
|
|
shares: i64|
|
|
-> Proposal {
|
|
let ballot_id_option = if ballot_id <= 0 {
|
|
None
|
|
} else {
|
|
Some(ballot_id as u32)
|
|
};
|
|
proposal.cast_vote(ballot_id_option, user_id as u32, option_id as u8, shares)
|
|
},
|
|
);
|
|
|
|
engine.register_fn(
|
|
"change_proposal_status",
|
|
|mut proposal: Proposal, status_str: String| -> Proposal {
|
|
let new_status = match status_str.as_str() {
|
|
"Draft" => ProposalStatus::Draft,
|
|
"Active" => ProposalStatus::Active,
|
|
"Approved" => ProposalStatus::Approved,
|
|
"Rejected" => ProposalStatus::Rejected,
|
|
"Cancelled" => ProposalStatus::Cancelled,
|
|
_ => ProposalStatus::Draft,
|
|
};
|
|
proposal.change_proposal_status(new_status)
|
|
},
|
|
);
|
|
|
|
engine.register_fn(
|
|
"change_vote_event_status",
|
|
|mut proposal: Proposal, status_str: String| -> Proposal {
|
|
let new_status = match status_str.as_str() {
|
|
"Open" => VoteEventStatus::Open,
|
|
"Closed" => VoteEventStatus::Closed,
|
|
"Cancelled" => VoteEventStatus::Cancelled,
|
|
_ => VoteEventStatus::Open,
|
|
};
|
|
proposal.change_vote_event_status(new_status)
|
|
},
|
|
);
|
|
|
|
// Register functions for database operations
|
|
engine.register_fn("save_proposal", |_db: Arc<OurDB>, proposal: Proposal| {
|
|
println!("Proposal saved: {}", proposal.title);
|
|
});
|
|
|
|
engine.register_fn(
|
|
"get_proposal_by_id",
|
|
|_db: Arc<OurDB>, id: i64| -> Proposal {
|
|
// In a real implementation, this would retrieve the proposal from the database
|
|
let start_date = Utc::now();
|
|
let end_date = start_date + Duration::days(14);
|
|
Proposal::new(
|
|
Some(id as u32),
|
|
"Retrieved Creator",
|
|
"Retrieved Creator Name",
|
|
"Retrieved Proposal",
|
|
"Retrieved Description",
|
|
ProposalStatus::Draft,
|
|
Utc::now(),
|
|
Utc::now(),
|
|
start_date,
|
|
end_date,
|
|
)
|
|
},
|
|
);
|
|
|
|
// Register a function to check if a proposal exists
|
|
engine.register_fn("proposal_exists", |_db: Arc<OurDB>, id: i64| -> bool {
|
|
// In a real implementation, this would check if the proposal exists in the database
|
|
id == 1 || id == 2
|
|
});
|
|
|
|
// Define the function for get_all_proposals
|
|
fn get_all_proposals(_db: Arc<OurDB>) -> Vec<Proposal> {
|
|
// In a real implementation, this would retrieve all proposals from the database
|
|
let start_date = Utc::now();
|
|
let end_date = start_date + Duration::days(14);
|
|
vec![
|
|
Proposal::new(
|
|
Some(1),
|
|
"Creator 1",
|
|
"Creator Name 1",
|
|
"Proposal 1",
|
|
"Description 1",
|
|
ProposalStatus::Draft,
|
|
Utc::now(),
|
|
Utc::now(),
|
|
start_date,
|
|
end_date,
|
|
),
|
|
Proposal::new(
|
|
Some(2),
|
|
"Creator 2",
|
|
"Creator Name 2",
|
|
"Proposal 2",
|
|
"Description 2",
|
|
ProposalStatus::Draft,
|
|
Utc::now(),
|
|
Utc::now(),
|
|
start_date,
|
|
end_date,
|
|
),
|
|
]
|
|
}
|
|
|
|
// Register the function with the wrap_vec_return macro
|
|
engine.register_fn(
|
|
"get_all_proposals",
|
|
wrap_vec_return!(get_all_proposals, Arc<OurDB> => Proposal),
|
|
);
|
|
|
|
engine.register_fn("delete_proposal_by_id", |_db: Arc<OurDB>, _id: i64| {
|
|
// In a real implementation, this would delete the proposal from the database
|
|
println!("Proposal deleted with ID: {}", _id);
|
|
});
|
|
|
|
// Register helper functions for accessing proposal options and ballots
|
|
engine.register_fn("get_option_count", |proposal: Proposal| -> i64 {
|
|
proposal.options.len() as i64
|
|
});
|
|
|
|
engine.register_fn(
|
|
"get_option_at",
|
|
|proposal: Proposal, index: i64| -> VoteOption {
|
|
if index >= 0 && index < proposal.options.len() as i64 {
|
|
proposal.options[index as usize].clone()
|
|
} else {
|
|
VoteOption::new(
|
|
0,
|
|
"Invalid Option",
|
|
Some("This is an invalid option".to_string()),
|
|
)
|
|
}
|
|
},
|
|
);
|
|
|
|
engine.register_fn("get_option_text", |option: VoteOption| -> String {
|
|
option.text.clone()
|
|
});
|
|
|
|
engine.register_fn("get_option_votes", |option: VoteOption| -> i64 {
|
|
option.count
|
|
});
|
|
|
|
engine.register_fn("get_ballot_count", |proposal: Proposal| -> i64 {
|
|
proposal.ballots.len() as i64
|
|
});
|
|
|
|
engine.register_fn(
|
|
"get_ballot_at",
|
|
|proposal: Proposal, index: i64| -> Ballot {
|
|
if index >= 0 && index < proposal.ballots.len() as i64 {
|
|
proposal.ballots[index as usize].clone()
|
|
} else {
|
|
Ballot::new(None, 0, 0, 0)
|
|
}
|
|
},
|
|
);
|
|
|
|
engine.register_fn("get_ballot_user_id", |ballot: Ballot| -> i64 {
|
|
ballot.user_id as i64
|
|
});
|
|
|
|
engine.register_fn("get_ballot_option_id", |ballot: Ballot| -> i64 {
|
|
ballot.vote_option_id as i64
|
|
});
|
|
|
|
engine.register_fn("get_ballot_shares", |ballot: Ballot| -> i64 {
|
|
ballot.shares_count
|
|
});
|
|
|
|
// Load and evaluate the Rhai script
|
|
let script_path = Path::new("examples/governance_rhai/governance.rhai");
|
|
let script = fs::read_to_string(script_path)?;
|
|
|
|
match engine.eval::<()>(&script) {
|
|
Ok(_) => println!("Script executed successfully!"),
|
|
Err(e) => eprintln!("Script execution failed: {}", e),
|
|
}
|
|
|
|
Ok(())
|
|
}
|