check: what the site mails, before anyone receives it #1

Open
bl wants to merge 3 commits from mail-checks into main
Showing only changes of commit 07dd6c0f40 - Show all commits
+21 -2
View File
@@ -13,8 +13,9 @@
//! the account is made and its sign-in link reaches nobody; //! the account is made and its sign-in link reaches nobody;
//! - **fail** an invite mail without its `{link}`, or with a //! - **fail** an invite mail without its `{link}`, or with a
//! placeholder the invite cannot fill; //! placeholder the invite cannot fill;
//! - **warn** a placeholder only some of the bucket's forms collect: it //! - **warn** a placeholder only some of the bucket's forms collect, or
//! is blank in the mails about the others; //! 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 //! - **warn** a dialogue that does not close: the person is mailed on
//! the way in and not told how their case ended; //! the way in and not told how their case ended;
//! - **warn** a mail that tells a person their case is where they may //! - **warn** a mail that tells a person their case is where they may
@@ -158,6 +159,15 @@ pub fn check(questions: &HashMap<String, Question>, aggregates: &HashMap<String,
let having: Vec<&String> = bucket_forms.iter().filter(|(_, f)| f.contains(&key)).map(|(n, _)| n).collect(); let having: Vec<&String> = bucket_forms.iter().filter(|(_, f)| f.contains(&key)).map(|(n, _)| n).collect();
if having.is_empty() { 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(", "))); 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() { } else if having.len() < bucket_forms.len() {
let missing: Vec<&String> = bucket_forms.iter().filter(|(_, f)| !f.contains(&key)).map(|(n, _)| n).collect(); 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::<Vec<_>>().join(", "))); warns.push(format!("{at}: {{{key}}} is blank for records sent from {}", missing.iter().map(|n| format!("{n:?}")).collect::<Vec<_>>().join(", ")));
@@ -289,6 +299,15 @@ mod tests {
assert!(f.iter().any(|x| x.text.contains("no {link}"))); 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] #[test]
fn a_long_answer_in_a_subject_line_is_found() { fn a_long_answer_in_a_subject_line_is_found() {
let agg = AGG.replace("Got it, {name}", "About {brief}"); let agg = AGG.replace("Got it, {name}", "About {brief}");