Skip to main content

shared/settings/
app.rs

1use crate::prelude::StringExt;
2
3use super::{
4    ExtensionSettings, SettingsDeserializeExt, SettingsDeserializer, SettingsSerializeExt,
5    SettingsSerializer,
6};
7use compact_str::ToCompactString;
8use serde::{Deserialize, Serialize};
9use utoipa::ToSchema;
10
11#[derive(ToSchema, Serialize, Deserialize, Clone, Copy)]
12#[serde(rename_all = "snake_case")]
13pub enum TwoFactorRequirement {
14    Admins,
15    AllUsers,
16    None,
17}
18
19#[derive(Clone, ToSchema, Serialize, Deserialize)]
20pub struct AppSettingsApp {
21    pub name: compact_str::CompactString,
22    pub icon: compact_str::CompactString,
23    pub icon_light: Option<compact_str::CompactString>,
24    pub banner: Option<compact_str::CompactString>,
25    pub banner_light: Option<compact_str::CompactString>,
26    pub url: compact_str::CompactString,
27    pub language: compact_str::CompactString,
28    pub two_factor_requirement: TwoFactorRequirement,
29
30    pub session_cookie: compact_str::CompactString,
31    pub session_duration_seconds: u64,
32
33    pub telemetry_enabled: bool,
34    pub registration_enabled: bool,
35}
36
37#[async_trait::async_trait]
38impl SettingsSerializeExt for AppSettingsApp {
39    async fn serialize(
40        &self,
41        serializer: SettingsSerializer,
42    ) -> Result<SettingsSerializer, anyhow::Error> {
43        Ok(serializer
44            .write_raw_setting("name", &*self.name)
45            .write_raw_setting("icon", &*self.icon)
46            .write_raw_setting("icon_light", self.icon_light.as_deref().unwrap_or(""))
47            .write_raw_setting("banner", self.banner.as_deref().unwrap_or(""))
48            .write_raw_setting("banner_light", self.banner_light.as_deref().unwrap_or(""))
49            .write_raw_setting("url", &*self.url)
50            .write_raw_setting("language", &*self.language)
51            .write_raw_setting(
52                "two_factor_requirement",
53                match self.two_factor_requirement {
54                    TwoFactorRequirement::Admins => "admins",
55                    TwoFactorRequirement::AllUsers => "all_users",
56                    TwoFactorRequirement::None => "none",
57                },
58            )
59            .write_raw_setting("session_cookie", &*self.session_cookie)
60            .write_raw_setting(
61                "session_duration_seconds",
62                self.session_duration_seconds.to_compact_string(),
63            )
64            .write_raw_setting(
65                "telemetry_enabled",
66                self.telemetry_enabled.to_compact_string(),
67            )
68            .write_raw_setting(
69                "registration_enabled",
70                self.registration_enabled.to_compact_string(),
71            ))
72    }
73}
74
75pub struct AppSettingsAppDeserializer;
76
77#[async_trait::async_trait]
78impl SettingsDeserializeExt for AppSettingsAppDeserializer {
79    async fn deserialize_boxed(
80        &self,
81        mut deserializer: SettingsDeserializer<'_>,
82    ) -> Result<ExtensionSettings, anyhow::Error> {
83        Ok(Box::new(AppSettingsApp {
84            name: deserializer
85                .take_raw_setting("name")
86                .unwrap_or_else(|| "Calagopus".into()),
87            icon: deserializer
88                .take_raw_setting("icon")
89                .unwrap_or_else(|| "/icon.svg".into()),
90            icon_light: deserializer
91                .take_raw_setting("icon_light")
92                .and_then(|s| s.into_optional()),
93            banner: deserializer
94                .take_raw_setting("banner")
95                .and_then(|s| s.into_optional()),
96            banner_light: deserializer
97                .take_raw_setting("banner_light")
98                .and_then(|s| s.into_optional()),
99            url: deserializer
100                .take_raw_setting("url")
101                .unwrap_or_else(|| "http://localhost:8000".into()),
102            language: deserializer
103                .take_raw_setting("language")
104                .unwrap_or_else(|| "en".into()),
105            two_factor_requirement: match deserializer
106                .take_raw_setting("two_factor_requirement")
107                .as_deref()
108            {
109                Some("admins") => TwoFactorRequirement::Admins,
110                Some("all_users") => TwoFactorRequirement::AllUsers,
111                _ => TwoFactorRequirement::None,
112            },
113            session_cookie: deserializer
114                .take_raw_setting("session_cookie")
115                .unwrap_or_else(|| "calagopus_session".into()),
116            session_duration_seconds: deserializer
117                .take_raw_setting("session_duration_seconds")
118                .and_then(|s| s.parse::<u64>().ok())
119                .unwrap_or(7 * 24 * 3600),
120            telemetry_enabled: deserializer
121                .take_raw_setting("telemetry_enabled")
122                .map(|s| s == "true")
123                .unwrap_or(true),
124            registration_enabled: deserializer
125                .take_raw_setting("registration_enabled")
126                .map(|s| s == "true")
127                .unwrap_or(true),
128        }))
129    }
130}