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"
|
||||
checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3"
|
||||
|
||||
[[package]]
|
||||
name = "beef"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.0"
|
||||
|
@ -618,7 +624,7 @@ dependencies = [
|
|||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
"strsim 0.11.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -746,6 +752,59 @@ dependencies = [
|
|||
"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]]
|
||||
name = "darling"
|
||||
version = "0.20.11"
|
||||
|
@ -766,7 +825,7 @@ dependencies = [
|
|||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"strsim 0.11.1",
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
|
@ -810,6 +869,27 @@ dependencies = [
|
|||
"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]]
|
||||
name = "displaydoc"
|
||||
version = "0.2.5"
|
||||
|
@ -852,6 +932,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"chrono-tz",
|
||||
"clap",
|
||||
"dirs",
|
||||
"dpts-core",
|
||||
"serde",
|
||||
"thiserror 2.0.12",
|
||||
|
@ -869,6 +950,7 @@ dependencies = [
|
|||
"chrono-tz",
|
||||
"clap",
|
||||
"csv",
|
||||
"cynic",
|
||||
"dotenv",
|
||||
"dpts-migration",
|
||||
"iana-time-zone",
|
||||
|
@ -1602,6 +1684,15 @@ dependencies = [
|
|||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lalrpop-util"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8d05b3fe34b8bd562c338db725dfa9beb9451a48f65f129ccb9538b48d2c93b"
|
||||
dependencies = [
|
||||
"rustversion",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
|
@ -1623,6 +1714,16 @@ version = "0.2.13"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.30.1"
|
||||
|
@ -1671,6 +1772,39 @@ dependencies = [
|
|||
"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]]
|
||||
name = "matchers"
|
||||
version = "0.1.0"
|
||||
|
@ -1868,6 +2002,12 @@ dependencies = [
|
|||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "option-ext"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||
|
||||
[[package]]
|
||||
name = "ordered-float"
|
||||
version = "4.6.0"
|
||||
|
@ -2258,6 +2398,37 @@ dependencies = [
|
|||
"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]]
|
||||
name = "regex"
|
||||
version = "1.11.1"
|
||||
|
@ -2980,6 +3151,12 @@ dependencies = [
|
|||
"unicode-properties",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
|
|
|
@ -11,6 +11,7 @@ dpts-server = { path = "dpts-server" }
|
|||
chrono = {version = "0.4", features = ["serde"]}
|
||||
chrono-tz = {version = "0.10.3", features = ["serde"]}
|
||||
clap = {version = "4.5", features = ["derive"]}
|
||||
dirs = "6.0.0"
|
||||
dotenv = "0.15.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
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 dpts_client::auth::try_login;
|
||||
use dpts_client::config::{
|
||||
Config,
|
||||
ClientConfig,
|
||||
ClientRemoteStorageConfig,
|
||||
ClientStorageConfig,
|
||||
PartialGlobalConfig
|
||||
ClientConfig, ClientRemoteStorageConfig, ClientStorageConfig, Config, GlobalConfig, PartialGlobalConfig
|
||||
};
|
||||
|
||||
#[derive(Args, Clone, Debug)]
|
||||
|
@ -17,10 +13,10 @@ pub struct InitArgs {
|
|||
}
|
||||
|
||||
impl InitArgs {
|
||||
pub fn run(self) -> Result<(), Error> {
|
||||
pub async fn run(self) -> Result<(), Error> {
|
||||
match self.command {
|
||||
InitCommand::Local(x) => x.run(),
|
||||
InitCommand::Remote(x) => x.run(),
|
||||
InitCommand::Local(x) => x.run().await,
|
||||
InitCommand::Remote(x) => x.run().await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,11 +29,14 @@ enum InitCommand {
|
|||
|
||||
#[derive(Args, Clone, Debug)]
|
||||
pub struct InitLocalArgs {
|
||||
#[arg(short, long)]
|
||||
pub time_zone: Option<Tz>,
|
||||
#[arg(short, long)]
|
||||
pub force: bool
|
||||
}
|
||||
|
||||
impl InitLocalArgs {
|
||||
pub fn run(self) -> Result<(), Error> {
|
||||
pub async fn run(self) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
@ -51,13 +50,15 @@ pub struct InitRemoteArgs {
|
|||
pub password: String,
|
||||
#[arg(short, long)]
|
||||
pub time_zone: Option<Tz>,
|
||||
#[arg(short, long)]
|
||||
pub force: bool,
|
||||
}
|
||||
|
||||
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 config: Config = Config{
|
||||
global: PartialGlobalConfig {
|
||||
global: GlobalConfig {
|
||||
time_zone: self.time_zone.clone()
|
||||
},
|
||||
client: ClientConfig {
|
||||
|
@ -67,6 +68,6 @@ impl InitRemoteArgs {
|
|||
}),
|
||||
}
|
||||
};
|
||||
todo!() // Write config
|
||||
config.write_to_default_toml().await
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
//mod label;
|
||||
pub mod error;
|
||||
mod init;
|
||||
mod record;
|
||||
mod user;
|
||||
|
||||
pub use dpts_client::error;
|
||||
|
||||
|
||||
//use label::LabelArgs;
|
||||
|
@ -33,7 +34,7 @@ async fn main() -> Result<(), Error> {
|
|||
let cli = Cli::parse();
|
||||
match cli.command {
|
||||
//Some(Commands::Add(x)) => x.run(),
|
||||
Command::Init(x) => x.run(),
|
||||
Command::Init(x) => x.run().await,
|
||||
//Some(Commands::Label(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]
|
||||
chrono-tz.workspace = true
|
||||
clap = { workspace = true, optional = true }
|
||||
dirs.workspace = true
|
||||
dpts-core.workspace = true
|
||||
serde.workspace = true
|
||||
thiserror.workspace = true
|
||||
|
|
|
@ -1,27 +1,72 @@
|
|||
mod storage;
|
||||
|
||||
use std::{fmt::{Display, Formatter}, path::{Path, PathBuf}, str::FromStr};
|
||||
|
||||
pub use dpts_core::config::*;
|
||||
pub use storage::*;
|
||||
|
||||
|
||||
|
||||
use crate::error::Error;
|
||||
use serde::{
|
||||
Deserialize,
|
||||
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 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)]
|
||||
|
||||
pub struct Config {
|
||||
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)]
|
||||
pub struct ClientConfig {
|
||||
pub storage: ClientStorageConfig,
|
||||
|
@ -47,19 +92,19 @@ storage = "local"
|
|||
client: ClientConfig{
|
||||
storage: ClientStorageConfig::Local,
|
||||
},
|
||||
global: PartialGlobalConfig { time_zone: None },
|
||||
global: GlobalConfig { time_zone: None },
|
||||
}
|
||||
}).await
|
||||
}
|
||||
#[tokio::test]
|
||||
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);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
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]
|
||||
|
@ -80,19 +125,18 @@ time_zone = "UTC"
|
|||
access_key: "test".to_string(),
|
||||
})
|
||||
},
|
||||
global: PartialGlobalConfig { time_zone: Some(UTC) }
|
||||
global: GlobalConfig { time_zone: Some(UTC) }
|
||||
}
|
||||
}).await
|
||||
}
|
||||
#[tokio::test]
|
||||
async fn deserialize_remote_storage_client_config() {
|
||||
let config: Config = toml::from_str(REMOTE_STORAGE_CONFIG_TOML).unwrap();
|
||||
async fn deserialize_remote_storage_client_config() { let config: Config = Config::from_toml(REMOTE_STORAGE_CONFIG_TOML).unwrap();
|
||||
assert_eq!(&config, get_remote_storage_client_config_struct().await);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
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 config;
|
||||
pub mod error;
|
||||
|
||||
use error::Error;
|
||||
pub use dpts_core::error;
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ chrono = {workspace = true}
|
|||
chrono-tz.workspace = true
|
||||
clap = { workspace = true, optional = true }
|
||||
csv = "1.3.1"
|
||||
cynic = "3.10.0"
|
||||
dotenv = {workspace = true}
|
||||
dpts-migration = { workspace = true }
|
||||
iana-time-zone = "0.1.63"
|
||||
|
|
|
@ -9,14 +9,14 @@ use crate::Error;
|
|||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
pub struct GlobalConfig {
|
||||
pub time_zone: Tz,
|
||||
pub time_zone: Option<Tz>,
|
||||
}
|
||||
|
||||
impl TryFrom<PartialGlobalConfig> for GlobalConfig{
|
||||
type Error = Error;
|
||||
fn try_from(p: PartialGlobalConfig) -> Result<GlobalConfig, Self::Error> {
|
||||
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::{
|
||||
ActiveModel as UserActiveModel,
|
||||
Column as UserColumn,
|
||||
Entity as UserEntity,
|
||||
Model as UserModel,
|
||||
};
|
||||
|
|
|
@ -2,6 +2,9 @@ use async_graphql::SimpleObject;
|
|||
use chrono::{DateTime, FixedOffset,};
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::error::Error;
|
||||
|
||||
use crate::DATABASE_CONNECTION;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, SimpleObject, Deserialize)]
|
||||
#[sea_orm(table_name = "user")]
|
||||
|
@ -17,6 +20,22 @@ pub struct Model {
|
|||
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)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(has_many = "super::record_header::Entity")]
|
||||
|
@ -36,5 +55,10 @@ impl Related<super::record_tag::Entity> for Model {
|
|||
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)]
|
||||
pub enum Error {
|
||||
#[error("IO error")]
|
||||
Io(#[from] std::io::Error),
|
||||
#[error("Parse int error")]
|
||||
ParseInt(#[from] std::num::ParseIntError),
|
||||
#[error("Parse toml error")]
|
||||
#[error("Deserialize toml error")]
|
||||
TomlDe(#[from] toml::de::Error),
|
||||
#[error("Serialize toml error")]
|
||||
TomlSer(#[from] toml::ser::Error),
|
||||
#[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_header;
|
||||
mod record_tag;
|
||||
mod user;
|
||||
|
||||
pub use mutation::Mutation;
|
||||
pub use query::Query;
|
||||
pub use user::UserObject;
|
||||
pub use user::PartialUser;
|
|
@ -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 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 created_at: Option<DateTime<FixedOffset>>,
|
||||
pub updated_at: Option<DateTime<FixedOffset>>,
|
||||
}
|
||||
|
||||
#[Object]
|
||||
impl UserObject {
|
||||
async fn id(&self) -> i32 {
|
||||
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!()
|
||||
}
|
||||
#[derive(SimpleObject)]
|
||||
pub struct Users{
|
||||
users: Vec<UserModel>
|
||||
}
|
||||
|
||||
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_axum::GraphQL;
|
||||
use axum::{routing::get, Router};
|
||||
use dpts_core::graphql::{
|
||||
Query,
|
||||
Mutation,
|
||||
};
|
||||
|
||||
|
||||
pub fn build_schema() -> Schema<Query, Mutation, EmptySubscription>{
|
||||
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 crate::graphql::build_service;
|
||||
|
||||
use dpts_core::entity as entity;
|
||||
|
||||
|
||||
pub fn build_app() -> Router {
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
use async_graphql::{http::{playground_source, GraphQLPlaygroundConfig}, *};
|
||||
use async_graphql_axum::GraphQL;
|
||||
use dpts_core::graphql::{
|
||||
Mutation,
|
||||
Query,
|
||||
};
|
||||
|
||||
use dpts_server::{build_app, Args};
|
||||
use axum::{response::{Html, IntoResponse}, routing::get, Router};
|
||||
use clap::Parser;
|
||||
|
|
Loading…
Add table
Reference in a new issue