Skip to main content

server/command/
config.rs

1use sqlx::Row;
2use std::fmt::Debug;
3use supp_macro::command;
4
5use super::{CmdError, CmdResult};
6use crate::{
7    config::{ConfigError, ConfigOption, config, set_config},
8    db::get_connection,
9};
10command! {
11    GetConfig {
12        #[required]
13        name: String,
14    } => {
15        Ok(config(&name).await?.map(|v| match v {
16            ConfigOption::String(s) => CmdResult::String(s),
17            ConfigOption::Blob(b) => CmdResult::Data(b),
18        }))
19    }
20}
21
22command! {
23    GetVersion {
24    } => {
25        const HASH: &str = env!("GIT_HASH");
26        Ok(Some(CmdResult::String(HASH.to_string())))
27    }
28}
29
30command! {
31    GetBuildDate {
32    } => {
33    const BUILD: &str = env!("BUILD_DATE");
34        Ok(Some(CmdResult::String(BUILD.to_string())))
35    }
36}
37
38command! {
39    SetConfig {
40        #[required]
41        name: String,
42        #[required]
43        value: String,
44    } => {
45        set_config(&name, ConfigOption::String(value)).await?;
46        Ok(None)
47    }
48}
49
50command! {
51    SelectColumn {
52        #[required]
53        field: String,
54        #[required]
55        table: String,
56    } => {
57        let mut conn = get_connection().await.map_err(|err| {
58            log::error!("{}", t!("Database error: %{err}", err = err : {:?}));
59            ConfigError::DB
60        })?;
61
62        let values: Vec<String> = sqlx::query(&format!("SELECT {field}::text FROM {table}"))
63            .fetch_all(&mut *conn)
64            .await?
65            .into_iter()
66            .map(|row| row.get::<Option<String>, _>(0).unwrap_or_default())
67            .collect();
68
69        Ok(Some(CmdResult::Lines(values)))
70    }
71}
72
73#[cfg(test)]
74mod command_config_tests {
75    use super::*;
76    use crate::{db::DB_POOL, user::User};
77    use sqlx::{PgPool, types::Uuid};
78    use supp_macro::local_db_sqlx_test;
79    use tokio::sync::OnceCell;
80
81    /// Context for keeping environment intact
82    static CONTEXT: OnceCell<()> = OnceCell::const_new();
83    static USER: OnceCell<User> = OnceCell::const_new();
84
85    async fn setup() {
86        CONTEXT
87            .get_or_init(|| async {
88                #[cfg(feature = "testlog")]
89                let _ = env_logger::builder()
90                    .is_test(true)
91                    .filter_level(log::LevelFilter::Trace)
92                    .try_init();
93            })
94            .await;
95        USER.get_or_init(|| async { User { id: Uuid::new_v4() } })
96            .await;
97    }
98
99    #[local_db_sqlx_test]
100    async fn test_config_string(pool: PgPool) -> anyhow::Result<()> {
101        let opt = ConfigOption::String("testval".to_string());
102        crate::config::set_config("testfield", opt.clone())
103            .await
104            .unwrap();
105
106        let val = GetConfig::new()
107            .name("testfield".to_string())
108            .run()
109            .await?
110            .unwrap();
111        assert_eq!(opt.to_string(), val.to_string());
112    }
113}