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