1
use sqlx::Row;
2
use sqlx::types::Uuid;
3
use std::fmt::Debug;
4
use supp_macro::command;
5

            
6
use super::{CmdError, CmdResult};
7
use crate::{
8
    config::{ConfigError, ConfigOption},
9
    db::get_connection,
10
    user::User,
11
};
12
command! {
13
    GetConfig {
14
        #[required]
15
        user_id: Uuid,
16
        #[required]
17
        name: String,
18
    } => {
19
        let user = User { id: user_id };
20
37
        Ok(user.config(&name).await?.map(|v| match v {
21
37
            ConfigOption::String(s) => CmdResult::String(s),
22
            ConfigOption::Blob(b) => CmdResult::Data(b),
23
37
        }))
24
    }
25
301
}
26

            
27
command! {
28
    GetVersion {
29
    } => {
30
        const HASH: &str = env!("GIT_HASH");
31
        Ok(Some(CmdResult::String(HASH.to_string())))
32
    }
33
147
}
34

            
35
command! {
36
    GetBuildDate {
37
    } => {
38
    const BUILD: &str = env!("BUILD_DATE");
39
        Ok(Some(CmdResult::String(BUILD.to_string())))
40
    }
41
118
}
42

            
43
command! {
44
    SetConfig {
45
        #[required]
46
        user_id: Uuid,
47
        #[required]
48
        name: String,
49
        #[required]
50
        value: String,
51
    } => {
52
        let user = User { id: user_id };
53
        user.set_config(&name, ConfigOption::String(value)).await?;
54
        Ok(None)
55
    }
56
131
}
57

            
58
command! {
59
    SelectColumn {
60
        #[required]
61
        field: String,
62
        #[required]
63
        table: String,
64
    } => {
65
        let mut conn = get_connection().await.map_err(|err| {
66
            log::error!("{}", t!("Database error: %{err}", err = err : {:?}));
67
            ConfigError::DB
68
        })?;
69

            
70
        let values: Vec<String> = sqlx::query(&format!("SELECT {field}::text FROM {table}"))
71
            .fetch_all(&mut *conn)
72
            .await?
73
            .into_iter()
74
            .map(|row| row.get::<Option<String>, _>(0).unwrap_or_default())
75
            .collect();
76

            
77
        Ok(Some(CmdResult::Lines(values)))
78
    }
79
}
80

            
81
#[cfg(test)]
82
mod command_config_tests {
83
    use super::*;
84
    use crate::{db::DB_POOL, user::User};
85
    use sqlx::{PgPool, types::Uuid};
86
    use supp_macro::local_db_sqlx_test;
87
    use tokio::sync::OnceCell;
88

            
89
    /// Context for keeping environment intact
90
    static CONTEXT: OnceCell<()> = OnceCell::const_new();
91
    static USER: OnceCell<User> = OnceCell::const_new();
92

            
93
1
    async fn setup() {
94
1
        CONTEXT
95
1
            .get_or_init(|| async {
96
                #[cfg(feature = "testlog")]
97
1
                let _ = env_logger::builder()
98
1
                    .is_test(true)
99
1
                    .filter_level(log::LevelFilter::Trace)
100
1
                    .try_init();
101
2
            })
102
1
            .await;
103
2
        USER.get_or_init(|| async { User { id: Uuid::new_v4() } })
104
1
            .await;
105
1
    }
106

            
107
    #[local_db_sqlx_test]
108
    async fn set_then_get_config_round_trips_per_user(pool: PgPool) -> anyhow::Result<()> {
109
        let user_id = Uuid::new_v4();
110
        SetConfig::new()
111
            .user_id(user_id)
112
            .name("testfield".to_string())
113
            .value("testval".to_string())
114
            .run()
115
            .await?;
116

            
117
        let val = GetConfig::new()
118
            .user_id(user_id)
119
            .name("testfield".to_string())
120
            .run()
121
            .await?
122
            .unwrap();
123
        assert_eq!(val.to_string(), "testval");
124
    }
125
}