autter_core/database/
user_warnings.rs

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