From 19d76041c0e2299046aae38bb9539f49e63844f6 Mon Sep 17 00:00:00 2001 From: Egor Berezovskiy Date: Fri, 10 Jan 2025 13:50:05 +0100 Subject: [PATCH] editoast: add consist params validation Signed-off-by: Egor Berezovskiy --- editoast/openapi.yaml | 4 +- editoast/src/views/timetable/stdcm/request.rs | 54 +++++++++++++++++-- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/editoast/openapi.yaml b/editoast/openapi.yaml index 8b1d0df6109..fa0968c337f 100644 --- a/editoast/openapi.yaml +++ b/editoast/openapi.yaml @@ -2793,7 +2793,7 @@ paths: max_speed: type: number format: double - description: Maximum speed of the consist in km/h + description: Maximum speed of the consist in m/s nullable: true maximum_departure_delay: type: integer @@ -8977,7 +8977,7 @@ components: max_speed: type: number format: double - description: Maximum speed of the consist in km/h + description: Maximum speed of the consist in m/s nullable: true maximum_departure_delay: type: integer diff --git a/editoast/src/views/timetable/stdcm/request.rs b/editoast/src/views/timetable/stdcm/request.rs index f3c682533e3..9eb8af8d9bb 100644 --- a/editoast/src/views/timetable/stdcm/request.rs +++ b/editoast/src/views/timetable/stdcm/request.rs @@ -9,6 +9,7 @@ use editoast_schemas::train_schedule::PathItem; use editoast_schemas::train_schedule::PathItemLocation; use itertools::Itertools; use serde::Deserialize; +use serde::Deserializer; use serde::Serialize; use utoipa::ToSchema; use validator::Validate; @@ -103,17 +104,62 @@ pub(super) struct Request { #[schema(value_type = Option, example = json!(["5%", "2min/100km"]))] pub(super) margin: Option, /// Total mass of the consist in kg - #[validate(range(exclusive_min = 0.0))] + #[serde(deserialize_with = "total_mass_parse")] pub(super) total_mass: Option, /// Total length of the consist in meters - #[validate(range(exclusive_min = 0.0))] + #[serde(deserialize_with = "total_length_parse")] pub(super) total_length: Option, - /// Maximum speed of the consist in km/h - #[validate(range(exclusive_min = 0.0))] + /// Maximum speed of the consist in m/s + #[serde(deserialize_with = "max_speed_parse")] pub(super) max_speed: Option, pub(super) loading_gauge_type: Option, } +fn range_parse<'de, D>(min: f64, max: f64, de: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let value: Option = Deserialize::deserialize(de)?; + if let Some(val) = value { + if val < min || val > max { + return Err(serde::de::Error::custom(format!( + "Value must be between {} and {}", + min, max + ))); + } + } + Ok(value) +} + +pub fn total_mass_parse<'de, D>(de: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + range_parse(20000.0, 10000000.0, de) +} + +pub fn total_length_parse<'de, D>(de: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + range_parse(9.0, 750.0, de) +} + +pub fn max_speed_parse<'de, D>(de: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let value: Option = Deserialize::deserialize(de)?; + if let Some(max_speed) = value { + if max_speed < 8.33 { + return Err(serde::de::Error::custom( + "Value must be greater than 8.33m/s", + )); + } + } + Ok(value) +} + impl Request { /// Returns the earliest time that has been set on any step pub(super) fn get_earliest_step_time(&self) -> DateTime {