Merge pull request #2585 from BEDOLAGA-DEV/dev

Release: dev -> main
This commit is contained in:
Egor
2026-02-10 04:04:30 +03:00
committed by GitHub
3 changed files with 39 additions and 11 deletions

View File

@@ -1,4 +1,5 @@
import logging
import re
from aiogram import Dispatcher, F, types
from aiogram.fsm.context import FSMContext
@@ -11,6 +12,14 @@ from app.utils.decorators import admin_required, error_handler
from app.utils.validators import get_html_help_text, validate_html_tags
def _safe_preview(html_text: str, limit: int = 500) -> str:
"""Создаёт превью текста, безопасно обрезая HTML-теги."""
plain = re.sub(r'<[^>]+>', '', html_text)
if len(plain) <= limit:
return plain
return plain[:limit] + '...'
logger = logging.getLogger(__name__)
@@ -79,7 +88,7 @@ async def start_edit_rules(callback: types.CallbackQuery, db_user: User, state:
try:
current_rules = await get_current_rules_content(db, db_user.language)
preview = current_rules[:500] + ('...' if len(current_rules) > 500 else '')
preview = _safe_preview(current_rules, 500)
text = (
'✏️ <b>Редактирование правил</b>\n\n'
@@ -139,7 +148,7 @@ async def process_rules_edit(message: types.Message, db_user: User, state: FSMCo
if len(preview_text) > 4000:
preview_text = (
'📋 <b>Предварительный просмотр новых правил:</b>\n\n'
f'{new_rules[:500]}...\n\n'
f'{_safe_preview(new_rules, 500)}\n\n'
f'⚠️ <b>Внимание!</b> Новые правила будут показываться всем пользователям.\n\n'
f'Текст правил: {len(new_rules)} символов\n'
f'Сохранить изменения?'

View File

@@ -7,16 +7,19 @@
from __future__ import annotations
from datetime import datetime
from types import SimpleNamespace
from typing import Any
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
from sqlalchemy import select
from sqlalchemy.exc import MissingGreenlet
from sqlalchemy.ext.asyncio import AsyncSession
from app.config import settings
from app.database.crud.user import get_user_by_telegram_id
from app.database.database import get_db
from app.database.database import AsyncSessionLocal, get_db
from app.database.models import Subscription
from app.localization.texts import get_texts
from app.services.subscription_checkout_service import (
has_subscription_checkout_draft,
@@ -46,12 +49,26 @@ class PaymentCommonMixin:
and not getattr(subscription, 'is_trial', False)
and getattr(subscription, 'is_active', False)
)
except MissingGreenlet as error:
logger.warning(
'Не удалось лениво загрузить подписку пользователя %s при построении клавиатуры после пополнения: %s',
getattr(user, 'id', None),
error,
)
except MissingGreenlet:
# user вне сессии — загружаем подписку отдельным запросом
try:
async with AsyncSessionLocal() as session:
result = await session.execute(
select(Subscription.status, Subscription.is_trial, Subscription.end_date)
.where(Subscription.user_id == user.id)
.order_by(Subscription.created_at.desc())
.limit(1)
)
row = result.one_or_none()
if row:
is_active = row.status == 'active' and row.end_date > datetime.utcnow()
has_active_subscription = bool(is_active and not row.is_trial)
except Exception as db_error:
logger.warning(
'Не удалось загрузить подписку пользователя %s из БД: %s',
getattr(user, 'id', None),
db_error,
)
except Exception as error: # pragma: no cover - защитный код
logger.error(
'Ошибка загрузки подписки пользователя %s при построении клавиатуры после пополнения: %s',

View File

@@ -260,7 +260,10 @@ class HeleketPaymentMixin:
invoice_message = metadata.get('invoice_message') or {}
invoice_message_removed = False
if getattr(self, 'bot', None) and invoice_message:
status_normalized = (status or '').lower()
is_final = status_normalized in {'paid', 'paid_over', 'cancel', 'fail', 'system_fail', 'refund_paid'}
if getattr(self, 'bot', None) and invoice_message and is_final:
chat_id = invoice_message.get('chat_id')
message_id = invoice_message.get('message_id')
if chat_id and message_id:
@@ -300,7 +303,6 @@ class HeleketPaymentMixin:
)
return updated_payment
status_normalized = (status or '').lower()
if status_normalized not in {'paid', 'paid_over'}:
logger.info('Heleket платеж %s в статусе %s, зачисление не требуется', updated_payment.uuid, status)
return updated_payment