Fixed opening hours validation accepting input the server cannot parse. Fixes #3
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+53
-6
@@ -331,26 +331,36 @@ impl TryFrom<&str> for DayHour {
|
||||
}
|
||||
}
|
||||
|
||||
fn hours_error(code: &'static str, message: &'static str) -> ValidationError {
|
||||
let mut err = ValidationError::new(code);
|
||||
err.message = Some(message.into());
|
||||
err
|
||||
}
|
||||
|
||||
fn validate_hours(value: &WeekHours) -> Result<(), ValidationError> {
|
||||
if value.hours().is_empty() {
|
||||
// Wrong format is already reported by the regex on the field
|
||||
if value.hours().is_empty() || !RE_HOURS.is_match(value.hours()) {
|
||||
return Ok(())
|
||||
}
|
||||
if let Ok(h) = DayHours::try_new(value.hours()) {
|
||||
for hr in h.hours() {
|
||||
if hr.from() >= hr.to() { return Err(ValidationError::new("TO_BEFORE_FROM")) }
|
||||
if hr.from() >= hr.to() {
|
||||
return Err(hours_error("TO_BEFORE_FROM", "Time 'to' must be after time 'from'"))
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Ok(())
|
||||
Err(hours_error("HOURS_FORMAT", "Hours must be in HH:MM - HH:MM format"))
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref RE_HOURS: Regex = Regex::new(r"^$|(^\d{2}:\d{2} ?- ?\d{2}:\d{2} ?(\(\d+\))?,? ?)+").unwrap();
|
||||
static ref RE_HOURS: Regex = Regex::new(
|
||||
r"^$|^\d{2}:\d{2} ?- ?\d{2}:\d{2}( ?\(\d+\))?( ?, ?\d{2}:\d{2} ?- ?\d{2}:\d{2}( ?\(\d+\))?)*$").unwrap();
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, Validate)]
|
||||
#[validate(schema(function = "validate_hours", message = "Time 'to' must be after time 'from'"))]
|
||||
#[validate(schema(function = "validate_hours"))]
|
||||
pub struct WeekHours {
|
||||
day: Weekday,
|
||||
#[validate(regex(path = "RE_HOURS", message = "Hours must be in HH:MM - HH:MM format"))]
|
||||
@@ -948,12 +958,49 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn week_hours_rejects_wrong_format() {
|
||||
for input in ["8-12", "8:00 - 12:00", "morning", "08.00 - 12.00"] {
|
||||
for input in ["8-12", "8:00 - 12:00", "morning", "08.00 - 12.00",
|
||||
"08:00 - 12:00, nonsense", "08:00 - 12:00 garbage", "08:00 - 12:00,", ", 08:00 - 12:00"] {
|
||||
let hours = WeekHours { day: Weekday::Mon, hours: input.to_string() };
|
||||
assert!(has_field_error(&hours, "hours"), "input: {:?}", input);
|
||||
assert!(!has_field_error(&hours, "__all__"), "input: {:?}", input);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn week_hours_rejects_hours_that_cannot_be_parsed() {
|
||||
// Matches the format, but is not a valid time
|
||||
for input in ["25:00 - 26:00", "08:00 - 12:60", "08:00 - 12:00, 13:00 - 24:00"] {
|
||||
let hours = WeekHours { day: Weekday::Mon, hours: input.to_string() };
|
||||
assert!(has_field_error(&hours, "__all__"), "input: {:?}", input);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn week_hours_validation_agrees_with_parser() {
|
||||
for input in ["", "08:00 - 12:00", "08:00-12:00", "08:00 - 12:00,13:00 - 17:00", "08:00 - 12:00 , 13:00 - 17:00",
|
||||
"08:00 - 12:00, nonsense", "08:00 - 12:00,", "25:00 - 26:00", "08:00 - 12:00 garbage"] {
|
||||
let hours = WeekHours { day: Weekday::Mon, hours: input.to_string() };
|
||||
if hours.validate().is_ok() {
|
||||
assert!(DayHours::try_new(input).is_ok(), "input: {:?}", input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn week_hours_error_messages() {
|
||||
let message = |input: &str| {
|
||||
let hours = WeekHours { day: Weekday::Mon, hours: input.to_string() };
|
||||
let errors = hours.validate().unwrap_err();
|
||||
let all = errors.field_errors().values().flat_map(|e| e.iter()).map(|e| e.message.clone().unwrap().to_string()).collect::<Vec<_>>();
|
||||
assert_eq!(all.len(), 1, "input: {:?}", input);
|
||||
all[0].clone()
|
||||
};
|
||||
|
||||
assert_eq!(message("nonsense"), "Hours must be in HH:MM - HH:MM format");
|
||||
assert_eq!(message("25:00 - 26:00"), "Hours must be in HH:MM - HH:MM format");
|
||||
assert_eq!(message("12:00 - 08:00"), "Time 'to' must be after time 'from'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn week_hours_rejects_to_before_from() {
|
||||
for input in ["12:00 - 08:00", "08:00 - 08:00", "08:00 - 12:00, 17:00 - 13:00"] {
|
||||
|
||||
@@ -103,6 +103,7 @@ lazy_static! {
|
||||
("Date can't be in past", "Datum nesmí být v minulosti"),
|
||||
("Enter your username", "Zadejte své uživatelské jméno"),
|
||||
("Hours must be in HH:MM - HH:MM format", "Hodiny musí být zadány ve tvaru HH:MM - HH:MM"),
|
||||
("Time 'to' must be after time 'from'", "Čas 'do' musí být po čase 'od'"),
|
||||
("Edit profile", "Upravit profil"),
|
||||
("Get emails", "Dostávat e-maily"),
|
||||
("Enter username", "Zadejte uživatelské jméno"),
|
||||
|
||||
Reference in New Issue
Block a user