cloudillo_core/settings/
handler.rs1use axum::{
7 extract::{Path, Query, State},
8 http::StatusCode,
9 Json,
10};
11use serde::Deserialize;
12
13use crate::{
14 extract::{Auth, OptionalRequestId},
15 prelude::*,
16 settings::types::SettingValue,
17};
18use cloudillo_types::types::ApiResponse;
19
20#[derive(serde::Serialize)]
22pub struct SettingResponse {
23 pub key: String,
24 pub value: SettingValue,
25 pub scope: String,
26 pub permission: String,
27 pub description: String,
28}
29
30#[derive(Deserialize, Default)]
32pub struct ListSettingsQuery {
33 pub prefix: Option<String>,
35}
36
37pub async fn list_settings(
41 State(app): State<App>,
42 Auth(auth): Auth,
43 Query(query): Query<ListSettingsQuery>,
44 OptionalRequestId(req_id): OptionalRequestId,
45) -> ClResult<(StatusCode, Json<ApiResponse<Vec<SettingResponse>>>)> {
46 let mut settings_response = Vec::new();
47
48 if let Some(ref prefix) = query.prefix {
49 for (key, value, definition) in app.settings.list_by_prefix(auth.tn_id, prefix).await? {
52 settings_response.push(SettingResponse {
53 key,
54 value,
55 scope: format!("{:?}", definition.scope),
56 permission: format!("{:?}", definition.permission),
57 description: definition.description.clone(),
58 });
59 }
60 } else {
61 for definition in app.settings_registry.list() {
63 if let Ok(value) = app.settings.get(auth.tn_id, &definition.key).await {
64 settings_response.push(SettingResponse {
65 key: definition.key.clone(),
66 value,
67 scope: format!("{:?}", definition.scope),
68 permission: format!("{:?}", definition.permission),
69 description: definition.description.clone(),
70 });
71 }
72 }
73 }
74
75 let total = settings_response.len();
76 let response = ApiResponse::with_pagination(settings_response, 0, 100, total)
77 .with_req_id(req_id.unwrap_or_default());
78
79 Ok((StatusCode::OK, Json(response)))
80}
81
82pub async fn get_setting(
84 State(app): State<App>,
85 Auth(auth): Auth,
86 Path(name): Path<String>,
87 OptionalRequestId(req_id): OptionalRequestId,
88) -> ClResult<(StatusCode, Json<ApiResponse<SettingResponse>>)> {
89 let definition = app.settings_registry.get(&name).ok_or(Error::NotFound)?;
91
92 let value = app.settings.get(auth.tn_id, &name).await?;
94
95 let response_data = SettingResponse {
96 key: definition.key.clone(),
97 value,
98 scope: format!("{:?}", definition.scope),
99 permission: format!("{:?}", definition.permission),
100 description: definition.description.clone(),
101 };
102
103 let response = ApiResponse::new(response_data).with_req_id(req_id.unwrap_or_default());
104
105 Ok((StatusCode::OK, Json(response)))
106}
107
108#[derive(Deserialize)]
111pub struct UpdateSettingRequest {
112 pub value: SettingValue,
113}
114
115pub async fn update_setting(
116 State(app): State<App>,
117 Auth(auth): Auth,
118 Path(name): Path<String>,
119 OptionalRequestId(req_id): OptionalRequestId,
120 Json(req): Json<UpdateSettingRequest>,
121) -> ClResult<(StatusCode, Json<ApiResponse<SettingResponse>>)> {
122 let definition = app.settings_registry.get(&name).ok_or(Error::NotFound)?;
124
125 if !definition.permission.check(&auth.roles) {
127 warn!("User {} attempted to update setting {} without permission", auth.id_tag, name);
128 return Err(Error::PermissionDenied);
129 }
130
131 if let Some(ref validator) = definition.validator {
133 validator(&req.value)?;
134 }
135
136 app.settings.set(auth.tn_id, &name, req.value.clone(), &auth.roles).await?;
138
139 info!("User {} updated setting {} in tenant {}", auth.id_tag, name, auth.tn_id);
140
141 let value = app.settings.get(auth.tn_id, &name).await?;
143
144 let response_data = SettingResponse {
145 key: definition.key.clone(),
146 value,
147 scope: format!("{:?}", definition.scope),
148 permission: format!("{:?}", definition.permission),
149 description: definition.description.clone(),
150 };
151
152 let response = ApiResponse::new(response_data).with_req_id(req_id.unwrap_or_default());
153
154 Ok((StatusCode::OK, Json(response)))
155}
156
157