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