From 6294814f6276036888aea7e9f33e422f374c5bac Mon Sep 17 00:00:00 2001 From: didier amyot Date: Thu, 15 Dec 2022 10:11:52 -0500 Subject: [PATCH] I should be working... --- Cargo.lock | 41 +++++++++ Cargo.toml | 5 +- src/db/_cheques.rs | 21 +++++ src/db/_external_id.rs | 151 ++++++++++++++++++++++++++++++++++ src/db/mod.rs | 9 +- src/services/_transactions.rs | 15 +++- 6 files changed, 237 insertions(+), 5 deletions(-) create mode 100644 src/db/_cheques.rs create mode 100644 src/db/_external_id.rs diff --git a/Cargo.lock b/Cargo.lock index 8f3c409..446a052 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,6 +13,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + [[package]] name = "atty" version = "0.2.14" @@ -144,8 +153,11 @@ version = "0.1.0" dependencies = [ "clap", "clap-verbosity-flag", + "hex", "home", + "lazy_static", "log", + "regex", "resource", "rusqlite", "serde", @@ -220,6 +232,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "home" version = "0.5.4" @@ -267,6 +285,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + [[package]] name = "num_threads" version = "0.1.6" @@ -336,6 +360,23 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "regex" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" + [[package]] name = "resource" version = "0.5.0" diff --git a/Cargo.toml b/Cargo.toml index 904fa5b..5276d15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,4 +15,7 @@ log = "0.4.17" home = "0.5.4" sha2 = "0.10.6" serde_json = "1.0" -resource = "0.5.0" \ No newline at end of file +resource = "0.5.0" +hex = "0.4.3" +regex = "1.7.0" +lazy_static = "1.4.0" \ No newline at end of file diff --git a/src/db/_cheques.rs b/src/db/_cheques.rs new file mode 100644 index 0000000..88f470a --- /dev/null +++ b/src/db/_cheques.rs @@ -0,0 +1,21 @@ +use crate::db::_external_id::ExternalId; + +pub struct SecurityEmitterCheque { + drawer_user_id: ExternalId, + security_id: ExternalId, + cheque_number: u32, + amount: u32, +} + +impl Cheque { + pub fn is_valid(self: &Cheque) -> bool { + return true; + } + + + pub fn cash_cheque(&self){ + + } + + +} diff --git a/src/db/_external_id.rs b/src/db/_external_id.rs new file mode 100644 index 0000000..100191a --- /dev/null +++ b/src/db/_external_id.rs @@ -0,0 +1,151 @@ +use std::io::Read; + +use regex::{Captures, Regex}; + + +#[derive(PartialEq, Debug)] +struct SafeId { + encrypted_id: [u8; 4], + signature: [u8; 4], +} + +#[derive(PartialEq, Debug)] +pub enum ExternalId { + AccountId(SafeId), + UserId(SafeId), + SecurityId(SafeId), +} + +impl ToString for SafeId { + fn to_string(&self) -> String { + format!("{}-{}", hex::encode(self.encrypted_id), hex::encode(self.signature)) + } +} + +fn deserialize_str(s: &str) -> Option<[u8; 4]> { + let mut encrypted_id_bytes = [0u8; 4]; + let r = hex::decode_to_slice(s, &mut encrypted_id_bytes as &mut [u8]); + return match r { + Ok(_) => Some(encrypted_id_bytes), + Err(_) => None + }; +} + +impl SafeId { + fn from_regex_captures(caps: &Captures) -> Option { + let encrypted_id = caps.name("id")?; + let signature = caps.name("sign")?; + + Some(SafeId { + encrypted_id: deserialize_str(&encrypted_id.as_str())?, + signature: deserialize_str(&signature.as_str())?, + }) + } + + pub fn from_string(s: &String) -> Option { + let external_id_pattern = Regex::new(r"^(?P\w+)-(?P\w+)$").unwrap(); + let caps = external_id_pattern.captures(&s)?; + return Self::from_regex_captures(&caps); + } + + pub fn from_id(id: u32) -> SafeId { + let bytes = u32::to_be_bytes(id); + SafeId { + encrypted_id: bytes, + signature: bytes, + } + } + + pub fn get_id(&self) -> u32 { + return u32::from_be_bytes(self.encrypted_id); + } +} + + +impl ToString for ExternalId { + fn to_string(&self) -> String { + match self { + ExternalId::UserId(sid) => format!("a-{}", sid.to_string()), + ExternalId::AccountId(sid) => format!("u-{}", sid.to_string()), + ExternalId::SecurityId(sid) => format!("s-{}", sid.to_string()), + } + } +} + + +impl ExternalId { + pub fn from_string(s: &String) -> Option { + let pattern = Regex::new(r"^(?P\w)-(?P\w+)-(?P\w+)$").unwrap(); + let caps = pattern.captures(&s)?; + + match caps.name("type")?.as_str() { + "a" => Some(ExternalId::AccountId(SafeId::from_regex_captures(&caps)?)), + "u" => Some(ExternalId::UserId(SafeId::from_regex_captures(&caps)?)), + "s" => Some(ExternalId::SecurityId(SafeId::from_regex_captures(&caps)?)), + _ => None + } + } + + pub fn get_id(&self) -> u32 { + match self { + ExternalId::UserId(x) => x.get_id(), + ExternalId::AccountId(x) => x.get_id(), + ExternalId::SecurityId(x) => x.get_id(), + } + } +} + + +pub mod test_util { + use std::any::Any; + + use super::*; + + + #[test] + fn safe_id_happy_path_1() { + let sid = SafeId { encrypted_id: [1, 2, 3, 4], signature: [7, 8, 9, 10] }; + assert_eq!("01020304-0708090a".to_string(), sid.to_string()); + let deserialized_eid = SafeId::from_string(&sid.to_string()).unwrap(); + assert_eq!(sid, deserialized_eid); + } + + #[test] + fn safe_id_happy_path_2() { + let sid = SafeId::from_id(56); + assert_eq!("00000038-00000038".to_string(), sid.to_string()); + let deserialized_eid = SafeId::from_string(&sid.to_string()).unwrap(); + assert_eq!(sid, deserialized_eid); + assert_eq!(56, deserialized_eid.get_id()); + } + + #[test] + fn safe_id_un_happy_path() { + let bad_strings = vec!["a", "a-b", "01020304-0708090É"]; + for bad_string in bad_strings.iter() { + let ret = SafeId::from_string(&bad_string.to_string()); + assert!(ret.is_none(), "This should not be a valid safe id: {}", bad_string); + } + } + + #[test] + fn external_id_simple_test() { + let eid = ExternalId::from_string(&"u-01020304-0708090a".to_string()).unwrap(); + assert!(match eid { + ExternalId::UserId(_) => true, + _ => false + }); + + let eid = ExternalId::from_string(&"a-01020304-0708090a".to_string()).unwrap(); + assert!(match eid { + ExternalId::AccountId(_) => true, + _ => false + }); + + let eid = ExternalId::from_string(&"s-01020304-0708090a".to_string()).unwrap(); + assert!(match eid { + ExternalId::SecurityId(_) => true, + _ => false + }); + } +} \ No newline at end of file diff --git a/src/db/mod.rs b/src/db/mod.rs index 675d720..5177021 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -1,16 +1,21 @@ mod _users; mod _securities; mod _accounts; +mod _cheques; +mod _external_id; pub mod securities{ pub use super::_securities::{list_securities, get_security_by_id, Security}; - } -pub mod users{ +pub mod users { pub use super::_users::{create_user, list_users, User}; } pub mod accounts { pub use super::_accounts::{get_account_by_id, list_accounts, create_account, Account}; +} + +pub mod cheques { + pub use super::_cheques::{Cheque}; } \ No newline at end of file diff --git a/src/services/_transactions.rs b/src/services/_transactions.rs index 9980f18..4e757fb 100644 --- a/src/services/_transactions.rs +++ b/src/services/_transactions.rs @@ -1,9 +1,20 @@ use rusqlite::{Transaction, Result}; use crate::db::accounts::get_account_by_id; +use crate::db::cheques::Cheque; use crate::db::securities::get_security_by_id; -fn update_account(tx: & Transaction, account_id: u32) -> Result<()>{ + + +fn cash_cheque(cheque: &Cheque) -> Result<()> { + if !cheque.is_valid() { + + + } + Ok(()) +} + +fn update_account(tx: &Transaction, account_id: u32) -> Result<()> { let account = get_account_by_id(tx, account_id)?; // let sec = get_security_by_id(tx, account.) - return Ok(()) + return Ok(()); } \ No newline at end of file