diff --git a/src/db/_securities.rs b/src/db/_securities.rs index ad2d660..e138e7d 100644 --- a/src/db/_securities.rs +++ b/src/db/_securities.rs @@ -2,6 +2,7 @@ use rusqlite::{params, Connection, Result, Row, ToSql, Transaction}; use serde::Serialize; use crate::db::_external_id::{Id, SecurityId}; +use crate::util::{CustomResult, Error}; #[derive(Debug, Serialize, PartialEq)] @@ -61,32 +62,33 @@ pub struct NewSecurity { pub name: String, } -pub fn create_security(tx: &Transaction, sec: &NewSecurity) -> Result { +pub fn create_security(tx: &Transaction, sec: &NewSecurity) -> CustomResult { let q = "INSERT INTO securities(name, symbol, security_type) VALUES(?1, ?2, ?3)"; let params = (&sec.name, &sec.symbol, &sec.security_type); - tx.execute(q, params)?; + tx.execute(q, params).map_err(Error::SqlError)?; let new_sec_id = tx.last_insert_rowid() as i32; return get_security_by_id(tx, new_sec_id); } -pub fn get_security_by_id(tx: &Transaction, id: i32) -> Result { +pub fn get_security_by_id(tx: &Transaction, id: i32) -> CustomResult { let q = "SELECT id AS sec_id, security_type AS sec_security_type, symbol AS sec_symbol FROM securities WHERE id = ?1"; - tx.query_row(q, params![id], Security::from_row) + tx.query_row(q, params![id], Security::from_row).map_err(Error::SqlError) } -pub fn list_securities(conn: &Connection) -> Result> { +pub fn list_securities(conn: &Connection) -> CustomResult> { let q = "SELECT id AS sec_id, security_type AS sec_security_type, symbol AS sec_symbol FROM securities ORDER BY id ASC"; - let mut stmt = conn.prepare(q)?; + let mut stmt = conn.prepare(q).map_err(Error::SqlError)?; let ret: Vec = stmt - .query_map([], Security::from_row)? + .query_map([], Security::from_row) + .map_err(Error::SqlError)? .filter(Result::is_ok) .map(Result::unwrap) .collect(); @@ -130,25 +132,26 @@ mod test_securities { } #[test] - fn test_create_security() -> Result<(), rusqlite::Error> { + fn test_create_security() -> CustomResult<()> { let (mut conn, _users) = setup(); let new_sec = mock_currency_1(); - let tx = conn.transaction()?; + let tx = conn.transaction().unwrap(); let sec = create_security(&tx, &new_sec)?; assert_eq!(sec.symbol, new_sec.symbol); - tx.commit() + tx.commit().unwrap(); + Ok(()) } #[test] - fn test_list_security() -> Result<(), rusqlite::Error> { + fn test_list_security() -> CustomResult<()> { let (mut conn, _users) = setup(); assert_eq!(0, list_securities(&conn)?.len()); let sec = mock_currency_1(); - let tx = conn.transaction()?; + let tx = conn.transaction().unwrap(); create_security(&tx, &sec)?; - tx.commit()?; + tx.commit().unwrap(); let ret = list_securities(&conn)?; let expt = Security { id: 1, @@ -164,9 +167,9 @@ mod test_securities { security_type: SecurityType::Bond, symbol: "B".to_string(), }; - let tx = conn.transaction()?; + let tx = conn.transaction().unwrap(); create_security(&tx, &sec)?; - tx.commit()?; + tx.commit().unwrap(); let ret = list_securities(&conn)?; assert_eq!(2, ret.len()); assert_eq!(&expt, ret.get(1).unwrap()); diff --git a/src/db/_test_utils.rs b/src/db/_test_utils.rs index 6ddf43b..122f375 100644 --- a/src/db/_test_utils.rs +++ b/src/db/_test_utils.rs @@ -24,19 +24,19 @@ pub fn mock_currency_2() -> NewSecurity { }; } -pub fn setup_users(tx: &Transaction) -> Result> { +pub fn setup_users(tx: &Transaction) -> CustomResult> { let user_1 = _users::create_user(tx, &"bernard".to_string(), &"123".to_string())?; let user_2 = _users::create_user(tx, &"sam".to_string(), &"abc".to_string())?; return Ok(vec![user_1, user_2]); } -pub fn setup_securities(tx: &Transaction, _owner: &UserId) -> Result> { +pub fn setup_securities(tx: &Transaction, _owner: &UserId) -> CustomResult> { let sec_1 = _securities::create_security(tx, &mock_currency_1())?; let sec_2 = _securities::create_security(tx, &mock_currency_2())?; return Ok(vec![sec_1, sec_2]); } -pub fn setup_users_and_securities(tx: &Transaction) -> Result<(Vec, Vec)> { +pub fn setup_users_and_securities(tx: &Transaction) -> CustomResult<(Vec, Vec)> { let users = setup_users(tx)?; let securities = setup_securities(tx, &users.get(0).unwrap().id())?; Ok((users, securities)) diff --git a/src/db/_users.rs b/src/db/_users.rs index 35997cc..f8eca29 100644 --- a/src/db/_users.rs +++ b/src/db/_users.rs @@ -1,6 +1,7 @@ use crate::db::_external_id::{Id, UserId}; use rusqlite::{params, Connection, Result, Row, Transaction}; use serde::Serialize; +use crate::util::{CustomResult, Error}; #[derive(Debug, Serialize)] pub struct User { @@ -15,11 +16,11 @@ impl User { } } -pub fn create_user(tx: &Transaction, name: &String, public_key: &String) -> Result { +pub fn create_user(tx: &Transaction, name: &String, public_key: &String) -> CustomResult { tx.execute( "INSERT INTO users (name, public_key) VALUES (?1, ?2)", (name, public_key), - )?; + ).map_err(Error::SqlError)?; return get_user_by_id(tx, tx.last_insert_rowid() as i32); } @@ -31,17 +32,18 @@ fn _user_from_row(row: &Row) -> Result { }) } -fn get_user_by_id(tx: &Transaction, id: i32) -> Result { +fn get_user_by_id(tx: &Transaction, id: i32) -> CustomResult { let q = "SELECT id, name, public_key FROM users WHERE id = ?1"; - tx.query_row(q, params![id], _user_from_row) + tx.query_row(q, params![id], _user_from_row).map_err(Error::SqlError) } -pub fn list_users(conn: &Connection) -> Result> { - let mut stmt = conn.prepare("SELECT id, name, public_key FROM users")?; +pub fn list_users(conn: &Connection) -> CustomResult> { + let mut stmt = conn.prepare("SELECT id, name, public_key FROM users").map_err(Error::SqlError)?; let ret: Vec = stmt - .query_map([], _user_from_row)? + .query_map([], _user_from_row) + .map_err(Error::SqlError)? .filter(Result::is_ok) .map(Result::unwrap) .collect(); diff --git a/src/main.rs b/src/main.rs index 7eaa5c7..dc8302e 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; @@ -12,6 +12,7 @@ use db::securities::list_securities; use crate::db::users::{create_user, list_users}; use crate::event_processor::process_event_files; use crate::migration::apply_migrations; +use crate::util::{CustomResult, Error}; use crate::webui::web_ui_main; mod db; @@ -37,15 +38,15 @@ impl Output { } trait CommandLineUserLogic { - fn create_user(&mut self, conn: &mut Connection, name: &String, public_key: &String); + fn create_user(&mut self, conn: &mut Connection, name: &String, public_key: &String) -> CustomResult<()>; - fn list_user(&mut self, conn: &Connection); + fn list_user(&mut self, conn: &Connection) -> CustomResult<()>; - fn list_securities(&mut self, conn: &Connection); + fn list_securities(&mut self, conn: &Connection) -> CustomResult<()>; - fn process_events(&mut self, conn: &mut Connection, files: ValuesRef); + fn process_events(&mut self, conn: &mut Connection, files: ValuesRef) -> CustomResult<()>; - 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) -> CustomResult<()>; } fn verbosity_arg() -> Arg { @@ -178,34 +179,34 @@ fn process_new_user_command_line( conn: &mut Connection, m: &ArgMatches, logic: &mut dyn CommandLineUserLogic, -) { +) -> CustomResult<()> { debug!("Processing new user command line {:?}.", m); let name = m.get_one::("name").unwrap(); let pk = m.get_one::("public_key").unwrap(); - logic.create_user(conn, name, pk); + logic.create_user(conn, name, pk) } fn process_list_user_command_line( conn: &Connection, m: &ArgMatches, logic: &mut dyn CommandLineUserLogic, -) { +) -> CustomResult<()>{ debug!("Processing list users command line {:?}.", m); - logic.list_user(conn); + logic.list_user(conn) } fn process_user_command_line( conn: &mut Connection, m: &ArgMatches, logic: &mut dyn CommandLineUserLogic, -) { +) -> CustomResult<()> { debug!("Processing user command line {:?}.", m); match m.subcommand() { Some(("new", new_user_match)) => { - process_new_user_command_line(conn, new_user_match, logic); + process_new_user_command_line(conn, new_user_match, logic) } Some(("ls", list_user_match)) => { - process_list_user_command_line(conn, list_user_match, logic); + process_list_user_command_line(conn, list_user_match, logic) } _ => unreachable!(), } @@ -215,46 +216,46 @@ fn process_list_securities_command_line( conn: &Connection, m: &ArgMatches, logic: &mut dyn CommandLineUserLogic, -) { +) -> CustomResult<()>{ debug!("Processing list securities command line {:?}.", m); - logic.list_securities(conn); + logic.list_securities(conn) } fn process_process_events_command_line( conn: &mut Connection, m: &ArgMatches, logic: &mut dyn CommandLineUserLogic, -) { +) -> CustomResult<()> { debug!("Processing process event command line {:?}.", m); let mut files = m.get_many::("PATH").unwrap(); if files.any(|x| !x.exists()) { error!("Some passed files do not exists. Existing right now."); - return; + return Err(Error::UserInputError("Some passed files do not exists. Existing right now.".to_string())); } - logic.process_events(conn, files); + logic.process_events(conn, files) } fn process_run_wui_command_line( conn: &mut Connection, m: &ArgMatches, logic: &mut dyn CommandLineUserLogic, -) { +) -> CustomResult<()> { debug!("Processing run wui command line {:?}.", m); let port = m.get_one::("port").unwrap_or(&2222); let enable_template_autoreload = m.get_flag("enable-template-autoreload"); - logic.run_webui(conn, *port, enable_template_autoreload); + logic.run_webui(conn, *port, enable_template_autoreload) } fn process_securities_command_line( conn: &Connection, m: &ArgMatches, logic: &mut dyn CommandLineUserLogic, -) { +) -> CustomResult<()>{ debug!("Processing securities command line {:?}.", m); match m.subcommand() { Some(("ls", list_securities_match)) => { - process_list_securities_command_line(conn, list_securities_match, logic); + process_list_securities_command_line(conn, list_securities_match, logic) } _ => unreachable!(), } @@ -264,11 +265,11 @@ fn process_events_command_line( conn: &mut Connection, m: &ArgMatches, logic: &mut dyn CommandLineUserLogic, -) { +) -> CustomResult<()>{ debug!("Processing events command line {:?}.", m); match m.subcommand() { Some(("process", process_events_match)) => { - process_process_events_command_line(conn, process_events_match, logic); + process_process_events_command_line(conn, process_events_match, logic) } _ => unreachable!(), } @@ -278,11 +279,11 @@ fn process_wui_command_line( conn: &mut Connection, m: &ArgMatches, logic: &mut dyn CommandLineUserLogic, -) { +) -> CustomResult<()> { debug!("Processing wui command line {:?}.", m); match m.subcommand() { Some(("run", run_wui_match)) => { - process_run_wui_command_line(conn, run_wui_match, logic); + process_run_wui_command_line(conn, run_wui_match, logic) } _ => unreachable!(), } @@ -292,20 +293,20 @@ fn process_command_line( conn: &mut Connection, m: &ArgMatches, logic: &mut dyn CommandLineUserLogic, -) { +) -> CustomResult<()> { debug!("Processing command line {:?}.", m); match m.subcommand() { Some(("users", user_match)) => { - process_user_command_line(conn, user_match, logic); + process_user_command_line(conn, user_match, logic) } Some(("securities", securities_match)) => { - process_securities_command_line(conn, securities_match, logic); + process_securities_command_line(conn, securities_match, logic) } Some(("events", events_match)) => { - process_events_command_line(conn, events_match, logic); + process_events_command_line(conn, events_match, logic) } Some(("wui", wui_match)) => { - process_wui_command_line(conn, wui_match, logic); + process_wui_command_line(conn, wui_match, logic) } _ => { println!("Received un parsable command. {:?}", m.subcommand()); @@ -339,20 +340,24 @@ mod cli_test { } impl CommandLineUserLogic for TestCommandLineLogic { - fn create_user(&mut self, _conn: &mut Connection, _name: &String, _public_key: &String) { + fn create_user(&mut self, _conn: &mut Connection, _name: &String, _public_key: &String) -> CustomResult<()> { self.create_user_count += 1; + Ok(()) } - fn list_user(&mut self, _conn: &Connection) { + fn list_user(&mut self, _conn: &Connection) -> CustomResult<()>{ self.list_user_count += 1; + Ok(()) } - fn list_securities(&mut self, _conn: &Connection) { + fn list_securities(&mut self, _conn: &Connection) -> CustomResult<()>{ self.list_securities_count += 1; + Ok(()) } - fn process_events(&mut self, _conn: &mut Connection, _files: ValuesRef) { + fn process_events(&mut self, _conn: &mut Connection, _files: ValuesRef) -> CustomResult<()> { self.process_events_count += 1; + Ok(()) } fn run_webui( @@ -360,8 +365,9 @@ mod cli_test { _conn: &mut Connection, _port: u16, _enable_template_autoreload: bool, - ) { + ) -> CustomResult<()> { self.run_webui_count += 1; + Ok(()) } } @@ -465,47 +471,33 @@ impl ProCommandLineLogic { } impl CommandLineUserLogic for ProCommandLineLogic { - fn create_user(&mut self, conn: &mut Connection, name: &String, public_key: &String) { - let tx = conn.transaction().unwrap(); - create_user(&tx, name, public_key).unwrap(); - tx.commit().unwrap(); + fn create_user(&mut self, conn: &mut Connection, name: &String, public_key: &String) -> CustomResult<()> { + let tx = conn.transaction().map_err(Error::SqlError)?; + create_user(&tx, name, public_key)?; + tx.commit().map_err(Error::SqlError) } - fn list_user(&mut self, conn: &Connection) { - let users = list_users(conn); - match users { - Ok(u) => { - let out = Output::success(u); - println!("{}", serde_json::to_string(&out).unwrap()); - } - Err(e) => { - println!("{:?}", e); - } - } + fn list_user(&mut self, conn: &Connection) -> CustomResult<()> { + let users = list_users(conn)?; + let out = Output::success(users); + println!("{}", serde_json::to_string(&out).unwrap()); + Ok(()) } - fn list_securities(&mut self, conn: &Connection) { - let securities = list_securities(conn); - match securities { - Ok(s) => { - let out = Output::success(s); - println!("{}", serde_json::to_string(&out).unwrap()); - } - Err(e) => { - println!("{:?}", e); - } - }; + fn list_securities(&mut self, conn: &Connection) -> CustomResult<()> { + let securities = list_securities(conn)?; + let out = Output::success(securities); + println!("{}", serde_json::to_string(&out).unwrap()); + Ok(()) } - fn process_events(&mut self, conn: &mut Connection, files: ValuesRef) { - process_event_files(conn, files).unwrap(); - - println!("fuck me"); + fn process_events(&mut self, conn: &mut Connection, files: ValuesRef) -> CustomResult<()> { + process_event_files(conn, files) } - 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) -> CustomResult<()> { info!("Serving web-ui on port {:?}", port); - web_ui_main(port, enable_template_autoreload).unwrap(); + web_ui_main(port, enable_template_autoreload) } } diff --git a/src/util.rs b/src/util.rs index 148d7b7..ddb24dc 100644 --- a/src/util.rs +++ b/src/util.rs @@ -10,6 +10,7 @@ pub enum Error { InvalidPayee(String), DoubleSpendingError(String), IOError(io::Error), + UserInputError(String), Testing(String), } diff --git a/src/webui/mod.rs b/src/webui/mod.rs index dba811b..f1f7645 100644 --- a/src/webui/mod.rs +++ b/src/webui/mod.rs @@ -1,25 +1,24 @@ #![feature(future_join)] - use std::{env, path::PathBuf}; -use crate::webui::worker::worker_loop; use actix_files; - use actix_web::{ + App, dev::ServiceResponse, error, - http::{header::ContentType, StatusCode}, - middleware::{ErrorHandlerResponse, ErrorHandlers, Logger}, - web, App, FromRequest, HttpRequest, HttpResponse, HttpServer, Responder, Result, + FromRequest, + http::{header::ContentType, StatusCode}, HttpRequest, HttpResponse, HttpServer, middleware::{ErrorHandlerResponse, ErrorHandlers, Logger}, Responder, Result, web, }; use actix_web_lab::respond::Html; use async_channel; -use futures::{pin_mut, select, FutureExt}; +use futures::{FutureExt, pin_mut, select}; use minijinja; use minijinja_autoreload::AutoReloader; +use crate::util::CustomResult; +use crate::webui::worker::worker_loop; mod views; mod worker; @@ -59,7 +58,7 @@ impl FromRequest for MiniJinjaRenderer { } #[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) -> CustomResult<()> { // The closure is invoked every time the environment is outdated to recreate it. let tmpl_reloader = AutoReloader::new(move |notifier| { let mut env: minijinja::Environment<'static> = minijinja::Environment::new(); @@ -95,8 +94,9 @@ pub async fn web_ui_main(port: u16, enable_template_autoreload: bool) -> std::io .wrap(ErrorHandlers::new().handler(StatusCode::NOT_FOUND, not_found)) .wrap(Logger::default()) }) - .workers(2) - .bind(("0.0.0.0", port))?; + .workers(2) + .bind(("0.0.0.0", port)) + .unwrap(); let t1 = server.run().fuse(); let t2 = worker_loop(r).fuse(); @@ -105,7 +105,8 @@ pub async fn web_ui_main(port: u16, enable_template_autoreload: bool) -> std::io select! { x = t1 => x, y = t2 => y, - } + }; + Ok(()) } /// Error handler for a 404 Page not found error. diff --git a/src/webui/views.rs b/src/webui/views.rs index 0bfa217..d484725 100644 --- a/src/webui/views.rs +++ b/src/webui/views.rs @@ -1,9 +1,9 @@ - +use actix_web::http::header::q; use actix_web::{web, HttpRequest, Responder}; use clap::builder::TypedValueParser; use log::info; use minijinja::context; - +use resource::resource_str; use serde::Deserialize; use std::collections::HashMap; @@ -26,7 +26,7 @@ pub async fn overview(tmpl_env: MiniJinjaRenderer) -> actix_web::Result>, ) -> actix_web::Result { @@ -38,7 +38,7 @@ pub async fn overview_submit_button( #[actix_web::get("/partials/actions/action-form")] pub async fn actions_partials( - _req: HttpRequest, + req: HttpRequest, tmpl_env: MiniJinjaRenderer, query: web::Query>, ) -> actix_web::Result {