1use oiseau::cache::Cache;
2use crate::model::{Error, Result, auth::User, auth::UserBlock, permissions::FinePermission};
3use crate::{auto_method, DataManager};
4
5use oiseau::{PostgresRow, execute, get, query_row, query_rows, params};
6
7impl DataManager {
8 pub(crate) fn get_userblock_from_row(x: &PostgresRow) -> UserBlock {
10 UserBlock {
11 id: get!(x->0(i64)) as usize,
12 created: get!(x->1(i64)) as usize,
13 initiator: get!(x->2(i64)) as usize,
14 receiver: get!(x->3(i64)) as usize,
15 }
16 }
17
18 auto_method!(get_userblock_by_id()@get_userblock_from_row -> "SELECT * FROM userblocks WHERE id = $1" --name="user block" --returns=UserBlock --cache-key-tmpl="atto.userblock:{}");
19
20 pub async fn fill_userblocks_receivers(&self, list: Vec<UserBlock>) -> Result<Vec<User>> {
22 let mut out = Vec::new();
23
24 for block in list {
25 out.push(match self.get_user_by_id(block.receiver).await {
26 Ok(ua) => ua,
27 Err(_) => {
28 self.delete_userblock_sudo(block.id).await?;
29 continue;
30 }
31 });
32 }
33
34 Ok(out)
35 }
36
37 pub async fn get_userblock_by_initiator_receiver(
39 &self,
40 initiator: usize,
41 receiver: usize,
42 ) -> Result<UserBlock> {
43 let conn = match self.0.connect().await {
44 Ok(c) => c,
45 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
46 };
47
48 let res = query_row!(
49 &conn,
50 "SELECT * FROM userblocks WHERE initiator = $1 AND receiver = $2",
51 &[&(initiator as i64), &(receiver as i64)],
52 |x| { Ok(Self::get_userblock_from_row(x)) }
53 );
54
55 if res.is_err() {
56 return Err(Error::GeneralNotFound("user block".to_string()));
57 }
58
59 Ok(res.unwrap())
60 }
61
62 pub async fn get_userblock_by_receiver_initiator(
64 &self,
65 receiver: usize,
66 initiator: usize,
67 ) -> Result<UserBlock> {
68 let conn = match self.0.connect().await {
69 Ok(c) => c,
70 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
71 };
72
73 let res = query_row!(
74 &conn,
75 "SELECT * FROM userblocks WHERE receiver = $1 AND initiator = $2",
76 &[&(receiver as i64), &(initiator as i64)],
77 |x| { Ok(Self::get_userblock_from_row(x)) }
78 );
79
80 if res.is_err() {
81 return Err(Error::GeneralNotFound("user block".to_string()));
82 }
83
84 Ok(res.unwrap())
85 }
86
87 pub async fn get_userblocks_receivers(
89 &self,
90 initiator: usize,
91 associated: &Vec<usize>,
92 do_associated: bool,
93 ) -> Vec<usize> {
94 let mut associated_str = String::new();
95
96 if do_associated {
97 for id in associated {
98 associated_str.push_str(&(" OR initiator = ".to_string() + &id.to_string()));
99 }
100 }
101
102 let conn = match self.0.connect().await {
104 Ok(c) => c,
105 Err(_) => return Vec::new(),
106 };
107
108 let res = query_rows!(
109 &conn,
110 &format!("SELECT * FROM userblocks WHERE initiator = $1{associated_str}"),
111 &[&(initiator as i64)],
112 |x| { Self::get_userblock_from_row(x) }
113 );
114
115 if res.is_err() {
116 return Vec::new();
117 }
118
119 let mut out: Vec<usize> = Vec::new();
121
122 for b in res.unwrap() {
123 out.push(b.receiver);
124 }
125
126 out
128 }
129
130 pub async fn get_userblocks_by_initiator(&self, initiator: usize) -> Vec<UserBlock> {
132 let conn = match self.0.connect().await {
133 Ok(c) => c,
134 Err(_) => return Vec::new(),
135 };
136
137 let res = query_rows!(
138 &conn,
139 "SELECT * FROM userblocks WHERE initiator = $1",
140 &[&(initiator as i64)],
141 |x| { Self::get_userblock_from_row(x) }
142 );
143
144 if res.is_err() {
145 return Vec::new();
146 }
147
148 res.unwrap()
150 }
151
152 pub async fn get_userblocks_initiator_by_receivers(&self, receiver: usize) -> Vec<usize> {
154 let conn = match self.0.connect().await {
155 Ok(c) => c,
156 Err(_) => return Vec::new(),
157 };
158
159 let res = query_rows!(
160 &conn,
161 "SELECT * FROM userblocks WHERE receiver = $1",
162 &[&(receiver as i64)],
163 |x| { Self::get_userblock_from_row(x) }
164 );
165
166 if res.is_err() {
167 return Vec::new();
168 }
169
170 let mut out: Vec<usize> = Vec::new();
172
173 for b in res.unwrap() {
174 out.push(b.initiator);
175 }
176
177 out
179 }
180
181 pub async fn create_userblock(&self, data: UserBlock) -> Result<()> {
186 let initiator = self.get_user_by_id(data.initiator).await?;
187 let receiver = self.get_user_by_id(data.receiver).await?;
188
189 let conn = match self.0.connect().await {
191 Ok(c) => c,
192 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
193 };
194
195 let res = execute!(
196 &conn,
197 "INSERT INTO userblocks VALUES ($1, $2, $3, $4)",
198 params![
199 &(data.id as i64),
200 &(data.created as i64),
201 &(data.initiator as i64),
202 &(data.receiver as i64)
203 ]
204 );
205
206 if let Err(e) = res {
207 return Err(Error::DatabaseError(e.to_string()));
208 }
209
210 for community in self.get_communities_by_owner(data.receiver).await? {
212 if let Ok(membership) = self
213 .get_membership_by_owner_community_no_void(data.initiator, community.id)
214 .await
215 {
216 self.delete_membership_force(membership.id).await?;
217 }
218 }
219
220 if let Ok(f) = self
222 .get_userfollow_by_initiator_receiver(data.initiator, data.receiver)
223 .await
224 {
225 self.delete_userfollow(f.id, &initiator, false).await?;
226 }
227
228 if let Ok(f) = self
229 .get_userfollow_by_receiver_initiator(data.initiator, data.receiver)
230 .await
231 {
232 self.delete_userfollow(f.id, &receiver, false).await?;
233 }
234
235 Ok(())
237 }
238
239 pub async fn delete_userblock(&self, id: usize, user: User) -> Result<()> {
240 let block = self.get_userblock_by_id(id).await?;
241
242 if user.id != block.initiator {
243 if !user.permissions.check(FinePermission::MANAGE_FOLLOWS) {
245 return Err(Error::NotAllowed);
246 }
247 }
248
249 let conn = match self.0.connect().await {
250 Ok(c) => c,
251 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
252 };
253
254 let res = execute!(
255 &conn,
256 "DELETE FROM userblocks WHERE id = $1",
257 &[&(id as i64)]
258 );
259
260 if let Err(e) = res {
261 return Err(Error::DatabaseError(e.to_string()));
262 }
263
264 self.0.1.remove(format!("atto.userblock:{}", id)).await;
265
266 Ok(())
268 }
269
270 pub async fn delete_userblock_sudo(&self, id: usize) -> Result<()> {
271 let conn = match self.0.connect().await {
272 Ok(c) => c,
273 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
274 };
275
276 let res = execute!(
277 &conn,
278 "DELETE FROM userblocks WHERE id = $1",
279 &[&(id as i64)]
280 );
281
282 if let Err(e) = res {
283 return Err(Error::DatabaseError(e.to_string()));
284 }
285
286 self.0.1.remove(format!("atto.userblock:{}", id)).await;
287
288 Ok(())
290 }
291}