From 8d791c56b120045ce955fc32cd7748317a7e962a Mon Sep 17 00:00:00 2001 From: Arthur Bougeard Date: Tue, 22 Sep 2026 17:35:32 +0200 Subject: [PATCH 1/2] editoast: views: use `ViewError` in fonts view Signed-off-by: Arthur Bougeard --- editoast/openapi.yaml | 58 +++++++++++++++-------------- editoast/src/views/fonts.rs | 21 +++++------ front/public/locales/en/errors.json | 2 +- front/public/locales/fr/errors.json | 2 +- osrd_schemas/osrd_schemas/models.py | 16 -------- 5 files changed, 43 insertions(+), 56 deletions(-) diff --git a/editoast/openapi.yaml b/editoast/openapi.yaml index 685843d90f7..9992a9583af 100644 --- a/editoast/openapi.yaml +++ b/editoast/openapi.yaml @@ -822,7 +822,37 @@ paths: '200': description: Glyphs in PBF format of the font at the requested unicode block '404': - description: Font not found + description: '' + content: + application/json: + schema: + oneOf: + - type: object + description: File '{file}' not found + required: + - type + - status + - message + - context + properties: + context: + type: object + required: + - file + properties: + file: + type: string + message: + type: string + status: + type: integer + format: int32 + enum: + - '404' + type: + type: string + enum: + - editoast:fonts:file_not_found /health: get: responses: @@ -7547,7 +7577,6 @@ components: - $ref: '#/components/schemas/EditoastErrorDatabase' - $ref: '#/components/schemas/EditoastErrorInfraNotFound' - $ref: '#/components/schemas/EditoastErrorInvalidInput' - - $ref: '#/components/schemas/EditoastFontErrorsFileNotFound' - $ref: '#/components/schemas/EditoastGeometryErrorUnexpectedGeometry' - $ref: '#/components/schemas/EditoastGetObjectsErrorsDuplicateIdsProvided' - $ref: '#/components/schemas/EditoastGetObjectsErrorsObjectIdNotFound' @@ -7755,31 +7784,6 @@ components: type: string enum: - editoast:search_journeys:InvalidInput - EditoastFontErrorsFileNotFound: - type: object - required: - - type - - status - - message - properties: - context: - type: object - title: EditoastFontErrorsFileNotFoundContext - required: - - file - properties: - file: - type: string - message: - type: string - status: - type: integer - enum: - - 404 - type: - type: string - enum: - - editoast:fonts:FileNotFound EditoastGeometryErrorUnexpectedGeometry: type: object required: diff --git a/editoast/src/views/fonts.rs b/editoast/src/views/fonts.rs index c29ec1a63f0..e87e1f095f9 100644 --- a/editoast/src/views/fonts.rs +++ b/editoast/src/views/fonts.rs @@ -2,7 +2,7 @@ use axum::extract::Path; use axum::extract::Request; use axum::extract::State; use axum::response::IntoResponse; -use editoast_derive::EditoastError; +use editoast_derive::ViewError; use thiserror::Error; use tower::ServiceExt as _; use tower_http::services::ServeFile; @@ -10,12 +10,11 @@ use tower_http::services::ServeFile; use crate::AppState; use crate::error::Result; -#[derive(Debug, Error, EditoastError)] -#[editoast_error(base_id = "fonts")] -enum FontErrors { - #[error("File '{file}' not found")] - #[editoast_error(status = 404)] - FileNotFound { file: String }, +#[derive(Debug, Error, ViewError)] +#[error("File '{file}' not found")] +#[view_error(status = NOT_FOUND, context, path = fonts::file_not_found)] +pub(in crate::views) struct FileNotFound { + file: String, } /// This endpoint is used by map libre to retrieve the fonts. They are separated by font and unicode block @@ -29,27 +28,27 @@ enum FontErrors { ), responses( (status = 200, description = "Glyphs in PBF format of the font at the requested unicode block"), - (status = 404, description = "Font not found"), + FileNotFound, ), )] pub(in crate::views) async fn fonts( Path((font, file_name)): Path<(String, String)>, State(AppState { config, .. }): State, request: Request, -) -> Result { +) -> Result { let path = config .dynamic_assets_path .join(format!("fonts/glyphs/{font}/{file_name}")); if !path.is_file() { - return Err(FontErrors::FileNotFound { file: file_name }.into()); + return Err(FileNotFound { file: file_name }); } // Avoid path traversal attack by ensuring the path is within the dynamic assets directory let canonical_path = path.canonicalize().unwrap(); let canonical_assets_path = config.dynamic_assets_path.canonicalize().unwrap(); if !canonical_path.starts_with(&canonical_assets_path) { - return Err(FontErrors::FileNotFound { file: file_name }.into()); + return Err(FileNotFound { file: file_name }); } Ok(ServeFile::new(&path).oneshot(request).await) diff --git a/front/public/locales/en/errors.json b/front/public/locales/en/errors.json index c2ec24c724e..4d363b97356 100644 --- a/front/public/locales/en/errors.json +++ b/front/public/locales/en/errors.json @@ -95,7 +95,7 @@ "NotFound": "Electrical Profile Set '{{electrical_profile_set_id}}', could not be found" }, "fonts": { - "FileNotFound": "File for the requested font not found" + "file_not_found": "File for the requested font not found" }, "geometry": { "UnexpectedGeometry": "Expected geometry {{expected}} but got {{actual}}" diff --git a/front/public/locales/fr/errors.json b/front/public/locales/fr/errors.json index a8d8d2335b6..f2449e57eac 100644 --- a/front/public/locales/fr/errors.json +++ b/front/public/locales/fr/errors.json @@ -95,7 +95,7 @@ "NotFound": "Profil électrique '{{electrical_profile_set_id}}' non trouvé" }, "fonts": { - "FileNotFound": "Fichier pour la police de charactère demandée non trouvé" + "file_not_found": "Fichier pour la police de caractères demandée non trouvé" }, "geometry": { "UnexpectedGeometry": "Géometrie {{expected}} attendue mais {{actual}} reçue" diff --git a/osrd_schemas/osrd_schemas/models.py b/osrd_schemas/osrd_schemas/models.py index 207f74c6926..246bb39da01 100644 --- a/osrd_schemas/osrd_schemas/models.py +++ b/osrd_schemas/osrd_schemas/models.py @@ -984,20 +984,6 @@ class EditoastErrorInvalidInput(BaseModel): ) -class EditoastFontErrorsFileNotFoundContext(BaseModel): - file: str - - -class EditoastFontErrorsFileNotFound(BaseModel): - context: Annotated[ - EditoastFontErrorsFileNotFoundContext | None, - Field(title="EditoastFontErrorsFileNotFoundContext"), - ] = None - message: str - status: Literal[404] = 404 - type: Literal["editoast:fonts:FileNotFound"] = "editoast:fonts:FileNotFound" - - class EditoastGeometryErrorUnexpectedGeometryContext(BaseModel): actual: str expected: str @@ -4994,7 +4980,6 @@ class EditoastError( | EditoastErrorDatabase | EditoastErrorInfraNotFound | EditoastErrorInvalidInput - | EditoastFontErrorsFileNotFound | EditoastGeometryErrorUnexpectedGeometry | EditoastGetObjectsErrorsDuplicateIdsProvided | EditoastGetObjectsErrorsObjectIdNotFound @@ -5172,7 +5157,6 @@ class EditoastError( | EditoastErrorDatabase | EditoastErrorInfraNotFound | EditoastErrorInvalidInput - | EditoastFontErrorsFileNotFound | EditoastGeometryErrorUnexpectedGeometry | EditoastGetObjectsErrorsDuplicateIdsProvided | EditoastGetObjectsErrorsObjectIdNotFound From 0a1d6d5e239a87c68e801f8ceeecc7a6b154c015 Mon Sep 17 00:00:00 2001 From: Arthur Bougeard Date: Wed, 23 Sep 2026 17:14:53 +0200 Subject: [PATCH 2/2] editoast: fix translation for document error Signed-off-by: Arthur Bougeard --- front/public/locales/en/errors.json | 6 ++++-- front/public/locales/fr/errors.json | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/front/public/locales/en/errors.json b/front/public/locales/en/errors.json index 4d363b97356..110b8346e2a 100644 --- a/front/public/locales/en/errors.json +++ b/front/public/locales/en/errors.json @@ -83,12 +83,14 @@ "MqClientError": "Core: MQ client error", "UnparsableErrorOutput": "Core returned an error in an unknown format" }, + "database": { + "internal": "Internal error (database)" + }, "delimited_area": { "InvalidLocations": "Some locations are invalid" }, "document": { - "Database": "Internal error (database)", - "NotFound": "Document '{{document_key}}' not found" + "not_found": "Document '{{document_key}}' not found" }, "electrical_profiles": { "Database": "Internal error (database)", diff --git a/front/public/locales/fr/errors.json b/front/public/locales/fr/errors.json index f2449e57eac..db536e5ded4 100644 --- a/front/public/locales/fr/errors.json +++ b/front/public/locales/fr/errors.json @@ -83,12 +83,14 @@ "MqClientError": "Core : erreur du client MQ", "UnparsableErrorOutput": "Core : a renvoyé une erreur dans un format inconnu" }, + "database": { + "internal": "Erreur interne (base de données)" + }, "delimited_area": { "InvalidLocations": "Certaines localisations sont invalides" }, "document": { - "Database": "Erreur interne (base de données)", - "NotFound": "Document '{{document_key}}' non trouvé" + "not_found": "Document '{{document_key}}' non trouvé" }, "electrical_profiles": { "Database": "Erreur interne (base de données)",