]> Untitled Git - lemmy.git/blob - crates/db_views/src/registration_application_view.rs
1a5fc9bbbb0c695cf12ddb768075e2a7b81d8c2b
[lemmy.git] / crates / db_views / src / registration_application_view.rs
1 use diesel::{dsl::count, result::Error, *};
2 use lemmy_db_schema::{
3   limit_and_offset,
4   schema::{local_user, person, person_alias_1, registration_application},
5   source::{
6     local_user::{LocalUser, LocalUserSettings},
7     person::{Person, PersonAlias1, PersonSafe, PersonSafeAlias1},
8     registration_application::RegistrationApplication,
9   },
10   traits::{MaybeOptional, ToSafe, ToSafeSettings, ViewToVec},
11 };
12 use serde::{Deserialize, Serialize};
13
14 #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
15 pub struct RegistrationApplicationView {
16   pub registration_application: RegistrationApplication,
17   pub creator_local_user: LocalUserSettings,
18   pub creator: PersonSafe,
19   pub admin: Option<PersonSafeAlias1>,
20 }
21
22 type RegistrationApplicationViewTuple = (
23   RegistrationApplication,
24   LocalUserSettings,
25   PersonSafe,
26   Option<PersonSafeAlias1>,
27 );
28
29 impl RegistrationApplicationView {
30   pub fn read(conn: &PgConnection, registration_application_id: i32) -> Result<Self, Error> {
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::table
40             .on(registration_application::admin_id.eq(person_alias_1::id.nullable())),
41         )
42         .order_by(registration_application::published.desc())
43         .select((
44           registration_application::all_columns,
45           LocalUser::safe_settings_columns_tuple(),
46           Person::safe_columns_tuple(),
47           PersonAlias1::safe_columns_tuple().nullable(),
48         ))
49         .first::<RegistrationApplicationViewTuple>(conn)?;
50
51     Ok(RegistrationApplicationView {
52       registration_application,
53       creator_local_user,
54       creator,
55       admin,
56     })
57   }
58
59   /// Returns the current unread registration_application count
60   pub fn get_unread_count(conn: &PgConnection, verified_email_only: bool) -> Result<i64, Error> {
61     let mut query = registration_application::table
62       .inner_join(local_user::table.on(registration_application::local_user_id.eq(local_user::id)))
63       .inner_join(person::table.on(local_user::person_id.eq(person::id)))
64       .left_join(
65         person_alias_1::table
66           .on(registration_application::admin_id.eq(person_alias_1::id.nullable())),
67       )
68       .filter(registration_application::admin_id.is_null())
69       .into_boxed();
70
71     if verified_email_only {
72       query = query.filter(local_user::email_verified.eq(true))
73     }
74
75     query
76       .select(count(registration_application::id))
77       .first::<i64>(conn)
78   }
79 }
80
81 pub struct RegistrationApplicationQueryBuilder<'a> {
82   conn: &'a PgConnection,
83   unread_only: Option<bool>,
84   verified_email_only: Option<bool>,
85   page: Option<i64>,
86   limit: Option<i64>,
87 }
88
89 impl<'a> RegistrationApplicationQueryBuilder<'a> {
90   pub fn create(conn: &'a PgConnection) -> Self {
91     RegistrationApplicationQueryBuilder {
92       conn,
93       unread_only: None,
94       verified_email_only: None,
95       page: None,
96       limit: None,
97     }
98   }
99
100   pub fn unread_only<T: MaybeOptional<bool>>(mut self, unread_only: T) -> Self {
101     self.unread_only = unread_only.get_optional();
102     self
103   }
104
105   pub fn verified_email_only<T: MaybeOptional<bool>>(mut self, verified_email_only: T) -> Self {
106     self.verified_email_only = verified_email_only.get_optional();
107     self
108   }
109
110   pub fn page<T: MaybeOptional<i64>>(mut self, page: T) -> Self {
111     self.page = page.get_optional();
112     self
113   }
114
115   pub fn limit<T: MaybeOptional<i64>>(mut self, limit: T) -> Self {
116     self.limit = limit.get_optional();
117     self
118   }
119
120   pub fn list(self) -> Result<Vec<RegistrationApplicationView>, Error> {
121     let mut query = registration_application::table
122       .inner_join(local_user::table.on(registration_application::local_user_id.eq(local_user::id)))
123       .inner_join(person::table.on(local_user::person_id.eq(person::id)))
124       .left_join(
125         person_alias_1::table
126           .on(registration_application::admin_id.eq(person_alias_1::id.nullable())),
127       )
128       .order_by(registration_application::published.desc())
129       .select((
130         registration_application::all_columns,
131         LocalUser::safe_settings_columns_tuple(),
132         Person::safe_columns_tuple(),
133         PersonAlias1::safe_columns_tuple().nullable(),
134       ))
135       .into_boxed();
136
137     if self.unread_only.unwrap_or(false) {
138       query = query.filter(registration_application::admin_id.is_null())
139     }
140
141     if self.verified_email_only.unwrap_or(false) {
142       query = query.filter(local_user::email_verified.eq(true))
143     }
144
145     let (limit, offset) = limit_and_offset(self.page, self.limit);
146
147     query = query
148       .limit(limit)
149       .offset(offset)
150       .order_by(registration_application::published.desc());
151
152     let res = query.load::<RegistrationApplicationViewTuple>(self.conn)?;
153
154     Ok(RegistrationApplicationView::from_tuple_to_vec(res))
155   }
156 }
157
158 impl ViewToVec for RegistrationApplicationView {
159   type DbTuple = RegistrationApplicationViewTuple;
160   fn from_tuple_to_vec(items: Vec<Self::DbTuple>) -> Vec<Self> {
161     items
162       .iter()
163       .map(|a| Self {
164         registration_application: a.0.to_owned(),
165         creator_local_user: a.1.to_owned(),
166         creator: a.2.to_owned(),
167         admin: a.3.to_owned(),
168       })
169       .collect::<Vec<Self>>()
170   }
171 }
172
173 #[cfg(test)]
174 mod tests {
175   use crate::registration_application_view::{
176     RegistrationApplicationQueryBuilder,
177     RegistrationApplicationView,
178   };
179   use lemmy_db_schema::{
180     establish_unpooled_connection,
181     source::{
182       local_user::{LocalUser, LocalUserForm, LocalUserSettings},
183       person::*,
184       registration_application::{RegistrationApplication, RegistrationApplicationForm},
185     },
186     traits::Crud,
187   };
188   use serial_test::serial;
189
190   #[test]
191   #[serial]
192   fn test_crud() {
193     let conn = establish_unpooled_connection();
194
195     let timmy_person_form = PersonForm {
196       name: "timmy_rav".into(),
197       admin: Some(true),
198       ..PersonForm::default()
199     };
200
201     let inserted_timmy_person = Person::create(&conn, &timmy_person_form).unwrap();
202
203     let timmy_local_user_form = LocalUserForm {
204       person_id: Some(inserted_timmy_person.id),
205       password_encrypted: Some("nada".to_string()),
206       ..LocalUserForm::default()
207     };
208
209     let _inserted_timmy_local_user = LocalUser::create(&conn, &timmy_local_user_form).unwrap();
210
211     let sara_person_form = PersonForm {
212       name: "sara_rav".into(),
213       ..PersonForm::default()
214     };
215
216     let inserted_sara_person = Person::create(&conn, &sara_person_form).unwrap();
217
218     let sara_local_user_form = LocalUserForm {
219       person_id: Some(inserted_sara_person.id),
220       password_encrypted: Some("nada".to_string()),
221       ..LocalUserForm::default()
222     };
223
224     let inserted_sara_local_user = LocalUser::create(&conn, &sara_local_user_form).unwrap();
225
226     // Sara creates an application
227     let sara_app_form = RegistrationApplicationForm {
228       local_user_id: Some(inserted_sara_local_user.id),
229       answer: Some("LET ME IIIIINN".to_string()),
230       ..RegistrationApplicationForm::default()
231     };
232
233     let sara_app = RegistrationApplication::create(&conn, &sara_app_form).unwrap();
234
235     let read_sara_app_view = RegistrationApplicationView::read(&conn, sara_app.id).unwrap();
236
237     let jess_person_form = PersonForm {
238       name: "jess_rav".into(),
239       ..PersonForm::default()
240     };
241
242     let inserted_jess_person = Person::create(&conn, &jess_person_form).unwrap();
243
244     let jess_local_user_form = LocalUserForm {
245       person_id: Some(inserted_jess_person.id),
246       password_encrypted: Some("nada".to_string()),
247       ..LocalUserForm::default()
248     };
249
250     let inserted_jess_local_user = LocalUser::create(&conn, &jess_local_user_form).unwrap();
251
252     // Sara creates an application
253     let jess_app_form = RegistrationApplicationForm {
254       local_user_id: Some(inserted_jess_local_user.id),
255       answer: Some("LET ME IIIIINN".to_string()),
256       ..RegistrationApplicationForm::default()
257     };
258
259     let jess_app = RegistrationApplication::create(&conn, &jess_app_form).unwrap();
260
261     let read_jess_app_view = RegistrationApplicationView::read(&conn, jess_app.id).unwrap();
262
263     let mut expected_sara_app_view = RegistrationApplicationView {
264       registration_application: sara_app.to_owned(),
265       creator_local_user: LocalUserSettings {
266         id: inserted_sara_local_user.id,
267         person_id: inserted_sara_local_user.person_id,
268         email: inserted_sara_local_user.email,
269         show_nsfw: inserted_sara_local_user.show_nsfw,
270         theme: inserted_sara_local_user.theme,
271         default_sort_type: inserted_sara_local_user.default_sort_type,
272         default_listing_type: inserted_sara_local_user.default_listing_type,
273         lang: inserted_sara_local_user.lang,
274         show_avatars: inserted_sara_local_user.show_avatars,
275         send_notifications_to_email: inserted_sara_local_user.send_notifications_to_email,
276         validator_time: inserted_sara_local_user.validator_time,
277         show_bot_accounts: inserted_sara_local_user.show_bot_accounts,
278         show_scores: inserted_sara_local_user.show_scores,
279         show_read_posts: inserted_sara_local_user.show_read_posts,
280         show_new_post_notifs: inserted_sara_local_user.show_new_post_notifs,
281         email_verified: inserted_sara_local_user.email_verified,
282         accepted_application: inserted_sara_local_user.accepted_application,
283       },
284       creator: PersonSafe {
285         id: inserted_sara_person.id,
286         name: inserted_sara_person.name.to_owned(),
287         display_name: None,
288         published: inserted_sara_person.published,
289         avatar: None,
290         actor_id: inserted_sara_person.actor_id.to_owned(),
291         local: true,
292         banned: false,
293         deleted: false,
294         admin: false,
295         bot_account: false,
296         bio: None,
297         banner: None,
298         updated: None,
299         inbox_url: inserted_sara_person.inbox_url.to_owned(),
300         shared_inbox_url: None,
301         matrix_user_id: None,
302       },
303       admin: None,
304     };
305
306     assert_eq!(read_sara_app_view, expected_sara_app_view);
307
308     // Do a batch read of the applications
309     let apps = RegistrationApplicationQueryBuilder::create(&conn)
310       .unread_only(true)
311       .list()
312       .unwrap();
313
314     assert_eq!(
315       apps,
316       [
317         read_jess_app_view.to_owned(),
318         expected_sara_app_view.to_owned()
319       ]
320     );
321
322     // Make sure the counts are correct
323     let unread_count = RegistrationApplicationView::get_unread_count(&conn, false).unwrap();
324     assert_eq!(unread_count, 2);
325
326     // Approve the application
327     let approve_form = RegistrationApplicationForm {
328       admin_id: Some(inserted_timmy_person.id),
329       deny_reason: None,
330       ..RegistrationApplicationForm::default()
331     };
332
333     RegistrationApplication::update(&conn, sara_app.id, &approve_form).unwrap();
334
335     // Update the local_user row
336     let approve_local_user_form = LocalUserForm {
337       accepted_application: Some(true),
338       ..LocalUserForm::default()
339     };
340
341     LocalUser::update(&conn, inserted_sara_local_user.id, &approve_local_user_form).unwrap();
342
343     let read_sara_app_view_after_approve =
344       RegistrationApplicationView::read(&conn, sara_app.id).unwrap();
345
346     // Make sure the columns changed
347     expected_sara_app_view
348       .creator_local_user
349       .accepted_application = true;
350     expected_sara_app_view.registration_application.admin_id = Some(inserted_timmy_person.id);
351
352     expected_sara_app_view.admin = Some(PersonSafeAlias1 {
353       id: inserted_timmy_person.id,
354       name: inserted_timmy_person.name.to_owned(),
355       display_name: None,
356       published: inserted_timmy_person.published,
357       avatar: None,
358       actor_id: inserted_timmy_person.actor_id.to_owned(),
359       local: true,
360       banned: false,
361       deleted: false,
362       admin: true,
363       bot_account: false,
364       bio: None,
365       banner: None,
366       updated: None,
367       inbox_url: inserted_timmy_person.inbox_url.to_owned(),
368       shared_inbox_url: None,
369       matrix_user_id: None,
370     });
371     assert_eq!(read_sara_app_view_after_approve, expected_sara_app_view);
372
373     // Do a batch read of apps again
374     // It should show only jessicas which is unresolved
375     let apps_after_resolve = RegistrationApplicationQueryBuilder::create(&conn)
376       .unread_only(true)
377       .list()
378       .unwrap();
379     assert_eq!(apps_after_resolve, vec![read_jess_app_view]);
380
381     // Make sure the counts are correct
382     let unread_count_after_approve =
383       RegistrationApplicationView::get_unread_count(&conn, false).unwrap();
384     assert_eq!(unread_count_after_approve, 1);
385
386     // Make sure the not undenied_only has all the apps
387     let all_apps = RegistrationApplicationQueryBuilder::create(&conn)
388       .list()
389       .unwrap();
390     assert_eq!(all_apps.len(), 2);
391
392     Person::delete(&conn, inserted_timmy_person.id).unwrap();
393     Person::delete(&conn, inserted_sara_person.id).unwrap();
394     Person::delete(&conn, inserted_jess_person.id).unwrap();
395   }
396 }