Skip to main content

hvz/
settings.rs

1use std::{io, str::FromStr};
2
3use diesel::{
4    ExpressionMethods, QueryDsl, RunQueryDsl, Selectable,
5    prelude::{Insertable, Queryable},
6};
7use serde::{Deserialize, Serialize};
8
9use crate::{establish_connection, schema::settings};
10
11pub const HAS_STARTED: &str = "has_started";
12pub const MAINTENANCE: &str = "maintenance";
13pub const CHECKPOINT: &str = "checkpoint";
14pub const Z0_REVEALED: &str = "z0_revealed";
15pub const UPLOAD_PATH: &str = "./uploads";
16
17/// Settings struct
18#[derive(Clone, Debug, Serialize, Deserialize, Selectable, Queryable, Insertable)]
19#[diesel(table_name = crate::schema::settings)]
20#[diesel(check_for_backend(diesel::mysql::Mysql))]
21pub struct Settings {
22    pub id: String,
23    pub settings_key: String,
24    pub settings_value: String,
25}
26
27/// Implementation of the Settings struct
28impl Settings {
29    /// New settings from a key/value pair
30    /// 
31    /// # Arguments
32    /// * `key` - The key of the setting
33    /// * `value` - The value of the setting
34    /// 
35    /// # Returns
36    /// * `Self` - The new settings
37    pub fn new(key: &str, value: &str) -> Self {
38        Self {
39            id: uuid::Uuid::new_v4().to_string(),
40            settings_key: String::from(key),
41            settings_value: String::from(value),
42        }
43    }
44    
45    /// Set a settings
46    ///
47    /// It uses a generic type to set the value of the setting
48    ///
49    /// # Arguments
50    /// * `key` - The key of the setting to set
51    /// * `value` - The value of the setting to set
52    ///
53    /// # Returns
54    /// * `Result<Settings, String>` - The updated settings or an error message
55    pub async fn set_settings<T: ToString>(key: &str, value: T) -> Result<Settings, String>
56    {
57        let connection = &mut establish_connection();
58
59        let settings = Settings::new(key, &value.to_string());
60
61        let count = settings::table
62            .filter(settings::settings_key.eq(settings.settings_key.clone()))
63            .count()
64            .first::<i64>(connection)
65            .expect("Failed to count settings");
66
67        if count == 0 {
68            diesel::insert_into(settings::table)
69                .values(settings.clone())
70                .execute(connection)
71                .expect("Failed to insert settings");
72        } else {
73            diesel::update(settings::table)
74                .filter(settings::settings_key.eq(settings.settings_key.clone()))
75                .set(settings::settings_value.eq(settings.settings_value.clone()))
76                .execute(connection)
77                .expect("Failed to update settings");
78        }
79
80        Ok(settings)
81    }
82
83    /// Get a setting
84    ///
85    /// It uses a generic type to get the value of the setting
86    ///
87    /// # Arguments
88    /// * `key` - The key of the setting to get
89    ///
90    /// # Returns
91    /// * `Result<T, <T as FromStr>::Err>` - The value of the setting or an error message
92    pub async fn get_settings<T: FromStr>(key: &str) -> Result<T, <T as FromStr>::Err>
93    {
94        let connection = &mut establish_connection();
95
96        let settings = settings::table
97            .filter(settings::settings_key.eq(&key))
98            .first::<Settings>(connection)
99            .expect("Key not found");
100
101        settings.settings_value.parse::<T>()
102    }
103
104    /// Initialize the settings
105    ///
106    /// # Returns
107    /// * `Result<(), String>` - An error message if the settings could not be initialized
108    pub async fn init_settings() -> io::Result<()> {
109        let connection = &mut establish_connection();
110
111        let settings = vec![
112            Settings::new(HAS_STARTED, "false"),
113            Settings::new(MAINTENANCE, "false"),
114            Settings::new(CHECKPOINT, ""),
115            Settings::new(Z0_REVEALED, "false"),
116        ];
117
118        for setting in settings {
119            if settings::table
120                .filter(settings::settings_key.eq(&setting.settings_key))
121                .first::<Settings>(connection)
122                .is_ok()
123            {
124                continue;
125            }
126            
127            diesel::insert_into(settings::table)
128                .values(&setting)
129                .execute(connection)
130                .expect("Failed to insert setting");
131        }
132
133        Ok(())
134    }
135}