]> Untitled Git - lemmy.git/blob - crates/db_schema/src/impls/captcha_answer.rs
Fixing removed posts showing. Fixes #2875 (#3279)
[lemmy.git] / crates / db_schema / src / impls / captcha_answer.rs
1 use crate::{
2   schema::captcha_answer,
3   source::captcha_answer::CaptchaAnswer,
4   utils::{functions::lower, get_conn, naive_now, 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: &CaptchaAnswer) -> Result<Self, Error> {
19     let conn = &mut get_conn(pool).await?;
20
21     insert_into(captcha_answer::table)
22       .values(captcha)
23       .get_result::<Self>(conn)
24       .await
25   }
26
27   pub async fn check_captcha(pool: &DbPool, to_check: CaptchaAnswer) -> Result<bool, Error> {
28     let conn = &mut get_conn(pool).await?;
29
30     // delete any expired captchas
31     delete(captcha_answer::table.filter(captcha_answer::expires.lt(&naive_now())))
32       .execute(conn)
33       .await?;
34
35     // fetch requested captcha
36     let captcha_exists = select(exists(
37       captcha_answer::dsl::captcha_answer
38         .filter((captcha_answer::dsl::uuid).eq(to_check.uuid.clone()))
39         .filter(lower(captcha_answer::dsl::answer).eq(to_check.answer.to_lowercase().clone())),
40     ))
41     .get_result::<bool>(conn)
42     .await?;
43
44     // delete checked captcha
45     delete(captcha_answer::table.filter(captcha_answer::uuid.eq(to_check.uuid.clone())))
46       .execute(conn)
47       .await?;
48
49     Ok(captcha_exists)
50   }
51 }
52
53 #[cfg(test)]
54 mod tests {
55   use crate::{
56     source::captcha_answer::CaptchaAnswer,
57     utils::{build_db_pool_for_tests, naive_now},
58   };
59   use chrono::Duration;
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
67     let captcha_a_id = "a".to_string();
68
69     let _ = CaptchaAnswer::insert(
70       pool,
71       &CaptchaAnswer {
72         uuid: captcha_a_id.clone(),
73         answer: "XYZ".to_string(),
74         expires: naive_now() + Duration::minutes(10),
75       },
76     )
77     .await;
78
79     let result = CaptchaAnswer::check_captcha(
80       pool,
81       CaptchaAnswer {
82         uuid: captcha_a_id.clone(),
83         answer: "xyz".to_string(),
84         expires: chrono::NaiveDateTime::MIN,
85       },
86     )
87     .await;
88
89     assert!(result.is_ok());
90     assert!(result.unwrap());
91   }
92
93   #[tokio::test]
94   #[serial]
95   async fn test_captcha_repeat_answer_fails() {
96     let pool = &build_db_pool_for_tests().await;
97
98     let captcha_a_id = "a".to_string();
99
100     let _ = CaptchaAnswer::insert(
101       pool,
102       &CaptchaAnswer {
103         uuid: captcha_a_id.clone(),
104         answer: "XYZ".to_string(),
105         expires: naive_now() + Duration::minutes(10),
106       },
107     )
108     .await;
109
110     let result = CaptchaAnswer::check_captcha(
111       pool,
112       CaptchaAnswer {
113         uuid: captcha_a_id.clone(),
114         answer: "xyz".to_string(),
115         expires: chrono::NaiveDateTime::MIN,
116       },
117     )
118     .await;
119
120     let result_repeat = CaptchaAnswer::check_captcha(
121       pool,
122       CaptchaAnswer {
123         uuid: captcha_a_id.clone(),
124         answer: "xyz".to_string(),
125         expires: chrono::NaiveDateTime::MIN,
126       },
127     )
128     .await;
129
130     assert!(result_repeat.is_ok());
131     assert!(!result_repeat.unwrap());
132   }
133
134   #[tokio::test]
135   #[serial]
136   async fn test_captcha_expired_fails() {
137     let pool = &build_db_pool_for_tests().await;
138
139     let expired_id = "already_expired".to_string();
140
141     let _ = CaptchaAnswer::insert(
142       pool,
143       &CaptchaAnswer {
144         uuid: expired_id.clone(),
145         answer: "xyz".to_string(),
146         expires: naive_now() - Duration::seconds(1),
147       },
148     )
149     .await;
150
151     let expired_result = CaptchaAnswer::check_captcha(
152       pool,
153       CaptchaAnswer {
154         uuid: expired_id.clone(),
155         answer: "xyz".to_string(),
156         expires: chrono::NaiveDateTime::MIN,
157       },
158     )
159     .await;
160
161     assert!(expired_result.is_ok());
162     assert!(!expired_result.unwrap());
163   }
164 }