check: warn on a long answer (textarea) in a mail's subject line
Test / test (pull_request) Successful in 2m6s

Found by the trainer's first mail rewording: 'We'll take on {project}'
puts the whole brief in the inbox list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Bendik Aagaard Lynghaug
2026-09-28 18:27:17 +02:00
co-authored by Claude Opus 5.5
parent 8bee3ed4ec
commit de622e4164
+18 -1
View File
@@ -18,7 +18,9 @@
//! - **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
//! now act on it, and gives them no link to do so.
//! now act on it, and gives them no link to do so;
//! - **warn** a long answer (a `textarea` field) put in a subject line,
//! which becomes the whole brief in someone's inbox list.
use std::collections::{BTreeMap, BTreeSet, HashMap};
@@ -161,6 +163,12 @@ pub fn check(questions: &HashMap<String, Question>, aggregates: &HashMap<String,
warns.push(format!("{at}: {{{key}}} is blank for records sent from {}", missing.iter().map(|n| format!("{n:?}")).collect::<Vec<_>>().join(", ")));
}
}
for key in placeholders(&mail.subject) {
let long = 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)).any(|r| r.name == key && r.kind == "textarea");
if long {
warns.push(format!("{at}: the subject carries {{{key}}}, a long answer (textarea) - the whole of it lands in the subject line"));
}
}
for path in site_links(&mail.body).into_iter().chain(site_links(&mail.subject)) {
if path.contains('{') {
continue; // filled per record; the page is checked where the pattern is declared
@@ -281,6 +289,15 @@ mod tests {
assert!(f.iter().any(|x| x.text.contains("no {link}")));
}
#[test]
fn a_long_answer_in_a_subject_line_is_found() {
let agg = AGG.replace("Got it, {name}", "About {brief}");
let form = FORM.replace(" - { name: email, type: email }\n", " - { name: email, type: email }\n - { name: brief, type: textarea }\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("{brief}") && x.text.contains("subject")), "{f:?}");
}
#[test]
fn a_mail_about_a_case_the_person_may_act_on_links_to_it() {
let agg = AGG.replace("Withdraw at {site}/decide/trial?chain={chain}", "We have it");