]> Untitled Git - lemmy.git/blob - crates/db_views/src/registration_application_view.rs
Dont upsert Instance row every apub fetch (#2771)
[lemmy.git] / crates / db_views / src / registration_application_view.rs
1 use crate::structs::RegistrationApplicationView;
2 use diesel::{
3   dsl::count,
4   result::Error,
5   ExpressionMethods,
6   JoinOnDsl,
7   NullableExpressionMethods,
8   QueryDsl,
9 };
10 use diesel_async::RunQueryDsl;
11 use lemmy_db_schema::{
12   schema::{local_user, person, registration_application},
13   source::{
14     local_user::{LocalUser, LocalUserSettings},
15     person::{Person, PersonSafe},
16     registration_application::RegistrationApplication,
17   },
18   traits::{ToSafe, ToSafeSettings, ViewToVec},
19   utils::{get_conn, limit_and_offset, DbPool},
20 };
21 use typed_builder::TypedBuilder;
22
23 type RegistrationApplicationViewTuple = (
24   RegistrationApplication,
25   LocalUserSettings,
26   PersonSafe,
27   Option<PersonSafe>,
28 );
29
30 impl RegistrationApplicationView {
31   pub async fn read(pool: &DbPool, registration_application_id: i32) -> Result<Self, Error> {
32     let conn = &mut get_conn(pool).await?;
33     let person_alias_1 = diesel::alias!(person as person1);
34
35     let (registration_application, creator_local_user, creator, admin) =
36       registration_application::table
37         .find(registration_application_id)
38         .inner_join(
39           local_user::table.on(registration_application::local_user_id.eq(local_user::id)),
40         )
41         .inner_join(person::table.on(local_user::person_id.eq(person::id)))
42         .left_join(
43           person_alias_1
44             .on(registration_application::admin_id.eq(person_alias_1.field(person::id).nullable())),
45         )
46         .order_by(registration_application::published.desc())
47         .select((
48           registration_application::all_columns,
49           LocalUser::safe_settings_columns_tuple(),
50           Person::safe_columns_tuple(),
51           person_alias_1
52             .fields(Person::safe_columns_tuple())
53             .nullable(),
54         ))
55         .first::<RegistrationApplicationViewTuple>(conn)
56         .await?;
57
58     Ok(RegistrationApplicationView {
59       registration_application,
60       creator_local_user,
61       creator,
62       admin,
63     })
64   }
65
66   /// Returns the current unread registration_application count
67   pub async fn get_unread_count(pool: &DbPool, verified_email_only: bool) -> Result<i64, Error> {
68     let conn = &mut get_conn(pool).await?;
69     let person_alias_1 = diesel::alias!(person as person1);
70
71     let mut query = registration_application::table
72       .inner_join(local_user::table.on(registration_application::local_user_id.eq(local_user::id)))
73       .inner_join(person::table.on(local_user::person_id.eq(person::id)))
74       .left_join(
75         person_alias_1
76           .on(registration_application::admin_id.eq(person_alias_1.field(person::id).nullable())),
77       )
78       .filter(registration_application::admin_id.is_null())
79       .into_boxed();
80
81     if verified_email_only {
82       query = query.filter(local_user::email_verified.eq(true))
83     }
84
85     query
86       .select(count(registration_application::id))
87       .first::<i64>(conn)
88       .await
89   }
90 }
91
92 #[derive(TypedBuilder)]
93 #[builder(field_defaults(default))]
94 pub struct RegistrationApplicationQuery<'a> {
95   #[builder(!default)]
96   pool: &'a DbPool,
97   unread_only: Option<bool>,
98   verified_email_only: Option<bool>,
99   page: Option<i64>,
100   limit: Option<i64>,
101 }
102
103 impl<'a> RegistrationApplicationQuery<'a> {
104   pub async fn list(self) -> Result<Vec<RegistrationApplicationView>, Error> {
105     let conn = &mut get_conn(self.pool).await?;
106     let person_alias_1 = diesel::alias!(person as person1);
107
108     let mut query = registration_application::table
109       .inner_join(local_user::table.on(registration_application::local_user_id.eq(local_user::id)))
110       .inner_join(person::table.on(local_user::person_id.eq(person::id)))
111       .left_join(
112         person_alias_1
113           .on(registration_application::admin_id.eq(person_alias_1.field(person::id).nullable())),
114       )
115       .order_by(registration_application::published.desc())
116       .select((
117         registration_application::all_columns,
118         LocalUser::safe_settings_columns_tuple(),
119         Person::safe_columns_tuple(),
120         person_alias_1
121           .fields(Person::safe_columns_tuple())
122           .nullable(),
123       ))
124       .into_boxed();
125
126     if self.unread_only.unwrap_or(false) {
127       query = query.filter(registration_application::admin_id.is_null())
128     }
129
130     if self.verified_email_only.unwrap_or(false) {
131       query = query.filter(local_user::email_verified.eq(true))
132     }
133
134     let (limit, offset) = limit_and_offset(self.page, self.limit)?;
135
136     query = query
137       .limit(limit)
138       .offset(offset)
139       .order_by(registration_application::published.desc());
140
141     let res = query.load::<RegistrationApplicationViewTuple>(conn).await?;
142
143     Ok(RegistrationApplicationView::from_tuple_to_vec(res))
144   }
145 }
146
147 impl ViewToVec for RegistrationApplicationView {
148   type DbTuple = RegistrationApplicationViewTuple;
149   fn from_tuple_to_vec(items: Vec<Self::DbTuple>) -> Vec<Self> {
150     items
151       .into_iter()
152       .map(|a| Self {
153         registration_application: a.0,
154         creator_local_user: a.1,
155         creator: a.2,
156         admin: a.3,
157       })
158       .collect::<Vec<Self>>()
159   }
160 }
161
162 #[cfg(test)]
163 mod tests {
164   use crate::registration_application_view::{
165     RegistrationApplicationQuery,
166     RegistrationApplicationView,
167   };
168   use lemmy_db_schema::{
169     source::{
170       instance::Instance,
171       local_user::{LocalUser, LocalUserInsertForm, LocalUserSettings, LocalUserUpdateForm},
172       person::{Person, PersonInsertForm, PersonSafe},
173       registration_application::{
174         RegistrationApplication,
175         RegistrationApplicationInsertForm,
176         RegistrationApplicationUpdateForm,
177       },
178     },
179     traits::Crud,
180     utils::build_db_pool_for_tests,
181   };
182   use serial_test::serial;
183
184   #[tokio::test]
185   #[serial]
186   async fn test_crud() {
187     let pool = &build_db_pool_for_tests().await;
188
189     let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string())
190       .await
191       .unwrap();
192
193     let timmy_person_form = PersonInsertForm::builder()
194       .name("timmy_rav".into())
195       .admin(Some(true))
196       .public_key("pubkey".to_string())
197       .instance_id(inserted_instance.id)
198       .build();
199
200     let inserted_timmy_person = Person::create(pool, &timmy_person_form).await.unwrap();
201
202     let timmy_local_user_form = LocalUserInsertForm::builder()
203       .person_id(inserted_timmy_person.id)
204       .password_encrypted("nada".to_string())
205       .build();
206
207     let _inserted_timmy_local_user = LocalUser::create(pool, &timmy_local_user_form)
208       .await
209       .unwrap();
210
211     let sara_person_form = PersonInsertForm::builder()
212       .name("sara_rav".into())
213       .public_key("pubkey".to_string())
214       .instance_id(inserted_instance.id)
215       .build();
216
217     let inserted_sara_person = Person::create(pool, &sara_person_form).await.unwrap();
218
219     let sara_local_user_form = LocalUserInsertForm::builder()
220       .person_id(inserted_sara_person.id)
221       .password_encrypted("nada".to_string())
222       .build();
223
224     let inserted_sara_local_user = LocalUser::create(pool, &sara_local_user_form)
225       .await
226       .unwrap();
227
228     // Sara creates an application
229     let sara_app_form = RegistrationApplicationInsertForm {
230       local_user_id: inserted_sara_local_user.id,
231       answer: "LET ME IIIIINN".to_string(),
232     };
233
234     let sara_app = RegistrationApplication::create(pool, &sara_app_form)
235       .await
236       .unwrap();
237
238     let read_sara_app_view = RegistrationApplicationView::read(pool, sara_app.id)
239       .await
240       .unwrap();
241
242     let jess_person_form = PersonInsertForm::builder()
243       .name("jess_rav".into())
244       .public_key("pubkey".to_string())
245       .instance_id(inserted_instance.id)
246       .build();
247
248     let inserted_jess_person = Person::create(pool, &jess_person_form).await.unwrap();
249
250     let jess_local_user_form = LocalUserInsertForm::builder()
251       .person_id(inserted_jess_person.id)
252       .password_encrypted("nada".to_string())
253       .build();
254
255     let inserted_jess_local_user = LocalUser::create(pool, &jess_local_user_form)
256       .await
257       .unwrap();
258
259     // Sara creates an application
260     let jess_app_form = RegistrationApplicationInsertForm {
261       local_user_id: inserted_jess_local_user.id,
262       answer: "LET ME IIIIINN".to_string(),
263     };
264
265     let jess_app = RegistrationApplication::create(pool, &jess_app_form)
266       .await
267       .unwrap();
268
269     let read_jess_app_view = RegistrationApplicationView::read(pool, jess_app.id)
270       .await
271       .unwrap();
272
273     let mut expected_sara_app_view = RegistrationApplicationView {
274       registration_application: sara_app.clone(),
275       creator_local_user: LocalUserSettings {
276         id: inserted_sara_local_user.id,
277         person_id: inserted_sara_local_user.person_id,
278         email: inserted_sara_local_user.email,
279         show_nsfw: inserted_sara_local_user.show_nsfw,
280         theme: inserted_sara_local_user.theme,
281         default_sort_type: inserted_sara_local_user.default_sort_type,
282         default_listing_type: inserted_sara_local_user.default_listing_type,
283         interface_language: inserted_sara_local_user.interface_language,
284         show_avatars: inserted_sara_local_user.show_avatars,
285         send_notifications_to_email: inserted_sara_local_user.send_notifications_to_email,
286         validator_time: inserted_sara_local_user.validator_time,
287         show_bot_accounts: inserted_sara_local_user.show_bot_accounts,
288         show_scores: inserted_sara_local_user.show_scores,
289         show_read_posts: inserted_sara_local_user.show_read_posts,
290         show_new_post_notifs: inserted_sara_local_user.show_new_post_notifs,
291         email_verified: inserted_sara_local_user.email_verified,
292         accepted_application: inserted_sara_local_user.accepted_application,
293       },
294       creator: PersonSafe {
295         id: inserted_sara_person.id,
296         name: inserted_sara_person.name.clone(),
297         display_name: None,
298         published: inserted_sara_person.published,
299         avatar: None,
300         actor_id: inserted_sara_person.actor_id.clone(),
301         local: true,
302         banned: false,
303         ban_expires: None,
304         deleted: false,
305         admin: false,
306         bot_account: false,
307         bio: None,
308         banner: None,
309         updated: None,
310         inbox_url: inserted_sara_person.inbox_url.clone(),
311         shared_inbox_url: None,
312         matrix_user_id: None,
313         instance_id: inserted_instance.id,
314       },
315       admin: None,
316     };
317
318     assert_eq!(read_sara_app_view, expected_sara_app_view);
319
320     // Do a batch read of the applications
321     let apps = RegistrationApplicationQuery::builder()
322       .pool(pool)
323       .unread_only(Some(true))
324       .build()
325       .list()
326       .await
327       .unwrap();
328
329     assert_eq!(
330       apps,
331       [read_jess_app_view.clone(), expected_sara_app_view.clone()]
332     );
333
334     // Make sure the counts are correct
335     let unread_count = RegistrationApplicationView::get_unread_count(pool, false)
336       .await
337       .unwrap();
338     assert_eq!(unread_count, 2);
339
340     // Approve the application
341     let approve_form = RegistrationApplicationUpdateForm {
342       admin_id: Some(Some(inserted_timmy_person.id)),
343       deny_reason: None,
344     };
345
346     RegistrationApplication::update(pool, sara_app.id, &approve_form)
347       .await
348       .unwrap();
349
350     // Update the local_user row
351     let approve_local_user_form = LocalUserUpdateForm::builder()
352       .accepted_application(Some(true))
353       .build();
354
355     LocalUser::update(pool, inserted_sara_local_user.id, &approve_local_user_form)
356       .await
357       .unwrap();
358
359     let read_sara_app_view_after_approve = RegistrationApplicationView::read(pool, sara_app.id)
360       .await
361       .unwrap();
362
363     // Make sure the columns changed
364     expected_sara_app_view
365       .creator_local_user
366       .accepted_application = true;
367     expected_sara_app_view.registration_application.admin_id = Some(inserted_timmy_person.id);
368
369     expected_sara_app_view.admin = Some(PersonSafe {
370       id: inserted_timmy_person.id,
371       name: inserted_timmy_person.name.clone(),
372       display_name: None,
373       published: inserted_timmy_person.published,
374       avatar: None,
375       actor_id: inserted_timmy_person.actor_id.clone(),
376       local: true,
377       banned: false,
378       ban_expires: None,
379       deleted: false,
380       admin: true,
381       bot_account: false,
382       bio: None,
383       banner: None,
384       updated: None,
385       inbox_url: inserted_timmy_person.inbox_url.clone(),
386       shared_inbox_url: None,
387       matrix_user_id: None,
388       instance_id: inserted_instance.id,
389     });
390     assert_eq!(read_sara_app_view_after_approve, expected_sara_app_view);
391
392     // Do a batch read of apps again
393     // It should show only jessicas which is unresolved
394     let apps_after_resolve = RegistrationApplicationQuery::builder()
395       .pool(pool)
396       .unread_only(Some(true))
397       .build()
398       .list()
399       .await
400       .unwrap();
401     assert_eq!(apps_after_resolve, vec![read_jess_app_view]);
402
403     // Make sure the counts are correct
404     let unread_count_after_approve = RegistrationApplicationView::get_unread_count(pool, false)
405       .await
406       .unwrap();
407     assert_eq!(unread_count_after_approve, 1);
408
409     // Make sure the not undenied_only has all the apps
410     let all_apps = RegistrationApplicationQuery::builder()
411       .pool(pool)
412       .build()
413       .list()
414       .await
415       .unwrap();
416     assert_eq!(all_apps.len(), 2);
417
418     Person::delete(pool, inserted_timmy_person.id)
419       .await
420       .unwrap();
421     Person::delete(pool, inserted_sara_person.id).await.unwrap();
422     Person::delete(pool, inserted_jess_person.id).await.unwrap();
423     Instance::delete(pool, inserted_instance.id).await.unwrap();
424   }
425 }