]> Untitled Git - lemmy.git/blob - crates/db_views/src/registration_application_view.rs
00cc926748d9efa284e6d35741507a6f4c3fcbdf
[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       },
291       creator: Person {
292         id: inserted_sara_person.id,
293         name: inserted_sara_person.name.clone(),
294         display_name: None,
295         published: inserted_sara_person.published,
296         avatar: None,
297         actor_id: inserted_sara_person.actor_id.clone(),
298         local: true,
299         banned: false,
300         ban_expires: None,
301         deleted: false,
302         admin: false,
303         bot_account: false,
304         bio: None,
305         banner: None,
306         updated: None,
307         inbox_url: inserted_sara_person.inbox_url.clone(),
308         shared_inbox_url: None,
309         matrix_user_id: None,
310         instance_id: inserted_instance.id,
311         private_key: inserted_sara_person.private_key,
312         public_key: inserted_sara_person.public_key,
313         last_refreshed_at: inserted_sara_person.last_refreshed_at,
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(Person {
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       private_key: inserted_timmy_person.private_key,
390       public_key: inserted_timmy_person.public_key,
391       last_refreshed_at: inserted_timmy_person.last_refreshed_at,
392     });
393     assert_eq!(read_sara_app_view_after_approve, expected_sara_app_view);
394
395     // Do a batch read of apps again
396     // It should show only jessicas which is unresolved
397     let apps_after_resolve = RegistrationApplicationQuery::builder()
398       .pool(pool)
399       .unread_only(Some(true))
400       .build()
401       .list()
402       .await
403       .unwrap();
404     assert_eq!(apps_after_resolve, vec![read_jess_app_view]);
405
406     // Make sure the counts are correct
407     let unread_count_after_approve = RegistrationApplicationView::get_unread_count(pool, false)
408       .await
409       .unwrap();
410     assert_eq!(unread_count_after_approve, 1);
411
412     // Make sure the not undenied_only has all the apps
413     let all_apps = RegistrationApplicationQuery::builder()
414       .pool(pool)
415       .build()
416       .list()
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 }