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::Postgres;
5use sqlx::pool::PoolConnection;
6use sqlx::types::Uuid;
7
8// `userpool` is the production per-user routing path. Compile it whenever we
9// are NOT inside server's own `cfg(test)` runs. That keeps the module
10// available to external test consumers (the workspace `tests-integration`
11// crate, web's integration tests under `--all-features`, etc.) so they can
12// fall back to userpool when the test-pool override is absent.
13#[cfg(not(test))]
14mod userpool;
15
16pub struct User {
17    pub id: Uuid,
18}
19
20impl User {
21    cfg_if! {
22        if #[cfg(test)] {
23        pub async fn get_connection(&self) -> Result<PoolConnection<Postgres>, DBError> {
24            crate::db::get_connection().await
25        }
26        } else if #[cfg(feature = "test-utils")] {
27        pub async fn get_connection(&self) -> Result<PoolConnection<Postgres>, DBError> {
28            if crate::db::test_pool_is_set() {
29                crate::db::get_connection().await
30            } else {
31                userpool::get_connection(self.id).await
32            }
33        }
34        } else {
35        pub async fn get_connection(&self) -> Result<PoolConnection<Postgres>, DBError> {
36            userpool::get_connection(self.id).await
37        }
38        }
39    }
40
41    /// Reads a config field from THIS user's database. Per-user config is
42    /// isolated to the user's own DB (distinct from server-wide
43    /// [`crate::config::system_config`]).
44    ///
45    /// # Errors
46    /// [`ConfigError::DB`] on a connection or query error.
47    pub async fn config(&self, field: &str) -> Result<Option<ConfigOption>, ConfigError> {
48        let mut conn = self.get_connection().await.map_err(|_| ConfigError::DB)?;
49        config_on(&mut conn, field).await
50    }
51
52    /// Writes a config field to THIS user's database.
53    ///
54    /// # Errors
55    /// [`ConfigError::DB`] on a connection or query error.
56    pub async fn set_config(&self, field: &str, contents: ConfigOption) -> Result<(), ConfigError> {
57        let mut conn = self.get_connection().await.map_err(|_| ConfigError::DB)?;
58        set_config_on(&mut conn, field, contents).await
59    }
60}
61
62#[cfg(test)]
63impl User {
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, db_name, created_at
70            ) VALUES (
71                $1, 'Test User', 'test@example.com', 'default.png',
72                FALSE, 'password123', 'user', 'database', NOW()
73            )",
74            self.id,
75        )
76        .execute(&mut *conn)
77        .await?;
78
79        Ok(())
80    }
81}