mas_templates/context/
captcha.rs1use std::{collections::BTreeMap, sync::Arc};
9
10use mas_i18n::DataLocale;
11use minijinja::{
12 Value,
13 value::{Enumerator, Object},
14};
15use rand::Rng;
16use serde::Serialize;
17
18use crate::{TemplateContext, context::SampleIdentifier};
19
20#[derive(Debug)]
21struct CaptchaConfig(mas_data_model::CaptchaConfig);
22
23impl Object for CaptchaConfig {
24 fn get_value(self: &Arc<Self>, key: &Value) -> Option<Value> {
25 match key.as_str() {
26 Some("service") => Some(match &self.0.service {
27 mas_data_model::CaptchaService::RecaptchaV2 => "recaptcha_v2".into(),
28 mas_data_model::CaptchaService::CloudflareTurnstile => {
29 "cloudflare_turnstile".into()
30 }
31 mas_data_model::CaptchaService::HCaptcha => "hcaptcha".into(),
32 }),
33 Some("site_key") => Some(self.0.site_key.clone().into()),
34 _ => None,
35 }
36 }
37
38 fn enumerate(self: &Arc<Self>) -> Enumerator {
39 Enumerator::Str(&["service", "site_key"])
40 }
41}
42
43#[derive(Serialize)]
45pub struct WithCaptcha<T> {
46 captcha_config: Option<Value>,
47
48 #[serde(flatten)]
49 inner: T,
50}
51
52impl<T> WithCaptcha<T> {
53 #[must_use]
54 pub(crate) fn new(captcha: Option<mas_data_model::CaptchaConfig>, inner: T) -> Self {
55 Self {
56 captcha_config: captcha.map(|captcha| Value::from_object(CaptchaConfig(captcha))),
57 inner,
58 }
59 }
60}
61
62impl<T: TemplateContext> TemplateContext for WithCaptcha<T> {
63 fn sample<R: Rng>(
64 now: chrono::DateTime<chrono::prelude::Utc>,
65 rng: &mut R,
66 locales: &[DataLocale],
67 ) -> BTreeMap<SampleIdentifier, Self>
68 where
69 Self: Sized,
70 {
71 T::sample(now, rng, locales)
72 .into_iter()
73 .map(|(k, inner)| (k, Self::new(None, inner)))
74 .collect()
75 }
76}