Update project configuration and codebase

This commit is contained in:
2026-04-12 12:19:53 +07:00
parent 0ed0ad2b92
commit 0ac8ed8d64
25 changed files with 273 additions and 310 deletions

View File

@@ -1,11 +1,10 @@
import urllib.parse
from typing import Optional
from datetime import UTC, datetime, timedelta
from random import choice
from datetime import datetime, timedelta, timezone
import texts
from config import settings
from schemas.subscriptions import SubscriptionDuration, SubscriptionPlan
import texts
QUOTES: list[str] = [
"Верните себе свободный интернет.",
@@ -47,12 +46,16 @@ def fetch_quote() -> str:
def format_bytes(num_bytes: float) -> str:
"""Конвертировать байты в читаемый формат: ГБ / МБ / КБ / Б."""
if num_bytes >= 1_073_741_824: # >= 1 ГБ
return f"{num_bytes / 1_073_741_824:.1f} ГБ"
if num_bytes >= 1_048_576: # >= 1 МБ
return f"{num_bytes / 1_048_576:.1f} МБ"
if num_bytes >= 1_024: # >= 1 КБ
return f"{num_bytes / 1_024:.1f} КБ"
gb_capacity = 1_073_741_824
mb_capacity = 1_048_576
kb_capacity = 1_024
if num_bytes >= gb_capacity: # >= 1 ГБ
return f"{num_bytes / gb_capacity:.1f} ГБ"
if num_bytes >= mb_capacity: # >= 1 МБ
return f"{num_bytes / mb_capacity:.1f} МБ"
if num_bytes >= kb_capacity: # >= 1 КБ
return f"{num_bytes / kb_capacity:.1f} КБ"
return f"{num_bytes:.0f} Б"
@@ -69,7 +72,7 @@ def format_traffic(used: float, limit: int) -> str:
return texts.TRAFFIC_WITH_LIMIT.format(used=used_str, limit=limit_str)
def format_hwid_limit(limit: Optional[int]) -> str:
def format_hwid_limit(limit: int | None) -> str:
"""Форматировать лимит HWID: число или «без ограничений»."""
if limit is None or limit == 0:
return texts.UNLIMITED_HWID
@@ -90,11 +93,11 @@ def format_days_left(expire_at: datetime) -> str:
- «истекает сегодня» — если осталось 0 дней
- «истекла N дн. назад» — если уже истекла
"""
now = datetime.now(tz=timezone.utc)
now = datetime.now(tz=UTC)
# Убедимся что expire_at timezone-aware
if expire_at.tzinfo is None:
expire_at = expire_at.replace(tzinfo=timezone.utc)
expire_at = expire_at.replace(tzinfo=UTC)
delta = expire_at - now
days = delta.days # целое, может быть отрицательным
@@ -118,12 +121,10 @@ def format_status(status: str) -> tuple[str, str]:
"LIMITED": (texts.STATUS_ICON_LIMITED, texts.STATUS_LIMITED),
"ON_HOLD": (texts.STATUS_ICON_UNKNOWN, texts.STATUS_UNKNOWN),
}
return mapping.get(
status.upper(), (texts.STATUS_ICON_UNKNOWN, texts.STATUS_UNKNOWN)
)
return mapping.get(status.upper(), (texts.STATUS_ICON_UNKNOWN, texts.STATUS_UNKNOWN))
def format_username(username: Optional[str]) -> str:
def format_username(username: str | None) -> str:
"""Форматировать username: «@user» или «нет username»."""
if username:
return "@" + username
@@ -151,14 +152,14 @@ def convert_int_to_duration(value: int) -> SubscriptionDuration:
def convert_duration_to_timedelta(duration: SubscriptionDuration) -> timedelta:
MONTH_DELTA = timedelta(days=30)
month_delta = timedelta(days=30)
mapping: dict[str, timedelta] = {
SubscriptionDuration.MONTH.value: MONTH_DELTA,
SubscriptionDuration.THREE_MONTHS.value: MONTH_DELTA * 3,
SubscriptionDuration.SIX_MONTHS.value: MONTH_DELTA * 6,
SubscriptionDuration.YEAR.value: MONTH_DELTA * 12,
SubscriptionDuration.MONTH.value: month_delta,
SubscriptionDuration.THREE_MONTHS.value: month_delta * 3,
SubscriptionDuration.SIX_MONTHS.value: month_delta * 6,
SubscriptionDuration.YEAR.value: month_delta * 12,
}
return mapping.get(duration.value, MONTH_DELTA)
return mapping.get(duration.value, month_delta)
def calculate_price(subscription: SubscriptionPlan):
@@ -172,7 +173,7 @@ def calculate_price(subscription: SubscriptionPlan):
) * convert_duration_to_int(subscription.duration)
def format_subscription_link(link: Optional[str] = None):
def format_subscription_link(link: str | None = None):
return f"<code>{link or '...'}</code>"
@@ -185,7 +186,7 @@ def format_support_subscription(
full_name: str,
user_id: int,
balance: int,
username: Optional[str] = None,
username: str | None = None,
) -> str:
username = format_username(username)
whitelist_description = "ВЫКЛ"
@@ -208,3 +209,7 @@ def format_support_subscription(
def get_subscription_link(short_uuid: str):
return settings.subscription_url + "/" + short_uuid
def build_main_menu_text(link: str) -> str:
return texts.MAIN_MENU.format(quote=fetch_quote(), link=link)