Linted code.

This commit is contained in:
didier amyot committed 2023-01-30 08:10:00 -05:00
1 parent 894f969d0f
commit 174d7e855a
16 files changed
+276 -178

No files matched your search

+1
View File
@@ -45,6 +45,7 @@
RUST_SRC_PATH = rustPlatform.rustLibSrc; RUST_SRC_PATH = rustPlatform.rustLibSrc;
shellHook = '' shellHook = ''
export PROJECT_ROOT=${PROJECT_ROOT}; export PROJECT_ROOT=${PROJECT_ROOT};
export PATH=$PROJECT_ROOT/tools:$PATH;
''; '';
}; };
}); });
+47 -18
View File
@@ -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::_external_id::{AccountId, Id, UserId};
use crate::db::_securities::Security; use crate::db::_securities::Security;
@@ -100,7 +100,6 @@ impl AccountHistory {
} }
} }
pub fn list_accounts<'a>(conn: &Connection) -> CustomResult<Vec<Account>> { pub fn list_accounts<'a>(conn: &Connection) -> CustomResult<Vec<Account>> {
let q = "SELECT acc.id AS acc_id, let q = "SELECT acc.id AS acc_id,
acc.amount AS acc_amount, acc.amount AS acc_amount,
@@ -135,17 +134,25 @@ pub fn get_account_by_id(tx: &Connection, id: &AccountId) -> CustomResult<Accoun
FROM accounts acc FROM accounts acc
JOIN securities sec ON acc.security = sec.id JOIN securities sec ON acc.security = sec.id
WHERE acc.id = ?1"; WHERE acc.id = ?1";
return tx.query_row(q, params![id], Account::from_row).map_err(Error::SqlError); return tx
.query_row(q, params![id], Account::from_row)
.map_err(Error::SqlError);
} }
fn create_account(tx: &Connection, sec: &SecurityId, user: &UserId, account_type: AccountType) -> CustomResult<Account> { fn create_account(
tx: &Connection,
sec: &SecurityId,
user: &UserId,
account_type: AccountType,
) -> CustomResult<Account> {
let q = "INSERT INTO accounts(security, version, amount, timestamp, account_type) let q = "INSERT INTO accounts(security, version, amount, timestamp, account_type)
VALUES (?1, 0, 0, CURRENT_TIMESTAMP, ?2)"; VALUES (?1, 0, 0, CURRENT_TIMESTAMP, ?2)";
let account_type = match account_type { let account_type = match account_type {
AccountType::Checking => "checking", AccountType::Checking => "checking",
AccountType::SecurityEmitter => "security_emitter", 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 id = AccountId::from_id(tx.last_insert_rowid() as i64);
let q = "INSERT INTO account_user_permissions(user_id, account_id) let q = "INSERT INTO account_user_permissions(user_id, account_id)
@@ -165,7 +172,8 @@ fn get_account_history(tx: &Connection, id: &AccountId) -> CustomResult<AccountH
WHERE account_id = ?1 WHERE account_id = ?1
ORDER BY account_version DESC"; ORDER BY account_version DESC";
let mut stmt = tx.prepare(q).map_err(Error::SqlError)?; let mut stmt = tx.prepare(q).map_err(Error::SqlError)?;
let snapshots: Vec<AccountSnapshot> = stmt.query_map(params![id], AccountSnapshot::from_row) let snapshots: Vec<AccountSnapshot> = stmt
.query_map(params![id], AccountSnapshot::from_row)
.map_err(Error::SqlError)? .map_err(Error::SqlError)?
.filter(Result::is_ok) .filter(Result::is_ok)
.map(Result::unwrap) .map(Result::unwrap)
@@ -174,11 +182,19 @@ fn get_account_history(tx: &Connection, id: &AccountId) -> CustomResult<AccountH
return AccountHistory::new(get_account_by_id(tx, id)?, snapshots); return AccountHistory::new(get_account_by_id(tx, id)?, snapshots);
} }
pub fn create_checking_account(tx: &Connection, sec: &SecurityId, user: &UserId) -> CustomResult<Account> { pub fn create_checking_account(
tx: &Connection,
sec: &SecurityId,
user: &UserId,
) -> CustomResult<Account> {
create_account(tx, sec, user, AccountType::Checking) create_account(tx, sec, user, AccountType::Checking)
} }
pub fn create_security_emitter_account(tx: &Connection, sec: &SecurityId, user: &UserId) -> CustomResult<Account> { pub fn create_security_emitter_account(
tx: &Connection,
sec: &SecurityId,
user: &UserId,
) -> CustomResult<Account> {
create_account(tx, sec, user, AccountType::SecurityEmitter) 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 q = "SELECT id FROM account_user_permissions WHERE account_id = ?1 AND user_id = ?2";
let params = params![account_id, user_id]; let params = params![account_id, user_id];
let ite = |row: &Row| row.get::<usize, i64>(0); let ite = |row: &Row| row.get::<usize, i64>(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()) Ok(option.is_some())
} }
@@ -218,13 +237,16 @@ fn update_account_history(tx: &Connection, account_id: &AccountId) -> CustomResu
FROM accounts FROM accounts
WHERE id = ?1 WHERE id = ?1
"; ";
tx.execute(q, params![account_id]).map_err(Error::SqlError)?; tx.execute(q, params![account_id])
.map_err(Error::SqlError)?;
Ok(()) Ok(())
} }
pub fn add_to_account(tx: &Connection, pub fn add_to_account(
tx: &Connection,
account_id: &AccountId, account_id: &AccountId,
amount: i64) -> CustomResult<AccountChangeReceipt> { amount: i64,
) -> CustomResult<AccountChangeReceipt> {
let q = " let q = "
UPDATE accounts SET amount = CASE account_type UPDATE accounts SET amount = CASE account_type
WHEN 'security_emitter' WHEN 'security_emitter'
@@ -236,7 +258,9 @@ pub fn add_to_account(tx: &Connection,
RETURNING id, version, amount, UNIXEPOCH(CURRENT_TIMESTAMP) as timestamp RETURNING id, version, amount, UNIXEPOCH(CURRENT_TIMESTAMP) as timestamp
"; ";
let params = params![amount, account_id]; 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)?; update_account_history(tx, account_id)?;
return ret; return ret;
} }
@@ -261,7 +285,11 @@ mod test_accounts {
return (conn, users, securities); return (conn, users, securities);
} }
fn create_all_accounts(tx: &Transaction, users: &Vec<User>, secs: &Vec<Security>) -> CustomResult<Vec<Account>> { fn create_all_accounts(
tx: &Transaction,
users: &Vec<User>,
secs: &Vec<Security>,
) -> CustomResult<Vec<Account>> {
let mut ret: Vec<Account> = Vec::new(); let mut ret: Vec<Account> = Vec::new();
for sec in secs.iter() { for sec in secs.iter() {
for user in users.iter() { for user in users.iter() {
@@ -361,8 +389,10 @@ mod test_accounts {
let acc = get_account_by_id(&tx2, &acc.id()).unwrap(); let acc = get_account_by_id(&tx2, &acc.id()).unwrap();
assert_eq!(acc.timestamp, receipt.timestamp); assert_eq!(acc.timestamp, receipt.timestamp);
assert_eq!(acc.amount, 33); assert_eq!(acc.amount, 33);
assert_eq!(get_account_history(&tx2, &acc.id())?.average_amount(), assert_eq!(
Fraction::from(0 + 33) / Fraction::from(2)); get_account_history(&tx2, &acc.id())?.average_amount(),
Fraction::from(0 + 33) / Fraction::from(2)
);
Ok(()) Ok(())
} }
@@ -390,4 +420,3 @@ mod test_accounts {
Ok(()) Ok(())
} }
} }
+1 -4
View File
@@ -14,10 +14,7 @@ pub struct Cheque {
} }
impl Cheque { impl Cheque {
pub fn new(drawer: Drawer, pub fn new(drawer: Drawer, payee: Payee, amount: i64, cheque_number: i64) -> Cheque {
payee: Payee,
amount: i64,
cheque_number: i64) -> Cheque {
Cheque { Cheque {
drawer_user_id: drawer.0, drawer_user_id: drawer.0,
drawer_account_id: drawer.1, drawer_account_id: drawer.1,
+53 -28
View File
@@ -8,7 +8,6 @@ struct SafeId {
signature: [u8; 8], signature: [u8; 8],
} }
pub trait Id { pub trait Id {
type Output; type Output;
fn from_regex_captures(caps: &Captures) -> Option<Self::Output>; fn from_regex_captures(caps: &Captures) -> Option<Self::Output>;
@@ -19,7 +18,12 @@ pub trait Id {
impl fmt::Display for SafeId { impl fmt::Display for SafeId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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 { macro_rules! impl_ids {
($T:ident, $prefix:literal) => { ($T:ident, $prefix:literal) => {
impl fmt::Display for $T { impl fmt::Display for $T {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}-{}", $prefix, self.0) write!(f, "{}-{}", $prefix, self.0)
@@ -78,16 +79,17 @@ macro_rules! impl_ids {
fn from_regex_captures(caps: &Captures) -> Option<$T> { fn from_regex_captures(caps: &Captures) -> Option<$T> {
let type_ = caps.name("type")?; let type_ = caps.name("type")?;
if(type_.as_str() != $prefix){ if (type_.as_str() != $prefix) {
return None; return None;
} }
SafeId::from_regex_captures(caps).map(|x| $T(x)) SafeId::from_regex_captures(caps).map(|x| $T(x))
} }
fn from_string(s: &String) -> Option<$T> { fn from_string(s: &String) -> Option<$T> {
let external_id_pattern = Regex::new(r"^(?P<type>\w)-(?P<id>\w+)-(?P<sign>\w+)$").unwrap(); let external_id_pattern =
Regex::new(r"^(?P<type>\w)-(?P<id>\w+)-(?P<sign>\w+)$").unwrap();
let caps = external_id_pattern.captures(&s)?; let caps = external_id_pattern.captures(&s)?;
Self::from_regex_captures(& caps) Self::from_regex_captures(&caps)
} }
fn from_id(id: i64) -> $T { fn from_id(id: i64) -> $T {
@@ -98,7 +100,7 @@ macro_rules! impl_ids {
self.0.get_id() self.0.get_id()
} }
} }
} };
} }
#[derive(PartialEq, Debug, Clone)] #[derive(PartialEq, Debug, Clone)]
@@ -121,17 +123,15 @@ pub enum ExternalId {
SecurityId(SecurityId), SecurityId(SecurityId),
} }
fn deserialize_str(s: &str) -> Option<[u8; 8]> { fn deserialize_str(s: &str) -> Option<[u8; 8]> {
let mut encrypted_id_bytes = [0u8; 8]; let mut encrypted_id_bytes = [0u8; 8];
let r = hex::decode_to_slice(s, &mut encrypted_id_bytes as &mut [u8]); let r = hex::decode_to_slice(s, &mut encrypted_id_bytes as &mut [u8]);
return match r { return match r {
Ok(_) => Some(encrypted_id_bytes), Ok(_) => Some(encrypted_id_bytes),
Err(_) => None Err(_) => None,
}; };
} }
impl ToString for ExternalId { impl ToString for ExternalId {
fn to_string(&self) -> String { fn to_string(&self) -> String {
match self { match self {
@@ -142,17 +142,20 @@ impl ToString for ExternalId {
} }
} }
impl ExternalId { impl ExternalId {
pub fn from_string(s: &String) -> Option<ExternalId> { pub fn from_string(s: &String) -> Option<ExternalId> {
let pattern = Regex::new(r"^(?P<type>\w)-(?P<id>\w+)-(?P<sign>\w+)$").unwrap(); let pattern = Regex::new(r"^(?P<type>\w)-(?P<id>\w+)-(?P<sign>\w+)$").unwrap();
let caps = pattern.captures(&s)?; let caps = pattern.captures(&s)?;
match caps.name("type")?.as_str() { 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)?)), "u" => Some(ExternalId::UserId(UserId::from_regex_captures(&caps)?)),
"s" => Some(ExternalId::SecurityId(SecurityId::from_regex_captures(&caps)?)), "s" => Some(ExternalId::SecurityId(SecurityId::from_regex_captures(
_ => None &caps,
)?)),
_ => None,
} }
} }
@@ -172,16 +175,31 @@ pub mod test_external_ids {
#[test] #[test]
fn test_id_macro() { fn test_id_macro() {
let id = SecurityId::from_id(33); let id = SecurityId::from_id(33);
assert_eq!(id.to_string(), "s-0000000000000021-0000000000000021".to_string()); assert_eq!(
assert!(SecurityId::from_string(&"s-0000000000000021-0000000000000021".to_string()).is_some()); id.to_string(),
assert!(SecurityId::from_string(&"u-0000000000000021-0000000000000021".to_string()).is_none()); "s-0000000000000021-0000000000000021".to_string()
assert!(SecurityId::from_string(&"0000000000000021-0000000000000021".to_string()).is_none()); );
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] #[test]
fn safe_id_happy_path_1() { 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] }; let sid = SafeId {
assert_eq!("0102030405060708-0807060504030201".to_string(), sid.to_string()); 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(); let deserialized_eid = SafeId::from_string(&sid.to_string()).unwrap();
assert_eq!(sid, deserialized_eid); assert_eq!(sid, deserialized_eid);
} }
@@ -189,7 +207,10 @@ pub mod test_external_ids {
#[test] #[test]
fn safe_id_happy_path_2() { fn safe_id_happy_path_2() {
let sid = SafeId::from_id(56); 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(); let deserialized_eid = SafeId::from_string(&sid.to_string()).unwrap();
assert_eq!(sid, deserialized_eid); assert_eq!(sid, deserialized_eid);
assert_eq!(56, deserialized_eid.get_id()); assert_eq!(56, deserialized_eid.get_id());
@@ -200,31 +221,35 @@ pub mod test_external_ids {
let bad_strings = vec!["a", "a-b", "01020304-0708090É"]; let bad_strings = vec!["a", "a-b", "01020304-0708090É"];
for bad_string in bad_strings.iter() { for bad_string in bad_strings.iter() {
let ret = SafeId::from_string(&bad_string.to_string()); 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] #[test]
fn external_id_simple_test() { fn external_id_simple_test() {
let base = "0000000000000038-0000000000000038"; 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 { assert!(match eid {
ExternalId::UserId(_) => true, ExternalId::UserId(_) => true,
_ => false _ => false,
}); });
assert_eq!(eid.to_string(), format!("u-{:}", base)); assert_eq!(eid.to_string(), format!("u-{:}", base));
let eid = ExternalId::from_string(&format!("a-{:}", base)).unwrap(); let eid = ExternalId::from_string(&format!("a-{:}", base)).unwrap();
assert!(match eid { assert!(match eid {
ExternalId::AccountId(_) => true, ExternalId::AccountId(_) => true,
_ => false _ => false,
}); });
assert_eq!(eid.to_string(), format!("a-{:}", base)); assert_eq!(eid.to_string(), format!("a-{:}", base));
let eid = ExternalId::from_string(&format!("s-{:}", base)).unwrap(); let eid = ExternalId::from_string(&format!("s-{:}", base)).unwrap();
assert!(match eid { assert!(match eid {
ExternalId::SecurityId(_) => true, ExternalId::SecurityId(_) => true,
_ => false _ => false,
}); });
assert_eq!(eid.to_string(), format!("s-{:}", base)); assert_eq!(eid.to_string(), format!("s-{:}", base));
} }
-1
View File
@@ -1,2 +1 @@
+3 -7
View File
@@ -1,4 +1,4 @@
use rusqlite::{Connection, params, Result, Row, ToSql, Transaction}; use rusqlite::{params, Connection, Result, Row, ToSql, Transaction};
use serde::Serialize; use serde::Serialize;
use crate::db::_external_id::{Id, SecurityId}; use crate::db::_external_id::{Id, SecurityId};
@@ -61,8 +61,7 @@ pub struct NewSecurity {
pub name: String, pub name: String,
} }
pub fn create_security(tx: &Transaction, pub fn create_security(tx: &Transaction, sec: &NewSecurity) -> Result<Security> {
sec: &NewSecurity) -> Result<Security> {
let q = "INSERT INTO let q = "INSERT INTO
securities(name, symbol, security_type) securities(name, symbol, security_type)
VALUES(?1, ?2, ?3)"; VALUES(?1, ?2, ?3)";
@@ -73,7 +72,6 @@ pub fn create_security(tx: &Transaction,
return get_security_by_id(tx, new_sec_id); return get_security_by_id(tx, new_sec_id);
} }
pub fn get_security_by_id(tx: &Transaction, id: i32) -> Result<Security> { pub fn get_security_by_id(tx: &Transaction, id: i32) -> Result<Security> {
let q = "SELECT id AS sec_id, security_type AS sec_security_type, symbol AS sec_symbol let q = "SELECT id AS sec_id, security_type AS sec_security_type, symbol AS sec_symbol
FROM securities FROM securities
@@ -95,10 +93,9 @@ pub fn list_securities(conn: &Connection) -> Result<Vec<Security>> {
return Ok(ret); return Ok(ret);
} }
#[cfg(test)] #[cfg(test)]
mod test_securities { mod test_securities {
use rusqlite::{Connection, params}; use rusqlite::{params, Connection};
use crate::db::_test_utils::*; use crate::db::_test_utils::*;
use crate::migration; use crate::migration;
@@ -160,7 +157,6 @@ mod test_securities {
assert_eq!(1, ret.len()); assert_eq!(1, ret.len());
assert_eq!(&expt, ret.get(0).unwrap()); assert_eq!(&expt, ret.get(0).unwrap());
let sec = mock_currency_2(); let sec = mock_currency_2();
let expt = Security { let expt = Security {
id: 2, id: 2,
+12 -6
View File
@@ -1,11 +1,11 @@
use rusqlite::{Result, Transaction}; use rusqlite::{Result, Transaction};
use crate::db::{_securities, _users};
use crate::db::_accounts::create_checking_account; use crate::db::_accounts::create_checking_account;
use crate::db::_external_id::UserId; use crate::db::_external_id::UserId;
use crate::db::_securities::{NewSecurity, Security, SecurityType}; use crate::db::_securities::{NewSecurity, Security, SecurityType};
use crate::db::_users::User; use crate::db::_users::User;
use crate::db::accounts::Account; use crate::db::accounts::Account;
use crate::db::{_securities, _users};
use crate::util::CustomResult; use crate::util::CustomResult;
pub fn mock_currency_1() -> NewSecurity { pub fn mock_currency_1() -> NewSecurity {
@@ -42,14 +42,20 @@ pub fn setup_users_and_securities(tx: &Transaction) -> Result<(Vec<User>, Vec<Se
Ok((users, securities)) Ok((users, securities))
} }
pub fn setup_basic_environment(tx: &Transaction) -> CustomResult<(Vec<User>, Vec<Security>, Vec<Account>)> { pub fn setup_basic_environment(
tx: &Transaction,
) -> CustomResult<(Vec<User>, Vec<Security>, Vec<Account>)> {
let (users, securities) = setup_users_and_securities(tx).unwrap(); let (users, securities) = setup_users_and_securities(tx).unwrap();
let acc1 = create_checking_account(tx, let acc1 = create_checking_account(
tx,
&securities.get(0).unwrap().id(), &securities.get(0).unwrap().id(),
&users.get(0).unwrap().id())?; &users.get(0).unwrap().id(),
let acc2 = create_checking_account(tx, )?;
let acc2 = create_checking_account(
tx,
&securities.get(1).unwrap().id(), &securities.get(1).unwrap().id(),
&users.get(1).unwrap().id())?; &users.get(1).unwrap().id(),
)?;
Ok((users, securities, vec![acc1, acc2])) Ok((users, securities, vec![acc1, acc2]))
} }
+9 -7
View File
@@ -1,7 +1,6 @@
use rusqlite::{Connection, params, Result, Transaction, Row}; use crate::db::_external_id::{Id, UserId};
use serde::{Serialize}; use rusqlite::{params, Connection, Result, Row, Transaction};
use crate::db::_external_id::{UserId, Id}; use serde::Serialize;
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub struct User { pub struct User {
@@ -17,8 +16,10 @@ impl User {
} }
pub fn create_user(tx: &Transaction, name: &String, public_key: &String) -> Result<User> { pub fn create_user(tx: &Transaction, name: &String, public_key: &String) -> Result<User> {
tx.execute("INSERT INTO users (name, public_key) VALUES (?1, ?2)", tx.execute(
(name, public_key))?; "INSERT INTO users (name, public_key) VALUES (?1, ?2)",
(name, public_key),
)?;
return get_user_by_id(tx, tx.last_insert_rowid() as i32); return get_user_by_id(tx, tx.last_insert_rowid() as i32);
} }
@@ -39,7 +40,8 @@ fn get_user_by_id(tx: &Transaction, id: i32) -> Result<User> {
pub fn list_users(conn: &Connection) -> Result<Vec<User>> { pub fn list_users(conn: &Connection) -> Result<Vec<User>> {
let mut stmt = conn.prepare("SELECT id, name, public_key FROM users")?; let mut stmt = conn.prepare("SELECT id, name, public_key FROM users")?;
let ret: Vec<User> = stmt.query_map([], _user_from_row)? let ret: Vec<User> = stmt
.query_map([], _user_from_row)?
.filter(Result::is_ok) .filter(Result::is_ok)
.map(Result::unwrap) .map(Result::unwrap)
.collect(); .collect();
+8 -14
View File
@@ -1,10 +1,10 @@
mod _users;
mod _securities;
mod _accounts; mod _accounts;
mod _cheques; mod _cheques;
mod _external_id; mod _external_id;
mod _test_utils;
mod _interests; mod _interests;
mod _securities;
mod _test_utils;
mod _users;
pub mod external_id { pub mod external_id {
pub use super::_external_id::*; pub use super::_external_id::*;
@@ -19,14 +19,10 @@ pub mod users {
} }
pub mod accounts { pub mod accounts {
pub use super::_accounts::{Account, pub use super::_accounts::{
AccountChangeReceipt, add_to_account, create_checking_account, create_security_emitter_account,
create_checking_account, get_account_by_id, is_owner, list_accounts, Account, AccountChangeReceipt,
create_security_emitter_account, };
is_owner,
get_account_by_id,
list_accounts,
add_to_account};
} }
pub mod cheques { pub mod cheques {
@@ -34,7 +30,5 @@ pub mod cheques {
} }
pub mod test_utils { pub mod test_utils {
pub use super::_test_utils::{mock_currency_1, pub use super::_test_utils::{mock_currency_1, mock_currency_2, setup_basic_environment};
mock_currency_2,
setup_basic_environment};
} }
+1 -3
View File
@@ -5,6 +5,7 @@ use std::fs::File;
use std::io::{BufReader, Read, Write}; use std::io::{BufReader, Read, Write};
use std::path::PathBuf; use std::path::PathBuf;
use crate::util::{CustomResult, Error};
use apache_avro::types::Value; use apache_avro::types::Value;
use apache_avro::Schema::Union; use apache_avro::Schema::Union;
use apache_avro::{ use apache_avro::{
@@ -13,8 +14,6 @@ use apache_avro::{
use resource::resource_str; use resource::resource_str;
use rusqlite::Connection; use rusqlite::Connection;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::util::{CustomResult, Error};
#[derive(Deserialize, Serialize, Debug, PartialEq)] #[derive(Deserialize, Serialize, Debug, PartialEq)]
struct CacheChequeEvent { struct CacheChequeEvent {
@@ -50,7 +49,6 @@ mod test {
use super::*; use super::*;
#[test] #[test]
fn test_basic() -> CustomResult<()> { fn test_basic() -> CustomResult<()> {
let file = tempfile().unwrap(); let file = tempfile().unwrap();
+16 -12
View File
@@ -1,7 +1,7 @@
use std::path::PathBuf; use std::path::PathBuf;
use clap::{Arg, ArgAction, ArgMatches, Command, value_parser};
use clap::parser::ValuesRef; use clap::parser::ValuesRef;
use clap::{value_parser, Arg, ArgAction, ArgMatches, Command};
use log::{debug, error, info}; use log::{debug, error, info};
use rusqlite::Connection; use rusqlite::Connection;
use serde::Serialize; use serde::Serialize;
@@ -99,18 +99,14 @@ fn new_user_command_line_parser() -> Command {
} }
fn ls_user_command_line_parser() -> Command { fn ls_user_command_line_parser() -> Command {
return Command::new("ls") return Command::new("ls").long_flag("ls").about("List all users.");
.long_flag("ls")
.about("List all users.");
} }
fn process_events_command_line_parser() -> Command { fn process_events_command_line_parser() -> Command {
Command::new("process") Command::new("process")
.about("Process events one after the other. In the order received") .about("Process events one after the other. In the order received")
.arg_required_else_help(true) .arg_required_else_help(true)
.arg(clap::arg!(<PATH> ... "Stuff to add") .arg(clap::arg!(<PATH> ... "Stuff to add").value_parser(value_parser!(PathBuf)))
.value_parser(value_parser!(PathBuf)))
} }
fn user_command_line_parser() -> Command { 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 { fn run_web_ui_command_line_parser() -> Command {
return Command::new("run") return Command::new("run")
.arg(Arg::new("port") .arg(
Arg::new("port")
.long("port") .long("port")
.value_parser(clap::value_parser!(u16).range(3000..)) .value_parser(clap::value_parser!(u16).range(3000..))
.action(ArgAction::Set) .action(ArgAction::Set)
.default_value("3200")) .default_value("3200"),
.arg(Arg::new("enable-template-autoreload") )
.arg(
Arg::new("enable-template-autoreload")
.long("enable-template-autoreload") .long("enable-template-autoreload")
.required(false) .required(false)
.num_args(0) .num_args(0)
.help("Reload underlying template (for development)") .help("Reload underlying template (for development)"),
) )
.about("Run web user interface."); .about("Run web user interface.");
} }
@@ -356,7 +355,12 @@ mod cli_test {
self.process_events_count += 1; 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; self.run_webui_count += 1;
} }
} }
+14 -9
View File
@@ -1,7 +1,7 @@
use std::time::Instant; use resource::resource_str;
use rusqlite::{Connection, Transaction}; use rusqlite::{Connection, Transaction};
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use resource::{resource_str}; use std::time::Instant;
#[derive(Debug)] #[derive(Debug)]
pub enum IntegrityError { pub enum IntegrityError {
@@ -33,10 +33,10 @@ fn get_id_of_new_migration(tx: &Transaction) -> Result<usize, rusqlite::Error> {
return tx.query_row(q, (), |row| row.get::<usize, usize>(0)); return tx.query_row(q, (), |row| row.get::<usize, usize>(0));
} }
pub fn migrate(conn: &mut Connection, migrations: &Vec<String>) -> Result<(), Error> { pub fn migrate(conn: &mut Connection, migrations: &Vec<String>) -> Result<(), Error> {
let tx = conn.transaction().map_err(|e| Error::Sql(e))?; 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))?; let id = get_id_of_new_migration(&tx).map_err(|e| Error::Sql(e))?;
for (i, migration) in migrations.iter().enumerate() { 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)"; let q = "INSERT INTO shitty_migrations(id, sha256) VALUES (?1, ?2)";
tx.execute(q, (&id, &hash)).map_err(|e| Error::Sql(e))?; tx.execute(q, (&id, &hash)).map_err(|e| Error::Sql(e))?;
let now = Instant::now(); let now = Instant::now();
tx.execute_batch(migration).map_err(|e| Error::Sql(e))?; tx.execute_batch(migration).map_err(|e| Error::Sql(e))?;
let elapsed_time = now.elapsed(); let elapsed_time = now.elapsed();
let q = "UPDATE shitty_migrations SET duration = ?1 WHERE id = ?2"; 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(()); return Ok(());
} }
@@ -76,7 +76,9 @@ fn compute_migration_sha256(migration: &String) -> String {
fn check_migration(tx: &Transaction, id: usize, migration: &String) -> Result<(), Error> { fn check_migration(tx: &Transaction, id: usize, migration: &String) -> Result<(), Error> {
let q = "SELECT sha256 FROM shitty_migrations WHERE id = ?1"; let q = "SELECT sha256 FROM shitty_migrations WHERE id = ?1";
let res = tx.query_row(q, (&id, ), |row| row.get::<usize, String>(0)).map_err(|e| Error::Sql(e))?; let res = tx
.query_row(q, (&id,), |row| row.get::<usize, String>(0))
.map_err(|e| Error::Sql(e))?;
let expected = compute_migration_sha256(migration); let expected = compute_migration_sha256(migration);
if !res.eq(&expected) { if !res.eq(&expected) {
return Err(Error::Integrity(IntegrityError::MigrationCheckFailed { return Err(Error::Integrity(IntegrityError::MigrationCheckFailed {
@@ -91,11 +93,14 @@ fn check_migration(tx: &Transaction, id: usize, migration: &String) -> Result<()
fn get_migrations() -> Vec<String> { fn get_migrations() -> Vec<String> {
let mut ret = Vec::new(); 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; return ret;
} }
pub fn apply_migrations(conn: &mut Connection) -> Result<(), Error> { pub fn apply_migrations(conn: &mut Connection) -> Result<(), Error> {
let migrations = get_migrations(); let migrations = get_migrations();
return migrate(conn, &migrations); return migrate(conn, &migrations);
+104 -64
View File
@@ -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;
use crate::db::accounts::get_account_by_id; 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::db::external_id::AccountId;
use crate::util::*; use crate::util::*;
fn _move_securities(tx: &Savepoint, fn _move_securities(
tx: &Savepoint,
cheque: &Cheque, cheque: &Cheque,
account_id: &AccountId) -> CustomResult<(accounts::AccountChangeReceipt, accounts::AccountChangeReceipt)> { account_id: &AccountId,
) -> CustomResult<(
accounts::AccountChangeReceipt,
accounts::AccountChangeReceipt,
)> {
let drawer_receipt = accounts::add_to_account(tx, &cheque.drawer_account_id, -cheque.amount)?; 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)?; let payee_receipt = accounts::add_to_account(tx, account_id, cheque.amount)?;
if drawer_receipt.amount < 0 { 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)); return Err(Error::InvalidAmount(m));
} }
Ok((drawer_receipt, payee_receipt)) Ok((drawer_receipt, payee_receipt))
} }
fn _add_cheque_to_cashed_cheques_log(tx: &Connection, fn _add_cheque_to_cashed_cheques_log(
tx: &Connection,
cheque: &Cheque, cheque: &Cheque,
drawer_receipt: &accounts::AccountChangeReceipt, drawer_receipt: &accounts::AccountChangeReceipt,
payee_receipt: &accounts::AccountChangeReceipt) -> Result<(), Error> { payee_receipt: &accounts::AccountChangeReceipt,
) -> Result<(), Error> {
let q = " let q = "
INSERT INTO cashed_cheques( INSERT INTO cashed_cheques(
drawer_user_id, drawer_user_id,
@@ -36,7 +46,8 @@ fn _add_cheque_to_cashed_cheques_log(tx: &Connection,
) )
VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9) VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)
"; ";
let params = params![cheque.drawer_user_id, let params = params![
cheque.drawer_user_id,
cheque.drawer_account_id, cheque.drawer_account_id,
drawer_receipt.version, drawer_receipt.version,
cheque.payee_user_id, cheque.payee_user_id,
@@ -44,41 +55,60 @@ fn _add_cheque_to_cashed_cheques_log(tx: &Connection,
payee_receipt.version, payee_receipt.version,
cheque.cheque_number, cheque.cheque_number,
cheque.amount, cheque.amount,
cheque.security_id]; cheque.security_id
];
let ret = tx.execute(q, params).map_err(Error::SqlError); let ret = tx.execute(q, params).map_err(Error::SqlError);
match ret { match ret {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(Error::SqlError(rusqlite::Error::SqliteFailure(ffi::Error { code: _, extended_code: 2067 }, _))) => Err(Error::SqlError(rusqlite::Error::SqliteFailure(
Err(Error::DoubleSpendingError(format!("Cheque number {} from user {} has already been cached.", cheque.cheque_number, cheque.drawer_user_id))), ffi::Error {
Err(a) => Err(a) 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, fn cash_cheque_unsafe(
savepoint: &Savepoint,
cheque: &Cheque, cheque: &Cheque,
account_id: &AccountId) -> CustomResult<()> { account_id: &AccountId,
) -> CustomResult<()> {
if cheque.amount < 0 { 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)? { if !accounts::is_owner(
return Err(Error::InvalidDrawer(format!("The drawer is the security owner: {:?}", cheque))); &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)? { if !accounts::is_owner(&savepoint, account_id, &cheque.payee_user_id)? {
return Err(Error::InvalidPayee(format!("Trying to cash the cheque {:?} in \ return Err(Error::InvalidPayee(format!(
an account {:?} that is not owned by the payee.", cheque, account_id))); "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)?; let (drawer_receipt, payee_receipt) = _move_securities(&savepoint, cheque, account_id)?;
_add_cheque_to_cashed_cheques_log(&savepoint, _add_cheque_to_cashed_cheques_log(&savepoint, cheque, &drawer_receipt, &payee_receipt)?;
cheque,
&drawer_receipt,
&payee_receipt)?;
Ok(()) Ok(())
} }
fn cash_cheque(tx: &mut Transaction, fn cash_cheque(tx: &mut Transaction, cheque: &Cheque, account_id: &AccountId) -> CustomResult<()> {
cheque: &Cheque,
account_id: &AccountId) -> CustomResult<()> {
let mut savepoint = tx.savepoint().map_err(Error::SqlError)?; let mut savepoint = tx.savepoint().map_err(Error::SqlError)?;
let ret = cash_cheque_unsafe(&savepoint, cheque, account_id); let ret = cash_cheque_unsafe(&savepoint, cheque, account_id);
match ret { match ret {
@@ -86,13 +116,10 @@ fn cash_cheque(tx: &mut Transaction,
savepoint.rollback().map_err(Error::SqlError)?; savepoint.rollback().map_err(Error::SqlError)?;
ret ret
} }
Ok(_) => { Ok(_) => savepoint.commit().map_err(Error::SqlError),
savepoint.commit().map_err(Error::SqlError)
}
} }
} }
#[cfg(test)] #[cfg(test)]
mod test_caching_cheques { mod test_caching_cheques {
use rusqlite::Connection; use rusqlite::Connection;
@@ -118,7 +145,8 @@ mod test_caching_cheques {
let sec = securities.get(0).unwrap(); let sec = securities.get(0).unwrap();
let drawer = users.get(0).unwrap(); let drawer = users.get(0).unwrap();
let payee = users.get(1).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(); let payee_account = create_checking_account(&tx, &sec.id(), &payee.id()).unwrap();
tx.commit().unwrap(); tx.commit().unwrap();
@@ -127,9 +155,13 @@ mod test_caching_cheques {
(conn, security_emitter, payee, payee_account.id()) (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) { fn _create_100_secs_in_payee_account(
let cheque = Cheque::new( tx: &mut Transaction,
security_emitter.clone(), payee.clone(), 100, 99); 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(); cash_cheque(tx, &cheque, &payee_account).unwrap();
} }
@@ -144,7 +176,8 @@ mod test_caching_cheques {
let mut tx = conn.transaction().unwrap(); let mut tx = conn.transaction().unwrap();
_create_100_secs_in_payee_account(&mut tx, &security_emitter, &payee, &payee_account); _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(); tx.commit().unwrap();
@@ -154,14 +187,12 @@ mod test_caching_cheques {
return (conn, drawer, new_payee, reg_account.id()); return (conn, drawer, new_payee, reg_account.id());
} }
#[test] #[test]
fn test_happy_path_currency_emitter() -> CustomResult<()> { fn test_happy_path_currency_emitter() -> CustomResult<()> {
let (mut conn, security_emitter, payee, payee_account) = setup_security_emitter(); let (mut conn, security_emitter, payee, payee_account) = setup_security_emitter();
let mut tx = conn.transaction().unwrap(); let mut tx = conn.transaction().unwrap();
let cheque = Cheque::new( let cheque = Cheque::new(security_emitter, payee, 1000, 99);
security_emitter, payee, 1000, 99);
cash_cheque(&mut tx, &cheque, &payee_account)?; cash_cheque(&mut tx, &cheque, &payee_account)?;
tx.commit().unwrap(); tx.commit().unwrap();
@@ -178,8 +209,7 @@ mod test_caching_cheques {
let (mut conn, drawer, payee, payee_account) = setup_basic(); let (mut conn, drawer, payee, payee_account) = setup_basic();
let mut tx = conn.transaction().unwrap(); let mut tx = conn.transaction().unwrap();
let cheque = Cheque::new( let cheque = Cheque::new(drawer.clone(), payee, 25, 10001);
drawer.clone(), payee, 25, 10001);
cash_cheque(&mut tx, &cheque, &payee_account)?; cash_cheque(&mut tx, &cheque, &payee_account)?;
@@ -192,16 +222,22 @@ mod test_caching_cheques {
Ok(()) 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 mut tx = conn.transaction().unwrap();
let cheque = Cheque::new( let cheque = Cheque::new(drawer, payee, -1, 99);
drawer, payee, -1, 99);
let ret = cash_cheque(&mut tx, &cheque, &payee_account); let ret = cash_cheque(&mut tx, &cheque, &payee_account);
match ret { match ret {
Err(Error::InvalidAmount(_)) => Ok(()), 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) 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 mut tx = conn.transaction().unwrap();
let cheque = Cheque::new( let cheque = Cheque::new(drawer, payee, 10, 99);
drawer,
payee,
10,
99,
);
cash_cheque(&mut tx, &cheque, &payee_account)?; cash_cheque(&mut tx, &cheque, &payee_account)?;
tx.commit().unwrap(); tx.commit().unwrap();
@@ -234,7 +270,9 @@ mod test_caching_cheques {
let ret = cash_cheque(&mut tx, &cheque, &payee_account); let ret = cash_cheque(&mut tx, &cheque, &payee_account);
match ret { match ret {
Err(Error::DoubleSpendingError(_)) => Ok(()), 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) 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 mut tx = conn.transaction().unwrap();
let not_currency_owner_user_id = UserId::from_id(drawer.0.get_id() + 72623); 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 not_currency_owner: Drawer = (not_currency_owner_user_id, drawer.1, drawer.2);
let cheque = Cheque::new( let cheque = Cheque::new(not_currency_owner, payee, 100, 99);
not_currency_owner,
payee,
100,
99,
);
let ret = cash_cheque(&mut tx, &cheque, &payee_account); let ret = cash_cheque(&mut tx, &cheque, &payee_account);
match ret { match ret {
Err(Error::InvalidDrawer(_)) => Ok(()), 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) 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 conn, security_emitter, payee, payee_account) = setup_security_emitter();
let mut tx = conn.transaction().unwrap(); let mut tx = conn.transaction().unwrap();
let wrong_payee_account = &security_emitter.1; let wrong_payee_account = &security_emitter.1;
let cheque = Cheque::new( let cheque = Cheque::new(security_emitter.clone(), payee.clone(), 1000, 99);
security_emitter.clone(), payee.clone(), 1000, 99);
let ret = cash_cheque(&mut tx, &cheque, wrong_payee_account); let ret = cash_cheque(&mut tx, &cheque, wrong_payee_account);
match ret { match ret {
Err(Error::InvalidPayee(_)) => Ok(()), Err(Error::InvalidPayee(_)) => Ok(()),
_ => Err(Error::Testing("Expected invalid payee here.".to_string())) _ => Err(Error::Testing("Expected invalid payee here.".to_string())),
} }
} }
#[test] #[test]
fn test_invalid_payee_security_emitter_cheque() -> CustomResult<()> { fn test_invalid_payee_security_emitter_cheque() -> CustomResult<()> {
let (mut conn, security_emitter, payee, payee_account) = setup_security_emitter(); let (mut conn, security_emitter, payee, payee_account) = setup_security_emitter();
+2 -3
View File
@@ -3,12 +3,12 @@ mod views;
use actix_utils::future::{ready, Ready}; use actix_utils::future::{ready, Ready};
use minijinja; use minijinja;
use minijinja_autoreload::AutoReloader; use minijinja_autoreload::AutoReloader;
use std::{collections::HashMap, env, fs, io, path::PathBuf};
use std::io::{Error, ErrorKind}; use std::io::{Error, ErrorKind};
use std::path::Path; use std::path::Path;
use std::{collections::HashMap, env, fs, io, path::PathBuf};
use actix_web::{ use actix_web::{
dev::{ServiceResponse}, dev::ServiceResponse,
error, error,
http::{header::ContentType, StatusCode}, http::{header::ContentType, StatusCode},
middleware::{ErrorHandlerResponse, ErrorHandlers, Logger}, middleware::{ErrorHandlerResponse, ErrorHandlers, Logger},
@@ -54,7 +54,6 @@ impl FromRequest for MiniJinjaRenderer {
} }
} }
#[tokio::main] #[tokio::main]
pub async fn web_ui_main(port: u16, enable_template_autoreload: bool) -> std::io::Result<()> { 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. // The closure is invoked every time the environment is outdated to recreate it.
+2 -2
View File
@@ -1,6 +1,6 @@
use std::collections::HashMap;
use actix_web::{Responder, web};
use crate::webui::MiniJinjaRenderer; use crate::webui::MiniJinjaRenderer;
use actix_web::{web, Responder};
use std::collections::HashMap;
#[actix_web::get("/")] #[actix_web::get("/")]
pub async fn index( pub async fn index(
Executable
+3
View File
@@ -0,0 +1,3 @@
#!/usr/bin/env bash
find ${PROJECT_ROOT}/src -name '*.rs' | xargs rustfmt --edition 2021