From e2640b942143e837103bd9365fee924497a6878e Mon Sep 17 00:00:00 2001 From: Timur Gordon <31495328+timurgordon@users.noreply.github.com> Date: Sat, 21 Jun 2025 09:23:22 +0200 Subject: [PATCH 1/2] update to follow rhailib --- heromodels/Cargo.toml | 5 + heromodels/examples/gov_example.rhai | 222 +++++++++++++++++++ heromodels/examples/gov_rhai_example.rs | 57 +++++ heromodels/src/models/access/access.rs | 67 +++++- heromodels/src/models/access/rhai.rs | 14 +- heromodels/src/models/gov/committee.rs | 169 +++++++++++++++ heromodels/src/models/gov/company.rs | 191 ++++++++++++++++ heromodels/src/models/gov/meeting.rs | 227 ++++++++++++++++++++ heromodels/src/models/gov/mod.rs | 16 ++ heromodels/src/models/gov/resolution.rs | 143 ++++++++++++ heromodels/src/models/gov/shareholder.rs | 113 ++++++++++ heromodels/src/models/gov/user.rs | 74 +++++++ heromodels/src/models/gov/vote.rs | 191 ++++++++++++++++ heromodels/src/models/legal/rhai.rs | 24 +-- heromodels/src/models/library/collection.rs | 5 + heromodels/src/models/library/rhai.rs | 6 + 16 files changed, 1500 insertions(+), 24 deletions(-) create mode 100644 heromodels/examples/gov_example.rhai create mode 100644 heromodels/examples/gov_rhai_example.rs create mode 100644 heromodels/src/models/gov/committee.rs create mode 100644 heromodels/src/models/gov/company.rs create mode 100644 heromodels/src/models/gov/meeting.rs create mode 100644 heromodels/src/models/gov/mod.rs create mode 100644 heromodels/src/models/gov/resolution.rs create mode 100644 heromodels/src/models/gov/shareholder.rs create mode 100644 heromodels/src/models/gov/user.rs create mode 100644 heromodels/src/models/gov/vote.rs diff --git a/heromodels/Cargo.toml b/heromodels/Cargo.toml index e7ba96c..87b0ced 100644 --- a/heromodels/Cargo.toml +++ b/heromodels/Cargo.toml @@ -82,3 +82,8 @@ required-features = ["rhai"] name = "library_rhai" path = "examples/library_rhai/example.rs" required-features = ["rhai"] + +[[example]] +name = "rhai_auth_example" +path = "examples/rhai_auth_example.rs" +required-features = ["rhai", "authorization"] diff --git a/heromodels/examples/gov_example.rhai b/heromodels/examples/gov_example.rhai new file mode 100644 index 0000000..5187ea5 --- /dev/null +++ b/heromodels/examples/gov_example.rhai @@ -0,0 +1,222 @@ +// Governance Example - Demonstrates using the governance models with embedded types +// This example shows how to create, retrieve, and manipulate governance entities with embedded types + +// Get the database instance +let db = get_db(); +println("Hero Models - Governance Example"); +println("================================"); + +// Create a company with a business type using the fluent builder pattern +println("Creating a company..."); +// Create a business type directly +let business_type = #{ + type_name: "Corporation", + description: "A corporation is a legal entity that is separate and distinct from its owners" +}; + +let company = company__builder(1) + .name("Acme Corporation") + .registration_number("REG123456") + .incorporation_date(now()) + .fiscal_year_end("December 31") + .email("info@acme.com") + .phone("+1 555-123-4567") + .website("https://acme.com") + .address("123 Main St, Anytown, USA") + .business_type(business_type) + .industry("Technology") + .description("A leading technology company") + .status("Active") + .build(); + +// Save the company to the database +set_company(db, company); +println("Company created successfully!"); +println(""); + +// Create a committee with members using the fluent builder pattern +println("Creating a committee..."); +let committee = committee__builder(1) + .company_id(1) + .name("Board of Directors") + .description("The main governing body of the company") + .add_member( + committee_member() + .id(1) + .user_id(101) + .name("John Smith") + .role(CommitteeRole::Chair) + ) + .add_member( + committee_member() + .id(2) + .user_id(102) + .name("Jane Doe") + .role(CommitteeRole::Secretary) + ) + .add_member( + committee_member() + .id(3) + .user_id(103) + .name("Bob Johnson") + .role(CommitteeRole::Member) + ) + .build(); + +// Save the committee to the database +set_committee(db, committee); +println("Committee created successfully!"); +println(""); + +// Create a meeting with attendees using the fluent builder pattern +println("Creating a meeting..."); +let meeting = meeting__builder(1) + .company_id(1) + .title("Q2 Board Meeting") + .date(now() + days(7)) + .location("Conference Room A") + .description("Quarterly board meeting to review financial performance") + .add_attendee( + attendee() + .id(1) + .user_id(101) + .name("John Smith") + .role(AttendeeRole::Coordinator) + .status(AttendeeStatus::Confirmed) + ) + .add_attendee( + attendee() + .id(2) + .user_id(102) + .name("Jane Doe") + .role(AttendeeRole::Secretary) + .status(AttendeeStatus::Confirmed) + ) + .add_attendee( + attendee() + .id(3) + .user_id(103) + .name("Bob Johnson") + .role(AttendeeRole::Member) + .status(AttendeeStatus::Pending) + ) + .build(); + +// Save the meeting to the database +set_meeting(db, meeting); +println("Meeting created successfully!"); +println(""); + +// Create a resolution with approvals using the fluent builder pattern +println("Creating a resolution..."); +let resolution = resolution__builder(1) + .company_id(1) + .title("New Product Line Resolution") + .description("Resolution to approve the development of a new product line") + .resolution_type(ResolutionType::Ordinary) + .status(ResolutionStatus::Proposed) + .proposed_date(now()) + .effective_date(now() + days(30)) + .expiry_date(now() + days(365)) + .add_approval("John Smith") + .add_approval("Jane Doe") + .build(); + +// Save the resolution to the database +set_resolution(db, resolution); +println("Resolution created successfully!"); +println(""); + +// Create a vote with ballots using the fluent builder pattern +println("Creating a vote..."); +let vote = vote__builder(1) + .company_id(1) + .resolution_id(1) + .title("Vote on New Product Line") + .description("Vote to approve the development of a new product line") + .status(VoteStatus::Open) + .add_ballot( + ballot() + .id(1) + .user_id(101) + .user_name("John Smith") + .option(VoteOption::Yes) + .comments("Strongly support this initiative") + ) + .add_ballot( + ballot() + .id(2) + .user_id(102) + .user_name("Jane Doe") + .option(VoteOption::Yes) + .comments("Agree with the proposal") + ) + .add_ballot( + ballot() + .id(3) + .user_id(103) + .user_name("Bob Johnson") + .option(VoteOption::Abstain) + .comments("Need more information") + ) + .start_date(now()) + .end_date(now() + days(7)) + .build(); + +// Save the vote to the database +set_vote(db, vote); +println("Vote created successfully!"); +println(""); + +// Retrieve and display the company +println("Retrieving company..."); +let retrieved_company = get_company_by_id(db, 1); +println("Company: " + retrieved_company.name); +println("Business Type: " + retrieved_company.business_type.type_name); +println(""); + +// Retrieve and display the committee +println("Retrieving committee..."); +let retrieved_committee = get_committee_by_id(db, 1); +println("Committee: " + retrieved_committee.name); +println("Members: " + retrieved_committee.members.len()); +for member in retrieved_committee.members { + println("- " + member.name + " (" + member.role + ")"); +} +println(""); + +// Retrieve and display the meeting +println("Retrieving meeting..."); +let retrieved_meeting = get_meeting_by_id(db, 1); +println("Meeting: " + retrieved_meeting.title); +println("Date: " + retrieved_meeting.date); +println("Attendees: " + retrieved_meeting.attendees.len()); +for attendee in retrieved_meeting.attendees { + println("- " + attendee.name + " (" + attendee.role + ", " + attendee.status + ")"); +} +println(""); + +// Retrieve and display the resolution +println("Retrieving resolution..."); +let retrieved_resolution = get_resolution_by_id(db, 1); +println("Resolution: " + retrieved_resolution.title); +println("Status: " + retrieved_resolution.status); +println("Approvals: " + retrieved_resolution.approvals.len()); +for approval in retrieved_resolution.approvals { + println("- " + approval); +} +println(""); + +// Retrieve and display the vote +println("Retrieving vote..."); +let retrieved_vote = get_vote_by_id(db, 1); +println("Vote: " + retrieved_vote.title); +println("Status: " + retrieved_vote.status); +println("Ballots: " + retrieved_vote.ballots.len()); +for ballot in retrieved_vote.ballots { + println("- " + ballot.user_name + ": " + ballot.option); +} +println(""); + +println("Governance example completed successfully!"); +() diff --git a/heromodels/examples/gov_rhai_example.rs b/heromodels/examples/gov_rhai_example.rs new file mode 100644 index 0000000..0f09b78 --- /dev/null +++ b/heromodels/examples/gov_rhai_example.rs @@ -0,0 +1,57 @@ +use heromodels::db::hero::OurDB; +use heromodels::register_db_functions; +use rhai::Engine; +use std::sync::Arc; +use std::fs; +use std::path::Path; +use chrono::{DateTime, Utc, Duration}; + +fn main() -> Result<(), Box> { + // Create a temporary directory for the database + let temp_dir = std::env::temp_dir().join("heromodels_gov_example"); + if temp_dir.exists() { + fs::remove_dir_all(&temp_dir)?; + } + fs::create_dir_all(&temp_dir)?; + + println!("Using temporary database at: {}", temp_dir.display()); + + // Create a new OurDB instance + let db = OurDB::new(&temp_dir, true)?; + let db = Arc::new(db); + + // Create a new Rhai engine + let mut engine = Engine::new(); + + // Register the auto-generated DB functions with the engine + register_db_functions(&mut engine); + + // Register print functions + engine.register_fn("println", |s: &str| println!("{}", s)); + engine.register_fn("print", |s: &str| print!("{}", s)); + + // Register date/time functions + engine.register_fn("now", || Utc::now()); + engine.register_fn("days", |n: i64| Duration::days(n)); + engine.register_fn("+", |dt: DateTime, duration: Duration| dt + duration); + + // Add the DB instance to the engine's scope + engine.register_fn("get_db", move || -> Arc { db.clone() }); + + // Load and execute the Rhai script + let script_path = Path::new(env!("CARGO_MANIFEST_DIR")) + .join("examples") + .join("gov_example.rhai"); + + println!("Loading Rhai script from: {}", script_path.display()); + + match engine.eval_file::<()>(script_path) { + Ok(_) => println!("Script executed successfully"), + Err(e) => eprintln!("Error executing script: {}", e), + } + + // Clean up the temporary directory + fs::remove_dir_all(&temp_dir)?; + + Ok(()) +} diff --git a/heromodels/src/models/access/access.rs b/heromodels/src/models/access/access.rs index bdc4907..b5b8050 100644 --- a/heromodels/src/models/access/access.rs +++ b/heromodels/src/models/access/access.rs @@ -1,3 +1,6 @@ +use std::sync::Arc; + +use crate::db::{hero::OurDB, Collection, Db}; use heromodels_core::BaseModelData; use heromodels_derive::model; // Temporarily removed to fix compilation issues @@ -7,14 +10,19 @@ use serde::{Deserialize, Serialize}; /// Represents an event in a contact #[model] -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType, Default)] pub struct Access { /// Base model data pub base_data: BaseModelData, #[index] + pub object_type: String, + #[index] pub object_id: u32, - pub circle_id: u32, + #[index] + pub circle_pk: String, + #[index] pub contact_id: u32, + #[index] pub group_id: u32, pub expires_at: Option, } @@ -24,13 +32,19 @@ impl Access { Access { base_data: BaseModelData::new(), object_id: 0, - circle_id: 0, + object_type: String::new(), + circle_pk: String::new(), contact_id: 0, group_id: 0, expires_at: None, } } + pub fn object_type(mut self, object_type: String) -> Self { + self.object_type = object_type; + self + } + pub fn object_id(mut self, object_id: u32) -> Self { self.object_id = object_id; self @@ -46,8 +60,8 @@ impl Access { self } - pub fn circle_id(mut self, circle_id: u32) -> Self { - self.circle_id = circle_id; + pub fn circle_pk(mut self, circle_pk: String) -> Self { + self.circle_pk = circle_pk; self } @@ -56,3 +70,46 @@ impl Access { self } } + + +/// Checks if a caller has permission to access a specific resource. +/// Access is granted if the caller is a super admin or if an `Access` record exists +/// granting them `can_access = true` for the given resource type and ID. +/// +/// # Arguments +/// * `db`: An `Arc` for database interaction. +/// * `public_key`: The public key of the caller. +/// * `_resource_id_to_check`: The ID of the resource being accessed (now unused). +/// * `_resource_type_to_check`: The type of the resource (e.g., "Collection", "Image") (now unused). +/// +/// # Errors +/// Returns `Err(EvalAltResult::ErrorRuntime)` if there's a database error during the check. +pub fn can_access_resource( + db: Arc, + public_key: &str, + _resource_id_to_check: u32, + _resource_type_to_check: &str, +) -> bool { + // Query for Access records matching the public key. + // Note: This fetches all access records for the user. For performance with many records, + // consider a more specific query if your DB supports it, or caching. + let access_records = match db + .collection::() + .expect("Failed to get Access collection") + .get::(public_key) + { + Ok(records) => records, + Err(_e) => { + // Optionally log the error for debugging purposes. + // For example: log::warn!("Error fetching access records for public key {}: {:?}", public_key, e); + // If database query fails, assume access is not granted. + return false; + } + }; + + if !access_records.is_empty() { + return true; + } + + false // Default to deny if no grant is found +} diff --git a/heromodels/src/models/access/rhai.rs b/heromodels/src/models/access/rhai.rs index 307b417..fff6411 100644 --- a/heromodels/src/models/access/rhai.rs +++ b/heromodels/src/models/access/rhai.rs @@ -43,17 +43,17 @@ mod rhai_access_module { Ok(access.clone()) } - #[rhai_fn(name = "circle_id", return_raw, global, pure)] - pub fn access_circle_id( + #[rhai_fn(name = "circle_pk", return_raw, global, pure)] + pub fn access_circle_pk( access: &mut RhaiAccess, - circle_id: u32, + circle_pk: String, ) -> Result> { // Create a default Access to replace the taken one let default_access = Access::new(); // Take ownership of the access, apply the builder method, then put it back let owned_access = std::mem::replace(access, default_access); - *access = owned_access.circle_id(circle_id); + *access = owned_access.circle_pk(circle_pk); Ok(access.clone()) } @@ -110,9 +110,9 @@ mod rhai_access_module { access.object_id as i64 } - #[rhai_fn(get = "circle_id", pure)] - pub fn get_access_circle_id(access: &mut RhaiAccess) -> i64 { - access.circle_id as i64 + #[rhai_fn(get = "circle_pk", pure)] + pub fn get_access_circle_pk(access: &mut RhaiAccess) -> String { + access.circle_pk.clone() } #[rhai_fn(get = "group_id", pure)] diff --git a/heromodels/src/models/gov/committee.rs b/heromodels/src/models/gov/committee.rs new file mode 100644 index 0000000..6189791 --- /dev/null +++ b/heromodels/src/models/gov/committee.rs @@ -0,0 +1,169 @@ +use heromodels_core::{Model, BaseModelData, IndexKey}; +use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; + +/// CommitteeRole represents the role of a committee member +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum CommitteeRole { + Chair, + ViceChair, + Secretary, + Treasurer, + Member, + Observer, + Advisor, +} + +/// CommitteeMember represents a member of a committee +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CommitteeMember { + pub id: u32, + pub user_id: u32, + pub name: String, + pub role: CommitteeRole, + pub joined_date: DateTime, + pub notes: String, +} + +impl CommitteeMember { + /// Create a new committee member + pub fn new() -> Self { + Self { + id: 0, + user_id: 0, + name: String::new(), + role: CommitteeRole::Member, + joined_date: Utc::now(), + notes: String::new(), + } + } + + /// Set the ID + pub fn id(mut self, id: u32) -> Self { + self.id = id; + self + } + + /// Set the user ID + pub fn user_id(mut self, user_id: u32) -> Self { + self.user_id = user_id; + self + } + + /// Set the name + pub fn name(mut self, name: impl ToString) -> Self { + self.name = name.to_string(); + self + } + + /// Set the role + pub fn role(mut self, role: CommitteeRole) -> Self { + self.role = role; + self + } + + /// Set the joined date + pub fn joined_date(mut self, joined_date: DateTime) -> Self { + self.joined_date = joined_date; + self + } + + /// Set the notes + pub fn notes(mut self, notes: impl ToString) -> Self { + self.notes = notes.to_string(); + self + } + + /// Build the committee member + pub fn build(self) -> Self { + self + } +} + +/// Committee represents a committee in the governance system +#[derive(Debug, Clone, Serialize, Deserialize)] +#[model] +pub struct Committee { + pub base_data: BaseModelData, + pub company_id: u32, + pub name: String, + pub description: String, + pub created_date: DateTime, + pub members: Vec, +} + +impl Committee { + /// Create a new committee + pub fn new(id: u32) -> Self { + Self { + base_data: BaseModelData::new(id), + company_id: 0, + name: String::new(), + description: String::new(), + created_date: Utc::now(), + members: Vec::new(), + } + } + + /// Set the company ID + pub fn company_id(mut self, company_id: u32) -> Self { + self.company_id = company_id; + self + } + + /// Set the name + pub fn name(mut self, name: impl ToString) -> Self { + self.name = name.to_string(); + self + } + + /// Set the description + pub fn description(mut self, description: impl ToString) -> Self { + self.description = description.to_string(); + self + } + + /// Set the created date + pub fn created_date(mut self, created_date: DateTime) -> Self { + self.created_date = created_date; + self + } + + /// Add a member + pub fn add_member(mut self, member: CommitteeMember) -> Self { + self.members.push(member); + self + } + + /// Build the committee + pub fn build(self) -> Self { + self + } +} + +impl Model for Committee { + fn db_prefix() -> &'static str { + "committee" + } + + fn get_id(&self) -> u32 { + self.base_data.id + } + + fn base_data_mut(&mut self) -> &mut BaseModelData { + &mut self.base_data + } + + fn db_keys(&self) -> Vec { + vec![ + IndexKey { + name: "company_id", + value: self.company_id.to_string(), + }, + IndexKey { + name: "name", + value: self.name.clone(), + }, + ] + } +} diff --git a/heromodels/src/models/gov/company.rs b/heromodels/src/models/gov/company.rs new file mode 100644 index 0000000..c1701fe --- /dev/null +++ b/heromodels/src/models/gov/company.rs @@ -0,0 +1,191 @@ +use heromodels_core::{Model, BaseModelData, IndexKey}; +use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; + +/// CompanyStatus represents the status of a company +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum CompanyStatus { + Active, + Inactive, + Dissolved, + Suspended, + Pending, +} + +/// BusinessType represents the type of a business +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BusinessType { + pub type_name: String, + pub description: String, +} + +impl BusinessType { + /// Create a new business type + pub fn new() -> Self { + Self { + type_name: String::new(), + description: String::new(), + } + } + + /// Set the type name + pub fn type_name(mut self, type_name: impl ToString) -> Self { + self.type_name = type_name.to_string(); + self + } + + /// Set the description + pub fn description(mut self, description: impl ToString) -> Self { + self.description = description.to_string(); + self + } + + /// Build the business type + pub fn build(self) -> Self { + self + } +} + +/// Company represents a company in the governance system +#[derive(Debug, Clone, Serialize, Deserialize)] +#[model] +pub struct Company { + pub base_data: BaseModelData, + pub name: String, + pub registration_number: String, + pub incorporation_date: DateTime, + pub fiscal_year_end: String, + pub email: String, + pub phone: String, + pub website: String, + pub address: String, + pub business_type: BusinessType, + pub industry: String, + pub description: String, + pub status: CompanyStatus, +} + +impl Company { + /// Create a new company + pub fn new(id: u32) -> Self { + Self { + base_data: BaseModelData::new(id), + name: String::new(), + registration_number: String::new(), + incorporation_date: Utc::now(), + fiscal_year_end: String::new(), + email: String::new(), + phone: String::new(), + website: String::new(), + address: String::new(), + business_type: BusinessType::new(), + industry: String::new(), + description: String::new(), + status: CompanyStatus::Pending, + } + } + + /// Set the name + pub fn name(mut self, name: impl ToString) -> Self { + self.name = name.to_string(); + self + } + + /// Set the registration number + pub fn registration_number(mut self, registration_number: impl ToString) -> Self { + self.registration_number = registration_number.to_string(); + self + } + + /// Set the incorporation date + pub fn incorporation_date(mut self, incorporation_date: DateTime) -> Self { + self.incorporation_date = incorporation_date; + self + } + + /// Set the fiscal year end + pub fn fiscal_year_end(mut self, fiscal_year_end: impl ToString) -> Self { + self.fiscal_year_end = fiscal_year_end.to_string(); + self + } + + /// Set the email + pub fn email(mut self, email: impl ToString) -> Self { + self.email = email.to_string(); + self + } + + /// Set the phone + pub fn phone(mut self, phone: impl ToString) -> Self { + self.phone = phone.to_string(); + self + } + + /// Set the website + pub fn website(mut self, website: impl ToString) -> Self { + self.website = website.to_string(); + self + } + + /// Set the address + pub fn address(mut self, address: impl ToString) -> Self { + self.address = address.to_string(); + self + } + + /// Set the business type + pub fn business_type(mut self, business_type: BusinessType) -> Self { + self.business_type = business_type; + self + } + + /// Set the industry + pub fn industry(mut self, industry: impl ToString) -> Self { + self.industry = industry.to_string(); + self + } + + /// Set the description + pub fn description(mut self, description: impl ToString) -> Self { + self.description = description.to_string(); + self + } + + /// Set the status + pub fn status(mut self, status: CompanyStatus) -> Self { + self.status = status; + self + } + + /// Build the company + pub fn build(self) -> Self { + self + } +} + +impl Model for Company { + fn db_prefix() -> &'static str { + "company" + } + + fn get_id(&self) -> u32 { + self.base_data.id + } + + fn base_data_mut(&mut self) -> &mut BaseModelData { + &mut self.base_data + } + + fn db_keys(&self) -> Vec { + vec![ + IndexKey { + name: "name", + value: self.name.clone(), + }, + IndexKey { + name: "registration_number", + value: self.registration_number.clone(), + }, + ] + } +} diff --git a/heromodels/src/models/gov/meeting.rs b/heromodels/src/models/gov/meeting.rs new file mode 100644 index 0000000..4caa11b --- /dev/null +++ b/heromodels/src/models/gov/meeting.rs @@ -0,0 +1,227 @@ +use heromodels_core::{Model, BaseModelData, IndexKey}; +use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; + +/// MeetingStatus represents the status of a meeting +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum MeetingStatus { + Scheduled, + InProgress, + Completed, + Cancelled, +} + +/// MeetingType represents the type of a meeting +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum MeetingType { + BoardMeeting, + CommitteeMeeting, + GeneralAssembly, + AnnualGeneralMeeting, + ExtraordinaryGeneralMeeting, + Other, +} + +/// AttendanceStatus represents the status of an attendee +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum AttendanceStatus { + Invited, + Confirmed, + Declined, + Attended, + Absent, +} + +/// Attendee represents an attendee of a meeting +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Attendee { + pub user_id: u32, + pub name: String, + pub role: String, + pub status: AttendanceStatus, + pub notes: String, +} + +impl Attendee { + /// Create a new attendee + pub fn new() -> Self { + Self { + user_id: 0, + name: String::new(), + role: String::new(), + status: AttendanceStatus::Invited, + notes: String::new(), + } + } + + /// Set the user ID + pub fn user_id(mut self, user_id: u32) -> Self { + self.user_id = user_id; + self + } + + /// Set the name + pub fn name(mut self, name: impl ToString) -> Self { + self.name = name.to_string(); + self + } + + /// Set the role + pub fn role(mut self, role: impl ToString) -> Self { + self.role = role.to_string(); + self + } + + /// Set the status + pub fn status(mut self, status: AttendanceStatus) -> Self { + self.status = status; + self + } + + /// Set the notes + pub fn notes(mut self, notes: impl ToString) -> Self { + self.notes = notes.to_string(); + self + } + + /// Build the attendee + pub fn build(self) -> Self { + self + } +} + +/// Meeting represents a meeting in the governance system +#[derive(Debug, Clone, Serialize, Deserialize)] +#[model] +pub struct Meeting { + pub base_data: BaseModelData, + pub company_id: u32, + pub title: String, + pub description: String, + pub meeting_type: MeetingType, + pub status: MeetingStatus, + pub start_time: DateTime, + pub end_time: DateTime, + pub location: String, + pub agenda: String, + pub minutes: String, + pub attendees: Vec, +} + +impl Meeting { + /// Create a new meeting + pub fn new(id: u32) -> Self { + Self { + base_data: BaseModelData::new(id), + company_id: 0, + title: String::new(), + description: String::new(), + meeting_type: MeetingType::Other, + status: MeetingStatus::Scheduled, + start_time: Utc::now(), + end_time: Utc::now(), + location: String::new(), + agenda: String::new(), + minutes: String::new(), + attendees: Vec::new(), + } + } + + /// Set the company ID + pub fn company_id(mut self, company_id: u32) -> Self { + self.company_id = company_id; + self + } + + /// Set the title + pub fn title(mut self, title: impl ToString) -> Self { + self.title = title.to_string(); + self + } + + /// Set the description + pub fn description(mut self, description: impl ToString) -> Self { + self.description = description.to_string(); + self + } + + /// Set the meeting type + pub fn meeting_type(mut self, meeting_type: MeetingType) -> Self { + self.meeting_type = meeting_type; + self + } + + /// Set the status + pub fn status(mut self, status: MeetingStatus) -> Self { + self.status = status; + self + } + + /// Set the start time + pub fn start_time(mut self, start_time: DateTime) -> Self { + self.start_time = start_time; + self + } + + /// Set the end time + pub fn end_time(mut self, end_time: DateTime) -> Self { + self.end_time = end_time; + self + } + + /// Set the location + pub fn location(mut self, location: impl ToString) -> Self { + self.location = location.to_string(); + self + } + + /// Set the agenda + pub fn agenda(mut self, agenda: impl ToString) -> Self { + self.agenda = agenda.to_string(); + self + } + + /// Set the minutes + pub fn minutes(mut self, minutes: impl ToString) -> Self { + self.minutes = minutes.to_string(); + self + } + + /// Add an attendee + pub fn add_attendee(mut self, attendee: Attendee) -> Self { + self.attendees.push(attendee); + self + } + + /// Build the meeting + pub fn build(self) -> Self { + self + } +} + +impl Model for Meeting { + fn db_prefix() -> &'static str { + "meeting" + } + + fn get_id(&self) -> u32 { + self.base_data.id + } + + fn base_data_mut(&mut self) -> &mut BaseModelData { + &mut self.base_data + } + + fn db_keys(&self) -> Vec { + vec![ + IndexKey { + name: "company_id", + value: self.company_id.to_string(), + }, + IndexKey { + name: "title", + value: self.title.clone(), + }, + ] + } +} diff --git a/heromodels/src/models/gov/mod.rs b/heromodels/src/models/gov/mod.rs new file mode 100644 index 0000000..e3feb21 --- /dev/null +++ b/heromodels/src/models/gov/mod.rs @@ -0,0 +1,16 @@ +pub mod company; +pub mod shareholder; +pub mod meeting; +pub mod user; +pub mod vote; +pub mod resolution; +pub mod committee; + +// Re-export all model types for convenience +pub use company::{Company, CompanyStatus, BusinessType}; +pub use shareholder::{Shareholder, ShareholderType}; +pub use meeting::{Meeting, Attendee, MeetingStatus, MeetingType, AttendanceStatus}; +pub use user::User; +pub use vote::{Vote, VoteOption, Ballot, VoteStatus}; +pub use resolution::{Resolution, ResolutionStatus}; +pub use committee::{Committee, CommitteeMember, CommitteeRole}; diff --git a/heromodels/src/models/gov/resolution.rs b/heromodels/src/models/gov/resolution.rs new file mode 100644 index 0000000..10ed792 --- /dev/null +++ b/heromodels/src/models/gov/resolution.rs @@ -0,0 +1,143 @@ +use heromodels_core::{Model, BaseModelData, BaseModelDataBuilder, IndexKey}; +use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; + +/// ResolutionStatus represents the status of a resolution +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum ResolutionStatus { + Draft, + Proposed, + Approved, + Rejected, + Expired, +} + +/// ResolutionType represents the type of a resolution +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum ResolutionType { + Ordinary, + Special, + Unanimous, + Written, + Other, +} + +/// Resolution represents a resolution in the governance system +#[derive(Debug, Clone, Serialize, Deserialize)] +#[model] +pub struct Resolution { + pub base_data: BaseModelData, + pub company_id: u32, + pub title: String, + pub description: String, + pub resolution_type: ResolutionType, + pub status: ResolutionStatus, + pub proposed_date: DateTime, + pub effective_date: Option>, + pub expiry_date: Option>, + pub approvals: Vec, +} + +impl Resolution { + /// Create a new resolution + pub fn new(id: u32) -> Self { + Self { + base_data: BaseModelData::new(id), + company_id: 0, + title: String::new(), + description: String::new(), + resolution_type: ResolutionType::Ordinary, + status: ResolutionStatus::Draft, + proposed_date: Utc::now(), + effective_date: None, + expiry_date: None, + approvals: Vec::new(), + } + } + + /// Set the company ID + pub fn company_id(mut self, company_id: u32) -> Self { + self.company_id = company_id; + self + } + + /// Set the title + pub fn title(mut self, title: impl ToString) -> Self { + self.title = title.to_string(); + self + } + + /// Set the description + pub fn description(mut self, description: impl ToString) -> Self { + self.description = description.to_string(); + self + } + + /// Set the resolution type + pub fn resolution_type(mut self, resolution_type: ResolutionType) -> Self { + self.resolution_type = resolution_type; + self + } + + /// Set the status + pub fn status(mut self, status: ResolutionStatus) -> Self { + self.status = status; + self + } + + /// Set the proposed date + pub fn proposed_date(mut self, proposed_date: DateTime) -> Self { + self.proposed_date = proposed_date; + self + } + + /// Set the effective date + pub fn effective_date(mut self, effective_date: Option>) -> Self { + self.effective_date = effective_date; + self + } + + /// Set the expiry date + pub fn expiry_date(mut self, expiry_date: Option>) -> Self { + self.expiry_date = expiry_date; + self + } + + /// Add an approval + pub fn add_approval(mut self, approval: impl ToString) -> Self { + self.approvals.push(approval.to_string()); + self + } + + /// Build the resolution + pub fn build(self) -> Self { + self + } +} + +impl Model for Resolution { + fn db_prefix() -> &'static str { + "resolution" + } + + fn get_id(&self) -> u32 { + self.base_data.id + } + + fn base_data_mut(&mut self) -> &mut BaseModelData { + &mut self.base_data + } + + fn db_keys(&self) -> Vec { + vec![ + IndexKey { + name: "company_id", + value: self.company_id.to_string(), + }, + IndexKey { + name: "title", + value: self.title.clone(), + }, + ] + } +} diff --git a/heromodels/src/models/gov/shareholder.rs b/heromodels/src/models/gov/shareholder.rs new file mode 100644 index 0000000..e20864a --- /dev/null +++ b/heromodels/src/models/gov/shareholder.rs @@ -0,0 +1,113 @@ +use heromodels_core::{Model, BaseModelData, BaseModelDataBuilder, IndexKey}; +use serde::{Deserialize, Serialize}; + +/// ShareholderType represents the type of a shareholder +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum ShareholderType { + Individual, + Corporate, + Trust, + Partnership, + Government, + Other, +} + +/// Shareholder represents a shareholder in the governance system +#[derive(Debug, Clone, Serialize, Deserialize)] +#[model] +pub struct Shareholder { + pub base_data: BaseModelData, + pub company_id: u32, + pub name: String, + pub shareholder_type: ShareholderType, + pub contact_info: String, + pub shares: u32, + pub percentage: f64, +} + +impl Shareholder { + /// Create a new shareholder + pub fn new(id: u32) -> Self { + Self { + base_data: BaseModelData::new(id), + company_id: 0, + name: String::new(), + shareholder_type: ShareholderType::Individual, + contact_info: String::new(), + shares: 0, + percentage: 0.0, + } + } + + /// Set the company ID + pub fn company_id(mut self, company_id: u32) -> Self { + self.company_id = company_id; + self + } + + /// Set the name + pub fn name(mut self, name: impl ToString) -> Self { + self.name = name.to_string(); + self + } + + /// Set the shareholder type + pub fn shareholder_type(mut self, shareholder_type: ShareholderType) -> Self { + self.shareholder_type = shareholder_type; + self + } + + /// Set the contact info + pub fn contact_info(mut self, contact_info: impl ToString) -> Self { + self.contact_info = contact_info.to_string(); + self + } + + /// Set the shares + pub fn shares(mut self, shares: u32) -> Self { + self.shares = shares; + self + } + + /// Set the percentage + pub fn percentage(mut self, percentage: f64) -> Self { + self.percentage = percentage; + self + } + + /// Build the shareholder + pub fn build(self) -> Self { + self + } +} + +impl Model for Shareholder { + fn db_prefix() -> &'static str { + "shareholder" + } + + fn get_id(&self) -> u32 { + self.base_data.id + } + + fn base_data_mut(&mut self) -> &mut BaseModelData { + &mut self.base_data + } + + fn db_keys(&self) -> Vec { + vec![ + IndexKey { + name: "company_id", + value: self.company_id.to_string(), + }, + IndexKey { + name: "name", + value: self.name.clone(), + }, + IndexKey { + name: "contact_info", + value: self.contact_info.clone(), + }, + ] + } +} diff --git a/heromodels/src/models/gov/user.rs b/heromodels/src/models/gov/user.rs new file mode 100644 index 0000000..8d6be0e --- /dev/null +++ b/heromodels/src/models/gov/user.rs @@ -0,0 +1,74 @@ +use heromodels_core::{Model, BaseModelData, BaseModelDataBuilder, IndexKey}; +use serde::{Deserialize, Serialize}; + +/// User represents a user in the governance system +#[derive(Debug, Clone, Serialize, Deserialize)] +#[model] +pub struct User { + pub base_data: BaseModelData, + pub name: String, + pub email: String, + pub role: String, +} + +impl User { + /// Create a new user + pub fn new(id: u32) -> Self { + Self { + base_data: BaseModelData::new(id), + name: String::new(), + email: String::new(), + role: String::new(), + } + } + + /// Set the name + pub fn name(mut self, name: impl ToString) -> Self { + self.name = name.to_string(); + self + } + + /// Set the email + pub fn email(mut self, email: impl ToString) -> Self { + self.email = email.to_string(); + self + } + + /// Set the role + pub fn role(mut self, role: impl ToString) -> Self { + self.role = role.to_string(); + self + } + + /// Build the user + pub fn build(self) -> Self { + self + } +} + +impl Model for User { + fn db_prefix() -> &'static str { + "gov_user" + } + + fn get_id(&self) -> u32 { + self.base_data.id + } + + fn base_data_mut(&mut self) -> &mut BaseModelData { + &mut self.base_data + } + + fn db_keys(&self) -> Vec { + vec![ + IndexKey { + name: "name", + value: self.name.clone(), + }, + IndexKey { + name: "email", + value: self.email.clone(), + }, + ] + } +} diff --git a/heromodels/src/models/gov/vote.rs b/heromodels/src/models/gov/vote.rs new file mode 100644 index 0000000..3c8e808 --- /dev/null +++ b/heromodels/src/models/gov/vote.rs @@ -0,0 +1,191 @@ +use heromodels_core::{Model, BaseModelData, BaseModelDataBuilder, IndexKey}; +use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; + +/// VoteStatus represents the status of a vote +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum VoteStatus { + Draft, + Open, + Closed, + Cancelled, +} + +/// VoteOption represents an option in a vote +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum VoteOption { + Yes, + No, + Abstain, + Custom(String), +} + +/// Ballot represents a ballot cast in a vote +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Ballot { + pub user_id: u32, + pub option: VoteOption, + pub weight: f64, + pub cast_at: DateTime, + pub notes: String, +} + +impl Ballot { + /// Create a new ballot + pub fn new() -> Self { + Self { + user_id: 0, + option: VoteOption::Abstain, + weight: 1.0, + cast_at: Utc::now(), + notes: String::new(), + } + } + + /// Set the user ID + pub fn user_id(mut self, user_id: u32) -> Self { + self.user_id = user_id; + self + } + + /// Set the option + pub fn option(mut self, option: VoteOption) -> Self { + self.option = option; + self + } + + /// Set the weight + pub fn weight(mut self, weight: f64) -> Self { + self.weight = weight; + self + } + + /// Set the cast time + pub fn cast_at(mut self, cast_at: DateTime) -> Self { + self.cast_at = cast_at; + self + } + + /// Set the notes + pub fn notes(mut self, notes: impl ToString) -> Self { + self.notes = notes.to_string(); + self + } + + /// Build the ballot + pub fn build(self) -> Self { + self + } +} + +/// Vote represents a vote in the governance system +#[derive(Debug, Clone, Serialize, Deserialize)] +#[model] +pub struct Vote { + pub base_data: BaseModelData, + pub company_id: u32, + pub resolution_id: u32, + pub title: String, + pub description: String, + pub status: VoteStatus, + pub start_date: DateTime, + pub end_date: DateTime, + pub ballots: Vec, +} + +impl Vote { + /// Create a new vote + pub fn new(id: u32) -> Self { + Self { + base_data: BaseModelData::new(id), + company_id: 0, + resolution_id: 0, + title: String::new(), + description: String::new(), + status: VoteStatus::Draft, + start_date: Utc::now(), + end_date: Utc::now(), + ballots: Vec::new(), + } + } + + /// Set the company ID + pub fn company_id(mut self, company_id: u32) -> Self { + self.company_id = company_id; + self + } + + /// Set the resolution ID + pub fn resolution_id(mut self, resolution_id: u32) -> Self { + self.resolution_id = resolution_id; + self + } + + /// Set the title + pub fn title(mut self, title: impl ToString) -> Self { + self.title = title.to_string(); + self + } + + /// Set the description + pub fn description(mut self, description: impl ToString) -> Self { + self.description = description.to_string(); + self + } + + /// Set the status + pub fn status(mut self, status: VoteStatus) -> Self { + self.status = status; + self + } + + /// Set the start date + pub fn start_date(mut self, start_date: DateTime) -> Self { + self.start_date = start_date; + self + } + + /// Set the end date + pub fn end_date(mut self, end_date: DateTime) -> Self { + self.end_date = end_date; + self + } + + /// Add a ballot + pub fn add_ballot(mut self, ballot: Ballot) -> Self { + self.ballots.push(ballot); + self + } + + /// Build the vote + pub fn build(self) -> Self { + self + } +} + +impl Model for Vote { + fn db_prefix() -> &'static str { + "vote" + } + + fn get_id(&self) -> u32 { + self.base_data.id + } + + fn base_data_mut(&mut self) -> &mut BaseModelData { + &mut self.base_data + } + + fn db_keys(&self) -> Vec { + vec![ + IndexKey { + name: "company_id", + value: self.company_id.to_string(), + }, + IndexKey { + name: "title", + value: self.title.clone(), + }, + ] + } +} diff --git a/heromodels/src/models/legal/rhai.rs b/heromodels/src/models/legal/rhai.rs index afb83e8..279fa0a 100644 --- a/heromodels/src/models/legal/rhai.rs +++ b/heromodels/src/models/legal/rhai.rs @@ -94,13 +94,13 @@ pub fn register_legal_rhai_module(engine: &mut Engine, db: Arc) { -> Result> { let version = i64_to_u32( version_i64, - context.call_position(), + context.position(), "version", "new_contract_revision", )?; let created_at = i64_to_u64( created_at_i64, - context.call_position(), + context.position(), "created_at", "new_contract_revision", )?; @@ -170,7 +170,7 @@ pub fn register_legal_rhai_module(engine: &mut Engine, db: Arc) { -> Result> { let signed_at_u64 = i64_to_u64( signed_at_i64, - context.call_position(), + context.position(), "signed_at", "ContractSigner.signed_at", )?; @@ -247,7 +247,7 @@ pub fn register_legal_rhai_module(engine: &mut Engine, db: Arc) { -> Result> { let base_id = i64_to_u32( base_id_i64, - context.call_position(), + context.position(), "base_id", "new_contract", )?; @@ -290,7 +290,7 @@ pub fn register_legal_rhai_module(engine: &mut Engine, db: Arc) { -> Result> { let start_date_u64 = i64_to_u64( start_date_i64, - context.call_position(), + context.position(), "start_date", "Contract.start_date", )?; @@ -309,7 +309,7 @@ pub fn register_legal_rhai_module(engine: &mut Engine, db: Arc) { -> Result> { let end_date_u64 = i64_to_u64( end_date_i64, - context.call_position(), + context.position(), "end_date", "Contract.end_date", )?; @@ -328,7 +328,7 @@ pub fn register_legal_rhai_module(engine: &mut Engine, db: Arc) { -> Result> { let days_i32 = i64_to_i32( days_i64, - context.call_position(), + context.position(), "renewal_period_days", "Contract.renewal_period_days", )?; @@ -348,7 +348,7 @@ pub fn register_legal_rhai_module(engine: &mut Engine, db: Arc) { -> Result> { let date_u64 = i64_to_u64( date_i64, - context.call_position(), + context.position(), "next_renewal_date", "Contract.next_renewal_date", )?; @@ -400,7 +400,7 @@ pub fn register_legal_rhai_module(engine: &mut Engine, db: Arc) { -> Result> { let version_u32 = i64_to_u32( version_i64, - context.call_position(), + context.position(), "current_version", "Contract.current_version", )?; @@ -416,7 +416,7 @@ pub fn register_legal_rhai_module(engine: &mut Engine, db: Arc) { -> Result> { let date_u64 = i64_to_u64( date_i64, - context.call_position(), + context.position(), "last_signed_date", "Contract.last_signed_date", )?; @@ -578,7 +578,7 @@ pub fn register_legal_rhai_module(engine: &mut Engine, db: Arc) { captured_db_for_set.set(&contract).map(|_| ()).map_err(|e| { Box::new(EvalAltResult::ErrorRuntime( format!( - "Failed to set Contract (ID: {}): {}", + "Failed to set Contract (ID: {}): {:?}", contract.base_data.id, e ) .into(), @@ -592,7 +592,7 @@ pub fn register_legal_rhai_module(engine: &mut Engine, db: Arc) { engine.register_fn( "get_contract_by_id", move |context: NativeCallContext, id_i64: i64| -> Result> { - let id_u32 = i64_to_u32(id_i64, context.call_position(), "id", "get_contract_by_id")?; + let id_u32 = i64_to_u32(id_i64, context.position(), "id", "get_contract_by_id")?; captured_db_for_get .get_by_id(id_u32) diff --git a/heromodels/src/models/library/collection.rs b/heromodels/src/models/library/collection.rs index c0acead..48d7a45 100644 --- a/heromodels/src/models/library/collection.rs +++ b/heromodels/src/models/library/collection.rs @@ -47,6 +47,11 @@ impl Collection { Self::default() } + /// Returns the ID of the collection. + pub fn id(&self) -> u32 { + self.base_data.id + } + /// Sets the title of the collection. pub fn title(mut self, title: impl Into) -> Self { self.title = title.into(); diff --git a/heromodels/src/models/library/rhai.rs b/heromodels/src/models/library/rhai.rs index 734f04b..57a606a 100644 --- a/heromodels/src/models/library/rhai.rs +++ b/heromodels/src/models/library/rhai.rs @@ -47,6 +47,12 @@ where #[rhai_type(name = "CollectionArray")] pub struct RhaiCollectionArray(pub Vec); +impl From> for RhaiCollectionArray { + fn from(collections: Vec) -> Self { + RhaiCollectionArray(collections) + } +} + #[export_module] mod rhai_library_module { // --- Collection Functions --- From cd2557c1c33e5b7eb5f84a8c56293ea083c1a0d9 Mon Sep 17 00:00:00 2001 From: Timur Gordon <31495328+timurgordon@users.noreply.github.com> Date: Tue, 24 Jun 2025 19:23:27 +0200 Subject: [PATCH 2/2] move dsl's to rhailib wip --- .../src/models/library => _archive}/rhai.rs | 2 +- heromodels/Cargo.toml | 2 +- heromodels/src/models/access/access.rs | 19 +++-- heromodels/src/models/library/items.rs | 78 +++++++------------ heromodels/src/models/library/mod.rs | 2 - heromodels/src/models/log/README.md | 3 + heromodels/src/models/log/log.rs | 60 ++++++++++++++ heromodels/src/models/log/mod.rs | 5 ++ heromodels/src/models/mod.rs | 3 +- heromodels/src/models/object/README.md | 3 + heromodels/src/models/object/mod.rs | 5 ++ heromodels/src/models/object/object.rs | 44 +++++++++++ 12 files changed, 161 insertions(+), 65 deletions(-) rename {heromodels/src/models/library => _archive}/rhai.rs (99%) create mode 100644 heromodels/src/models/log/README.md create mode 100644 heromodels/src/models/log/log.rs create mode 100644 heromodels/src/models/log/mod.rs create mode 100644 heromodels/src/models/object/README.md create mode 100644 heromodels/src/models/object/mod.rs create mode 100644 heromodels/src/models/object/object.rs diff --git a/heromodels/src/models/library/rhai.rs b/_archive/rhai.rs similarity index 99% rename from heromodels/src/models/library/rhai.rs rename to _archive/rhai.rs index 57a606a..e33d8a4 100644 --- a/heromodels/src/models/library/rhai.rs +++ b/_archive/rhai.rs @@ -655,7 +655,7 @@ mod rhai_library_module { } } -pub fn register_library_rhai_module(engine: &mut Engine, db: Arc) { +pub fn register_library_rhai_module(engine: &mut Engine) { let module = exported_module!(rhai_library_module); engine.register_global_module(module.into()); diff --git a/heromodels/Cargo.toml b/heromodels/Cargo.toml index 87b0ced..4cd485a 100644 --- a/heromodels/Cargo.toml +++ b/heromodels/Cargo.toml @@ -86,4 +86,4 @@ required-features = ["rhai"] [[example]] name = "rhai_auth_example" path = "examples/rhai_auth_example.rs" -required-features = ["rhai", "authorization"] +required-features = ["rhai", "macros"] diff --git a/heromodels/src/models/access/access.rs b/heromodels/src/models/access/access.rs index b5b8050..5aede48 100644 --- a/heromodels/src/models/access/access.rs +++ b/heromodels/src/models/access/access.rs @@ -87,16 +87,16 @@ impl Access { pub fn can_access_resource( db: Arc, public_key: &str, - _resource_id_to_check: u32, - _resource_type_to_check: &str, + object_id: u32, + _object_type: &str, ) -> bool { - // Query for Access records matching the public key. - // Note: This fetches all access records for the user. For performance with many records, - // consider a more specific query if your DB supports it, or caching. + println!("Checking access for public key: {}", public_key); + + // get all access records for object let access_records = match db .collection::() .expect("Failed to get Access collection") - .get::(public_key) + .get::(&object_id) { Ok(records) => records, Err(_e) => { @@ -107,9 +107,8 @@ pub fn can_access_resource( } }; - if !access_records.is_empty() { - return true; - } + println!("Access records: {:#?}", access_records); - false // Default to deny if no grant is found + // if circle_pk is in access records true + return access_records.iter().any(|record| record.circle_pk == public_key) } diff --git a/heromodels/src/models/library/items.rs b/heromodels/src/models/library/items.rs index aacd182..02056b1 100644 --- a/heromodels/src/models/library/items.rs +++ b/heromodels/src/models/library/items.rs @@ -41,6 +41,11 @@ impl Image { Self::default() } + /// Gets the ID of the image. + pub fn id(&self) -> u32 { + self.base_data.id + } + /// Sets the title of the image. pub fn title(mut self, title: impl Into) -> Self { self.title = title.into(); @@ -107,6 +112,11 @@ impl Pdf { Self::default() } + /// Gets the ID of the image. + pub fn id(&self) -> u32 { + self.base_data.id + } + /// Sets the title of the PDF. pub fn title(mut self, title: impl Into) -> Self { self.title = title.into(); @@ -134,7 +144,7 @@ impl Pdf { /// Represents a Markdown document library item. #[model] -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType, Default)] pub struct Markdown { /// Base model data pub base_data: BaseModelData, @@ -147,23 +157,17 @@ pub struct Markdown { pub content: String, } -impl Default for Markdown { - fn default() -> Self { - Self { - base_data: BaseModelData::new(), - title: String::new(), - description: None, - content: String::new(), - } - } -} - impl Markdown { /// Creates a new `Markdown` document with default values. pub fn new() -> Self { Self::default() } + /// Gets the ID of the image. + pub fn id(&self) -> u32 { + self.base_data.id + } + /// Sets the title of the document. pub fn title(mut self, title: impl Into) -> Self { self.title = title.into(); @@ -184,7 +188,7 @@ impl Markdown { } /// Represents a table of contents entry for a book. -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType, Default)] pub struct TocEntry { /// Title of the chapter/section pub title: String, @@ -194,16 +198,6 @@ pub struct TocEntry { pub subsections: Vec, } -impl Default for TocEntry { - fn default() -> Self { - Self { - title: String::new(), - page: 0, - subsections: Vec::new(), - } - } -} - impl TocEntry { /// Creates a new `TocEntry` with default values. pub fn new() -> Self { @@ -231,7 +225,7 @@ impl TocEntry { /// Represents a Book library item (collection of markdown pages with TOC). #[model] -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType, Default)] pub struct Book { /// Base model data pub base_data: BaseModelData, @@ -246,24 +240,17 @@ pub struct Book { pub pages: Vec, } -impl Default for Book { - fn default() -> Self { - Self { - base_data: BaseModelData::new(), - title: String::new(), - description: None, - table_of_contents: Vec::new(), - pages: Vec::new(), - } - } -} - impl Book { /// Creates a new `Book` with default values. pub fn new() -> Self { Self::default() } + /// Gets the ID of the book. + pub fn id(&self) -> u32 { + self.base_data.id + } + /// Sets the title of the book. pub fn title(mut self, title: impl Into) -> Self { self.title = title.into(); @@ -303,7 +290,7 @@ impl Book { /// Represents a Slides library item (collection of images for slideshow). #[model] -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType, Default)] pub struct Slides { /// Base model data pub base_data: BaseModelData, @@ -318,24 +305,17 @@ pub struct Slides { pub slide_titles: Vec>, } -impl Default for Slides { - fn default() -> Self { - Self { - base_data: BaseModelData::new(), - title: String::new(), - description: None, - slide_urls: Vec::new(), - slide_titles: Vec::new(), - } - } -} - impl Slides { /// Creates a new `Slides` with default values. pub fn new() -> Self { Self::default() } + /// Gets the ID of the slideshow. + pub fn id(&self) -> u32 { + self.base_data.id + } + /// Sets the title of the slideshow. pub fn title(mut self, title: impl Into) -> Self { self.title = title.into(); diff --git a/heromodels/src/models/library/mod.rs b/heromodels/src/models/library/mod.rs index a9bcd44..f13c08e 100644 --- a/heromodels/src/models/library/mod.rs +++ b/heromodels/src/models/library/mod.rs @@ -1,4 +1,2 @@ pub mod collection; pub mod items; -pub mod rhai; -pub use rhai::register_library_rhai_module; diff --git a/heromodels/src/models/log/README.md b/heromodels/src/models/log/README.md new file mode 100644 index 0000000..472a8e7 --- /dev/null +++ b/heromodels/src/models/log/README.md @@ -0,0 +1,3 @@ +## Object Model + +This is a generic object model mostly used for testing purposes. \ No newline at end of file diff --git a/heromodels/src/models/log/log.rs b/heromodels/src/models/log/log.rs new file mode 100644 index 0000000..1dc2c3b --- /dev/null +++ b/heromodels/src/models/log/log.rs @@ -0,0 +1,60 @@ +use std::sync::Arc; + +use crate::db::{hero::OurDB, Collection, Db}; +use heromodels_core::BaseModelData; +use heromodels_derive::model; +// Temporarily removed to fix compilation issues +// use rhai_autobind_macros::rhai_model_export; +use rhai::{CustomType, TypeBuilder}; +use serde::{Deserialize, Serialize}; + +/// Represents an event in a contact +#[model] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType, Default)] +pub struct Log { + /// Base model data + pub base_data: BaseModelData, + #[index] + pub title: String, + pub description: String, + #[index] + pub subject_pk: String, + #[index] + pub object_id: u32, +} + +impl Log { + pub fn new() -> Self { + Log { + title: String::new(), + base_data: BaseModelData::new(), + description: String::new(), + subject_pk: String::new(), + object_id: 0, + } + } + + pub fn id(&self) -> u32 { + self.base_data.id + } + + pub fn title(mut self, title: String) -> Self { + self.title = title; + self + } + + pub fn description(mut self, description: String) -> Self { + self.description = description; + self + } + + pub fn subject_pk(mut self, subject_pk: String) -> Self { + self.subject_pk = subject_pk; + self + } + + pub fn object_id(mut self, object_id: u32) -> Self { + self.object_id = object_id; + self + } +} \ No newline at end of file diff --git a/heromodels/src/models/log/mod.rs b/heromodels/src/models/log/mod.rs new file mode 100644 index 0000000..77f230e --- /dev/null +++ b/heromodels/src/models/log/mod.rs @@ -0,0 +1,5 @@ +// Export contact module +pub mod log; + +// Re-export contact, Group from the inner contact module (contact.rs) within src/models/contact/mod.rs +pub use self::log::Log; diff --git a/heromodels/src/models/mod.rs b/heromodels/src/models/mod.rs index 7763482..4689378 100644 --- a/heromodels/src/models/mod.rs +++ b/heromodels/src/models/mod.rs @@ -12,6 +12,7 @@ pub mod flow; pub mod governance; pub mod legal; pub mod library; +pub mod object; pub mod projects; // Re-export key types for convenience @@ -38,6 +39,4 @@ pub use circle::register_circle_rhai_module; pub use flow::register_flow_rhai_module; pub use legal::register_legal_rhai_module; #[cfg(feature = "rhai")] -pub use library::register_library_rhai_module; -#[cfg(feature = "rhai")] pub use projects::register_projects_rhai_module; diff --git a/heromodels/src/models/object/README.md b/heromodels/src/models/object/README.md new file mode 100644 index 0000000..472a8e7 --- /dev/null +++ b/heromodels/src/models/object/README.md @@ -0,0 +1,3 @@ +## Object Model + +This is a generic object model mostly used for testing purposes. \ No newline at end of file diff --git a/heromodels/src/models/object/mod.rs b/heromodels/src/models/object/mod.rs new file mode 100644 index 0000000..16a1ca7 --- /dev/null +++ b/heromodels/src/models/object/mod.rs @@ -0,0 +1,5 @@ +// Export contact module +pub mod object; + +// Re-export contact, Group from the inner contact module (contact.rs) within src/models/contact/mod.rs +pub use self::object::Object; diff --git a/heromodels/src/models/object/object.rs b/heromodels/src/models/object/object.rs new file mode 100644 index 0000000..8c5bcd5 --- /dev/null +++ b/heromodels/src/models/object/object.rs @@ -0,0 +1,44 @@ +use std::sync::Arc; + +use crate::db::{hero::OurDB, Collection, Db}; +use heromodels_core::BaseModelData; +use heromodels_derive::model; +// Temporarily removed to fix compilation issues +// use rhai_autobind_macros::rhai_model_export; +use rhai::{CustomType, TypeBuilder}; +use serde::{Deserialize, Serialize}; + +/// Represents an event in a contact +#[model] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType, Default)] +pub struct Object { + /// Base model data + pub base_data: BaseModelData, + #[index] + pub title: String, + pub description: String +} + +impl Object { + pub fn new() -> Self { + Object { + title: String::new(), + base_data: BaseModelData::new(), + description: String::new(), + } + } + + pub fn id(&self) -> u32 { + self.base_data.id + } + + pub fn title(mut self, title: String) -> Self { + self.title = title; + self + } + + pub fn description(mut self, description: String) -> Self { + self.description = description; + self + } +} \ No newline at end of file