Skip to main content

tetratto_core2/database/
user_blocks.rs

1use oiseau::cache::Cache;
2use crate::model::id::Id;
3use crate::model::{Error, Result, auth::User, auth::UserBlock, permissions::FinePermission};
4use crate::{auto_method, DataManager};
5
6use oiseau::{PostgresRow, execute, get, query_row, query_rows, params};
7
8impl DataManager {
9    /// Get a [`UserBlock`] from an SQL row.
10    pub(crate) fn get_user_block_from_row(x: &PostgresRow) -> UserBlock {
11        UserBlock {
12            id: crate::model::id::Id::deserialize(&get!(x->0(String))),
13            created: get!(x->1(i64)) as u128,
14            initiator: crate::model::id::Id::deserialize(&get!(x->2(String))),
15            receiver: crate::model::id::Id::deserialize(&get!(x->3(String))),
16        }
17    }
18
19    auto_method!(get_user_block_by_id()@get_user_block_from_row -> "SELECT * FROM user_blocks WHERE id = $1" --name="user block" --returns=UserBlock --cache-key-tmpl="atto.user_block:{}");
20
21    /// Fill a vector of user blocks with their receivers.
22    pub async fn fill_user_blocks_receivers(
23        &self,
24        list: Vec<UserBlock>,
25    ) -> Result<Vec<(UserBlock, User)>> {
26        let mut out = Vec::new();
27
28        for block in list {
29            out.push(match self.get_user_by_id(&block.receiver).await {
30                Ok(ua) => (block, ua),
31                Err(_) => {
32                    self.delete_user_block_forced(&block.id).await?;
33                    continue;
34                }
35            });
36        }
37
38        Ok(out)
39    }
40
41    /// Get a user block by its users.
42    pub async fn get_user_block_by_users(
43        &self,
44        initiator: &Id,
45        receiver: &Id,
46    ) -> Result<UserBlock> {
47        let conn = match self.0.connect().await {
48            Ok(c) => c,
49            Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
50        };
51
52        let res = query_row!(
53            &conn,
54            "SELECT * FROM user_blocks WHERE (initiator = $1 AND receiver = $2) OR (initiator = $2 AND receiver = $1)",
55            &[&initiator.printable(), &receiver.printable()],
56            |x| { Ok(Self::get_user_block_from_row(x)) }
57        );
58
59        if res.is_err() {
60            return Err(Error::GeneralNotFound("user block".to_string()));
61        }
62
63        Ok(res.unwrap())
64    }
65
66    /// Get a user block by `initiator` and `receiver` (in that order).
67    pub async fn get_user_block_by_initiator_receiver(
68        &self,
69        initiator: &Id,
70        receiver: &Id,
71    ) -> Result<UserBlock> {
72        let conn = match self.0.connect().await {
73            Ok(c) => c,
74            Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
75        };
76
77        let res = query_row!(
78            &conn,
79            "SELECT * FROM user_blocks WHERE initiator = $1 AND receiver = $2",
80            &[&initiator.printable(), &receiver.printable()],
81            |x| { Ok(Self::get_user_block_from_row(x)) }
82        );
83
84        if res.is_err() {
85            return Err(Error::GeneralNotFound("user block".to_string()));
86        }
87
88        Ok(res.unwrap())
89    }
90
91    /// Get a user block by `receiver` and `initiator` (in that order).
92    pub async fn get_user_block_by_receiver_initiator(
93        &self,
94        receiver: &Id,
95        initiator: &Id,
96    ) -> Result<UserBlock> {
97        let conn = match self.0.connect().await {
98            Ok(c) => c,
99            Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
100        };
101
102        let res = query_row!(
103            &conn,
104            "SELECT * FROM user_blocks WHERE receiver = $1 AND initiator = $2",
105            &[&receiver.printable(), &initiator.printable()],
106            |x| { Ok(Self::get_user_block_from_row(x)) }
107        );
108
109        if res.is_err() {
110            return Err(Error::GeneralNotFound("user block".to_string()));
111        }
112
113        Ok(res.unwrap())
114    }
115
116    /// Get the receiver of all user blocks for the given `initiator`.
117    pub async fn get_user_blocks_receivers(&self, initiator: &Id) -> Vec<Id> {
118        let conn = match self.0.connect().await {
119            Ok(c) => c,
120            Err(_) => return Vec::new(),
121        };
122
123        let res = query_rows!(
124            &conn,
125            "SELECT * FROM user_blocks WHERE initiator = $1",
126            &[&initiator.printable()],
127            |x| { Self::get_user_block_from_row(x) }
128        );
129
130        if res.is_err() {
131            return Vec::new();
132        }
133
134        // get receivers
135        let mut out: Vec<Id> = Vec::new();
136
137        for b in res.unwrap() {
138            out.push(b.receiver);
139        }
140
141        // return
142        out
143    }
144
145    /// Get all user blocks created by the given `initiator`.
146    pub async fn get_user_blocks_by_initiator(
147        &self,
148        initiator: &Id,
149        batch: usize,
150        page: usize,
151    ) -> Vec<UserBlock> {
152        let conn = match self.0.connect().await {
153            Ok(c) => c,
154            Err(_) => return Vec::new(),
155        };
156
157        let res = query_rows!(
158            &conn,
159            "SELECT * FROM user_blocks WHERE initiator = $1 ORDER BY created DESC LIMIT $2 OFFSET $3",
160            &[
161                &initiator.printable(),
162                &(batch as i64),
163                &((page * batch) as i64)
164            ],
165            |x| { Self::get_user_block_from_row(x) }
166        );
167
168        if res.is_err() {
169            return Vec::new();
170        }
171
172        // return
173        res.unwrap()
174    }
175
176    /// Get the owner of all user blocks for the given `receiver`.
177    pub async fn get_user_blocks_initiator_by_receivers(&self, receiver: &Id) -> Vec<Id> {
178        let conn = match self.0.connect().await {
179            Ok(c) => c,
180            Err(_) => return Vec::new(),
181        };
182
183        let res = query_rows!(
184            &conn,
185            "SELECT * FROM user_blocks WHERE receiver = $1",
186            &[&receiver.printable()],
187            |x| { Self::get_user_block_from_row(x) }
188        );
189
190        if res.is_err() {
191            return Vec::new();
192        }
193
194        // get owner
195        let mut out: Vec<Id> = Vec::new();
196
197        for b in res.unwrap() {
198            out.push(b.initiator);
199        }
200
201        // return
202        out
203    }
204
205    /// Create a new user block in the database.
206    ///
207    /// # Arguments
208    /// * `data` - a mock [`UserBlock`] object to insert
209    pub async fn create_user_block(&self, data: UserBlock) -> Result<()> {
210        let initiator = self.get_user_by_id(&data.initiator).await?;
211        let receiver = self.get_user_by_id(&data.receiver).await?;
212
213        // ...
214        let conn = match self.0.connect().await {
215            Ok(c) => c,
216            Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
217        };
218
219        let res = execute!(
220            &conn,
221            "INSERT INTO user_blocks VALUES ($1, $2, $3, $4)",
222            params![
223                &data.id.printable(),
224                &(data.created as i64),
225                &data.initiator.printable(),
226                &data.receiver.printable()
227            ]
228        );
229
230        if let Err(e) = res {
231            return Err(Error::DatabaseError(e.to_string()));
232        }
233
234        // unfollow/remove follower
235        if let Ok(f) = self
236            .get_user_follow_by_initiator_receiver(&data.initiator, &data.receiver)
237            .await
238        {
239            self.delete_user_follow(&f.id, &initiator, false).await?;
240        }
241
242        if let Ok(f) = self
243            .get_user_follow_by_receiver_initiator(&data.initiator, &data.receiver)
244            .await
245        {
246            self.delete_user_follow(&f.id, &receiver, false).await?;
247        }
248
249        // return
250        Ok(())
251    }
252
253    pub async fn delete_user_block(&self, id: &crate::model::id::Id, user: User) -> Result<()> {
254        let block = self.get_user_block_by_id(id).await?;
255
256        if user.id != block.initiator {
257            // only the initiator (or moderators) can delete user blocks!
258            if !user.permissions.check(FinePermission::ManageFollows) {
259                return Err(Error::NotAllowed);
260            }
261        }
262
263        let conn = match self.0.connect().await {
264            Ok(c) => c,
265            Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
266        };
267
268        let res = execute!(
269            &conn,
270            "DELETE FROM user_blocks WHERE id = $1",
271            &[&id.printable()]
272        );
273
274        if let Err(e) = res {
275            return Err(Error::DatabaseError(e.to_string()));
276        }
277
278        self.0.1.remove(format!("atto.user_block:{}", id)).await;
279
280        // return
281        Ok(())
282    }
283
284    pub async fn delete_user_block_forced(&self, id: &crate::model::id::Id) -> Result<()> {
285        let conn = match self.0.connect().await {
286            Ok(c) => c,
287            Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
288        };
289
290        let res = execute!(
291            &conn,
292            "DELETE FROM user_blocks WHERE id = $1",
293            &[&id.printable()]
294        );
295
296        if let Err(e) = res {
297            return Err(Error::DatabaseError(e.to_string()));
298        }
299
300        self.0.1.remove(format!("atto.user_block:{}", id)).await;
301
302        // return
303        Ok(())
304    }
305}