fix: enforce user restrictions in cabinet API and fix poll history crash

- Add restriction_topup check to POST /cabinet/balance/topup
- Add restriction_subscription check to 6 subscription endpoints:
  /renew, /purchase, /purchase-tariff, /traffic, /devices/purchase, /devices (legacy)
- All restricted endpoints return 403 Forbidden
- Fix TypeError in broadcast history when message_text is None (polls)
This commit is contained in:
Fringg
2026-03-01 20:59:06 +03:00
parent 4c72058d4a
commit faba3a8ed6
3 changed files with 45 additions and 1 deletions

View File

@@ -314,6 +314,12 @@ async def create_topup(
db: AsyncSession = Depends(get_cabinet_db),
):
"""Create payment for balance top-up."""
if getattr(user, 'restriction_topup', False):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail='Balance top-up is restricted for this account',
)
# Validate payment method
methods = await get_payment_methods(user=user, db=db)
method = next((m for m in methods if m.id == request.payment_method), None)

View File

@@ -396,6 +396,12 @@ async def renew_subscription(
db: AsyncSession = Depends(get_cabinet_db),
):
"""Renew subscription (pay from balance)."""
if getattr(user, 'restriction_subscription', False):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail='Subscription renewal is restricted for this account',
)
await db.refresh(user, ['subscription'])
if not user.subscription:
@@ -656,6 +662,12 @@ async def purchase_traffic(
db: AsyncSession = Depends(get_cabinet_db),
):
"""Purchase additional traffic."""
if getattr(user, 'restriction_subscription', False):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail='Subscription purchases are restricted for this account',
)
from app.database.crud.subscription import add_subscription_traffic
from app.database.crud.tariff import get_tariff_by_id
from app.utils.pricing_utils import calculate_prorated_price
@@ -922,6 +934,12 @@ async def purchase_devices_legacy(
DEPRECATED: Use /devices/purchase instead for full tariff and discount support.
"""
if getattr(user, 'restriction_subscription', False):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail='Subscription purchases are restricted for this account',
)
await db.refresh(user, ['subscription'])
if not user.subscription:
@@ -1632,6 +1650,12 @@ async def submit_purchase(
db: AsyncSession = Depends(get_cabinet_db),
) -> dict[str, Any]:
"""Submit subscription purchase (deduct from balance, classic mode only)."""
if getattr(user, 'restriction_subscription', False):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail='Subscription purchases are restricted for this account',
)
# This endpoint is for classic mode only, tariffs mode uses /purchase-tariff
if settings.is_tariffs_mode():
raise HTTPException(
@@ -1769,6 +1793,12 @@ async def purchase_tariff(
db: AsyncSession = Depends(get_cabinet_db),
) -> dict[str, Any]:
"""Purchase a tariff (for tariffs mode)."""
if getattr(user, 'restriction_subscription', False):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail='Subscription purchases are restricted for this account',
)
try:
# Check tariffs mode
if not settings.is_tariffs_mode():
@@ -2170,6 +2200,12 @@ async def purchase_devices(
db: AsyncSession = Depends(get_cabinet_db),
):
"""Purchase additional device slots for subscription."""
if getattr(user, 'restriction_subscription', False):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail='Subscription purchases are restricted for this account',
)
try:
await db.refresh(user, ['subscription'])
subscription = user.subscription

View File

@@ -613,7 +613,9 @@ async def show_messages_history(callback: types.CallbackQuery, db_user: User, db
)
message_preview = (
broadcast.message_text[:100] + '...' if len(broadcast.message_text) > 100 else broadcast.message_text
broadcast.message_text[:100] + '...'
if broadcast.message_text and len(broadcast.message_text) > 100
else (broadcast.message_text or '📊 Опрос')
)
import html