96 lines
3.7 KiB
Python
96 lines
3.7 KiB
Python
from datetime import datetime
|
||
from uuid import uuid4
|
||
from fastapi import HTTPException
|
||
from app.db.database import db
|
||
|
||
player_inventory_collection = db.player_inventory
|
||
marketplace_operations_collection = db.marketplace_operations
|
||
|
||
def _serialize_mongodb_doc(doc):
|
||
"""Преобразует MongoDB документ для JSON сериализации"""
|
||
if doc is None:
|
||
return None
|
||
|
||
# Добавить проверку на список
|
||
if isinstance(doc, list):
|
||
return [_serialize_mongodb_doc(item) for item in doc]
|
||
|
||
result = {}
|
||
for key, value in doc.items():
|
||
# Обработка ObjectId
|
||
if key == "_id":
|
||
result["_id"] = str(value)
|
||
continue
|
||
|
||
# Обработка ISODate
|
||
if isinstance(value, datetime):
|
||
result[key] = value.isoformat()
|
||
# Обработка вложенных словарей
|
||
elif isinstance(value, dict):
|
||
if "$date" in value:
|
||
# Это ISODate
|
||
result[key] = datetime.fromisoformat(value["$date"].replace("Z", "+00:00")).isoformat()
|
||
else:
|
||
result[key] = _serialize_mongodb_doc(value)
|
||
# Обработка списков
|
||
elif isinstance(value, list):
|
||
result[key] = [_serialize_mongodb_doc(item) if isinstance(item, dict) else item for item in value]
|
||
else:
|
||
result[key] = value
|
||
|
||
return result
|
||
|
||
class InventoryService:
|
||
async def list_items(self, username: str, server_ip: str, page: int = 1, limit: int = 20):
|
||
q = {"username": username, "server_ip": server_ip, "status": {"$in": ["stored", "withdrawing"]}}
|
||
skip = max(page - 1, 0) * limit
|
||
|
||
items = await player_inventory_collection.find(q) \
|
||
.sort("created_at", -1) \
|
||
.skip(skip) \
|
||
.limit(limit) \
|
||
.to_list(length=limit)
|
||
|
||
serialized_items = _serialize_mongodb_doc(items)
|
||
total = await player_inventory_collection.count_documents(q)
|
||
return {"items": serialized_items, "page": page, "limit": limit, "total": total}
|
||
|
||
async def withdraw_item(self, username: str, item_id: str, server_ip: str):
|
||
item = await player_inventory_collection.find_one({"id": item_id})
|
||
if not item:
|
||
raise HTTPException(status_code=404, detail="Item not found")
|
||
|
||
if item["username"] != username:
|
||
raise HTTPException(status_code=403, detail="Not your item")
|
||
|
||
if item["server_ip"] != server_ip:
|
||
raise HTTPException(status_code=400, detail="Wrong server_ip for this item")
|
||
|
||
if item.get("status") != "stored":
|
||
raise HTTPException(status_code=400, detail="Item is not available for withdraw")
|
||
|
||
# создаём операцию выдачи НА СЕРВЕР (тип оставляем case_reward)
|
||
op_id = str(uuid4())
|
||
operation = {
|
||
"id": op_id,
|
||
"type": "case_reward",
|
||
"player_name": username,
|
||
"item_data": item["item_data"],
|
||
"server_ip": server_ip,
|
||
"status": "pending",
|
||
"created_at": datetime.utcnow(),
|
||
|
||
# важно: связка с инвентарём, чтобы confirm мог отметить delivered
|
||
"inventory_item_id": item_id,
|
||
"source": item.get("source"),
|
||
}
|
||
await marketplace_operations_collection.insert_one(operation)
|
||
|
||
# помечаем предмет как withdrawing
|
||
await player_inventory_collection.update_one(
|
||
{"id": item_id},
|
||
{"$set": {"status": "withdrawing", "withdraw_operation_id": op_id}}
|
||
)
|
||
|
||
return {"ok": True, "operation_id": op_id, "item_id": item_id}
|