From 174d7e855ab158d318c1f0dce65c8a806b3ea8b2 Mon Sep 17 00:00:00 2001 From: didier amyot Date: Mon, 30 Jan 2023 08:10:00 -0500 Subject: [PATCH] Linted code. --- flake.nix | 1 + src/db/_accounts.rs | 67 ++++++++---- src/db/_cheques.rs | 5 +- src/db/_external_id.rs | 83 ++++++++++----- src/db/_interests.rs | 1 - src/db/_securities.rs | 12 +-- src/db/_test_utils.rs | 24 +++-- src/db/_users.rs | 18 ++-- src/db/mod.rs | 24 ++--- src/event_processor.rs | 4 +- src/main.rs | 40 +++---- src/migration.rs | 25 +++-- src/services/_transactions.rs | 192 ++++++++++++++++++++-------------- src/services/mod.rs | 2 +- src/webui/mod.rs | 5 +- src/webui/views.rs | 4 +- tools/lint | 3 + 17 files changed, 304 insertions(+), 206 deletions(-) create mode 100755 tools/lint diff --git a/flake.nix b/flake.nix index e6f82b5..b6b9b11 100644 --- a/flake.nix +++ b/flake.nix @@ -45,6 +45,7 @@ RUST_SRC_PATH = rustPlatform.rustLibSrc; shellHook = '' export PROJECT_ROOT=${PROJECT_ROOT}; + export PATH=$PROJECT_ROOT/tools:$PATH; ''; }; }); diff --git a/src/db/_accounts.rs b/src/db/_accounts.rs index 7397d88..c49a16f 100644 --- a/src/db/_accounts.rs +++ b/src/db/_accounts.rs @@ -1,5 +1,5 @@ -use rusqlite::{Connection, OptionalExtension, params, Result, Row, Transaction}; -use fraction::{Fraction}; +use fraction::Fraction; +use rusqlite::{params, Connection, OptionalExtension, Result, Row, Transaction}; use crate::db::_external_id::{AccountId, Id, UserId}; use crate::db::_securities::Security; @@ -100,7 +100,6 @@ impl AccountHistory { } } - pub fn list_accounts<'a>(conn: &Connection) -> CustomResult> { let q = "SELECT acc.id AS acc_id, acc.amount AS acc_amount, @@ -135,17 +134,25 @@ pub fn get_account_by_id(tx: &Connection, id: &AccountId) -> CustomResult CustomResult { +fn create_account( + tx: &Connection, + sec: &SecurityId, + user: &UserId, + account_type: AccountType, +) -> CustomResult { let q = "INSERT INTO accounts(security, version, amount, timestamp, account_type) VALUES (?1, 0, 0, CURRENT_TIMESTAMP, ?2)"; let account_type = match account_type { AccountType::Checking => "checking", AccountType::SecurityEmitter => "security_emitter", }; - tx.execute(q, (sec, account_type)).map_err(Error::SqlError)?; + tx.execute(q, (sec, account_type)) + .map_err(Error::SqlError)?; let id = AccountId::from_id(tx.last_insert_rowid() as i64); let q = "INSERT INTO account_user_permissions(user_id, account_id) @@ -165,7 +172,8 @@ fn get_account_history(tx: &Connection, id: &AccountId) -> CustomResult = stmt.query_map(params![id], AccountSnapshot::from_row) + let snapshots: Vec = stmt + .query_map(params![id], AccountSnapshot::from_row) .map_err(Error::SqlError)? .filter(Result::is_ok) .map(Result::unwrap) @@ -174,11 +182,19 @@ fn get_account_history(tx: &Connection, id: &AccountId) -> CustomResult CustomResult { +pub fn create_checking_account( + tx: &Connection, + sec: &SecurityId, + user: &UserId, +) -> CustomResult { create_account(tx, sec, user, AccountType::Checking) } -pub fn create_security_emitter_account(tx: &Connection, sec: &SecurityId, user: &UserId) -> CustomResult { +pub fn create_security_emitter_account( + tx: &Connection, + sec: &SecurityId, + user: &UserId, +) -> CustomResult { create_account(tx, sec, user, AccountType::SecurityEmitter) } @@ -186,7 +202,10 @@ pub fn is_owner(tx: &Connection, account_id: &AccountId, user_id: &UserId) -> Cu let q = "SELECT id FROM account_user_permissions WHERE account_id = ?1 AND user_id = ?2"; let params = params![account_id, user_id]; let ite = |row: &Row| row.get::(0); - let option = tx.query_row(q, params, ite).optional().map_err(Error::SqlError)?; + let option = tx + .query_row(q, params, ite) + .optional() + .map_err(Error::SqlError)?; Ok(option.is_some()) } @@ -218,13 +237,16 @@ fn update_account_history(tx: &Connection, account_id: &AccountId) -> CustomResu FROM accounts WHERE id = ?1 "; - tx.execute(q, params![account_id]).map_err(Error::SqlError)?; + tx.execute(q, params![account_id]) + .map_err(Error::SqlError)?; Ok(()) } -pub fn add_to_account(tx: &Connection, - account_id: &AccountId, - amount: i64) -> CustomResult { +pub fn add_to_account( + tx: &Connection, + account_id: &AccountId, + amount: i64, +) -> CustomResult { let q = " UPDATE accounts SET amount = CASE account_type WHEN 'security_emitter' @@ -236,7 +258,9 @@ pub fn add_to_account(tx: &Connection, RETURNING id, version, amount, UNIXEPOCH(CURRENT_TIMESTAMP) as timestamp "; let params = params![amount, account_id]; - let ret = tx.query_row(q, params, AccountChangeReceipt::from_row).map_err(Error::SqlError); + let ret = tx + .query_row(q, params, AccountChangeReceipt::from_row) + .map_err(Error::SqlError); update_account_history(tx, account_id)?; return ret; } @@ -261,7 +285,11 @@ mod test_accounts { return (conn, users, securities); } - fn create_all_accounts(tx: &Transaction, users: &Vec, secs: &Vec) -> CustomResult> { + fn create_all_accounts( + tx: &Transaction, + users: &Vec, + secs: &Vec, + ) -> CustomResult> { let mut ret: Vec = Vec::new(); for sec in secs.iter() { for user in users.iter() { @@ -361,8 +389,10 @@ mod test_accounts { let acc = get_account_by_id(&tx2, &acc.id()).unwrap(); assert_eq!(acc.timestamp, receipt.timestamp); assert_eq!(acc.amount, 33); - assert_eq!(get_account_history(&tx2, &acc.id())?.average_amount(), - Fraction::from(0 + 33) / Fraction::from(2)); + assert_eq!( + get_account_history(&tx2, &acc.id())?.average_amount(), + Fraction::from(0 + 33) / Fraction::from(2) + ); Ok(()) } @@ -390,4 +420,3 @@ mod test_accounts { Ok(()) } } - diff --git a/src/db/_cheques.rs b/src/db/_cheques.rs index 7f4d6f0..50d3304 100644 --- a/src/db/_cheques.rs +++ b/src/db/_cheques.rs @@ -14,10 +14,7 @@ pub struct Cheque { } impl Cheque { - pub fn new(drawer: Drawer, - payee: Payee, - amount: i64, - cheque_number: i64) -> Cheque { + pub fn new(drawer: Drawer, payee: Payee, amount: i64, cheque_number: i64) -> Cheque { Cheque { drawer_user_id: drawer.0, drawer_account_id: drawer.1, diff --git a/src/db/_external_id.rs b/src/db/_external_id.rs index b153a41..a9e3ff5 100644 --- a/src/db/_external_id.rs +++ b/src/db/_external_id.rs @@ -8,7 +8,6 @@ struct SafeId { signature: [u8; 8], } - pub trait Id { type Output; fn from_regex_captures(caps: &Captures) -> Option; @@ -19,7 +18,12 @@ pub trait Id { impl fmt::Display for SafeId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}-{}", hex::encode(self.encrypted_id), hex::encode(self.signature)) + write!( + f, + "{}-{}", + hex::encode(self.encrypted_id), + hex::encode(self.signature) + ) } } @@ -55,11 +59,8 @@ impl Id for SafeId { } } - - macro_rules! impl_ids { ($T:ident, $prefix:literal) => { - impl fmt::Display for $T { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}-{}", $prefix, self.0) @@ -78,16 +79,17 @@ macro_rules! impl_ids { fn from_regex_captures(caps: &Captures) -> Option<$T> { let type_ = caps.name("type")?; - if(type_.as_str() != $prefix){ + if (type_.as_str() != $prefix) { return None; } SafeId::from_regex_captures(caps).map(|x| $T(x)) } fn from_string(s: &String) -> Option<$T> { - let external_id_pattern = Regex::new(r"^(?P\w)-(?P\w+)-(?P\w+)$").unwrap(); + let external_id_pattern = + Regex::new(r"^(?P\w)-(?P\w+)-(?P\w+)$").unwrap(); let caps = external_id_pattern.captures(&s)?; - Self::from_regex_captures(& caps) + Self::from_regex_captures(&caps) } fn from_id(id: i64) -> $T { @@ -98,7 +100,7 @@ macro_rules! impl_ids { self.0.get_id() } } - } + }; } #[derive(PartialEq, Debug, Clone)] @@ -121,17 +123,15 @@ pub enum ExternalId { SecurityId(SecurityId), } - fn deserialize_str(s: &str) -> Option<[u8; 8]> { let mut encrypted_id_bytes = [0u8; 8]; let r = hex::decode_to_slice(s, &mut encrypted_id_bytes as &mut [u8]); return match r { Ok(_) => Some(encrypted_id_bytes), - Err(_) => None + Err(_) => None, }; } - impl ToString for ExternalId { fn to_string(&self) -> String { match self { @@ -142,17 +142,20 @@ impl ToString for ExternalId { } } - 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(AccountId::from_regex_captures(&caps)?)), + "a" => Some(ExternalId::AccountId(AccountId::from_regex_captures( + &caps, + )?)), "u" => Some(ExternalId::UserId(UserId::from_regex_captures(&caps)?)), - "s" => Some(ExternalId::SecurityId(SecurityId::from_regex_captures(&caps)?)), - _ => None + "s" => Some(ExternalId::SecurityId(SecurityId::from_regex_captures( + &caps, + )?)), + _ => None, } } @@ -172,16 +175,31 @@ pub mod test_external_ids { #[test] fn test_id_macro() { let id = SecurityId::from_id(33); - assert_eq!(id.to_string(), "s-0000000000000021-0000000000000021".to_string()); - assert!(SecurityId::from_string(&"s-0000000000000021-0000000000000021".to_string()).is_some()); - assert!(SecurityId::from_string(&"u-0000000000000021-0000000000000021".to_string()).is_none()); - assert!(SecurityId::from_string(&"0000000000000021-0000000000000021".to_string()).is_none()); + assert_eq!( + id.to_string(), + "s-0000000000000021-0000000000000021".to_string() + ); + assert!( + SecurityId::from_string(&"s-0000000000000021-0000000000000021".to_string()).is_some() + ); + assert!( + SecurityId::from_string(&"u-0000000000000021-0000000000000021".to_string()).is_none() + ); + assert!( + SecurityId::from_string(&"0000000000000021-0000000000000021".to_string()).is_none() + ); } #[test] fn safe_id_happy_path_1() { - let sid = SafeId { encrypted_id: [1, 2, 3, 4, 5, 6, 7, 8], signature: [8, 7, 6, 5, 4, 3, 2, 1] }; - assert_eq!("0102030405060708-0807060504030201".to_string(), sid.to_string()); + let sid = SafeId { + encrypted_id: [1, 2, 3, 4, 5, 6, 7, 8], + signature: [8, 7, 6, 5, 4, 3, 2, 1], + }; + assert_eq!( + "0102030405060708-0807060504030201".to_string(), + sid.to_string() + ); let deserialized_eid = SafeId::from_string(&sid.to_string()).unwrap(); assert_eq!(sid, deserialized_eid); } @@ -189,7 +207,10 @@ pub mod test_external_ids { #[test] fn safe_id_happy_path_2() { let sid = SafeId::from_id(56); - assert_eq!("0000000000000038-0000000000000038".to_string(), sid.to_string()); + assert_eq!( + "0000000000000038-0000000000000038".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()); @@ -200,32 +221,36 @@ pub mod test_external_ids { 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); + assert!( + ret.is_none(), + "This should not be a valid safe id: {}", + bad_string + ); } } #[test] fn external_id_simple_test() { let base = "0000000000000038-0000000000000038"; - let eid = ExternalId::from_string(& format!("u-{:}", base)).unwrap(); + let eid = ExternalId::from_string(&format!("u-{:}", base)).unwrap(); assert!(match eid { ExternalId::UserId(_) => true, - _ => false + _ => false, }); assert_eq!(eid.to_string(), format!("u-{:}", base)); let eid = ExternalId::from_string(&format!("a-{:}", base)).unwrap(); assert!(match eid { ExternalId::AccountId(_) => true, - _ => false + _ => false, }); assert_eq!(eid.to_string(), format!("a-{:}", base)); let eid = ExternalId::from_string(&format!("s-{:}", base)).unwrap(); assert!(match eid { ExternalId::SecurityId(_) => true, - _ => false + _ => false, }); assert_eq!(eid.to_string(), format!("s-{:}", base)); } -} \ No newline at end of file +} diff --git a/src/db/_interests.rs b/src/db/_interests.rs index 139597f..8b13789 100644 --- a/src/db/_interests.rs +++ b/src/db/_interests.rs @@ -1,2 +1 @@ - diff --git a/src/db/_securities.rs b/src/db/_securities.rs index 8fe67db..6ab7b83 100644 --- a/src/db/_securities.rs +++ b/src/db/_securities.rs @@ -1,4 +1,4 @@ -use rusqlite::{Connection, params, Result, Row, ToSql, Transaction}; +use rusqlite::{params, Connection, Result, Row, ToSql, Transaction}; use serde::Serialize; use crate::db::_external_id::{Id, SecurityId}; @@ -61,8 +61,7 @@ pub struct NewSecurity { pub name: String, } -pub fn create_security(tx: &Transaction, - sec: &NewSecurity) -> Result { +pub fn create_security(tx: &Transaction, sec: &NewSecurity) -> Result { let q = "INSERT INTO securities(name, symbol, security_type) VALUES(?1, ?2, ?3)"; @@ -73,7 +72,6 @@ pub fn create_security(tx: &Transaction, return get_security_by_id(tx, new_sec_id); } - pub fn get_security_by_id(tx: &Transaction, id: i32) -> Result { let q = "SELECT id AS sec_id, security_type AS sec_security_type, symbol AS sec_symbol FROM securities @@ -95,10 +93,9 @@ pub fn list_securities(conn: &Connection) -> Result> { return Ok(ret); } - #[cfg(test)] mod test_securities { - use rusqlite::{Connection, params}; + use rusqlite::{params, Connection}; use crate::db::_test_utils::*; use crate::migration; @@ -160,7 +157,6 @@ mod test_securities { assert_eq!(1, ret.len()); assert_eq!(&expt, ret.get(0).unwrap()); - let sec = mock_currency_2(); let expt = Security { id: 2, @@ -176,4 +172,4 @@ mod test_securities { return Ok(()); } -} \ No newline at end of file +} diff --git a/src/db/_test_utils.rs b/src/db/_test_utils.rs index fc94605..6ddf43b 100644 --- a/src/db/_test_utils.rs +++ b/src/db/_test_utils.rs @@ -1,11 +1,11 @@ use rusqlite::{Result, Transaction}; -use crate::db::{_securities, _users}; use crate::db::_accounts::create_checking_account; use crate::db::_external_id::UserId; use crate::db::_securities::{NewSecurity, Security, SecurityType}; use crate::db::_users::User; use crate::db::accounts::Account; +use crate::db::{_securities, _users}; use crate::util::CustomResult; pub fn mock_currency_1() -> NewSecurity { @@ -42,14 +42,20 @@ pub fn setup_users_and_securities(tx: &Transaction) -> Result<(Vec, Vec CustomResult<(Vec, Vec, Vec)> { +pub fn setup_basic_environment( + tx: &Transaction, +) -> CustomResult<(Vec, Vec, Vec)> { let (users, securities) = setup_users_and_securities(tx).unwrap(); - let acc1 = create_checking_account(tx, - &securities.get(0).unwrap().id(), - &users.get(0).unwrap().id())?; - let acc2 = create_checking_account(tx, - &securities.get(1).unwrap().id(), - &users.get(1).unwrap().id())?; + let acc1 = create_checking_account( + tx, + &securities.get(0).unwrap().id(), + &users.get(0).unwrap().id(), + )?; + let acc2 = create_checking_account( + tx, + &securities.get(1).unwrap().id(), + &users.get(1).unwrap().id(), + )?; Ok((users, securities, vec![acc1, acc2])) -} \ No newline at end of file +} diff --git a/src/db/_users.rs b/src/db/_users.rs index 0481d15..35997cc 100644 --- a/src/db/_users.rs +++ b/src/db/_users.rs @@ -1,7 +1,6 @@ -use rusqlite::{Connection, params, Result, Transaction, Row}; -use serde::{Serialize}; -use crate::db::_external_id::{UserId, Id}; - +use crate::db::_external_id::{Id, UserId}; +use rusqlite::{params, Connection, Result, Row, Transaction}; +use serde::Serialize; #[derive(Debug, Serialize)] pub struct User { @@ -17,8 +16,10 @@ impl User { } pub fn create_user(tx: &Transaction, name: &String, public_key: &String) -> Result { - tx.execute("INSERT INTO users (name, public_key) VALUES (?1, ?2)", - (name, public_key))?; + tx.execute( + "INSERT INTO users (name, public_key) VALUES (?1, ?2)", + (name, public_key), + )?; return get_user_by_id(tx, tx.last_insert_rowid() as i32); } @@ -39,9 +40,10 @@ fn get_user_by_id(tx: &Transaction, id: i32) -> Result { pub fn list_users(conn: &Connection) -> Result> { let mut stmt = conn.prepare("SELECT id, name, public_key FROM users")?; - let ret: Vec = stmt.query_map([], _user_from_row)? + let ret: Vec = stmt + .query_map([], _user_from_row)? .filter(Result::is_ok) .map(Result::unwrap) .collect(); return Ok(ret); -} \ No newline at end of file +} diff --git a/src/db/mod.rs b/src/db/mod.rs index bc19e9b..f9d9b7b 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -1,10 +1,10 @@ -mod _users; -mod _securities; mod _accounts; mod _cheques; mod _external_id; -mod _test_utils; mod _interests; +mod _securities; +mod _test_utils; +mod _users; pub mod external_id { pub use super::_external_id::*; @@ -19,14 +19,10 @@ pub mod users { } pub mod accounts { - pub use super::_accounts::{Account, - AccountChangeReceipt, - create_checking_account, - create_security_emitter_account, - is_owner, - get_account_by_id, - list_accounts, - add_to_account}; + pub use super::_accounts::{ + add_to_account, create_checking_account, create_security_emitter_account, + get_account_by_id, is_owner, list_accounts, Account, AccountChangeReceipt, + }; } pub mod cheques { @@ -34,7 +30,5 @@ pub mod cheques { } pub mod test_utils { - pub use super::_test_utils::{mock_currency_1, - mock_currency_2, - setup_basic_environment}; -} \ No newline at end of file + pub use super::_test_utils::{mock_currency_1, mock_currency_2, setup_basic_environment}; +} diff --git a/src/event_processor.rs b/src/event_processor.rs index e0c27c7..9bee827 100644 --- a/src/event_processor.rs +++ b/src/event_processor.rs @@ -5,6 +5,7 @@ use std::fs::File; use std::io::{BufReader, Read, Write}; use std::path::PathBuf; +use crate::util::{CustomResult, Error}; use apache_avro::types::Value; use apache_avro::Schema::Union; use apache_avro::{ @@ -13,8 +14,6 @@ use apache_avro::{ use resource::resource_str; use rusqlite::Connection; use serde::{Deserialize, Serialize}; -use crate::util::{CustomResult, Error}; - #[derive(Deserialize, Serialize, Debug, PartialEq)] struct CacheChequeEvent { @@ -50,7 +49,6 @@ mod test { use super::*; - #[test] fn test_basic() -> CustomResult<()> { let file = tempfile().unwrap(); diff --git a/src/main.rs b/src/main.rs index ad0d37b..65de72d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; -use clap::{Arg, ArgAction, ArgMatches, Command, value_parser}; use clap::parser::ValuesRef; +use clap::{value_parser, Arg, ArgAction, ArgMatches, Command}; use log::{debug, error, info}; use rusqlite::Connection; use serde::Serialize; @@ -99,18 +99,14 @@ fn new_user_command_line_parser() -> Command { } fn ls_user_command_line_parser() -> Command { - return Command::new("ls") - .long_flag("ls") - .about("List all users."); + return Command::new("ls").long_flag("ls").about("List all users."); } - fn process_events_command_line_parser() -> Command { Command::new("process") .about("Process events one after the other. In the order received") .arg_required_else_help(true) - .arg(clap::arg!( ... "Stuff to add") - .value_parser(value_parser!(PathBuf))) + .arg(clap::arg!( ... "Stuff to add").value_parser(value_parser!(PathBuf))) } fn user_command_line_parser() -> Command { @@ -136,16 +132,19 @@ fn ls_securities_command_line_parser() -> Command { fn run_web_ui_command_line_parser() -> Command { return Command::new("run") - .arg(Arg::new("port") - .long("port") - .value_parser(clap::value_parser!(u16).range(3000..)) - .action(ArgAction::Set) - .default_value("3200")) - .arg(Arg::new("enable-template-autoreload") - .long("enable-template-autoreload") - .required(false) - .num_args(0) - .help("Reload underlying template (for development)") + .arg( + Arg::new("port") + .long("port") + .value_parser(clap::value_parser!(u16).range(3000..)) + .action(ArgAction::Set) + .default_value("3200"), + ) + .arg( + Arg::new("enable-template-autoreload") + .long("enable-template-autoreload") + .required(false) + .num_args(0) + .help("Reload underlying template (for development)"), ) .about("Run web user interface."); } @@ -356,7 +355,12 @@ mod cli_test { self.process_events_count += 1; } - fn run_webui(&mut self, conn: &mut Connection, port: u16, enable_template_autoreload: bool) { + fn run_webui( + &mut self, + conn: &mut Connection, + port: u16, + enable_template_autoreload: bool, + ) { self.run_webui_count += 1; } } diff --git a/src/migration.rs b/src/migration.rs index 8904cf1..8979659 100644 --- a/src/migration.rs +++ b/src/migration.rs @@ -1,7 +1,7 @@ -use std::time::Instant; +use resource::resource_str; use rusqlite::{Connection, Transaction}; use sha2::{Digest, Sha256}; -use resource::{resource_str}; +use std::time::Instant; #[derive(Debug)] pub enum IntegrityError { @@ -33,10 +33,10 @@ fn get_id_of_new_migration(tx: &Transaction) -> Result { return tx.query_row(q, (), |row| row.get::(0)); } - pub fn migrate(conn: &mut Connection, migrations: &Vec) -> Result<(), Error> { let tx = conn.transaction().map_err(|e| Error::Sql(e))?; - tx.execute(INITIAL_MIGRATION, ()).map_err(|e| Error::Sql(e))?; + tx.execute(INITIAL_MIGRATION, ()) + .map_err(|e| Error::Sql(e))?; let id = get_id_of_new_migration(&tx).map_err(|e| Error::Sql(e))?; for (i, migration) in migrations.iter().enumerate() { @@ -56,13 +56,13 @@ fn apply_migration(tx: &Transaction, id: usize, migration: &String) -> Result<() let q = "INSERT INTO shitty_migrations(id, sha256) VALUES (?1, ?2)"; tx.execute(q, (&id, &hash)).map_err(|e| Error::Sql(e))?; - let now = Instant::now(); tx.execute_batch(migration).map_err(|e| Error::Sql(e))?; let elapsed_time = now.elapsed(); let q = "UPDATE shitty_migrations SET duration = ?1 WHERE id = ?2"; - tx.execute(q, (elapsed_time.as_secs_f32(), &id)).map_err(|e| Error::Sql(e))?; + tx.execute(q, (elapsed_time.as_secs_f32(), &id)) + .map_err(|e| Error::Sql(e))?; return Ok(()); } @@ -76,7 +76,9 @@ fn compute_migration_sha256(migration: &String) -> String { fn check_migration(tx: &Transaction, id: usize, migration: &String) -> Result<(), Error> { let q = "SELECT sha256 FROM shitty_migrations WHERE id = ?1"; - let res = tx.query_row(q, (&id, ), |row| row.get::(0)).map_err(|e| Error::Sql(e))?; + let res = tx + .query_row(q, (&id,), |row| row.get::(0)) + .map_err(|e| Error::Sql(e))?; let expected = compute_migration_sha256(migration); if !res.eq(&expected) { return Err(Error::Integrity(IntegrityError::MigrationCheckFailed { @@ -91,11 +93,14 @@ fn check_migration(tx: &Transaction, id: usize, migration: &String) -> Result<() fn get_migrations() -> Vec { let mut ret = Vec::new(); - ret.push(resource_str!("migrations/sql/create_tables_001.sql").as_ref().to_string()); + ret.push( + resource_str!("migrations/sql/create_tables_001.sql") + .as_ref() + .to_string(), + ); return ret; } - pub fn apply_migrations(conn: &mut Connection) -> Result<(), Error> { let migrations = get_migrations(); return migrate(conn, &migrations); @@ -155,4 +160,4 @@ mod test_migration { assert!(ret.is_err()); return Ok(()); } -} \ No newline at end of file +} diff --git a/src/services/_transactions.rs b/src/services/_transactions.rs index bb17e57..d0a2e40 100644 --- a/src/services/_transactions.rs +++ b/src/services/_transactions.rs @@ -1,4 +1,4 @@ -use rusqlite::{Connection, ffi, params, Savepoint, Transaction}; +use rusqlite::{ffi, params, Connection, Savepoint, Transaction}; use crate::db::accounts; use crate::db::accounts::get_account_by_id; @@ -6,22 +6,32 @@ use crate::db::cheques::Cheque; use crate::db::external_id::AccountId; use crate::util::*; -fn _move_securities(tx: &Savepoint, - cheque: &Cheque, - account_id: &AccountId) -> CustomResult<(accounts::AccountChangeReceipt, accounts::AccountChangeReceipt)> { +fn _move_securities( + tx: &Savepoint, + cheque: &Cheque, + account_id: &AccountId, +) -> CustomResult<( + accounts::AccountChangeReceipt, + accounts::AccountChangeReceipt, +)> { let drawer_receipt = accounts::add_to_account(tx, &cheque.drawer_account_id, -cheque.amount)?; let payee_receipt = accounts::add_to_account(tx, account_id, cheque.amount)?; if drawer_receipt.amount < 0 { - let m = format!("Drawer of {:?} does not have sufficient amount in account.", cheque); + let m = format!( + "Drawer of {:?} does not have sufficient amount in account.", + cheque + ); return Err(Error::InvalidAmount(m)); } Ok((drawer_receipt, payee_receipt)) } -fn _add_cheque_to_cashed_cheques_log(tx: &Connection, - cheque: &Cheque, - drawer_receipt: &accounts::AccountChangeReceipt, - payee_receipt: &accounts::AccountChangeReceipt) -> Result<(), Error> { +fn _add_cheque_to_cashed_cheques_log( + tx: &Connection, + cheque: &Cheque, + drawer_receipt: &accounts::AccountChangeReceipt, + payee_receipt: &accounts::AccountChangeReceipt, +) -> Result<(), Error> { let q = " INSERT INTO cashed_cheques( drawer_user_id, @@ -36,49 +46,69 @@ fn _add_cheque_to_cashed_cheques_log(tx: &Connection, ) VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9) "; - let params = params![cheque.drawer_user_id, - cheque.drawer_account_id, - drawer_receipt.version, - cheque.payee_user_id, - payee_receipt.account_id, - payee_receipt.version, - cheque.cheque_number, - cheque.amount, - cheque.security_id]; + let params = params![ + cheque.drawer_user_id, + cheque.drawer_account_id, + drawer_receipt.version, + cheque.payee_user_id, + payee_receipt.account_id, + payee_receipt.version, + cheque.cheque_number, + cheque.amount, + cheque.security_id + ]; let ret = tx.execute(q, params).map_err(Error::SqlError); match ret { Ok(_) => Ok(()), - Err(Error::SqlError(rusqlite::Error::SqliteFailure(ffi::Error { code: _, extended_code: 2067 }, _))) => - Err(Error::DoubleSpendingError(format!("Cheque number {} from user {} has already been cached.", cheque.cheque_number, cheque.drawer_user_id))), - Err(a) => Err(a) + Err(Error::SqlError(rusqlite::Error::SqliteFailure( + ffi::Error { + code: _, + extended_code: 2067, + }, + _, + ))) => Err(Error::DoubleSpendingError(format!( + "Cheque number {} from user {} has already been cached.", + cheque.cheque_number, cheque.drawer_user_id + ))), + Err(a) => Err(a), } } -fn cash_cheque_unsafe(savepoint: &Savepoint, - cheque: &Cheque, - account_id: &AccountId) -> CustomResult<()> { +fn cash_cheque_unsafe( + savepoint: &Savepoint, + cheque: &Cheque, + account_id: &AccountId, +) -> CustomResult<()> { if cheque.amount < 0 { - return Err(Error::InvalidAmount(format!("The cheque {:?} has a negative amount.", cheque))); + return Err(Error::InvalidAmount(format!( + "The cheque {:?} has a negative amount.", + cheque + ))); } - if !accounts::is_owner(&savepoint, &cheque.drawer_account_id, &cheque.drawer_user_id)? { - return Err(Error::InvalidDrawer(format!("The drawer is the security owner: {:?}", cheque))); + if !accounts::is_owner( + &savepoint, + &cheque.drawer_account_id, + &cheque.drawer_user_id, + )? { + return Err(Error::InvalidDrawer(format!( + "The drawer is the security owner: {:?}", + cheque + ))); } if !accounts::is_owner(&savepoint, account_id, &cheque.payee_user_id)? { - return Err(Error::InvalidPayee(format!("Trying to cash the cheque {:?} in \ - an account {:?} that is not owned by the payee.", cheque, account_id))); + return Err(Error::InvalidPayee(format!( + "Trying to cash the cheque {:?} in \ + an account {:?} that is not owned by the payee.", + cheque, account_id + ))); } let (drawer_receipt, payee_receipt) = _move_securities(&savepoint, cheque, account_id)?; - _add_cheque_to_cashed_cheques_log(&savepoint, - cheque, - &drawer_receipt, - &payee_receipt)?; + _add_cheque_to_cashed_cheques_log(&savepoint, cheque, &drawer_receipt, &payee_receipt)?; Ok(()) } -fn cash_cheque(tx: &mut Transaction, - cheque: &Cheque, - account_id: &AccountId) -> CustomResult<()> { +fn cash_cheque(tx: &mut Transaction, cheque: &Cheque, account_id: &AccountId) -> CustomResult<()> { let mut savepoint = tx.savepoint().map_err(Error::SqlError)?; let ret = cash_cheque_unsafe(&savepoint, cheque, account_id); match ret { @@ -86,13 +116,10 @@ fn cash_cheque(tx: &mut Transaction, savepoint.rollback().map_err(Error::SqlError)?; ret } - Ok(_) => { - savepoint.commit().map_err(Error::SqlError) - } + Ok(_) => savepoint.commit().map_err(Error::SqlError), } } - #[cfg(test)] mod test_caching_cheques { use rusqlite::Connection; @@ -118,7 +145,8 @@ mod test_caching_cheques { 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 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(); tx.commit().unwrap(); @@ -127,9 +155,13 @@ mod test_caching_cheques { (conn, security_emitter, payee, payee_account.id()) } - fn _create_100_secs_in_payee_account(tx: &mut Transaction, security_emitter: &Drawer, payee: &Payee, payee_account: &AccountId) { - let cheque = Cheque::new( - security_emitter.clone(), payee.clone(), 100, 99); + fn _create_100_secs_in_payee_account( + tx: &mut Transaction, + security_emitter: &Drawer, + payee: &Payee, + payee_account: &AccountId, + ) { + let cheque = Cheque::new(security_emitter.clone(), payee.clone(), 100, 99); cash_cheque(tx, &cheque, &payee_account).unwrap(); } @@ -144,7 +176,8 @@ mod test_caching_cheques { let mut tx = conn.transaction().unwrap(); _create_100_secs_in_payee_account(&mut tx, &security_emitter, &payee, &payee_account); - let reg_account = create_checking_account(&tx, &security_emitter.2, &security_emitter.0).unwrap(); + let reg_account = + create_checking_account(&tx, &security_emitter.2, &security_emitter.0).unwrap(); tx.commit().unwrap(); @@ -154,14 +187,12 @@ mod test_caching_cheques { return (conn, drawer, new_payee, reg_account.id()); } - #[test] fn test_happy_path_currency_emitter() -> CustomResult<()> { let (mut conn, security_emitter, payee, payee_account) = setup_security_emitter(); let mut tx = conn.transaction().unwrap(); - let cheque = Cheque::new( - security_emitter, payee, 1000, 99); + let cheque = Cheque::new(security_emitter, payee, 1000, 99); cash_cheque(&mut tx, &cheque, &payee_account)?; tx.commit().unwrap(); @@ -178,8 +209,7 @@ mod test_caching_cheques { let (mut conn, drawer, payee, payee_account) = setup_basic(); let mut tx = conn.transaction().unwrap(); - let cheque = Cheque::new( - drawer.clone(), payee, 25, 10001); + let cheque = Cheque::new(drawer.clone(), payee, 25, 10001); cash_cheque(&mut tx, &cheque, &payee_account)?; @@ -192,16 +222,22 @@ mod test_caching_cheques { Ok(()) } - fn test_negative_cheque(conn: &mut Connection, drawer: Drawer, payee: Payee, payee_account: AccountId) -> CustomResult<()> { + fn test_negative_cheque( + conn: &mut Connection, + drawer: Drawer, + payee: Payee, + payee_account: AccountId, + ) -> CustomResult<()> { let mut tx = conn.transaction().unwrap(); - let cheque = Cheque::new( - drawer, payee, -1, 99); + let cheque = Cheque::new(drawer, payee, -1, 99); let ret = cash_cheque(&mut tx, &cheque, &payee_account); match ret { Err(Error::InvalidAmount(_)) => Ok(()), - _ => Err(Error::Testing("Expected invalid amount error here.".to_string())) + _ => Err(Error::Testing( + "Expected invalid amount error here.".to_string(), + )), } } @@ -217,15 +253,15 @@ mod test_caching_cheques { test_negative_cheque(&mut conn, drawer, payee, payee_account) } - fn test_double_spend(conn: &mut Connection, drawer: Drawer, payee: Payee, payee_account: AccountId) -> CustomResult<()> { + fn test_double_spend( + conn: &mut Connection, + drawer: Drawer, + payee: Payee, + payee_account: AccountId, + ) -> CustomResult<()> { let mut tx = conn.transaction().unwrap(); - let cheque = Cheque::new( - drawer, - payee, - 10, - 99, - ); + let cheque = Cheque::new(drawer, payee, 10, 99); cash_cheque(&mut tx, &cheque, &payee_account)?; tx.commit().unwrap(); @@ -234,7 +270,9 @@ mod test_caching_cheques { let ret = cash_cheque(&mut tx, &cheque, &payee_account); match ret { Err(Error::DoubleSpendingError(_)) => Ok(()), - _ => Err(Error::Testing("Expected double spending error here.".to_string())) + _ => Err(Error::Testing( + "Expected double spending error here.".to_string(), + )), } } @@ -250,21 +288,21 @@ mod test_caching_cheques { test_double_spend(&mut conn, drawer, payee, payee_account) } - fn test_invalid_drawer(conn: &mut Connection, drawer: Drawer, payee: Payee, payee_account: AccountId) -> CustomResult<()> { + fn test_invalid_drawer( + conn: &mut Connection, + drawer: Drawer, + payee: Payee, + payee_account: AccountId, + ) -> CustomResult<()> { let mut tx = conn.transaction().unwrap(); let not_currency_owner_user_id = UserId::from_id(drawer.0.get_id() + 72623); let not_currency_owner: Drawer = (not_currency_owner_user_id, drawer.1, drawer.2); - let cheque = Cheque::new( - not_currency_owner, - payee, - 100, - 99, - ); + let cheque = Cheque::new(not_currency_owner, payee, 100, 99); let ret = cash_cheque(&mut tx, &cheque, &payee_account); match ret { Err(Error::InvalidDrawer(_)) => Ok(()), - _ => Err(Error::Testing("Expected invalid drawer here.".to_string())) + _ => Err(Error::Testing("Expected invalid drawer here.".to_string())), } } @@ -280,22 +318,24 @@ mod test_caching_cheques { test_invalid_drawer(&mut conn, drawer, payee, payee_account) } - fn test_invalid_payee(conn: &mut Connection, security_emitter: Drawer, payee: Payee) -> CustomResult<()> { + fn test_invalid_payee( + conn: &mut Connection, + security_emitter: Drawer, + payee: Payee, + ) -> CustomResult<()> { let (mut conn, security_emitter, payee, payee_account) = setup_security_emitter(); let mut tx = conn.transaction().unwrap(); let wrong_payee_account = &security_emitter.1; - let cheque = Cheque::new( - security_emitter.clone(), payee.clone(), 1000, 99); + let cheque = Cheque::new(security_emitter.clone(), payee.clone(), 1000, 99); let ret = cash_cheque(&mut tx, &cheque, wrong_payee_account); match ret { Err(Error::InvalidPayee(_)) => Ok(()), - _ => Err(Error::Testing("Expected invalid payee here.".to_string())) + _ => Err(Error::Testing("Expected invalid payee here.".to_string())), } } - #[test] fn test_invalid_payee_security_emitter_cheque() -> CustomResult<()> { let (mut conn, security_emitter, payee, payee_account) = setup_security_emitter(); @@ -307,4 +347,4 @@ mod test_caching_cheques { let (mut conn, drawer, payee, payee_account) = setup_basic(); test_invalid_payee(&mut conn, drawer, payee) } -} \ No newline at end of file +} diff --git a/src/services/mod.rs b/src/services/mod.rs index 490f567..31a58b4 100644 --- a/src/services/mod.rs +++ b/src/services/mod.rs @@ -1 +1 @@ -mod _transactions; \ No newline at end of file +mod _transactions; diff --git a/src/webui/mod.rs b/src/webui/mod.rs index 7ae83e2..5c747b4 100644 --- a/src/webui/mod.rs +++ b/src/webui/mod.rs @@ -3,12 +3,12 @@ mod views; use actix_utils::future::{ready, Ready}; use minijinja; use minijinja_autoreload::AutoReloader; -use std::{collections::HashMap, env, fs, io, path::PathBuf}; use std::io::{Error, ErrorKind}; use std::path::Path; +use std::{collections::HashMap, env, fs, io, path::PathBuf}; use actix_web::{ - dev::{ServiceResponse}, + dev::ServiceResponse, error, http::{header::ContentType, StatusCode}, middleware::{ErrorHandlerResponse, ErrorHandlers, Logger}, @@ -54,7 +54,6 @@ impl FromRequest for MiniJinjaRenderer { } } - #[tokio::main] pub async fn web_ui_main(port: u16, enable_template_autoreload: bool) -> std::io::Result<()> { // The closure is invoked every time the environment is outdated to recreate it. diff --git a/src/webui/views.rs b/src/webui/views.rs index f1a5957..7958be1 100644 --- a/src/webui/views.rs +++ b/src/webui/views.rs @@ -1,6 +1,6 @@ -use std::collections::HashMap; -use actix_web::{Responder, web}; use crate::webui::MiniJinjaRenderer; +use actix_web::{web, Responder}; +use std::collections::HashMap; #[actix_web::get("/")] pub async fn index( diff --git a/tools/lint b/tools/lint new file mode 100755 index 0000000..f93ec0e --- /dev/null +++ b/tools/lint @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +find ${PROJECT_ROOT}/src -name '*.rs' | xargs rustfmt --edition 2021 \ No newline at end of file