salvo_captcha/finder/
query_finder.rs1use salvo_core::http::Request;
13
14use crate::CaptchaFinder;
15
16#[derive(Debug)]
18pub struct CaptchaQueryFinder {
19 pub token_name: String,
23
24 pub answer_name: String,
28}
29
30impl CaptchaQueryFinder {
31 pub fn new() -> Self {
33 Self::default()
34 }
35
36 pub fn token_name(mut self, token_name: String) -> Self {
38 self.token_name = token_name;
39 self
40 }
41
42 pub fn answer_name(mut self, answer_name: String) -> Self {
44 self.answer_name = answer_name;
45 self
46 }
47}
48
49impl Default for CaptchaQueryFinder {
50 fn default() -> Self {
54 Self {
55 token_name: "c_t".to_string(),
56 answer_name: "c_a".to_string(),
57 }
58 }
59}
60
61impl CaptchaFinder for CaptchaQueryFinder {
62 async fn find_token(&self, req: &mut Request) -> Option<Option<String>> {
63 req.queries()
64 .get(&self.token_name)
65 .map(|o| Some(o.to_owned()))
66 }
67
68 async fn find_answer(&self, req: &mut Request) -> Option<Option<String>> {
69 req.queries()
70 .get(&self.answer_name)
71 .map(|o| Some(o.to_owned()))
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 #[tokio::test]
80 #[rstest::rstest]
81 #[case::not_found(None, None, None, None, None, None)]
82 #[case::normal(
83 None,
84 None,
85 Some(("c_t", "token")),
86 Some(("c_a", "answer")),
87 Some(Some("token")),
88 Some(Some("answer"))
89 )]
90 #[case::custom_keys(
91 Some("cc_t"),
92 Some("cc_a"),
93 Some(("cc_t", "token")),
94 Some(("cc_a", "answer")),
95 Some(Some("token")),
96 Some(Some("answer"))
97 )]
98 #[case::only_token(
99 None,
100 None,
101 Some(("c_t", "token")),
102 None,
103 Some(Some("token")),
104 None
105 )]
106 #[case::only_answer(None, None, None, Some(("c_a", "ans")), None, Some(Some("ans")))]
107 #[case::custom_not_found(Some("cc_t"), Some("cc_a"), None, None, None, None)]
108 #[case::custom_not_found_with_query(
109 Some("cc_t"),
110 Some("cc_a"),
111 Some(("c_t", "token")),
112 Some(("c_a", "answer")),
113 None,
114 None
115 )]
116 async fn test_query_finder(
117 #[case] custom_token_key: Option<&'static str>,
118 #[case] custom_answer_key: Option<&'static str>,
119 #[case] token_key_val: Option<(&'static str, &'static str)>,
120 #[case] answer_key_val: Option<(&'static str, &'static str)>,
121 #[case] excepted_token: Option<Option<&'static str>>,
122 #[case] excepted_answer: Option<Option<&'static str>>,
123 ) {
124 let mut req = Request::default();
125 let mut finder = CaptchaQueryFinder::new();
126 if let Some(token_key) = custom_token_key {
127 finder = finder.token_name(token_key.to_string())
128 }
129 if let Some(answer_key) = custom_answer_key {
130 finder = finder.answer_name(answer_key.to_string())
131 }
132
133 let queries = req.queries_mut();
134
135 if let Some((k, v)) = token_key_val {
136 queries.insert(k.to_owned(), v.to_owned());
137 }
138 if let Some((k, v)) = answer_key_val {
139 queries.insert(k.to_owned(), v.to_owned());
140 }
141
142 assert_eq!(
143 finder.find_token(&mut req).await,
144 excepted_token.map(|o| o.map(ToOwned::to_owned))
145 );
146 assert_eq!(
147 finder.find_answer(&mut req).await,
148 excepted_answer.map(|o| o.map(ToOwned::to_owned))
149 );
150 }
151}