mirror of https://git.envs.net/envs/clinte.git
letting errors flow up
This commit is contained in:
parent
567a66d30f
commit
fd2f770938
|
@ -1,4 +1,7 @@
|
|||
pub fn helper<T, V>(res: Result<T, V>) -> T
|
||||
// This Result is used elsewhere, not in helper()
|
||||
pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
|
||||
|
||||
pub fn helper<T, V>(res: std::result::Result<T, V>) -> T
|
||||
where
|
||||
V: std::fmt::Debug,
|
||||
{
|
||||
|
@ -17,7 +20,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn shouldnt_panic() {
|
||||
let ok: Result<&str, &str> = Ok("okay");
|
||||
let ok: std::result::Result<&str, &str> = Ok("okay");
|
||||
let rhs = helper(ok);
|
||||
assert_eq!("okay", rhs);
|
||||
}
|
||||
|
@ -25,7 +28,7 @@ mod tests {
|
|||
#[test]
|
||||
#[should_panic]
|
||||
fn should_panic() {
|
||||
let err: Result<&str, &str> = Err("oops");
|
||||
let err: std::result::Result<&str, &str> = Err("oops");
|
||||
helper(err);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,14 @@ use std::fs::File;
|
|||
use chrono::offset::Utc;
|
||||
use simplelog::*;
|
||||
|
||||
use crate::error;
|
||||
use crate::user;
|
||||
|
||||
lazy_static! {
|
||||
static ref FILE: String = format!("/tmp/clinte_{}.log", *user::NAME);
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
pub fn init() -> error::Result<()> {
|
||||
// If the log file exists on startup,
|
||||
// move and timestamp it so we get a
|
||||
// fresh log file.
|
||||
|
@ -19,7 +20,7 @@ pub fn init() {
|
|||
let time = Utc::now().to_rfc3339();
|
||||
new_file.push_str(".");
|
||||
new_file.push_str(&time);
|
||||
fs::rename(FILE.clone(), new_file).unwrap();
|
||||
fs::rename(FILE.clone(), new_file)?;
|
||||
}
|
||||
|
||||
CombinedLogger::init(vec![
|
||||
|
@ -27,10 +28,12 @@ pub fn init() {
|
|||
WriteLogger::new(
|
||||
LevelFilter::Info,
|
||||
Config::default(),
|
||||
File::create(FILE.clone()).unwrap(),
|
||||
File::create(FILE.clone())?,
|
||||
),
|
||||
])
|
||||
.expect("Unable to initialize logging");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -43,7 +46,7 @@ mod tests {
|
|||
fn init_logs() {
|
||||
let blank = " ".bytes().collect::<Vec<u8>>();
|
||||
fs::write(&*FILE, &blank).unwrap();
|
||||
init();
|
||||
init().unwrap();
|
||||
|
||||
info!("TEST LOG MESSAGE");
|
||||
let logfile = fs::read_to_string(&*FILE).unwrap();
|
||||
|
|
18
src/main.rs
18
src/main.rs
|
@ -13,7 +13,7 @@ mod logging;
|
|||
mod posts;
|
||||
mod user;
|
||||
|
||||
fn main() {
|
||||
fn main() -> error::Result<()> {
|
||||
let arg_matches = clap::App::new("clinte")
|
||||
.version(clap::crate_version!())
|
||||
.author("Ben Morrison (gbmor)")
|
||||
|
@ -24,7 +24,7 @@ fn main() {
|
|||
.get_matches();
|
||||
|
||||
let start = time::Instant::now();
|
||||
logging::init();
|
||||
logging::init()?;
|
||||
info!("clinte starting up!");
|
||||
println!("clinte v{}", clap::crate_version!());
|
||||
println!("a community notices system");
|
||||
|
@ -36,24 +36,26 @@ fn main() {
|
|||
|
||||
if arg_matches.subcommand_matches("post").is_some() {
|
||||
info!("New post...");
|
||||
posts::create(&db);
|
||||
posts::create(&db)?;
|
||||
} else if arg_matches.subcommand_matches("update").is_some() {
|
||||
let id: u32 = if let Some(val) = arg_matches.subcommand_matches("update_handler") {
|
||||
val.value_of("id").unwrap().parse().unwrap()
|
||||
val.value_of("id").unwrap().parse()?
|
||||
} else {
|
||||
0
|
||||
};
|
||||
info!("Updating post ...");
|
||||
posts::update_handler(&db, id);
|
||||
posts::update_handler(&db, id)?;
|
||||
} else if arg_matches.subcommand_matches("delete").is_some() {
|
||||
let id: u32 = if let Some(val) = arg_matches.subcommand_matches("update_handler") {
|
||||
val.value_of("id").unwrap().parse().unwrap()
|
||||
val.value_of("id").unwrap_or_else(|| "0").parse()?
|
||||
} else {
|
||||
0
|
||||
};
|
||||
info!("Deleting post");
|
||||
posts::delete_handler(&db, id);
|
||||
posts::delete_handler(&db, id)?;
|
||||
}
|
||||
|
||||
posts::display(&db);
|
||||
posts::display(&db)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
103
src/posts.rs
103
src/posts.rs
|
@ -1,17 +1,15 @@
|
|||
use std::error::Error;
|
||||
use std::io;
|
||||
|
||||
use rusqlite;
|
||||
|
||||
use crate::db;
|
||||
use crate::ed;
|
||||
use crate::error;
|
||||
use crate::user;
|
||||
|
||||
type Result<T> = std::result::Result<T, Box<dyn Error>>;
|
||||
|
||||
// Executes the sql statement that inserts a new post
|
||||
// Broken off for unit testing.
|
||||
pub fn exec_new(stmt: &mut rusqlite::Statement, title: &str, body: &str) -> Result<()> {
|
||||
pub fn exec_new(stmt: &mut rusqlite::Statement, title: &str, body: &str) -> error::Result<()> {
|
||||
stmt.execute_named(&[
|
||||
(":title", &title),
|
||||
(":author", &*user::NAME),
|
||||
|
@ -33,16 +31,15 @@ fn str_to_utf8(str: &str) -> String {
|
|||
}
|
||||
|
||||
// First handler for creating a new post.
|
||||
pub fn create(db: &db::Conn) {
|
||||
pub fn create(db: &db::Conn) -> error::Result<()> {
|
||||
let mut stmt = db
|
||||
.conn
|
||||
.prepare("INSERT INTO posts (title, author, body) VALUES (:title, :author, :body)")
|
||||
.unwrap();
|
||||
.prepare("INSERT INTO posts (title, author, body) VALUES (:title, :author, :body)")?;
|
||||
|
||||
println!();
|
||||
println!("Title of the new post: ");
|
||||
let mut title = String::new();
|
||||
io::stdin().read_line(&mut title).unwrap();
|
||||
io::stdin().read_line(&mut title)?;
|
||||
let title = str_to_utf8(title.trim());
|
||||
let title = if title.len() > 30 {
|
||||
&title[..30]
|
||||
|
@ -58,28 +55,27 @@ pub fn create(db: &db::Conn) {
|
|||
&body
|
||||
};
|
||||
|
||||
exec_new(&mut stmt, title, body).unwrap();
|
||||
exec_new(&mut stmt, title, body)?;
|
||||
|
||||
println!();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Shows the most recent posts.
|
||||
pub fn display(db: &db::Conn) {
|
||||
let mut stmt = db.conn.prepare("SELECT * FROM posts").unwrap();
|
||||
let out = stmt
|
||||
.query_map(rusqlite::NO_PARAMS, |row| {
|
||||
let id: u32 = row.get(0)?;
|
||||
let title: String = row.get(1)?;
|
||||
let author: String = row.get(2)?;
|
||||
let body: String = row.get(3)?;
|
||||
Ok(db::Post {
|
||||
id,
|
||||
title,
|
||||
author,
|
||||
body,
|
||||
})
|
||||
pub fn display(db: &db::Conn) -> error::Result<()> {
|
||||
let mut stmt = db.conn.prepare("SELECT * FROM posts")?;
|
||||
let out = stmt.query_map(rusqlite::NO_PARAMS, |row| {
|
||||
let id: u32 = row.get(0)?;
|
||||
let title: String = row.get(1)?;
|
||||
let author: String = row.get(2)?;
|
||||
let body: String = row.get(3)?;
|
||||
Ok(db::Post {
|
||||
id,
|
||||
title,
|
||||
author,
|
||||
body,
|
||||
})
|
||||
.unwrap();
|
||||
})?;
|
||||
|
||||
let mut postvec = Vec::new();
|
||||
out.for_each(|row| {
|
||||
|
@ -96,38 +92,35 @@ pub fn display(db: &db::Conn) {
|
|||
print!("{}", e);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// First handler to update posts.
|
||||
pub fn update_handler(db: &db::Conn, id: u32) {
|
||||
pub fn update_handler(db: &db::Conn, id: u32) -> error::Result<()> {
|
||||
let id_num_in = if id == 0 {
|
||||
println!();
|
||||
println!("ID number of your post to edit?");
|
||||
let mut id_num_in = String::new();
|
||||
io::stdin().read_line(&mut id_num_in).unwrap();
|
||||
id_num_in.trim().parse().unwrap()
|
||||
io::stdin().read_line(&mut id_num_in)?;
|
||||
id_num_in.trim().parse()?
|
||||
} else {
|
||||
id
|
||||
};
|
||||
|
||||
let mut get_stmt = db
|
||||
.conn
|
||||
.prepare("SELECT * FROM posts WHERE id = :id")
|
||||
.unwrap();
|
||||
let mut get_stmt = db.conn.prepare("SELECT * FROM posts WHERE id = :id")?;
|
||||
|
||||
let row = get_stmt
|
||||
.query_row_named(&[(":id", &id_num_in)], |row| {
|
||||
let title: String = row.get(1).unwrap();
|
||||
let author = row.get(2).unwrap();
|
||||
let body = row.get(3).unwrap();
|
||||
Ok(vec![title, author, body])
|
||||
})
|
||||
.unwrap();
|
||||
let row = get_stmt.query_row_named(&[(":id", &id_num_in)], |row| {
|
||||
let title: String = row.get(1)?;
|
||||
let author = row.get(2)?;
|
||||
let body = row.get(3)?;
|
||||
Ok(vec![title, author, body])
|
||||
})?;
|
||||
|
||||
if *user::NAME != row[1] {
|
||||
println!();
|
||||
println!("Username mismatch - can't update_handler post!");
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut new_title = String::new();
|
||||
|
@ -138,17 +131,18 @@ pub fn update_handler(db: &db::Conn, id: u32) {
|
|||
println!("Title: {}\n\nBody: {}", row[0], row[2]);
|
||||
println!();
|
||||
println!("Enter new title:");
|
||||
io::stdin().read_line(&mut new_title).unwrap();
|
||||
io::stdin().read_line(&mut new_title)?;
|
||||
println!();
|
||||
println!("Enter new body:");
|
||||
io::stdin().read_line(&mut new_body).unwrap();
|
||||
io::stdin().read_line(&mut new_body)?;
|
||||
println!();
|
||||
|
||||
update(&new_title, &new_body, id_num_in, &db).unwrap();
|
||||
update(&new_title, &new_body, id_num_in, &db)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Allows editing of posts - called by main::update
|
||||
pub fn update(new_title: &str, new_body: &str, id_num_in: u32, db: &db::Conn) -> Result<()> {
|
||||
pub fn update(new_title: &str, new_body: &str, id_num_in: u32, db: &db::Conn) -> error::Result<()> {
|
||||
let new_title = new_title.trim();
|
||||
let new_body = new_body.trim();
|
||||
|
||||
|
@ -164,20 +158,20 @@ pub fn update(new_title: &str, new_body: &str, id_num_in: u32, db: &db::Conn) ->
|
|||
}
|
||||
|
||||
// Helper to just run a sql statement.
|
||||
pub fn exec_stmt_no_params(stmt: &mut rusqlite::Statement) -> Result<()> {
|
||||
pub fn exec_stmt_no_params(stmt: &mut rusqlite::Statement) -> error::Result<()> {
|
||||
stmt.execute(rusqlite::NO_PARAMS)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// First handler to remove a post
|
||||
pub fn delete_handler(db: &db::Conn, id: u32) {
|
||||
pub fn delete_handler(db: &db::Conn, id: u32) -> error::Result<()> {
|
||||
let id_num_in: u32 = if id == 0 {
|
||||
println!();
|
||||
println!("ID of the post to delete?");
|
||||
let mut id_num_in = String::new();
|
||||
io::stdin().read_line(&mut id_num_in).unwrap();
|
||||
id_num_in.trim().parse().unwrap()
|
||||
io::stdin().read_line(&mut id_num_in)?;
|
||||
id_num_in.trim().parse()?
|
||||
} else {
|
||||
id
|
||||
};
|
||||
|
@ -185,21 +179,20 @@ pub fn delete_handler(db: &db::Conn, id: u32) {
|
|||
let del_stmt = format!("DELETE FROM posts WHERE id = {}", id_num_in);
|
||||
let get_stmt = format!("SELECT * FROM posts WHERE id = {}", id_num_in);
|
||||
|
||||
let mut get_stmt = db.conn.prepare(&get_stmt).unwrap();
|
||||
let mut del_stmt = db.conn.prepare(&del_stmt).unwrap();
|
||||
let mut get_stmt = db.conn.prepare(&get_stmt)?;
|
||||
let mut del_stmt = db.conn.prepare(&del_stmt)?;
|
||||
|
||||
let user_in_post: String = get_stmt
|
||||
.query_row(rusqlite::NO_PARAMS, |row| row.get(2))
|
||||
.unwrap();
|
||||
let user_in_post: String = get_stmt.query_row(rusqlite::NO_PARAMS, |row| row.get(2))?;
|
||||
|
||||
if *user::NAME != user_in_post {
|
||||
println!();
|
||||
println!("Users don't match. Can't delete!");
|
||||
println!();
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
exec_stmt_no_params(&mut del_stmt).unwrap();
|
||||
exec_stmt_no_params(&mut del_stmt)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
Loading…
Reference in New Issue