Compare commits
5 Commits
developmen
...
main
Author | SHA1 | Date | |
---|---|---|---|
33d7eafeac | |||
05259db53d | |||
|
0cffda37a7 | ||
|
1a62fcacdd | ||
7d9a6906c6 |
2056
Cargo.lock
generated
Normal file
2056
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
9
Cargo.toml
Normal file
9
Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"heromodels",
|
||||
"heromodels_core",
|
||||
"heromodels-derive",
|
||||
"ourdb",
|
||||
"radixtree",
|
||||
"tst",
|
||||
]
|
246
do.sql
Normal file
246
do.sql
Normal file
@ -0,0 +1,246 @@
|
||||
-- --------------------------------------------------------------
|
||||
-- do.sql – create tables for HeroLedger models (PostgreSQL)
|
||||
-- --------------------------------------------------------------
|
||||
BEGIN;
|
||||
|
||||
-- 1. DNSZONE
|
||||
CREATE TABLE dnszone (
|
||||
id SERIAL PRIMARY KEY,
|
||||
created BIGINT,
|
||||
updated BIGINT,
|
||||
deleted BOOLEAN,
|
||||
version INTEGER,
|
||||
domain TEXT, -- @[index]
|
||||
administrators INTEGER[], -- array of user ids
|
||||
status TEXT,
|
||||
metadata JSONB,
|
||||
soarecord JSONB, -- store array of SOARecord structs as JSONB
|
||||
data JSONB NOT NULL
|
||||
);
|
||||
CREATE INDEX idx_dnszone_domain ON dnszone(domain);
|
||||
|
||||
-- 2. DNSRECORD
|
||||
CREATE TABLE dnsrecord (
|
||||
id SERIAL PRIMARY KEY,
|
||||
created BIGINT,
|
||||
updated BIGINT,
|
||||
deleted BOOLEAN,
|
||||
version INTEGER,
|
||||
subdomain TEXT,
|
||||
record_type TEXT,
|
||||
value TEXT,
|
||||
priority INTEGER,
|
||||
ttl INTEGER,
|
||||
is_active BOOLEAN,
|
||||
cat TEXT,
|
||||
is_wildcard BOOLEAN,
|
||||
data JSONB NOT NULL
|
||||
);
|
||||
-- No explicit index required – rarely queried alone
|
||||
|
||||
-- 3. GROUP
|
||||
CREATE TABLE "group" (
|
||||
id SERIAL PRIMARY KEY,
|
||||
created BIGINT,
|
||||
updated BIGINT,
|
||||
deleted BOOLEAN,
|
||||
version INTEGER,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
dnsrecords INTEGER[], -- FK → dnsrecord.id (array)
|
||||
administrators INTEGER[],
|
||||
config JSONB, -- embedded GroupConfig struct
|
||||
status TEXT,
|
||||
visibility TEXT,
|
||||
created_ts BIGINT,
|
||||
updated_ts BIGINT,
|
||||
data JSONB NOT NULL
|
||||
);
|
||||
CREATE UNIQUE INDEX idx_group_name ON "group"(name);
|
||||
|
||||
-- 4. USER_GROUP_MEMBERSHIP
|
||||
CREATE TABLE user_group_membership (
|
||||
id SERIAL PRIMARY KEY,
|
||||
created BIGINT,
|
||||
updated BIGINT,
|
||||
deleted BOOLEAN,
|
||||
version INTEGER,
|
||||
user_id INTEGER NOT NULL,
|
||||
group_ids INTEGER[], -- array of group ids
|
||||
data JSONB NOT NULL
|
||||
);
|
||||
CREATE INDEX idx_ugm_user_id ON user_group_membership(user_id);
|
||||
CREATE INDEX idx_ugm_group_ids ON user_group_membership USING GIN (group_ids);
|
||||
|
||||
-- 5. MEMBER (circle/member.v)
|
||||
CREATE TABLE member (
|
||||
id SERIAL PRIMARY KEY,
|
||||
created BIGINT,
|
||||
updated BIGINT,
|
||||
deleted BOOLEAN,
|
||||
version INTEGER,
|
||||
user_id INTEGER NOT NULL,
|
||||
role TEXT,
|
||||
status TEXT,
|
||||
joined_at BIGINT,
|
||||
invited_by INTEGER,
|
||||
permissions TEXT[],
|
||||
data JSONB NOT NULL
|
||||
);
|
||||
CREATE INDEX idx_member_user_id ON member(user_id);
|
||||
|
||||
-- 6. ACCOUNT
|
||||
CREATE TABLE account (
|
||||
id SERIAL PRIMARY KEY,
|
||||
created BIGINT,
|
||||
updated BIGINT,
|
||||
deleted BOOLEAN,
|
||||
version INTEGER,
|
||||
owner_id INTEGER,
|
||||
address TEXT NOT NULL,
|
||||
balance DOUBLE PRECISION,
|
||||
currency TEXT,
|
||||
assetid INTEGER,
|
||||
last_activity BIGINT,
|
||||
administrators INTEGER[],
|
||||
accountpolicy INTEGER,
|
||||
data JSONB NOT NULL
|
||||
);
|
||||
CREATE UNIQUE INDEX idx_account_address ON account(address);
|
||||
CREATE INDEX idx_account_assetid ON account(assetid);
|
||||
|
||||
-- 7. ASSET
|
||||
CREATE TABLE asset (
|
||||
id SERIAL PRIMARY KEY,
|
||||
created BIGINT,
|
||||
updated BIGINT,
|
||||
deleted BOOLEAN,
|
||||
version INTEGER,
|
||||
address TEXT NOT NULL,
|
||||
assetid INTEGER NOT NULL,
|
||||
asset_type TEXT,
|
||||
issuer INTEGER,
|
||||
supply DOUBLE PRECISION,
|
||||
decimals SMALLINT,
|
||||
is_frozen BOOLEAN,
|
||||
metadata JSONB,
|
||||
administrators INTEGER[],
|
||||
min_signatures INTEGER,
|
||||
data JSONB NOT NULL
|
||||
);
|
||||
CREATE UNIQUE INDEX idx_asset_address ON asset(address);
|
||||
CREATE UNIQUE INDEX idx_asset_assetid ON asset(assetid);
|
||||
CREATE INDEX idx_asset_issuer ON asset(issuer);
|
||||
|
||||
-- 8. ACCOUNT_POLICY (holds three AccountPolicyItem JSONB blobs)
|
||||
CREATE TABLE account_policy (
|
||||
id SERIAL PRIMARY KEY,
|
||||
created BIGINT,
|
||||
updated BIGINT,
|
||||
deleted BOOLEAN,
|
||||
version INTEGER,
|
||||
transferpolicy JSONB,
|
||||
adminpolicy JSONB,
|
||||
clawbackpolicy JSONB,
|
||||
freezepolicy JSONB,
|
||||
data JSONB NOT NULL
|
||||
);
|
||||
|
||||
-- 9. ACCOUNT_POLICY_ITEM (stand‑alone if you ever need a table)
|
||||
-- (optional – we store it as JSONB inside account_policy, so not created)
|
||||
|
||||
-- 10. TRANSACTION
|
||||
CREATE TABLE transaction (
|
||||
id SERIAL PRIMARY KEY,
|
||||
created BIGINT,
|
||||
updated BIGINT,
|
||||
deleted BOOLEAN,
|
||||
version INTEGER,
|
||||
txid INTEGER NOT NULL,
|
||||
source INTEGER,
|
||||
destination INTEGER,
|
||||
assetid INTEGER,
|
||||
amount DOUBLE PRECISION,
|
||||
timestamp BIGINT,
|
||||
status TEXT,
|
||||
memo TEXT,
|
||||
tx_type TEXT,
|
||||
signatures JSONB, -- array of Signature JSON objects
|
||||
data JSONB NOT NULL
|
||||
);
|
||||
CREATE UNIQUE INDEX idx_transaction_txid ON transaction(txid);
|
||||
CREATE INDEX idx_transaction_source ON transaction(source);
|
||||
CREATE INDEX idx_transaction_destination ON transaction(destination);
|
||||
CREATE INDEX idx_transaction_assetid ON transaction(assetid);
|
||||
|
||||
-- 11. SIGNATURE
|
||||
CREATE TABLE signature (
|
||||
id SERIAL PRIMARY KEY,
|
||||
created BIGINT,
|
||||
updated BIGINT,
|
||||
deleted BOOLEAN,
|
||||
version INTEGER,
|
||||
signature_id INTEGER NOT NULL,
|
||||
user_id INTEGER NOT NULL,
|
||||
value TEXT,
|
||||
objectid INTEGER,
|
||||
objecttype TEXT,
|
||||
status TEXT,
|
||||
timestamp BIGINT,
|
||||
data JSONB NOT NULL
|
||||
);
|
||||
CREATE INDEX idx_signature_signature_id ON signature(signature_id);
|
||||
CREATE INDEX idx_signature_user_id ON signature(user_id);
|
||||
CREATE INDEX idx_signature_objectid ON signature(objectid);
|
||||
|
||||
-- 12. USER_KVS
|
||||
CREATE TABLE user_kvs (
|
||||
id SERIAL PRIMARY KEY,
|
||||
created BIGINT,
|
||||
updated BIGINT,
|
||||
deleted BOOLEAN,
|
||||
version INTEGER,
|
||||
userid INTEGER NOT NULL,
|
||||
name TEXT,
|
||||
data JSONB NOT NULL
|
||||
);
|
||||
CREATE INDEX idx_userkvs_userid ON user_kvs(userid);
|
||||
|
||||
-- 13. USER_KVS_ITEM
|
||||
CREATE TABLE user_kvs_item (
|
||||
id SERIAL PRIMARY KEY,
|
||||
created BIGINT,
|
||||
updated BIGINT,
|
||||
deleted BOOLEAN,
|
||||
version INTEGER,
|
||||
userkvs_id INTEGER NOT NULL,
|
||||
key TEXT NOT NULL,
|
||||
value TEXT,
|
||||
secretbox JSONB,
|
||||
timestamp BIGINT,
|
||||
data JSONB NOT NULL
|
||||
);
|
||||
CREATE INDEX idx_userkvs_item_userkvs_id ON user_kvs_item(userkvs_id);
|
||||
CREATE INDEX idx_userkvs_item_key ON user_kvs_item(key);
|
||||
|
||||
-- 14. USER
|
||||
CREATE TABLE "user" (
|
||||
id SERIAL PRIMARY KEY,
|
||||
created BIGINT,
|
||||
updated BIGINT,
|
||||
deleted BOOLEAN,
|
||||
version INTEGER,
|
||||
username TEXT NOT NULL,
|
||||
pubkey TEXT NOT NULL,
|
||||
email TEXT[] NOT NULL,
|
||||
status TEXT,
|
||||
userprofile JSONB,
|
||||
kyc JSONB,
|
||||
data JSONB NOT NULL
|
||||
);
|
||||
CREATE UNIQUE INDEX idx_user_username ON "user"(username);
|
||||
CREATE UNIQUE INDEX idx_user_pubkey ON "user"(pubkey);
|
||||
-- Email array index – use GIN for fast containment queries
|
||||
CREATE INDEX idx_user_email ON "user" USING GIN (email);
|
||||
|
||||
COMMIT;
|
@ -14,7 +14,6 @@ ourdb = { path = "../ourdb" }
|
||||
tst = { path = "../tst" }
|
||||
heromodels-derive = { path = "../heromodels-derive" }
|
||||
heromodels_core = { path = "../heromodels_core" }
|
||||
rhailib_derive = { package = "derive", path = "../../rhailib/src/derive" }
|
||||
rhai = { version = "1.21.0", features = [
|
||||
"std",
|
||||
"sync",
|
||||
|
@ -1,318 +0,0 @@
|
||||
# Payment Model Usage Guide
|
||||
|
||||
This document provides comprehensive instructions for AI assistants on how to use the Payment model in the heromodels repository.
|
||||
|
||||
## Overview
|
||||
|
||||
The Payment model represents a payment transaction in the system, typically associated with company registration or subscription payments. It integrates with Stripe for payment processing and maintains comprehensive status tracking.
|
||||
|
||||
## Model Structure
|
||||
|
||||
```rust
|
||||
pub struct Payment {
|
||||
pub base_data: BaseModelData, // Auto-managed ID, timestamps, comments
|
||||
pub payment_intent_id: String, // Stripe payment intent ID
|
||||
pub company_id: u32, // Foreign key to Company
|
||||
pub payment_plan: String, // "monthly", "yearly", "two_year"
|
||||
pub setup_fee: f64, // One-time setup fee
|
||||
pub monthly_fee: f64, // Recurring monthly fee
|
||||
pub total_amount: f64, // Total amount paid
|
||||
pub currency: String, // Currency code (defaults to "usd")
|
||||
pub status: PaymentStatus, // Current payment status
|
||||
pub stripe_customer_id: Option<String>, // Stripe customer ID (set on completion)
|
||||
pub created_at: i64, // Payment creation timestamp
|
||||
pub completed_at: Option<i64>, // Payment completion timestamp
|
||||
}
|
||||
|
||||
pub enum PaymentStatus {
|
||||
Pending, // Initial state - payment created but not processed
|
||||
Processing, // Payment is being processed by Stripe
|
||||
Completed, // Payment successfully completed
|
||||
Failed, // Payment processing failed
|
||||
Refunded, // Payment was refunded
|
||||
}
|
||||
```
|
||||
|
||||
## Basic Usage
|
||||
|
||||
### 1. Creating a New Payment
|
||||
|
||||
```rust
|
||||
use heromodels::models::biz::{Payment, PaymentStatus};
|
||||
|
||||
// Create a new payment with required fields
|
||||
let payment = Payment::new(
|
||||
"pi_1234567890".to_string(), // Stripe payment intent ID
|
||||
company_id, // Company ID from database
|
||||
"monthly".to_string(), // Payment plan
|
||||
100.0, // Setup fee
|
||||
49.99, // Monthly fee
|
||||
149.99, // Total amount
|
||||
);
|
||||
|
||||
// Payment defaults:
|
||||
// - status: PaymentStatus::Pending
|
||||
// - currency: "usd"
|
||||
// - stripe_customer_id: None
|
||||
// - created_at: current timestamp
|
||||
// - completed_at: None
|
||||
```
|
||||
|
||||
### 2. Using Builder Pattern
|
||||
|
||||
```rust
|
||||
let payment = Payment::new(
|
||||
"pi_1234567890".to_string(),
|
||||
company_id,
|
||||
"yearly".to_string(),
|
||||
500.0,
|
||||
99.99,
|
||||
1699.88,
|
||||
)
|
||||
.currency("eur".to_string())
|
||||
.stripe_customer_id(Some("cus_existing_customer".to_string()));
|
||||
```
|
||||
|
||||
### 3. Database Operations
|
||||
|
||||
```rust
|
||||
use heromodels::db::Collection;
|
||||
|
||||
// Save payment to database
|
||||
let db = get_db()?;
|
||||
let (payment_id, saved_payment) = db.set(&payment)?;
|
||||
|
||||
// Retrieve payment by ID
|
||||
let retrieved_payment: Payment = db.get_by_id(payment_id)?.unwrap();
|
||||
|
||||
// Update payment
|
||||
let updated_payment = saved_payment.complete_payment(Some("cus_new_customer".to_string()));
|
||||
let (_, final_payment) = db.set(&updated_payment)?;
|
||||
```
|
||||
|
||||
## Payment Status Management
|
||||
|
||||
### Status Transitions
|
||||
|
||||
```rust
|
||||
// 1. Start with Pending status (default)
|
||||
let payment = Payment::new(/* ... */);
|
||||
assert!(payment.is_pending());
|
||||
|
||||
// 2. Mark as processing when Stripe starts processing
|
||||
let processing_payment = payment.process_payment();
|
||||
assert!(processing_payment.is_processing());
|
||||
|
||||
// 3. Complete payment when Stripe confirms success
|
||||
let completed_payment = processing_payment.complete_payment(Some("cus_123".to_string()));
|
||||
assert!(completed_payment.is_completed());
|
||||
assert!(completed_payment.completed_at.is_some());
|
||||
|
||||
// 4. Handle failure if payment fails
|
||||
let failed_payment = processing_payment.fail_payment();
|
||||
assert!(failed_payment.has_failed());
|
||||
|
||||
// 5. Refund if needed
|
||||
let refunded_payment = completed_payment.refund_payment();
|
||||
assert!(refunded_payment.is_refunded());
|
||||
```
|
||||
|
||||
### Status Check Methods
|
||||
|
||||
```rust
|
||||
// Check current status
|
||||
if payment.is_pending() {
|
||||
// Show "Payment Pending" UI
|
||||
} else if payment.is_processing() {
|
||||
// Show "Processing Payment" UI
|
||||
} else if payment.is_completed() {
|
||||
// Show "Payment Successful" UI
|
||||
// Enable company features
|
||||
} else if payment.has_failed() {
|
||||
// Show "Payment Failed" UI
|
||||
// Offer retry option
|
||||
} else if payment.is_refunded() {
|
||||
// Show "Payment Refunded" UI
|
||||
}
|
||||
```
|
||||
|
||||
## Integration with Company Model
|
||||
|
||||
### Complete Payment Flow
|
||||
|
||||
```rust
|
||||
use heromodels::models::biz::{Company, CompanyStatus, Payment, PaymentStatus};
|
||||
|
||||
// 1. Create company with pending payment status
|
||||
let company = Company::new(
|
||||
"TechStart Inc.".to_string(),
|
||||
"REG-TS-2024-001".to_string(),
|
||||
chrono::Utc::now().timestamp(),
|
||||
)
|
||||
.email("contact@techstart.com".to_string())
|
||||
.status(CompanyStatus::PendingPayment);
|
||||
|
||||
let (company_id, company) = db.set(&company)?;
|
||||
|
||||
// 2. Create payment for the company
|
||||
let payment = Payment::new(
|
||||
stripe_payment_intent_id,
|
||||
company_id,
|
||||
"yearly".to_string(),
|
||||
500.0, // Setup fee
|
||||
99.0, // Monthly fee
|
||||
1688.0, // Total (setup + 12 months)
|
||||
);
|
||||
|
||||
let (payment_id, payment) = db.set(&payment)?;
|
||||
|
||||
// 3. Process payment through Stripe
|
||||
let processing_payment = payment.process_payment();
|
||||
let (_, processing_payment) = db.set(&processing_payment)?;
|
||||
|
||||
// 4. On successful Stripe webhook
|
||||
let completed_payment = processing_payment.complete_payment(Some(stripe_customer_id));
|
||||
let (_, completed_payment) = db.set(&completed_payment)?;
|
||||
|
||||
// 5. Activate company
|
||||
let active_company = company.status(CompanyStatus::Active);
|
||||
let (_, active_company) = db.set(&active_company)?;
|
||||
```
|
||||
|
||||
## Database Indexing
|
||||
|
||||
The Payment model provides custom indexes for efficient querying:
|
||||
|
||||
```rust
|
||||
// Indexed fields for fast lookups:
|
||||
// - payment_intent_id: Find payment by Stripe intent ID
|
||||
// - company_id: Find all payments for a company
|
||||
// - status: Find payments by status
|
||||
|
||||
// Example queries (conceptual - actual implementation depends on your query layer)
|
||||
// let pending_payments = db.find_by_index("status", "Pending")?;
|
||||
// let company_payments = db.find_by_index("company_id", company_id.to_string())?;
|
||||
// let stripe_payment = db.find_by_index("payment_intent_id", "pi_1234567890")?;
|
||||
```
|
||||
|
||||
## Error Handling Best Practices
|
||||
|
||||
```rust
|
||||
use heromodels::db::DbError;
|
||||
|
||||
fn process_payment_flow(payment_intent_id: String, company_id: u32) -> Result<Payment, DbError> {
|
||||
let db = get_db()?;
|
||||
|
||||
// Create payment
|
||||
let payment = Payment::new(
|
||||
payment_intent_id,
|
||||
company_id,
|
||||
"monthly".to_string(),
|
||||
100.0,
|
||||
49.99,
|
||||
149.99,
|
||||
);
|
||||
|
||||
// Save to database
|
||||
let (payment_id, payment) = db.set(&payment)?;
|
||||
|
||||
// Process through Stripe (external API call)
|
||||
match process_stripe_payment(&payment.payment_intent_id) {
|
||||
Ok(stripe_customer_id) => {
|
||||
// Success: complete payment
|
||||
let completed_payment = payment.complete_payment(Some(stripe_customer_id));
|
||||
let (_, final_payment) = db.set(&completed_payment)?;
|
||||
Ok(final_payment)
|
||||
}
|
||||
Err(_) => {
|
||||
// Failure: mark as failed
|
||||
let failed_payment = payment.fail_payment();
|
||||
let (_, final_payment) = db.set(&failed_payment)?;
|
||||
Ok(final_payment)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
The Payment model includes comprehensive tests in `tests/payment.rs`. When working with payments:
|
||||
|
||||
1. **Always test status transitions**
|
||||
2. **Verify timestamp handling**
|
||||
3. **Test database persistence**
|
||||
4. **Test integration with Company model**
|
||||
5. **Test builder pattern methods**
|
||||
|
||||
```bash
|
||||
# Run payment tests
|
||||
cargo test payment
|
||||
|
||||
# Run specific test
|
||||
cargo test test_payment_completion
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### 1. Payment Retry Logic
|
||||
```rust
|
||||
fn retry_failed_payment(payment: Payment) -> Payment {
|
||||
if payment.has_failed() {
|
||||
// Reset to pending for retry
|
||||
Payment::new(
|
||||
payment.payment_intent_id,
|
||||
payment.company_id,
|
||||
payment.payment_plan,
|
||||
payment.setup_fee,
|
||||
payment.monthly_fee,
|
||||
payment.total_amount,
|
||||
)
|
||||
.currency(payment.currency)
|
||||
} else {
|
||||
payment
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Payment Summary
|
||||
```rust
|
||||
fn get_payment_summary(payment: &Payment) -> String {
|
||||
format!(
|
||||
"Payment {} for company {}: {} {} ({})",
|
||||
payment.payment_intent_id,
|
||||
payment.company_id,
|
||||
payment.total_amount,
|
||||
payment.currency.to_uppercase(),
|
||||
payment.status
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Payment Validation
|
||||
```rust
|
||||
fn validate_payment(payment: &Payment) -> Result<(), String> {
|
||||
if payment.total_amount <= 0.0 {
|
||||
return Err("Total amount must be positive".to_string());
|
||||
}
|
||||
if payment.payment_intent_id.is_empty() {
|
||||
return Err("Payment intent ID is required".to_string());
|
||||
}
|
||||
if payment.company_id == 0 {
|
||||
return Err("Valid company ID is required".to_string());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
## Key Points for AI Assistants
|
||||
|
||||
1. **Always use auto-generated IDs** - Don't manually set IDs, let OurDB handle them
|
||||
2. **Follow status flow** - Pending → Processing → Completed/Failed → (optionally) Refunded
|
||||
3. **Update timestamps** - `completed_at` is automatically set when calling `complete_payment()`
|
||||
4. **Use builder pattern** - For optional fields and cleaner code
|
||||
5. **Test thoroughly** - Payment logic is critical, always verify with tests
|
||||
6. **Handle errors gracefully** - Payment failures should be tracked, not ignored
|
||||
7. **Integrate with Company** - Payments typically affect company status
|
||||
8. **Use proper indexing** - Leverage indexed fields for efficient queries
|
||||
|
||||
This model follows the heromodels patterns and integrates seamlessly with the existing codebase architecture.
|
301
heromodels/docs/prompts/v_specs_to_rust_heromodels.md
Normal file
301
heromodels/docs/prompts/v_specs_to_rust_heromodels.md
Normal file
@ -0,0 +1,301 @@
|
||||
# AI Prompt: Convert V Language Specs to Rust Hero Models
|
||||
|
||||
## Objective
|
||||
Convert V language model specifications (`.v` files) to Rust hero models that integrate with the heromodels framework. The generated Rust models should follow the established patterns for base data embedding, indexing, fluent builder APIs, and Rhai scripting integration.
|
||||
|
||||
## V Language Input Structure Analysis
|
||||
|
||||
### V Spec Patterns to Recognize:
|
||||
1. **Module Declaration**: `module circle` or `module group`
|
||||
2. **Base Embedding**: `core.Base` - represents the base model data
|
||||
3. **Index Fields**: Fields marked with `@[index]` comments
|
||||
4. **Mutability**: Fields declared with `pub mut:`
|
||||
5. **Enums**: `pub enum Status { active, inactive, suspended }`
|
||||
6. **Nested Structs**: Embedded configuration or related data structures
|
||||
7. **Collections**: `[]u32`, `[]string`, `map[string]string`
|
||||
8. **References**: `u32` fields typically represent foreign key references
|
||||
|
||||
### Example V Spec Structure:
|
||||
```v
|
||||
module circle
|
||||
|
||||
import freeflowuniverse.herolib.hero.models.core
|
||||
|
||||
pub struct User {
|
||||
core.Base
|
||||
pub mut:
|
||||
username string @[index] // Unique username
|
||||
email []string @[index] // Multiple email addresses
|
||||
status UserStatus // Enum reference
|
||||
profile UserProfile // Nested struct
|
||||
metadata map[string]string // Key-value pairs
|
||||
}
|
||||
|
||||
pub enum UserStatus {
|
||||
active
|
||||
inactive
|
||||
suspended
|
||||
}
|
||||
|
||||
pub struct UserProfile {
|
||||
pub mut:
|
||||
full_name string
|
||||
bio string
|
||||
links map[string]string
|
||||
}
|
||||
```
|
||||
|
||||
## Rust Hero Model Conversion Rules
|
||||
|
||||
### 1. File Structure and Imports
|
||||
```rust
|
||||
use heromodels_core::{Model, BaseModelData, IndexKey};
|
||||
use heromodels_derive::model;
|
||||
use rhai::CustomType;
|
||||
use rhailib_derive::RhaiApi;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use chrono::{DateTime, Utc};
|
||||
```
|
||||
|
||||
### 2. Base Data Embedding
|
||||
- **V**: `core.Base`
|
||||
- **Rust**: `pub base_data: BaseModelData,`
|
||||
|
||||
### 3. Index Field Conversion
|
||||
- **V**: `field_name string @[index]`
|
||||
- **Rust**: `#[index] pub field_name: String,`
|
||||
|
||||
### 4. Type Mappings
|
||||
| V Type | Rust Type |
|
||||
|--------|-----------|
|
||||
| `string` | `String` |
|
||||
| `[]string` | `Vec<String>` |
|
||||
| `[]u32` | `Vec<u32>` |
|
||||
| `u32` | `u32` |
|
||||
| `u64` | `u64` |
|
||||
| `f64` | `f64` |
|
||||
| `bool` | `bool` |
|
||||
| `map[string]string` | `std::collections::HashMap<String, String>` |
|
||||
|
||||
### 5. Struct Declaration Pattern
|
||||
```rust
|
||||
/// Documentation comment describing the model
|
||||
#[model]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType, Default, RhaiApi)]
|
||||
pub struct ModelName {
|
||||
/// Base model data
|
||||
pub base_data: BaseModelData,
|
||||
#[index]
|
||||
pub indexed_field: String,
|
||||
pub regular_field: String,
|
||||
pub optional_field: Option<String>,
|
||||
pub nested_struct: NestedType,
|
||||
pub collection: Vec<u32>,
|
||||
pub metadata: std::collections::HashMap<String, String>,
|
||||
}
|
||||
```
|
||||
|
||||
### 6. Enum Conversion
|
||||
```rust
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum UserStatus {
|
||||
Active,
|
||||
Inactive,
|
||||
Suspended,
|
||||
}
|
||||
```
|
||||
|
||||
### 7. Fluent Builder Implementation
|
||||
Every model must implement a fluent builder pattern:
|
||||
|
||||
```rust
|
||||
impl ModelName {
|
||||
/// Create a new instance
|
||||
pub fn new(id: u32) -> Self {
|
||||
Self {
|
||||
base_data: BaseModelData::new(id),
|
||||
indexed_field: String::new(),
|
||||
regular_field: String::new(),
|
||||
optional_field: None,
|
||||
nested_struct: NestedType::new(),
|
||||
collection: Vec::new(),
|
||||
metadata: std::collections::HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set indexed field (fluent)
|
||||
pub fn indexed_field(mut self, value: impl ToString) -> Self {
|
||||
self.indexed_field = value.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set regular field (fluent)
|
||||
pub fn regular_field(mut self, value: impl ToString) -> Self {
|
||||
self.regular_field = value.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set optional field (fluent)
|
||||
pub fn optional_field(mut self, value: impl ToString) -> Self {
|
||||
self.optional_field = Some(value.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Set nested struct (fluent)
|
||||
pub fn nested_struct(mut self, value: NestedType) -> Self {
|
||||
self.nested_struct = value;
|
||||
self
|
||||
}
|
||||
|
||||
/// Add to collection (fluent)
|
||||
pub fn add_to_collection(mut self, value: u32) -> Self {
|
||||
self.collection.push(value);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set entire collection (fluent)
|
||||
pub fn collection(mut self, value: Vec<u32>) -> Self {
|
||||
self.collection = value;
|
||||
self
|
||||
}
|
||||
|
||||
/// Add metadata entry (fluent)
|
||||
pub fn add_metadata(mut self, key: impl ToString, value: impl ToString) -> Self {
|
||||
self.metadata.insert(key.to_string(), value.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the final instance
|
||||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 8. Model Trait Implementation
|
||||
```rust
|
||||
impl Model for ModelName {
|
||||
fn db_prefix() -> &'static str {
|
||||
"modelname"
|
||||
}
|
||||
|
||||
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<IndexKey> {
|
||||
let mut keys = Vec::new();
|
||||
|
||||
// Add index keys for fields marked with #[index]
|
||||
keys.push(IndexKey::new("indexed_field", &self.indexed_field));
|
||||
|
||||
// Add additional index keys as needed
|
||||
keys
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 9. Nested Struct Builder Pattern
|
||||
For embedded types, implement similar builder patterns:
|
||||
|
||||
```rust
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct NestedType {
|
||||
pub field1: String,
|
||||
pub field2: String,
|
||||
}
|
||||
|
||||
impl NestedType {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
field1: String::new(),
|
||||
field2: String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn field1(mut self, value: impl ToString) -> Self {
|
||||
self.field1 = value.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn field2(mut self, value: impl ToString) -> Self {
|
||||
self.field2 = value.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Conversion Steps
|
||||
|
||||
1. **Analyze V Spec Structure**
|
||||
- Identify the module name and main structs
|
||||
- Note which fields are marked with `@[index]`
|
||||
- Identify nested structs and enums
|
||||
- Map field types from V to Rust
|
||||
|
||||
2. **Create Rust File Structure**
|
||||
- Add appropriate imports
|
||||
- Convert enums first (they're often referenced by structs)
|
||||
- Convert nested structs before main structs
|
||||
|
||||
3. **Implement Main Struct**
|
||||
- Add `#[model]` macro and derives
|
||||
- Embed `BaseModelData` as `base_data`
|
||||
- Mark indexed fields with `#[index]`
|
||||
- Convert field types according to mapping table
|
||||
|
||||
4. **Implement Builder Pattern**
|
||||
- Add `new(id: u32)` constructor
|
||||
- Add fluent setter methods for each field
|
||||
- Handle optional fields appropriately
|
||||
- Add collection manipulation methods
|
||||
|
||||
5. **Implement Model Trait**
|
||||
- Define appropriate `db_prefix`
|
||||
- Implement required trait methods
|
||||
- Add index keys for searchable fields
|
||||
|
||||
6. **Add Documentation**
|
||||
- Document the struct and its purpose
|
||||
- Document each field's meaning
|
||||
- Add usage examples in comments
|
||||
|
||||
## Example Usage After Conversion
|
||||
|
||||
```rust
|
||||
let user = User::new(1)
|
||||
.username("john_doe")
|
||||
.add_email("john@example.com")
|
||||
.add_email("john.doe@company.com")
|
||||
.status(UserStatus::Active)
|
||||
.profile(
|
||||
UserProfile::new()
|
||||
.full_name("John Doe")
|
||||
.bio("Software developer")
|
||||
.build()
|
||||
)
|
||||
.add_metadata("department", "engineering")
|
||||
.build();
|
||||
```
|
||||
|
||||
## Notes and Best Practices
|
||||
|
||||
1. **Field Naming**: Convert V snake_case to Rust snake_case (usually no change needed)
|
||||
2. **Optional Fields**: Use `Option<T>` for fields that may be empty in V
|
||||
3. **Collections**: Always provide both `add_item` and `set_collection` methods
|
||||
4. **Error Handling**: Builder methods should not panic; use appropriate defaults
|
||||
5. **Documentation**: Include comprehensive documentation for public APIs
|
||||
6. **Testing**: Consider adding unit tests for builder patterns
|
||||
7. **Validation**: Add validation logic in builder methods if needed
|
||||
|
||||
## File Organization
|
||||
|
||||
Place the converted Rust models in the appropriate subdirectory under `heromodels/src/models/` based on the domain (e.g., `user/`, `finance/`, `governance/`, etc.).
|
301
heromodels/src/models/heroledger/dnsrecord.rs
Normal file
301
heromodels/src/models/heroledger/dnsrecord.rs
Normal file
@ -0,0 +1,301 @@
|
||||
use heromodels_core::{Model, BaseModelData, IndexKey};
|
||||
use heromodels_derive::model;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Defines the supported DNS record types
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum NameType {
|
||||
A,
|
||||
AAAA,
|
||||
CNAME,
|
||||
MX,
|
||||
TXT,
|
||||
SRV,
|
||||
PTR,
|
||||
NS,
|
||||
}
|
||||
|
||||
impl Default for NameType {
|
||||
fn default() -> Self {
|
||||
NameType::A
|
||||
}
|
||||
}
|
||||
|
||||
/// Category of the DNS record
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum NameCat {
|
||||
IPv4,
|
||||
IPv6,
|
||||
Mycelium,
|
||||
}
|
||||
|
||||
impl Default for NameCat {
|
||||
fn default() -> Self {
|
||||
NameCat::IPv4
|
||||
}
|
||||
}
|
||||
|
||||
/// Status of a DNS zone
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum DNSZoneStatus {
|
||||
Active,
|
||||
Suspended,
|
||||
Archived,
|
||||
}
|
||||
|
||||
impl Default for DNSZoneStatus {
|
||||
fn default() -> Self {
|
||||
DNSZoneStatus::Active
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a DNS record configuration
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct DNSRecord {
|
||||
pub subdomain: String,
|
||||
pub record_type: NameType,
|
||||
pub value: String,
|
||||
pub priority: u32,
|
||||
pub ttl: u32,
|
||||
pub is_active: bool,
|
||||
pub cat: NameCat,
|
||||
pub is_wildcard: bool,
|
||||
}
|
||||
|
||||
impl DNSRecord {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
subdomain: String::new(),
|
||||
record_type: NameType::default(),
|
||||
value: String::new(),
|
||||
priority: 0,
|
||||
ttl: 3600,
|
||||
is_active: true,
|
||||
cat: NameCat::default(),
|
||||
is_wildcard: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn subdomain(mut self, subdomain: impl ToString) -> Self {
|
||||
self.subdomain = subdomain.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn record_type(mut self, record_type: NameType) -> Self {
|
||||
self.record_type = record_type;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn value(mut self, value: impl ToString) -> Self {
|
||||
self.value = value.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn priority(mut self, priority: u32) -> Self {
|
||||
self.priority = priority;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn ttl(mut self, ttl: u32) -> Self {
|
||||
self.ttl = ttl;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn is_active(mut self, is_active: bool) -> Self {
|
||||
self.is_active = is_active;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn cat(mut self, cat: NameCat) -> Self {
|
||||
self.cat = cat;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn is_wildcard(mut self, is_wildcard: bool) -> Self {
|
||||
self.is_wildcard = is_wildcard;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// SOA (Start of Authority) record for a DNS zone
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct SOARecord {
|
||||
pub zone_id: u32,
|
||||
pub primary_ns: String,
|
||||
pub admin_email: String,
|
||||
pub serial: u64,
|
||||
pub refresh: u32,
|
||||
pub retry: u32,
|
||||
pub expire: u32,
|
||||
pub minimum_ttl: u32,
|
||||
pub is_active: bool,
|
||||
}
|
||||
|
||||
impl SOARecord {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
zone_id: 0,
|
||||
primary_ns: String::new(),
|
||||
admin_email: String::new(),
|
||||
serial: 0,
|
||||
refresh: 3600,
|
||||
retry: 600,
|
||||
expire: 604800,
|
||||
minimum_ttl: 3600,
|
||||
is_active: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn zone_id(mut self, zone_id: u32) -> Self {
|
||||
self.zone_id = zone_id;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn primary_ns(mut self, primary_ns: impl ToString) -> Self {
|
||||
self.primary_ns = primary_ns.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn admin_email(mut self, admin_email: impl ToString) -> Self {
|
||||
self.admin_email = admin_email.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn serial(mut self, serial: u64) -> Self {
|
||||
self.serial = serial;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn refresh(mut self, refresh: u32) -> Self {
|
||||
self.refresh = refresh;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn retry(mut self, retry: u32) -> Self {
|
||||
self.retry = retry;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn expire(mut self, expire: u32) -> Self {
|
||||
self.expire = expire;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn minimum_ttl(mut self, minimum_ttl: u32) -> Self {
|
||||
self.minimum_ttl = minimum_ttl;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn is_active(mut self, is_active: bool) -> Self {
|
||||
self.is_active = is_active;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a DNS zone with its configuration and records
|
||||
#[model]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
pub struct DNSZone {
|
||||
/// Base model data
|
||||
pub base_data: BaseModelData,
|
||||
#[index]
|
||||
pub domain: String,
|
||||
pub dnsrecords: Vec<DNSRecord>,
|
||||
pub administrators: Vec<u32>,
|
||||
pub status: DNSZoneStatus,
|
||||
pub metadata: HashMap<String, String>,
|
||||
pub soarecord: Vec<SOARecord>,
|
||||
}
|
||||
|
||||
impl DNSZone {
|
||||
/// Create a new DNS zone instance
|
||||
pub fn new(id: u32) -> Self {
|
||||
let mut base_data = BaseModelData::new();
|
||||
base_data.update_id(id);
|
||||
Self {
|
||||
base_data,
|
||||
domain: String::new(),
|
||||
dnsrecords: Vec::new(),
|
||||
administrators: Vec::new(),
|
||||
status: DNSZoneStatus::default(),
|
||||
metadata: HashMap::new(),
|
||||
soarecord: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the domain name (fluent)
|
||||
pub fn domain(mut self, domain: impl ToString) -> Self {
|
||||
self.domain = domain.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a DNS record (fluent)
|
||||
pub fn add_dnsrecord(mut self, record: DNSRecord) -> Self {
|
||||
self.dnsrecords.push(record);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set all DNS records (fluent)
|
||||
pub fn dnsrecords(mut self, dnsrecords: Vec<DNSRecord>) -> Self {
|
||||
self.dnsrecords = dnsrecords;
|
||||
self
|
||||
}
|
||||
|
||||
/// Add an administrator (fluent)
|
||||
pub fn add_administrator(mut self, admin_id: u32) -> Self {
|
||||
self.administrators.push(admin_id);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set all administrators (fluent)
|
||||
pub fn administrators(mut self, administrators: Vec<u32>) -> Self {
|
||||
self.administrators = administrators;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the zone status (fluent)
|
||||
pub fn status(mut self, status: DNSZoneStatus) -> Self {
|
||||
self.status = status;
|
||||
self
|
||||
}
|
||||
|
||||
/// Add metadata entry (fluent)
|
||||
pub fn add_metadata(mut self, key: impl ToString, value: impl ToString) -> Self {
|
||||
self.metadata.insert(key.to_string(), value.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Set all metadata (fluent)
|
||||
pub fn metadata(mut self, metadata: HashMap<String, String>) -> Self {
|
||||
self.metadata = metadata;
|
||||
self
|
||||
}
|
||||
|
||||
/// Add an SOA record (fluent)
|
||||
pub fn add_soarecord(mut self, soa: SOARecord) -> Self {
|
||||
self.soarecord.push(soa);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set all SOA records (fluent)
|
||||
pub fn soarecord(mut self, soarecord: Vec<SOARecord>) -> Self {
|
||||
self.soarecord = soarecord;
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the final DNS zone instance
|
||||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
236
heromodels/src/models/heroledger/group.rs
Normal file
236
heromodels/src/models/heroledger/group.rs
Normal file
@ -0,0 +1,236 @@
|
||||
use heromodels_core::{Model, BaseModelData, IndexKey};
|
||||
use heromodels_derive::model;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Defines the lifecycle of a group
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum GroupStatus {
|
||||
Active,
|
||||
Inactive,
|
||||
Suspended,
|
||||
Archived,
|
||||
}
|
||||
|
||||
impl Default for GroupStatus {
|
||||
fn default() -> Self {
|
||||
GroupStatus::Active
|
||||
}
|
||||
}
|
||||
|
||||
/// Visibility controls who can discover or view the group
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum Visibility {
|
||||
Public, // Anyone can see and request to join
|
||||
Private, // Only invited users can see the group
|
||||
Unlisted, // Not visible in search; only accessible by direct link or DNS
|
||||
}
|
||||
|
||||
impl Default for Visibility {
|
||||
fn default() -> Self {
|
||||
Visibility::Public
|
||||
}
|
||||
}
|
||||
|
||||
/// GroupConfig holds rules that govern group membership and behavior
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
pub struct GroupConfig {
|
||||
pub max_members: u32,
|
||||
pub allow_guests: bool,
|
||||
pub auto_approve: bool,
|
||||
pub require_invite: bool,
|
||||
}
|
||||
|
||||
impl GroupConfig {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
max_members: 0,
|
||||
allow_guests: false,
|
||||
auto_approve: false,
|
||||
require_invite: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn max_members(mut self, max_members: u32) -> Self {
|
||||
self.max_members = max_members;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn allow_guests(mut self, allow_guests: bool) -> Self {
|
||||
self.allow_guests = allow_guests;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn auto_approve(mut self, auto_approve: bool) -> Self {
|
||||
self.auto_approve = auto_approve;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn require_invite(mut self, require_invite: bool) -> Self {
|
||||
self.require_invite = require_invite;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a collaborative or access-controlled unit within the system
|
||||
#[model]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
pub struct Group {
|
||||
/// Base model data
|
||||
pub base_data: BaseModelData,
|
||||
#[index]
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub dnsrecords: Vec<u32>,
|
||||
pub administrators: Vec<u32>,
|
||||
pub config: GroupConfig,
|
||||
pub status: GroupStatus,
|
||||
pub visibility: Visibility,
|
||||
pub created: u64,
|
||||
pub updated: u64,
|
||||
}
|
||||
|
||||
impl Group {
|
||||
/// Create a new group instance
|
||||
pub fn new(id: u32) -> Self {
|
||||
let mut base_data = BaseModelData::new();
|
||||
base_data.update_id(id);
|
||||
Self {
|
||||
base_data,
|
||||
name: String::new(),
|
||||
description: String::new(),
|
||||
dnsrecords: Vec::new(),
|
||||
administrators: Vec::new(),
|
||||
config: GroupConfig::new(),
|
||||
status: GroupStatus::default(),
|
||||
visibility: Visibility::default(),
|
||||
created: 0,
|
||||
updated: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the group name (fluent)
|
||||
pub fn name(mut self, name: impl ToString) -> Self {
|
||||
self.name = name.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the group description (fluent)
|
||||
pub fn description(mut self, description: impl ToString) -> Self {
|
||||
self.description = description.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a DNS record ID (fluent)
|
||||
pub fn add_dnsrecord(mut self, dnsrecord_id: u32) -> Self {
|
||||
self.dnsrecords.push(dnsrecord_id);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set all DNS record IDs (fluent)
|
||||
pub fn dnsrecords(mut self, dnsrecords: Vec<u32>) -> Self {
|
||||
self.dnsrecords = dnsrecords;
|
||||
self
|
||||
}
|
||||
|
||||
/// Add an administrator user ID (fluent)
|
||||
pub fn add_administrator(mut self, user_id: u32) -> Self {
|
||||
self.administrators.push(user_id);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set all administrator user IDs (fluent)
|
||||
pub fn administrators(mut self, administrators: Vec<u32>) -> Self {
|
||||
self.administrators = administrators;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the group configuration (fluent)
|
||||
pub fn config(mut self, config: GroupConfig) -> Self {
|
||||
self.config = config;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the group status (fluent)
|
||||
pub fn status(mut self, status: GroupStatus) -> Self {
|
||||
self.status = status;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the group visibility (fluent)
|
||||
pub fn visibility(mut self, visibility: Visibility) -> Self {
|
||||
self.visibility = visibility;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the created timestamp (fluent)
|
||||
pub fn created(mut self, created: u64) -> Self {
|
||||
self.created = created;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the updated timestamp (fluent)
|
||||
pub fn updated(mut self, updated: u64) -> Self {
|
||||
self.updated = updated;
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the final group instance
|
||||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Represents the membership relationship between users and groups
|
||||
#[model]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
pub struct UserGroupMembership {
|
||||
/// Base model data
|
||||
pub base_data: BaseModelData,
|
||||
#[index]
|
||||
pub user_id: u32,
|
||||
pub group_ids: Vec<u32>,
|
||||
}
|
||||
|
||||
impl UserGroupMembership {
|
||||
/// Create a new user group membership instance
|
||||
pub fn new(id: u32) -> Self {
|
||||
let mut base_data = BaseModelData::new();
|
||||
base_data.update_id(id);
|
||||
Self {
|
||||
base_data,
|
||||
user_id: 0,
|
||||
group_ids: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the user ID (fluent)
|
||||
pub fn user_id(mut self, user_id: u32) -> Self {
|
||||
self.user_id = user_id;
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a group ID (fluent)
|
||||
pub fn add_group_id(mut self, group_id: u32) -> Self {
|
||||
self.group_ids.push(group_id);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set all group IDs (fluent)
|
||||
pub fn group_ids(mut self, group_ids: Vec<u32>) -> Self {
|
||||
self.group_ids = group_ids;
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the final membership instance
|
||||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
115
heromodels/src/models/heroledger/membership.rs
Normal file
115
heromodels/src/models/heroledger/membership.rs
Normal file
@ -0,0 +1,115 @@
|
||||
use heromodels_core::{Model, BaseModelData, IndexKey};
|
||||
use heromodels_derive::model;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Defines the possible roles a member can have
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum MemberRole {
|
||||
Owner,
|
||||
Admin,
|
||||
Moderator,
|
||||
Member,
|
||||
Guest,
|
||||
}
|
||||
|
||||
impl Default for MemberRole {
|
||||
fn default() -> Self {
|
||||
MemberRole::Member
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the current status of membership
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum MemberStatus {
|
||||
Active,
|
||||
Pending,
|
||||
Suspended,
|
||||
Removed,
|
||||
}
|
||||
|
||||
impl Default for MemberStatus {
|
||||
fn default() -> Self {
|
||||
MemberStatus::Pending
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a member within a circle
|
||||
#[model]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
pub struct Member {
|
||||
/// Base model data
|
||||
pub base_data: BaseModelData,
|
||||
#[index]
|
||||
pub user_id: u32,
|
||||
pub role: MemberRole,
|
||||
pub status: MemberStatus,
|
||||
pub joined_at: u64,
|
||||
pub invited_by: u32,
|
||||
pub permissions: Vec<String>,
|
||||
}
|
||||
|
||||
impl Member {
|
||||
/// Create a new member instance
|
||||
pub fn new(id: u32) -> Self {
|
||||
let mut base_data = BaseModelData::new();
|
||||
base_data.update_id(id);
|
||||
Self {
|
||||
base_data,
|
||||
user_id: 0,
|
||||
role: MemberRole::default(),
|
||||
status: MemberStatus::default(),
|
||||
joined_at: 0,
|
||||
invited_by: 0,
|
||||
permissions: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the user ID (fluent)
|
||||
pub fn user_id(mut self, user_id: u32) -> Self {
|
||||
self.user_id = user_id;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the member role (fluent)
|
||||
pub fn role(mut self, role: MemberRole) -> Self {
|
||||
self.role = role;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the member status (fluent)
|
||||
pub fn status(mut self, status: MemberStatus) -> Self {
|
||||
self.status = status;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the joined timestamp (fluent)
|
||||
pub fn joined_at(mut self, joined_at: u64) -> Self {
|
||||
self.joined_at = joined_at;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set who invited this member (fluent)
|
||||
pub fn invited_by(mut self, invited_by: u32) -> Self {
|
||||
self.invited_by = invited_by;
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a permission (fluent)
|
||||
pub fn add_permission(mut self, permission: impl ToString) -> Self {
|
||||
self.permissions.push(permission.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Set all permissions (fluent)
|
||||
pub fn permissions(mut self, permissions: Vec<String>) -> Self {
|
||||
self.permissions = permissions;
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the final member instance
|
||||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
19
heromodels/src/models/heroledger/mod.rs
Normal file
19
heromodels/src/models/heroledger/mod.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// Export all heroledger model modules
|
||||
pub mod user;
|
||||
pub mod group;
|
||||
pub mod money;
|
||||
pub mod membership;
|
||||
pub mod dnsrecord;
|
||||
pub mod secretbox;
|
||||
pub mod signature;
|
||||
pub mod user_kvs;
|
||||
|
||||
// Re-export key types for convenience
|
||||
pub use user::{User, UserStatus, UserProfile, KYCInfo, KYCStatus, SecretBox};
|
||||
pub use group::{Group, UserGroupMembership, GroupStatus, Visibility, GroupConfig};
|
||||
pub use money::{Account, Asset, AccountPolicy, AccountPolicyItem, Transaction, AccountStatus, TransactionType, Signature as TransactionSignature};
|
||||
pub use membership::{Member, MemberRole, MemberStatus};
|
||||
pub use dnsrecord::{DNSZone, DNSRecord, SOARecord, NameType, NameCat, DNSZoneStatus};
|
||||
pub use secretbox::{Notary, NotaryStatus, SecretBoxCategory};
|
||||
pub use signature::{Signature, SignatureStatus, ObjectType};
|
||||
pub use user_kvs::{UserKVS, UserKVSItem};
|
515
heromodels/src/models/heroledger/money.rs
Normal file
515
heromodels/src/models/heroledger/money.rs
Normal file
@ -0,0 +1,515 @@
|
||||
use heromodels_core::{Model, BaseModelData, IndexKey};
|
||||
use heromodels_derive::model;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Represents the status of an account
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum AccountStatus {
|
||||
Active,
|
||||
Inactive,
|
||||
Suspended,
|
||||
Archived,
|
||||
}
|
||||
|
||||
impl Default for AccountStatus {
|
||||
fn default() -> Self {
|
||||
AccountStatus::Active
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the type of transaction
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum TransactionType {
|
||||
Transfer,
|
||||
Clawback,
|
||||
Freeze,
|
||||
Unfreeze,
|
||||
Issue,
|
||||
Burn,
|
||||
}
|
||||
|
||||
impl Default for TransactionType {
|
||||
fn default() -> Self {
|
||||
TransactionType::Transfer
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a signature for transactions
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct Signature {
|
||||
pub signer_id: u32,
|
||||
pub signature: String,
|
||||
pub timestamp: u64,
|
||||
}
|
||||
|
||||
impl Signature {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
signer_id: 0,
|
||||
signature: String::new(),
|
||||
timestamp: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn signer_id(mut self, signer_id: u32) -> Self {
|
||||
self.signer_id = signer_id;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn signature(mut self, signature: impl ToString) -> Self {
|
||||
self.signature = signature.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn timestamp(mut self, timestamp: u64) -> Self {
|
||||
self.timestamp = timestamp;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Policy item for account operations
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
pub struct AccountPolicyItem {
|
||||
pub signers: Vec<u32>,
|
||||
pub min_signatures: u32,
|
||||
pub enabled: bool,
|
||||
pub threshold: f64,
|
||||
pub recipient: u32,
|
||||
}
|
||||
|
||||
impl AccountPolicyItem {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
signers: Vec::new(),
|
||||
min_signatures: 0,
|
||||
enabled: false,
|
||||
threshold: 0.0,
|
||||
recipient: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_signer(mut self, signer_id: u32) -> Self {
|
||||
self.signers.push(signer_id);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn signers(mut self, signers: Vec<u32>) -> Self {
|
||||
self.signers = signers;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn min_signatures(mut self, min_signatures: u32) -> Self {
|
||||
self.min_signatures = min_signatures;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn enabled(mut self, enabled: bool) -> Self {
|
||||
self.enabled = enabled;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn threshold(mut self, threshold: f64) -> Self {
|
||||
self.threshold = threshold;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn recipient(mut self, recipient: u32) -> Self {
|
||||
self.recipient = recipient;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents an account in the financial system
|
||||
#[model]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
pub struct Account {
|
||||
/// Base model data
|
||||
pub base_data: BaseModelData,
|
||||
pub owner_id: u32,
|
||||
#[index]
|
||||
pub address: String,
|
||||
pub balance: f64,
|
||||
pub currency: String,
|
||||
pub assetid: u32,
|
||||
pub last_activity: u64,
|
||||
pub administrators: Vec<u32>,
|
||||
pub accountpolicy: u32,
|
||||
}
|
||||
|
||||
impl Account {
|
||||
/// Create a new account instance
|
||||
pub fn new(id: u32) -> Self {
|
||||
let mut base_data = BaseModelData::new();
|
||||
base_data.update_id(id);
|
||||
Self {
|
||||
base_data,
|
||||
owner_id: 0,
|
||||
address: String::new(),
|
||||
balance: 0.0,
|
||||
currency: String::new(),
|
||||
assetid: 0,
|
||||
last_activity: 0,
|
||||
administrators: Vec::new(),
|
||||
accountpolicy: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the owner ID (fluent)
|
||||
pub fn owner_id(mut self, owner_id: u32) -> Self {
|
||||
self.owner_id = owner_id;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the blockchain address (fluent)
|
||||
pub fn address(mut self, address: impl ToString) -> Self {
|
||||
self.address = address.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the balance (fluent)
|
||||
pub fn balance(mut self, balance: f64) -> Self {
|
||||
self.balance = balance;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the currency (fluent)
|
||||
pub fn currency(mut self, currency: impl ToString) -> Self {
|
||||
self.currency = currency.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the asset ID (fluent)
|
||||
pub fn assetid(mut self, assetid: u32) -> Self {
|
||||
self.assetid = assetid;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the last activity timestamp (fluent)
|
||||
pub fn last_activity(mut self, last_activity: u64) -> Self {
|
||||
self.last_activity = last_activity;
|
||||
self
|
||||
}
|
||||
|
||||
/// Add an administrator (fluent)
|
||||
pub fn add_administrator(mut self, admin_id: u32) -> Self {
|
||||
self.administrators.push(admin_id);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set all administrators (fluent)
|
||||
pub fn administrators(mut self, administrators: Vec<u32>) -> Self {
|
||||
self.administrators = administrators;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the account policy ID (fluent)
|
||||
pub fn accountpolicy(mut self, accountpolicy: u32) -> Self {
|
||||
self.accountpolicy = accountpolicy;
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the final account instance
|
||||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Represents an asset in the financial system
|
||||
#[model]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
pub struct Asset {
|
||||
/// Base model data
|
||||
pub base_data: BaseModelData,
|
||||
#[index]
|
||||
pub address: String,
|
||||
pub assetid: u32,
|
||||
pub asset_type: String,
|
||||
pub issuer: u32,
|
||||
pub supply: f64,
|
||||
pub decimals: u8,
|
||||
pub is_frozen: bool,
|
||||
pub metadata: HashMap<String, String>,
|
||||
pub administrators: Vec<u32>,
|
||||
pub min_signatures: u32,
|
||||
}
|
||||
|
||||
impl Asset {
|
||||
/// Create a new asset instance
|
||||
pub fn new(id: u32) -> Self {
|
||||
let mut base_data = BaseModelData::new();
|
||||
base_data.update_id(id);
|
||||
Self {
|
||||
base_data,
|
||||
address: String::new(),
|
||||
assetid: 0,
|
||||
asset_type: String::new(),
|
||||
issuer: 0,
|
||||
supply: 0.0,
|
||||
decimals: 0,
|
||||
is_frozen: false,
|
||||
metadata: HashMap::new(),
|
||||
administrators: Vec::new(),
|
||||
min_signatures: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the blockchain address (fluent)
|
||||
pub fn address(mut self, address: impl ToString) -> Self {
|
||||
self.address = address.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the asset ID (fluent)
|
||||
pub fn assetid(mut self, assetid: u32) -> Self {
|
||||
self.assetid = assetid;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the asset type (fluent)
|
||||
pub fn asset_type(mut self, asset_type: impl ToString) -> Self {
|
||||
self.asset_type = asset_type.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the issuer (fluent)
|
||||
pub fn issuer(mut self, issuer: u32) -> Self {
|
||||
self.issuer = issuer;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the supply (fluent)
|
||||
pub fn supply(mut self, supply: f64) -> Self {
|
||||
self.supply = supply;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the decimals (fluent)
|
||||
pub fn decimals(mut self, decimals: u8) -> Self {
|
||||
self.decimals = decimals;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the frozen status (fluent)
|
||||
pub fn is_frozen(mut self, is_frozen: bool) -> Self {
|
||||
self.is_frozen = is_frozen;
|
||||
self
|
||||
}
|
||||
|
||||
/// Add metadata entry (fluent)
|
||||
pub fn add_metadata(mut self, key: impl ToString, value: impl ToString) -> Self {
|
||||
self.metadata.insert(key.to_string(), value.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Set all metadata (fluent)
|
||||
pub fn metadata(mut self, metadata: HashMap<String, String>) -> Self {
|
||||
self.metadata = metadata;
|
||||
self
|
||||
}
|
||||
|
||||
/// Add an administrator (fluent)
|
||||
pub fn add_administrator(mut self, admin_id: u32) -> Self {
|
||||
self.administrators.push(admin_id);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set all administrators (fluent)
|
||||
pub fn administrators(mut self, administrators: Vec<u32>) -> Self {
|
||||
self.administrators = administrators;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set minimum signatures required (fluent)
|
||||
pub fn min_signatures(mut self, min_signatures: u32) -> Self {
|
||||
self.min_signatures = min_signatures;
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the final asset instance
|
||||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Represents account policies for various operations
|
||||
#[model]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
pub struct AccountPolicy {
|
||||
/// Base model data
|
||||
pub base_data: BaseModelData,
|
||||
pub transferpolicy: AccountPolicyItem,
|
||||
pub adminpolicy: AccountPolicyItem,
|
||||
pub clawbackpolicy: AccountPolicyItem,
|
||||
pub freezepolicy: AccountPolicyItem,
|
||||
}
|
||||
|
||||
impl AccountPolicy {
|
||||
/// Create a new account policy instance
|
||||
pub fn new(id: u32) -> Self {
|
||||
let mut base_data = BaseModelData::new();
|
||||
base_data.update_id(id);
|
||||
Self {
|
||||
base_data,
|
||||
transferpolicy: AccountPolicyItem::new(),
|
||||
adminpolicy: AccountPolicyItem::new(),
|
||||
clawbackpolicy: AccountPolicyItem::new(),
|
||||
freezepolicy: AccountPolicyItem::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the transfer policy (fluent)
|
||||
pub fn transferpolicy(mut self, transferpolicy: AccountPolicyItem) -> Self {
|
||||
self.transferpolicy = transferpolicy;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the admin policy (fluent)
|
||||
pub fn adminpolicy(mut self, adminpolicy: AccountPolicyItem) -> Self {
|
||||
self.adminpolicy = adminpolicy;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the clawback policy (fluent)
|
||||
pub fn clawbackpolicy(mut self, clawbackpolicy: AccountPolicyItem) -> Self {
|
||||
self.clawbackpolicy = clawbackpolicy;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the freeze policy (fluent)
|
||||
pub fn freezepolicy(mut self, freezepolicy: AccountPolicyItem) -> Self {
|
||||
self.freezepolicy = freezepolicy;
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the final account policy instance
|
||||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Represents a financial transaction
|
||||
#[model]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
pub struct Transaction {
|
||||
/// Base model data
|
||||
pub base_data: BaseModelData,
|
||||
pub txid: u32,
|
||||
pub source: u32,
|
||||
pub destination: u32,
|
||||
pub assetid: u32,
|
||||
pub amount: f64,
|
||||
pub timestamp: u64,
|
||||
pub status: String,
|
||||
pub memo: String,
|
||||
pub tx_type: TransactionType,
|
||||
pub signatures: Vec<Signature>,
|
||||
}
|
||||
|
||||
impl Transaction {
|
||||
/// Create a new transaction instance
|
||||
pub fn new(id: u32) -> Self {
|
||||
let mut base_data = BaseModelData::new();
|
||||
base_data.update_id(id);
|
||||
Self {
|
||||
base_data,
|
||||
txid: 0,
|
||||
source: 0,
|
||||
destination: 0,
|
||||
assetid: 0,
|
||||
amount: 0.0,
|
||||
timestamp: 0,
|
||||
status: String::new(),
|
||||
memo: String::new(),
|
||||
tx_type: TransactionType::default(),
|
||||
signatures: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the transaction ID (fluent)
|
||||
pub fn txid(mut self, txid: u32) -> Self {
|
||||
self.txid = txid;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the source account (fluent)
|
||||
pub fn source(mut self, source: u32) -> Self {
|
||||
self.source = source;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the destination account (fluent)
|
||||
pub fn destination(mut self, destination: u32) -> Self {
|
||||
self.destination = destination;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the asset ID (fluent)
|
||||
pub fn assetid(mut self, assetid: u32) -> Self {
|
||||
self.assetid = assetid;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the amount (fluent)
|
||||
pub fn amount(mut self, amount: f64) -> Self {
|
||||
self.amount = amount;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the timestamp (fluent)
|
||||
pub fn timestamp(mut self, timestamp: u64) -> Self {
|
||||
self.timestamp = timestamp;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the status (fluent)
|
||||
pub fn status(mut self, status: impl ToString) -> Self {
|
||||
self.status = status.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the memo (fluent)
|
||||
pub fn memo(mut self, memo: impl ToString) -> Self {
|
||||
self.memo = memo.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the transaction type (fluent)
|
||||
pub fn tx_type(mut self, tx_type: TransactionType) -> Self {
|
||||
self.tx_type = tx_type;
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a signature (fluent)
|
||||
pub fn add_signature(mut self, signature: Signature) -> Self {
|
||||
self.signatures.push(signature);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set all signatures (fluent)
|
||||
pub fn signatures(mut self, signatures: Vec<Signature>) -> Self {
|
||||
self.signatures = signatures;
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the final transaction instance
|
||||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
142
heromodels/src/models/heroledger/secretbox.rs
Normal file
142
heromodels/src/models/heroledger/secretbox.rs
Normal file
@ -0,0 +1,142 @@
|
||||
use heromodels_core::{Model, BaseModelData, IndexKey};
|
||||
use heromodels_derive::model;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Category of the secret box
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum SecretBoxCategory {
|
||||
Profile,
|
||||
}
|
||||
|
||||
impl Default for SecretBoxCategory {
|
||||
fn default() -> Self {
|
||||
SecretBoxCategory::Profile
|
||||
}
|
||||
}
|
||||
|
||||
/// Status of a notary
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum NotaryStatus {
|
||||
Active,
|
||||
Inactive,
|
||||
Suspended,
|
||||
Archived,
|
||||
Error,
|
||||
}
|
||||
|
||||
impl Default for NotaryStatus {
|
||||
fn default() -> Self {
|
||||
NotaryStatus::Active
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents an encrypted secret box for storing sensitive data
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct SecretBox {
|
||||
pub notary_id: u32,
|
||||
pub value: String,
|
||||
pub version: u16,
|
||||
pub timestamp: u64,
|
||||
pub cat: SecretBoxCategory,
|
||||
}
|
||||
|
||||
impl SecretBox {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
notary_id: 0,
|
||||
value: String::new(),
|
||||
version: 1,
|
||||
timestamp: 0,
|
||||
cat: SecretBoxCategory::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn notary_id(mut self, notary_id: u32) -> Self {
|
||||
self.notary_id = notary_id;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn value(mut self, value: impl ToString) -> Self {
|
||||
self.value = value.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn version(mut self, version: u16) -> Self {
|
||||
self.version = version;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn timestamp(mut self, timestamp: u64) -> Self {
|
||||
self.timestamp = timestamp;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn cat(mut self, cat: SecretBoxCategory) -> Self {
|
||||
self.cat = cat;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a notary who can decrypt secret boxes
|
||||
#[model]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
pub struct Notary {
|
||||
/// Base model data
|
||||
pub base_data: BaseModelData,
|
||||
#[index]
|
||||
pub userid: u32,
|
||||
pub status: NotaryStatus,
|
||||
pub myceliumaddress: String,
|
||||
#[index]
|
||||
pub pubkey: String,
|
||||
}
|
||||
|
||||
impl Notary {
|
||||
/// Create a new notary instance
|
||||
pub fn new(id: u32) -> Self {
|
||||
let mut base_data = BaseModelData::new();
|
||||
base_data.update_id(id);
|
||||
Self {
|
||||
base_data,
|
||||
userid: 0,
|
||||
status: NotaryStatus::default(),
|
||||
myceliumaddress: String::new(),
|
||||
pubkey: String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the user ID (fluent)
|
||||
pub fn userid(mut self, userid: u32) -> Self {
|
||||
self.userid = userid;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the notary status (fluent)
|
||||
pub fn status(mut self, status: NotaryStatus) -> Self {
|
||||
self.status = status;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the mycelium address (fluent)
|
||||
pub fn myceliumaddress(mut self, myceliumaddress: impl ToString) -> Self {
|
||||
self.myceliumaddress = myceliumaddress.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the public key (fluent)
|
||||
pub fn pubkey(mut self, pubkey: impl ToString) -> Self {
|
||||
self.pubkey = pubkey.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the final notary instance
|
||||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
120
heromodels/src/models/heroledger/signature.rs
Normal file
120
heromodels/src/models/heroledger/signature.rs
Normal file
@ -0,0 +1,120 @@
|
||||
use heromodels_core::{Model, BaseModelData, IndexKey};
|
||||
use heromodels_derive::model;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Status of a signature
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum SignatureStatus {
|
||||
Active,
|
||||
Inactive,
|
||||
Pending,
|
||||
Revoked,
|
||||
}
|
||||
|
||||
impl Default for SignatureStatus {
|
||||
fn default() -> Self {
|
||||
SignatureStatus::Pending
|
||||
}
|
||||
}
|
||||
|
||||
/// Type of object being signed
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum ObjectType {
|
||||
Account,
|
||||
DNSRecord,
|
||||
Membership,
|
||||
User,
|
||||
Transaction,
|
||||
KYC,
|
||||
}
|
||||
|
||||
impl Default for ObjectType {
|
||||
fn default() -> Self {
|
||||
ObjectType::User
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a cryptographic signature for various objects
|
||||
#[model]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
pub struct Signature {
|
||||
/// Base model data
|
||||
pub base_data: BaseModelData,
|
||||
#[index]
|
||||
pub signature_id: u32,
|
||||
#[index]
|
||||
pub user_id: u32,
|
||||
pub value: String,
|
||||
#[index]
|
||||
pub objectid: u32,
|
||||
pub objecttype: ObjectType,
|
||||
pub status: SignatureStatus,
|
||||
pub timestamp: u64,
|
||||
}
|
||||
|
||||
impl Signature {
|
||||
/// Create a new signature instance
|
||||
pub fn new(id: u32) -> Self {
|
||||
let mut base_data = BaseModelData::new();
|
||||
base_data.update_id(id);
|
||||
Self {
|
||||
base_data,
|
||||
signature_id: 0,
|
||||
user_id: 0,
|
||||
value: String::new(),
|
||||
objectid: 0,
|
||||
objecttype: ObjectType::default(),
|
||||
status: SignatureStatus::default(),
|
||||
timestamp: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the signature ID (fluent)
|
||||
pub fn signature_id(mut self, signature_id: u32) -> Self {
|
||||
self.signature_id = signature_id;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the user ID (fluent)
|
||||
pub fn user_id(mut self, user_id: u32) -> Self {
|
||||
self.user_id = user_id;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the signature value (fluent)
|
||||
pub fn value(mut self, value: impl ToString) -> Self {
|
||||
self.value = value.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the object ID (fluent)
|
||||
pub fn objectid(mut self, objectid: u32) -> Self {
|
||||
self.objectid = objectid;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the object type (fluent)
|
||||
pub fn objecttype(mut self, objecttype: ObjectType) -> Self {
|
||||
self.objecttype = objecttype;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the signature status (fluent)
|
||||
pub fn status(mut self, status: SignatureStatus) -> Self {
|
||||
self.status = status;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the timestamp (fluent)
|
||||
pub fn timestamp(mut self, timestamp: u64) -> Self {
|
||||
self.timestamp = timestamp;
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the final signature instance
|
||||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
370
heromodels/src/models/heroledger/user.rs
Normal file
370
heromodels/src/models/heroledger/user.rs
Normal file
@ -0,0 +1,370 @@
|
||||
use heromodels_core::{Model, BaseModelData, IndexKey};
|
||||
use heromodels_derive::model;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Represents the status of a user in the system
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum UserStatus {
|
||||
Active,
|
||||
Inactive,
|
||||
Suspended,
|
||||
Archived,
|
||||
}
|
||||
|
||||
impl Default for UserStatus {
|
||||
fn default() -> Self {
|
||||
UserStatus::Active
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the KYC status of a user
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum KYCStatus {
|
||||
Pending,
|
||||
Approved,
|
||||
Rejected,
|
||||
}
|
||||
|
||||
impl Default for KYCStatus {
|
||||
fn default() -> Self {
|
||||
KYCStatus::Pending
|
||||
}
|
||||
}
|
||||
|
||||
/// User profile information
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct UserProfile {
|
||||
pub user_id: u32,
|
||||
pub full_name: String,
|
||||
pub bio: String,
|
||||
pub profile_pic: String,
|
||||
pub links: HashMap<String, String>,
|
||||
pub metadata: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl UserProfile {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
user_id: 0,
|
||||
full_name: String::new(),
|
||||
bio: String::new(),
|
||||
profile_pic: String::new(),
|
||||
links: HashMap::new(),
|
||||
metadata: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn user_id(mut self, user_id: u32) -> Self {
|
||||
self.user_id = user_id;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn full_name(mut self, full_name: impl ToString) -> Self {
|
||||
self.full_name = full_name.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn bio(mut self, bio: impl ToString) -> Self {
|
||||
self.bio = bio.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn profile_pic(mut self, profile_pic: impl ToString) -> Self {
|
||||
self.profile_pic = profile_pic.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_link(mut self, key: impl ToString, value: impl ToString) -> Self {
|
||||
self.links.insert(key.to_string(), value.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn links(mut self, links: HashMap<String, String>) -> Self {
|
||||
self.links = links;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_metadata(mut self, key: impl ToString, value: impl ToString) -> Self {
|
||||
self.metadata.insert(key.to_string(), value.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn metadata(mut self, metadata: HashMap<String, String>) -> Self {
|
||||
self.metadata = metadata;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// KYC (Know Your Customer) information for a user
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct KYCInfo {
|
||||
pub user_id: u32,
|
||||
pub full_name: String,
|
||||
pub date_of_birth: u64,
|
||||
pub address: String,
|
||||
pub phone_number: String,
|
||||
pub id_number: String,
|
||||
pub id_type: String,
|
||||
pub id_expiry: u64,
|
||||
pub kyc_status: KYCStatus,
|
||||
pub kyc_verified: bool,
|
||||
pub kyc_verified_by: u32,
|
||||
pub kyc_verified_at: u64,
|
||||
pub kyc_rejected_reason: String,
|
||||
pub kyc_signature: u32,
|
||||
pub metadata: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl KYCInfo {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
user_id: 0,
|
||||
full_name: String::new(),
|
||||
date_of_birth: 0,
|
||||
address: String::new(),
|
||||
phone_number: String::new(),
|
||||
id_number: String::new(),
|
||||
id_type: String::new(),
|
||||
id_expiry: 0,
|
||||
kyc_status: KYCStatus::default(),
|
||||
kyc_verified: false,
|
||||
kyc_verified_by: 0,
|
||||
kyc_verified_at: 0,
|
||||
kyc_rejected_reason: String::new(),
|
||||
kyc_signature: 0,
|
||||
metadata: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn user_id(mut self, user_id: u32) -> Self {
|
||||
self.user_id = user_id;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn full_name(mut self, full_name: impl ToString) -> Self {
|
||||
self.full_name = full_name.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn date_of_birth(mut self, date_of_birth: u64) -> Self {
|
||||
self.date_of_birth = date_of_birth;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn address(mut self, address: impl ToString) -> Self {
|
||||
self.address = address.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn phone_number(mut self, phone_number: impl ToString) -> Self {
|
||||
self.phone_number = phone_number.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn id_number(mut self, id_number: impl ToString) -> Self {
|
||||
self.id_number = id_number.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn id_type(mut self, id_type: impl ToString) -> Self {
|
||||
self.id_type = id_type.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn id_expiry(mut self, id_expiry: u64) -> Self {
|
||||
self.id_expiry = id_expiry;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn kyc_status(mut self, kyc_status: KYCStatus) -> Self {
|
||||
self.kyc_status = kyc_status;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn kyc_verified(mut self, kyc_verified: bool) -> Self {
|
||||
self.kyc_verified = kyc_verified;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn kyc_verified_by(mut self, kyc_verified_by: u32) -> Self {
|
||||
self.kyc_verified_by = kyc_verified_by;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn kyc_verified_at(mut self, kyc_verified_at: u64) -> Self {
|
||||
self.kyc_verified_at = kyc_verified_at;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn kyc_rejected_reason(mut self, kyc_rejected_reason: impl ToString) -> Self {
|
||||
self.kyc_rejected_reason = kyc_rejected_reason.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn kyc_signature(mut self, kyc_signature: u32) -> Self {
|
||||
self.kyc_signature = kyc_signature;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_metadata(mut self, key: impl ToString, value: impl ToString) -> Self {
|
||||
self.metadata.insert(key.to_string(), value.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn metadata(mut self, metadata: HashMap<String, String>) -> Self {
|
||||
self.metadata = metadata;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a secret box for storing encrypted data
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct SecretBox {
|
||||
pub data: Vec<u8>,
|
||||
pub nonce: Vec<u8>,
|
||||
}
|
||||
|
||||
impl SecretBox {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
data: Vec::new(),
|
||||
nonce: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data(mut self, data: Vec<u8>) -> Self {
|
||||
self.data = data;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn nonce(mut self, nonce: Vec<u8>) -> Self {
|
||||
self.nonce = nonce;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a user in the heroledger system
|
||||
#[model]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct User {
|
||||
/// Base model data
|
||||
pub base_data: BaseModelData,
|
||||
#[index]
|
||||
pub username: String,
|
||||
#[index]
|
||||
pub pubkey: String,
|
||||
pub email: Vec<String>,
|
||||
pub status: UserStatus,
|
||||
pub userprofile: Vec<SecretBox>,
|
||||
pub kyc: Vec<SecretBox>,
|
||||
}
|
||||
|
||||
impl Default for User {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
base_data: BaseModelData::new(),
|
||||
username: String::new(),
|
||||
pubkey: String::new(),
|
||||
email: Vec::new(),
|
||||
status: UserStatus::default(),
|
||||
userprofile: Vec::new(),
|
||||
kyc: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl User {
|
||||
/// Create a new user instance
|
||||
pub fn new(id: u32) -> Self {
|
||||
let mut base_data = BaseModelData::new();
|
||||
base_data.update_id(id);
|
||||
Self {
|
||||
base_data,
|
||||
username: String::new(),
|
||||
pubkey: String::new(),
|
||||
email: Vec::new(),
|
||||
status: UserStatus::default(),
|
||||
userprofile: Vec::new(),
|
||||
kyc: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the user ID
|
||||
pub fn id(&self) -> u32 {
|
||||
self.base_data.id
|
||||
}
|
||||
|
||||
/// Set the username (fluent)
|
||||
pub fn username(mut self, username: impl ToString) -> Self {
|
||||
self.username = username.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the public key (fluent)
|
||||
pub fn pubkey(mut self, pubkey: impl ToString) -> Self {
|
||||
self.pubkey = pubkey.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Add an email address (fluent)
|
||||
pub fn add_email(mut self, email: impl ToString) -> Self {
|
||||
self.email.push(email.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Set all email addresses (fluent)
|
||||
pub fn email(mut self, email: Vec<String>) -> Self {
|
||||
self.email = email;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the user status (fluent)
|
||||
pub fn status(mut self, status: UserStatus) -> Self {
|
||||
self.status = status;
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a user profile secret box (fluent)
|
||||
pub fn add_userprofile(mut self, profile: SecretBox) -> Self {
|
||||
self.userprofile.push(profile);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set all user profile secret boxes (fluent)
|
||||
pub fn userprofile(mut self, userprofile: Vec<SecretBox>) -> Self {
|
||||
self.userprofile = userprofile;
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a KYC secret box (fluent)
|
||||
pub fn add_kyc(mut self, kyc: SecretBox) -> Self {
|
||||
self.kyc.push(kyc);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set all KYC secret boxes (fluent)
|
||||
pub fn kyc(mut self, kyc: Vec<SecretBox>) -> Self {
|
||||
self.kyc = kyc;
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the final user instance
|
||||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
120
heromodels/src/models/heroledger/user_kvs.rs
Normal file
120
heromodels/src/models/heroledger/user_kvs.rs
Normal file
@ -0,0 +1,120 @@
|
||||
use heromodels_core::{Model, BaseModelData, IndexKey};
|
||||
use heromodels_derive::model;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use super::secretbox::SecretBox;
|
||||
|
||||
/// Represents a per-user key-value store
|
||||
#[model]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
pub struct UserKVS {
|
||||
/// Base model data
|
||||
pub base_data: BaseModelData,
|
||||
#[index]
|
||||
pub userid: u32,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
impl UserKVS {
|
||||
/// Create a new user KVS instance
|
||||
pub fn new(id: u32) -> Self {
|
||||
let mut base_data = BaseModelData::new();
|
||||
base_data.update_id(id);
|
||||
Self {
|
||||
base_data,
|
||||
userid: 0,
|
||||
name: String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the user ID (fluent)
|
||||
pub fn userid(mut self, userid: u32) -> Self {
|
||||
self.userid = userid;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the KVS name (fluent)
|
||||
pub fn name(mut self, name: impl ToString) -> Self {
|
||||
self.name = name.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the final user KVS instance
|
||||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Represents an item in a user's key-value store
|
||||
#[model]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
pub struct UserKVSItem {
|
||||
/// Base model data
|
||||
pub base_data: BaseModelData,
|
||||
#[index]
|
||||
pub userkvs_id: u32,
|
||||
pub key: String,
|
||||
pub value: String,
|
||||
pub secretbox: Vec<SecretBox>,
|
||||
pub timestamp: u64,
|
||||
}
|
||||
|
||||
impl UserKVSItem {
|
||||
/// Create a new user KVS item instance
|
||||
pub fn new(id: u32) -> Self {
|
||||
let mut base_data = BaseModelData::new();
|
||||
base_data.update_id(id);
|
||||
Self {
|
||||
base_data,
|
||||
userkvs_id: 0,
|
||||
key: String::new(),
|
||||
value: String::new(),
|
||||
secretbox: Vec::new(),
|
||||
timestamp: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the user KVS ID (fluent)
|
||||
pub fn userkvs_id(mut self, userkvs_id: u32) -> Self {
|
||||
self.userkvs_id = userkvs_id;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the key (fluent)
|
||||
pub fn key(mut self, key: impl ToString) -> Self {
|
||||
self.key = key.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the value (fluent)
|
||||
pub fn value(mut self, value: impl ToString) -> Self {
|
||||
self.value = value.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a secret box (fluent)
|
||||
pub fn add_secretbox(mut self, secretbox: SecretBox) -> Self {
|
||||
self.secretbox.push(secretbox);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set all secret boxes (fluent)
|
||||
pub fn secretbox(mut self, secretbox: Vec<SecretBox>) -> Self {
|
||||
self.secretbox = secretbox;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the timestamp (fluent)
|
||||
pub fn timestamp(mut self, timestamp: u64) -> Self {
|
||||
self.timestamp = timestamp;
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the final user KVS item instance
|
||||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ pub mod contact;
|
||||
pub mod finance;
|
||||
pub mod flow;
|
||||
pub mod governance;
|
||||
pub mod heroledger;
|
||||
pub mod legal;
|
||||
pub mod library;
|
||||
pub mod object;
|
||||
|
@ -2,12 +2,11 @@ use heromodels_core::BaseModelData;
|
||||
use heromodels_derive::model;
|
||||
use rhai::CustomType;
|
||||
use rhai::TypeBuilder;
|
||||
use rhailib_derive::RhaiApi;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Represents an event in a contact
|
||||
#[model]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType, Default, RhaiApi)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType, Default)]
|
||||
pub struct Object {
|
||||
/// Base model data
|
||||
pub base_data: BaseModelData,
|
||||
|
11
specs/models_heroledger/core/base.v
Normal file
11
specs/models_heroledger/core/base.v
Normal file
@ -0,0 +1,11 @@
|
||||
module core
|
||||
|
||||
// BaseData provides common fields for all models
|
||||
pub struct Base {
|
||||
pub mut:
|
||||
id u32
|
||||
created u64 // Unix timestamp of creation
|
||||
updated u64 // Unix timestamp of last update
|
||||
deleted bool
|
||||
version u32
|
||||
}
|
69
specs/models_heroledger/main/dnsrecord.v
Normal file
69
specs/models_heroledger/main/dnsrecord.v
Normal file
@ -0,0 +1,69 @@
|
||||
module circle
|
||||
|
||||
import freeflowuniverse.herolib.hero.models.core
|
||||
|
||||
|
||||
pub struct DNSZone {
|
||||
core.Base
|
||||
pub mut:
|
||||
domain string @[index] // The actual domain name
|
||||
dnsrecords []DNSRecord
|
||||
administrators []u32
|
||||
status DNSZoneStatus // active, suspended, etc.
|
||||
metadata map[string]string
|
||||
soarecord []SOARecord //one soa record per zone, last one is valid, rest is for history
|
||||
}
|
||||
|
||||
|
||||
// Name represents a domain name configuration for a circle
|
||||
pub struct DNSRecord {
|
||||
pub mut:
|
||||
subdomain string // Optional subdomain e.g. main, means mail.example.com, example.com would be the domain, here only 'mail'
|
||||
record_type NameType // Type of DNS record
|
||||
value string // DNS record value/target
|
||||
priority u32 // Priority for MX records
|
||||
ttl u32 // Time to live in seconds
|
||||
is_active bool // Whether this record is currently active
|
||||
cat NameCat // Category of the DNS record, e.g., ipv4, ipv6, mycelium
|
||||
is_wildcard bool // Whether this is a wildcard record
|
||||
|
||||
}
|
||||
|
||||
// NameType defines the supported DNS record types
|
||||
pub enum NameType {
|
||||
a
|
||||
aaaa
|
||||
cname
|
||||
mx
|
||||
txt
|
||||
srv
|
||||
ptr
|
||||
ns
|
||||
}
|
||||
|
||||
pub enum NameCat {
|
||||
ipv4
|
||||
ipv6
|
||||
mycelium
|
||||
}
|
||||
|
||||
pub enum DNSZoneStatus {
|
||||
active
|
||||
suspended
|
||||
archived
|
||||
}
|
||||
|
||||
// SOA (Start of Authority) record for a DNS zone
|
||||
pub struct SOARecord {
|
||||
pub mut:
|
||||
zone_id u32 // Reference to DNSZone
|
||||
primary_ns string // Primary nameserver (e.g., ns1.example.com)
|
||||
admin_email string // Responsible party's email (e.g., admin.example.com)
|
||||
serial u64 // Serial number of the zone file, needs to be incremented on changes
|
||||
refresh u32 = 3600 // Time before zone should be refreshed (in seconds)
|
||||
retry u32 = 600 // Time before retry if refresh fails (in seconds)
|
||||
expire u32 = 604800 // Time before zone is considered no longer authoritative
|
||||
minimum_ttl u32 = 3600 // Default TTL for records without explicit TTL
|
||||
is_active bool = true // Whether this SOA record is active
|
||||
}
|
||||
|
51
specs/models_heroledger/main/group.v
Normal file
51
specs/models_heroledger/main/group.v
Normal file
@ -0,0 +1,51 @@
|
||||
module group
|
||||
|
||||
import freeflowuniverse.herolib.hero.models.core
|
||||
|
||||
// Group represents a collaborative or access-controlled unit within the system
|
||||
@[heap]
|
||||
pub struct Group {
|
||||
core.Base
|
||||
pub mut:
|
||||
name string // Human-readable name of the group @[index]
|
||||
description string // Detailed explanation of the group's purpose
|
||||
dnsrecords []u32 // DNSRecord IDs associated with this group (if any)
|
||||
administrators []u32 // User IDs with admin rights over the group
|
||||
config GroupConfig // Configuration settings for group behavior
|
||||
status GroupStatus // Current operational state
|
||||
visibility Visibility // Who can see this group
|
||||
created u64 // Unix timestamp when the group was created
|
||||
updated u64 // Unix timestamp when the group was last updated
|
||||
}
|
||||
|
||||
@[heap]
|
||||
pub struct UserGroupMembership {
|
||||
core.Base
|
||||
pub mut:
|
||||
user_id u32 @[index] // Reference to the user entity
|
||||
group_ids []u32 @[index] // Reference to the group entity
|
||||
}
|
||||
|
||||
// GroupConfig holds rules that govern group membership and behavior
|
||||
pub struct GroupConfig {
|
||||
pub mut:
|
||||
max_members u32 // Maximum number of users allowed
|
||||
allow_guests bool // Whether guest users (unregistered or read-only) can access
|
||||
auto_approve bool // Whether member join requests are auto-approved
|
||||
require_invite bool // Whether joining the group requires an explicit invitation
|
||||
}
|
||||
|
||||
// GroupStatus defines the lifecycle of a group
|
||||
pub enum GroupStatus {
|
||||
active
|
||||
inactive
|
||||
suspended
|
||||
archived
|
||||
}
|
||||
|
||||
// Visibility controls who can discover or view the group
|
||||
pub enum Visibility {
|
||||
public // Anyone can see and request to join
|
||||
private // Only invited users can see the group
|
||||
unlisted // Not visible in search; only accessible by direct link or DNS
|
||||
}
|
34
specs/models_heroledger/main/membership.v
Normal file
34
specs/models_heroledger/main/membership.v
Normal file
@ -0,0 +1,34 @@
|
||||
module circle
|
||||
|
||||
import freeflowuniverse.herolib.hero.models.core
|
||||
|
||||
> STILL WRONG
|
||||
|
||||
// Member represents a member within a circle
|
||||
pub struct Member {
|
||||
core.Base
|
||||
pub mut:
|
||||
user_id u32 // Reference to the user entity @[index]
|
||||
role MemberRole // Member's role within the circle
|
||||
status MemberStatus // Current membership status
|
||||
joined_at u64 // Unix timestamp when member joined
|
||||
invited_by u32 // User ID of who invited this member
|
||||
permissions []string // List of custom permissions
|
||||
}
|
||||
|
||||
// MemberRole defines the possible roles a member can have
|
||||
pub enum MemberRole {
|
||||
owner
|
||||
admin
|
||||
moderator
|
||||
member
|
||||
guest
|
||||
}
|
||||
|
||||
// MemberStatus represents the current status of membership
|
||||
pub enum MemberStatus {
|
||||
active
|
||||
pending
|
||||
suspended
|
||||
removed
|
||||
}
|
94
specs/models_heroledger/main/money.v
Normal file
94
specs/models_heroledger/main/money.v
Normal file
@ -0,0 +1,94 @@
|
||||
module circle
|
||||
|
||||
import freeflowuniverse.herolib.hero.models.core
|
||||
|
||||
// Wallet represents a wallet associated with a circle for financial operations
|
||||
pub struct Account {
|
||||
core.Base
|
||||
pub mut:
|
||||
owner_id u32 // Reference to the user who owns this account, owner not necessarily has admin rights
|
||||
address string // Blockchain address for this wallet @[index]
|
||||
balance f64 // Current balance in the wallet
|
||||
currency string // Currency type (e.g., "USD", "BTC", "ETH")
|
||||
assetid u32 @[index]
|
||||
last_activity u64 // Unix timestamp of last transaction
|
||||
administrators []u32 // List of user IDs who are super admins, they have all rights, without any treashold
|
||||
accountpolicy u32 // Policy for signing transactions, 0 means none
|
||||
}
|
||||
|
||||
|
||||
pub struct Asset {
|
||||
core.Base
|
||||
pub mut:
|
||||
address string // Blockchain address for this asset @[index]
|
||||
assetid u32 @[index] // Unique identifier for the asset (e.g., "USD", "BTC", "ETH")
|
||||
asset_type string // "fiat", "crypto", "stablecoin", etc.
|
||||
issuer u32 @[index] // Issuer account
|
||||
supply f64 // Total circulating supply
|
||||
decimals u8 // Decimal precision (e.g., 2 for cents)
|
||||
is_frozen bool // Whether the asset is frozen globally
|
||||
metadata map[string]string // Additional metadata associated with the asset
|
||||
administrators []u32
|
||||
min_signatures u32 // Minimum number of signatures required for change of properties, linked to administrators
|
||||
|
||||
//BLOCKCHAIN
|
||||
}
|
||||
|
||||
|
||||
pub struct AccountPolicy {
|
||||
core.Base
|
||||
pub mut:
|
||||
transferpolicy AccountPolicyItem //can transfer money
|
||||
adminpolicy AccountPolicyItem //can change other policies
|
||||
clawbackpolicy AccountPolicyItem // Policy for clawback money
|
||||
freezepolicy AccountPolicyItem // Policy for freezing, unfreezing funds
|
||||
}
|
||||
|
||||
pub struct AccountPolicyItem {
|
||||
pub mut:
|
||||
signers []u32 // List of user IDs who are authorized to sign transactions
|
||||
min_signatures u32 // Minimum number of signatures required for a transaction
|
||||
enabled bool // Whether clawback is enabled for this account
|
||||
threshold f64 // Threshold amount for triggering clawback
|
||||
recipient u32 @[index] // Account ID of the recipient for clawback funds
|
||||
}
|
||||
|
||||
pub enum AccountStatus {
|
||||
active
|
||||
inactive
|
||||
suspended
|
||||
archived
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub struct Transaction {
|
||||
core.Base
|
||||
pub mut:
|
||||
txid u32 @[index] // Unique identifier for the transaction
|
||||
source u32 @[index]
|
||||
destination u32 @[index]
|
||||
assetid u32 @[index]
|
||||
amount f64
|
||||
timestamp u64
|
||||
status string // pending, confirmed, failed
|
||||
memo string
|
||||
tx_type TransactionType // transfer, clawback, freeze, issue, etc.
|
||||
signatures []Signature
|
||||
}
|
||||
|
||||
|
||||
pub enum AccountStatus {
|
||||
active
|
||||
inactive
|
||||
suspended
|
||||
archived
|
||||
}
|
||||
pub enum TransactionType {
|
||||
transfer
|
||||
clawback
|
||||
freeze
|
||||
unfreeze
|
||||
issue
|
||||
burn
|
||||
}
|
31
specs/models_heroledger/main/secretbox.v
Normal file
31
specs/models_heroledger/main/secretbox.v
Normal file
@ -0,0 +1,31 @@
|
||||
module main
|
||||
|
||||
pub struct SecretBox {
|
||||
pub mut:
|
||||
notary_id u32 // person who is allowed to decrypt this info
|
||||
value string //the actual incrypted value
|
||||
version u16 //version of the schema used to encrypt this value
|
||||
timestamp u64
|
||||
cat SecretBoxCategory //category of the secret box, e.g. profile
|
||||
}
|
||||
|
||||
pub enum SecretBoxCategory {
|
||||
profile
|
||||
}
|
||||
|
||||
pub struct Notary {
|
||||
core.Base
|
||||
pub mut:
|
||||
userid u32 // Reference to the user entity @[index]
|
||||
status NotaryStatus // Current user status
|
||||
myceliumaddress string // Mycelium address of the notary
|
||||
pubkey string // Public key for cryptographic operations @[index]
|
||||
}
|
||||
|
||||
pub enum NotaryStatus {
|
||||
active
|
||||
inactive
|
||||
suspended
|
||||
archived
|
||||
error
|
||||
}
|
32
specs/models_heroledger/main/signature.v
Normal file
32
specs/models_heroledger/main/signature.v
Normal file
@ -0,0 +1,32 @@
|
||||
module circle
|
||||
|
||||
import freeflowuniverse.herolib.hero.models.core
|
||||
|
||||
// Wallet represents a wallet associated with a circle for financial operations
|
||||
pub struct Signature {
|
||||
core.Base
|
||||
pub mut:
|
||||
signature_id u32 // Reference to the user who created the signature @[index]
|
||||
user_id u32 // Reference to the user who created the signature @[index]
|
||||
value string // The actual signature value
|
||||
objectid u32 // Reference to the user who created the signature @[index]
|
||||
objecttype ObjectType // Type of object being signed (e.g.,
|
||||
status SignatureStatus
|
||||
timestamp u64
|
||||
}
|
||||
|
||||
pub enum SignatureStatus {
|
||||
active
|
||||
inactive
|
||||
pending
|
||||
revoked
|
||||
}
|
||||
|
||||
pub enum ObjectType {
|
||||
account
|
||||
dnsrecord
|
||||
membership
|
||||
user
|
||||
transaction
|
||||
kyc
|
||||
}
|
58
specs/models_heroledger/main/user.v
Normal file
58
specs/models_heroledger/main/user.v
Normal file
@ -0,0 +1,58 @@
|
||||
module circle
|
||||
|
||||
import freeflowuniverse.herolib.hero.models.core
|
||||
|
||||
// Wallet represents a wallet associated with a circle for financial operations
|
||||
pub struct User {
|
||||
core.Base
|
||||
pub mut:
|
||||
username string // Unique username for the user @[index]
|
||||
pubkey string // Public key for cryptographic operations @[index]
|
||||
email []string @[index] // User's email addresses, needs to be considered unique and can be multiple
|
||||
status UserStatus // Current user status
|
||||
userprofile []SecretBox // User profile information stored in a secret box
|
||||
kyc []SecretBox // KYC information stored in a secret box
|
||||
}
|
||||
|
||||
|
||||
pub enum UserStatus {
|
||||
active
|
||||
inactive
|
||||
suspended
|
||||
archived
|
||||
}
|
||||
|
||||
pub struct UserProfile {
|
||||
pub mut:
|
||||
user_id u32 // Reference to the user entity @[index]
|
||||
full_name string // Full name of the user
|
||||
bio string // Short biography or description
|
||||
profile_pic string // URL to the user's profile picture
|
||||
links map[string]string // Social media or other relevant links
|
||||
metadata map[string]string // Additional metadata associated with the user profile
|
||||
}
|
||||
|
||||
pub struct KYCInfo {
|
||||
pub mut:
|
||||
user_id u32 // Reference to the user entity @[index]
|
||||
full_name string // Full name of the user
|
||||
date_of_birth u64 // Unix timestamp of user's date of birth
|
||||
address string // User's residential address
|
||||
phone_number string // User's phone number
|
||||
id_number string // Government-issued ID number (e.g., passport, driver's license)
|
||||
id_type string // Type of ID (e.g., "passport", "driver's license")
|
||||
id_expiry u64 // Unix timestamp of ID expiry date
|
||||
kyc_status KYCStatus // Current KYC status
|
||||
kyc_verified bool // Whether the KYC information has been verified
|
||||
kyc_verified_by u32 // User ID of the person who verified the KYC
|
||||
kyc_verified_at u64 // Unix timestamp when KYC was verified
|
||||
kyc_rejected_reason string // Reason for KYC rejection, if applicable
|
||||
kyc_signature u32 // Signature of the user for KYC verification
|
||||
metadata map[string]string // Additional metadata associated with the user profile
|
||||
}
|
||||
|
||||
pub enum KYCStatus {
|
||||
pending
|
||||
approved
|
||||
rejected
|
||||
}
|
22
specs/models_heroledger/main/user_kvs.v
Normal file
22
specs/models_heroledger/main/user_kvs.v
Normal file
@ -0,0 +1,22 @@
|
||||
module circle
|
||||
|
||||
import freeflowuniverse.herolib.hero.models.core
|
||||
|
||||
//a per user db
|
||||
pub struct UserKVS {
|
||||
core.Base
|
||||
pub mut:
|
||||
userid u32 // Reference to the user entity @[index]
|
||||
name string // Name of the key-value store
|
||||
}
|
||||
|
||||
pub struct UserKVSItem {
|
||||
core.Base
|
||||
pub mut:
|
||||
userkvs_id u32 // Reference to the user entity @[index]
|
||||
key string
|
||||
value string // Value associated with the key
|
||||
secretbox []SecretBox // Optional secret boxes for sensitive data
|
||||
timestamp u64 // Timestamp when the item was created or last updated
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user