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