tuitbot_server/routes/settings/
mod.rs1pub mod handlers;
8pub mod validation;
9
10#[cfg(test)]
11mod tests;
12pub use handlers::{config_status, get_settings, init_settings, patch_settings, validate_settings};
16pub use validation::{factory_reset, get_defaults, merge_patch_and_parse, test_llm};
17
18use serde::{Deserialize, Serialize};
19use tuitbot_core::error::ConfigError;
20
21#[derive(Deserialize)]
26pub struct TestLlmRequest {
27 pub provider: String,
28 #[serde(default)]
29 pub api_key: Option<String>,
30 #[serde(default)]
31 pub model: String,
32 #[serde(default)]
33 pub base_url: Option<String>,
34}
35
36pub(super) const FACTORY_RESET_PHRASE: &str = "RESET TUITBOT";
42
43#[derive(Deserialize)]
44pub struct FactoryResetRequest {
45 pub confirmation: String,
46}
47
48#[derive(Serialize)]
49pub(super) struct FactoryResetResponse {
50 pub status: String,
51 pub cleared: FactoryResetCleared,
52}
53
54#[derive(Serialize)]
55pub(super) struct FactoryResetCleared {
56 pub tables_cleared: u32,
57 pub rows_deleted: u64,
58 pub config_deleted: bool,
59 pub passphrase_deleted: bool,
60 pub media_deleted: bool,
61 pub credentials_deleted: bool,
62 pub runtimes_stopped: u32,
63}
64
65#[derive(Deserialize)]
71pub(super) struct ClaimRequest {
72 pub passphrase: String,
73}
74
75#[derive(Deserialize)]
80pub(super) struct XProfileData {
81 pub x_user_id: String,
82 pub x_username: String,
83 pub x_display_name: String,
84 #[serde(default)]
85 pub x_avatar_url: Option<String>,
86}
87
88#[derive(Serialize)]
89pub(super) struct ValidationResponse {
90 pub valid: bool,
91 #[serde(skip_serializing_if = "Vec::is_empty")]
92 pub errors: Vec<ValidationErrorItem>,
93}
94
95#[derive(Serialize)]
96pub(super) struct ValidationErrorItem {
97 pub field: String,
98 pub message: String,
99}
100
101#[derive(Serialize)]
102pub(super) struct TestResult {
103 pub success: bool,
104 #[serde(skip_serializing_if = "Option::is_none")]
105 pub error: Option<String>,
106 #[serde(skip_serializing_if = "Option::is_none")]
107 pub latency_ms: Option<u64>,
108}
109
110pub(super) fn config_errors_to_response(errors: Vec<ConfigError>) -> Vec<ValidationErrorItem> {
115 errors
116 .into_iter()
117 .map(|e| match e {
118 ConfigError::MissingField { field } => ValidationErrorItem {
119 field,
120 message: "this field is required".to_string(),
121 },
122 ConfigError::InvalidValue { field, message } => ValidationErrorItem { field, message },
123 other => ValidationErrorItem {
124 field: String::new(),
125 message: other.to_string(),
126 },
127 })
128 .collect()
129}