Skip to content

Commit

Permalink
Made into workspace, fixed example and a bug with transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
Emilgardis committed Mar 25, 2017
1 parent 8db25be commit 594f74f
Show file tree
Hide file tree
Showing 20 changed files with 127 additions and 1,447 deletions.
736 changes: 0 additions & 736 deletions Cargo.lock

This file was deleted.

31 changes: 6 additions & 25 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,26 +1,7 @@
[package]
name = "atm-machine"
version = "0.1.0"
authors = ["Emil Gardström <[email protected]>"]
[workspace]
members = [
"atm",
"atm-web",
"examples/basic",
]

[dependencies]
uuid = { version = "*", features = ["serde", "v4"] }
rand = "*"
rust-argon2 = "*"
chrono = { version = "*", features = ["serde"] }
serde = "*"
serde_derive = "*"
base64 = "*"
error-chain = "*"
slog = "*"
cursive = "*"
diesel = { version = "*", features = ["postgres", "chrono", "uuid"] }
diesel_codegen = { version = "*", features = ["postgres"] }
dotenv = "*"
steel-cent = { path = "steel-cent", features = ["serde_serialize"] }
clippy = {version = "*", optional = true}
byteorder = "*"

[[example]]
name = "basic"
path = "examples/basic/src/main.rs"
15 changes: 15 additions & 0 deletions atm-web/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "atm-web"
version = "0.1.0"
authors = ["Emil Gardström <[email protected]>"]

[dependencies]
atm-lib = { path = "../atm"}
diesel = "*"
r2d2 = "*"
r2d2-diesel = "*"
rocket = "*"
rocket_contrib = {version = "*", default-features = false, features = ["json", "tera_templates", "uuid"]}
rocket_codegen = "*"
serde_derive = "*"
serde_json = "*"
20 changes: 20 additions & 0 deletions atm-web/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#![feature(plugin)]
#![plugin(rocket_codegen)]

extern crate atm_lib;

extern crate diesel;

extern crate rocket;
extern crate rocket_contrib;

extern crate r2d2;
extern crate r2d2_diesel;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;

fn main() {
println!("Hello, world!");
}
Empty file.
22 changes: 22 additions & 0 deletions atm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "atm-lib"
version = "0.1.0"
authors = ["Emil Gardström <[email protected]>"]

[dependencies]
uuid = { version = "*", features = ["serde", "v4"] }
rand = "*"
rust-argon2 = "*"
chrono = { version = "*", features = ["serde"] }
serde = "*"
serde_derive = "*"
base64 = "*"
error-chain = "*"
slog = "*"
cursive = "*"
diesel = { version = "*", features = ["postgres", "chrono", "uuid"] }
diesel_codegen = { version = "*", features = ["postgres"] }
dotenv = "*"
steel-cent = { path = "../steel-cent", features = ["serde_serialize"] }
clippy = {version = "*", optional = true}
byteorder = "*"
35 changes: 17 additions & 18 deletions src/account/mod.rs → atm/src/account/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,14 @@ impl NewAccount {
funds: F,
password: T)
-> Result<NewAccount> {
//#[cfg(all(debug_assertions, not(test)))] // Disable this print on test, but enable otherwise when in debug
//#println!("WARNING! Please note that currently all accounts are using plaintext \
//# passwords\nBuild in --release to use scrypt");
let id = Uuid::new_v4();

//#[cfg(not(debug_assertions))]
let pw_hash: String = {
let mut rng = OsRng::new()?;
let mut rng = OsRng::new().chain_err(|| "While making random generator")?;

let salt: Vec<u8> = rng.gen_iter::<u8>().take(16).collect();
let pw = password.as_ref().as_bytes();
let config = argon2::Config::default();
argon2::hash_encoded(pw, salt.as_slice(), &config)?.to_owned()
argon2::hash_encoded(pw, salt.as_slice(), &config).chain_err(|| "While making encoded hash of password")?.to_owned()

};
//#[cfg(debug_assertions)]
Expand Down Expand Up @@ -96,7 +91,9 @@ impl Account {

pub fn open<T: AsRef<str>>(&mut self, password: T) -> Result<()> {
//#[cfg(not(debug_assertions))]
let password_matches = argon2::verify_encoded(self.pw_hash.as_str(), password.as_ref().as_bytes())
let password_matches = argon2::verify_encoded(
self.pw_hash.as_str(), password.as_ref().as_bytes()
)
.chain_err(|| format!("Failed to check password for {}.", self.id()))?;
//#[cfg(debug_assertions)]
//#let password_matches = {
Expand All @@ -110,29 +107,31 @@ impl Account {
bail!("Password didn't match!")
}

pub fn funds(&self) -> HashMap<steel_cent::currency::Currency, i64> {
pub fn funds(&self, conn: &PgConnection) -> Result<HashMap<steel_cent::currency::Currency, i64>> {
// TODO: Should be stored as a vec of all their specific transactions, and maybe
// optimised so that we neer really do 20+ searches.
// let mut map = HashMap::new();
// for trans in &self.account.transactions {
// if let Some(money) = trans.get_change(&self.id) {
// *map.entry(money.currency).or_insert(0) += money.minor_amount()
// }
//
// map
let mut map = HashMap::new();
// Carrier on for and if let is wierd...
for trans in diesel_conn::transactions_from(conn, self)
.chain_err(|| format!("While trying to get transactions affecting account {:?}", self.id()))? {
if let Some(money) = trans.get_change(&self.id)
.chain_err(|| format!("While calculating value of transaction id: {}", trans.serial()))? {
*map.entry(money.currency).or_insert(0) += money.minor_amount()
}
}
Ok(map)
// for trans in &self.account.transactions {
// if let Some((curr, amount)) = trans.get_change(&self.id){
// *map.entry(curr).or_insert(0.0) += amount;
// }
//
// map.into_iter().map(|(curr, amount)| Money::new(curr, amount)).collect()
// map
unimplemented!()
}

pub fn transfer(&self, conn: &PgConnection, other: &mut Account, amount: Money) -> Result<Transaction> {
let trans = NewTransaction::transfer(self.id().clone(), other.id().clone(), amount);
diesel_conn::execute_transaction(conn, trans)
diesel_conn::execute_transaction(conn, trans).chain_err(|| "Transaction failed")

}
}
Expand Down
File renamed without changes.
File renamed without changes.
7 changes: 5 additions & 2 deletions src/error.rs → atm/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@
use argon2;
use diesel;
use dotenv;

error_chain! {
links {
DotEnv(dotenv::Error, dotenv::ErrorKind);
}
foreign_links {
Fmt(::std::fmt::Error);
Io(::std::io::Error);
Argon2(argon2::Error);
DotEnv(dotenv::DotenvError);

VarErr(::std::env::VarError);
DieselConn(diesel::ConnectionError);
Diesel(diesel::result::Error);
Expand Down
18 changes: 15 additions & 3 deletions src/interface/diesel_conn.rs → atm/src/interface/diesel_conn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ pub fn establish_connection() -> Result<PgConnection> {
dotenv().chain_err(|| "While setting up dotenv")?;

let database_url = env::var("DATABASE_URL").chain_err(|| "While getting env var DATABASE_URL")?;
PgConnection::establish(&database_url).map_err(|e| e.into())
PgConnection::establish(&database_url).map_err::<Error, _>(|e| e.into()).chain_err(|| "Couldn't establish connection")
}

pub fn add_account(conn: &PgConnection, account: NewAccount) -> Result<Account> {
diesel::insert(&account).into(acc_table)
.execute(conn)
.chain_err(|| "While trying to execute insert")?;
acc_table.find(account.id()).first(conn).map_err(|e| e.into())
acc_table.find(account.id()).first(conn).map_err::<Error, _>(|e| e.into()).chain_err(|| "Couldn't find newly added accout")
}

pub fn execute_transaction(conn: &PgConnection, ntrans: NewTransaction) -> Result<Transaction> {
Expand All @@ -38,6 +38,18 @@ pub fn all_accounts(conn: &PgConnection) -> Result<Vec<Account>> {
acc_table.load(conn).map_err(|e| e.into())
}

pub fn find_by_owner(conn: &PgConnection, owner: Owner) -> Result<Vec<Account>> {
pub fn all_transactions(conn: &PgConnection) -> Result<Vec<Transaction>> {
trans_table.load(conn).map_err(|e| e.into())
}

pub fn accounts_by_owner(conn: &PgConnection, owner: &Owner) -> Result<Vec<Account>> {
acc_table.filter(acc_dsl::owner_id.eq(owner.id())).get_results(conn).map_err(|e| e.into())
}

pub fn transactions_from(conn: &PgConnection, account: &Account) -> Result<Vec<Transaction>> {
trans_table
.filter(
trans_dsl::sender.eq(account.id())
.or(trans_dsl::recipient.eq(account.id())))
.get_results(conn).map_err(|e| e.into())
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
18 changes: 15 additions & 3 deletions src/transaction/mod.rs → atm/src/transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,9 @@ impl From<TransactionE> for NewTransaction {
}

impl Transaction {
pub fn serial(&self) -> i32 {
self.serial
}
/// As account with id `id`, how much does this transaction affect me?
pub fn get_change(&self, id: &Uuid) -> error::Result<Option<Money>> {
let amount = Money::of_minor(
Expand All @@ -223,7 +226,6 @@ impl Transaction {
match self.trans_type {
TransactionType::Deposit => {
if &self.sender == id {
// What does from even do here?
return Ok(Some(amount));
}
Ok(None)
Expand All @@ -237,7 +239,12 @@ impl Transaction {
return Ok(Some(amount));
};
if &self.recipient.unwrap() == id {
return Ok(Some(amount));
return Ok(
Some(
amount.checked_neg()
.expect("This error shouldn't happen, but not sure how to fix.")
)
);
};
Ok(None)
}
Expand All @@ -246,7 +253,12 @@ impl Transaction {
bail!("Transaction of type `{:?}` was invalid, recipient was null", self.trans_type );
}
if &self.recipient.unwrap() == id {
return Ok(Some(amount));
return Ok(
Some(
amount.checked_neg()
.expect("This error shouldn't happen, but not sure how to fix.")
)
);
};
Ok(None)
}
Expand Down
Loading

0 comments on commit 594f74f

Please sign in to comment.