99 lines
3.0 KiB
Python
99 lines
3.0 KiB
Python
"""Проверка и разбор форм админки (чистые функции — без HTTP и БД)."""
|
||
|
||
from __future__ import annotations
|
||
|
||
from typing import Any
|
||
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
|
||
|
||
WEEKDAY_NAMES: dict[int, str] = {
|
||
1: "Пн",
|
||
2: "Вт",
|
||
3: "Ср",
|
||
4: "Чт",
|
||
5: "Пт",
|
||
6: "Сб",
|
||
7: "Вс",
|
||
}
|
||
|
||
MAX_DESCRIPTION_LENGTH = 200
|
||
|
||
|
||
def format_weekdays(days: list[int] | tuple[int, ...] | None) -> str:
|
||
"""Человеческое описание дней ISO: ``1,3,5`` -> ``Пн, Ср, Пт``."""
|
||
if not days:
|
||
return "каждый день"
|
||
return ", ".join(WEEKDAY_NAMES[day] for day in sorted(set(days)) if day in WEEKDAY_NAMES)
|
||
|
||
|
||
def parse_schedule_fields(
|
||
*,
|
||
template_key: str,
|
||
hour: str,
|
||
minute: str,
|
||
weekdays: list[str],
|
||
timezone: str,
|
||
description: str,
|
||
enabled: bool,
|
||
) -> tuple[dict[str, Any] | None, list[str]]:
|
||
"""Собрать данные расписания из полей формы.
|
||
|
||
Возвращает ``(data, errors)``: при ошибках ``data is None`` и заполнен ``errors``.
|
||
"""
|
||
errors: list[str] = []
|
||
|
||
try:
|
||
hour_value = int(hour)
|
||
except (TypeError, ValueError):
|
||
hour_value = -1
|
||
errors.append("Час должен быть числом")
|
||
try:
|
||
minute_value = int(minute)
|
||
except (TypeError, ValueError):
|
||
minute_value = -1
|
||
errors.append("Минуты должны быть числом")
|
||
|
||
if not 0 <= hour_value <= 23 and "Час должен быть числом" not in errors:
|
||
errors.append("Час должен быть от 0 до 23")
|
||
if not 0 <= minute_value <= 59 and "Минуты должны быть числом" not in errors:
|
||
errors.append("Минуты должны быть от 0 до 59")
|
||
|
||
days: list[int] = []
|
||
for raw in weekdays:
|
||
try:
|
||
day = int(raw)
|
||
except (TypeError, ValueError):
|
||
errors.append(f"Некорректный день недели: {raw}")
|
||
continue
|
||
if 1 <= day <= 7:
|
||
days.append(day)
|
||
else:
|
||
errors.append("День недели должен быть от 1 (Пн) до 7 (Вс)")
|
||
|
||
tz_name = (timezone or "").strip() or "Europe/Moscow"
|
||
try:
|
||
ZoneInfo(tz_name)
|
||
except (ZoneInfoNotFoundError, ValueError):
|
||
errors.append(f"Неизвестная таймзона: {tz_name}")
|
||
|
||
if not template_key.strip():
|
||
errors.append("Выберите шаблон сообщения")
|
||
|
||
if len(description) > MAX_DESCRIPTION_LENGTH:
|
||
errors.append(f"Описание длиннее {MAX_DESCRIPTION_LENGTH} символов")
|
||
|
||
if errors:
|
||
return None, errors
|
||
|
||
return (
|
||
{
|
||
"template_key": template_key,
|
||
"hour": hour_value,
|
||
"minute": minute_value,
|
||
"weekdays": sorted(set(days)),
|
||
"timezone": tz_name,
|
||
"enabled": enabled,
|
||
"description": description.strip(),
|
||
},
|
||
[],
|
||
)
|