]> Untitled Git - lemmy.git/blob - crates/db_views/src/registration_application_view.rs
ad6a7e9d34d908bfdf9d050d992f6ba7ffa775ed
[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,
15     person::Person,
16     registration_application::RegistrationApplication,
17   },
18   traits::JoinView,
19   utils::{get_conn, limit_and_offset, DbPool},
20 };
21 use typed_builder::TypedBuilder;
22
23 type RegistrationApplicationViewTuple =
24   (RegistrationApplication, LocalUser, Person, Option<Person>);
25
26 impl RegistrationApplicationView {
27   pub async fn read(
28     pool: &mut DbPool<'_>,
29     registration_application_id: i32,
30   ) -> Result<Self, Error> {
31     let conn = &mut get_conn(pool).await?;
32     let person_alias_1 = diesel::alias!(person as person1);
33
34     let (registration_application, creator_local_user, creator, admin) =
35       registration_application::table
36         .find(registration_application_id)
37         .inner_join(
38           local_user::table.on(registration_application::local_user_id.eq(local_user::id)),
39         )
40         .inner_join(person::table.on(local_user::person_id.eq(person::id)))
41         .left_join(
42           person_alias_1
43             .on(registration_application::admin_id.eq(person_alias_1.field(person::id).nullable())),
44         )
45         .order_by(registration_application::published.desc())
46         .select((
47           registration_application::all_columns,
48           local_user::all_columns,
49           person::all_columns,
50           person_alias_1.fields(person::all_columns).nullable(),
51         ))
52         .first::<RegistrationApplicationViewTuple>(conn)
53         .await?;
54
55     Ok(RegistrationApplicationView {
56       registration_application,
57       creator_local_user,
58       creator,
59       admin,
60     })
61   }
62
63   /// Returns the current unread registration_application count
64   pub async fn get_unread_count(
65     pool: &mut DbPool<'_>,
66     verified_email_only: bool,
67   ) -> 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, 'b: 'a> {
95   #[builder(!default)]
96   pool: &'a mut DbPool<'b>,
97   unread_only: Option<bool>,
98   verified_email_only: Option<bool>,
99   page: Option<i64>,
100   limit: Option<i64>,
101 }
102
103 impl<'a, 'b: 'a> RegistrationApplicationQuery<'a, 'b> {
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         local_user::all_columns,
119         person::all_columns,
120         person_alias_1.fields(person::all_columns).nullable(),
121       ))
122       .into_boxed();
123
124     if self.unread_only.unwrap_or(false) {
125       query = query.filter(registration_application::admin_id.is_null())
126     }
127
128     if self.verified_email_only.unwrap_or(false) {
129       query = query.filter(local_user::email_verified.eq(true))
130     }
131
132     let (limit, offset) = limit_and_offset(self.page, self.limit)?;
133
134     query = query
135       .limit(limit)
136       .offset(offset)
137       .order_by(registration_application::published.desc());
138
139     let res = query.load::<RegistrationApplicationViewTuple>(conn).await?;
140
141     Ok(
142       res
143         .into_iter()
144         .map(RegistrationApplicationView::from_tuple)
145         .collect(),
146     )
147   }
148 }
149
150 impl JoinView for RegistrationApplicationView {
151   type JoinTuple = RegistrationApplicationViewTuple;
152   fn from_tuple(a: Self::JoinTuple) -> Self {
153     Self {
154       registration_application: a.0,
155       creator_local_user: a.1,
156       creator: a.2,
157       admin: a.3,
158     }
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, LocalUserUpdateForm},
172       person::{Person, PersonInsertForm},
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     let pool = &mut pool.into();
189
190     let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string())
191       .await
192       .unwrap();
193
194     let timmy_person_form = PersonInsertForm::builder()
195       .name("timmy_rav".into())
196       .admin(Some(true))
197       .public_key("pubkey".to_string())
198       .instance_id(inserted_instance.id)
199       .build();
200
201     let inserted_timmy_person = Person::create(pool, &timmy_person_form).await.unwrap();
202
203     let timmy_local_user_form = LocalUserInsertForm::builder()
204       .person_id(inserted_timmy_person.id)
205       .password_encrypted("nada".to_string())
206       .build();
207
208     let _inserted_timmy_local_user = LocalUser::create(pool, &timmy_local_user_form)
209       .await
210       .unwrap();
211
212     let sara_person_form = PersonInsertForm::builder()
213       .name("sara_rav".into())
214       .public_key("pubkey".to_string())
215       .instance_id(inserted_instance.id)
216       .build();
217
218     let inserted_sara_person = Person::create(pool, &sara_person_form).await.unwrap();
219
220     let sara_local_user_form = LocalUserInsertForm::builder()
221       .person_id(inserted_sara_person.id)
222       .password_encrypted("nada".to_string())
223       .build();
224
225     let inserted_sara_local_user = LocalUser::create(pool, &sara_local_user_form)
226       .await
227       .unwrap();
228
229     // Sara creates an application
230     let sara_app_form = RegistrationApplicationInsertForm {
231       local_user_id: inserted_sara_local_user.id,
232       answer: "LET ME IIIIINN".to_string(),
233     };
234
235     let sara_app = RegistrationApplication::create(pool, &sara_app_form)
236       .await
237       .unwrap();
238
239     let read_sara_app_view = RegistrationApplicationView::read(pool, sara_app.id)
240       .await
241       .unwrap();
242
243     let jess_person_form = PersonInsertForm::builder()
244       .name("jess_rav".into())
245       .public_key("pubkey".to_string())
246       .instance_id(inserted_instance.id)
247       .build();
248
249     let inserted_jess_person = Person::create(pool, &jess_person_form).await.unwrap();
250
251     let jess_local_user_form = LocalUserInsertForm::builder()
252       .person_id(inserted_jess_person.id)
253       .password_encrypted("nada".to_string())
254       .build();
255
256     let inserted_jess_local_user = LocalUser::create(pool, &jess_local_user_form)
257       .await
258       .unwrap();
259
260     // Sara creates an application
261     let jess_app_form = RegistrationApplicationInsertForm {
262       local_user_id: inserted_jess_local_user.id,
263       answer: "LET ME IIIIINN".to_string(),
264     };
265
266     let jess_app = RegistrationApplication::create(pool, &jess_app_form)
267       .await
268       .unwrap();
269
270     let read_jess_app_view = RegistrationApplicationView::read(pool, jess_app.id)
271       .await
272       .unwrap();
273
274     let mut expected_sara_app_view = RegistrationApplicationView {
275       registration_application: sara_app.clone(),
276       creator_local_user: LocalUser {
277         id: inserted_sara_local_user.id,
278         person_id: inserted_sara_local_user.person_id,
279         email: inserted_sara_local_user.email,
280         show_nsfw: inserted_sara_local_user.show_nsfw,
281         theme: inserted_sara_local_user.theme,
282         default_sort_type: inserted_sara_local_user.default_sort_type,
283         default_listing_type: inserted_sara_local_user.default_listing_type,
284         interface_language: inserted_sara_local_user.interface_language,
285         show_avatars: inserted_sara_local_user.show_avatars,
286         send_notifications_to_email: inserted_sara_local_user.send_notifications_to_email,
287         validator_time: inserted_sara_local_user.validator_time,
288         show_bot_accounts: inserted_sara_local_user.show_bot_accounts,
289         show_scores: inserted_sara_local_user.show_scores,
290         show_read_posts: inserted_sara_local_user.show_read_posts,
291         show_new_post_notifs: inserted_sara_local_user.show_new_post_notifs,
292         email_verified: inserted_sara_local_user.email_verified,
293         accepted_application: inserted_sara_local_user.accepted_application,
294         totp_2fa_secret: inserted_sara_local_user.totp_2fa_secret,
295         totp_2fa_url: inserted_sara_local_user.totp_2fa_url,
296         password_encrypted: inserted_sara_local_user.password_encrypted,
297         open_links_in_new_tab: inserted_sara_local_user.open_links_in_new_tab,
298       },
299       creator: Person {
300         id: inserted_sara_person.id,
301         name: inserted_sara_person.name.clone(),
302         display_name: None,
303         published: inserted_sara_person.published,
304         avatar: None,
305         actor_id: inserted_sara_person.actor_id.clone(),
306         local: true,
307         banned: false,
308         ban_expires: None,
309         deleted: false,
310         admin: false,
311         bot_account: false,
312         bio: None,
313         banner: None,
314         updated: None,
315         inbox_url: inserted_sara_person.inbox_url.clone(),
316         shared_inbox_url: None,
317         matrix_user_id: None,
318         instance_id: inserted_instance.id,
319         private_key: inserted_sara_person.private_key,
320         public_key: inserted_sara_person.public_key,
321         last_refreshed_at: inserted_sara_person.last_refreshed_at,
322       },
323       admin: None,
324     };
325
326     assert_eq!(read_sara_app_view, expected_sara_app_view);
327
328     // Do a batch read of the applications
329     let apps = RegistrationApplicationQuery::builder()
330       .pool(pool)
331       .unread_only(Some(true))
332       .build()
333       .list()
334       .await
335       .unwrap();
336
337     assert_eq!(
338       apps,
339       [read_jess_app_view.clone(), expected_sara_app_view.clone()]
340     );
341
342     // Make sure the counts are correct
343     let unread_count = RegistrationApplicationView::get_unread_count(pool, false)
344       .await
345       .unwrap();
346     assert_eq!(unread_count, 2);
347
348     // Approve the application
349     let approve_form = RegistrationApplicationUpdateForm {
350       admin_id: Some(Some(inserted_timmy_person.id)),
351       deny_reason: None,
352     };
353
354     RegistrationApplication::update(pool, sara_app.id, &approve_form)
355       .await
356       .unwrap();
357
358     // Update the local_user row
359     let approve_local_user_form = LocalUserUpdateForm::builder()
360       .accepted_application(Some(true))
361       .build();
362
363     LocalUser::update(pool, inserted_sara_local_user.id, &approve_local_user_form)
364       .await
365       .unwrap();
366
367     let read_sara_app_view_after_approve = RegistrationApplicationView::read(pool, sara_app.id)
368       .await
369       .unwrap();
370
371     // Make sure the columns changed
372     expected_sara_app_view
373       .creator_local_user
374       .accepted_application = true;
375     expected_sara_app_view.registration_application.admin_id = Some(inserted_timmy_person.id);
376
377     expected_sara_app_view.admin = Some(Person {
378       id: inserted_timmy_person.id,
379       name: inserted_timmy_person.name.clone(),
380       display_name: None,
381       published: inserted_timmy_person.published,
382       avatar: None,
383       actor_id: inserted_timmy_person.actor_id.clone(),
384       local: true,
385       banned: false,
386       ban_expires: None,
387       deleted: false,
388       admin: true,
389       bot_account: false,
390       bio: None,
391       banner: None,
392       updated: None,
393       inbox_url: inserted_timmy_person.inbox_url.clone(),
394       shared_inbox_url: None,
395       matrix_user_id: None,
396       instance_id: inserted_instance.id,
397       private_key: inserted_timmy_person.private_key,
398       public_key: inserted_timmy_person.public_key,
399       last_refreshed_at: inserted_timmy_person.last_refreshed_at,
400     });
401     assert_eq!(read_sara_app_view_after_approve, expected_sara_app_view);
402
403     // Do a batch read of apps again
404     // It should show only jessicas which is unresolved
405     let apps_after_resolve = RegistrationApplicationQuery::builder()
406       .pool(pool)
407       .unread_only(Some(true))
408       .build()
409       .list()
410       .await
411       .unwrap();
412     assert_eq!(apps_after_resolve, vec![read_jess_app_view]);
413
414     // Make sure the counts are correct
415     let unread_count_after_approve = RegistrationApplicationView::get_unread_count(pool, false)
416       .await
417       .unwrap();
418     assert_eq!(unread_count_after_approve, 1);
419
420     // Make sure the not undenied_only has all the apps
421     let all_apps = RegistrationApplicationQuery::builder()
422       .pool(pool)
423       .build()
424       .list()
425       .await
426       .unwrap();
427     assert_eq!(all_apps.len(), 2);
428
429     Person::delete(pool, inserted_timmy_person.id)
430       .await
431       .unwrap();
432     Person::delete(pool, inserted_sara_person.id).await.unwrap();
433     Person::delete(pool, inserted_jess_person.id).await.unwrap();
434     Instance::delete(pool, inserted_instance.id).await.unwrap();
435   }
436 }