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 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 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 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 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 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 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 let mut out: Vec<Id> = Vec::new();
136
137 for b in res.unwrap() {
138 out.push(b.receiver);
139 }
140
141 out
143 }
144
145 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 res.unwrap()
174 }
175
176 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 let mut out: Vec<Id> = Vec::new();
196
197 for b in res.unwrap() {
198 out.push(b.initiator);
199 }
200
201 out
203 }
204
205 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 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 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 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 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 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 Ok(())
304 }
305}