Merge origin SMB fixes with local Phase 21-22 features
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
This commit is contained in:
208
markbase-core/src/api/config.rs
Normal file
208
markbase-core/src/api/config.rs
Normal file
@@ -0,0 +1,208 @@
|
||||
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(),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user