1
use crate::config::{ConfigError, ConfigOption, config_on, set_config_on};
2
use crate::db::DBError;
3
use cfg_if::cfg_if;
4
use sqlx::types::Uuid;
5

            
6
// `userpool` is the production per-user routing path. Its DB-facing half is
7
// excluded from server's own `cfg(test)` runs (see the module docs), where
8
// `get_connection` below short-circuits to the injected test pool; the
9
// bookkeeping half compiles always so it can be tested.
10
mod connection;
11
mod userpool;
12

            
13
pub use connection::TenantConnection;
14

            
15
pub struct User {
16
    pub id: Uuid,
17
}
18

            
19
impl User {
20
    cfg_if! {
21
        if #[cfg(test)] {
22
1077
        pub async fn get_connection(&self) -> Result<TenantConnection, DBError> {
23
1077
            crate::db::get_connection().await.map(TenantConnection::global)
24
1077
        }
25
        } else if #[cfg(feature = "test-utils")] {
26
24882
        pub async fn get_connection(&self) -> Result<TenantConnection, DBError> {
27
24882
            if crate::db::test_pool_is_set() {
28
22854
                crate::db::get_connection().await.map(TenantConnection::global)
29
            } else {
30
2028
                userpool::get_connection(self.id).await
31
            }
32
24882
        }
33
        } else {
34
        pub async fn get_connection(&self) -> Result<TenantConnection, DBError> {
35
            userpool::get_connection(self.id).await
36
        }
37
        }
38
    }
39

            
40
    /// Reads a config field from THIS user's database. Per-user config is
41
    /// isolated to the user's own DB (distinct from server-wide
42
    /// [`crate::config::system_config`]).
43
    ///
44
    /// # Errors
45
    /// [`ConfigError::DB`] on a connection or query error.
46
196
    pub async fn config(&self, field: &str) -> Result<Option<ConfigOption>, ConfigError> {
47
81
        let mut conn = self.get_connection().await.map_err(|_| ConfigError::DB)?;
48
81
        config_on(&mut conn, field).await
49
81
    }
50

            
51
    /// Writes a config field to THIS user's database.
52
    ///
53
    /// # Errors
54
    /// [`ConfigError::DB`] on a connection or query error.
55
196
    pub async fn set_config(&self, field: &str, contents: ConfigOption) -> Result<(), ConfigError> {
56
56
        let mut conn = self.get_connection().await.map_err(|_| ConfigError::DB)?;
57
56
        set_config_on(&mut conn, field, contents).await
58
56
    }
59
}
60

            
61
#[cfg(test)]
62
impl User {
63
    /// `verified = TRUE`: the fixture is a usable account.
64
130
    pub async fn commit(&self) -> Result<(), sqlx::Error> {
65
130
        let mut conn = self.get_connection().await.unwrap();
66

            
67
130
        sqlx::query!(
68
            "INSERT INTO users (
69
                id, user_name, email, photo, verified, user_password, user_role, database_name, created_at
70
            ) VALUES (
71
                $1, 'Test User', 'test@example.com', 'default.png',
72
                TRUE, 'password123', 'user', 'database', NOW()
73
            )",
74
            self.id,
75
        )
76
130
        .execute(&mut *conn)
77
130
        .await?;
78

            
79
130
        Ok(())
80
130
    }
81
}