feat: added users command line.
This commit is contained in:
1 parent
fb26468175
commit
ded31da7a3
5 files changed
+238
-74
No files matched your search
Generated
+33
@@ -212,6 +212,8 @@ dependencies = [
|
|||||||
"home",
|
"home",
|
||||||
"log",
|
"log",
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"simple_logger",
|
"simple_logger",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -298,11 +300,42 @@ dependencies = [
|
|||||||
"smallvec",
|
"smallvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.147"
|
version = "1.0.147"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
|
checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.147"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.89"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "simple_logger"
|
name = "simple_logger"
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rusqlite = { version = "0.28.0", features = ["bundled"] }
|
rusqlite = { version = "0.28.0", features = ["bundled"] }
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
clap = { version = "4.0.26", features = ["derive"] }
|
clap = { version = "4.0.26", features = ["derive"] }
|
||||||
clap-verbosity-flag = "2.0.0"
|
clap-verbosity-flag = "2.0.0"
|
||||||
simple_logger = "4.0.0"
|
simple_logger = "4.0.0"
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
home = "0.5.4"
|
home = "0.5.4"
|
||||||
|
serde_json = "1.0"
|
||||||
+177
-71
@@ -1,15 +1,38 @@
|
|||||||
mod migration;
|
|
||||||
mod users;
|
|
||||||
|
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use clap::{Command, Arg, ArgAction, ArgMatches, value_parser};
|
|
||||||
use log::{debug, info};
|
|
||||||
use simple_logger::SimpleLogger;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use rusqlite::{Connection};
|
|
||||||
|
use clap::{Arg, ArgAction, ArgMatches, Command, value_parser};
|
||||||
|
use serde::{Serialize};
|
||||||
|
|
||||||
|
use log::{debug, error, info};
|
||||||
|
use rusqlite::Connection;
|
||||||
|
use simple_logger::SimpleLogger;
|
||||||
|
|
||||||
use crate::migration::migrate;
|
use crate::migration::migrate;
|
||||||
|
|
||||||
|
mod migration;
|
||||||
|
mod users;
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
struct Output<T> {
|
||||||
|
status: String,
|
||||||
|
result: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Output<T> {
|
||||||
|
fn success(shit: T) -> Output<T> {
|
||||||
|
return Output{status: "success".to_string(), result: shit};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
trait CommandLineUserLogic {
|
||||||
|
fn create_user(&mut self, conn: &Connection, name: &String, public_key: &String);
|
||||||
|
|
||||||
|
fn list_user(&mut self, conn: &Connection);
|
||||||
|
|
||||||
|
// fn list_securities(&mut self, conn: &Connection);
|
||||||
|
}
|
||||||
|
|
||||||
fn verbosity_arg() -> Arg {
|
fn verbosity_arg() -> Arg {
|
||||||
return Arg::new("verbosity")
|
return Arg::new("verbosity")
|
||||||
@@ -18,7 +41,7 @@ fn verbosity_arg() -> Arg {
|
|||||||
.default_value("0");
|
.default_value("0");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_verbosity(m: & ArgMatches) -> log::LevelFilter {
|
fn get_verbosity(m: &ArgMatches) -> log::LevelFilter {
|
||||||
match m.get_one::<u8>("verbosity") {
|
match m.get_one::<u8>("verbosity") {
|
||||||
None => log::LevelFilter::Error,
|
None => log::LevelFilter::Error,
|
||||||
Some(1) => log::LevelFilter::Warn,
|
Some(1) => log::LevelFilter::Warn,
|
||||||
@@ -41,10 +64,100 @@ fn get_db_path(m: & ArgMatches) -> & PathBuf{
|
|||||||
return m.get_one::<PathBuf>("db-path").unwrap();
|
return m.get_one::<PathBuf>("db-path").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_user_command_line_parser() -> Command {
|
||||||
|
return Command::new("new")
|
||||||
|
.long_flag("new")
|
||||||
|
.about("Create new user.")
|
||||||
|
.arg(Arg::new("name").long("name").help("name of new user.").action(ArgAction::Set))
|
||||||
|
.arg(Arg::new("public_key").long("public-key").help("public key of users.").action(ArgAction::Set));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ls_user_command_line_parser() -> Command {
|
||||||
|
return Command::new("ls")
|
||||||
|
.long_flag("ls")
|
||||||
|
.about("List all users.");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn user_command_line_parser() -> Command {
|
||||||
|
return Command::new("users")
|
||||||
|
.subcommand(new_user_command_line_parser())
|
||||||
|
.subcommand(ls_user_command_line_parser());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn command_line_parser() -> Command {
|
||||||
|
return Command::new("prog")
|
||||||
|
.arg(verbosity_arg())
|
||||||
|
.arg(db_path_arg())
|
||||||
|
.subcommand(user_command_line_parser());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_new_user_command_line(conn: &Connection, m: &ArgMatches, logic: &mut dyn CommandLineUserLogic) {
|
||||||
|
debug!("Processing new user command line {:?}.", m);
|
||||||
|
let name = m.get_one::<String>("name").unwrap();
|
||||||
|
let pk = m.get_one::<String>("public_key").unwrap();
|
||||||
|
logic.create_user(conn, name, pk);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_list_user_command_line(conn: &Connection, m: &ArgMatches, logic: &mut dyn CommandLineUserLogic) {
|
||||||
|
debug!("Processing list users command line {:?}.", m);
|
||||||
|
logic.list_user(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_user_command_line(conn: &Connection, m: &ArgMatches, logic: &mut dyn CommandLineUserLogic) {
|
||||||
|
debug!("Processing user command line {:?}.", m);
|
||||||
|
match m.subcommand() {
|
||||||
|
Some(("new", new_user_match)) => {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_command_line(conn: &Connection, m: &ArgMatches, logic: &mut dyn CommandLineUserLogic) {
|
||||||
|
debug!("Processing command line {:?}.", m);
|
||||||
|
match m.subcommand() {
|
||||||
|
Some(("users", user_match)) => {
|
||||||
|
process_user_command_line(conn, user_match, logic);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
println!("Received unparsable command. {:?}", m.subcommand());
|
||||||
|
unreachable!();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
struct TestCommandLineLogic {
|
||||||
|
list_user_count: usize,
|
||||||
|
create_user_count: usize,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestCommandLineLogic {
|
||||||
|
fn new() -> TestCommandLineLogic {
|
||||||
|
return TestCommandLineLogic {
|
||||||
|
list_user_count: 0,
|
||||||
|
create_user_count: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CommandLineUserLogic for TestCommandLineLogic {
|
||||||
|
fn create_user(&mut self, conn: &Connection, name: &String, public_key: &String) {
|
||||||
|
self.create_user_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn list_user(&mut self, conn: &Connection) {
|
||||||
|
self.list_user_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn verbosity() {
|
fn verbosity() {
|
||||||
{
|
{
|
||||||
@@ -67,7 +180,7 @@ mod test {
|
|||||||
let cmd = Command::new("test").arg(db_path_arg());
|
let cmd = Command::new("test").arg(db_path_arg());
|
||||||
let m = cmd.get_matches_from(vec!["test", "--db-path", "/foo/bar"]);
|
let m = cmd.get_matches_from(vec!["test", "--db-path", "/foo/bar"]);
|
||||||
let expt = PathBuf::from("/foo/bar");
|
let expt = PathBuf::from("/foo/bar");
|
||||||
assert_eq!(get_db_path(&m), & expt);
|
assert_eq!(get_db_path(&m), &expt);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -76,78 +189,70 @@ mod test {
|
|||||||
let expt = PathBuf::from("ledger.sqlite");
|
let expt = PathBuf::from("ledger.sqlite");
|
||||||
assert_eq!(get_db_path(&m), &expt);
|
assert_eq!(get_db_path(&m), &expt);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create_user() {
|
||||||
|
let cmd = command_line_parser();
|
||||||
|
let m = cmd.get_matches_from(vec!["test", "users", "new", "--name", "paul", "--public-key", "123abc"]);
|
||||||
|
let mut logic = TestCommandLineLogic::new();
|
||||||
|
let conn = Connection::open_in_memory().unwrap();
|
||||||
|
process_command_line(&conn, &m, &mut logic);
|
||||||
|
assert_eq!(logic.create_user_count, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn list_users() {
|
||||||
|
let cmd = command_line_parser();
|
||||||
|
let m = cmd.get_matches_from(vec!["test", "users", "ls"]);
|
||||||
|
let mut logic = TestCommandLineLogic::new();
|
||||||
|
let conn = Connection::open_in_memory().unwrap();
|
||||||
|
process_command_line(&conn, &m, &mut logic);
|
||||||
|
assert_eq!(logic.list_user_count, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_user_command_line_parser() -> Command {
|
struct ProCommandLineLogic {}
|
||||||
return Command::new("new")
|
|
||||||
.long_flag("new")
|
|
||||||
.about("Create new user.")
|
|
||||||
.arg(Arg::new("name").help("name of new user.").action(ArgAction::Set));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ls_user_command_line_parser() -> Command {
|
impl ProCommandLineLogic {
|
||||||
return Command::new("list")
|
fn new() -> ProCommandLineLogic {
|
||||||
.long_flag("ls")
|
return ProCommandLineLogic {};
|
||||||
.about("List all users.");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn user_command_line_parser() -> Command {
|
|
||||||
return Command::new("users")
|
|
||||||
.subcommand(new_user_command_line_parser())
|
|
||||||
.subcommand(ls_user_command_line_parser());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn command_line_parser() -> Command {
|
|
||||||
return Command::new("prog")
|
|
||||||
.arg(verbosity_arg())
|
|
||||||
.arg(db_path_arg())
|
|
||||||
.subcommand(user_command_line_parser());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_new_user_command_line(conn: &Connection, m: &ArgMatches){
|
|
||||||
debug!("Processing new user command line {:?}.", m);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_list_user_command_line(conn: &Connection, m: &ArgMatches){
|
|
||||||
debug!("Processing list users command line {:?}.", m);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_user_command_line(conn: &Connection, m: &ArgMatches){
|
|
||||||
debug!("Processing user command line {:?}.", m);
|
|
||||||
match m.subcommand() {
|
|
||||||
Some(("new", new_user_match)) => {
|
|
||||||
process_new_user_command_line(conn, new_user_match);
|
|
||||||
}
|
|
||||||
Some(("list", list_user_match)) => {
|
|
||||||
process_list_user_command_line(conn, list_user_match);
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_command_line(conn: & Connection, m: & ArgMatches) {
|
|
||||||
debug!("Processing command line {:?}.", m);
|
|
||||||
match m.subcommand() {
|
|
||||||
Some(("users", user_match)) => {
|
|
||||||
process_user_command_line(conn, user_match);
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_connection(m: & ArgMatches) -> Connection {
|
impl CommandLineUserLogic for ProCommandLineLogic {
|
||||||
|
fn create_user(&mut self, conn: &Connection, name: &String, public_key: &String) {
|
||||||
|
users::create_user(conn, name, public_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn list_user(&mut self, conn: &Connection) {
|
||||||
|
let users = users::list_users(conn);
|
||||||
|
match users {
|
||||||
|
Ok(u) => {
|
||||||
|
let r: Vec<& users::User> = u.iter()
|
||||||
|
.filter(|& x| x.is_ok())
|
||||||
|
.map(| x| x.as_ref().unwrap())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let out = Output::success(r);
|
||||||
|
|
||||||
|
println!("{}", serde_json::to_string(& out).unwrap());
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("{:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn get_connection(m: &ArgMatches) -> Connection {
|
||||||
let path = get_db_path(&m);
|
let path = get_db_path(&m);
|
||||||
info!("Sqlite database location is {:?}.", path);
|
info!("Sqlite database location is {:?}.", path);
|
||||||
return Connection::open(path).unwrap();
|
return Connection::open(path).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_logger(m: & ArgMatches) {
|
fn set_logger(m: &ArgMatches) {
|
||||||
SimpleLogger::new().with_level(get_verbosity(&m)).init().unwrap();
|
SimpleLogger::new().with_level(get_verbosity(&m)).init().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,8 +260,9 @@ fn main() {
|
|||||||
let command = command_line_parser();
|
let command = command_line_parser();
|
||||||
let m = command.get_matches();
|
let m = command.get_matches();
|
||||||
|
|
||||||
set_logger(& m);
|
set_logger(&m);
|
||||||
let conn = get_connection(& m);
|
let conn = get_connection(&m);
|
||||||
migrate(&conn);
|
migrate(&conn);
|
||||||
process_command_line(& conn, & m);
|
let mut logic = ProCommandLineLogic::new();
|
||||||
|
process_command_line(&conn, &m, &mut logic);
|
||||||
}
|
}
|
||||||
+1
-1
@@ -5,7 +5,7 @@ const MIGRATION_SCRIPT: &str = "
|
|||||||
CREATE TABLE IF NOT EXISTS users (
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
key TEXT NOT NULL
|
public_key TEXT NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS security_types (
|
CREATE TABLE IF NOT EXISTS security_types (
|
||||||
|
|||||||
+25
-2
@@ -1,5 +1,28 @@
|
|||||||
use rusqlite::Connection;
|
use rusqlite::{Connection, Result};
|
||||||
|
use serde::{Serialize};
|
||||||
|
|
||||||
fn create_user(conn: & Connection){
|
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
pub struct User {
|
||||||
|
id: i32,
|
||||||
|
name: String,
|
||||||
|
public_key: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_user(conn: & Connection, name: &String, public_key: &String){
|
||||||
|
conn.execute("INSERT INTO users (name, public_key) VALUES (?1, ?2)",
|
||||||
|
(name, public_key)).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn list_users(conn: & Connection) -> Result<Vec<Result<User>>>{
|
||||||
|
|
||||||
|
let mut stmt = conn.prepare("SELECT id, name, public_key FROM users")?;
|
||||||
|
let ret: Vec<Result<User>> = stmt.query_map([], |row| {
|
||||||
|
Ok(User {
|
||||||
|
id: row.get(0)?,
|
||||||
|
name: row.get(1)?,
|
||||||
|
public_key: row.get(2)?,
|
||||||
|
})
|
||||||
|
}).unwrap().collect();
|
||||||
|
return Ok(ret);
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user