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