]> Untitled Git - lemmy.git/blob - crates/db_schema/src/impls/captcha_answer.rs
de5fac65e235190fe1f19d31ca648b9d7baedf6d
[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: &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(pool: &DbPool, to_check: CheckCaptchaAnswer) -> Result<bool, Error> {
28     let conn = &mut get_conn(pool).await?;
29
30     // fetch requested captcha
31     let captcha_exists = select(exists(
32       captcha_answer
33         .filter((uuid).eq(to_check.uuid))
34         .filter(lower(answer).eq(to_check.answer.to_lowercase().clone())),
35     ))
36     .get_result::<bool>(conn)
37     .await?;
38
39     // delete checked captcha
40     delete(captcha_answer.filter(uuid.eq(to_check.uuid)))
41       .execute(conn)
42       .await?;
43
44     Ok(captcha_exists)
45   }
46 }
47
48 #[cfg(test)]
49 mod tests {
50   use crate::{
51     source::captcha_answer::{CaptchaAnswer, CaptchaAnswerForm, CheckCaptchaAnswer},
52     utils::build_db_pool_for_tests,
53   };
54   use serial_test::serial;
55
56   #[tokio::test]
57   #[serial]
58   async fn test_captcha_happy_path() {
59     let pool = &build_db_pool_for_tests().await;
60
61     let inserted = CaptchaAnswer::insert(
62       pool,
63       &CaptchaAnswerForm {
64         answer: "XYZ".to_string(),
65       },
66     )
67     .await
68     .expect("should not fail to insert captcha");
69
70     let result = CaptchaAnswer::check_captcha(
71       pool,
72       CheckCaptchaAnswer {
73         uuid: inserted.uuid,
74         answer: "xyz".to_string(),
75       },
76     )
77     .await;
78
79     assert!(result.is_ok());
80     assert!(result.unwrap());
81   }
82
83   #[tokio::test]
84   #[serial]
85   async fn test_captcha_repeat_answer_fails() {
86     let pool = &build_db_pool_for_tests().await;
87
88     let inserted = CaptchaAnswer::insert(
89       pool,
90       &CaptchaAnswerForm {
91         answer: "XYZ".to_string(),
92       },
93     )
94     .await
95     .expect("should not fail to insert captcha");
96
97     let _result = CaptchaAnswer::check_captcha(
98       pool,
99       CheckCaptchaAnswer {
100         uuid: inserted.uuid,
101         answer: "xyz".to_string(),
102       },
103     )
104     .await;
105
106     let result_repeat = CaptchaAnswer::check_captcha(
107       pool,
108       CheckCaptchaAnswer {
109         uuid: inserted.uuid,
110         answer: "xyz".to_string(),
111       },
112     )
113     .await;
114
115     assert!(result_repeat.is_ok());
116     assert!(!result_repeat.unwrap());
117   }
118 }