Private
Public Access
1
0

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

This commit is contained in:
2026-05-13 00:07:46 +00:00
parent c8b1feee19
commit c8b6b01dbc
2 changed files with 56 additions and 56 deletions

View File

@ -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,

View File

@ -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)
}