]> Untitled Git - lemmy.git/blob - crates/db_views/src/registration_application_view.rs
Get rid of Safe Views, use serde_skip (#2767)
[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         password_encrypted: inserted_sara_local_user.password_encrypted,
288       },
289       creator: Person {
290         id: inserted_sara_person.id,
291         name: inserted_sara_person.name.clone(),
292         display_name: None,
293         published: inserted_sara_person.published,
294         avatar: None,
295         actor_id: inserted_sara_person.actor_id.clone(),
296         local: true,
297         banned: false,
298         ban_expires: None,
299         deleted: false,
300         admin: false,
301         bot_account: false,
302         bio: None,
303         banner: None,
304         updated: None,
305         inbox_url: inserted_sara_person.inbox_url.clone(),
306         shared_inbox_url: None,
307         matrix_user_id: None,
308         instance_id: inserted_instance.id,
309         private_key: inserted_sara_person.private_key,
310         public_key: inserted_sara_person.public_key,
311         last_refreshed_at: inserted_sara_person.last_refreshed_at,
312       },
313       admin: None,
314     };
315
316     assert_eq!(read_sara_app_view, expected_sara_app_view);
317
318     // Do a batch read of the applications
319     let apps = RegistrationApplicationQuery::builder()
320       .pool(pool)
321       .unread_only(Some(true))
322       .build()
323       .list()
324       .await
325       .unwrap();
326
327     assert_eq!(
328       apps,
329       [read_jess_app_view.clone(), expected_sara_app_view.clone()]
330     );
331
332     // Make sure the counts are correct
333     let unread_count = RegistrationApplicationView::get_unread_count(pool, false)
334       .await
335       .unwrap();
336     assert_eq!(unread_count, 2);
337
338     // Approve the application
339     let approve_form = RegistrationApplicationUpdateForm {
340       admin_id: Some(Some(inserted_timmy_person.id)),
341       deny_reason: None,
342     };
343
344     RegistrationApplication::update(pool, sara_app.id, &approve_form)
345       .await
346       .unwrap();
347
348     // Update the local_user row
349     let approve_local_user_form = LocalUserUpdateForm::builder()
350       .accepted_application(Some(true))
351       .build();
352
353     LocalUser::update(pool, inserted_sara_local_user.id, &approve_local_user_form)
354       .await
355       .unwrap();
356
357     let read_sara_app_view_after_approve = RegistrationApplicationView::read(pool, sara_app.id)
358       .await
359       .unwrap();
360
361     // Make sure the columns changed
362     expected_sara_app_view
363       .creator_local_user
364       .accepted_application = true;
365     expected_sara_app_view.registration_application.admin_id = Some(inserted_timmy_person.id);
366
367     expected_sara_app_view.admin = Some(Person {
368       id: inserted_timmy_person.id,
369       name: inserted_timmy_person.name.clone(),
370       display_name: None,
371       published: inserted_timmy_person.published,
372       avatar: None,
373       actor_id: inserted_timmy_person.actor_id.clone(),
374       local: true,
375       banned: false,
376       ban_expires: None,
377       deleted: false,
378       admin: true,
379       bot_account: false,
380       bio: None,
381       banner: None,
382       updated: None,
383       inbox_url: inserted_timmy_person.inbox_url.clone(),
384       shared_inbox_url: None,
385       matrix_user_id: None,
386       instance_id: inserted_instance.id,
387       private_key: inserted_timmy_person.private_key,
388       public_key: inserted_timmy_person.public_key,
389       last_refreshed_at: inserted_timmy_person.last_refreshed_at,
390     });
391     assert_eq!(read_sara_app_view_after_approve, expected_sara_app_view);
392
393     // Do a batch read of apps again
394     // It should show only jessicas which is unresolved
395     let apps_after_resolve = RegistrationApplicationQuery::builder()
396       .pool(pool)
397       .unread_only(Some(true))
398       .build()
399       .list()
400       .await
401       .unwrap();
402     assert_eq!(apps_after_resolve, vec![read_jess_app_view]);
403
404     // Make sure the counts are correct
405     let unread_count_after_approve = RegistrationApplicationView::get_unread_count(pool, false)
406       .await
407       .unwrap();
408     assert_eq!(unread_count_after_approve, 1);
409
410     // Make sure the not undenied_only has all the apps
411     let all_apps = RegistrationApplicationQuery::builder()
412       .pool(pool)
413       .build()
414       .list()
415       .await
416       .unwrap();
417     assert_eq!(all_apps.len(), 2);
418
419     Person::delete(pool, inserted_timmy_person.id)
420       .await
421       .unwrap();
422     Person::delete(pool, inserted_sara_person.id).await.unwrap();
423     Person::delete(pool, inserted_jess_person.id).await.unwrap();
424     Instance::delete(pool, inserted_instance.id).await.unwrap();
425   }
426 }