scouter_sql/sql/traits/
user.rs

1use crate::sql::query::Queries;
2use crate::sql::schema::User;
3
4use crate::sql::error::SqlError;
5use async_trait::async_trait;
6
7use sqlx::{Pool, Postgres};
8use std::result::Result::Ok;
9
10#[async_trait]
11pub trait UserSqlLogic {
12    /// Inserts a new user into the database.
13    ///
14    /// # Arguments
15    /// * `pool` - The database connection pool
16    /// * `user` - The user to insert
17    ///
18    /// # Returns
19    /// * A result indicating success or failure
20    async fn insert_user(pool: &Pool<Postgres>, user: &User) -> Result<(), SqlError> {
21        let query = Queries::InsertUser.get_query();
22
23        let hashed_recovery_codes = serde_json::to_value(&user.hashed_recovery_codes)?;
24        let group_permissions = serde_json::to_value(&user.group_permissions)?;
25        let permissions = serde_json::to_value(&user.permissions)?;
26        let favorite_spaces = serde_json::to_value(&user.favorite_spaces)?;
27
28        sqlx::query(&query.sql)
29            .bind(&user.username)
30            .bind(&user.password_hash)
31            .bind(&hashed_recovery_codes)
32            .bind(&permissions)
33            .bind(&group_permissions)
34            .bind(&favorite_spaces)
35            .bind(&user.role)
36            .bind(user.active)
37            .bind(&user.email)
38            .execute(pool)
39            .await?;
40
41        Ok(())
42    }
43
44    /// Retrieves a user from the database by username.
45    ///
46    /// # Arguments
47    /// * `pool` - The database connection pool
48    /// * `username` - The username of the user to retrieve
49    ///
50    /// # Returns
51    /// * A result containing the user if found, or None if not found
52    async fn get_user(pool: &Pool<Postgres>, username: &str) -> Result<Option<User>, SqlError> {
53        let query = Queries::GetUser.get_query();
54
55        let user: Option<User> = sqlx::query_as(&query.sql)
56            .bind(username)
57            .fetch_optional(pool)
58            .await
59            .map_err(SqlError::SqlxError)?;
60
61        Ok(user)
62    }
63
64    /// Updates a user in the database.
65    ///
66    /// # Arguments
67    ///
68    /// * `pool` - The database connection pool
69    /// * `user` - The user to update
70    ///
71    /// # Returns
72    /// * A result indicating success or failure
73    async fn update_user(pool: &Pool<Postgres>, user: &User) -> Result<(), SqlError> {
74        let query = Queries::UpdateUser.get_query();
75
76        let hashed_recovery_codes = serde_json::to_value(&user.hashed_recovery_codes)?;
77        let group_permissions = serde_json::to_value(&user.group_permissions)?;
78        let permissions = serde_json::to_value(&user.permissions)?;
79        let favorite_spaces = serde_json::to_value(&user.favorite_spaces)?;
80
81        sqlx::query(&query.sql)
82            .bind(user.active)
83            .bind(&user.password_hash)
84            .bind(&hashed_recovery_codes)
85            .bind(&permissions)
86            .bind(&group_permissions)
87            .bind(&favorite_spaces)
88            .bind(&user.refresh_token)
89            .bind(&user.email)
90            .bind(&user.username)
91            .execute(pool)
92            .await?;
93
94        Ok(())
95    }
96
97    /// Retrieves all users from the database.
98    ///
99    /// # Arguments
100    /// * `pool` - The database connection pool
101    ///
102    /// # Returns
103    /// * A result containing a vector of users
104    async fn get_users(pool: &Pool<Postgres>) -> Result<Vec<User>, SqlError> {
105        let query = Queries::GetUsers.get_query();
106
107        let users = sqlx::query_as::<_, User>(&query.sql)
108            .fetch_all(pool)
109            .await
110            .map_err(SqlError::SqlxError)?;
111
112        Ok(users)
113    }
114
115    /// Checks if user is the last admin in the system.
116    ///
117    /// # Arguments
118    /// * `pool` - The database connection pool
119    /// * `username` - The username of the user to check
120    ///
121    /// # Returns
122    /// * Boolean indicating if the user is the last admin
123    async fn is_last_admin(pool: &Pool<Postgres>, username: &str) -> Result<bool, SqlError> {
124        // Count admins in the system
125        let query = Queries::LastAdmin.get_query();
126
127        let admins: Vec<String> = sqlx::query_scalar(&query.sql)
128            .fetch_all(pool)
129            .await
130            .map_err(SqlError::SqlxError)?;
131
132        // check if length is 1 and the username is the same
133        if admins.len() > 1 {
134            return Ok(false);
135        }
136
137        // no admins found
138        if admins.is_empty() {
139            return Ok(false);
140        }
141
142        // check if the username is the last admin
143        Ok(admins.len() == 1 && admins[0] == username)
144    }
145
146    /// Deletes a user from the database.
147    ///
148    /// # Arguments
149    /// * `pool` - The database connection pool
150    /// * `username` - The username of the user to delete
151    async fn delete_user(pool: &Pool<Postgres>, username: &str) -> Result<(), SqlError> {
152        let query = Queries::DeleteUser.get_query();
153
154        sqlx::query(&query.sql)
155            .bind(username)
156            .execute(pool)
157            .await
158            .map_err(SqlError::SqlxError)?;
159
160        Ok(())
161    }
162}