feat: enhance error handling and configuration validation
Some checks failed
CI / lint-and-test (push) Failing after 27s

- Added a global exception handler to log unhandled exceptions and return a generic 500 JSON response without exposing details to the client.
- Updated the configuration to validate the `DATABASE_URL` format, ensuring it starts with `sqlite://` or `postgresql://`, and log warnings for invalid formats.
- Introduced safe parsing for numeric environment variables (`HTTP_PORT`, `INIT_DATA_MAX_AGE_SECONDS`) with defaults on invalid values, including logging warnings for out-of-range values.
- Enhanced the duty schedule parser to enforce limits on the number of schedule rows and the length of full names and duty strings, raising appropriate errors when exceeded.
- Updated internationalization messages to include generic error responses for import failures and parsing issues, improving user experience.
- Added unit tests to verify the new error handling and configuration validation behaviors.
This commit is contained in:
2026-03-02 23:36:03 +03:00
parent 43386b15fa
commit 7ffa727832
20 changed files with 451 additions and 70 deletions

View File

@@ -72,7 +72,9 @@ MESSAGES: dict[str, dict[str, str]] = {
"import.send_json": "Send the duty-schedule file (JSON).",
"import.need_json": "File must have .json extension.",
"import.parse_error": "File parse error: {error}",
"import.parse_error_generic": "The file could not be parsed. Check the format and try again.",
"import.import_error": "Import error: {error}",
"import.import_error_generic": "Import failed. Please try again or contact an administrator.",
"import.done": (
"Import done: {users} users, {duties} duties{unavailable}{vacation} "
"({total} events total)."
@@ -88,6 +90,7 @@ MESSAGES: dict[str, dict[str, str]] = {
"api.access_denied": "Access denied",
"dates.bad_format": "Parameters from and to must be in YYYY-MM-DD format",
"dates.from_after_to": "from date must not be after to",
"dates.range_too_large": "Date range is too large. Request a shorter period.",
"contact.show": "Contacts",
"contact.back": "Back",
"current_duty.title": "Current Duty",
@@ -160,7 +163,9 @@ MESSAGES: dict[str, dict[str, str]] = {
"import.send_json": "Отправьте файл в формате duty-schedule (JSON).",
"import.need_json": "Нужен файл с расширением .json",
"import.parse_error": "Ошибка разбора файла: {error}",
"import.parse_error_generic": "Не удалось разобрать файл. Проверьте формат и попробуйте снова.",
"import.import_error": "Ошибка импорта: {error}",
"import.import_error_generic": "Импорт не выполнен. Попробуйте снова или обратитесь к администратору.",
"import.done": "Импорт выполнен: {users} пользователей, {duties} дежурств{unavailable}{vacation} (всего {total} событий).",
"import.done_unavailable": ", {count} недоступностей",
"import.done_vacation": ", {count} отпусков",
@@ -171,6 +176,7 @@ MESSAGES: dict[str, dict[str, str]] = {
"api.access_denied": "Доступ запрещён",
"dates.bad_format": "Параметры from и to должны быть в формате YYYY-MM-DD",
"dates.from_after_to": "Дата from не должна быть позже to",
"dates.range_too_large": "Диапазон дат слишком большой. Запросите более короткий период.",
"contact.show": "Контакты",
"contact.back": "Назад",
"current_duty.title": "Текущее дежурство",