from typing import Any, List from fastapi import APIRouter, Depends, HTTPException, status, UploadFile, File, Form from sqlalchemy.orm import Session from app import crud, models, schemas from app.api import deps from app.models.transaction import TransactionType from app.models.wallet import WalletType from app.services.file_upload import save_deposit_proof from app.core.email import send_deposit_confirmation from app.core.config import settings router = APIRouter() @router.post("/request", response_model=schemas.Deposit) async def create_deposit_request( *, db: Session = Depends(deps.get_db), current_user: models.User = Depends(deps.get_current_active_verified_user), amount: float = Form(...), transaction_hash: str = Form(...), proof_image: UploadFile = File(...), ) -> Any: """ Create a new deposit request. """ # Validate minimum deposit amount if amount < settings.MIN_DEPOSIT_AMOUNT: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=f"Minimum deposit amount is {settings.MIN_DEPOSIT_AMOUNT} USDT", ) # Save proof image proof_image_path = save_deposit_proof(current_user.id, proof_image) # Create deposit request deposit_in = schemas.DepositCreate( user_id=current_user.id, amount=amount, transaction_hash=transaction_hash, ) deposit = crud.deposit.create(db, obj_in=deposit_in) # Update deposit with proof image path crud.deposit.update(db, db_obj=deposit, obj_in={"proof_image_path": proof_image_path}) return deposit @router.get("/", response_model=List[schemas.Deposit]) def read_deposits( *, db: Session = Depends(deps.get_db), current_user: models.User = Depends(deps.get_current_active_verified_user), skip: int = 0, limit: int = 100, ) -> Any: """ Retrieve user's deposit requests. """ deposits = crud.deposit.get_by_user(db, user_id=current_user.id, skip=skip, limit=limit) return deposits @router.get("/{deposit_id}", response_model=schemas.Deposit) def read_deposit( *, db: Session = Depends(deps.get_db), current_user: models.User = Depends(deps.get_current_active_verified_user), deposit_id: int, ) -> Any: """ Get a specific deposit by ID. """ deposit = crud.deposit.get(db, id=deposit_id) if not deposit: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Deposit not found", ) if deposit.user_id != current_user.id and current_user.role != "admin": raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Access denied", ) return deposit # Admin endpoints @router.get("/admin/pending", response_model=List[schemas.Deposit]) def read_pending_deposits( *, db: Session = Depends(deps.get_db), current_user: models.User = Depends(deps.get_current_admin), skip: int = 0, limit: int = 100, ) -> Any: """ Retrieve all pending deposit requests (admin only). """ deposits = crud.deposit.get_all_pending(db, skip=skip, limit=limit) return deposits @router.put("/admin/{deposit_id}/approve", response_model=schemas.Deposit) def approve_deposit_request( *, db: Session = Depends(deps.get_db), current_user: models.User = Depends(deps.get_current_admin), deposit_id: int, deposit_data: schemas.DepositApprove, ) -> Any: """ Approve a deposit request (admin only). """ deposit = crud.deposit.get(db, id=deposit_id) if not deposit: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Deposit not found", ) if deposit.status != "pending": raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=f"Deposit is already {deposit.status}", ) # Get user's spot wallet spot_wallet = crud.wallet.get_by_user_and_type( db, user_id=deposit.user_id, wallet_type=WalletType.SPOT ) if not spot_wallet: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="User's spot wallet not found", ) # Update wallet balance crud.wallet.update_balance(db, wallet_id=spot_wallet.id, amount=deposit.amount, add=True) # Approve deposit updated_deposit = crud.deposit.approve( db, db_obj=deposit, admin_notes=deposit_data.admin_notes ) # Create transaction record transaction = crud.transaction.create( db, obj_in=schemas.TransactionCreate( user_id=deposit.user_id, wallet_id=spot_wallet.id, amount=deposit.amount, transaction_type=TransactionType.DEPOSIT, description=f"Deposit - {deposit.transaction_hash}", deposit_id=deposit.id, ), ) # Send confirmation email to user user = crud.user.get(db, id=deposit.user_id) if user: send_deposit_confirmation( email_to=user.email, amount=deposit.amount, transaction_id=str(transaction.id), ) return updated_deposit @router.put("/admin/{deposit_id}/reject", response_model=schemas.Deposit) def reject_deposit_request( *, db: Session = Depends(deps.get_db), current_user: models.User = Depends(deps.get_current_admin), deposit_id: int, deposit_data: schemas.DepositReject, ) -> Any: """ Reject a deposit request (admin only). """ deposit = crud.deposit.get(db, id=deposit_id) if not deposit: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Deposit not found", ) if deposit.status != "pending": raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=f"Deposit is already {deposit.status}", ) # Reject deposit updated_deposit = crud.deposit.reject( db, db_obj=deposit, admin_notes=deposit_data.admin_notes ) return updated_deposit