Add user command
This commit is contained in:
parent
ba84742a13
commit
4b3484e7d3
24 changed files with 418 additions and 123 deletions
181
Cargo.lock
generated
181
Cargo.lock
generated
|
@ -486,6 +486,12 @@ version = "1.7.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3"
|
checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "beef"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.9.0"
|
version = "2.9.0"
|
||||||
|
@ -618,7 +624,7 @@ dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"clap_lex",
|
"clap_lex",
|
||||||
"strsim",
|
"strsim 0.11.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -746,6 +752,59 @@ dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cynic"
|
||||||
|
version = "3.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c99c59968c8aa7f90d84240ab6ded4d3864125ce36b5b044554542cebc974946"
|
||||||
|
dependencies = [
|
||||||
|
"cynic-proc-macros",
|
||||||
|
"ref-cast",
|
||||||
|
"serde",
|
||||||
|
"static_assertions",
|
||||||
|
"thiserror 1.0.69",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cynic-codegen"
|
||||||
|
version = "3.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "332695dddff7f260dfda1e97502b6440d443816f576994548b7751494991d2e3"
|
||||||
|
dependencies = [
|
||||||
|
"cynic-parser",
|
||||||
|
"darling",
|
||||||
|
"once_cell",
|
||||||
|
"ouroboros",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"strsim 0.10.0",
|
||||||
|
"syn 2.0.100",
|
||||||
|
"thiserror 1.0.69",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cynic-parser"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cbb0f21f2f8d3134c2e887a16564c165694231f48b6ae2769193299081ecf662"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
|
"lalrpop-util",
|
||||||
|
"logos",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cynic-proc-macros"
|
||||||
|
version = "3.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a7880789c425a73aff3ba286b2a9c794f330d4770769a42a1493d6175e4606c1"
|
||||||
|
dependencies = [
|
||||||
|
"cynic-codegen",
|
||||||
|
"darling",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.100",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling"
|
name = "darling"
|
||||||
version = "0.20.11"
|
version = "0.20.11"
|
||||||
|
@ -766,7 +825,7 @@ dependencies = [
|
||||||
"ident_case",
|
"ident_case",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"strsim",
|
"strsim 0.11.1",
|
||||||
"syn 2.0.100",
|
"syn 2.0.100",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -810,6 +869,27 @@ dependencies = [
|
||||||
"subtle",
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dirs"
|
||||||
|
version = "6.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
|
||||||
|
dependencies = [
|
||||||
|
"dirs-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dirs-sys"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"option-ext",
|
||||||
|
"redox_users",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "displaydoc"
|
name = "displaydoc"
|
||||||
version = "0.2.5"
|
version = "0.2.5"
|
||||||
|
@ -852,6 +932,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono-tz",
|
"chrono-tz",
|
||||||
"clap",
|
"clap",
|
||||||
|
"dirs",
|
||||||
"dpts-core",
|
"dpts-core",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
|
@ -869,6 +950,7 @@ dependencies = [
|
||||||
"chrono-tz",
|
"chrono-tz",
|
||||||
"clap",
|
"clap",
|
||||||
"csv",
|
"csv",
|
||||||
|
"cynic",
|
||||||
"dotenv",
|
"dotenv",
|
||||||
"dpts-migration",
|
"dpts-migration",
|
||||||
"iana-time-zone",
|
"iana-time-zone",
|
||||||
|
@ -1602,6 +1684,15 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lalrpop-util"
|
||||||
|
version = "0.22.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e8d05b3fe34b8bd562c338db725dfa9beb9451a48f65f129ccb9538b48d2c93b"
|
||||||
|
dependencies = [
|
||||||
|
"rustversion",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
|
@ -1623,6 +1714,16 @@ version = "0.2.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c9627da5196e5d8ed0b0495e61e518847578da83483c37288316d9b2e03a7f72"
|
checksum = "c9627da5196e5d8ed0b0495e61e518847578da83483c37288316d9b2e03a7f72"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libredox"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libsqlite3-sys"
|
name = "libsqlite3-sys"
|
||||||
version = "0.30.1"
|
version = "0.30.1"
|
||||||
|
@ -1671,6 +1772,39 @@ dependencies = [
|
||||||
"value-bag",
|
"value-bag",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "logos"
|
||||||
|
version = "0.14.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7251356ef8cb7aec833ddf598c6cb24d17b689d20b993f9d11a3d764e34e6458"
|
||||||
|
dependencies = [
|
||||||
|
"logos-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "logos-codegen"
|
||||||
|
version = "0.14.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59f80069600c0d66734f5ff52cc42f2dabd6b29d205f333d61fd7832e9e9963f"
|
||||||
|
dependencies = [
|
||||||
|
"beef",
|
||||||
|
"fnv",
|
||||||
|
"lazy_static",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"regex-syntax 0.8.5",
|
||||||
|
"syn 2.0.100",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "logos-derive"
|
||||||
|
version = "0.14.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "24fb722b06a9dc12adb0963ed585f19fc61dc5413e6a9be9422ef92c091e731d"
|
||||||
|
dependencies = [
|
||||||
|
"logos-codegen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matchers"
|
name = "matchers"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -1868,6 +2002,12 @@ dependencies = [
|
||||||
"vcpkg",
|
"vcpkg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "option-ext"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ordered-float"
|
name = "ordered-float"
|
||||||
version = "4.6.0"
|
version = "4.6.0"
|
||||||
|
@ -2258,6 +2398,37 @@ dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_users"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.2.16",
|
||||||
|
"libredox",
|
||||||
|
"thiserror 2.0.12",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ref-cast"
|
||||||
|
version = "1.0.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf"
|
||||||
|
dependencies = [
|
||||||
|
"ref-cast-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ref-cast-impl"
|
||||||
|
version = "1.0.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.100",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.11.1"
|
version = "1.11.1"
|
||||||
|
@ -2980,6 +3151,12 @@ dependencies = [
|
||||||
"unicode-properties",
|
"unicode-properties",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
|
|
|
@ -11,6 +11,7 @@ dpts-server = { path = "dpts-server" }
|
||||||
chrono = {version = "0.4", features = ["serde"]}
|
chrono = {version = "0.4", features = ["serde"]}
|
||||||
chrono-tz = {version = "0.10.3", features = ["serde"]}
|
chrono-tz = {version = "0.10.3", features = ["serde"]}
|
||||||
clap = {version = "4.5", features = ["derive"]}
|
clap = {version = "4.5", features = ["derive"]}
|
||||||
|
dirs = "6.0.0"
|
||||||
dotenv = "0.15.0"
|
dotenv = "0.15.0"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
thiserror = "2.0.12"
|
thiserror = "2.0.12"
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
#[derive(thiserror::Error, Debug)]
|
|
||||||
pub enum Error {
|
|
||||||
#[error("Parse int error")]
|
|
||||||
ParseInt(#[from] std::num::ParseIntError),
|
|
||||||
#[error("Missing config value: ({0})")]
|
|
||||||
MissingConfig(String),
|
|
||||||
#[error("Parse toml error")]
|
|
||||||
TomlDe(#[from] toml::de::Error),
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<dpts_client::error::Error> for Error {
|
|
||||||
fn from(e: dpts_client::error::Error) -> Self {
|
|
||||||
match e {
|
|
||||||
dpts_client::error::Error::TomlDe(x)=> Self::TomlDe(x),
|
|
||||||
dpts_client::error::Error::ParseInt(x) => Self::ParseInt(x),
|
|
||||||
dpts_client::error::Error::MissingConfig(x) => Self::MissingConfig(x),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,11 +3,7 @@ use chrono_tz::Tz;
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use dpts_client::auth::try_login;
|
use dpts_client::auth::try_login;
|
||||||
use dpts_client::config::{
|
use dpts_client::config::{
|
||||||
Config,
|
ClientConfig, ClientRemoteStorageConfig, ClientStorageConfig, Config, GlobalConfig, PartialGlobalConfig
|
||||||
ClientConfig,
|
|
||||||
ClientRemoteStorageConfig,
|
|
||||||
ClientStorageConfig,
|
|
||||||
PartialGlobalConfig
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Args, Clone, Debug)]
|
#[derive(Args, Clone, Debug)]
|
||||||
|
@ -17,10 +13,10 @@ pub struct InitArgs {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InitArgs {
|
impl InitArgs {
|
||||||
pub fn run(self) -> Result<(), Error> {
|
pub async fn run(self) -> Result<(), Error> {
|
||||||
match self.command {
|
match self.command {
|
||||||
InitCommand::Local(x) => x.run(),
|
InitCommand::Local(x) => x.run().await,
|
||||||
InitCommand::Remote(x) => x.run(),
|
InitCommand::Remote(x) => x.run().await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,11 +29,14 @@ enum InitCommand {
|
||||||
|
|
||||||
#[derive(Args, Clone, Debug)]
|
#[derive(Args, Clone, Debug)]
|
||||||
pub struct InitLocalArgs {
|
pub struct InitLocalArgs {
|
||||||
|
#[arg(short, long)]
|
||||||
pub time_zone: Option<Tz>,
|
pub time_zone: Option<Tz>,
|
||||||
|
#[arg(short, long)]
|
||||||
|
pub force: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InitLocalArgs {
|
impl InitLocalArgs {
|
||||||
pub fn run(self) -> Result<(), Error> {
|
pub async fn run(self) -> Result<(), Error> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,13 +50,15 @@ pub struct InitRemoteArgs {
|
||||||
pub password: String,
|
pub password: String,
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
pub time_zone: Option<Tz>,
|
pub time_zone: Option<Tz>,
|
||||||
|
#[arg(short, long)]
|
||||||
|
pub force: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InitRemoteArgs {
|
impl InitRemoteArgs {
|
||||||
pub fn run(self) -> Result<(), Error> {
|
pub async fn run(self) -> Result<(), Error> {
|
||||||
let token: String = try_login(&self.user_name, &self.password, &self.endpoint)?;
|
let token: String = try_login(&self.user_name, &self.password, &self.endpoint)?;
|
||||||
let config: Config = Config{
|
let config: Config = Config{
|
||||||
global: PartialGlobalConfig {
|
global: GlobalConfig {
|
||||||
time_zone: self.time_zone.clone()
|
time_zone: self.time_zone.clone()
|
||||||
},
|
},
|
||||||
client: ClientConfig {
|
client: ClientConfig {
|
||||||
|
@ -67,6 +68,6 @@ impl InitRemoteArgs {
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
todo!() // Write config
|
config.write_to_default_toml().await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
//mod label;
|
//mod label;
|
||||||
pub mod error;
|
|
||||||
mod init;
|
mod init;
|
||||||
mod record;
|
mod record;
|
||||||
|
mod user;
|
||||||
|
|
||||||
|
pub use dpts_client::error;
|
||||||
|
|
||||||
|
|
||||||
//use label::LabelArgs;
|
//use label::LabelArgs;
|
||||||
|
@ -33,7 +34,7 @@ async fn main() -> Result<(), Error> {
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
match cli.command {
|
match cli.command {
|
||||||
//Some(Commands::Add(x)) => x.run(),
|
//Some(Commands::Add(x)) => x.run(),
|
||||||
Command::Init(x) => x.run(),
|
Command::Init(x) => x.run().await,
|
||||||
//Some(Commands::Label(x)) => x.run(),
|
//Some(Commands::Label(x)) => x.run(),
|
||||||
Command::Record(x) => x.run(),
|
Command::Record(x) => x.run(),
|
||||||
|
|
||||||
|
|
45
dpts-cli/src/user.rs
Normal file
45
dpts-cli/src/user.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
use clap::{Args, Subcommand};
|
||||||
|
use crate::error::Error;
|
||||||
|
use dpts_client::config::Config;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Args, Clone, Debug)]
|
||||||
|
pub struct UserArgs {
|
||||||
|
#[command(subcommand)]
|
||||||
|
pub command: UserCommand,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserArgs {
|
||||||
|
pub async fn run(self) -> Result<(), Error> {
|
||||||
|
Config::read_from_default_toml().await?.set_global();
|
||||||
|
match self.command {
|
||||||
|
UserCommand::Add(x) => x.add().await,
|
||||||
|
UserCommand::List => todo!(),
|
||||||
|
UserCommand::Modify(x) => x.modify().await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Clone, Debug, Subcommand)]
|
||||||
|
|
||||||
|
enum UserCommand {
|
||||||
|
List,
|
||||||
|
Add(UserDataArgs),
|
||||||
|
Modify(UserDataArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Clone, Debug)]
|
||||||
|
pub struct UserDataArgs {
|
||||||
|
#[arg(short, long)]
|
||||||
|
pub user_name: String,
|
||||||
|
#[arg(short, long)]
|
||||||
|
pub password: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserDataArgs {
|
||||||
|
pub async fn add(self) -> Result<(), Error> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
pub async fn modify(self) -> Result<(), Error> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ clap = ["dep:clap"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono-tz.workspace = true
|
chrono-tz.workspace = true
|
||||||
clap = { workspace = true, optional = true }
|
clap = { workspace = true, optional = true }
|
||||||
|
dirs.workspace = true
|
||||||
dpts-core.workspace = true
|
dpts-core.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
thiserror.workspace = true
|
thiserror.workspace = true
|
||||||
|
|
|
@ -1,27 +1,72 @@
|
||||||
mod storage;
|
mod storage;
|
||||||
|
|
||||||
|
use std::{fmt::{Display, Formatter}, path::{Path, PathBuf}, str::FromStr};
|
||||||
|
|
||||||
pub use dpts_core::config::*;
|
pub use dpts_core::config::*;
|
||||||
pub use storage::*;
|
pub use storage::*;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use serde::{
|
use serde::{
|
||||||
Deserialize,
|
Deserialize,
|
||||||
Serialize
|
Serialize
|
||||||
};
|
};
|
||||||
|
|
||||||
use tokio::sync::OnceCell;
|
use tokio::{fs::{self, File}, io::AsyncWriteExt, sync::OnceCell};
|
||||||
|
|
||||||
|
pub static DEFAULT_CONFIG_FILE_NAME: &str = "dpts_client.toml";
|
||||||
|
pub static DEFAULT_CONFIG_DIR_NAME: &str = "dpts";
|
||||||
|
|
||||||
pub static CLIENT_CONFIG: OnceCell<ClientConfig> = OnceCell::const_new();
|
pub static CLIENT_CONFIG: OnceCell<ClientConfig> = OnceCell::const_new();
|
||||||
|
|
||||||
|
pub fn get_default_config_file_path() -> Result<PathBuf, Error> {
|
||||||
|
let config_dir = dirs::config_dir().ok_or(Error::DefaultConfigDir)?;
|
||||||
|
Ok(config_dir.join(DEFAULT_CONFIG_DIR_NAME).join(DEFAULT_CONFIG_FILE_NAME))
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||||
|
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub client: ClientConfig,
|
pub client: ClientConfig,
|
||||||
pub global: PartialGlobalConfig,
|
pub global: GlobalConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
pub async fn read_from_default_toml() -> Result<Self, Error> {
|
||||||
|
Ok(Self::read_from_toml(&get_default_config_file_path()?).await?)
|
||||||
|
}
|
||||||
|
pub async fn write_to_default_toml(&self) -> Result<(), Error> {
|
||||||
|
Ok(self.write_to_toml(&get_default_config_file_path()?).await?)
|
||||||
|
}
|
||||||
|
pub async fn write_to_toml(&self, p: &Path) -> Result<(), Error> {
|
||||||
|
let toml = self.to_toml()?;
|
||||||
|
let mut file = File::create(p).await?;
|
||||||
|
file.write_all(toml.as_bytes()).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub async fn read_from_toml(p: &Path) -> Result<Self, Error> {
|
||||||
|
let raw = fs::read_to_string(p).await?;
|
||||||
|
Ok(Self::from_toml(&raw)?)
|
||||||
|
}
|
||||||
|
pub fn from_toml(s: &str) -> Result<Self, Error> {
|
||||||
|
Ok(toml::from_str(s)?)
|
||||||
|
}
|
||||||
|
pub fn to_toml(&self) -> Result<String, Error> {
|
||||||
|
Ok(toml::to_string(self)?)
|
||||||
|
}
|
||||||
|
pub fn set_global(self) -> Result<(), Error> {
|
||||||
|
CLIENT_CONFIG.set(self.client)?;
|
||||||
|
GLOBAL_CONFIG.set(self.global)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn from_global() -> Result<Self, Error> {
|
||||||
|
Ok(Self {
|
||||||
|
client: CLIENT_CONFIG.get().ok_or(Error::UninitializedOnceCell("CLIENT_CONFIG".to_string()))?.clone(),
|
||||||
|
global: GLOBAL_CONFIG.get().ok_or(Error::UninitializedOnceCell("GLOBAL_CONFIG".to_string()))?.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||||
pub struct ClientConfig {
|
pub struct ClientConfig {
|
||||||
pub storage: ClientStorageConfig,
|
pub storage: ClientStorageConfig,
|
||||||
|
@ -47,19 +92,19 @@ storage = "local"
|
||||||
client: ClientConfig{
|
client: ClientConfig{
|
||||||
storage: ClientStorageConfig::Local,
|
storage: ClientStorageConfig::Local,
|
||||||
},
|
},
|
||||||
global: PartialGlobalConfig { time_zone: None },
|
global: GlobalConfig { time_zone: None },
|
||||||
}
|
}
|
||||||
}).await
|
}).await
|
||||||
}
|
}
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn deserialize_local_storage_client_config() {
|
async fn deserialize_local_storage_client_config() {
|
||||||
let config: Config = toml::from_str(LOCAL_STORAGE_CONFIG_TOML).unwrap();
|
let config: Config = Config::from_toml(LOCAL_STORAGE_CONFIG_TOML).unwrap();
|
||||||
assert_eq!(&config, get_local_storage_client_config_struct().await);
|
assert_eq!(&config, get_local_storage_client_config_struct().await);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn serialize_local_storage_client_config() {
|
async fn serialize_local_storage_client_config() {
|
||||||
assert_eq!(LOCAL_STORAGE_CONFIG_TOML, toml::to_string(get_local_storage_client_config_struct().await).unwrap());
|
assert_eq!(LOCAL_STORAGE_CONFIG_TOML, get_local_storage_client_config_struct().await.to_toml().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
const REMOTE_STORAGE_CONFIG_TOML: &str = r#"[client.storage.remote]
|
const REMOTE_STORAGE_CONFIG_TOML: &str = r#"[client.storage.remote]
|
||||||
|
@ -80,19 +125,18 @@ time_zone = "UTC"
|
||||||
access_key: "test".to_string(),
|
access_key: "test".to_string(),
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
global: PartialGlobalConfig { time_zone: Some(UTC) }
|
global: GlobalConfig { time_zone: Some(UTC) }
|
||||||
}
|
}
|
||||||
}).await
|
}).await
|
||||||
}
|
}
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn deserialize_remote_storage_client_config() {
|
async fn deserialize_remote_storage_client_config() { let config: Config = Config::from_toml(REMOTE_STORAGE_CONFIG_TOML).unwrap();
|
||||||
let config: Config = toml::from_str(REMOTE_STORAGE_CONFIG_TOML).unwrap();
|
|
||||||
assert_eq!(&config, get_remote_storage_client_config_struct().await);
|
assert_eq!(&config, get_remote_storage_client_config_struct().await);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn serialize_remote_storage_client_config() {
|
async fn serialize_remote_storage_client_config() {
|
||||||
assert_eq!(REMOTE_STORAGE_CONFIG_TOML, toml::to_string(get_remote_storage_client_config_struct().await).unwrap());
|
assert_eq!(REMOTE_STORAGE_CONFIG_TOML, get_remote_storage_client_config_struct().await.to_toml().unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
#[derive(thiserror::Error, Debug)]
|
|
||||||
pub enum Error {
|
|
||||||
#[error("Parse int error")]
|
|
||||||
ParseInt(#[from] std::num::ParseIntError),
|
|
||||||
#[error("Parse toml error")]
|
|
||||||
TomlDe(#[from] toml::de::Error),
|
|
||||||
#[error("Missing config value: ({0})")]
|
|
||||||
MissingConfig(String)
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,8 +1,7 @@
|
||||||
pub mod auth;
|
pub mod auth;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod error;
|
|
||||||
|
|
||||||
use error::Error;
|
pub use dpts_core::error;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ chrono = {workspace = true}
|
||||||
chrono-tz.workspace = true
|
chrono-tz.workspace = true
|
||||||
clap = { workspace = true, optional = true }
|
clap = { workspace = true, optional = true }
|
||||||
csv = "1.3.1"
|
csv = "1.3.1"
|
||||||
|
cynic = "3.10.0"
|
||||||
dotenv = {workspace = true}
|
dotenv = {workspace = true}
|
||||||
dpts-migration = { workspace = true }
|
dpts-migration = { workspace = true }
|
||||||
iana-time-zone = "0.1.63"
|
iana-time-zone = "0.1.63"
|
||||||
|
|
|
@ -9,14 +9,14 @@ use crate::Error;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||||
pub struct GlobalConfig {
|
pub struct GlobalConfig {
|
||||||
pub time_zone: Tz,
|
pub time_zone: Option<Tz>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<PartialGlobalConfig> for GlobalConfig{
|
impl TryFrom<PartialGlobalConfig> for GlobalConfig{
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
fn try_from(p: PartialGlobalConfig) -> Result<GlobalConfig, Self::Error> {
|
fn try_from(p: PartialGlobalConfig) -> Result<GlobalConfig, Self::Error> {
|
||||||
Ok(GlobalConfig{
|
Ok(GlobalConfig{
|
||||||
time_zone: p.time_zone.ok_or(Error::MissingConfig("time_zone".to_string()))?,
|
time_zone: p.time_zone,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ mod user;
|
||||||
|
|
||||||
pub use user::{
|
pub use user::{
|
||||||
ActiveModel as UserActiveModel,
|
ActiveModel as UserActiveModel,
|
||||||
|
Column as UserColumn,
|
||||||
Entity as UserEntity,
|
Entity as UserEntity,
|
||||||
Model as UserModel,
|
Model as UserModel,
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,6 +2,9 @@ use async_graphql::SimpleObject;
|
||||||
use chrono::{DateTime, FixedOffset,};
|
use chrono::{DateTime, FixedOffset,};
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use crate::error::Error;
|
||||||
|
|
||||||
|
use crate::DATABASE_CONNECTION;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, SimpleObject, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, SimpleObject, Deserialize)]
|
||||||
#[sea_orm(table_name = "user")]
|
#[sea_orm(table_name = "user")]
|
||||||
|
@ -17,6 +20,22 @@ pub struct Model {
|
||||||
pub updated_at: DateTimeWithTimeZone,
|
pub updated_at: DateTimeWithTimeZone,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Entity {
|
||||||
|
pub async fn find_by_name(user_name: &str) -> Result<Option<Model>, Error> {
|
||||||
|
Ok(Entity::find()
|
||||||
|
.filter(Column::LoginName.contains(user_name))
|
||||||
|
.one(DATABASE_CONNECTION.get().unwrap())
|
||||||
|
.await?
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub async fn find_all() -> Result<Vec<Model>, Error> {
|
||||||
|
Ok(Entity::find()
|
||||||
|
.all(DATABASE_CONNECTION.get().unwrap())
|
||||||
|
.await?
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, DeriveRelation, EnumIter)]
|
#[derive(Copy, Clone, Debug, DeriveRelation, EnumIter)]
|
||||||
pub enum Relation {
|
pub enum Relation {
|
||||||
#[sea_orm(has_many = "super::record_header::Entity")]
|
#[sea_orm(has_many = "super::record_header::Entity")]
|
||||||
|
@ -36,5 +55,10 @@ impl Related<super::record_tag::Entity> for Model {
|
||||||
Relation::RecordTag.def()
|
Relation::RecordTag.def()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl ActiveModel {
|
||||||
|
pub async fn create_user(login_name: &str, password: &str) -> Result<Model, Error>{
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
|
|
@ -1,10 +1,32 @@
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
#[error("IO error")]
|
||||||
|
Io(#[from] std::io::Error),
|
||||||
#[error("Parse int error")]
|
#[error("Parse int error")]
|
||||||
ParseInt(#[from] std::num::ParseIntError),
|
ParseInt(#[from] std::num::ParseIntError),
|
||||||
#[error("Parse toml error")]
|
#[error("Deserialize toml error")]
|
||||||
TomlDe(#[from] toml::de::Error),
|
TomlDe(#[from] toml::de::Error),
|
||||||
|
#[error("Serialize toml error")]
|
||||||
|
TomlSer(#[from] toml::ser::Error),
|
||||||
#[error("Missing config value: ({0})")]
|
#[error("Missing config value: ({0})")]
|
||||||
MissingConfig(String)
|
MissingConfig(String),
|
||||||
|
#[error("Cannot get default config directory")]
|
||||||
|
DefaultConfigDir,
|
||||||
|
#[error("Uninitialized global var: {0}")]
|
||||||
|
UninitializedOnceCell(String),
|
||||||
|
#[error("Once cell is initializing: {0}")]
|
||||||
|
InitializingOnceCell(String),
|
||||||
|
#[error("Once cell is already Initialized: {0}")]
|
||||||
|
AlreadyInitializedOnceCell(String),
|
||||||
|
#[error("DB Error: {0}")]
|
||||||
|
Db(#[from]sea_orm::DbErr),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<tokio::sync::SetError<T>> for Error{
|
||||||
|
fn from(e: tokio::sync::SetError<T>) -> Self {
|
||||||
|
match e {
|
||||||
|
tokio::sync::SetError::AlreadyInitializedError(_) => Self::AlreadyInitializedOnceCell(std::any::type_name::<T>().to_string()),
|
||||||
|
tokio::sync::SetError::InitializingError(_) => Self::InitializingOnceCell(std::any::type_name::<T>().to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
mod mutation;
|
|
||||||
mod query;
|
|
||||||
mod record_detail;
|
mod record_detail;
|
||||||
mod record_header;
|
mod record_header;
|
||||||
mod record_tag;
|
mod record_tag;
|
||||||
mod user;
|
mod user;
|
||||||
|
|
||||||
pub use mutation::Mutation;
|
pub use user::PartialUser;
|
||||||
pub use query::Query;
|
|
||||||
pub use user::UserObject;
|
|
|
@ -1,10 +0,0 @@
|
||||||
use async_graphql::*;
|
|
||||||
|
|
||||||
pub struct Mutation;
|
|
||||||
|
|
||||||
#[Object]
|
|
||||||
impl Mutation {
|
|
||||||
async fn login(&self, username:String, password: String) -> Result<String> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
use async_graphql::{
|
|
||||||
*,
|
|
||||||
http::GraphiQLSource,
|
|
||||||
};
|
|
||||||
use axum::{
|
|
||||||
response::{Html, IntoResponse},
|
|
||||||
routing::get,
|
|
||||||
Router,
|
|
||||||
};
|
|
||||||
use super::user::UserObject;
|
|
||||||
pub struct Query;
|
|
||||||
|
|
||||||
#[Object]
|
|
||||||
impl Query {
|
|
||||||
pub async fn user(&self, username: String) -> Result<Option<UserObject>> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +1,27 @@
|
||||||
use async_graphql::*;
|
use async_graphql::*;
|
||||||
use chrono::{DateTime, FixedOffset};
|
use chrono::{DateTime, FixedOffset};
|
||||||
|
|
||||||
|
use crate::entity::UserModel;
|
||||||
|
|
||||||
pub struct UserObject {
|
|
||||||
pub id: i32,
|
#[derive(SimpleObject)]
|
||||||
|
pub struct PartialUser {
|
||||||
|
pub id: Option<i32>,
|
||||||
pub login_name: Option<String>,
|
pub login_name: Option<String>,
|
||||||
pub created_at: Option<DateTime<FixedOffset>>,
|
pub created_at: Option<DateTime<FixedOffset>>,
|
||||||
pub updated_at: Option<DateTime<FixedOffset>>,
|
pub updated_at: Option<DateTime<FixedOffset>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Object]
|
#[derive(SimpleObject)]
|
||||||
impl UserObject {
|
pub struct Users{
|
||||||
async fn id(&self) -> i32 {
|
users: Vec<UserModel>
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
async fn login_name(&self) -> Option<String> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
async fn created_at(&self) -> Option<DateTime<FixedOffset>> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
async fn updated_at(&self) -> Option<DateTime<FixedOffset>> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct CreateUser {
|
||||||
|
login_name: String,
|
||||||
|
password: String,
|
||||||
|
}
|
||||||
|
pub struct ModifyUser {
|
||||||
|
login_name: Option<String>,
|
||||||
|
password: Option<String>,
|
||||||
|
}
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
|
mod mutation;
|
||||||
|
mod query;
|
||||||
|
|
||||||
|
pub use dpts_core::graphql::*;
|
||||||
|
|
||||||
|
pub use mutation::Mutation;
|
||||||
|
pub use query::Query;
|
||||||
|
|
||||||
use async_graphql::{EmptySubscription, Schema};
|
use async_graphql::{EmptySubscription, Schema};
|
||||||
use async_graphql_axum::GraphQL;
|
use async_graphql_axum::GraphQL;
|
||||||
use axum::{routing::get, Router};
|
use axum::{routing::get, Router};
|
||||||
use dpts_core::graphql::{
|
|
||||||
Query,
|
|
||||||
Mutation,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn build_schema() -> Schema<Query, Mutation, EmptySubscription>{
|
pub fn build_schema() -> Schema<Query, Mutation, EmptySubscription>{
|
||||||
Schema::build(Query, Mutation, EmptySubscription).finish()
|
Schema::build(Query, Mutation, EmptySubscription).finish()
|
16
dpts-server/src/graphql/mutation.rs
Normal file
16
dpts-server/src/graphql/mutation.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
use async_graphql::*;
|
||||||
|
use dpts_core::entity::UserModel;
|
||||||
|
|
||||||
|
use crate::{auth::try_hash_password, entity::UserActiveModel};
|
||||||
|
|
||||||
|
pub struct Mutation;
|
||||||
|
|
||||||
|
#[Object]
|
||||||
|
impl Mutation {
|
||||||
|
async fn login(&self, username:String, password: String) -> Result<String> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
async fn create_user(&self, username:String, password: String) -> Result<UserModel> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
22
dpts-server/src/graphql/query.rs
Normal file
22
dpts-server/src/graphql/query.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
use async_graphql::{
|
||||||
|
*,
|
||||||
|
http::GraphiQLSource,
|
||||||
|
};
|
||||||
|
use axum::{
|
||||||
|
response::{Html, IntoResponse},
|
||||||
|
routing::get,
|
||||||
|
Router,
|
||||||
|
};
|
||||||
|
use crate::{entity::{UserEntity, UserModel},};
|
||||||
|
|
||||||
|
pub struct Query;
|
||||||
|
|
||||||
|
#[Object]
|
||||||
|
impl Query {
|
||||||
|
pub async fn user(&self, user_name: String) -> Result<Option<UserModel>> {
|
||||||
|
Ok(UserEntity::find_by_name(&user_name).await?)
|
||||||
|
}
|
||||||
|
pub async fn users(&self) -> Result<Vec<UserModel>> {
|
||||||
|
Ok(UserEntity::find_all().await?)
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ use async_graphql_axum::{
|
||||||
};
|
};
|
||||||
use axum::{routing::get, Router};
|
use axum::{routing::get, Router};
|
||||||
use crate::graphql::build_service;
|
use crate::graphql::build_service;
|
||||||
|
use dpts_core::entity as entity;
|
||||||
|
|
||||||
|
|
||||||
pub fn build_app() -> Router {
|
pub fn build_app() -> Router {
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
use async_graphql::{http::{playground_source, GraphQLPlaygroundConfig}, *};
|
use async_graphql::{http::{playground_source, GraphQLPlaygroundConfig}, *};
|
||||||
use async_graphql_axum::GraphQL;
|
use async_graphql_axum::GraphQL;
|
||||||
use dpts_core::graphql::{
|
|
||||||
Mutation,
|
|
||||||
Query,
|
|
||||||
};
|
|
||||||
use dpts_server::{build_app, Args};
|
use dpts_server::{build_app, Args};
|
||||||
use axum::{response::{Html, IntoResponse}, routing::get, Router};
|
use axum::{response::{Html, IntoResponse}, routing::get, Router};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
Loading…
Add table
Reference in a new issue