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