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