]> Untitled Git - lemmy.git/blob - crates/db_views_actor/src/person_mention_view.rs
59e9011388ebc321d5569094181fd6539da270b4
[lemmy.git] / crates / db_views_actor / src / person_mention_view.rs
1 use crate::structs::PersonMentionView;
2 use diesel::{dsl::*, result::Error, *};
3 use lemmy_db_schema::{
4   aggregates::structs::CommentAggregates,
5   newtypes::{PersonId, PersonMentionId},
6   schema::{
7     comment,
8     comment_aggregates,
9     comment_like,
10     comment_saved,
11     community,
12     community_follower,
13     community_person_ban,
14     person,
15     person_alias_1,
16     person_block,
17     person_mention,
18     post,
19   },
20   source::{
21     comment::{Comment, CommentSaved},
22     community::{Community, CommunityFollower, CommunityPersonBan, CommunitySafe},
23     person::{Person, PersonAlias1, PersonSafe, PersonSafeAlias1},
24     person_block::PersonBlock,
25     person_mention::PersonMention,
26     post::Post,
27   },
28   traits::{MaybeOptional, ToSafe, ViewToVec},
29   utils::{functions::hot_rank, limit_and_offset, SortType},
30 };
31
32 type PersonMentionViewTuple = (
33   PersonMention,
34   Comment,
35   PersonSafe,
36   Post,
37   CommunitySafe,
38   PersonSafeAlias1,
39   CommentAggregates,
40   Option<CommunityPersonBan>,
41   Option<CommunityFollower>,
42   Option<CommentSaved>,
43   Option<PersonBlock>,
44   Option<i16>,
45 );
46
47 impl PersonMentionView {
48   pub fn read(
49     conn: &PgConnection,
50     person_mention_id: PersonMentionId,
51     my_person_id: Option<PersonId>,
52   ) -> Result<Self, Error> {
53     // The left join below will return None in this case
54     let person_id_join = my_person_id.unwrap_or(PersonId(-1));
55
56     let (
57       person_mention,
58       comment,
59       creator,
60       post,
61       community,
62       recipient,
63       counts,
64       creator_banned_from_community,
65       subscribed,
66       saved,
67       creator_blocked,
68       my_vote,
69     ) = person_mention::table
70       .find(person_mention_id)
71       .inner_join(comment::table)
72       .inner_join(person::table.on(comment::creator_id.eq(person::id)))
73       .inner_join(post::table.on(comment::post_id.eq(post::id)))
74       .inner_join(community::table.on(post::community_id.eq(community::id)))
75       .inner_join(person_alias_1::table)
76       .inner_join(comment_aggregates::table.on(comment::id.eq(comment_aggregates::comment_id)))
77       .left_join(
78         community_person_ban::table.on(
79           community::id
80             .eq(community_person_ban::community_id)
81             .and(community_person_ban::person_id.eq(comment::creator_id))
82             .and(
83               community_person_ban::expires
84                 .is_null()
85                 .or(community_person_ban::expires.gt(now)),
86             ),
87         ),
88       )
89       .left_join(
90         community_follower::table.on(
91           post::community_id
92             .eq(community_follower::community_id)
93             .and(community_follower::person_id.eq(person_id_join)),
94         ),
95       )
96       .left_join(
97         comment_saved::table.on(
98           comment::id
99             .eq(comment_saved::comment_id)
100             .and(comment_saved::person_id.eq(person_id_join)),
101         ),
102       )
103       .left_join(
104         person_block::table.on(
105           comment::creator_id
106             .eq(person_block::target_id)
107             .and(person_block::person_id.eq(person_id_join)),
108         ),
109       )
110       .left_join(
111         comment_like::table.on(
112           comment::id
113             .eq(comment_like::comment_id)
114             .and(comment_like::person_id.eq(person_id_join)),
115         ),
116       )
117       .select((
118         person_mention::all_columns,
119         comment::all_columns,
120         Person::safe_columns_tuple(),
121         post::all_columns,
122         Community::safe_columns_tuple(),
123         PersonAlias1::safe_columns_tuple(),
124         comment_aggregates::all_columns,
125         community_person_ban::all_columns.nullable(),
126         community_follower::all_columns.nullable(),
127         comment_saved::all_columns.nullable(),
128         person_block::all_columns.nullable(),
129         comment_like::score.nullable(),
130       ))
131       .first::<PersonMentionViewTuple>(conn)?;
132
133     Ok(PersonMentionView {
134       person_mention,
135       comment,
136       creator,
137       post,
138       community,
139       recipient,
140       counts,
141       creator_banned_from_community: creator_banned_from_community.is_some(),
142       subscribed: subscribed.is_some(),
143       saved: saved.is_some(),
144       creator_blocked: creator_blocked.is_some(),
145       my_vote,
146     })
147   }
148
149   /// Gets the number of unread mentions
150   pub fn get_unread_mentions(conn: &PgConnection, my_person_id: PersonId) -> Result<i64, Error> {
151     use diesel::dsl::*;
152
153     person_mention::table
154       .filter(person_mention::recipient_id.eq(my_person_id))
155       .filter(person_mention::read.eq(false))
156       .select(count(person_mention::id))
157       .first::<i64>(conn)
158   }
159 }
160
161 pub struct PersonMentionQueryBuilder<'a> {
162   conn: &'a PgConnection,
163   my_person_id: Option<PersonId>,
164   recipient_id: Option<PersonId>,
165   sort: Option<SortType>,
166   unread_only: Option<bool>,
167   page: Option<i64>,
168   limit: Option<i64>,
169 }
170
171 impl<'a> PersonMentionQueryBuilder<'a> {
172   pub fn create(conn: &'a PgConnection) -> Self {
173     PersonMentionQueryBuilder {
174       conn,
175       my_person_id: None,
176       recipient_id: None,
177       sort: None,
178       unread_only: None,
179       page: None,
180       limit: None,
181     }
182   }
183
184   pub fn sort<T: MaybeOptional<SortType>>(mut self, sort: T) -> Self {
185     self.sort = sort.get_optional();
186     self
187   }
188
189   pub fn unread_only<T: MaybeOptional<bool>>(mut self, unread_only: T) -> Self {
190     self.unread_only = unread_only.get_optional();
191     self
192   }
193
194   pub fn recipient_id<T: MaybeOptional<PersonId>>(mut self, recipient_id: T) -> Self {
195     self.recipient_id = recipient_id.get_optional();
196     self
197   }
198
199   pub fn my_person_id<T: MaybeOptional<PersonId>>(mut self, my_person_id: T) -> Self {
200     self.my_person_id = my_person_id.get_optional();
201     self
202   }
203
204   pub fn page<T: MaybeOptional<i64>>(mut self, page: T) -> Self {
205     self.page = page.get_optional();
206     self
207   }
208
209   pub fn limit<T: MaybeOptional<i64>>(mut self, limit: T) -> Self {
210     self.limit = limit.get_optional();
211     self
212   }
213
214   pub fn list(self) -> Result<Vec<PersonMentionView>, Error> {
215     use diesel::dsl::*;
216
217     // The left join below will return None in this case
218     let person_id_join = self.my_person_id.unwrap_or(PersonId(-1));
219
220     let mut query = person_mention::table
221       .inner_join(comment::table)
222       .inner_join(person::table.on(comment::creator_id.eq(person::id)))
223       .inner_join(post::table.on(comment::post_id.eq(post::id)))
224       .inner_join(community::table.on(post::community_id.eq(community::id)))
225       .inner_join(person_alias_1::table)
226       .inner_join(comment_aggregates::table.on(comment::id.eq(comment_aggregates::comment_id)))
227       .left_join(
228         community_person_ban::table.on(
229           community::id
230             .eq(community_person_ban::community_id)
231             .and(community_person_ban::person_id.eq(comment::creator_id))
232             .and(
233               community_person_ban::expires
234                 .is_null()
235                 .or(community_person_ban::expires.gt(now)),
236             ),
237         ),
238       )
239       .left_join(
240         community_follower::table.on(
241           post::community_id
242             .eq(community_follower::community_id)
243             .and(community_follower::person_id.eq(person_id_join)),
244         ),
245       )
246       .left_join(
247         comment_saved::table.on(
248           comment::id
249             .eq(comment_saved::comment_id)
250             .and(comment_saved::person_id.eq(person_id_join)),
251         ),
252       )
253       .left_join(
254         person_block::table.on(
255           comment::creator_id
256             .eq(person_block::target_id)
257             .and(person_block::person_id.eq(person_id_join)),
258         ),
259       )
260       .left_join(
261         comment_like::table.on(
262           comment::id
263             .eq(comment_like::comment_id)
264             .and(comment_like::person_id.eq(person_id_join)),
265         ),
266       )
267       .select((
268         person_mention::all_columns,
269         comment::all_columns,
270         Person::safe_columns_tuple(),
271         post::all_columns,
272         Community::safe_columns_tuple(),
273         PersonAlias1::safe_columns_tuple(),
274         comment_aggregates::all_columns,
275         community_person_ban::all_columns.nullable(),
276         community_follower::all_columns.nullable(),
277         comment_saved::all_columns.nullable(),
278         person_block::all_columns.nullable(),
279         comment_like::score.nullable(),
280       ))
281       .into_boxed();
282
283     if let Some(recipient_id) = self.recipient_id {
284       query = query.filter(person_mention::recipient_id.eq(recipient_id));
285     }
286
287     if self.unread_only.unwrap_or(false) {
288       query = query.filter(person_mention::read.eq(false));
289     }
290
291     query = match self.sort.unwrap_or(SortType::Hot) {
292       SortType::Hot | SortType::Active => query
293         .order_by(hot_rank(comment_aggregates::score, comment_aggregates::published).desc())
294         .then_order_by(comment_aggregates::published.desc()),
295       SortType::New | SortType::MostComments | SortType::NewComments => {
296         query.order_by(comment::published.desc())
297       }
298       SortType::TopAll => query.order_by(comment_aggregates::score.desc()),
299       SortType::TopYear => query
300         .filter(comment::published.gt(now - 1.years()))
301         .order_by(comment_aggregates::score.desc()),
302       SortType::TopMonth => query
303         .filter(comment::published.gt(now - 1.months()))
304         .order_by(comment_aggregates::score.desc()),
305       SortType::TopWeek => query
306         .filter(comment::published.gt(now - 1.weeks()))
307         .order_by(comment_aggregates::score.desc()),
308       SortType::TopDay => query
309         .filter(comment::published.gt(now - 1.days()))
310         .order_by(comment_aggregates::score.desc()),
311     };
312
313     let (limit, offset) = limit_and_offset(self.page, self.limit);
314
315     let res = query
316       .limit(limit)
317       .offset(offset)
318       .load::<PersonMentionViewTuple>(self.conn)?;
319
320     Ok(PersonMentionView::from_tuple_to_vec(res))
321   }
322 }
323
324 impl ViewToVec for PersonMentionView {
325   type DbTuple = PersonMentionViewTuple;
326   fn from_tuple_to_vec(items: Vec<Self::DbTuple>) -> Vec<Self> {
327     items
328       .iter()
329       .map(|a| Self {
330         person_mention: a.0.to_owned(),
331         comment: a.1.to_owned(),
332         creator: a.2.to_owned(),
333         post: a.3.to_owned(),
334         community: a.4.to_owned(),
335         recipient: a.5.to_owned(),
336         counts: a.6.to_owned(),
337         creator_banned_from_community: a.7.is_some(),
338         subscribed: a.8.is_some(),
339         saved: a.9.is_some(),
340         creator_blocked: a.10.is_some(),
341         my_vote: a.11,
342       })
343       .collect::<Vec<Self>>()
344   }
345 }