Skip to main content

server/
user.rs

1use crate::config::{ConfigError, ConfigOption, config_on, set_config_on};
2use crate::db::DBError;
3use cfg_if::cfg_if;
4use 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.
10mod connection;
11mod userpool;
12
13pub use connection::TenantConnection;
14
15pub struct User {
16    pub id: Uuid,
17}
18
19impl User {
20    cfg_if! {
21        if #[cfg(test)] {
22        pub async fn get_connection(&self) -> Result<TenantConnection, DBError> {
23            crate::db::get_connection().await.map(TenantConnection::global)
24        }
25        } else if #[cfg(feature = "test-utils")] {
26        pub async fn get_connection(&self) -> Result<TenantConnection, DBError> {
27            if crate::db::test_pool_is_set() {
28                crate::db::get_connection().await.map(TenantConnection::global)
29            } else {
30                userpool::get_connection(self.id).await
31            }
32        }
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    pub async fn config(&self, field: &str) -> Result<Option<ConfigOption>, ConfigError> {
47        let mut conn = self.get_connection().await.map_err(|_| ConfigError::DB)?;
48        config_on(&mut conn, field).await
49    }
50
51    /// Writes a config field to THIS user's database.
52    ///
53    /// # Errors
54    /// [`ConfigError::DB`] on a connection or query error.
55    pub async fn set_config(&self, field: &str, contents: ConfigOption) -> Result<(), ConfigError> {
56        let mut conn = self.get_connection().await.map_err(|_| ConfigError::DB)?;
57        set_config_on(&mut conn, field, contents).await
58    }
59}
60
61#[cfg(test)]
62impl User {
63    /// `verified = TRUE`: the fixture is a usable account.
64    pub async fn commit(&self) -> Result<(), sqlx::Error> {
65        let mut conn = self.get_connection().await.unwrap();
66
67        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        .execute(&mut *conn)
77        .await?;
78
79        Ok(())
80    }
81}