diff --git a/src/mail.rs b/src/mail.rs index 3ed0cf8..7d82558 100644 --- a/src/mail.rs +++ b/src/mail.rs @@ -13,8 +13,9 @@ //! the account is made and its sign-in link reaches nobody; //! - **fail** an invite mail without its `{link}`, or with a //! placeholder the invite cannot fill; -//! - **warn** a placeholder only some of the bucket's forms collect: it -//! is blank in the mails about the others; +//! - **warn** a placeholder only some of the bucket's forms collect, or +//! one every form marks optional: it is blank in the mails about the +//! others, or about anyone who skipped it; //! - **warn** a dialogue that does not close: the person is mailed on //! the way in and not told how their case ended; //! - **warn** a mail that tells a person their case is where they may @@ -158,6 +159,15 @@ pub fn check(questions: &HashMap, aggregates: &HashMap = bucket_forms.iter().filter(|(_, f)| f.contains(&key)).map(|(n, _)| n).collect(); if having.is_empty() { fail(format!("{at}: {{{key}}} is not a field any form recording into {bucket:?} collects, nor one portal fills ({}) - it would be sent blank", CASE_VARS.join(", "))); + } else if questions + .values() + .flat_map(|q| &q.alternatives) + .filter(|a| a.record_as.as_deref() == Some(bucket.as_str())) + .flat_map(|a| a.features.iter().flat_map(|f| &f.requirements)) + .filter(|r| r.name == key) + .all(|r| r.optional) + { + warns.push(format!("{at}: {{{key}}} is optional on every form - blank for anyone who skipped it")); } else if having.len() < bucket_forms.len() { let missing: Vec<&String> = bucket_forms.iter().filter(|(_, f)| !f.contains(&key)).map(|(n, _)| n).collect(); warns.push(format!("{at}: {{{key}}} is blank for records sent from {}", missing.iter().map(|n| format!("{n:?}")).collect::>().join(", "))); @@ -289,6 +299,15 @@ mod tests { assert!(f.iter().any(|x| x.text.contains("no {link}"))); } + #[test] + fn an_optional_answer_in_a_mail_is_found() { + let agg = AGG.replace("Got it, {name}", "Got it, {nick}"); + let form = FORM.replace(" - { name: email, type: email }\n", " - { name: email, type: email }\n - { name: nick, optional: true }\n"); + let (q, a) = repo(&agg, &[("/", &form), ("/decide/trial", DECIDE)]); + let f = check(&q, &a, &site("mail: { from: x@y.no }\n")); + assert!(f.iter().any(|x| x.level == Level::Warn && x.text.contains("{nick}") && x.text.contains("optional")), "{f:?}"); + } + #[test] fn a_long_answer_in_a_subject_line_is_found() { let agg = AGG.replace("Got it, {name}", "About {brief}");