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