]> Untitled Git - lemmy.git/blob - crates/db_schema/src/impls/captcha_answer.rs
fe85b78b28015d0385ff0ef1a275d7a6021ef008
[lemmy.git] / crates / db_schema / src / impls / captcha_answer.rs
1 use crate::{
2   schema::captcha_answer::dsl::{answer, captcha_answer, uuid},
3   source::captcha_answer::{CaptchaAnswer, CaptchaAnswerForm, CheckCaptchaAnswer},
4   utils::{functions::lower, get_conn, DbPool},
5 };
6 use diesel::{
7   delete,
8   dsl::exists,
9   insert_into,
10   result::Error,
11   select,
12   ExpressionMethods,
13   QueryDsl,
14 };
15 use diesel_async::RunQueryDsl;
16
17 impl CaptchaAnswer {
18   pub async fn insert(pool: &mut DbPool<'_>, captcha: &CaptchaAnswerForm) -> Result<Self, Error> {
19     let conn = &mut get_conn(pool).await?;
20
21     insert_into(captcha_answer)
22       .values(captcha)
23       .get_result::<Self>(conn)
24       .await
25   }
26
27   pub async fn check_captcha(
28     pool: &mut DbPool<'_>,
29     to_check: CheckCaptchaAnswer,
30   ) -> Result<bool, Error> {
31     let conn = &mut get_conn(pool).await?;
32
33     // fetch requested captcha
34     let captcha_exists = select(exists(
35       captcha_answer
36         .filter((uuid).eq(to_check.uuid))
37         .filter(lower(answer).eq(to_check.answer.to_lowercase().clone())),
38     ))
39     .get_result::<bool>(conn)
40     .await?;
41
42     // delete checked captcha
43     delete(captcha_answer.filter(uuid.eq(to_check.uuid)))
44       .execute(conn)
45       .await?;
46
47     Ok(captcha_exists)
48   }
49 }
50
51 #[cfg(test)]
52 mod tests {
53   use crate::{
54     source::captcha_answer::{CaptchaAnswer, CaptchaAnswerForm, CheckCaptchaAnswer},
55     utils::build_db_pool_for_tests,
56   };
57   use serial_test::serial;
58
59   #[tokio::test]
60   #[serial]
61   async fn test_captcha_happy_path() {
62     let pool = &build_db_pool_for_tests().await;
63     let pool = &mut pool.into();
64
65     let inserted = CaptchaAnswer::insert(
66       pool,
67       &CaptchaAnswerForm {
68         answer: "XYZ".to_string(),
69       },
70     )
71     .await
72     .expect("should not fail to insert captcha");
73
74     let result = CaptchaAnswer::check_captcha(
75       pool,
76       CheckCaptchaAnswer {
77         uuid: inserted.uuid,
78         answer: "xyz".to_string(),
79       },
80     )
81     .await;
82
83     assert!(result.is_ok());
84     assert!(result.unwrap());
85   }
86
87   #[tokio::test]
88   #[serial]
89   async fn test_captcha_repeat_answer_fails() {
90     let pool = &build_db_pool_for_tests().await;
91     let pool = &mut pool.into();
92
93     let inserted = CaptchaAnswer::insert(
94       pool,
95       &CaptchaAnswerForm {
96         answer: "XYZ".to_string(),
97       },
98     )
99     .await
100     .expect("should not fail to insert captcha");
101
102     let _result = CaptchaAnswer::check_captcha(
103       pool,
104       CheckCaptchaAnswer {
105         uuid: inserted.uuid,
106         answer: "xyz".to_string(),
107       },
108     )
109     .await;
110
111     let result_repeat = CaptchaAnswer::check_captcha(
112       pool,
113       CheckCaptchaAnswer {
114         uuid: inserted.uuid,
115         answer: "xyz".to_string(),
116       },
117     )
118     .await;
119
120     assert!(result_repeat.is_ok());
121     assert!(!result_repeat.unwrap());
122   }
123 }