From fe32c526eb9b62ce30eae10e4ed610ebeb59ce9a Mon Sep 17 00:00:00 2001 From: didier amyot Date: Fri, 7 Apr 2023 09:58:22 -0400 Subject: [PATCH] More things before going to fix my backyard. --- .../migrations/sql/create_tables_001.sql | 1 + resources/templates/accounts.html | 2 + resources/templates/actions.html | 3 +- resources/templates/components/navbar.html | 2 +- .../partials/actions/create_account.html | 10 ++ .../actions/create_wire_transfer.html | 50 ++++++ .../templates/{overview.html => users.html} | 2 +- src/db/_accounts.rs | 39 +++-- src/db/_test_utils.rs | 2 + src/event_processor.rs | 4 +- src/events.rs | 1 + src/services/_accounts.rs | 4 +- src/services/_transactions.rs | 142 ++++++++++++------ src/webui/mod.rs | 2 +- src/webui/views.rs | 6 +- 15 files changed, 199 insertions(+), 71 deletions(-) create mode 100644 resources/templates/partials/actions/create_wire_transfer.html rename resources/templates/{overview.html => users.html} (90%) diff --git a/resources/migrations/sql/create_tables_001.sql b/resources/migrations/sql/create_tables_001.sql index ef951c3..3ad3b52 100644 --- a/resources/migrations/sql/create_tables_001.sql +++ b/resources/migrations/sql/create_tables_001.sql @@ -53,6 +53,7 @@ CREATE TABLE IF NOT EXISTS accounts version INTEGER NOT NULL CHECK ( version >= 0 ), security INTEGER NOT NULL, account_type TEXT NOT NULL, + label TEXT NOT NULL, amount INTEGER NOT NULL, timestamp DATETIME NOT NULL, diff --git a/resources/templates/accounts.html b/resources/templates/accounts.html index 5f5feb1..486d6c1 100644 --- a/resources/templates/accounts.html +++ b/resources/templates/accounts.html @@ -9,6 +9,7 @@ id + Label Amount Account Type Last Update @@ -21,6 +22,7 @@ {{ account.id }} + {{ account.label }} {{ account.amount }} {{ account.account_type | replace("_", " ") | lower}} {{ account.last_update }} diff --git a/resources/templates/actions.html b/resources/templates/actions.html index 7793d9e..d5dd277 100644 --- a/resources/templates/actions.html +++ b/resources/templates/actions.html @@ -8,7 +8,7 @@
- Create new item +
diff --git a/resources/templates/components/navbar.html b/resources/templates/components/navbar.html index ce1d57a..4fbc982 100644 --- a/resources/templates/components/navbar.html +++ b/resources/templates/components/navbar.html @@ -5,7 +5,7 @@ Ledger
    - {% set nav_bar_items = [{'id': 'overview', 'label': 'Overview'}, + {% set nav_bar_items = [{'id': 'users', 'label': 'Users'}, {'id': 'accounts', 'label': 'Accounts'}, {'id': 'securities', 'label': 'Securities'}, {'id': 'actions', 'label': 'Actions'}]%} diff --git a/resources/templates/partials/actions/create_account.html b/resources/templates/partials/actions/create_account.html index facbbc2..8f41f3d 100644 --- a/resources/templates/partials/actions/create_account.html +++ b/resources/templates/partials/actions/create_account.html @@ -6,7 +6,17 @@ {% endfor %} + + +
    +
    diff --git a/resources/templates/partials/actions/create_wire_transfer.html b/resources/templates/partials/actions/create_wire_transfer.html new file mode 100644 index 0000000..b552c02 --- /dev/null +++ b/resources/templates/partials/actions/create_wire_transfer.html @@ -0,0 +1,50 @@ + + + + +
    + +
    + + +
    + +
    + + + +
    + +
    + +{%include "partials/actions/submit_button.html"%} diff --git a/resources/templates/overview.html b/resources/templates/users.html similarity index 90% rename from resources/templates/overview.html rename to resources/templates/users.html index c087b7f..536bde8 100644 --- a/resources/templates/overview.html +++ b/resources/templates/users.html @@ -1,4 +1,4 @@ -{% set active_navbar_item = 'overview' %} +{% set active_navbar_item = 'users' %} {% extends "base.html" %} diff --git a/src/db/_accounts.rs b/src/db/_accounts.rs index 0a6a095..69303ed 100644 --- a/src/db/_accounts.rs +++ b/src/db/_accounts.rs @@ -56,6 +56,7 @@ pub struct Account { timestamp: i64, security: Security, account_type: AccountType, + label: String, } impl Account { @@ -70,6 +71,7 @@ impl Account { timestamp: row.get("acc_timestamp")?, security: Security::from_row(row)?, account_type: AccountType::from_row(row)?, + label: row.get("acc_label")?, }); } @@ -89,6 +91,10 @@ impl Account { pub fn account_type(&self) -> &AccountType { &self.account_type } + + pub fn label(&self) -> &str { + &self.label + } } #[derive(Debug)] @@ -144,6 +150,7 @@ pub fn list_accounts<'a>(conn: &Connection) -> CustomResult> { acc.amount AS acc_amount, UNIXEPOCH(acc.timestamp) AS acc_timestamp, account_type AS acc_account_type, + label AS acc_label, sec.id AS sec_id, sec.symbol AS sec_symbol, @@ -167,6 +174,7 @@ pub fn list_user_accounts(conn: &Connection, user_id: & UserId) -> CustomResult< acc.amount AS acc_amount, UNIXEPOCH(acc.timestamp) AS acc_timestamp, account_type AS acc_account_type, + label AS acc_label, sec.id AS sec_id, sec.symbol AS sec_symbol, @@ -192,6 +200,7 @@ pub fn get_account_by_id(tx: &Connection, id: &AccountId) -> CustomResult acc.amount AS acc_amount, UNIXEPOCH(acc.timestamp) AS acc_timestamp, account_type AS acc_account_type, + label AS acc_label, sec.id AS sec_id, sec.symbol AS sec_symbol, @@ -235,14 +245,15 @@ fn create_account( sec: &SecurityId, user: &UserId, account_type: AccountType, + label: &String, ) -> CustomResult { - let q = "INSERT INTO accounts(security, version, amount, timestamp, account_type) - VALUES (?1, 0, 0, CURRENT_TIMESTAMP, ?2)"; + let q = "INSERT INTO accounts(security, version, amount, timestamp, account_type, label) + VALUES (?1, 0, 0, CURRENT_TIMESTAMP, ?2, ?3)"; let account_type = match account_type { AccountType::Checking => "checking", AccountType::SecurityEmitter => "security_emitter", }; - tx.execute(q, (sec, account_type)) + tx.execute(q, (sec, account_type, label)) .map_err(Error::SqlError)?; let id = AccountId::from_id(tx.last_insert_rowid() as i64); @@ -277,16 +288,18 @@ pub fn create_checking_account( tx: &Connection, sec: &SecurityId, user: &UserId, + label: &String, ) -> CustomResult { - create_account(tx, sec, user, AccountType::Checking) + create_account(tx, sec, user, AccountType::Checking, label) } pub fn create_security_emitter_account( tx: &Connection, sec: &SecurityId, user: &UserId, + label: &String, ) -> CustomResult { - create_account(tx, sec, user, AccountType::SecurityEmitter) + create_account(tx, sec, user, AccountType::SecurityEmitter, label) } pub fn is_owner(tx: &Connection, account_id: &AccountId, user_id: &UserId) -> CustomResult { @@ -392,7 +405,8 @@ mod test_accounts { let mut ret: Vec = Vec::new(); for sec in secs.iter() { for user in users.iter() { - ret.push(create_checking_account(&tx, &sec.id(), &user.id())?); + let label = &format!("Account for {:} in {:}", user.id(), sec.id()); + ret.push(create_checking_account(&tx, &sec.id(), &user.id(), label)?); } } return Ok(ret); @@ -418,7 +432,10 @@ mod test_accounts { let sec = secs.get(0).unwrap(); let tx = conn.transaction().unwrap(); - let acc = create_checking_account(&tx, &sec.id(), &user.id())?; + let acc = create_checking_account(&tx, + &sec.id(), + &user.id(), + &format!("Account for {:} in {:}", sec.id(), user.id()))?; assert_eq!(acc.account_type, AccountType::Checking); assert_eq!(0, acc.raw_amount()); @@ -437,7 +454,7 @@ mod test_accounts { let sec = secs.get(0).unwrap(); let tx = conn.transaction().unwrap(); - let acc = create_security_emitter_account(&tx, &sec.id(), &user.id())?; + let acc = create_security_emitter_account(&tx, &sec.id(), &user.id(), &"acc".to_string())?; assert_eq!(acc.account_type, AccountType::SecurityEmitter); assert_eq!(0, acc.raw_amount()); @@ -476,7 +493,7 @@ mod test_accounts { let user_2 = users.get(1).unwrap(); let sec = secs.get(0).unwrap(); - let acc = create_checking_account(&tx, &sec.id(), &user_1.id())?; + let acc = create_checking_account(&tx, &sec.id(), &user_1.id(), &"acc".to_string())?; assert!(is_owner(tx, &acc.id(), &user_1.id())?); assert!(!is_owner(tx, &acc.id(), &user_2.id())?); @@ -490,7 +507,7 @@ mod test_accounts { let tx = conn.transaction().unwrap(); let sec = secs.get(0).unwrap().id(); let user = users.get(0).unwrap().id(); - let acc = create_checking_account(&tx, &sec, &user).unwrap(); + let acc = create_checking_account(&tx, &sec, &user, & "acc".to_string()).unwrap(); let receipt = add_to_account(&tx, &acc.id(), 33)?; assert_eq!(receipt.account_id, acc.id()); assert_eq!(receipt.amount, 33); @@ -514,7 +531,7 @@ mod test_accounts { let tx = conn.transaction().unwrap(); let sec = secs.get(0).unwrap().id(); let user = users.get(0).unwrap().id(); - let acc = create_security_emitter_account(&tx, &sec, &user)?; + let acc = create_security_emitter_account(&tx, &sec, &user, & "acc".to_string())?; let receipt = add_to_account(&tx, &acc.id(), -33)?; assert_eq!(receipt.account_id, acc.id()); diff --git a/src/db/_test_utils.rs b/src/db/_test_utils.rs index debdbb9..953a393 100644 --- a/src/db/_test_utils.rs +++ b/src/db/_test_utils.rs @@ -51,11 +51,13 @@ pub fn setup_basic_environment( tx, &securities.get(0).unwrap().id(), &users.get(0).unwrap().id(), + &"acc1".to_string() )?; let acc2 = create_checking_account( tx, &securities.get(1).unwrap().id(), &users.get(1).unwrap().id(), + &"acc2".to_string() )?; Ok((users, securities, vec![acc1, acc2])) } diff --git a/src/event_processor.rs b/src/event_processor.rs index 2954e78..d26b871 100644 --- a/src/event_processor.rs +++ b/src/event_processor.rs @@ -15,7 +15,7 @@ fn process_create_new_security_event( ) -> CustomResult<()> { let r = event.to_create_new_security().unwrap(); let sec = create_security(tx, &r)?; - create_security_emitter_account(&tx, &sec.id(), &event.user_id)?; + create_security_emitter_account(&tx, &sec.id(), &event.user_id, & "acc".to_string())?; Ok(()) } @@ -25,7 +25,7 @@ fn process_create_new_user_event(tx: &mut Transaction, event: CreateNewUser) -> } fn process_create_new_account_event(tx: &mut Transaction, event: CreateNewAccount) -> CustomResult<()> { - create_checking_account(&tx, &event.securityId, &event.userId)?; + create_checking_account(&tx, &event.securityId, &event.userId, &event.label)?; Ok(()) } diff --git a/src/events.rs b/src/events.rs index 1013b0e..66003d7 100644 --- a/src/events.rs +++ b/src/events.rs @@ -42,6 +42,7 @@ pub struct CreateNewUser { pub struct CreateNewAccount { pub securityId: SecurityId, pub userId: UserId, + pub label: String, } #[derive(Deserialize, Serialize, Debug)] diff --git a/src/services/_accounts.rs b/src/services/_accounts.rs index d9fa84f..75435df 100644 --- a/src/services/_accounts.rs +++ b/src/services/_accounts.rs @@ -18,6 +18,7 @@ pub struct AccountDTO { pub account_type: String, pub last_update: i64, pub security: SecurityDTO, + pub label: String, } impl AccountDTO { @@ -27,7 +28,8 @@ impl AccountDTO { amount: account.amount(), account_type: account.account_type().to_string(), last_update: account.timestamp(), - security: SecurityDTO::from_entity(account.security()) + security: SecurityDTO::from_entity(account.security()), + label: account.label().to_string(), } } } diff --git a/src/services/_transactions.rs b/src/services/_transactions.rs index 5772ba7..54509a2 100644 --- a/src/services/_transactions.rs +++ b/src/services/_transactions.rs @@ -28,11 +28,9 @@ fn _transfer_securities_from_one_account_to_another( if drawer_receipt.security_id != drawer_receipt.security_id { let m = format!( "Incompatible security type between accounts {:} (drawer) and {:} (payee).", - drawer_account_id, - payee_account_id + drawer_account_id, payee_account_id ); return Err(Error::InvalidAmount(m)); - } Ok((drawer_receipt, payee_receipt)) } @@ -45,11 +43,14 @@ fn _transfer_cheque_securities( accounts::AccountChangeReceipt, accounts::AccountChangeReceipt, )> { - _transfer_securities_from_one_account_to_another(tx, &cheque.drawer_account_id, account_id, cheque.amount) + _transfer_securities_from_one_account_to_another( + tx, + &cheque.drawer_account_id, + account_id, + cheque.amount, + ) } - - fn _transfer_wire_transfer_securities( tx: &Savepoint, wire_transfer_request: &WireTransferRequest, @@ -57,16 +58,20 @@ fn _transfer_wire_transfer_securities( accounts::AccountChangeReceipt, accounts::AccountChangeReceipt, )> { - _transfer_securities_from_one_account_to_another(tx, - &wire_transfer_request.drawer_account_id, - &wire_transfer_request.payee_account_id, - wire_transfer_request.amount) + _transfer_securities_from_one_account_to_another( + tx, + &wire_transfer_request.drawer_account_id, + &wire_transfer_request.payee_account_id, + wire_transfer_request.amount, + ) } -fn _add_wire_transfer_request_to_wire_transfers_log(tx: &Connection, - cheque: &WireTransferRequest, - drawer_receipt: &accounts::AccountChangeReceipt, - payee_receipt: &accounts::AccountChangeReceipt) -> Result<(), Error> { +fn _add_wire_transfer_request_to_wire_transfers_log( + tx: &Connection, + cheque: &WireTransferRequest, + drawer_receipt: &accounts::AccountChangeReceipt, + payee_receipt: &accounts::AccountChangeReceipt, +) -> Result<(), Error> { let q = " INSERT INTO cached_wire_transfers( drawer_account_id, @@ -92,12 +97,12 @@ fn _add_wire_transfer_request_to_wire_transfers_log(tx: &Connection, match ret { Ok(_) => Ok(()), Err(Error::SqlError(rusqlite::Error::SqliteFailure( - ffi::Error { - code: _, - extended_code: 2067, - }, - _, - ))) => Err(Error::DoubleSpendingError(format!( + ffi::Error { + code: _, + extended_code: 2067, + }, + _, + ))) => Err(Error::DoubleSpendingError(format!( "Wire transfer number {} has already been cached.", cheque.amount ))), @@ -183,23 +188,28 @@ fn cash_cheque_unsafe( ))); } - let drawer_account_sec = accounts::get_account_by_id(&savepoint, &cheque.drawer_account_id)?.security().id(); - if drawer_account_sec != cheque.security_id{ + let drawer_account_sec = accounts::get_account_by_id(&savepoint, &cheque.drawer_account_id)? + .security() + .id(); + if drawer_account_sec != cheque.security_id { return Err(Error::InvalidDrawer(format!( "Impossible to use an account containing {:} to emit a cheque in {:}", drawer_account_sec, cheque.security_id ))); } - let payee_account_sec = accounts::get_account_by_id(&savepoint, &payee_account_id)?.security().id(); - if payee_account_sec != cheque.security_id{ + let payee_account_sec = accounts::get_account_by_id(&savepoint, &payee_account_id)? + .security() + .id(); + if payee_account_sec != cheque.security_id { return Err(Error::InvalidPayee(format!( "Impossible to cache a {:} cheque in {:} account .", cheque.security_id, payee_account_sec ))); } - let (drawer_receipt, payee_receipt) = _transfer_cheque_securities(&savepoint, cheque, payee_account_id)?; + let (drawer_receipt, payee_receipt) = + _transfer_cheque_securities(&savepoint, cheque, payee_account_id)?; _add_cheque_to_cashed_cheques_log(&savepoint, cheque, &drawer_receipt, &payee_receipt)?; Ok(()) } @@ -214,8 +224,14 @@ fn cash_wire_transfer_request_unsafe( // wire_transfer // ))); // } - let (drawer_receipt, payee_receipt) = _transfer_wire_transfer_securities(&savepoint, wire_transfer)?; - _add_wire_transfer_request_to_wire_transfers_log(&savepoint, wire_transfer, &drawer_receipt, &payee_receipt)?; + let (drawer_receipt, payee_receipt) = + _transfer_wire_transfer_securities(&savepoint, wire_transfer)?; + _add_wire_transfer_request_to_wire_transfers_log( + &savepoint, + wire_transfer, + &drawer_receipt, + &payee_receipt, + )?; Ok(()) } @@ -240,7 +256,7 @@ pub fn cash_wire_transfer_request( wire_transfer: &WireTransferRequest, ) -> CustomResult<()> { let mut savepoint = tx.savepoint().map_err(Error::SqlError)?; - let ret = cash_wire_transfer_request_unsafe(& savepoint, wire_transfer); + let ret = cash_wire_transfer_request_unsafe(&savepoint, wire_transfer); match ret { Err(_) => { savepoint.rollback().map_err(Error::SqlError)?; @@ -277,9 +293,16 @@ mod test_utils { let sec = securities.get(0).unwrap(); let drawer = users.get(0).unwrap(); let payee = users.get(1).unwrap(); - let security_emitter_account = - create_security_emitter_account(&tx, &sec.id(), &drawer.id()).unwrap(); - let payee_account = create_checking_account(&tx, &sec.id(), &payee.id()).unwrap(); + let security_emitter_account = create_security_emitter_account( + &tx, + &sec.id(), + &drawer.id(), + &"sec emitter".to_string(), + ) + .unwrap(); + let payee_account = + create_checking_account(&tx, &sec.id(), &payee.id(), &"checking account".to_string()) + .unwrap(); tx.commit().unwrap(); let security_emitter: Drawer = (drawer.id(), security_emitter_account.id(), sec.id()); @@ -295,15 +318,21 @@ mod test_utils { let sec_2 = securities.get(1).unwrap(); let drawer = users.get(0).unwrap(); let payee = users.get(1).unwrap(); - let security_emitter_account = - create_security_emitter_account(&tx, &sec_1.id(), &drawer.id()).unwrap(); - let payee_account = create_checking_account(&tx, &sec_2.id(), &payee.id()).unwrap(); + let security_emitter_account = create_security_emitter_account( + &tx, + &sec_1.id(), + &drawer.id(), + &"sec emitter account".to_string(), + ) + .unwrap(); + let payee_account = + create_checking_account(&tx, &sec_2.id(), &payee.id(), &"payee account".to_string()) + .unwrap(); tx.commit().unwrap(); let security_emitter: Drawer = (drawer.id(), security_emitter_account.id(), sec_1.id()); let payee: Payee = (payee.id(), sec_1.id()); (conn, security_emitter, payee, payee_account.id()) - } pub fn create_100_security_units_in_payee_account( @@ -326,9 +355,19 @@ mod test_utils { let mut tx = conn.transaction().unwrap(); - create_100_security_units_in_payee_account(&mut tx, &security_emitter, &payee, &payee_account); - let reg_account = - create_checking_account(&tx, &security_emitter.2, &security_emitter.0).unwrap(); + create_100_security_units_in_payee_account( + &mut tx, + &security_emitter, + &payee, + &payee_account, + ); + let reg_account = create_checking_account( + &tx, + &security_emitter.2, + &security_emitter.0, + &"reg account".to_string(), + ) + .unwrap(); tx.commit().unwrap(); @@ -351,11 +390,12 @@ mod test_caching_cheques { use crate::db::test_utils; use crate::migration; - use super::*; use super::test_utils::*; + use super::*; #[test] - fn test_happy_path_currency_emitter() -> CustomResult<()> { // done + fn test_happy_path_currency_emitter() -> CustomResult<()> { + // done let (mut conn, security_emitter, payee, payee_account) = setup_security_emitter(); let mut tx = conn.transaction().unwrap(); @@ -372,7 +412,8 @@ mod test_caching_cheques { } #[test] - fn test_happy_path_regular_cheque() -> CustomResult<()> { // done + fn test_happy_path_regular_cheque() -> CustomResult<()> { + // done let (mut conn, drawer, payee, payee_account) = setup_basic(); let mut tx = conn.transaction().unwrap(); @@ -531,24 +572,23 @@ mod test_caching_cheques { } #[test] - fn test_mismatch_securities() -> CustomResult<()>{ + fn test_mismatch_securities() -> CustomResult<()> { let (mut conn, drawer, payee, payee_account) = setup_security_emitter_mismatched_accounts(); let cheque = Cheque::new(drawer.clone(), payee.clone(), 1000, 99); let mut tx = conn.transaction().unwrap(); - match cash_cheque(&mut tx, &cheque, & payee_account) { + match cash_cheque(&mut tx, &cheque, &payee_account) { Err(Error::InvalidPayee(_)) => Ok(()), - _ => Err(Error::Testing("Expected invalid payee here.".to_string())) + _ => Err(Error::Testing("Expected invalid payee here.".to_string())), } } } - #[cfg(test)] mod test_wire_transfers { - use crate::db::accounts::get_account_by_id; - use super::*; use super::test_utils::*; + use super::*; + use crate::db::accounts::get_account_by_id; #[test] fn test_happy_path_currency_emitter() -> CustomResult<()> { @@ -556,7 +596,7 @@ mod test_wire_transfers { let mut tx = conn.transaction().unwrap(); // let cheque = Cheque::new(security_emitter, payee, 1000, 99); - let wire_transfer = WireTransferRequest::new(security_emitter, &payee_account, 1000, 777);; + let wire_transfer = WireTransferRequest::new(security_emitter, &payee_account, 1000, 777); cash_wire_transfer_request(&mut tx, &wire_transfer)?; tx.commit().unwrap(); @@ -599,7 +639,9 @@ mod test_wire_transfers { let ret = cash_wire_transfer_request(&mut tx, &wire_transfer); match ret { Err(Error::DoubleSpendingError(_)) => Ok(()), - _ => Err(Error::Testing("Expected DoubleSpendingError error".to_string())) + _ => Err(Error::Testing( + "Expected DoubleSpendingError error".to_string(), + )), } } -} \ No newline at end of file +} diff --git a/src/webui/mod.rs b/src/webui/mod.rs index b87024f..85924c7 100644 --- a/src/webui/mod.rs +++ b/src/webui/mod.rs @@ -70,7 +70,7 @@ fn create_views_scope() -> Scope { .service(views::account) .service(views::securities) .service(views::security) - .service(views::overview) + .service(views::users) .service(views::overview_submit_button) .service(views::actions_partials) .service(views::get_accounts_by_security_selectors) diff --git a/src/webui/views.rs b/src/webui/views.rs index fee1ee2..9347762 100644 --- a/src/webui/views.rs +++ b/src/webui/views.rs @@ -62,8 +62,8 @@ pub async fn security(tmpl_env: MiniJinjaRenderer, tmpl_env.render("security.html", ctx) } -#[actix_web::get("/overview")] -pub async fn overview( +#[actix_web::get("/users")] +pub async fn users( tmpl_env: MiniJinjaRenderer, service_factory: web::Data, ) -> actix_web::Result { @@ -74,7 +74,7 @@ pub async fn overview( let ctx = context! { users => users, }; - tmpl_env.render("overview.html", ctx) + tmpl_env.render("users.html", ctx) } #[actix_web::get("/partials/overview/submit_button")]