diff --git a/Cargo.lock b/Cargo.lock index a0c4b44..f9f0ad6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4270,11 +4270,13 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" name = "yet-another-nginx-proxy-manager" version = "0.1.0" dependencies = [ + "async-trait", "axum", "chrono", "config", "database", "migration", + "sea-orm", "serde", "serde_json", "tokio", diff --git a/apps/api/Cargo.toml b/apps/api/Cargo.toml index 55b3f06..87132f3 100644 --- a/apps/api/Cargo.toml +++ b/apps/api/Cargo.toml @@ -8,6 +8,7 @@ database = { path = "../../public/database" } migration = { path = "../../public/migration" } axum = { version = "0.8.7", features = ["form", "http1", "json", "matched-path", "original-uri", "query", "tokio", "tower-log", "tracing", "macros"]} +async-trait = { version = "0.1.89" } chrono = { version = "0.4.42", features = ["clock", "std", "oldtime", "wasmbind", "serde"] } config = { version = "0.15.19", features = ["toml", "json", "yaml", "ini", "ron", "json5", "convert-case", "async"] } tokio = { version = "1", features = ["fs", "io-util", "io-std", "macros", "net", "parking_lot", "process", "rt", "rt-multi-thread", "signal", "sync", "time", "tracing"] } @@ -16,3 +17,4 @@ tracing = { version = "0.1.41", features = ["std", "attributes"] } tracing-subscriber = { version = "0.3.20", features = ["smallvec", "fmt", "ansi", "tracing-log", "std", "chrono", "json", "serde", "serde_json", "time", "tracing"] } serde_json = { version = "1.0.145", features = ["std"] } serde = { version = "1.0.228", features = ["std", "derive"] } +sea-orm = { version = "2.0.0-rc" } diff --git a/apps/api/src/services.rs b/apps/api/src/services.rs new file mode 100644 index 0000000..6e98cef --- /dev/null +++ b/apps/api/src/services.rs @@ -0,0 +1 @@ +pub mod settings; diff --git a/apps/api/src/services/settings.rs b/apps/api/src/services/settings.rs new file mode 100644 index 0000000..c778427 --- /dev/null +++ b/apps/api/src/services/settings.rs @@ -0,0 +1,89 @@ +use std::sync::Arc; + +use database::generated::entities::config::{self, ActiveModel as ConfigActiveModel}; + +use sea_orm::{ + ActiveModelTrait, ActiveValue, ColumnTrait, DatabaseConnection, DbErr, EntityTrait, + IntoActiveModel, QueryFilter, +}; + +use crate::errors::service_error::{IntoServiceError, ServiceError}; + +#[async_trait::async_trait] +pub trait SettingsStore: Send + Sync { + async fn get_setting(&self, key: &str) -> Result; + async fn set_setting(&self, key: &str, value: String) -> Result<(), ServiceError>; +} + +pub struct SettingsService { + connection: Arc, +} + +impl SettingsService { + pub fn new(connection: Arc) -> Self { + Self { connection } + } +} + +#[async_trait::async_trait] +impl SettingsStore for SettingsService { + async fn get_setting(&self, key: &str) -> Result { + let setting = config::Entity::find() + .filter(config::Column::Key.eq(key)) + .one(&*self.connection) + .await; + + match setting { + Err(err) => Err(err.into_service_error()), + Ok(None) => Err( + DbErr::RecordNotFound(format!("Setting with key '{}' not found", key)) + .into_service_error(), + ), + Ok(Some(record)) => Ok(record.value), + } + } + + async fn set_setting(&self, key: &str, value: String) -> Result<(), ServiceError> { + let existing = config::Entity::find() + .filter(config::Column::Key.eq(key)) + .one(&*self.connection) + .await; + + let handle_not_found = async |key: String, value: String| { + let new_record = ConfigActiveModel { + key: ActiveValue::Set(key), + value: ActiveValue::Set(value), + created_at: ActiveValue::Set(chrono::Utc::now()), + updated_at: ActiveValue::Set(chrono::Utc::now()), + }; + new_record + .insert(&*self.connection) + .await + .map_err(|err| err.into_service_error()) + }; + + match existing { + Err(err) => match err { + DbErr::RecordNotFound(_) => { + handle_not_found(key.to_string(), value).await?; + } + _ => { + return Err(Box::new(err)); + } + }, + Ok(None) => { + handle_not_found(key.to_string(), value).await?; + } + Ok(Some(mut record)) => { + record.value = value; + record + .into_active_model() + .update(&*self.connection) + .await + .map_err(|err| err.into_service_error())?; + } + } + + Ok(()) + } +} diff --git a/public/database/src/lib.rs b/public/database/src/lib.rs index 7985e66..fb047b5 100644 --- a/public/database/src/lib.rs +++ b/public/database/src/lib.rs @@ -1,5 +1,5 @@ use log::LevelFilter; -pub use sea_orm::ConnectOptions; +use sea_orm::ConnectOptions; pub mod generated; pub async fn get_connection(