Skip to content

Commit 594f74f

Browse files
committed
Made into workspace, fixed example and a bug with transactions
1 parent 8db25be commit 594f74f

File tree

20 files changed

+127
-1447
lines changed

20 files changed

+127
-1447
lines changed

Cargo.lock

Lines changed: 0 additions & 736 deletions
This file was deleted.

Cargo.toml

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,7 @@
1-
[package]
2-
name = "atm-machine"
3-
version = "0.1.0"
4-
authors = ["Emil Gardström <[email protected]>"]
1+
[workspace]
2+
members = [
3+
"atm",
4+
"atm-web",
5+
"examples/basic",
6+
]
57

6-
[dependencies]
7-
uuid = { version = "*", features = ["serde", "v4"] }
8-
rand = "*"
9-
rust-argon2 = "*"
10-
chrono = { version = "*", features = ["serde"] }
11-
serde = "*"
12-
serde_derive = "*"
13-
base64 = "*"
14-
error-chain = "*"
15-
slog = "*"
16-
cursive = "*"
17-
diesel = { version = "*", features = ["postgres", "chrono", "uuid"] }
18-
diesel_codegen = { version = "*", features = ["postgres"] }
19-
dotenv = "*"
20-
steel-cent = { path = "steel-cent", features = ["serde_serialize"] }
21-
clippy = {version = "*", optional = true}
22-
byteorder = "*"
23-
24-
[[example]]
25-
name = "basic"
26-
path = "examples/basic/src/main.rs"

atm-web/Cargo.toml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "atm-web"
3+
version = "0.1.0"
4+
authors = ["Emil Gardström <[email protected]>"]
5+
6+
[dependencies]
7+
atm-lib = { path = "../atm"}
8+
diesel = "*"
9+
r2d2 = "*"
10+
r2d2-diesel = "*"
11+
rocket = "*"
12+
rocket_contrib = {version = "*", default-features = false, features = ["json", "tera_templates", "uuid"]}
13+
rocket_codegen = "*"
14+
serde_derive = "*"
15+
serde_json = "*"

atm-web/src/main.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#![feature(plugin)]
2+
#![plugin(rocket_codegen)]
3+
4+
extern crate atm_lib;
5+
6+
extern crate diesel;
7+
8+
extern crate rocket;
9+
extern crate rocket_contrib;
10+
11+
extern crate r2d2;
12+
extern crate r2d2_diesel;
13+
14+
#[macro_use]
15+
extern crate serde_derive;
16+
extern crate serde_json;
17+
18+
fn main() {
19+
println!("Hello, world!");
20+
}

atm-web/templates/account_view.html.tera

Whitespace-only changes.

atm/Cargo.toml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[package]
2+
name = "atm-lib"
3+
version = "0.1.0"
4+
authors = ["Emil Gardström <[email protected]>"]
5+
6+
[dependencies]
7+
uuid = { version = "*", features = ["serde", "v4"] }
8+
rand = "*"
9+
rust-argon2 = "*"
10+
chrono = { version = "*", features = ["serde"] }
11+
serde = "*"
12+
serde_derive = "*"
13+
base64 = "*"
14+
error-chain = "*"
15+
slog = "*"
16+
cursive = "*"
17+
diesel = { version = "*", features = ["postgres", "chrono", "uuid"] }
18+
diesel_codegen = { version = "*", features = ["postgres"] }
19+
dotenv = "*"
20+
steel-cent = { path = "../steel-cent", features = ["serde_serialize"] }
21+
clippy = {version = "*", optional = true}
22+
byteorder = "*"

src/account/mod.rs renamed to atm/src/account/mod.rs

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,14 @@ impl NewAccount {
3939
funds: F,
4040
password: T)
4141
-> Result<NewAccount> {
42-
//#[cfg(all(debug_assertions, not(test)))] // Disable this print on test, but enable otherwise when in debug
43-
//#println!("WARNING! Please note that currently all accounts are using plaintext \
44-
//# passwords\nBuild in --release to use scrypt");
4542
let id = Uuid::new_v4();
46-
47-
//#[cfg(not(debug_assertions))]
4843
let pw_hash: String = {
49-
let mut rng = OsRng::new()?;
44+
let mut rng = OsRng::new().chain_err(|| "While making random generator")?;
5045

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

5651
};
5752
//#[cfg(debug_assertions)]
@@ -96,7 +91,9 @@ impl Account {
9691

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

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

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

137136
}
138137
}
File renamed without changes.
File renamed without changes.

src/error.rs renamed to atm/src/error.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22
use argon2;
33
use diesel;
44
use dotenv;
5+
56
error_chain! {
7+
links {
8+
DotEnv(dotenv::Error, dotenv::ErrorKind);
9+
}
610
foreign_links {
711
Fmt(::std::fmt::Error);
8-
Io(::std::io::Error);
912
Argon2(argon2::Error);
10-
DotEnv(dotenv::DotenvError);
13+
1114
VarErr(::std::env::VarError);
1215
DieselConn(diesel::ConnectionError);
1316
Diesel(diesel::result::Error);

src/interface/diesel_conn.rs renamed to atm/src/interface/diesel_conn.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ pub fn establish_connection() -> Result<PgConnection> {
1313
dotenv().chain_err(|| "While setting up dotenv")?;
1414

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

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

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

41-
pub fn find_by_owner(conn: &PgConnection, owner: Owner) -> Result<Vec<Account>> {
41+
pub fn all_transactions(conn: &PgConnection) -> Result<Vec<Transaction>> {
42+
trans_table.load(conn).map_err(|e| e.into())
43+
}
44+
45+
pub fn accounts_by_owner(conn: &PgConnection, owner: &Owner) -> Result<Vec<Account>> {
4246
acc_table.filter(acc_dsl::owner_id.eq(owner.id())).get_results(conn).map_err(|e| e.into())
4347
}
48+
49+
pub fn transactions_from(conn: &PgConnection, account: &Account) -> Result<Vec<Transaction>> {
50+
trans_table
51+
.filter(
52+
trans_dsl::sender.eq(account.id())
53+
.or(trans_dsl::recipient.eq(account.id())))
54+
.get_results(conn).map_err(|e| e.into())
55+
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

src/transaction/mod.rs renamed to atm/src/transaction/mod.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,9 @@ impl From<TransactionE> for NewTransaction {
214214
}
215215

216216
impl Transaction {
217+
pub fn serial(&self) -> i32 {
218+
self.serial
219+
}
217220
/// As account with id `id`, how much does this transaction affect me?
218221
pub fn get_change(&self, id: &Uuid) -> error::Result<Option<Money>> {
219222
let amount = Money::of_minor(
@@ -223,7 +226,6 @@ impl Transaction {
223226
match self.trans_type {
224227
TransactionType::Deposit => {
225228
if &self.sender == id {
226-
// What does from even do here?
227229
return Ok(Some(amount));
228230
}
229231
Ok(None)
@@ -237,7 +239,12 @@ impl Transaction {
237239
return Ok(Some(amount));
238240
};
239241
if &self.recipient.unwrap() == id {
240-
return Ok(Some(amount));
242+
return Ok(
243+
Some(
244+
amount.checked_neg()
245+
.expect("This error shouldn't happen, but not sure how to fix.")
246+
)
247+
);
241248
};
242249
Ok(None)
243250
}
@@ -246,7 +253,12 @@ impl Transaction {
246253
bail!("Transaction of type `{:?}` was invalid, recipient was null", self.trans_type );
247254
}
248255
if &self.recipient.unwrap() == id {
249-
return Ok(Some(amount));
256+
return Ok(
257+
Some(
258+
amount.checked_neg()
259+
.expect("This error shouldn't happen, but not sure how to fix.")
260+
)
261+
);
250262
};
251263
Ok(None)
252264
}

0 commit comments

Comments
 (0)