fix: resolve settings save failure - boolean type mismatch and improve error messages
All checks were successful
CI Pipeline / Rust Format Check (push) Successful in 4s
CI Pipeline / Clippy Lints (push) Successful in 57s
CI Pipeline / Rust Unit Tests (push) Successful in 1m19s
CI Pipeline / Security Audit (push) Successful in 4s
CI Pipeline / Frontend Lint & Type Check (push) Successful in 15s
CI Pipeline / Build .deb & Release (push) Has been skipped
All checks were successful
CI Pipeline / Rust Format Check (push) Successful in 4s
CI Pipeline / Clippy Lints (push) Successful in 57s
CI Pipeline / Rust Unit Tests (push) Successful in 1m19s
CI Pipeline / Security Audit (push) Successful in 4s
CI Pipeline / Frontend Lint & Type Check (push) Successful in 15s
CI Pipeline / Build .deb & Release (push) Has been skipped
This commit is contained in:
@ -293,62 +293,57 @@ async fn update_settings(
|
||||
admin_only(&auth)?;
|
||||
|
||||
// Update Azure SSO config
|
||||
if let Some(azure) = &req.azure_sso {
|
||||
// Build dynamic UPDATE query — only set fields that are Some
|
||||
let mut sets = Vec::new();
|
||||
let mut vals: Vec<String> = Vec::new();
|
||||
let mut idx = 1;
|
||||
// Use static queries with proper typed bindings to avoid boolean→string mismatch
|
||||
if let Some(azure) = req.azure_sso {
|
||||
let update_secret = azure.client_secret.as_ref().is_some_and(|s| s != MASKED);
|
||||
|
||||
if let Some(v) = azure.enabled {
|
||||
sets.push(format!("enabled = ${}", idx));
|
||||
vals.push(v.to_string());
|
||||
idx += 1;
|
||||
}
|
||||
if let Some(ref v) = azure.tenant_id {
|
||||
sets.push(format!("tenant_id = ${}", idx));
|
||||
vals.push(v.clone());
|
||||
idx += 1;
|
||||
}
|
||||
if let Some(ref v) = azure.client_id {
|
||||
sets.push(format!("client_id = ${}", idx));
|
||||
vals.push(v.clone());
|
||||
idx += 1;
|
||||
}
|
||||
if let Some(ref v) = azure.client_secret {
|
||||
if v != MASKED {
|
||||
sets.push(format!("client_secret = ${}", idx));
|
||||
vals.push(v.clone());
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
if let Some(ref v) = azure.redirect_uri {
|
||||
sets.push(format!("redirect_uri = ${}", idx));
|
||||
vals.push(v.clone());
|
||||
idx += 1;
|
||||
}
|
||||
if let Some(ref v) = azure.scopes {
|
||||
sets.push(format!("scopes = ${}", idx));
|
||||
vals.push(v.clone());
|
||||
idx += 1;
|
||||
}
|
||||
let result = if update_secret {
|
||||
sqlx::query(
|
||||
"UPDATE azure_sso_config SET \
|
||||
enabled = COALESCE($1, enabled), \
|
||||
tenant_id = COALESCE($2, tenant_id), \
|
||||
client_id = COALESCE($3, client_id), \
|
||||
client_secret = $4, \
|
||||
redirect_uri = COALESCE($5, redirect_uri), \
|
||||
scopes = COALESCE($6, scopes), \
|
||||
updated_at = NOW() \
|
||||
WHERE id = 1",
|
||||
)
|
||||
.bind(azure.enabled)
|
||||
.bind(&azure.tenant_id)
|
||||
.bind(&azure.client_id)
|
||||
.bind(azure.client_secret.as_deref().unwrap_or(""))
|
||||
.bind(&azure.redirect_uri)
|
||||
.bind(&azure.scopes)
|
||||
.execute(&state.db)
|
||||
.await
|
||||
} else {
|
||||
sqlx::query(
|
||||
"UPDATE azure_sso_config SET \
|
||||
enabled = COALESCE($1, enabled), \
|
||||
tenant_id = COALESCE($2, tenant_id), \
|
||||
client_id = COALESCE($3, client_id), \
|
||||
redirect_uri = COALESCE($4, redirect_uri), \
|
||||
scopes = COALESCE($5, scopes), \
|
||||
updated_at = NOW() \
|
||||
WHERE id = 1",
|
||||
)
|
||||
.bind(azure.enabled)
|
||||
.bind(&azure.tenant_id)
|
||||
.bind(&azure.client_id)
|
||||
.bind(&azure.redirect_uri)
|
||||
.bind(&azure.scopes)
|
||||
.execute(&state.db)
|
||||
.await
|
||||
};
|
||||
|
||||
if !sets.is_empty() {
|
||||
let sql = format!(
|
||||
"UPDATE azure_sso_config SET {}, updated_at = NOW() WHERE id = 1",
|
||||
sets.join(", ")
|
||||
);
|
||||
let mut q = sqlx::query(&sql);
|
||||
for val in &vals {
|
||||
q = q.bind(val);
|
||||
}
|
||||
q.execute(&state.db).await.map_err(|e| {
|
||||
tracing::error!(error = %e, "Failed to update azure_sso_config");
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!({ "error": { "code": "internal_error", "message": "Database error" } })),
|
||||
)
|
||||
})?;
|
||||
}
|
||||
result.map_err(|e| {
|
||||
tracing::error!(error = %e, "Failed to update azure_sso_config");
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!({ "error": { "code": "internal_error", "message": format!("Failed to update Azure SSO config: {}", e) } })),
|
||||
)
|
||||
})?;
|
||||
|
||||
log_event(
|
||||
&state.db,
|
||||
|
||||
@ -5,6 +5,7 @@ import {
|
||||
IconButton, InputLabel, MenuItem, Select, Snackbar, Switch, TextField,
|
||||
Toolbar, Typography,
|
||||
} from '@mui/material'
|
||||
import type { AxiosError } from 'axios'
|
||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
|
||||
import SaveIcon from '@mui/icons-material/Save'
|
||||
import DeleteIcon from '@mui/icons-material/Delete'
|
||||
@ -78,8 +79,12 @@ export default function SettingsPage() {
|
||||
notification,
|
||||
})
|
||||
setSuccess('Settings saved successfully')
|
||||
} catch {
|
||||
setError('Failed to save settings')
|
||||
} catch (err: unknown) {
|
||||
const axiosErr = err as AxiosError<{ error?: { message?: string } }>
|
||||
const msg =
|
||||
axiosErr.response?.data?.error?.message ??
|
||||
(err instanceof Error ? err.message : 'Failed to save settings')
|
||||
setError(msg)
|
||||
} finally {
|
||||
setSaving(false)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user