Skip to main content

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_rows};
6use tetratto_core2::{auto_method, model::id::Id};
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: Id::deserialize(&get!(x->0(String))),
13            created: get!(x->1(i64)) as u128,
14            receiver: Id::Legacy(get!(x->2(i64)) as usize),
15            moderator: Id::Legacy(get!(x->3(i64)) as usize),
16            content: get!(x->4(String)),
17        }
18    }
19
20    auto_method!(get_user_warning_by_id()@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: &Id,
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            &[
43                &(user.as_usize() as i64),
44                &(batch as i64),
45                &((page * batch) as i64)
46            ],
47            |x| { Self::get_user_warning_from_row(x) }
48        );
49
50        if res.is_err() {
51            return Err(Error::GeneralNotFound("user warning".to_string()));
52        }
53
54        Ok(res.unwrap())
55    }
56
57    /// Create a new user warning in the database.
58    ///
59    /// # Arguments
60    /// * `data` - a mock [`UserWarning`] object to insert
61    pub async fn create_user_warning(&self, data: UserWarning) -> Result<()> {
62        let user = self.get_user_by_id(&data.moderator).await?;
63
64        // ONLY moderators can create warnings
65        if !user.permissions.contains(&UserPermission::ManageWarnings) {
66            return Err(Error::NotAllowed);
67        }
68
69        let conn = match self.0.connect().await {
70            Ok(c) => c,
71            Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
72        };
73
74        let res = execute!(
75            &conn,
76            "INSERT INTO a_user_warnings VALUES ($1, $2, $3, $4, $5)",
77            params![
78                &data.id.printable(),
79                &(data.created as i64),
80                &(data.receiver.as_usize() as i64),
81                &(data.moderator.as_usize() as i64),
82                &data.content
83            ]
84        );
85
86        if let Err(e) = res {
87            return Err(Error::DatabaseError(e.to_string()));
88        }
89
90        // create audit log entry
91        self.create_audit_log_entry(AuditLogEntry::new(
92            user.id,
93            format!(
94                "invoked `create_user_warning` with x value `{}`",
95                data.receiver
96            ),
97        ))
98        .await?;
99
100        // send notification
101        self.create_notification(Notification::new(
102            "You have received a new account warning.".to_string(),
103            data.content,
104            data.receiver,
105        ))
106        .await?;
107
108        // return
109        Ok(())
110    }
111
112    pub async fn delete_user_warning(&self, id: &Id, user: User) -> Result<()> {
113        // ONLY moderators can manage warnings
114        if !user.permissions.contains(&UserPermission::ManageWarnings) {
115            return Err(Error::NotAllowed);
116        }
117
118        let conn = match self.0.connect().await {
119            Ok(c) => c,
120            Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
121        };
122
123        let res = execute!(
124            &conn,
125            "DELETE FROM a_user_warnings WHERE id = $1",
126            &[&id.printable()]
127        );
128
129        if let Err(e) = res {
130            return Err(Error::DatabaseError(e.to_string()));
131        }
132
133        self.0.1.remove(format!("srmp.user_warning:{}", id)).await;
134
135        // create audit log entry
136        self.create_audit_log_entry(AuditLogEntry::new(
137            user.id,
138            format!("invoked `delete_user_warning` with x value `{id}`"),
139        ))
140        .await?;
141
142        // return
143        Ok(())
144    }
145}