]> Untitled Git - lemmy.git/blob - crates/db_views/src/comment_report_view.rs
Merge branch 'main' into split_user_table
[lemmy.git] / crates / db_views / src / comment_report_view.rs
1 use diesel::{result::Error, *};
2 use lemmy_db_queries::{limit_and_offset, MaybeOptional, ToSafe, ViewToVec};
3 use lemmy_db_schema::{
4   schema::{comment, comment_report, community, person, person_alias_1, person_alias_2, post},
5   source::{
6     comment::Comment,
7     comment_report::CommentReport,
8     community::{Community, CommunitySafe},
9     person::{Person, PersonAlias1, PersonAlias2, PersonSafe, PersonSafeAlias1, PersonSafeAlias2},
10     post::Post,
11   },
12 };
13 use serde::Serialize;
14
15 #[derive(Debug, PartialEq, Serialize, Clone)]
16 pub struct CommentReportView {
17   pub comment_report: CommentReport,
18   pub comment: Comment,
19   pub post: Post,
20   pub community: CommunitySafe,
21   pub creator: PersonSafe,
22   pub comment_creator: PersonSafeAlias1,
23   pub resolver: Option<PersonSafeAlias2>,
24 }
25
26 type CommentReportViewTuple = (
27   CommentReport,
28   Comment,
29   Post,
30   CommunitySafe,
31   PersonSafe,
32   PersonSafeAlias1,
33   Option<PersonSafeAlias2>,
34 );
35
36 impl CommentReportView {
37   /// returns the CommentReportView for the provided report_id
38   ///
39   /// * `report_id` - the report id to obtain
40   pub fn read(conn: &PgConnection, report_id: i32) -> Result<Self, Error> {
41     let (comment_report, comment, post, community, creator, comment_creator, resolver) =
42       comment_report::table
43         .find(report_id)
44         .inner_join(comment::table)
45         .inner_join(post::table.on(comment::post_id.eq(post::id)))
46         .inner_join(community::table.on(post::community_id.eq(community::id)))
47         .inner_join(person::table.on(comment_report::creator_id.eq(person::id)))
48         .inner_join(person_alias_1::table.on(post::creator_id.eq(person_alias_1::id)))
49         .left_join(
50           person_alias_2::table.on(comment_report::resolver_id.eq(person_alias_2::id.nullable())),
51         )
52         .select((
53           comment_report::all_columns,
54           comment::all_columns,
55           post::all_columns,
56           Community::safe_columns_tuple(),
57           Person::safe_columns_tuple(),
58           PersonAlias1::safe_columns_tuple(),
59           PersonAlias2::safe_columns_tuple().nullable(),
60         ))
61         .first::<CommentReportViewTuple>(conn)?;
62
63     Ok(Self {
64       comment_report,
65       comment,
66       post,
67       community,
68       creator,
69       comment_creator,
70       resolver,
71     })
72   }
73
74   /// returns the current unresolved post report count for the supplied community ids
75   ///
76   /// * `community_ids` - a Vec<i32> of community_ids to get a count for
77   /// TODO this eq_any is a bad way to do this, would be better to join to communitymoderator
78   /// for a person id
79   pub fn get_report_count(conn: &PgConnection, community_ids: &[i32]) -> Result<i64, Error> {
80     use diesel::dsl::*;
81     comment_report::table
82       .inner_join(comment::table)
83       .inner_join(post::table.on(comment::post_id.eq(post::id)))
84       .filter(
85         comment_report::resolved
86           .eq(false)
87           .and(post::community_id.eq_any(community_ids)),
88       )
89       .select(count(comment_report::id))
90       .first::<i64>(conn)
91   }
92 }
93
94 pub struct CommentReportQueryBuilder<'a> {
95   conn: &'a PgConnection,
96   community_ids: Option<Vec<i32>>, // TODO bad way to do this
97   page: Option<i64>,
98   limit: Option<i64>,
99   resolved: Option<bool>,
100 }
101
102 impl<'a> CommentReportQueryBuilder<'a> {
103   pub fn create(conn: &'a PgConnection) -> Self {
104     CommentReportQueryBuilder {
105       conn,
106       community_ids: None,
107       page: None,
108       limit: None,
109       resolved: Some(false),
110     }
111   }
112
113   pub fn community_ids<T: MaybeOptional<Vec<i32>>>(mut self, community_ids: T) -> Self {
114     self.community_ids = community_ids.get_optional();
115     self
116   }
117
118   pub fn page<T: MaybeOptional<i64>>(mut self, page: T) -> Self {
119     self.page = page.get_optional();
120     self
121   }
122
123   pub fn limit<T: MaybeOptional<i64>>(mut self, limit: T) -> Self {
124     self.limit = limit.get_optional();
125     self
126   }
127
128   pub fn resolved<T: MaybeOptional<bool>>(mut self, resolved: T) -> Self {
129     self.resolved = resolved.get_optional();
130     self
131   }
132
133   pub fn list(self) -> Result<Vec<CommentReportView>, Error> {
134     let mut query = comment_report::table
135       .inner_join(comment::table)
136       .inner_join(post::table.on(comment::post_id.eq(post::id)))
137       .inner_join(community::table.on(post::community_id.eq(community::id)))
138       .inner_join(person::table.on(comment_report::creator_id.eq(person::id)))
139       .inner_join(person_alias_1::table.on(post::creator_id.eq(person_alias_1::id)))
140       .left_join(
141         person_alias_2::table.on(comment_report::resolver_id.eq(person_alias_2::id.nullable())),
142       )
143       .select((
144         comment_report::all_columns,
145         comment::all_columns,
146         post::all_columns,
147         Community::safe_columns_tuple(),
148         Person::safe_columns_tuple(),
149         PersonAlias1::safe_columns_tuple(),
150         PersonAlias2::safe_columns_tuple().nullable(),
151       ))
152       .into_boxed();
153
154     if let Some(comm_ids) = self.community_ids {
155       query = query.filter(post::community_id.eq_any(comm_ids));
156     }
157
158     if let Some(resolved_flag) = self.resolved {
159       query = query.filter(comment_report::resolved.eq(resolved_flag));
160     }
161
162     let (limit, offset) = limit_and_offset(self.page, self.limit);
163
164     let res = query
165       .order_by(comment_report::published.asc())
166       .limit(limit)
167       .offset(offset)
168       .load::<CommentReportViewTuple>(self.conn)?;
169
170     Ok(CommentReportView::from_tuple_to_vec(res))
171   }
172 }
173
174 impl ViewToVec for CommentReportView {
175   type DbTuple = CommentReportViewTuple;
176   fn from_tuple_to_vec(items: Vec<Self::DbTuple>) -> Vec<Self> {
177     items
178       .iter()
179       .map(|a| Self {
180         comment_report: a.0.to_owned(),
181         comment: a.1.to_owned(),
182         post: a.2.to_owned(),
183         community: a.3.to_owned(),
184         creator: a.4.to_owned(),
185         comment_creator: a.5.to_owned(),
186         resolver: a.6.to_owned(),
187       })
188       .collect::<Vec<Self>>()
189   }
190 }