1use oiseau::cache::Cache;
2use crate::model::auth::{AchievementName, FollowResult};
3use crate::model::requests::{ActionRequest, ActionType};
4use crate::model::{Error, Result, auth::User, auth::UserFollow, permissions::FinePermission};
5use crate::{auto_method, DataManager};
6
7use oiseau::{PostgresRow, execute, get, query_row, query_rows, params};
8
9impl DataManager {
10 pub(crate) fn get_userfollow_from_row(x: &PostgresRow) -> UserFollow {
12 UserFollow {
13 id: get!(x->0(i64)) as usize,
14 created: get!(x->1(i64)) as usize,
15 initiator: get!(x->2(i64)) as usize,
16 receiver: get!(x->3(i64)) as usize,
17 }
18 }
19
20 auto_method!(get_userfollow_by_id()@get_userfollow_from_row -> "SELECT * FROM userfollows WHERE id = $1" --name="user follow" --returns=UserFollow --cache-key-tmpl="atto.userfollow:{}");
21
22 pub fn userfollows_user_filter(&self, x: &Vec<(UserFollow, User)>) -> Vec<(UserFollow, User)> {
24 let mut out: Vec<(UserFollow, User)> = Vec::new();
25
26 for mut y in x.clone() {
27 y.1.clean();
28 out.push(y);
29 }
30
31 out
32 }
33
34 pub async fn get_userfollow_by_initiator_receiver(
36 &self,
37 initiator: usize,
38 receiver: usize,
39 ) -> Result<UserFollow> {
40 let conn = match self.0.connect().await {
41 Ok(c) => c,
42 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
43 };
44
45 let res = query_row!(
46 &conn,
47 "SELECT * FROM userfollows WHERE initiator = $1 AND receiver = $2",
48 &[&(initiator as i64), &(receiver as i64)],
49 |x| { Ok(Self::get_userfollow_from_row(x)) }
50 );
51
52 if res.is_err() {
53 return Err(Error::GeneralNotFound("user follow".to_string()));
54 }
55
56 Ok(res.unwrap())
57 }
58
59 pub async fn get_userfollow_by_receiver_initiator(
61 &self,
62 receiver: usize,
63 initiator: usize,
64 ) -> Result<UserFollow> {
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 = query_row!(
71 &conn,
72 "SELECT * FROM userfollows WHERE receiver = $1 AND initiator = $2",
73 &[&(receiver as i64), &(initiator as i64)],
74 |x| { Ok(Self::get_userfollow_from_row(x)) }
75 );
76
77 if res.is_err() {
78 return Err(Error::GeneralNotFound("user follow".to_string()));
79 }
80
81 Ok(res.unwrap())
82 }
83
84 pub async fn get_userfollows_by_initiator(
91 &self,
92 id: usize,
93 batch: usize,
94 page: usize,
95 ) -> Result<Vec<UserFollow>> {
96 let conn = match self.0.connect().await {
97 Ok(c) => c,
98 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
99 };
100
101 let res = query_rows!(
102 &conn,
103 "SELECT * FROM userfollows WHERE initiator = $1 ORDER BY created DESC LIMIT $2 OFFSET $3",
104 &[&(id as i64), &(batch as i64), &((page * batch) as i64)],
105 |x| { Self::get_userfollow_from_row(x) }
106 );
107
108 if res.is_err() {
109 return Err(Error::GeneralNotFound("user follow".to_string()));
110 }
111
112 Ok(res.unwrap())
113 }
114
115 pub async fn get_userfollows_by_initiator_all(&self, id: usize) -> Result<Vec<UserFollow>> {
120 let conn = match self.0.connect().await {
121 Ok(c) => c,
122 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
123 };
124
125 let res = query_rows!(
126 &conn,
127 "SELECT * FROM userfollows WHERE initiator = $1",
128 &[&(id as i64)],
129 |x| { Self::get_userfollow_from_row(x) }
130 );
131
132 if res.is_err() {
133 return Err(Error::GeneralNotFound("user follow".to_string()));
134 }
135
136 Ok(res.unwrap())
137 }
138
139 pub async fn get_userfollows_by_receiver(
146 &self,
147 id: usize,
148 batch: usize,
149 page: usize,
150 ) -> Result<Vec<UserFollow>> {
151 let conn = match self.0.connect().await {
152 Ok(c) => c,
153 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
154 };
155
156 let res = query_rows!(
157 &conn,
158 "SELECT * FROM userfollows WHERE receiver = $1 ORDER BY created DESC LIMIT $2 OFFSET $3",
159 &[&(id as i64), &(batch as i64), &((page * batch) as i64)],
160 |x| { Self::get_userfollow_from_row(x) }
161 );
162
163 if res.is_err() {
164 return Err(Error::GeneralNotFound("user follow".to_string()));
165 }
166
167 Ok(res.unwrap())
168 }
169
170 pub async fn get_userfollows_by_receiver_all(&self, id: usize) -> Result<Vec<UserFollow>> {
175 let conn = match self.0.connect().await {
176 Ok(c) => c,
177 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
178 };
179
180 let res = query_rows!(
181 &conn,
182 "SELECT * FROM userfollows WHERE receiver = $1",
183 &[&(id as i64)],
184 |x| { Self::get_userfollow_from_row(x) }
185 );
186
187 if res.is_err() {
188 return Err(Error::GeneralNotFound("user follow".to_string()));
189 }
190
191 Ok(res.unwrap())
192 }
193
194 pub async fn fill_userfollows_with_receiver(
196 &self,
197 userfollows: Vec<UserFollow>,
198 as_user: &Option<User>,
199 do_check: bool,
200 ) -> Result<Vec<(UserFollow, User)>> {
201 let mut out: Vec<(UserFollow, User)> = Vec::new();
202
203 for userfollow in userfollows {
204 let receiver = userfollow.receiver;
205 let user = match self.get_user_by_id(receiver).await {
206 Ok(u) => u,
207 Err(_) => continue,
208 };
209
210 if user.settings.hide_from_social_lists && do_check {
211 if let Some(ua) = as_user {
212 if !ua.permissions.check(FinePermission::MANAGE_USERS) {
213 continue;
214 }
215 } else {
216 continue;
217 }
218 }
219
220 out.push((userfollow, user));
221 }
222
223 Ok(out)
224 }
225
226 pub async fn fill_userfollows_with_initiator(
228 &self,
229 userfollows: Vec<UserFollow>,
230 as_user: &Option<User>,
231 do_check: bool,
232 ) -> Result<Vec<(UserFollow, User)>> {
233 let mut out: Vec<(UserFollow, User)> = Vec::new();
234
235 for userfollow in userfollows {
236 let initiator = userfollow.initiator;
237 let user = match self.get_user_by_id(initiator).await {
238 Ok(u) => u,
239 Err(_) => continue,
240 };
241
242 if user.settings.hide_from_social_lists && do_check {
243 if let Some(ua) = as_user {
244 if !ua.permissions.check(FinePermission::MANAGE_USERS) {
245 continue;
246 }
247 } else {
248 continue;
249 }
250 }
251
252 out.push((userfollow, user));
253 }
254
255 Ok(out)
256 }
257
258 pub async fn create_userfollow(
264 &self,
265 data: UserFollow,
266 initiator: &User,
267 force: bool,
268 ) -> Result<FollowResult> {
269 if !force {
270 let mut other_user = self.get_user_by_id(data.receiver).await?;
271
272 if other_user.settings.private_profile {
273 self.create_request(ActionRequest::with_id(
275 data.initiator,
276 data.receiver,
277 ActionType::Follow,
278 data.receiver,
279 None,
280 ))
281 .await?;
282
283 return Ok(FollowResult::Requested);
284 }
285
286 if initiator.permissions.check(FinePermission::STAFF_BADGE) {
288 self.add_achievement(
289 &mut other_user,
290 AchievementName::FollowedByStaff.into(),
291 true,
292 )
293 .await?;
294 }
295
296 self.add_achievement(&mut other_user, AchievementName::Get1Follower.into(), true)
298 .await?;
299
300 if other_user.follower_count >= 9 {
301 self.add_achievement(
302 &mut other_user,
303 AchievementName::Get10Followers.into(),
304 true,
305 )
306 .await?;
307 }
308
309 if other_user.follower_count >= 49 {
310 self.add_achievement(
311 &mut other_user,
312 AchievementName::Get50Followers.into(),
313 true,
314 )
315 .await?;
316 }
317
318 if other_user.follower_count >= 99 {
319 self.add_achievement(
320 &mut other_user,
321 AchievementName::Get100Followers.into(),
322 true,
323 )
324 .await?;
325 }
326
327 if initiator.following_count >= 9 {
328 self.add_achievement(
329 &mut initiator.clone(),
330 AchievementName::Follow10Users.into(),
331 true,
332 )
333 .await?;
334 }
335 }
336
337 let conn = match self.0.connect().await {
339 Ok(c) => c,
340 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
341 };
342
343 let res = execute!(
344 &conn,
345 "INSERT INTO userfollows VALUES ($1, $2, $3, $4)",
346 params![
347 &(data.id as i64),
348 &(data.created as i64),
349 &(data.initiator as i64),
350 &(data.receiver as i64)
351 ]
352 );
353
354 if let Err(e) = res {
355 return Err(Error::DatabaseError(e.to_string()));
356 }
357
358 self.incr_user_following_count(data.initiator)
360 .await
361 .unwrap();
362
363 self.incr_user_follower_count(data.receiver).await.unwrap();
364
365 Ok(FollowResult::Followed)
367 }
368
369 pub async fn delete_userfollow(
370 &self,
371 id: usize,
372 user: &User,
373 is_deleting_user: bool,
374 ) -> Result<()> {
375 let follow = self.get_userfollow_by_id(id).await?;
376
377 if (user.id != follow.initiator)
378 && (user.id != follow.receiver)
379 && !user.permissions.check(FinePermission::MANAGE_FOLLOWS)
380 && !is_deleting_user
381 {
382 return Err(Error::NotAllowed);
383 }
384
385 let conn = match self.0.connect().await {
386 Ok(c) => c,
387 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
388 };
389
390 let res = execute!(
391 &conn,
392 "DELETE FROM userfollows WHERE id = $1",
393 &[&(id as i64)]
394 );
395
396 if let Err(e) = res {
397 return Err(Error::DatabaseError(e.to_string()));
398 }
399
400 self.0.1.remove(format!("atto.userfollow:{}", id)).await;
401
402 if !is_deleting_user | (follow.initiator != user.id) {
404 if self
405 .decr_user_following_count(follow.initiator)
406 .await
407 .is_err()
408 {
409 println!("ERR_TETRATTO_DECR_FOLLOWS: could not decr initiator follow count")
410 }
411 }
412
413 if !is_deleting_user | (follow.receiver != user.id) {
414 self.decr_user_follower_count(follow.receiver)
415 .await
416 .unwrap();
417 }
418
419 Ok(())
421 }
422
423 pub async fn delete_userfollow_sudo(&self, id: usize, user_id: usize) -> Result<()> {
424 let follow = self.get_userfollow_by_id(id).await?;
425
426 let conn = match self.0.connect().await {
427 Ok(c) => c,
428 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
429 };
430
431 let res = execute!(
432 &conn,
433 "DELETE FROM userfollows WHERE id = $1",
434 &[&(id as i64)]
435 );
436
437 if let Err(e) = res {
438 return Err(Error::DatabaseError(e.to_string()));
439 }
440
441 self.0.1.remove(format!("atto.userfollow:{}", id)).await;
442
443 if follow.initiator != user_id {
445 self.decr_user_following_count(follow.initiator)
446 .await
447 .unwrap();
448 }
449
450 if follow.receiver != user_id {
451 self.decr_user_follower_count(follow.receiver)
452 .await
453 .unwrap();
454 }
455
456 Ok(())
458 }
459}