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