tetratto_core/database/
user_warnings.rs

1use oiseau::cache::Cache;
2use crate::model::auth::{Notification, UserWarning};
3use crate::model::moderation::AuditLogEntry;
4use crate::model::{Error, Result, auth::User, permissions::FinePermission};
5use crate::{auto_method, DataManager};
6
7use oiseau::{PostgresRow, execute, get, query_row, query_rows, params};
8
9impl DataManager {
10    /// Get a [`UserWarning`] from an SQL row.
11    pub(crate) fn get_user_warning_from_row(x: &PostgresRow) -> UserWarning {
12        UserWarning {
13            id: get!(x->0(i64)) as usize,
14            created: get!(x->1(i64)) as usize,
15            receiver: get!(x->2(i64)) as usize,
16            moderator: get!(x->3(i64)) as usize,
17            content: get!(x->4(String)),
18        }
19    }
20
21    auto_method!(get_user_warning_by_id(usize)@get_user_warning_from_row -> "SELECT * FROM user_warnings WHERE id = $1" --name="user warning" --returns=UserWarning --cache-key-tmpl="atto.user_warning:{}");
22
23    /// Get all user warnings by user (paginated).
24    ///
25    /// # Arguments
26    /// * `user` - the ID of the user to fetch warnings for
27    /// * `batch` - the limit of items in each page
28    /// * `page` - the page number
29    pub async fn get_user_warnings_by_user(
30        &self,
31        user: usize,
32        batch: usize,
33        page: usize,
34    ) -> Result<Vec<UserWarning>> {
35        let conn = match self.0.connect().await {
36            Ok(c) => c,
37            Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
38        };
39
40        let res = query_rows!(
41            &conn,
42            "SELECT * FROM user_warnings WHERE receiver = $1 ORDER BY created DESC LIMIT $2 OFFSET $3",
43            &[&(user as i64), &(batch as i64), &((page * batch) as i64)],
44            |x| { Self::get_user_warning_from_row(x) }
45        );
46
47        if res.is_err() {
48            return Err(Error::GeneralNotFound("user warning".to_string()));
49        }
50
51        Ok(res.unwrap())
52    }
53
54    /// Create a new user warning in the database.
55    ///
56    /// # Arguments
57    /// * `data` - a mock [`UserWarning`] object to insert
58    pub async fn create_user_warning(&self, data: UserWarning) -> Result<()> {
59        let user = self.get_user_by_id(data.moderator).await?;
60
61        // ONLY moderators can create warnings
62        if !user.permissions.check(FinePermission::MANAGE_WARNINGS) {
63            return Err(Error::NotAllowed);
64        }
65
66        let conn = match self.0.connect().await {
67            Ok(c) => c,
68            Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
69        };
70
71        let res = execute!(
72            &conn,
73            "INSERT INTO user_warnings VALUES ($1, $2, $3, $4, $5)",
74            params![
75                &(data.id as i64),
76                &(data.created as i64),
77                &(data.receiver as i64),
78                &(data.moderator as i64),
79                &data.content
80            ]
81        );
82
83        if let Err(e) = res {
84            return Err(Error::DatabaseError(e.to_string()));
85        }
86
87        // create audit log entry
88        self.create_audit_log_entry(AuditLogEntry::new(
89            user.id,
90            format!(
91                "invoked `create_user_warning` with x value `{}`",
92                data.receiver
93            ),
94        ))
95        .await?;
96
97        // send notification
98        self.create_notification(Notification::new(
99            "You have received a new account warning.".to_string(),
100            data.content,
101            data.receiver,
102        ))
103        .await?;
104
105        // return
106        Ok(())
107    }
108
109    pub async fn delete_user_warning(&self, id: usize, user: User) -> Result<()> {
110        // ONLY moderators can manage warnings
111        if !user.permissions.check(FinePermission::MANAGE_WARNINGS) {
112            return Err(Error::NotAllowed);
113        }
114
115        let conn = match self.0.connect().await {
116            Ok(c) => c,
117            Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
118        };
119
120        let res = execute!(
121            &conn,
122            "DELETE FROM user_warnings WHERE id = $1",
123            &[&(id as i64)]
124        );
125
126        if let Err(e) = res {
127            return Err(Error::DatabaseError(e.to_string()));
128        }
129
130        self.0.1.remove(format!("atto.user_warning:{}", id)).await;
131
132        // create audit log entry
133        self.create_audit_log_entry(AuditLogEntry::new(
134            user.id,
135            format!("invoked `delete_user_warning` with x value `{id}`"),
136        ))
137        .await?;
138
139        // return
140        Ok(())
141    }
142}