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