From a019513efb557941dcf301aba5585aa5111f2279 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Tue, 22 Jan 2019 15:37:15 +0100 Subject: add support for `email = false` to disable email validation This allows a person to explicitly opt out from the mailing lists. --- src/data.rs | 7 +++++-- src/schema.rs | 45 ++++++++++++++++++++++++++++++++++++++++----- src/validate.rs | 5 +++-- 3 files changed, 48 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/data.rs b/src/data.rs index 22af7a2..a93fc4b 100644 --- a/src/data.rs +++ b/src/data.rs @@ -21,11 +21,14 @@ impl Data { }; data.load_dir("people", |this, person: Person| { + person.validate()?; this.people.insert(person.github().to_string(), person); + Ok(()) })?; data.load_dir("teams", |this, team: Team| { this.teams.insert(team.name().to_string(), team); + Ok(()) })?; Ok(data) @@ -34,13 +37,13 @@ impl Data { fn load_dir(&mut self, dir: &str, f: F) -> Result<(), Error> where T: for<'de> Deserialize<'de>, - F: Fn(&mut Self, T), + F: Fn(&mut Self, T) -> Result<(), Error>, { for entry in std::fs::read_dir(dir)? { let path = entry?.path(); if path.is_file() && path.extension() == Some(OsStr::new("toml")) { - f(self, load_file(&path)?); + f(self, load_file(&path)?)?; } } diff --git a/src/schema.rs b/src/schema.rs index de30b08..f527827 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -1,5 +1,5 @@ use crate::data::Data; -use failure::{err_msg, Error}; +use failure::{bail, err_msg, Error}; use std::collections::HashSet; #[derive(serde_derive::Deserialize, Debug)] @@ -14,13 +14,36 @@ impl Config { } } +// This is an enum to allow two kinds of values for the email field: +// email = false +// email = "foo@example.com" +#[derive(serde_derive::Deserialize, Debug)] +#[serde(untagged)] +enum EmailField { + Disabled(bool), + Explicit(Option), +} + +impl Default for EmailField { + fn default() -> Self { + EmailField::Explicit(None) + } +} + +pub(crate) enum Email<'a> { + Missing, + Disabled, + Present(&'a str), +} + #[derive(serde_derive::Deserialize, Debug)] #[serde(deny_unknown_fields)] pub(crate) struct Person { name: String, github: String, irc: Option, - email: Option, + #[serde(default)] + email: EmailField, discord: Option, } @@ -43,13 +66,25 @@ impl Person { } } - pub(crate) fn email(&self) -> Option<&str> { - self.email.as_ref().map(|e| e.as_str()) + pub(crate) fn email(&self) -> Email { + match &self.email { + EmailField::Disabled(false) => Email::Disabled, + EmailField::Disabled(true) => Email::Missing, + EmailField::Explicit(None) => Email::Missing, + EmailField::Explicit(Some(addr)) => Email::Present(addr.as_str()), + } } pub(crate) fn discord(&self) -> Option<&str> { self.discord.as_ref().map(|e| e.as_str()) } + + pub(crate) fn validate(&self) -> Result<(), Error> { + if let EmailField::Disabled(true) = &self.email { + bail!("`email = true` is not valid (for person {})", self.github); + } + Ok(()) + } } #[derive(serde_derive::Deserialize, Debug)] @@ -137,7 +172,7 @@ impl Team { let member = data .person(member) .ok_or_else(|| err_msg(format!("member {} is missing", member)))?; - if let Some(email) = member.email() { + if let Email::Present(email) = member.email() { list.emails.push(email.to_string()); } } diff --git a/src/validate.rs b/src/validate.rs index 3c2d6c7..c9c66a5 100644 --- a/src/validate.rs +++ b/src/validate.rs @@ -1,5 +1,6 @@ use crate::data::Data; use failure::{bail, Error}; +use crate::schema::Email; use regex::Regex; use std::collections::HashSet; @@ -107,7 +108,7 @@ fn validate_list_email_addresses(data: &Data, errors: &mut Vec) { } wrapper(team.members(data)?.iter(), errors, |member, _| { let member = data.person(member).unwrap(); - if member.email().is_none() { + if let Email::Missing = member.email() { bail!( "person `{}` is a member of a mailing list but has no email address", member.github() @@ -179,7 +180,7 @@ fn validate_list_addresses(data: &Data, errors: &mut Vec) { /// Ensure people email addresses are correct fn validate_people_addresses(data: &Data, errors: &mut Vec) { wrapper(data.people(), errors, |person, _| { - if let Some(email) = person.email() { + if let Email::Present(email) = person.email() { if !email.contains('@') { bail!("invalid email address of `{}`: {}", person.github(), email); } -- cgit v1.2.3