145 lines
5.3 KiB
Python
145 lines
5.3 KiB
Python
from fastapi import Request
|
|
from sqlalchemy import text
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from api.v2.schemas.identities import IdentityResponse, LoginResponse
|
|
from config import API_TOKEN_TTL_DAYS
|
|
from logger import logger
|
|
from utils.referral_codes import encode_partner_code
|
|
|
|
|
|
TOKEN_TTL_HINT = "бессрочно" if API_TOKEN_TTL_DAYS is None else f"{API_TOKEN_TTL_DAYS} дн."
|
|
TELEGRAM_LOGIN_MAX_AGE = 86400
|
|
|
|
|
|
def build_login_response(identity) -> LoginResponse:
|
|
return LoginResponse(
|
|
identity_id=identity.id,
|
|
identity=IdentityResponse.model_validate(identity),
|
|
)
|
|
|
|
_TRUSTED_PROXY_CIDRS: list[str] = []
|
|
|
|
|
|
def _client_ip(request: Request) -> str:
|
|
client_host = (request.client.host if request.client else "") or ""
|
|
forwarded = request.headers.get("x-forwarded-for") or request.headers.get("X-Forwarded-For")
|
|
if not forwarded:
|
|
return client_host
|
|
if not _TRUSTED_PROXY_CIDRS and client_host not in ("127.0.0.1", "::1"):
|
|
return client_host
|
|
return forwarded.split(",")[0].strip() or client_host
|
|
|
|
|
|
async def _resolve_partner_snapshot(session: AsyncSession, billing_user_id: int) -> dict[str, object]:
|
|
partner_feature_enabled = False
|
|
default_percent = 0.0
|
|
try:
|
|
from modules.partner_program import settings as partner_settings
|
|
|
|
partner_feature_enabled = True
|
|
raw_percent = getattr(partner_settings, "PARTNER_BONUS_PERCENTAGES", {}).get(1, 0.0)
|
|
default_percent = float(raw_percent) * 100.0
|
|
except Exception:
|
|
partner_feature_enabled = False
|
|
default_percent = 0.0
|
|
payload: dict[str, object] = {
|
|
"partner_enabled": partner_feature_enabled,
|
|
"partner_code": "",
|
|
"partner_balance": 0.0,
|
|
"partner_percent": default_percent,
|
|
"partner_percent_custom": False,
|
|
"partner_referred_total": 0,
|
|
"partner_referred_paid": 0,
|
|
"partner_payout_method": None,
|
|
}
|
|
try:
|
|
partner_row = (
|
|
await session.execute(
|
|
text(
|
|
"""
|
|
SELECT
|
|
tg_id,
|
|
COALESCE(partner_balance, 0),
|
|
partner_percent,
|
|
COALESCE(partner_percent_custom, false),
|
|
partner_code,
|
|
payout_method
|
|
FROM users
|
|
WHERE id = :user_id
|
|
LIMIT 1
|
|
"""
|
|
),
|
|
{"user_id": int(billing_user_id)},
|
|
)
|
|
).first()
|
|
except Exception:
|
|
partner_row = None
|
|
if partner_row is None:
|
|
return payload
|
|
tg_id = int(partner_row[0]) if partner_row[0] is not None else None
|
|
balance = float(partner_row[1] or 0.0)
|
|
percent_raw = partner_row[2]
|
|
percent_custom = bool(partner_row[3])
|
|
percent_value = float(percent_raw) if (percent_custom and percent_raw is not None) else float(default_percent)
|
|
code = str(partner_row[4] or "").strip()
|
|
if (not code or code.isdigit() or code.startswith("r1_")) and int(billing_user_id) > 0:
|
|
generated_code = encode_partner_code(int(billing_user_id))
|
|
code = generated_code
|
|
try:
|
|
await session.execute(
|
|
text("UPDATE users SET partner_code = :code WHERE id = :id"),
|
|
{"code": generated_code, "id": int(billing_user_id)},
|
|
)
|
|
await session.flush()
|
|
except Exception as e:
|
|
logger.warning("[Auth] Ошибка сохранения partner_code для billing_user_id={}: {}", billing_user_id, e)
|
|
payout_method = str(partner_row[5] or "").strip() or None
|
|
referred_total = 0
|
|
referred_paid = 0
|
|
if tg_id is not None:
|
|
try:
|
|
referred_total = int(
|
|
(
|
|
await session.execute(
|
|
text("SELECT COUNT(*) FROM partners WHERE partner_tg_id = :tg_id"),
|
|
{"tg_id": int(tg_id)},
|
|
)
|
|
).scalar()
|
|
or 0
|
|
)
|
|
except Exception:
|
|
referred_total = 0
|
|
try:
|
|
referred_paid = int(
|
|
(
|
|
await session.execute(
|
|
text(
|
|
"SELECT COUNT(DISTINCT pr.joined_tg_id) "
|
|
"FROM partners pr "
|
|
"WHERE pr.partner_tg_id = :tg_id "
|
|
"AND EXISTS ("
|
|
" SELECT 1 FROM payments pay "
|
|
" WHERE pay.tg_id = pr.joined_tg_id "
|
|
" AND lower(pay.status) = 'success'"
|
|
")"
|
|
),
|
|
{"tg_id": int(tg_id)},
|
|
)
|
|
).scalar()
|
|
or 0
|
|
)
|
|
except Exception:
|
|
referred_paid = 0
|
|
payload.update({
|
|
"partner_enabled": bool(partner_feature_enabled or code or referred_total > 0 or balance > 0),
|
|
"partner_code": code,
|
|
"partner_balance": balance,
|
|
"partner_percent": percent_value,
|
|
"partner_percent_custom": percent_custom,
|
|
"partner_referred_total": referred_total,
|
|
"partner_referred_paid": referred_paid,
|
|
"partner_payout_method": payout_method,
|
|
})
|
|
return payload
|