chore: backup warning details

This commit is contained in:
3252a8
2026-05-27 19:08:49 +03:00
parent 75586d8883
commit bce78c4f28
5 changed files with 101 additions and 18 deletions
+2 -6
View File
@@ -699,12 +699,8 @@ async def device_topup_options_route(request: web.Request) -> web.Response:
"currency": settings.DEFAULT_CURRENCY_SYMBOL or "RUB",
"title": f"+{count}",
"subtitle": tariff.name(lang),
"valid_from": _billing_iso_datetime(
(rub_quote or stars_quote).get("valid_from")
),
"valid_until": _billing_iso_datetime(
(rub_quote or stars_quote).get("valid_until")
),
"valid_from": _billing_iso_datetime((rub_quote or stars_quote).get("valid_from")),
"valid_until": _billing_iso_datetime((rub_quote or stars_quote).get("valid_until")),
"proration_ratio": float((rub_quote or stars_quote).get("proration_ratio") or 0),
}
if stars_quote and int(stars_quote.get("price") or 0) > 0:
+10 -6
View File
@@ -182,13 +182,17 @@ def payment_units_for_activation(payment: Any, sale_mode: str) -> Any:
"""Resolve purchased units from a payment record for webhook activation."""
base = sale_mode_base(sale_mode)
if sale_mode_is_traffic(base):
return getattr(payment, "purchased_gb", None) or getattr(
payment, "subscription_duration_months", None
) or 1
return (
getattr(payment, "purchased_gb", None)
or getattr(payment, "subscription_duration_months", None)
or 1
)
if sale_mode_is_hwid_devices(base):
return getattr(payment, "purchased_hwid_devices", None) or getattr(
payment, "subscription_duration_months", None
) or 1
return (
getattr(payment, "purchased_hwid_devices", None)
or getattr(payment, "subscription_duration_months", None)
or 1
)
return getattr(payment, "subscription_duration_months", None) or 1
+41 -5
View File
@@ -55,6 +55,9 @@ BACKUP_RUNTIME_SETTING_KEYS = {
"BACKUP_COMPOSE_SOURCE_DIR",
"BACKUP_COMPOSE_EXCLUDE_DIRS",
}
TELEGRAM_DOCUMENT_CAPTION_LIMIT = 1024
TELEGRAM_WARNING_DETAIL_LIMIT = 6
TELEGRAM_WARNING_LINE_LIMIT = 220
@dataclass
@@ -263,16 +266,26 @@ class BackupWorker:
def _stage_compose_source(self, target_dir: Path, warnings: list[str]) -> int:
source_raw = (self.settings.BACKUP_COMPOSE_SOURCE_DIR or "").strip()
if not source_raw:
warnings.append("Compose source directory is not configured.")
warnings.append(
"Compose source directory is not configured. Set "
"BACKUP_COMPOSE_SOURCE_DIR or mount the compose folder into the backup container."
)
return 0
source_dir = Path(source_raw).expanduser()
if not source_dir.exists() or not source_dir.is_dir():
warnings.append(f"Compose source directory is unavailable: {source_dir}")
warnings.append(
"If manual backup includes compose but scheduled backup does not, recreate "
"the worker service with the compose-source mount. Compose source directory "
f"is unavailable in this container: {source_dir}"
)
return 0
if not any((source_dir / marker).is_file() for marker in COMPOSE_MARKER_FILES):
warnings.append(f"Compose source directory has no compose file marker: {source_dir}")
warnings.append(
"Check that COMPOSE_BACKUP_SOURCE points to the folder with docker-compose.yml. "
f"Compose source directory has no compose file marker: {source_dir}"
)
excluded_dirs = self._compose_excluded_dirs()
files_count = 0
@@ -358,8 +371,31 @@ class BackupWorker:
f"Archive size: {self._human_size(result.size_bytes)}",
]
if result.warnings:
lines.append(f"Warnings: {len(result.warnings)}")
return "\n".join(lines)
lines.append(f"Warnings ({len(result.warnings)}):")
for index, warning in enumerate(
result.warnings[:TELEGRAM_WARNING_DETAIL_LIMIT],
start=1,
):
lines.append(f"{index}. {self._caption_warning(warning)}")
hidden_count = len(result.warnings) - TELEGRAM_WARNING_DETAIL_LIMIT
if hidden_count > 0:
lines.append(f"... and {hidden_count} more warning(s)")
return self._fit_caption(lines)
@staticmethod
def _caption_warning(warning: str) -> str:
text = " ".join(str(warning or "").split())
if len(text) <= TELEGRAM_WARNING_LINE_LIMIT:
return text
return f"{text[: TELEGRAM_WARNING_LINE_LIMIT - 1].rstrip()}..."
@staticmethod
def _fit_caption(lines: list[str]) -> str:
caption = "\n".join(lines)
if len(caption) <= TELEGRAM_DOCUMENT_CAPTION_LIMIT:
return caption
suffix = "\n... caption truncated"
return f"{caption[: TELEGRAM_DOCUMENT_CAPTION_LIMIT - len(suffix)].rstrip()}{suffix}"
@staticmethod
def _human_size(size_bytes: int) -> str: