...
This commit is contained in:
		@@ -1,12 +1,14 @@
 | 
			
		||||
use chrono::{Utc, Duration};
 | 
			
		||||
use herodb::db::{DBBuilder, SledDB, SledModel};
 | 
			
		||||
use herodb::db::{DBBuilder, DB};
 | 
			
		||||
use herodb::models::gov::{
 | 
			
		||||
    Company, CompanyStatus, BusinessType,
 | 
			
		||||
    Shareholder, ShareholderType,
 | 
			
		||||
    Meeting, Attendee, MeetingStatus, AttendeeRole, AttendeeStatus,
 | 
			
		||||
    User,
 | 
			
		||||
    Vote, VoteOption, Ballot, VoteStatus,
 | 
			
		||||
    Resolution, ResolutionStatus, Approval
 | 
			
		||||
    Resolution, ResolutionStatus, Approval,
 | 
			
		||||
    Committee, CommitteeRole, CommitteeMember,
 | 
			
		||||
    ComplianceRequirement, ComplianceDocument, ComplianceAudit
 | 
			
		||||
};
 | 
			
		||||
use std::path::PathBuf;
 | 
			
		||||
use std::fs;
 | 
			
		||||
@@ -31,6 +33,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
 | 
			
		||||
        .register_model::<User>()
 | 
			
		||||
        .register_model::<Vote>()
 | 
			
		||||
        .register_model::<Resolution>()
 | 
			
		||||
        .register_model::<Committee>()
 | 
			
		||||
        .register_model::<ComplianceRequirement>()
 | 
			
		||||
        .register_model::<ComplianceDocument>()
 | 
			
		||||
        .register_model::<ComplianceAudit>()
 | 
			
		||||
        .build()?;
 | 
			
		||||
 | 
			
		||||
    println!("\n1. Creating a Company");
 | 
			
		||||
@@ -325,7 +331,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
 | 
			
		||||
    println!("---------------------------");
 | 
			
		||||
 | 
			
		||||
    // Retrieve company and related objects
 | 
			
		||||
    let retrieved_company = db.get::<Company>(&company.id.to_string())?;
 | 
			
		||||
    let retrieved_company = db.get::<Company>(company.id)?;
 | 
			
		||||
    println!("Company: {} (ID: {})", retrieved_company.name, retrieved_company.id);
 | 
			
		||||
 | 
			
		||||
    // Get resolutions for this company
 | 
			
		||||
@@ -336,7 +342,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Get meeting and its resolutions
 | 
			
		||||
    let retrieved_meeting = db.get::<Meeting>(&meeting.id.to_string())?;
 | 
			
		||||
    let retrieved_meeting = db.get::<Meeting>(meeting.id)?;
 | 
			
		||||
    println!("Meeting: {} ({})", retrieved_meeting.title, retrieved_meeting.date.format("%Y-%m-%d"));
 | 
			
		||||
    
 | 
			
		||||
    let meeting_resolutions = retrieved_meeting.get_resolutions(&db)?;
 | 
			
		||||
@@ -346,7 +352,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Get vote and its resolution
 | 
			
		||||
    let retrieved_vote = db.get::<Vote>(&vote.id.to_string())?;
 | 
			
		||||
    let retrieved_vote = db.get::<Vote>(vote.id)?;
 | 
			
		||||
    println!("Vote: {} (Status: {:?})", retrieved_vote.title, retrieved_vote.status);
 | 
			
		||||
    
 | 
			
		||||
    if let Ok(Some(vote_res)) = retrieved_vote.get_resolution(&db) {
 | 
			
		||||
@@ -354,7 +360,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Get resolution and its related objects
 | 
			
		||||
    let retrieved_resolution = db.get::<Resolution>(&resolution.id.to_string())?;
 | 
			
		||||
    let retrieved_resolution = db.get::<Resolution>(resolution.id)?;
 | 
			
		||||
    println!("Resolution: {} (Status: {:?})", retrieved_resolution.title, retrieved_resolution.status);
 | 
			
		||||
    
 | 
			
		||||
    if let Ok(Some(res_meeting)) = retrieved_resolution.get_meeting(&db) {
 | 
			
		||||
 
 | 
			
		||||
@@ -26,5 +26,5 @@ pub trait Model: Storable + Debug + Clone + Send + Sync + 'static {
 | 
			
		||||
    fn db_prefix() -> &'static str;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Implement Storable for common types that might be used in models
 | 
			
		||||
impl<T: Serialize + for<'de> Deserialize<'de> + Sized> Storable for T {}
 | 
			
		||||
// Note: We don't provide a blanket implementation of Storable
 | 
			
		||||
// Each model type must implement Storable explicitly
 | 
			
		||||
@@ -2,6 +2,10 @@ use crate::db::db::DB;
 | 
			
		||||
use crate::db::model::Model;
 | 
			
		||||
use crate::impl_model_methods;
 | 
			
		||||
use crate::models::biz::{Product, Sale, Currency, ExchangeRate, Service, Customer, Contract, Invoice};
 | 
			
		||||
use crate::models::gov::{
 | 
			
		||||
    Company, Shareholder, Meeting, User, Vote, Resolution,
 | 
			
		||||
    Committee, ComplianceRequirement, ComplianceDocument, ComplianceAudit
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Implement model-specific methods for Product
 | 
			
		||||
impl_model_methods!(Product, product, products);
 | 
			
		||||
@@ -25,4 +29,34 @@ impl_model_methods!(Customer, customer, customers);
 | 
			
		||||
impl_model_methods!(Contract, contract, contracts);
 | 
			
		||||
 | 
			
		||||
// Implement model-specific methods for Invoice
 | 
			
		||||
impl_model_methods!(Invoice, invoice, invoices);
 | 
			
		||||
impl_model_methods!(Invoice, invoice, invoices);
 | 
			
		||||
 | 
			
		||||
// Implement model-specific methods for Company
 | 
			
		||||
impl_model_methods!(Company, company, companies);
 | 
			
		||||
 | 
			
		||||
// Implement model-specific methods for Shareholder
 | 
			
		||||
impl_model_methods!(Shareholder, shareholder, shareholders);
 | 
			
		||||
 | 
			
		||||
// Implement model-specific methods for Meeting
 | 
			
		||||
impl_model_methods!(Meeting, meeting, meetings);
 | 
			
		||||
 | 
			
		||||
// Implement model-specific methods for User
 | 
			
		||||
impl_model_methods!(User, user, users);
 | 
			
		||||
 | 
			
		||||
// Implement model-specific methods for Vote
 | 
			
		||||
impl_model_methods!(Vote, vote, votes);
 | 
			
		||||
 | 
			
		||||
// Implement model-specific methods for Resolution
 | 
			
		||||
impl_model_methods!(Resolution, resolution, resolutions);
 | 
			
		||||
 | 
			
		||||
// Implement model-specific methods for Committee
 | 
			
		||||
impl_model_methods!(Committee, committee, committees);
 | 
			
		||||
 | 
			
		||||
// Implement model-specific methods for ComplianceRequirement
 | 
			
		||||
impl_model_methods!(ComplianceRequirement, compliance_requirement, compliance_requirements);
 | 
			
		||||
 | 
			
		||||
// Implement model-specific methods for ComplianceDocument
 | 
			
		||||
impl_model_methods!(ComplianceDocument, compliance_document, compliance_documents);
 | 
			
		||||
 | 
			
		||||
// Implement model-specific methods for ComplianceAudit
 | 
			
		||||
impl_model_methods!(ComplianceAudit, compliance_audit, compliance_audits);
 | 
			
		||||
							
								
								
									
										143
									
								
								herodb/src/instructions.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								herodb/src/instructions.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,143 @@
 | 
			
		||||
# HeroDB: ACL Layer Implementation
 | 
			
		||||
 | 
			
		||||
## Project Overview
 | 
			
		||||
 | 
			
		||||
Create a new module that implements an Access Control List (ACL) layer on top of the existing `ourdb` and `tst` databases. This module will manage permissions and access control for data stored in the database system.
 | 
			
		||||
 | 
			
		||||
call this module: acldb
 | 
			
		||||
 | 
			
		||||
implement in acldb
 | 
			
		||||
 | 
			
		||||
remark: there is no dependency on herodb
 | 
			
		||||
 | 
			
		||||
## Architecture
 | 
			
		||||
 | 
			
		||||
- The module will sit as a layer between client applications and the underlying `ourdb` & `tst` databases
 | 
			
		||||
- ACLs are defined at the circle level and stored in a special topic called "acl"
 | 
			
		||||
- Data in `ourdb` is stored at path: `~/hero/var/ourdb/$circleid/$topicid`
 | 
			
		||||
- `tst` is used to create mappings between keys and IDs in `ourdb`
 | 
			
		||||
 | 
			
		||||
## ACL Structure
 | 
			
		||||
 | 
			
		||||
Each ACL contains:
 | 
			
		||||
- A unique name (per circle)
 | 
			
		||||
- A list of public keys with associated permissions
 | 
			
		||||
- Rights are hierarchical: read → write → delete → execute → admin (each right includes all rights to its left)
 | 
			
		||||
 | 
			
		||||
## Core Methods
 | 
			
		||||
 | 
			
		||||
### ACL Management
 | 
			
		||||
 | 
			
		||||
#### aclupdate
 | 
			
		||||
Updates or creates an ACL with specified permissions.
 | 
			
		||||
 | 
			
		||||
**Parameters:**
 | 
			
		||||
- `callerpubkey`: Public key of the requesting user
 | 
			
		||||
- `circleid`: ID of the circle where the ACL exists
 | 
			
		||||
- `name`: Unique name for the ACL within the circle
 | 
			
		||||
- `pubkeys`: Array of public keys to grant permissions to
 | 
			
		||||
- `right`: Permission level (enum: read/write/delete/execute/admin)
 | 
			
		||||
#### aclremove
 | 
			
		||||
Removes specific public keys from an existing ACL.
 | 
			
		||||
 | 
			
		||||
**Parameters:**
 | 
			
		||||
- `callerpubkey`: Public key of the requesting user
 | 
			
		||||
- `circleid`: ID of the circle where the ACL exists
 | 
			
		||||
- `name`: Name of the ACL to modify
 | 
			
		||||
- `pubkeys`: Array of public keys to remove from the ACL
 | 
			
		||||
 | 
			
		||||
#### acldel
 | 
			
		||||
Deletes an entire ACL.
 | 
			
		||||
 | 
			
		||||
**Parameters:**
 | 
			
		||||
- `callerpubkey`: Public key of the requesting user
 | 
			
		||||
- `circleid`: ID of the circle where the ACL exists
 | 
			
		||||
- `name`: Name of the ACL to delete
 | 
			
		||||
 | 
			
		||||
### Data Operations
 | 
			
		||||
 | 
			
		||||
#### set
 | 
			
		||||
Stores or updates data in the database with optional ACL protection.
 | 
			
		||||
 | 
			
		||||
**Parameters:**
 | 
			
		||||
- `callerpubkey`: Public key of the requesting user
 | 
			
		||||
- `circleid`: ID of the circle where the data belongs
 | 
			
		||||
- `topic`: String identifier for the database category (e.g., "customer", "product")
 | 
			
		||||
- `key`: Optional string key for the record
 | 
			
		||||
- `id`: Optional numeric ID for direct access
 | 
			
		||||
- `value`: Binary blob of data to store
 | 
			
		||||
- `aclid`: ID of the ACL to protect this record (0 for public access)
 | 
			
		||||
 | 
			
		||||
**Behavior:**
 | 
			
		||||
- If only `key` is provided, use `tst` to map the key to a new or existing ID
 | 
			
		||||
- If `id` is specified or derived from an existing key, update the corresponding record
 | 
			
		||||
- Returns the ID of the created/updated record
 | 
			
		||||
 | 
			
		||||
#### del
 | 
			
		||||
Marks a record as deleted.
 | 
			
		||||
 | 
			
		||||
**Parameters:**
 | 
			
		||||
- `callerpubkey`: Public key of the requesting user
 | 
			
		||||
- `circleid`: ID of the circle where the data belongs
 | 
			
		||||
- `topic`: String identifier for the database category
 | 
			
		||||
- `id` or `key`: Identifier for the record to delete
 | 
			
		||||
 | 
			
		||||
**Behavior:**
 | 
			
		||||
- Deletes the mapping in `tst` if a key was used
 | 
			
		||||
- Marks the record as deleted in `ourdb` (not physically removed)
 | 
			
		||||
 | 
			
		||||
#### get
 | 
			
		||||
Retrieves data from the database.
 | 
			
		||||
 | 
			
		||||
**Parameters:**
 | 
			
		||||
- `callerpubkey`: Public key of the requesting user
 | 
			
		||||
- `circleid`: ID of the circle where the data belongs
 | 
			
		||||
- `topic`: String identifier for the database category
 | 
			
		||||
- `id` or `key`: Identifier for the record to retrieve
 | 
			
		||||
 | 
			
		||||
**Returns:**
 | 
			
		||||
- The binary data stored in the record if the caller has access
 | 
			
		||||
 | 
			
		||||
## Implementation Details
 | 
			
		||||
 | 
			
		||||
### ACL Storage Format
 | 
			
		||||
- ACLs are stored in a special topic named "acl" within each circle
 | 
			
		||||
- Each ACL has a unique numeric ID within the circle
 | 
			
		||||
 | 
			
		||||
### Record ACL Protection
 | 
			
		||||
- When a record uses ACL protection, the first 4 bytes of the stored data contain the ACL ID
 | 
			
		||||
- A new constructor in `ourdb` should be created to handle ACL-protected records
 | 
			
		||||
- Records with ACL ID of 0 are accessible to everyone
 | 
			
		||||
 | 
			
		||||
## RPC Interface
 | 
			
		||||
 | 
			
		||||
The module should expose its functionality through an RPC interface:
 | 
			
		||||
 | 
			
		||||
1. Client sends:
 | 
			
		||||
   - Method name (e.g., "del", "set", "get")
 | 
			
		||||
   - JSON-encoded arguments
 | 
			
		||||
   - Cryptographic signature of the JSON data
 | 
			
		||||
 | 
			
		||||
2. Server:
 | 
			
		||||
   - Verifies the signature is valid
 | 
			
		||||
   - Extracts the caller's public key from the signature
 | 
			
		||||
   - Checks permissions against applicable ACLs
 | 
			
		||||
   - Executes the requested operation if authorized
 | 
			
		||||
   - Returns appropriate response
 | 
			
		||||
 | 
			
		||||
## Security Considerations
 | 
			
		||||
 | 
			
		||||
- All operations must validate the caller has appropriate permissions
 | 
			
		||||
- ACL changes should be logged for audit purposes
 | 
			
		||||
- Consider implementing rate limiting to prevent abuse
 | 
			
		||||
 | 
			
		||||
## THE SERVER
 | 
			
		||||
 | 
			
		||||
- create actix webserver
 | 
			
		||||
- make a router that handles the rpc interface
 | 
			
		||||
- use openapi spec
 | 
			
		||||
- embed swagger interface
 | 
			
		||||
- implement a queuing mechanism, so internal we don't have to implement locks, but we do 1 request after the other per circle, so we know we never have conflicting changes in 1 circle
 | 
			
		||||
- create a logger which gives us good overview of what happened when
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -69,6 +69,9 @@ impl Wallet {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Implement Storable trait
 | 
			
		||||
impl Storable for Wallet {}
 | 
			
		||||
 | 
			
		||||
// Implement Model trait
 | 
			
		||||
impl Model for Wallet {
 | 
			
		||||
    fn get_id(&self) -> u32 {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
use chrono::{DateTime, Utc};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
use crate::db::{SledModel, Storable, SledDB, SledDBError};
 | 
			
		||||
use crate::db::{Model, Storable, DB, DbError, DbResult};
 | 
			
		||||
use crate::models::gov::User;
 | 
			
		||||
 | 
			
		||||
/// CommitteeRole represents the role of a member in a committee
 | 
			
		||||
@@ -117,11 +117,11 @@ impl Committee {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Get all users who are members of this committee
 | 
			
		||||
    pub fn get_member_users(&self, db: &SledDB<User>) -> Result<Vec<User>, SledDBError> {
 | 
			
		||||
    pub fn get_member_users(&self, db: &DB) -> DbResult<Vec<User>> {
 | 
			
		||||
        let mut users = Vec::new();
 | 
			
		||||
        
 | 
			
		||||
        for member in &self.members {
 | 
			
		||||
            if let Ok(user) = db.get(&member.user_id.to_string()) {
 | 
			
		||||
            if let Ok(user) = db.get::<User>(member.user_id) {
 | 
			
		||||
                users.push(user);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -130,14 +130,31 @@ impl Committee {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Implement Storable trait (provides default dump/load)
 | 
			
		||||
impl Storable for Committee {}
 | 
			
		||||
impl Storable for CommitteeMember {}
 | 
			
		||||
// Implement Storable trait
 | 
			
		||||
impl Storable for Committee {
 | 
			
		||||
    fn serialize(&self) -> DbResult<Vec<u8>> {
 | 
			
		||||
        bincode::serialize(self).map_err(DbError::SerializationError)
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    fn deserialize(data: &[u8]) -> DbResult<Self> {
 | 
			
		||||
        bincode::deserialize(data).map_err(DbError::SerializationError)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Implement SledModel trait
 | 
			
		||||
impl SledModel for Committee {
 | 
			
		||||
    fn get_id(&self) -> String {
 | 
			
		||||
        self.id.to_string()
 | 
			
		||||
impl Storable for CommitteeMember {
 | 
			
		||||
    fn serialize(&self) -> DbResult<Vec<u8>> {
 | 
			
		||||
        bincode::serialize(self).map_err(DbError::SerializationError)
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    fn deserialize(data: &[u8]) -> DbResult<Self> {
 | 
			
		||||
        bincode::deserialize(data).map_err(DbError::SerializationError)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Implement Model trait
 | 
			
		||||
impl Model for Committee {
 | 
			
		||||
    fn get_id(&self) -> u32 {
 | 
			
		||||
        self.id
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn db_prefix() -> &'static str {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
use crate::db::{SledModel, Storable, SledDB, SledDBError};
 | 
			
		||||
use crate::db::{Model, Storable, DbError, DbResult};
 | 
			
		||||
use super::shareholder::Shareholder; // Use super:: for sibling module
 | 
			
		||||
use chrono::{DateTime, Utc};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
@@ -87,17 +87,16 @@ pub struct Company {
 | 
			
		||||
    // Removed shareholders property
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Storable trait provides default dump/load using bincode/brotli
 | 
			
		||||
impl Storable for Company {}
 | 
			
		||||
 | 
			
		||||
// SledModel requires get_id and db_prefix
 | 
			
		||||
impl SledModel for Company {
 | 
			
		||||
    fn get_id(&self) -> String {
 | 
			
		||||
        self.id.to_string()
 | 
			
		||||
 | 
			
		||||
// Model requires get_id and db_prefix
 | 
			
		||||
impl Model for Company {
 | 
			
		||||
    fn get_id(&self) -> u32 {
 | 
			
		||||
        self.id
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn db_prefix() -> &'static str {
 | 
			
		||||
        "company" // Prefix for company records in Sled
 | 
			
		||||
        "company" // Prefix for company records in the database
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -138,20 +137,20 @@ impl Company {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Add a shareholder to the company, saving it to the Shareholder's SledDB
 | 
			
		||||
    /// Add a shareholder to the company, saving it to the database
 | 
			
		||||
    pub fn add_shareholder(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        db: &SledDB<Shareholder>, // Pass in the Shareholder's SledDB
 | 
			
		||||
        db: &mut DB, // Pass in the DB instance
 | 
			
		||||
        mut shareholder: Shareholder,
 | 
			
		||||
    ) -> Result<(), SledDBError> {
 | 
			
		||||
    ) -> DbResult<()> {
 | 
			
		||||
        shareholder.company_id = self.id; // Set the company_id
 | 
			
		||||
        db.insert(&shareholder)?; // Insert the shareholder into its own DB
 | 
			
		||||
        db.set(&shareholder)?; // Insert the shareholder into the DB
 | 
			
		||||
        self.updated_at = Utc::now();
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Link this company to a Circle for access control
 | 
			
		||||
    pub fn link_to_circle(&mut self, circle_id: u32) -> Result<(), SledDBError> {
 | 
			
		||||
    pub fn link_to_circle(&mut self, circle_id: u32) -> DbResult<()> {
 | 
			
		||||
        // Implementation would involve updating a mapping in a separate database
 | 
			
		||||
        // For now, we'll just update the timestamp to indicate the change
 | 
			
		||||
        self.updated_at = Utc::now();
 | 
			
		||||
@@ -159,7 +158,7 @@ impl Company {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Link this company to a Customer in the biz module
 | 
			
		||||
    pub fn link_to_customer(&mut self, customer_id: u32) -> Result<(), SledDBError> {
 | 
			
		||||
    pub fn link_to_customer(&mut self, customer_id: u32) -> DbResult<()> {
 | 
			
		||||
        // Implementation would involve updating a mapping in a separate database
 | 
			
		||||
        // For now, we'll just update the timestamp to indicate the change
 | 
			
		||||
        self.updated_at = Utc::now();
 | 
			
		||||
@@ -167,7 +166,7 @@ impl Company {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Get all resolutions for this company
 | 
			
		||||
    pub fn get_resolutions(&self, db: &crate::db::DB) -> Result<Vec<super::Resolution>, SledDBError> {
 | 
			
		||||
    pub fn get_resolutions(&self, db: &DB) -> DbResult<Vec<super::Resolution>> {
 | 
			
		||||
        let all_resolutions = db.list::<super::Resolution>()?;
 | 
			
		||||
        let company_resolutions = all_resolutions
 | 
			
		||||
            .into_iter()
 | 
			
		||||
@@ -179,8 +178,8 @@ impl Company {
 | 
			
		||||
    
 | 
			
		||||
    // Future methods:
 | 
			
		||||
    // /// Get all committees for this company
 | 
			
		||||
    // pub fn get_committees(&self, db: &SledDB<Committee>) -> Result<Vec<Committee>, SledDBError> { ... }
 | 
			
		||||
    // pub fn get_committees(&self, db: &DB) -> DbResult<Vec<Committee>> { ... }
 | 
			
		||||
    //
 | 
			
		||||
    // /// Get all compliance requirements for this company
 | 
			
		||||
    // pub fn get_compliance_requirements(&self, db: &SledDB<ComplianceRequirement>) -> Result<Vec<ComplianceRequirement>, SledDBError> { ... }
 | 
			
		||||
    // pub fn get_compliance_requirements(&self, db: &DB) -> DbResult<Vec<ComplianceRequirement>> { ... }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
use chrono::{DateTime, Utc};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
use crate::db::{SledModel, Storable, SledDB, SledDBError};
 | 
			
		||||
use crate::db::{Model, Storable, DB, DbError, DbResult};
 | 
			
		||||
use crate::models::gov::Company;
 | 
			
		||||
 | 
			
		||||
/// ComplianceRequirement represents a regulatory requirement
 | 
			
		||||
@@ -82,13 +82,13 @@ impl ComplianceRequirement {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Get the company associated with this requirement
 | 
			
		||||
    pub fn get_company(&self, db: &SledDB<Company>) -> Result<Company, SledDBError> {
 | 
			
		||||
        db.get(&self.company_id.to_string())
 | 
			
		||||
    pub fn get_company(&self, db: &DB) -> DbResult<Company> {
 | 
			
		||||
        db.get::<Company>(self.company_id)
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Get all documents associated with this requirement
 | 
			
		||||
    pub fn get_documents(&self, db: &SledDB<ComplianceDocument>) -> Result<Vec<ComplianceDocument>, SledDBError> {
 | 
			
		||||
        let all_documents = db.list()?;
 | 
			
		||||
    pub fn get_documents(&self, db: &DB) -> DbResult<Vec<ComplianceDocument>> {
 | 
			
		||||
        let all_documents = db.list::<ComplianceDocument>()?;
 | 
			
		||||
        let requirement_documents = all_documents
 | 
			
		||||
            .into_iter()
 | 
			
		||||
            .filter(|doc| doc.requirement_id == self.id)
 | 
			
		||||
@@ -125,8 +125,8 @@ impl ComplianceDocument {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Get the requirement associated with this document
 | 
			
		||||
    pub fn get_requirement(&self, db: &SledDB<ComplianceRequirement>) -> Result<ComplianceRequirement, SledDBError> {
 | 
			
		||||
        db.get(&self.requirement_id.to_string())
 | 
			
		||||
    pub fn get_requirement(&self, db: &DB) -> DbResult<ComplianceRequirement> {
 | 
			
		||||
        db.get::<ComplianceRequirement>(self.requirement_id)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -170,20 +170,15 @@ impl ComplianceAudit {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Get the company associated with this audit
 | 
			
		||||
    pub fn get_company(&self, db: &SledDB<Company>) -> Result<Company, SledDBError> {
 | 
			
		||||
        db.get(&self.company_id.to_string())
 | 
			
		||||
    pub fn get_company(&self, db: &DB) -> DbResult<Company> {
 | 
			
		||||
        db.get::<Company>(self.company_id)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Implement Storable trait (provides default dump/load)
 | 
			
		||||
impl Storable for ComplianceRequirement {}
 | 
			
		||||
impl Storable for ComplianceDocument {}
 | 
			
		||||
impl Storable for ComplianceAudit {}
 | 
			
		||||
 | 
			
		||||
// Implement SledModel trait
 | 
			
		||||
impl SledModel for ComplianceRequirement {
 | 
			
		||||
    fn get_id(&self) -> String {
 | 
			
		||||
        self.id.to_string()
 | 
			
		||||
// Implement Model trait
 | 
			
		||||
impl Model for ComplianceRequirement {
 | 
			
		||||
    fn get_id(&self) -> u32 {
 | 
			
		||||
        self.id
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn db_prefix() -> &'static str {
 | 
			
		||||
@@ -191,9 +186,9 @@ impl SledModel for ComplianceRequirement {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl SledModel for ComplianceDocument {
 | 
			
		||||
    fn get_id(&self) -> String {
 | 
			
		||||
        self.id.to_string()
 | 
			
		||||
impl Model for ComplianceDocument {
 | 
			
		||||
    fn get_id(&self) -> u32 {
 | 
			
		||||
        self.id
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn db_prefix() -> &'static str {
 | 
			
		||||
@@ -201,9 +196,9 @@ impl SledModel for ComplianceDocument {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl SledModel for ComplianceAudit {
 | 
			
		||||
    fn get_id(&self) -> String {
 | 
			
		||||
        self.id.to_string()
 | 
			
		||||
impl Model for ComplianceAudit {
 | 
			
		||||
    fn get_id(&self) -> u32 {
 | 
			
		||||
        self.id
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn db_prefix() -> &'static str {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
use chrono::{DateTime, Utc};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
use crate::db::{SledModel, Storable, SledDB, SledDBError, SledDBResult}; // Import Sled traits from db module
 | 
			
		||||
use crate::db::{Model, Storable, DB, DbError, DbResult}; // Import traits from db module
 | 
			
		||||
// use std::collections::HashMap; // Removed unused import
 | 
			
		||||
 | 
			
		||||
// use super::db::Model; // Removed old Model trait import
 | 
			
		||||
@@ -156,7 +156,7 @@ impl Meeting {
 | 
			
		||||
            .collect()
 | 
			
		||||
    }
 | 
			
		||||
    /// Link this meeting to a Calendar Event in the mcc module
 | 
			
		||||
    pub fn link_to_event(&mut self, event_id: u32) -> Result<(), SledDBError> {
 | 
			
		||||
    pub fn link_to_event(&mut self, event_id: u32) -> DbResult<()> {
 | 
			
		||||
        // Implementation would involve updating a mapping in a separate database
 | 
			
		||||
        // For now, we'll just update the timestamp to indicate the change
 | 
			
		||||
        self.updated_at = Utc::now();
 | 
			
		||||
@@ -164,7 +164,7 @@ impl Meeting {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Get all resolutions discussed in this meeting
 | 
			
		||||
    pub fn get_resolutions(&self, db: &crate::db::DB) -> Result<Vec<super::Resolution>, SledDBError> {
 | 
			
		||||
    pub fn get_resolutions(&self, db: &DB) -> DbResult<Vec<super::Resolution>> {
 | 
			
		||||
        let all_resolutions = db.list::<super::Resolution>()?;
 | 
			
		||||
        let meeting_resolutions = all_resolutions
 | 
			
		||||
            .into_iter()
 | 
			
		||||
@@ -175,13 +175,10 @@ impl Meeting {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Implement Storable trait (provides default dump/load)
 | 
			
		||||
impl Storable for Meeting {}
 | 
			
		||||
 | 
			
		||||
// Implement SledModel trait
 | 
			
		||||
impl SledModel for Meeting {
 | 
			
		||||
    fn get_id(&self) -> String {
 | 
			
		||||
        self.id.to_string()
 | 
			
		||||
// Implement Model trait
 | 
			
		||||
impl Model for Meeting {
 | 
			
		||||
    fn get_id(&self) -> u32 {
 | 
			
		||||
        self.id
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn db_prefix() -> &'static str {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,9 +4,9 @@ pub mod meeting;
 | 
			
		||||
pub mod user;
 | 
			
		||||
pub mod vote;
 | 
			
		||||
pub mod resolution;
 | 
			
		||||
// Future modules:
 | 
			
		||||
// pub mod committee;
 | 
			
		||||
// pub mod compliance;
 | 
			
		||||
// All modules:
 | 
			
		||||
pub mod committee;
 | 
			
		||||
pub mod compliance;
 | 
			
		||||
 | 
			
		||||
// Re-export all model types for convenience
 | 
			
		||||
pub use company::{Company, CompanyStatus, BusinessType};
 | 
			
		||||
@@ -15,6 +15,8 @@ pub use meeting::{Meeting, Attendee, MeetingStatus, AttendeeRole, AttendeeStatus
 | 
			
		||||
pub use user::User;
 | 
			
		||||
pub use vote::{Vote, VoteOption, Ballot, VoteStatus};
 | 
			
		||||
pub use resolution::{Resolution, ResolutionStatus, Approval};
 | 
			
		||||
pub use committee::{Committee, CommitteeMember, CommitteeRole};
 | 
			
		||||
pub use compliance::{ComplianceRequirement, ComplianceDocument, ComplianceAudit};
 | 
			
		||||
 | 
			
		||||
// Re-export database components from db module
 | 
			
		||||
pub use crate::db::{SledDB, SledDBError, SledDBResult, Storable, SledModel, DB};
 | 
			
		||||
pub use crate::db::{DB, DBBuilder, Model, Storable, DbError, DbResult};
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
use chrono::{DateTime, Utc};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
use crate::db::{SledModel, Storable, SledDB, SledDBError};
 | 
			
		||||
use crate::db::{Model, Storable, DB, DbError, DbResult};
 | 
			
		||||
use crate::models::gov::{Meeting, Vote};
 | 
			
		||||
 | 
			
		||||
/// ResolutionStatus represents the status of a resolution
 | 
			
		||||
@@ -158,10 +158,10 @@ impl Resolution {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Get the meeting associated with this resolution
 | 
			
		||||
    pub fn get_meeting(&self, db: &crate::db::DB) -> Result<Option<Meeting>, SledDBError> {
 | 
			
		||||
    pub fn get_meeting(&self, db: &DB) -> DbResult<Option<Meeting>> {
 | 
			
		||||
        match self.meeting_id {
 | 
			
		||||
            Some(meeting_id) => {
 | 
			
		||||
                let meeting = db.get::<Meeting>(&meeting_id.to_string())?;
 | 
			
		||||
                let meeting = db.get::<Meeting>(meeting_id)?;
 | 
			
		||||
                Ok(Some(meeting))
 | 
			
		||||
            }
 | 
			
		||||
            None => Ok(None),
 | 
			
		||||
@@ -169,10 +169,10 @@ impl Resolution {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Get the vote associated with this resolution
 | 
			
		||||
    pub fn get_vote(&self, db: &crate::db::DB) -> Result<Option<Vote>, SledDBError> {
 | 
			
		||||
    pub fn get_vote(&self, db: &DB) -> DbResult<Option<Vote>> {
 | 
			
		||||
        match self.vote_id {
 | 
			
		||||
            Some(vote_id) => {
 | 
			
		||||
                let vote = db.get::<Vote>(&vote_id.to_string())?;
 | 
			
		||||
                let vote = db.get::<Vote>(vote_id)?;
 | 
			
		||||
                Ok(Some(vote))
 | 
			
		||||
            }
 | 
			
		||||
            None => Ok(None),
 | 
			
		||||
@@ -180,14 +180,10 @@ impl Resolution {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Implement Storable trait (provides default dump/load)
 | 
			
		||||
impl Storable for Resolution {}
 | 
			
		||||
impl Storable for Approval {}
 | 
			
		||||
 | 
			
		||||
// Implement SledModel trait
 | 
			
		||||
impl SledModel for Resolution {
 | 
			
		||||
    fn get_id(&self) -> String {
 | 
			
		||||
        self.id.to_string()
 | 
			
		||||
// Implement Model trait
 | 
			
		||||
impl Model for Resolution {
 | 
			
		||||
    fn get_id(&self) -> u32 {
 | 
			
		||||
        self.id
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn db_prefix() -> &'static str {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
use crate::db::{SledModel, Storable}; // Import Sled traits
 | 
			
		||||
use crate::db::{Model, Storable}; // Import db traits
 | 
			
		||||
use chrono::{DateTime, Utc};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
// use std::collections::HashMap; // Removed unused import
 | 
			
		||||
@@ -63,13 +63,10 @@ impl Shareholder {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Implement Storable trait (provides default dump/load)
 | 
			
		||||
impl Storable for Shareholder {}
 | 
			
		||||
 | 
			
		||||
// Implement SledModel trait
 | 
			
		||||
impl SledModel for Shareholder {
 | 
			
		||||
    fn get_id(&self) -> String {
 | 
			
		||||
        self.id.to_string()
 | 
			
		||||
// Implement Model trait
 | 
			
		||||
impl Model for Shareholder {
 | 
			
		||||
    fn get_id(&self) -> u32 {
 | 
			
		||||
        self.id
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn db_prefix() -> &'static str {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
use chrono::{DateTime, Utc};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
use crate::db::{SledModel, Storable}; // Import Sled traits
 | 
			
		||||
use crate::db::{Model, Storable}; // Import db traits
 | 
			
		||||
// use std::collections::HashMap; // Removed unused import
 | 
			
		||||
 | 
			
		||||
/// User represents a user in the governance system
 | 
			
		||||
@@ -42,13 +42,10 @@ impl User {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Implement Storable trait (provides default dump/load)
 | 
			
		||||
impl Storable for User {}
 | 
			
		||||
 | 
			
		||||
// Implement SledModel trait
 | 
			
		||||
impl SledModel for User {
 | 
			
		||||
    fn get_id(&self) -> String {
 | 
			
		||||
        self.id.to_string()
 | 
			
		||||
// Implement Model trait
 | 
			
		||||
impl Model for User {
 | 
			
		||||
    fn get_id(&self) -> u32 {
 | 
			
		||||
        self.id
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn db_prefix() -> &'static str {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
use chrono::{DateTime, Utc};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
use crate::db::{SledModel, Storable, SledDB, SledDBError}; // Import Sled traits from db module
 | 
			
		||||
use crate::db::{Model, Storable, DB, DbError, DbResult}; // Import traits from db module
 | 
			
		||||
// use std::collections::HashMap; // Removed unused import
 | 
			
		||||
 | 
			
		||||
// use super::db::Model; // Removed old Model trait import
 | 
			
		||||
@@ -128,7 +128,7 @@ impl Vote {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /// Get the resolution associated with this vote
 | 
			
		||||
    pub fn get_resolution(&self, db: &crate::db::DB) -> Result<Option<super::Resolution>, SledDBError> {
 | 
			
		||||
    pub fn get_resolution(&self, db: &DB) -> DbResult<Option<super::Resolution>> {
 | 
			
		||||
        let all_resolutions = db.list::<super::Resolution>()?;
 | 
			
		||||
        let vote_resolution = all_resolutions
 | 
			
		||||
            .into_iter()
 | 
			
		||||
@@ -138,13 +138,10 @@ impl Vote {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Implement Storable trait (provides default dump/load)
 | 
			
		||||
impl Storable for Vote {}
 | 
			
		||||
 | 
			
		||||
// Implement SledModel trait
 | 
			
		||||
impl SledModel for Vote {
 | 
			
		||||
    fn get_id(&self) -> String {
 | 
			
		||||
        self.id.to_string()
 | 
			
		||||
// Implement Model trait
 | 
			
		||||
impl Model for Vote {
 | 
			
		||||
    fn get_id(&self) -> u32 {
 | 
			
		||||
        self.id
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn db_prefix() -> &'static str {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user