Spaces:
Running
Running
| # router_wallet.py | |
| from fastapi import APIRouter, Depends, HTTPException, Request | |
| from fastapi.responses import Response | |
| from sqlalchemy.orm import Session | |
| import time | |
| import uuid | |
| import hashlib | |
| import os | |
| from database_sql import get_db | |
| from models_sql import Wallet, Transaction, Ownership | |
| from models import RechargeRequest, WithdrawRequest, PurchaseRequest, TipRequest | |
| import 数据库连接 as json_db | |
| router = APIRouter() | |
| try: | |
| from alipay import AliPay | |
| from alipay.utils import AliPayConfig | |
| alipay = AliPay( | |
| appid=os.environ.get("ALIPAY_APPID", ""), | |
| app_notify_url="https://zhiwei666-comfyui-ranking-api.hf.space/api/wallet/alipay_notify", | |
| app_private_key_string=os.environ.get("ALIPAY_PRIVATE_KEY", "").replace("\\n", "\n"), | |
| alipay_public_key_string=os.environ.get("ALIPAY_PUBLIC_KEY", "").replace("\\n", "\n"), | |
| sign_type="RSA2", | |
| debug=False, | |
| config=AliPayConfig(timeout=15) | |
| ) | |
| except Exception as e: | |
| alipay = None | |
| def calculate_tx_hash(tx_id, account, tx_type, amount, prev_hash): | |
| data = f"{tx_id}{account}{tx_type}{amount}{prev_hash}" | |
| return hashlib.sha256(data.encode()).hexdigest() | |
| async def create_recharge_order(req: RechargeRequest): | |
| if not alipay: | |
| raise HTTPException(status_code=500, detail="支付网关未配置或初始化失败") | |
| order_id = f"PAY_{int(time.time())}_{uuid.uuid4().hex[:6]}" | |
| subject = f"ComfyUI Community Points - {req.account}" | |
| order_string = alipay.api_alipay_trade_precreate( | |
| out_trade_no=order_id, | |
| total_amount=str(req.amount), | |
| subject=subject | |
| ) | |
| qr_code_url = order_string.get("qr_code") | |
| if not qr_code_url: | |
| raise HTTPException(status_code=500, detail="生成支付二维码失败") | |
| return {"status": "success", "order_id": order_id, "qr_code": qr_code_url} | |
| # 🟢 业务流转细节修复:正确解析 application/x-www-form-urlencoded | |
| async def alipay_notify(request: Request, db: Session = Depends(get_db)): | |
| # 强制将表单数据解析为纯字典,防止由于数据类型错误导致验签失败 | |
| form_data = await request.form() | |
| data = dict(form_data.items()) | |
| signature = data.pop("sign", None) | |
| data.pop("sign_type", None) | |
| if not alipay or not signature or not alipay.verify(data, signature): | |
| return Response(content="fail", media_type="text/plain") | |
| if data.get("trade_status") in ("TRADE_SUCCESS", "TRADE_FINISHED"): | |
| order_id = data.get("out_trade_no") | |
| existing_tx = db.query(Transaction).filter(Transaction.tx_id == order_id).first() | |
| if not existing_tx: | |
| amount = int(float(data.get("total_amount", 0))) | |
| account = data.get("subject", "").split(" - ")[-1] | |
| wallet = db.query(Wallet).filter(Wallet.account == account).with_for_update().first() | |
| if not wallet: | |
| wallet = Wallet(account=account) | |
| db.add(wallet) | |
| wallet.balance += amount | |
| last_tx = db.query(Transaction).filter(Transaction.account == account).order_by(Transaction.created_at.desc()).first() | |
| prev_hash = last_tx.tx_hash if last_tx else "GENESIS_HASH" | |
| tx_hash = calculate_tx_hash(order_id, account, "RECHARGE", amount, prev_hash) | |
| new_tx = Transaction( | |
| tx_id=order_id, account=account, tx_type="RECHARGE", amount=amount, | |
| prev_hash=prev_hash, tx_hash=tx_hash | |
| ) | |
| db.add(new_tx) | |
| db.commit() | |
| return Response(content="success", media_type="text/plain") | |
| async def check_order(order_id: str, db: Session = Depends(get_db)): | |
| tx = db.query(Transaction).filter(Transaction.tx_id == order_id).first() | |
| if tx: | |
| return {"status": "SUCCESS"} | |
| return {"status": "PENDING"} | |
| async def get_wallet(account: str, db: Session = Depends(get_db)): | |
| wallet = db.query(Wallet).filter(Wallet.account == account).first() | |
| if not wallet: | |
| return {"balance": 0, "earn_balance": 0, "tip_balance": 0} | |
| return { | |
| "balance": wallet.balance, | |
| "earn_balance": wallet.earn_balance, | |
| "tip_balance": wallet.tip_balance | |
| } | |
| async def purchase_item(req: PurchaseRequest, db: Session = Depends(get_db)): | |
| items_db = json_db.load_data("items.json", default_data=[]) | |
| item = next((i for i in items_db if i["id"] == req.item_id), None) | |
| if not item: | |
| raise HTTPException(status_code=404, detail="商品不存在") | |
| price = int(item.get("price", 0)) | |
| seller_account = item.get("author") | |
| if price <= 0 or req.account == seller_account: | |
| return {"status": "success", "already_owned": True} | |
| owned = db.query(Ownership).filter(Ownership.account == req.account, Ownership.item_id == req.item_id).first() | |
| if owned: | |
| return {"status": "success", "already_owned": True} | |
| buyer_wallet = db.query(Wallet).filter(Wallet.account == req.account).with_for_update().first() | |
| if not buyer_wallet or buyer_wallet.balance < price: | |
| raise HTTPException(status_code=402, detail="余额不足,请先充值") | |
| seller_wallet = db.query(Wallet).filter(Wallet.account == seller_account).with_for_update().first() | |
| if not seller_wallet: | |
| seller_wallet = Wallet(account=seller_account) | |
| db.add(seller_wallet) | |
| buyer_wallet.balance -= price | |
| seller_wallet.earn_balance += price | |
| new_ownership = Ownership(account=req.account, item_id=req.item_id) | |
| db.add(new_ownership) | |
| tx_id = f"BUY_{int(time.time())}_{uuid.uuid4().hex[:6]}" | |
| last_tx = db.query(Transaction).filter(Transaction.account == req.account).order_by(Transaction.created_at.desc()).first() | |
| prev_hash = last_tx.tx_hash if last_tx else "GENESIS_HASH" | |
| tx_hash = calculate_tx_hash(tx_id, req.account, "PURCHASE", -price, prev_hash) | |
| new_tx = Transaction( | |
| tx_id=tx_id, account=req.account, tx_type="PURCHASE", amount=-price, | |
| target_account=seller_account, prev_hash=prev_hash, tx_hash=tx_hash | |
| ) | |
| db.add(new_tx) | |
| db.commit() | |
| return {"status": "success", "already_owned": False} | |
| async def tip_user(req: TipRequest, db: Session = Depends(get_db)): | |
| if req.amount <= 0: | |
| raise HTTPException(status_code=400, detail="打赏金额必须大于0") | |
| sender_wallet = db.query(Wallet).filter(Wallet.account == req.sender_account).with_for_update().first() | |
| if not sender_wallet or sender_wallet.balance < req.amount: | |
| raise HTTPException(status_code=402, detail="余额不足") | |
| target_wallet = db.query(Wallet).filter(Wallet.account == req.target_account).with_for_update().first() | |
| if not target_wallet: | |
| target_wallet = Wallet(account=req.target_account) | |
| db.add(target_wallet) | |
| sender_wallet.balance -= req.amount | |
| target_wallet.tip_balance += req.amount | |
| tx_id = f"TIP_{int(time.time())}_{uuid.uuid4().hex[:6]}" | |
| last_tx = db.query(Transaction).filter(Transaction.account == req.sender_account).order_by(Transaction.created_at.desc()).first() | |
| prev_hash = last_tx.tx_hash if last_tx else "GENESIS_HASH" | |
| tx_hash = calculate_tx_hash(tx_id, req.sender_account, "TIP", -req.amount, prev_hash) | |
| new_tx = Transaction( | |
| tx_id=tx_id, account=req.sender_account, tx_type="TIP", amount=-req.amount, | |
| target_account=req.target_account, prev_hash=prev_hash, tx_hash=tx_hash | |
| ) | |
| db.add(new_tx) | |
| db.commit() | |
| from notifications import add_notification | |
| display_sender = "匿名用户" if req.is_anonymous else req.sender_account | |
| add_notification(req.target_account, { | |
| "type": "tip", | |
| "from_user": "system", | |
| "target_item_title": "您的主页", | |
| "content": f"🎉 {display_sender} 给您打赏了 {req.amount} 积分!" | |
| }) | |
| return {"status": "success", "balance": sender_wallet.balance} | |
| async def withdraw(req: WithdrawRequest, db: Session = Depends(get_db)): | |
| key = f"{req.account}_withdraw" | |
| code_data = VERIFY_CODES.get(key) | |
| if not code_data or code_data["code"] != req.code or time.time() > code_data["expires"]: | |
| raise HTTPException(status_code=400, detail="验证码无效或已过期") | |
| wallet = db.query(Wallet).filter(Wallet.account == req.account).with_for_update().first() | |
| if not wallet: | |
| raise HTTPException(status_code=400, detail="钱包不存在") | |
| total_withdrawable = wallet.earn_balance + wallet.tip_balance | |
| if req.amount > total_withdrawable: | |
| raise HTTPException(status_code=400, detail="可提现余额不足") | |
| if req.amount <= wallet.earn_balance: | |
| wallet.earn_balance -= req.amount | |
| else: | |
| remaining = req.amount - wallet.earn_balance | |
| wallet.earn_balance = 0 | |
| wallet.tip_balance -= remaining | |
| wallet.frozen_balance += req.amount | |
| tx_id = f"WD_{int(time.time())}_{uuid.uuid4().hex[:6]}" | |
| last_tx = db.query(Transaction).filter(Transaction.account == req.account).order_by(Transaction.created_at.desc()).first() | |
| prev_hash = last_tx.tx_hash if last_tx else "GENESIS_HASH" | |
| tx_hash = calculate_tx_hash(tx_id, req.account, "WITHDRAW", -req.amount, prev_hash) | |
| new_tx = Transaction( | |
| tx_id=tx_id, account=req.account, tx_type="WITHDRAW", amount=-req.amount, | |
| prev_hash=prev_hash, tx_hash=tx_hash | |
| ) | |
| db.add(new_tx) | |
| db.commit() | |
| del VERIFY_CODES[key] | |
| return {"status": "success"} |