Origin changes merged: - SMB performance optimization (pread/pwrite, tokio Mutex) - macOS SMB mount fix (AAPL caps, credit grant) - Compound request integration tests - CTDB architecture analysis Local changes preserved: - upload_path config (deployed, tested stable) - delete_file + preview_file routes (MyFiles UI) - SSH async I/O (cipher.rs, packet.rs, server.rs) - auth.sqlite (86016 bytes, important user data) - Admin WebDAV + CorsLayer - api/admin.rs + api/config.rs (new endpoints) Conflicts resolved: - myfiles.rs: kept upload_path + OnceLock static - auth.sqlite: preserved local version (important data) Test results: 393 passed, 5 auth tests failed - PG tests require external PostgreSQL - Auth tests expect specific password hashes - auth.sqlite preserved with actual user credentials
209 lines
7.2 KiB
Rust
209 lines
7.2 KiB
Rust
use axum::{
|
|
extract::Query,
|
|
http::StatusCode,
|
|
response::{IntoResponse, Json},
|
|
};
|
|
|
|
#[derive(Debug, serde::Deserialize)]
|
|
pub struct EditConfigQuery {
|
|
pub key: String,
|
|
pub value: String,
|
|
}
|
|
|
|
pub async fn get_config_handler() -> impl IntoResponse {
|
|
let config_path = std::path::Path::new("config/markbase.toml");
|
|
|
|
// Return defaults if config file doesn't exist yet (loadSettings in admin UI needs it)
|
|
if !config_path.exists() {
|
|
let mut config = crate::config::MarkBaseConfig::default_config();
|
|
config.merge_env();
|
|
return (
|
|
StatusCode::OK,
|
|
Json(serde_json::to_value(&config).unwrap_or_default()),
|
|
)
|
|
.into_response();
|
|
}
|
|
|
|
match crate::config::MarkBaseConfig::load(config_path) {
|
|
Ok(config) => (
|
|
StatusCode::OK,
|
|
Json(serde_json::to_value(&config).unwrap_or_default()),
|
|
)
|
|
.into_response(),
|
|
Err(e) => (
|
|
StatusCode::INTERNAL_SERVER_ERROR,
|
|
Json(serde_json::json!({"error": e.to_string()})),
|
|
)
|
|
.into_response(),
|
|
}
|
|
}
|
|
|
|
pub async fn edit_config_handler(Query(params): Query<EditConfigQuery>) -> impl IntoResponse {
|
|
let config_path = std::path::Path::new("config/markbase.toml");
|
|
|
|
// Load existing or use defaults, so admin can save settings without a pre-existing file
|
|
let mut config = if config_path.exists() {
|
|
match crate::config::MarkBaseConfig::load(config_path) {
|
|
Ok(c) => c,
|
|
Err(e) => {
|
|
return (StatusCode::INTERNAL_SERVER_ERROR,
|
|
Json(serde_json::json!({"error": e.to_string()}))).into_response();
|
|
}
|
|
}
|
|
} else {
|
|
let mut defaults = crate::config::MarkBaseConfig::default_config();
|
|
defaults.merge_env();
|
|
defaults
|
|
};
|
|
|
|
let old_value = config.get(¶ms.key).unwrap_or_default();
|
|
|
|
match config.set(¶ms.key, ¶ms.value) {
|
|
Ok(_) => match config.validate() {
|
|
Ok(_) => match config.save(config_path) {
|
|
Ok(_) => {
|
|
let audit = crate::audit::AuditLogger::default();
|
|
if let Err(e) = audit.log_config_change(
|
|
"markbase",
|
|
¶ms.key,
|
|
&old_value,
|
|
¶ms.value,
|
|
"system",
|
|
None,
|
|
) {
|
|
log::warn!("Failed to write audit log: {}", e);
|
|
}
|
|
|
|
(StatusCode::OK, Json(serde_json::json!({"ok": true}))).into_response()
|
|
}
|
|
Err(e) => (
|
|
StatusCode::INTERNAL_SERVER_ERROR,
|
|
Json(serde_json::json!({"error": e.to_string()})),
|
|
)
|
|
.into_response(),
|
|
},
|
|
Err(e) => (
|
|
StatusCode::BAD_REQUEST,
|
|
Json(serde_json::json!({"error": e.to_string()})),
|
|
)
|
|
.into_response(),
|
|
},
|
|
Err(e) => (
|
|
StatusCode::BAD_REQUEST,
|
|
Json(serde_json::json!({"error": e.to_string()})),
|
|
)
|
|
.into_response(),
|
|
}
|
|
}
|
|
|
|
pub async fn validate_config_handler() -> impl IntoResponse {
|
|
let config_path = std::path::Path::new("config/markbase.toml");
|
|
|
|
if !config_path.exists() {
|
|
return (
|
|
StatusCode::NOT_FOUND,
|
|
Json(serde_json::json!({"ok": false, "error": "Config file not found"})),
|
|
)
|
|
.into_response();
|
|
}
|
|
|
|
match crate::config::MarkBaseConfig::load(config_path) {
|
|
Ok(config) => match config.validate() {
|
|
Ok(_) => (StatusCode::OK, Json(serde_json::json!({"ok": true}))).into_response(),
|
|
Err(e) => (
|
|
StatusCode::BAD_REQUEST,
|
|
Json(serde_json::json!({"ok": false, "error": e.to_string()})),
|
|
)
|
|
.into_response(),
|
|
},
|
|
Err(e) => (
|
|
StatusCode::INTERNAL_SERVER_ERROR,
|
|
Json(serde_json::json!({"ok": false, "error": e.to_string()})),
|
|
)
|
|
.into_response(),
|
|
}
|
|
}
|
|
|
|
pub async fn get_s3_config_handler() -> impl IntoResponse {
|
|
match crate::s3_config::S3Config::load_default() {
|
|
Ok(config) => (
|
|
StatusCode::OK,
|
|
Json(serde_json::to_value(&config).unwrap_or_default()),
|
|
)
|
|
.into_response(),
|
|
Err(e) => (
|
|
StatusCode::INTERNAL_SERVER_ERROR,
|
|
Json(serde_json::json!({"error": e.to_string()})),
|
|
)
|
|
.into_response(),
|
|
}
|
|
}
|
|
|
|
pub async fn edit_s3_config_handler(Query(params): Query<EditConfigQuery>) -> impl IntoResponse {
|
|
match crate::s3_config::S3Config::load_default() {
|
|
Ok(mut config) => {
|
|
let old_value = config.get(¶ms.key).unwrap_or_default();
|
|
|
|
match config.set(¶ms.key, ¶ms.value) {
|
|
Ok(_) => match config.validate() {
|
|
Ok(_) => match config.save("config/s3.toml") {
|
|
Ok(_) => {
|
|
let audit = crate::audit::AuditLogger::default();
|
|
if let Err(e) = audit.log_config_change(
|
|
"s3",
|
|
¶ms.key,
|
|
&old_value,
|
|
¶ms.value,
|
|
"system",
|
|
None,
|
|
) {
|
|
log::warn!("Failed to write audit log: {}", e);
|
|
}
|
|
|
|
(StatusCode::OK, Json(serde_json::json!({"ok": true}))).into_response()
|
|
}
|
|
Err(e) => (
|
|
StatusCode::INTERNAL_SERVER_ERROR,
|
|
Json(serde_json::json!({"error": e.to_string()})),
|
|
)
|
|
.into_response(),
|
|
},
|
|
Err(e) => (
|
|
StatusCode::BAD_REQUEST,
|
|
Json(serde_json::json!({"error": e.to_string()})),
|
|
)
|
|
.into_response(),
|
|
},
|
|
Err(e) => (
|
|
StatusCode::BAD_REQUEST,
|
|
Json(serde_json::json!({"error": e.to_string()})),
|
|
)
|
|
.into_response(),
|
|
}
|
|
}
|
|
Err(e) => (
|
|
StatusCode::INTERNAL_SERVER_ERROR,
|
|
Json(serde_json::json!({"error": e.to_string()})),
|
|
)
|
|
.into_response(),
|
|
}
|
|
}
|
|
|
|
pub async fn validate_s3_config_handler() -> impl IntoResponse {
|
|
match crate::s3_config::S3Config::load_default() {
|
|
Ok(config) => match config.validate() {
|
|
Ok(_) => (StatusCode::OK, Json(serde_json::json!({"ok": true}))).into_response(),
|
|
Err(e) => (
|
|
StatusCode::BAD_REQUEST,
|
|
Json(serde_json::json!({"ok": false, "error": e.to_string()})),
|
|
)
|
|
.into_response(),
|
|
},
|
|
Err(e) => (
|
|
StatusCode::INTERNAL_SERVER_ERROR,
|
|
Json(serde_json::json!({"ok": false, "error": e.to_string()})),
|
|
)
|
|
.into_response(),
|
|
}
|
|
}
|