Fix hot-path endpoints: proper async DB sessions and awaited calls

Convert all money-flow endpoints (api_open_case, api_submit_contract,
api_execute_upgrade, api_sell_item, api_sell_bulk_items,
api_open_multiple_cases, api_open_slot_case, api_open_case_animated,
api_crash_bet, api_crash_cashout, api_get_inventory, api_item_detail,
api_rpu_info) to use AsyncSession + await throughout.

Critical bugfix: rpu.py and achievements.py functions (all async def)
were being called without 'await' and with sync Session objects, which
returned coroutine objects instead of actual data. This made RPU
weight adjustment, achievement tracking, and stat updates non-functional.

Also added AsyncSession to imports.
This commit is contained in:
2026-07-25 13:37:39 +00:00
parent 17da0b6d79
commit 9fed81082f
+173 -145
View File
@@ -29,7 +29,7 @@ from pathlib import Path
import json import json
from pathlib import Path from pathlib import Path
from database import get_db, get_db_executor, get_async_db, AsyncSessionLocal, SessionLocal, User, InventoryItem, CaseOpening, Contract, Upgrade, UpgradeRPU, PromoCode from database import get_db, get_db_executor, get_async_db, AsyncSessionLocal, SessionLocal, AsyncSession, User, InventoryItem, CaseOpening, Contract, Upgrade, UpgradeRPU, PromoCode
from websocket_manager import manager, crash_game from websocket_manager import manager, crash_game
from sqlalchemy import select, func as sa_func, desc from sqlalchemy import select, func as sa_func, desc
from achievements import ( from achievements import (
@@ -890,7 +890,7 @@ def open_case_with_rpu(case_name: str, adjusted_weights: dict = None) -> dict:
async def api_open_case( async def api_open_case(
case_name: str = Form(...), case_name: str = Form(...),
count: int = Form(1), count: int = Form(1),
db: Session = Depends(get_db), db: AsyncSession = Depends(get_async_db),
user: User = Depends(get_current_user) user: User = Depends(get_current_user)
): ):
"""Открытие кейса с проверкой баланса и учетом РПУ""" """Открытие кейса с проверкой баланса и учетом РПУ"""
@@ -916,7 +916,7 @@ async def api_open_case(
_rpu_mod._BATCH_MODE = True _rpu_mod._BATCH_MODE = True
try: try:
# Один раз считаем RPU на всю пачку (кэшируется внутри) # Один раз считаем RPU на всю пачку (кэшируется внутри)
adjusted_weights = get_adjusted_weights(db, user.id) adjusted_weights = await get_adjusted_weights(db, user.id)
results = [] results = []
for _ in range(count): for _ in range(count):
result = open_case_with_rpu(case_name, adjusted_weights) result = open_case_with_rpu(case_name, adjusted_weights)
@@ -975,34 +975,35 @@ async def api_open_case(
# Определяем был ли редкий дроп # Определяем был ли редкий дроп
had_rare = any(r.get("rarity") in ("Covert", "Rare Special Item", "Extraordinary") for r in results) had_rare = any(r.get("rarity") in ("Covert", "Rare Special Item", "Extraordinary") for r in results)
update_rpu_stats(db, user.id, total_price, count, total_received, await update_rpu_stats(db, user.id, total_price, count, total_received,
rarity=results[0]["rarity"] if results else None, is_rare=had_rare) rarity=results[0]["rarity"] if results else None, is_rare=had_rare)
# Проверка достижений # Проверка достижений
unlocked_ach = [] unlocked_ach = []
open_count = db.query(CaseOpening).filter(CaseOpening.user_id == user.id).count() open_count_result = await db.execute(select(sa_func.count(CaseOpening.id)).filter(CaseOpening.user_id == user.id))
unlocked_ach += check_open_cases_achievements(db, user.id) open_count = open_count_result.scalar()
user_rpu = get_user_rpu(db, user.id) unlocked_ach += await check_open_cases_achievements(db, user.id)
user_rpu = await get_user_rpu(db, user.id)
total_spent = user_rpu.total_spent total_spent = user_rpu.total_spent
unlocked_ach += check_spent_achievements(db, user.id, total_spent) unlocked_ach += await check_spent_achievements(db, user.id, total_spent)
for r in results: for r in results:
unlocked_ach += check_rare_item_achievement(db, user.id, r.get("rarity", "")) unlocked_ach += await check_rare_item_achievement(db, user.id, r.get("rarity", ""))
item_data = get_item(r.get("id", 0)) item_data = get_item(r.get("id", 0))
if item_data: if item_data:
unlocked_ach += check_knife_achievement(db, user.id, item_data) unlocked_ach += await check_knife_achievement(db, user.id, item_data)
unlocked_ach += check_inventory_achievements(db, user.id) unlocked_ach += await check_inventory_achievements(db, user.id)
unlocked_ach += check_dildo_achievements(db, user.id) unlocked_ach += await check_dildo_achievements(db, user.id)
unlocked_ach += check_items_unboxed_achievements(db, user.id) unlocked_ach += await check_items_unboxed_achievements(db, user.id)
unlocked_ach += check_rare_item_count_achievements(db, user.id) unlocked_ach += await check_rare_item_count_achievements(db, user.id)
unlocked_ach += check_knife_count_achievements(db, user.id) unlocked_ach += await check_knife_count_achievements(db, user.id)
unlocked_ach += check_balance_achievements(db, user.id) unlocked_ach += await check_balance_achievements(db, user.id)
unlocked_ach += check_achievements_count_achievements(db, user.id) unlocked_ach += await check_achievements_count_achievements(db, user.id)
unlocked_ach += check_midnight_case_achievement(db, user.id) unlocked_ach += await check_midnight_case_achievement(db, user.id)
unlocked_ach += check_exact_cases_achievement(db, user.id, open_count) unlocked_ach += await check_exact_cases_achievement(db, user.id, open_count)
profit = user.balance + total_spent profit = user.balance + total_spent
unlocked_ach += check_total_profit_achievements(db, user.id, profit) unlocked_ach += await check_total_profit_achievements(db, user.id, profit)
# Запись активности — используем ту же db-сессию # Запись активности — используем ту же db-сессию
for r in results: for r in results:
@@ -1029,7 +1030,7 @@ async def api_open_case(
_rpu_mod._batch_cache_clear() _rpu_mod._batch_cache_clear()
# Один большой commit вместо 40+ мелких # Один большой commit вместо 40+ мелких
db.commit() await db.commit()
asyncio.ensure_future(manager.send_personal(user.id, {"type": "inventory_update"})) asyncio.ensure_future(manager.send_personal(user.id, {"type": "inventory_update"}))
asyncio.ensure_future(manager.send_personal(user.id, {"type": "balance_update", "balance": user.balance})) asyncio.ensure_future(manager.send_personal(user.id, {"type": "balance_update", "balance": user.balance}))
@@ -1163,17 +1164,17 @@ async def api_promo_list(
@app.get("/web/api/rpu-info") @app.get("/web/api/rpu-info")
async def api_rpu_info( async def api_rpu_info(
db: Session = Depends(get_db), db: AsyncSession = Depends(get_async_db),
user: User = Depends(get_current_user) user: User = Depends(get_current_user)
): ):
from rpu import get_rpu_v2_info from rpu import get_rpu_v2_info
return get_rpu_v2_info(db, user.id) return await get_rpu_v2_info(db, user.id)
@app.post("/web/api/contracts/submit") @app.post("/web/api/contracts/submit")
async def api_submit_contract( async def api_submit_contract(
inventory_ids: str = Form(...), inventory_ids: str = Form(...),
db: Session = Depends(get_db), db: AsyncSession = Depends(get_async_db),
user: User = Depends(get_current_user) user: User = Depends(get_current_user)
): ):
try: try:
@@ -1189,10 +1190,13 @@ async def api_submit_contract(
all_knives = True all_knives = True
for inv_id in ids: for inv_id in ids:
inv_item = db.query(InventoryItem).filter( result = await db.execute(
InventoryItem.id == inv_id, select(InventoryItem).filter(
InventoryItem.user_id == user.id InventoryItem.id == inv_id,
).first() InventoryItem.user_id == user.id
)
)
inv_item = result.scalar_one_or_none()
if not inv_item: if not inv_item:
return JSONResponse(status_code=400, content={"error": f"Item {inv_id} not found"}) return JSONResponse(status_code=400, content={"error": f"Item {inv_id} not found"})
@@ -1221,8 +1225,8 @@ async def api_submit_contract(
# Крафт дилдоков из ножей # Крафт дилдоков из ножей
if all_knives and len(inventory_items) == 10: if all_knives and len(inventory_items) == 10:
for inv_item in inventory_items: for inv_item in inventory_items:
db.delete(inv_item) await db.delete(inv_item)
db.commit() await db.commit()
dildo_items = get_dildo_items() dildo_items = get_dildo_items()
if not dildo_items: if not dildo_items:
@@ -1285,7 +1289,7 @@ async def api_submit_contract(
result.probability = 0.01 result.probability = 0.01
for inv_item in inventory_items: for inv_item in inventory_items:
db.delete(inv_item) await db.delete(inv_item)
received_item_data = get_item(result.received_item.id) received_item_data = get_item(result.received_item.id)
@@ -1313,15 +1317,15 @@ async def api_submit_contract(
) )
db.add(contract) db.add(contract)
db.commit() await db.commit()
unlocked_ach = check_contracts_achievements(db, user.id) unlocked_ach = await check_contracts_achievements(db, user.id)
unlocked_ach += check_inventory_achievements(db, user.id) unlocked_ach += await check_inventory_achievements(db, user.id)
unlocked_ach += check_balance_achievements(db, user.id) unlocked_ach += await check_balance_achievements(db, user.id)
unlocked_ach += check_dildo_achievements(db, user.id) unlocked_ach += await check_dildo_achievements(db, user.id)
unlocked_ach += check_dildo_contract_achievement(db, user.id) unlocked_ach += await check_dildo_contract_achievement(db, user.id)
unlocked_ach += check_collection_achievements(db, user.id) unlocked_ach += await check_collection_achievements(db, user.id)
unlocked_ach += check_achievements_count_achievements(db, user.id) unlocked_ach += await check_achievements_count_achievements(db, user.id)
act = record_activity_own_session(user.id, user.username, "contract", act = record_activity_own_session(user.id, user.username, "contract",
f"🔄 выполнил(а) контракт и получил(а) {result.received_item.market_hash_name}", f"🔄 выполнил(а) контракт и получил(а) {result.received_item.market_hash_name}",
@@ -1352,14 +1356,17 @@ async def api_submit_contract(
@app.get("/web/api/inventory/items") @app.get("/web/api/inventory/items")
async def api_get_inventory( async def api_get_inventory(
db: Session = Depends(get_db), db: AsyncSession = Depends(get_async_db),
user: User = Depends(get_current_user) user: User = Depends(get_current_user)
): ):
"""Получение предметов инвентаря""" """Получение предметов инвентаря"""
items = db.query(InventoryItem).filter( result = await db.execute(
InventoryItem.user_id == user.id select(InventoryItem).filter(
).order_by(desc(InventoryItem.obtained_at)).all() InventoryItem.user_id == user.id
).order_by(desc(InventoryItem.obtained_at))
)
items = result.scalars().all()
result = [] result = []
for item in items: for item in items:
@@ -1409,19 +1416,25 @@ async def get_item_image(
@app.get("/web/api/inventory/item-detail/{inventory_id}") @app.get("/web/api/inventory/item-detail/{inventory_id}")
async def api_item_detail( async def api_item_detail(
inventory_id: int, inventory_id: int,
db: Session = Depends(get_db), db: AsyncSession = Depends(get_async_db),
user: User = Depends(get_current_user) user: User = Depends(get_current_user)
): ):
"""Детальная информация о предмете с коллекцией""" """Детальная информация о предмете с коллекцией"""
inv_item = db.query(InventoryItem).filter( result = await db.execute(
InventoryItem.id == inventory_id, select(InventoryItem).filter(
InventoryItem.user_id == user.id InventoryItem.id == inventory_id,
).first() InventoryItem.user_id == user.id
)
)
inv_item = result.scalar_one_or_none()
if not inv_item: if not inv_item:
# Also allow viewing if item exists (public profiles) # Also allow viewing if item exists (public profiles)
inv_item = db.query(InventoryItem).filter( result = await db.execute(
InventoryItem.id == inventory_id select(InventoryItem).filter(
).first() InventoryItem.id == inventory_id
)
)
inv_item = result.scalar_one_or_none()
if not inv_item: if not inv_item:
return JSONResponse(status_code=404, content={"error": "Предмет не найден"}) return JSONResponse(status_code=404, content={"error": "Предмет не найден"})
@@ -1471,10 +1484,12 @@ async def api_item_detail(
seen_base[base] = citem seen_base[base] = citem
# Все предметы пользователя — для проверки владения # Все предметы пользователя — для проверки владения
user_items = db.query(InventoryItem.item_id).filter( user_items_result = await db.execute(
InventoryItem.user_id == user.id select(InventoryItem.item_id).filter(
).all() InventoryItem.user_id == user.id
user_item_ids = {iid for (iid,) in user_items} )
)
user_item_ids = {row[0] for row in user_items_result.all()}
# Сортируем по редкости (низшая → высшая) # Сортируем по редкости (низшая → высшая)
sorted_bases = sorted(seen_base.values(), key=lambda x: RARITY_ORDER.get(x.get("rarity", "Unknown"), -1)) sorted_bases = sorted(seen_base.values(), key=lambda x: RARITY_ORDER.get(x.get("rarity", "Unknown"), -1))
@@ -1707,7 +1722,7 @@ async def get_user_balance(
@app.post("/web/api/cases/open/animated") @app.post("/web/api/cases/open/animated")
async def api_open_case_animated( async def api_open_case_animated(
case_name: str = Form(...), case_name: str = Form(...),
db: Session = Depends(get_db), db: AsyncSession = Depends(get_async_db),
user: User = Depends(get_current_user) user: User = Depends(get_current_user)
): ):
"""Открытие кейса с анимацией (возвращает результат)""" """Открытие кейса с анимацией (возвращает результат)"""
@@ -1720,7 +1735,7 @@ async def api_open_case_animated(
"error": f"Недостаточно средств. Нужно {price_per_case:.2f} ₽, у вас {user.balance:.2f}" "error": f"Недостаточно средств. Нужно {price_per_case:.2f} ₽, у вас {user.balance:.2f}"
}) })
adjusted_weights = get_adjusted_weights(db, user.id) adjusted_weights = await get_adjusted_weights(db, user.id)
result = open_case_with_rpu(case_name, adjusted_weights) result = open_case_with_rpu(case_name, adjusted_weights)
if not result: if not result:
@@ -1761,29 +1776,29 @@ async def api_open_case_animated(
user.balance -= price_per_case user.balance -= price_per_case
# Обновляем РПУ # Обновляем РПУ
from rpu import update_rpu_stats await update_rpu_stats(db, user.id, price_per_case, 1,
update_rpu_stats(db, user.id, price_per_case, 1, item_data.get("price_rub", 0),
item_data.get("price_rub", 0), rarity=item_data.get("rarity"),
rarity=item_data.get("rarity"), is_rare=item_data.get("rarity") in ("Covert", "Rare Special Item", "Extraordinary"))
is_rare=item_data.get("rarity") in ("Covert", "Rare Special Item", "Extraordinary"))
db.commit() await db.commit()
# Проверка достижений # Проверка достижений
unlocked_ach = [] unlocked_ach = []
unlocked_ach += check_open_cases_achievements(db, user.id) unlocked_ach += await check_open_cases_achievements(db, user.id)
unlocked_ach += check_spent_achievements(db, user.id, get_user_rpu(db, user.id).total_spent) user_rpu = await get_user_rpu(db, user.id)
unlocked_ach += check_rare_item_achievement(db, user.id, item_data.get("rarity", "")) unlocked_ach += await check_spent_achievements(db, user.id, user_rpu.total_spent)
unlocked_ach += await check_rare_item_achievement(db, user.id, item_data.get("rarity", ""))
item_full = get_item(result["id"]) item_full = get_item(result["id"])
if item_full: if item_full:
unlocked_ach += check_knife_achievement(db, user.id, item_full) unlocked_ach += await check_knife_achievement(db, user.id, item_full)
unlocked_ach += check_inventory_achievements(db, user.id) unlocked_ach += await check_inventory_achievements(db, user.id)
unlocked_ach += check_dildo_achievements(db, user.id) unlocked_ach += await check_dildo_achievements(db, user.id)
unlocked_ach += check_items_unboxed_achievements(db, user.id) unlocked_ach += await check_items_unboxed_achievements(db, user.id)
unlocked_ach += check_rare_item_count_achievements(db, user.id) unlocked_ach += await check_rare_item_count_achievements(db, user.id)
unlocked_ach += check_knife_count_achievements(db, user.id) unlocked_ach += await check_knife_count_achievements(db, user.id)
unlocked_ach += check_balance_achievements(db, user.id) unlocked_ach += await check_balance_achievements(db, user.id)
unlocked_ach += check_achievements_count_achievements(db, user.id) unlocked_ach += await check_achievements_count_achievements(db, user.id)
asyncio.ensure_future(manager.send_personal(user.id, {"type": "inventory_update"})) asyncio.ensure_future(manager.send_personal(user.id, {"type": "inventory_update"}))
asyncio.ensure_future(manager.send_personal(user.id, {"type": "balance_update", "balance": user.balance})) asyncio.ensure_future(manager.send_personal(user.id, {"type": "balance_update", "balance": user.balance}))
@@ -2010,7 +2025,7 @@ def pick_slot_reel(grouped_items: list, adjusted_weights: dict, exclude_groups:
async def api_open_slot_case( async def api_open_slot_case(
case_name: str = Form(...), case_name: str = Form(...),
free_spin: str = Form(""), free_spin: str = Form(""),
db: Session = Depends(get_db), db: AsyncSession = Depends(get_async_db),
user: User = Depends(get_current_user) user: User = Depends(get_current_user)
): ):
"""Слот-машина: 3 барабана, совпадение = приз""" """Слот-машина: 3 барабана, совпадение = приз"""
@@ -2029,7 +2044,7 @@ async def api_open_slot_case(
if not grouped_items or len(grouped_items) < 2: if not grouped_items or len(grouped_items) < 2:
return JSONResponse(status_code=400, content={"error": "В кейсе недостаточно предметов"}) return JSONResponse(status_code=400, content={"error": "В кейсе недостаточно предметов"})
adjusted_weights = get_adjusted_weights(db, user.id) adjusted_weights = await get_adjusted_weights(db, user.id)
# Буст для слотов: чаще выпадают активки # Буст для слотов: чаще выпадают активки
SLOT_RARITY_BOOST = { SLOT_RARITY_BOOST = {
@@ -2276,18 +2291,18 @@ async def api_open_slot_case(
if not is_free: if not is_free:
user.balance -= price_per_case user.balance -= price_per_case
update_rpu_stats(db, user.id, price_per_case, 1) await update_rpu_stats(db, user.id, price_per_case, 1)
# Проверка достижений для слота # Проверка достижений для слота
unlocked_ach = [] unlocked_ach = []
if match: if match:
unlocked_ach += check_slot_match_achievements(db, user.id) unlocked_ach += await check_slot_match_achievements(db, user.id)
unlocked_ach += check_slot_plays_achievements(db, user.id) unlocked_ach += await check_slot_plays_achievements(db, user.id)
unlocked_ach += check_slot_match_count_achievements(db, user.id) unlocked_ach += await check_slot_match_count_achievements(db, user.id)
unlocked_ach += check_balance_achievements(db, user.id) unlocked_ach += await check_balance_achievements(db, user.id)
unlocked_ach += check_achievements_count_achievements(db, user.id) unlocked_ach += await check_achievements_count_achievements(db, user.id)
db.commit() await db.commit()
return JSONResponse({ return JSONResponse({
"success": True, "success": True,
@@ -2309,7 +2324,7 @@ async def api_open_slot_case(
async def api_open_multiple_cases( async def api_open_multiple_cases(
case_name: str = Form(...), case_name: str = Form(...),
count: int = Form(...), count: int = Form(...),
db: Session = Depends(get_db), db: AsyncSession = Depends(get_async_db),
user: User = Depends(get_current_user) user: User = Depends(get_current_user)
): ):
"""Открытие нескольких кейсов с группировкой и РПУ""" """Открытие нескольких кейсов с группировкой и РПУ"""
@@ -2354,7 +2369,7 @@ async def api_open_multiple_cases(
_rpu_mod._BATCH_MODE = True _rpu_mod._BATCH_MODE = True
try: try:
# Один раз считаем RPU на всю пачку (кэшируется внутри) # Один раз считаем RPU на всю пачку (кэшируется внутри)
adjusted_weights = get_adjusted_weights(db, user.id) adjusted_weights = await get_adjusted_weights(db, user.id)
results = [] results = []
for _ in range(count): for _ in range(count):
result = open_case_with_variants_rpu(case_name, adjusted_weights) result = open_case_with_variants_rpu(case_name, adjusted_weights)
@@ -2423,10 +2438,10 @@ async def api_open_multiple_cases(
# Обновляем статистику РПУ # Обновляем статистику РПУ
total_received = sum(r.get("price", 0) for r in results) total_received = sum(r.get("price", 0) for r in results)
had_rare = any(r.get("rarity") in ("Covert", "Rare Special Item", "Extraordinary") for r in results) had_rare = any(r.get("rarity") in ("Covert", "Rare Special Item", "Extraordinary") for r in results)
update_rpu_stats(db, user.id, total_price, count, total_received, await update_rpu_stats(db, user.id, total_price, count, total_received,
rarity=results[0]["rarity"] if results else None, is_rare=had_rare) rarity=results[0]["rarity"] if results else None, is_rare=had_rare)
db.commit() await db.commit()
finally: finally:
_rpu_mod._BATCH_MODE = False _rpu_mod._BATCH_MODE = False
_rpu_mod._batch_cache_clear() _rpu_mod._batch_cache_clear()
@@ -2454,21 +2469,22 @@ async def api_open_multiple_cases(
# Проверка достижений # Проверка достижений
unlocked_ach = [] unlocked_ach = []
unlocked_ach += check_open_cases_achievements(db, user.id) unlocked_ach += await check_open_cases_achievements(db, user.id)
unlocked_ach += check_spent_achievements(db, user.id, get_user_rpu(db, user.id).total_spent) user_rpu = await get_user_rpu(db, user.id)
unlocked_ach += check_inventory_achievements(db, user.id) unlocked_ach += await check_spent_achievements(db, user.id, user_rpu.total_spent)
unlocked_ach += check_dildo_achievements(db, user.id) unlocked_ach += await check_inventory_achievements(db, user.id)
unlocked_ach += check_items_unboxed_achievements(db, user.id) unlocked_ach += await check_dildo_achievements(db, user.id)
unlocked_ach += check_rare_item_count_achievements(db, user.id) unlocked_ach += await check_items_unboxed_achievements(db, user.id)
unlocked_ach += check_knife_count_achievements(db, user.id) unlocked_ach += await check_rare_item_count_achievements(db, user.id)
unlocked_ach += check_balance_achievements(db, user.id) unlocked_ach += await check_knife_count_achievements(db, user.id)
unlocked_ach += check_achievements_count_achievements(db, user.id) unlocked_ach += await check_balance_achievements(db, user.id)
unlocked_ach += await check_achievements_count_achievements(db, user.id)
for r in results: for r in results:
unlocked_ach += check_rare_item_achievement(db, user.id, r.get("rarity", "")) unlocked_ach += await check_rare_item_achievement(db, user.id, r.get("rarity", ""))
item_full = get_item(r.get("id", 0)) item_full = get_item(r.get("id", 0))
if item_full: if item_full:
unlocked_ach += check_knife_achievement(db, user.id, item_full) unlocked_ach += await check_knife_achievement(db, user.id, item_full)
asyncio.ensure_future(manager.send_personal(user.id, {"type": "inventory_update"})) asyncio.ensure_future(manager.send_personal(user.id, {"type": "inventory_update"}))
asyncio.ensure_future(manager.send_personal(user.id, {"type": "balance_update", "balance": user.balance})) asyncio.ensure_future(manager.send_personal(user.id, {"type": "balance_update", "balance": user.balance}))
@@ -2487,15 +2503,18 @@ async def api_open_multiple_cases(
@app.post("/web/api/inventory/sell") @app.post("/web/api/inventory/sell")
async def api_sell_item( async def api_sell_item(
inventory_id: int = Form(...), inventory_id: int = Form(...),
db: Session = Depends(get_db), db: AsyncSession = Depends(get_async_db),
user: User = Depends(get_current_user) user: User = Depends(get_current_user)
): ):
"""Продажа предмета из инвентаря""" """Продажа предмета из инвентаря"""
inv_item = db.query(InventoryItem).filter( result = await db.execute(
InventoryItem.id == inventory_id, select(InventoryItem).filter(
InventoryItem.user_id == user.id InventoryItem.id == inventory_id,
).first() InventoryItem.user_id == user.id
)
)
inv_item = result.scalar_one_or_none()
if not inv_item: if not inv_item:
return JSONResponse(status_code=400, content={"error": "Предмет не найден"}) return JSONResponse(status_code=400, content={"error": "Предмет не найден"})
@@ -2513,8 +2532,8 @@ async def api_sell_item(
user.balance += price user.balance += price
# Удаляем предмет # Удаляем предмет
db.delete(inv_item) await db.delete(inv_item)
db.commit() await db.commit()
asyncio.ensure_future(manager.send_personal(user.id, {"type": "inventory_update"})) asyncio.ensure_future(manager.send_personal(user.id, {"type": "inventory_update"}))
asyncio.ensure_future(manager.send_personal(user.id, {"type": "balance_update", "balance": user.balance})) asyncio.ensure_future(manager.send_personal(user.id, {"type": "balance_update", "balance": user.balance}))
@@ -2531,7 +2550,7 @@ async def api_sell_item(
@app.post("/web/api/inventory/sell/bulk") @app.post("/web/api/inventory/sell/bulk")
async def api_sell_bulk_items( async def api_sell_bulk_items(
inventory_ids: str = Form(...), inventory_ids: str = Form(...),
db: Session = Depends(get_db), db: AsyncSession = Depends(get_async_db),
user: User = Depends(get_current_user) user: User = Depends(get_current_user)
): ):
"""Массовая продажа предметов из инвентаря""" """Массовая продажа предметов из инвентаря"""
@@ -2545,10 +2564,13 @@ async def api_sell_bulk_items(
return JSONResponse(status_code=400, content={"error": "Не выбрано ни одного предмета"}) return JSONResponse(status_code=400, content={"error": "Не выбрано ни одного предмета"})
# Получаем предметы # Получаем предметы
items_to_sell = db.query(InventoryItem).filter( result = await db.execute(
InventoryItem.id.in_(ids), select(InventoryItem).filter(
InventoryItem.user_id == user.id InventoryItem.id.in_(ids),
).all() InventoryItem.user_id == user.id
)
)
items_to_sell = result.scalars().all()
if not items_to_sell: if not items_to_sell:
return JSONResponse(status_code=400, content={"error": "Предметы не найдены"}) return JSONResponse(status_code=400, content={"error": "Предметы не найдены"})
@@ -2569,11 +2591,11 @@ async def api_sell_bulk_items(
sold_count += 1 sold_count += 1
# Удаляем предмет # Удаляем предмет
db.delete(inv_item) await db.delete(inv_item)
# Начисляем деньги # Начисляем деньги
user.balance += total_received user.balance += total_received
db.commit() await db.commit()
asyncio.ensure_future(manager.send_personal(user.id, {"type": "inventory_update"})) asyncio.ensure_future(manager.send_personal(user.id, {"type": "inventory_update"}))
asyncio.ensure_future(manager.send_personal(user.id, {"type": "balance_update", "balance": user.balance})) asyncio.ensure_future(manager.send_personal(user.id, {"type": "balance_update", "balance": user.balance}))
@@ -2764,13 +2786,16 @@ async def api_execute_upgrade(
input_inventory_id: int = Form(...), input_inventory_id: int = Form(...),
target_item_id: int = Form(...), target_item_id: int = Form(...),
quick_mode: bool = Form(False), quick_mode: bool = Form(False),
db: Session = Depends(get_db), db: AsyncSession = Depends(get_async_db),
user: User = Depends(get_current_user) user: User = Depends(get_current_user)
): ):
input_item = db.query(InventoryItem).filter( result = await db.execute(
InventoryItem.id == input_inventory_id, select(InventoryItem).filter(
InventoryItem.user_id == user.id InventoryItem.id == input_inventory_id,
).first() InventoryItem.user_id == user.id
)
)
input_item = result.scalar_one_or_none()
if not input_item: if not input_item:
return JSONResponse(status_code=400, content={"error": "Предмет не найден"}) return JSONResponse(status_code=400, content={"error": "Предмет не найден"})
@@ -2790,7 +2815,7 @@ async def api_execute_upgrade(
}) })
base_probability = calculate_upgrade_probability(input_price, target_price) base_probability = calculate_upgrade_probability(input_price, target_price)
adjusted_probability = get_adjusted_upgrade_probability(db, user.id, base_probability) adjusted_probability = await get_adjusted_upgrade_probability_async(db, user.id, base_probability)
# Бан: колесо падает аккурат на 1-15° после зелёной зоны (как будто был шанс) # Бан: колесо падает аккурат на 1-15° после зелёной зоны (как будто был шанс)
if user.is_banned: if user.is_banned:
@@ -2808,7 +2833,7 @@ async def api_execute_upgrade(
# Сохраняем поля до удаления # Сохраняем поля до удаления
saved_input_name = input_item.market_hash_name saved_input_name = input_item.market_hash_name
saved_input_item_id = input_item.item_id saved_input_item_id = input_item.item_id
db.delete(input_item) await db.delete(input_item)
if success: if success:
item_float = target_data.get("mid_float_used") or generate_item_float(target_data.get("rarity", "Unknown")) item_float = target_data.get("mid_float_used") or generate_item_float(target_data.get("rarity", "Unknown"))
@@ -2845,16 +2870,16 @@ async def api_execute_upgrade(
import rpu as _rpu_mod import rpu as _rpu_mod
_rpu_mod._BATCH_MODE = True _rpu_mod._BATCH_MODE = True
try: try:
update_upgrade_stats(db, user.id, success, input_price) await update_upgrade_stats_async(db, user.id, success, input_price)
unlocked_ach = check_upgrade_achievements(db, user.id) unlocked_ach = await check_upgrade_achievements(db, user.id)
unlocked_ach += check_upgrade_risk_achievements(db, user.id, input_price) unlocked_ach += await check_upgrade_risk_achievements(db, user.id, input_price)
unlocked_ach += check_upgrade_result_achievements(db, user.id, success, base_probability, input_price) unlocked_ach += await check_upgrade_result_achievements(db, user.id, success, base_probability, input_price)
unlocked_ach += check_inventory_achievements(db, user.id) unlocked_ach += await check_inventory_achievements(db, user.id)
unlocked_ach += check_dildo_achievements(db, user.id) unlocked_ach += await check_dildo_achievements(db, user.id)
unlocked_ach += check_balance_achievements(db, user.id) unlocked_ach += await check_balance_achievements(db, user.id)
unlocked_ach += check_collection_achievements(db, user.id) unlocked_ach += await check_collection_achievements(db, user.id)
unlocked_ach += check_achievements_count_achievements(db, user.id) unlocked_ach += await check_achievements_count_achievements(db, user.id)
if success: if success:
prob_pct = round(base_probability, 1) if base_probability > 0 else 0 prob_pct = round(base_probability, 1) if base_probability > 0 else 0
@@ -2877,7 +2902,7 @@ async def api_execute_upgrade(
finally: finally:
_rpu_mod._BATCH_MODE = False _rpu_mod._BATCH_MODE = False
db.commit() await db.commit()
asyncio.ensure_future(manager.send_personal(user.id, {"type": "inventory_update"})) asyncio.ensure_future(manager.send_personal(user.id, {"type": "inventory_update"}))
asyncio.ensure_future(manager.send_personal(user.id, {"type": "balance_update", "balance": user.balance})) asyncio.ensure_future(manager.send_personal(user.id, {"type": "balance_update", "balance": user.balance}))
@@ -3087,7 +3112,7 @@ async def crash_page(
@app.post("/web/api/crash/bet") @app.post("/web/api/crash/bet")
async def api_crash_bet( async def api_crash_bet(
amount: float = Form(...), amount: float = Form(...),
db: Session = Depends(get_db), db: AsyncSession = Depends(get_async_db),
user: User = Depends(get_current_user) user: User = Depends(get_current_user)
): ):
g = crash_game g = crash_game
@@ -3103,14 +3128,17 @@ async def api_crash_bet(
# Проверка достижений # Проверка достижений
from database import ActivityFeed as CrActivity from database import ActivityFeed as CrActivity
crash_count = db.query(CrActivity).filter( crash_count_result = await db.execute(
CrActivity.user_id == user.id, select(sa_func.count(CrActivity.id)).filter(
CrActivity.activity_type == "crash" CrActivity.user_id == user.id,
).count() + 1 CrActivity.activity_type == "crash"
unlocked_ach = check_crash_achievements(db, user.id, crash_count) )
unlocked_ach += check_balance_achievements(db, user.id) )
unlocked_ach += check_achievements_count_achievements(db, user.id) crash_count = crash_count_result.scalar() + 1
db.commit() unlocked_ach = await check_crash_achievements(db, user.id, crash_count)
unlocked_ach += await check_balance_achievements(db, user.id)
unlocked_ach += await check_achievements_count_achievements(db, user.id)
await db.commit()
asyncio.ensure_future(manager.send_personal(user.id, {"type": "balance_update", "balance": user.balance})) asyncio.ensure_future(manager.send_personal(user.id, {"type": "balance_update", "balance": user.balance}))
@@ -3124,7 +3152,7 @@ async def api_crash_bet(
@app.post("/web/api/crash/cashout") @app.post("/web/api/crash/cashout")
async def api_crash_cashout( async def api_crash_cashout(
db: Session = Depends(get_db), db: AsyncSession = Depends(get_async_db),
user: User = Depends(get_current_user) user: User = Depends(get_current_user)
): ):
g = crash_game g = crash_game
@@ -3142,11 +3170,11 @@ async def api_crash_cashout(
user.balance += payout user.balance += payout
# Проверка достижений # Проверка достижений
unlocked_ach = check_crash_cashout_achievements(db, user.id, g.current_multiplier) unlocked_ach = await check_crash_cashout_achievements(db, user.id, g.current_multiplier)
unlocked_ach += check_balance_achievements(db, user.id) unlocked_ach += await check_balance_achievements(db, user.id)
unlocked_ach += check_achievements_count_achievements(db, user.id) unlocked_ach += await check_achievements_count_achievements(db, user.id)
db.commit() await db.commit()
asyncio.ensure_future(manager.send_personal(user.id, {"type": "balance_update", "balance": user.balance})) asyncio.ensure_future(manager.send_personal(user.id, {"type": "balance_update", "balance": user.balance}))