From 6b4f015ac038d1afc730754bacaa86cc29ef5fb1 Mon Sep 17 00:00:00 2001 From: despiegk Date: Wed, 17 Sep 2025 16:45:14 +0200 Subject: [PATCH] ... --- lib/heromodels/location.v | 288 ++++++++++++++++++++ lib/threefold/models_ledger/account.v | 57 +++- lib/threefold/models_ledger/accountpolicy.v | 154 ----------- lib/threefold/models_ledger/asset.v | 3 +- 4 files changed, 341 insertions(+), 161 deletions(-) create mode 100644 lib/heromodels/location.v diff --git a/lib/heromodels/location.v b/lib/heromodels/location.v new file mode 100644 index 00000000..fbd68057 --- /dev/null +++ b/lib/heromodels/location.v @@ -0,0 +1,288 @@ +module heromodels + +import freeflowuniverse.herolib.data.encoder +import freeflowuniverse.herolib.data.ourtime +import freeflowuniverse.herolib.hero.db + +// Address represents a physical address +@[heap] +pub struct Address { +pub mut: + street string + city string + state string // Optional state/province + postal_code string + country string + company string // Optional company name +} + +// Location represents a location entity that can contain multiple addresses +@[heap] +pub struct Location { + db.Base +pub mut: + addresses []Address // Multiple addresses (home, work, etc.) + coordinates Coordinates // GPS coordinates + timezone string + is_verified bool + location_type LocationType +} + +// Coordinates represents GPS coordinates +@[heap] +pub struct Coordinates { +pub mut: + latitude f64 + longitude f64 + altitude f64 // Optional altitude in meters +} + +// LocationType represents different types of locations +pub enum LocationType { + home + work + business + delivery + billing + shipping + other +} + +pub struct DBLocation { +pub mut: + db &db.DB @[skip; str: skip] +} + +pub fn (self Location) type_name() string { + return 'location' +} + +// return example rpc call and result for each methodname +pub fn (self Location) description(methodname string) string { + match methodname { + 'set' { + return 'Create or update a location. Returns the ID of the location.' + } + 'get' { + return 'Retrieve a location by ID. Returns the location object.' + } + 'delete' { + return 'Delete a location by ID. Returns true if successful.' + } + 'exist' { + return 'Check if a location exists by ID. Returns true or false.' + } + 'list' { + return 'List all locations. Returns an array of location objects.' + } + else { + return 'This is generic method for the root object, TODO fill in, ...' + } + } +} + +// return example rpc call and result for each methodname +pub fn (self Location) example(methodname string) (string, string) { + match methodname { + 'set' { + return '{"location": {"name": "Home Address", "description": "Primary residence", "addresses": [{"street": "123 Main St", "city": "Anytown", "state": "CA", "postal_code": "12345", "country": "USA", "company": ""}], "coordinates": {"latitude": 37.7749, "longitude": -122.4194, "altitude": 0}, "timezone": "America/Los_Angeles", "is_verified": true, "location_type": "home"}}', '1' + } + 'get' { + return '{"id": 1}', '{"name": "Home Address", "description": "Primary residence", "addresses": [{"street": "123 Main St", "city": "Anytown", "state": "CA", "postal_code": "12345", "country": "USA", "company": ""}], "coordinates": {"latitude": 37.7749, "longitude": -122.4194, "altitude": 0}, "timezone": "America/Los_Angeles", "is_verified": true, "location_type": "home"}' + } + 'delete' { + return '{"id": 1}', 'true' + } + 'exist' { + return '{"id": 1}', 'true' + } + 'list' { + return '{}', '[{"name": "Home Address", "description": "Primary residence", "addresses": [{"street": "123 Main St", "city": "Anytown", "state": "CA", "postal_code": "12345", "country": "USA", "company": ""}], "coordinates": {"latitude": 37.7749, "longitude": -122.4194, "altitude": 0}, "timezone": "America/Los_Angeles", "is_verified": true, "location_type": "home"}]' + } + else { + return '{}', '{}' + } + } +} + +pub fn (self Address) dump(mut e encoder.Encoder) ! { + e.add_string(self.street) + e.add_string(self.city) + e.add_string(self.state) + e.add_string(self.postal_code) + e.add_string(self.country) + e.add_string(self.company) +} + +fn (mut self Address) load(mut e encoder.Decoder) ! { + self.street = e.get_string()! + self.city = e.get_string()! + self.state = e.get_string()! + self.postal_code = e.get_string()! + self.country = e.get_string()! + self.company = e.get_string()! +} + +pub fn (self Coordinates) dump(mut e encoder.Encoder) ! { + e.add_f64(self.latitude) + e.add_f64(self.longitude) + e.add_f64(self.altitude) +} + +fn (mut self Coordinates) load(mut e encoder.Decoder) ! { + self.latitude = e.get_f64()! + self.longitude = e.get_f64()! + self.altitude = e.get_f64()! +} + +pub fn (self Location) dump(mut e encoder.Encoder) ! { + // Encode addresses + e.add_u32(u32(self.addresses.len)) + for addr in self.addresses { + addr.dump(mut e)! + } + + // Encode coordinates + self.coordinates.dump(mut e)! + + // Encode other fields + e.add_string(self.timezone) + e.add_bool(self.is_verified) + e.add_u8(u8(self.location_type)) +} + +fn (mut self DBLocation) load(mut o Location, mut e encoder.Decoder) ! { + // Decode addresses + addr_count := e.get_u32()! + o.addresses = []Address{cap: int(addr_count)} + for _ in 0..addr_count { + mut addr := Address{} + addr.load(mut e)! + o.addresses << addr + } + + // Decode coordinates + o.coordinates.load(mut e)! + + // Decode other fields + o.timezone = e.get_string()! + o.is_verified = e.get_bool()! + o.location_type = LocationType(e.get_u8()!) +} + +@[params] +pub struct LocationArg { +pub mut: + name string + description string + addresses []Address + coordinates Coordinates + timezone string + is_verified bool + location_type LocationType +} + +@[params] +pub struct AddressArg { +pub mut: + street string + city string + state string + postal_code string + country string + company string +} + +@[params] +pub struct CoordinatesArg { +pub mut: + latitude f64 + longitude f64 + altitude f64 +} + +// Helper function to create a new address +pub fn new_address(args AddressArg) Address { + return Address{ + street: args.street + city: args.city + state: args.state + postal_code: args.postal_code + country: args.country + company: args.company + } +} + +// Helper function to create new coordinates +pub fn new_coordinates(args CoordinatesArg) Coordinates { + return Coordinates{ + latitude: args.latitude + longitude: args.longitude + altitude: args.altitude + } +} + +// get new location, not from the DB +pub fn (mut self DBLocation) new(args LocationArg) !Location { + mut o := Location{ + addresses: args.addresses + coordinates: args.coordinates + timezone: args.timezone + is_verified: args.is_verified + location_type: args.location_type + } + + // Set base fields + o.name = args.name + o.description = args.description + o.updated_at = ourtime.now().unix() + + return o +} + +pub fn (mut self DBLocation) set(o Location) !Location { + // Use db set function which returns the object with assigned ID + return self.db.set[Location](o)! +} + +pub fn (mut self DBLocation) delete(id u32) ! { + self.db.delete[Location](id)! +} + +pub fn (mut self DBLocation) exist(id u32) !bool { + return self.db.exists[Location](id)! +} + +pub fn (mut self DBLocation) get(id u32) !Location { + mut o, data := self.db.get_data[Location](id)! + mut e_decoder := encoder.decoder_new(data) + self.load(mut o, mut e_decoder)! + return o +} + +pub fn (mut self DBLocation) list() ![]Location { + return self.db.list[Location]()!.map(self.get(it)!) +} + +// Helper method to add an address to a location +pub fn (mut self Location) add_address(address Address) { + self.addresses << address +} + +// Helper method to get the primary address (first address) +pub fn (self Location) primary_address() ?Address { + if self.addresses.len > 0 { + return self.addresses[0] + } + return none +} + +// Helper method to format coordinates as string +pub fn (self Coordinates) to_string() string { + return '${self.latitude}, ${self.longitude}' +} + +// Helper method to check if coordinates are set +pub fn (self Coordinates) is_valid() bool { + return self.latitude != 0.0 || self.longitude != 0.0 +} \ No newline at end of file diff --git a/lib/threefold/models_ledger/account.v b/lib/threefold/models_ledger/account.v index 978f2909..120a4557 100644 --- a/lib/threefold/models_ledger/account.v +++ b/lib/threefold/models_ledger/account.v @@ -18,16 +18,63 @@ pub enum AccountStatus { pub struct Account { db.Base pub mut: - owner_id u32 - address string @[index] - balance f64 - currency string + owner_id u32 //link to user + location_id u32 //link to location, 0 is none + accountpolicies []AccountPolicy + assets []AccountAsset assetid u32 last_activity u64 administrators []u32 - accountpolicy u32 } +// AccountPolicy represents a set of rules for an account + +pub struct AccountPolicy { +pub mut: + policy_id u32 @[index] + admins []u32 //people who can transfer money out + min_signatures u8 //nr of people who need to sign + limits + whitelist_out []u32 //where money can go to + whitelist_in []u32 //where money can come from + lock_till u64 //date in epoch till no money can be transfered, only after + admin_lock_type LockType + admin_lock_till u64 //date in epoch when admin can unlock (0 means its free), this is unlock for changing this policy + admin_unlock []u32 //users who can unlock the admin policy + admin_unlock_min_signature u8 //nr of signatures from the adminunlock +} + +pub enum LockType{ + locked_till + locked + free +} + +pub struct AccountLimit { +pub mut: + amount f64 + asset_id u32 + period AccountLimitPeriodLimit +} + + +pub enum AccountLimitPeriodLimit{ + daily + weekly + monthly +} + + +pub struct AccountAsset { + db.Base +pub mut: + assetid u32 + balance f64 + metadata map[string]string +} + + + pub struct DBAccount { pub mut: db &db.DB @[skip; str: skip] diff --git a/lib/threefold/models_ledger/accountpolicy.v b/lib/threefold/models_ledger/accountpolicy.v index 844f4bdd..0fe251b9 100644 --- a/lib/threefold/models_ledger/accountpolicy.v +++ b/lib/threefold/models_ledger/accountpolicy.v @@ -4,157 +4,3 @@ import freeflowuniverse.herolib.data.encoder import freeflowuniverse.herolib.data.ourtime import freeflowuniverse.herolib.hero.db -// AccountPolicy represents a set of rules for an account -@[heap] -pub struct AccountPolicy { - db.Base -pub mut: - policy_id u32 @[index] - min_signatures u32 - max_tx_amount f64 - daily_limit f64 - whitelist []u32 - blacklist []u32 - require_2fa bool - lockout_period u64 - is_multisig bool -} - -pub struct DBAccountPolicy { -pub mut: - db &db.DB @[skip; str: skip] -} - - -pub fn (self AccountPolicy) type_name() string { - return 'accountpolicy' -} - -pub fn (self AccountPolicy) description(methodname string) string { - match methodname { - 'set' { - return 'Create or update an account policy. Returns the ID of the policy.' - } - 'get' { - return 'Retrieve an account policy by ID. Returns the policy object.' - } - 'delete' { - return 'Delete an account policy by ID. Returns true if successful.' - } - 'exist' { - return 'Check if an account policy exists by ID. Returns true or false.' - } - 'list' { - return 'List all account policies. Returns an array of policy objects.' - } - else { - return 'Account policy management operations' - } - } -} - -pub fn (self AccountPolicy) example(methodname string) (string, string) { - match methodname { - 'set' { - return '{"accountpolicy": {"policy_id": 1, "min_signatures": 2, "max_tx_amount": 10000.0, "daily_limit": 50000.0, "is_multisig": true}}', '1' - } - 'get' { - return '{"id": 1}', '{"policy_id": 1, "min_signatures": 2, "is_multisig": true}' - } - 'delete' { - return '{"id": 1}', 'true' - } - 'exist' { - return '{"id": 1}', 'true' - } - 'list' { - return '{}', '[{"policy_id": 1, "min_signatures": 2, "is_multisig": true}]' - } - else { - return '{}', '{}' - } - } -} - -pub fn (self AccountPolicy) dump(mut e encoder.Encoder) ! { - e.add_u32(self.policy_id) - e.add_u32(self.min_signatures) - e.add_f64(self.max_tx_amount) - e.add_f64(self.daily_limit) - e.add_list_u32(self.whitelist) - e.add_list_u32(self.blacklist) - e.add_bool(self.require_2fa) - e.add_u64(self.lockout_period) - e.add_bool(self.is_multisig) -} - -fn (mut self DBAccountPolicy) load(mut o AccountPolicy, mut e encoder.Decoder) ! { - o.policy_id = e.get_u32()! - o.min_signatures = e.get_u32()! - o.max_tx_amount = e.get_f64()! - o.daily_limit = e.get_f64()! - o.whitelist = e.get_list_u32()! - o.blacklist = e.get_list_u32()! - o.require_2fa = e.get_bool()! - o.lockout_period = e.get_u64()! - o.is_multisig = e.get_bool()! -} - -@[params] -pub struct AccountPolicyArg { -pub mut: - name string - description string - policy_id u32 - min_signatures u32 - max_tx_amount f64 - daily_limit f64 - whitelist []u32 - blacklist []u32 - require_2fa bool - lockout_period u64 - is_multisig bool -} - -pub fn (mut self DBAccountPolicy) new(args AccountPolicyArg) !AccountPolicy { - mut o := AccountPolicy{ - policy_id: args.policy_id - min_signatures: args.min_signatures - max_tx_amount: args.max_tx_amount - daily_limit: args.daily_limit - whitelist: args.whitelist - blacklist: args.blacklist - require_2fa: args.require_2fa - lockout_period: args.lockout_period - is_multisig: args.is_multisig - } - - o.name = args.name - o.description = args.description - o.updated_at = ourtime.now().unix() - - return o -} - -pub fn (mut self DBAccountPolicy) set(o AccountPolicy) !AccountPolicy { - return self.db.set[AccountPolicy](o)! -}_ - -pub fn (mut self DBAccountPolicy) delete(id u32) ! { - self.db.delete[AccountPolicy](id)! -} - -pub fn (mut self DBAccountPolicy) exist(id u32) !bool { - return self.db.exists[AccountPolicy](id)! -} - -pub fn (mut self DBAccountPolicy) get(id u32) !AccountPolicy { - mut o, data := self.db.get_data[AccountPolicy](id)! - mut e_decoder := encoder.decoder_new(data) - self.load(mut o, mut e_decoder)! - return o -} - -pub fn (mut self DBAccountPolicy) list() ![]AccountPolicy { - return self.db.list[AccountPolicy]()!.map(self.get(it)!) -} \ No newline at end of file diff --git a/lib/threefold/models_ledger/asset.v b/lib/threefold/models_ledger/asset.v index 87e8238e..06b4a0e9 100644 --- a/lib/threefold/models_ledger/asset.v +++ b/lib/threefold/models_ledger/asset.v @@ -11,9 +11,8 @@ pub struct Asset { db.Base pub mut: address string @[index] - assetid u32 asset_type string - issuer u32 + issuer u32 //link to a user supply f64 decimals u8 is_frozen bool