fix(settings): valida csv_delimiter/decimal_separator/auto_logout_minutes (#23)
PUT /api/settings/ non validava nulla: un csv_delimiter vuoto o di piu' caratteri arrivava intatto nel DB e faceva fallire csv.writer con TypeError dentro close_run (500, run mai chiuso). Aggiunta validazione per chiave nota (csv_delimiter 1 carattere fra , ; TAB |, csv_decimal_separator ',' o '.', auto_logout_minutes vuoto o intero 1-480, company_name/company_logo_path non vuoti) -> 422 sui valori fuori dominio. Chiavi non note passano senza validazione (store generico). Difesa in profondita' in production_export_service._csv_format: un csv_delimiter gia' sporco nel DB (scritto prima di questa validazione) non fa piu' fallire close_run, usa ';' e logga un WARNING. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,7 @@ files that open correctly in their Excel.
|
||||
"""
|
||||
import csv
|
||||
import io
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
@@ -25,10 +26,18 @@ from src.backend.models.orm.setting import SystemSetting
|
||||
from src.backend.models.orm.station import Station
|
||||
from src.backend.models.orm.task import RecipeSubtask
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Written under the upload directory: it is the volume that is already mounted and
|
||||
# backed up, so the files survive a container being replaced.
|
||||
EXPORT_SUBDIR = "statistics"
|
||||
|
||||
# `csv.writer` requires a 1-character delimiter. PUT /api/settings/ validates this
|
||||
# going forward (gitea#23), but a value written before that guard existed must not
|
||||
# be able to make close_run fail: fall back and log instead of raising.
|
||||
_VALID_CSV_DELIMITERS = {",", ";", "\t", "|"}
|
||||
_FALLBACK_CSV_DELIMITER = ";"
|
||||
|
||||
HEADER = [
|
||||
"production_run_id",
|
||||
"station_code",
|
||||
@@ -75,8 +84,17 @@ async def _csv_format(db: AsyncSession) -> tuple[str, str]:
|
||||
)
|
||||
)
|
||||
decimal = decimal_row.scalar_one_or_none()
|
||||
|
||||
delimiter_value = delimiter.setting_value if delimiter else ","
|
||||
if delimiter_value not in _VALID_CSV_DELIMITERS:
|
||||
logger.warning(
|
||||
"csv_delimiter non valido nel DB (%r): uso %r",
|
||||
delimiter_value, _FALLBACK_CSV_DELIMITER,
|
||||
)
|
||||
delimiter_value = _FALLBACK_CSV_DELIMITER
|
||||
|
||||
return (
|
||||
delimiter.setting_value if delimiter else ",",
|
||||
delimiter_value,
|
||||
decimal.setting_value if decimal else ".",
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user