]> Untitled Git - lemmy.git/blob - crates/db_views/src/private_message_report_view.rs
Dont upsert Instance row every apub fetch (#2771)
[lemmy.git] / crates / db_views / src / private_message_report_view.rs
1 use crate::structs::PrivateMessageReportView;
2 use diesel::{result::Error, ExpressionMethods, JoinOnDsl, NullableExpressionMethods, QueryDsl};
3 use diesel_async::RunQueryDsl;
4 use lemmy_db_schema::{
5   newtypes::PrivateMessageReportId,
6   schema::{person, private_message, private_message_report},
7   source::{
8     person::{Person, PersonSafe},
9     private_message::PrivateMessage,
10     private_message_report::PrivateMessageReport,
11   },
12   traits::{ToSafe, ViewToVec},
13   utils::{get_conn, limit_and_offset, DbPool},
14 };
15 use typed_builder::TypedBuilder;
16
17 type PrivateMessageReportViewTuple = (
18   PrivateMessageReport,
19   PrivateMessage,
20   PersonSafe,
21   PersonSafe,
22   Option<PersonSafe>,
23 );
24
25 impl PrivateMessageReportView {
26   /// returns the PrivateMessageReportView for the provided report_id
27   ///
28   /// * `report_id` - the report id to obtain
29   pub async fn read(pool: &DbPool, report_id: PrivateMessageReportId) -> Result<Self, Error> {
30     let conn = &mut get_conn(pool).await?;
31     let (person_alias_1, person_alias_2) = diesel::alias!(person as person1, person as person2);
32
33     let (private_message_report, private_message, private_message_creator, creator, resolver) =
34       private_message_report::table
35         .find(report_id)
36         .inner_join(private_message::table)
37         .inner_join(person::table.on(private_message::creator_id.eq(person::id)))
38         .inner_join(
39           person_alias_1
40             .on(private_message_report::creator_id.eq(person_alias_1.field(person::id))),
41         )
42         .left_join(
43           person_alias_2.on(
44             private_message_report::resolver_id.eq(person_alias_2.field(person::id).nullable()),
45           ),
46         )
47         .select((
48           private_message_report::all_columns,
49           private_message::all_columns,
50           Person::safe_columns_tuple(),
51           person_alias_1.fields(Person::safe_columns_tuple()),
52           person_alias_2
53             .fields(Person::safe_columns_tuple())
54             .nullable(),
55         ))
56         .first::<PrivateMessageReportViewTuple>(conn)
57         .await?;
58
59     Ok(Self {
60       private_message_report,
61       private_message,
62       private_message_creator,
63       creator,
64       resolver,
65     })
66   }
67
68   /// Returns the current unresolved post report count for the communities you mod
69   pub async fn get_report_count(pool: &DbPool) -> Result<i64, Error> {
70     use diesel::dsl::count;
71     let conn = &mut get_conn(pool).await?;
72
73     private_message_report::table
74       .inner_join(private_message::table)
75       .filter(private_message_report::resolved.eq(false))
76       .into_boxed()
77       .select(count(private_message_report::id))
78       .first::<i64>(conn)
79       .await
80   }
81 }
82
83 #[derive(TypedBuilder)]
84 #[builder(field_defaults(default))]
85 pub struct PrivateMessageReportQuery<'a> {
86   #[builder(!default)]
87   pool: &'a DbPool,
88   page: Option<i64>,
89   limit: Option<i64>,
90   unresolved_only: Option<bool>,
91 }
92
93 impl<'a> PrivateMessageReportQuery<'a> {
94   pub async fn list(self) -> Result<Vec<PrivateMessageReportView>, Error> {
95     let conn = &mut get_conn(self.pool).await?;
96     let (person_alias_1, person_alias_2) = diesel::alias!(person as person1, person as person2);
97
98     let mut query = private_message_report::table
99       .inner_join(private_message::table)
100       .inner_join(person::table.on(private_message::creator_id.eq(person::id)))
101       .inner_join(
102         person_alias_1.on(private_message_report::creator_id.eq(person_alias_1.field(person::id))),
103       )
104       .left_join(
105         person_alias_2
106           .on(private_message_report::resolver_id.eq(person_alias_2.field(person::id).nullable())),
107       )
108       .select((
109         private_message_report::all_columns,
110         private_message::all_columns,
111         Person::safe_columns_tuple(),
112         person_alias_1.fields(Person::safe_columns_tuple()),
113         person_alias_2
114           .fields(Person::safe_columns_tuple())
115           .nullable(),
116       ))
117       .into_boxed();
118
119     if self.unresolved_only.unwrap_or(true) {
120       query = query.filter(private_message_report::resolved.eq(false));
121     }
122
123     let (limit, offset) = limit_and_offset(self.page, self.limit)?;
124
125     query = query
126       .order_by(private_message::published.desc())
127       .limit(limit)
128       .offset(offset);
129
130     let res = query.load::<PrivateMessageReportViewTuple>(conn).await?;
131
132     Ok(PrivateMessageReportView::from_tuple_to_vec(res))
133   }
134 }
135
136 impl ViewToVec for PrivateMessageReportView {
137   type DbTuple = PrivateMessageReportViewTuple;
138   fn from_tuple_to_vec(items: Vec<Self::DbTuple>) -> Vec<Self> {
139     items
140       .into_iter()
141       .map(|a| Self {
142         private_message_report: a.0,
143         private_message: a.1,
144         private_message_creator: a.2,
145         creator: a.3,
146         resolver: a.4,
147       })
148       .collect::<Vec<Self>>()
149   }
150 }
151
152 #[cfg(test)]
153 mod tests {
154   use crate::private_message_report_view::PrivateMessageReportQuery;
155   use lemmy_db_schema::{
156     source::{
157       instance::Instance,
158       person::{Person, PersonInsertForm},
159       private_message::{PrivateMessage, PrivateMessageInsertForm},
160       private_message_report::{PrivateMessageReport, PrivateMessageReportForm},
161     },
162     traits::{Crud, Reportable},
163     utils::build_db_pool_for_tests,
164   };
165   use serial_test::serial;
166
167   #[tokio::test]
168   #[serial]
169   async fn test_crud() {
170     let pool = &build_db_pool_for_tests().await;
171
172     let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string())
173       .await
174       .unwrap();
175
176     let new_person_1 = PersonInsertForm::builder()
177       .name("timmy_mrv".into())
178       .public_key("pubkey".to_string())
179       .instance_id(inserted_instance.id)
180       .build();
181     let inserted_timmy = Person::create(pool, &new_person_1).await.unwrap();
182
183     let new_person_2 = PersonInsertForm::builder()
184       .name("jessica_mrv".into())
185       .public_key("pubkey".to_string())
186       .instance_id(inserted_instance.id)
187       .build();
188     let inserted_jessica = Person::create(pool, &new_person_2).await.unwrap();
189
190     // timmy sends private message to jessica
191     let pm_form = PrivateMessageInsertForm::builder()
192       .creator_id(inserted_timmy.id)
193       .recipient_id(inserted_jessica.id)
194       .content("something offensive".to_string())
195       .build();
196     let pm = PrivateMessage::create(pool, &pm_form).await.unwrap();
197
198     // jessica reports private message
199     let pm_report_form = PrivateMessageReportForm {
200       creator_id: inserted_jessica.id,
201       original_pm_text: pm.content.clone(),
202       private_message_id: pm.id,
203       reason: "its offensive".to_string(),
204     };
205     let pm_report = PrivateMessageReport::report(pool, &pm_report_form)
206       .await
207       .unwrap();
208
209     let reports = PrivateMessageReportQuery::builder()
210       .pool(pool)
211       .build()
212       .list()
213       .await
214       .unwrap();
215     assert_eq!(1, reports.len());
216     assert!(!reports[0].private_message_report.resolved);
217     assert_eq!(inserted_timmy.name, reports[0].private_message_creator.name);
218     assert_eq!(inserted_jessica.name, reports[0].creator.name);
219     assert_eq!(pm_report.reason, reports[0].private_message_report.reason);
220     assert_eq!(pm.content, reports[0].private_message.content);
221
222     let new_person_3 = PersonInsertForm::builder()
223       .name("admin_mrv".into())
224       .public_key("pubkey".to_string())
225       .instance_id(inserted_instance.id)
226       .build();
227     let inserted_admin = Person::create(pool, &new_person_3).await.unwrap();
228
229     // admin resolves the report (after taking appropriate action)
230     PrivateMessageReport::resolve(pool, pm_report.id, inserted_admin.id)
231       .await
232       .unwrap();
233
234     let reports = PrivateMessageReportQuery::builder()
235       .pool(pool)
236       .unresolved_only(Some(false))
237       .build()
238       .list()
239       .await
240       .unwrap();
241     assert_eq!(1, reports.len());
242     assert!(reports[0].private_message_report.resolved);
243     assert!(reports[0].resolver.is_some());
244     assert_eq!(
245       inserted_admin.name,
246       reports[0].resolver.as_ref().unwrap().name
247     );
248
249     Instance::delete(pool, inserted_instance.id).await.unwrap();
250   }
251 }