Refactor client API endpoints for DCA dashboard: Update endpoint structure to focus on client-specific functionalities, including dashboard summary, transaction history, and analytics. Enhance code readability with improved formatting and add support for exporting transaction data in CSV format.
This commit is contained in:
parent
edb0b4d05e
commit
32e8f31b82
2 changed files with 131 additions and 65 deletions
14
__init__.py
14
__init__.py
|
|
@ -15,7 +15,9 @@ logger.debug(
|
|||
)
|
||||
|
||||
|
||||
satmachineclient_ext: APIRouter = APIRouter(prefix="/satmachineclient", tags=["DCA Client"])
|
||||
satmachineclient_ext: APIRouter = APIRouter(
|
||||
prefix="/satmachineclient", tags=["DCA Client"]
|
||||
)
|
||||
satmachineclient_ext.include_router(satmachineclient_generic_router)
|
||||
satmachineclient_ext.include_router(satmachineclient_api_router)
|
||||
|
||||
|
|
@ -39,11 +41,15 @@ def satmachineclient_stop():
|
|||
|
||||
def satmachineclient_start():
|
||||
# Start invoice listener task
|
||||
invoice_task = create_permanent_unique_task("ext_satmachineclient", wait_for_paid_invoices)
|
||||
invoice_task = create_permanent_unique_task(
|
||||
"ext_satmachineclient", wait_for_paid_invoices
|
||||
)
|
||||
scheduled_tasks.append(invoice_task)
|
||||
|
||||
|
||||
# Start hourly transaction polling task
|
||||
polling_task = create_permanent_unique_task("ext_satmachineclient_polling", hourly_transaction_polling)
|
||||
polling_task = create_permanent_unique_task(
|
||||
"ext_satmachineclient_polling", hourly_transaction_polling
|
||||
)
|
||||
scheduled_tasks.append(polling_task)
|
||||
|
||||
|
||||
|
|
|
|||
182
views_api.py
182
views_api.py
|
|
@ -1,87 +1,147 @@
|
|||
# Description: This file contains the extensions API endpoints.
|
||||
# Description: Client-focused API endpoints for DCA dashboard
|
||||
|
||||
from http import HTTPStatus
|
||||
from typing import Optional
|
||||
from typing import List, Optional
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from fastapi import APIRouter, Depends, Request
|
||||
from lnbits.core.crud import get_user
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from lnbits.core.models import WalletTypeInfo
|
||||
from lnbits.core.services import create_invoice
|
||||
from lnbits.decorators import require_admin_key
|
||||
from lnbits.decorators import require_invoice_key
|
||||
from starlette.exceptions import HTTPException
|
||||
|
||||
from .crud import (
|
||||
# DCA CRUD operations
|
||||
create_dca_client,
|
||||
get_dca_client,
|
||||
get_all_deposits,
|
||||
get_deposit,
|
||||
get_client_balance_summary,
|
||||
get_client_dashboard_summary,
|
||||
get_client_transactions,
|
||||
get_client_analytics,
|
||||
update_client_dca_settings,
|
||||
get_client_by_user_id,
|
||||
)
|
||||
from .models import (
|
||||
# DCA models
|
||||
CreateDcaClientData,
|
||||
DcaClient,
|
||||
DcaDeposit,
|
||||
ClientBalanceSummary,
|
||||
ClientDashboardSummary,
|
||||
ClientTransaction,
|
||||
ClientAnalytics,
|
||||
UpdateClientSettings,
|
||||
)
|
||||
|
||||
satmachineclient_api_router = APIRouter()
|
||||
|
||||
|
||||
###################################################
|
||||
################ DCA API ENDPOINTS ################
|
||||
############## CLIENT DASHBOARD API ###############
|
||||
###################################################
|
||||
|
||||
# DCA Client Endpoints
|
||||
# Note: Client creation/update
|
||||
@satmachineclient_api_router.get("/api/v1/dashboard/summary")
|
||||
async def api_get_dashboard_summary(
|
||||
wallet: WalletTypeInfo = Depends(require_invoice_key),
|
||||
) -> ClientDashboardSummary:
|
||||
"""Get client dashboard summary metrics"""
|
||||
summary = await get_client_dashboard_summary(wallet.user)
|
||||
if not summary:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.NOT_FOUND,
|
||||
detail="Client data not found"
|
||||
)
|
||||
return summary
|
||||
|
||||
|
||||
@satmachineclient_api_router.post("/api/v1/dca/clients", status_code=HTTPStatus.CREATED)
|
||||
async def api_create_test_dca_client(
|
||||
data: CreateDcaClientData,
|
||||
wallet: WalletTypeInfo = Depends(require_admin_key),
|
||||
) -> DcaClient:
|
||||
return await create_dca_client(data)
|
||||
@satmachineclient_api_router.get("/api/v1/dashboard/transactions")
|
||||
async def api_get_client_transactions(
|
||||
wallet: WalletTypeInfo = Depends(require_invoice_key),
|
||||
limit: int = Query(50, ge=1, le=1000),
|
||||
offset: int = Query(0, ge=0),
|
||||
transaction_type: Optional[str] = Query(None),
|
||||
start_date: Optional[datetime] = Query(None),
|
||||
end_date: Optional[datetime] = Query(None),
|
||||
) -> List[ClientTransaction]:
|
||||
"""Get client's DCA transaction history with filtering"""
|
||||
return await get_client_transactions(
|
||||
wallet.user,
|
||||
limit=limit,
|
||||
offset=offset,
|
||||
transaction_type=transaction_type,
|
||||
start_date=start_date,
|
||||
end_date=end_date
|
||||
)
|
||||
|
||||
|
||||
@satmachineclient_api_router.get("/api/v1/dca/clients/{client_id}/balance")
|
||||
async def api_get_client_balance(
|
||||
client_id: str,
|
||||
wallet: WalletTypeInfo = Depends(require_admin_key),
|
||||
) -> ClientBalanceSummary:
|
||||
"""Get client balance summary"""
|
||||
client = await get_dca_client(client_id)
|
||||
@satmachineclient_api_router.get("/api/v1/dashboard/analytics")
|
||||
async def api_get_client_analytics(
|
||||
wallet: WalletTypeInfo = Depends(require_invoice_key),
|
||||
time_range: str = Query("30d", regex="^(7d|30d|90d|1y|all)$"),
|
||||
) -> ClientAnalytics:
|
||||
"""Get client performance analytics and cost basis data"""
|
||||
analytics = await get_client_analytics(wallet.user, time_range)
|
||||
if not analytics:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.NOT_FOUND,
|
||||
detail="Analytics data not available"
|
||||
)
|
||||
return analytics
|
||||
|
||||
|
||||
@satmachineclient_api_router.put("/api/v1/dashboard/settings")
|
||||
async def api_update_client_settings(
|
||||
settings: UpdateClientSettings,
|
||||
wallet: WalletTypeInfo = Depends(require_invoice_key),
|
||||
) -> dict:
|
||||
"""Update client DCA settings (mode, limits, status)"""
|
||||
client = await get_client_by_user_id(wallet.user)
|
||||
if not client:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.NOT_FOUND, detail="DCA client not found."
|
||||
status_code=HTTPStatus.NOT_FOUND,
|
||||
detail="Client profile not found"
|
||||
)
|
||||
|
||||
return await get_client_balance_summary(client_id)
|
||||
|
||||
|
||||
# DCA Deposit Endpoints
|
||||
|
||||
|
||||
# NOTE: to Claude - modify this so it only gets the deposits for the user! important security
|
||||
@satmachineclient_api_router.get("/api/v1/dca/deposits")
|
||||
async def api_get_deposits(
|
||||
wallet: WalletTypeInfo = Depends(require_admin_key),
|
||||
) -> list[DcaDeposit]:
|
||||
"""Get all deposits"""
|
||||
return await get_all_deposits()
|
||||
|
||||
|
||||
# NOTE: does the client have any need to get sepcific deposits?
|
||||
@satmachineclient_api_router.get("/api/v1/dca/deposits/{deposit_id}")
|
||||
async def api_get_deposit(
|
||||
deposit_id: str,
|
||||
wallet: WalletTypeInfo = Depends(require_admin_key),
|
||||
) -> DcaDeposit:
|
||||
"""Get a specific deposit"""
|
||||
deposit = await get_deposit(deposit_id)
|
||||
if not deposit:
|
||||
|
||||
success = await update_client_dca_settings(client.id, settings)
|
||||
if not success:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.NOT_FOUND, detail="Deposit not found."
|
||||
status_code=HTTPStatus.BAD_REQUEST,
|
||||
detail="Failed to update settings"
|
||||
)
|
||||
return deposit
|
||||
|
||||
return {"message": "Settings updated successfully"}
|
||||
|
||||
|
||||
@satmachineclient_api_router.get("/api/v1/dashboard/export/transactions")
|
||||
async def api_export_transactions(
|
||||
wallet: WalletTypeInfo = Depends(require_invoice_key),
|
||||
format: str = Query("csv", regex="^(csv|json)$"),
|
||||
start_date: Optional[datetime] = Query(None),
|
||||
end_date: Optional[datetime] = Query(None),
|
||||
):
|
||||
"""Export client transaction history"""
|
||||
transactions = await get_client_transactions(
|
||||
wallet.user,
|
||||
limit=10000, # Large limit for export
|
||||
start_date=start_date,
|
||||
end_date=end_date
|
||||
)
|
||||
|
||||
if format == "csv":
|
||||
# Return CSV response
|
||||
from io import StringIO
|
||||
import csv
|
||||
|
||||
output = StringIO()
|
||||
writer = csv.writer(output)
|
||||
writer.writerow(['Date', 'Amount (Sats)', 'Amount (Fiat)', 'Exchange Rate', 'Type', 'Status'])
|
||||
|
||||
for tx in transactions:
|
||||
writer.writerow([
|
||||
tx.created_at.isoformat(),
|
||||
tx.amount_sats,
|
||||
tx.amount_fiat / 100, # Convert centavos to full currency
|
||||
tx.exchange_rate,
|
||||
tx.transaction_type,
|
||||
tx.status
|
||||
])
|
||||
|
||||
from fastapi.responses import StreamingResponse
|
||||
output.seek(0)
|
||||
return StreamingResponse(
|
||||
iter([output.getvalue()]),
|
||||
media_type="text/csv",
|
||||
headers={"Content-Disposition": "attachment; filename=dca_transactions.csv"}
|
||||
)
|
||||
else:
|
||||
return {"transactions": transactions}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue