]> Untitled Git - lemmy.git/blob - crates/db_schema/src/impls/captcha_answer.rs
Cache & Optimize Woodpecker CI (#3450)
[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   #![allow(clippy::unwrap_used)]
54   #![allow(clippy::indexing_slicing)]
55
56   use crate::{
57     source::captcha_answer::{CaptchaAnswer, CaptchaAnswerForm, CheckCaptchaAnswer},
58     utils::build_db_pool_for_tests,
59   };
60   use serial_test::serial;
61
62   #[tokio::test]
63   #[serial]
64   async fn test_captcha_happy_path() {
65     let pool = &build_db_pool_for_tests().await;
66     let pool = &mut pool.into();
67
68     let inserted = CaptchaAnswer::insert(
69       pool,
70       &CaptchaAnswerForm {
71         answer: "XYZ".to_string(),
72       },
73     )
74     .await
75     .expect("should not fail to insert captcha");
76
77     let result = CaptchaAnswer::check_captcha(
78       pool,
79       CheckCaptchaAnswer {
80         uuid: inserted.uuid,
81         answer: "xyz".to_string(),
82       },
83     )
84     .await;
85
86     assert!(result.is_ok());
87     assert!(result.unwrap());
88   }
89
90   #[tokio::test]
91   #[serial]
92   async fn test_captcha_repeat_answer_fails() {
93     let pool = &build_db_pool_for_tests().await;
94     let pool = &mut pool.into();
95
96     let inserted = CaptchaAnswer::insert(
97       pool,
98       &CaptchaAnswerForm {
99         answer: "XYZ".to_string(),
100       },
101     )
102     .await
103     .expect("should not fail to insert captcha");
104
105     let _result = CaptchaAnswer::check_captcha(
106       pool,
107       CheckCaptchaAnswer {
108         uuid: inserted.uuid,
109         answer: "xyz".to_string(),
110       },
111     )
112     .await;
113
114     let result_repeat = CaptchaAnswer::check_captcha(
115       pool,
116       CheckCaptchaAnswer {
117         uuid: inserted.uuid,
118         answer: "xyz".to_string(),
119       },
120     )
121     .await;
122
123     assert!(result_repeat.is_ok());
124     assert!(!result_repeat.unwrap());
125   }
126 }