vpc_user/user_api/user_api.py

252 lines
9.2 KiB
Python

from fastapi import Depends, FastAPI, HTTPException, Query, Body, Request
from contextlib import asynccontextmanager
import asyncio
from statistics import median
from db import *
from call2api import check_user_token, user_in_db, transfer_coins, get_stats, create_invoice, delete_invoice, \
get_invoice
from func import *
#------------------------------------------------------------
# INIT
#------------------------------------------------------------
@asynccontextmanager
async def lifespan(app: FastAPI):
init_engine()
await create_db_and_tables()
yield
app = FastAPI(lifespan=lifespan)
CONFIG = asyncio.run(read())
SYSTEM_API_TOKEN = CONFIG['system_api_token']
#------------------------- END ------------------------------
#------------------------------------------------------------
# APIs (main code)
#------------------------------------------------------------
async def token_check(username, user_token):
result = await check_user_token(SYSTEM_API_TOKEN, username, user_token)
if result == 'OK':
return True
else:
return False
# For SystemAPI ONLY
# IN : token (str), user_token (str)
# OUT: 'OK' / 'Invalid token' (401) / 'Token already exist' (409) / General error (500)
@app.post('/api/register_user_token/')
async def register_user_token_api(
request: Request,
token: str = Body(),
user_token: str = Body(),
session: AsyncSession = Depends(get_session)
):
if await is_rate_limited(request.client.host):
raise HTTPException(status_code=429, detail='Too many requests')
if token != SYSTEM_API_TOKEN:
raise HTTPException(status_code=401, detail='Invalid token')
user_token_db = await user_token_in_db_func(session, user_token)
if user_token_db:
raise HTTPException(status_code=409, detail='Token already exist')
new_user_token = UserToken(token=user_token)
try:
session.add(new_user_token)
await session.commit()
await session.refresh(new_user_token)
return 'OK'
except Exception as e:
await session.rollback()
raise HTTPException(status_code=500, detail=str(e))
# For SystemAPI ONLY
# IN : token (str), user_token (str)
# OUT: 'OK' / 'Invalid token' (401) / 'Token not exist' (404) / General error (500)
@app.post('/api/unregister_user_token/')
async def unregister_user_token_api(
request: Request,
token: str = Body(),
user_token: str = Body(),
session: AsyncSession = Depends(get_session)
):
if await is_rate_limited(request.client.host):
raise HTTPException(status_code=429, detail='Too many requests')
if token != SYSTEM_API_TOKEN:
raise HTTPException(status_code=401, detail='Invalid token')
user_token_db = await user_token_in_db_func(session, user_token)
if not user_token_db:
raise HTTPException(status_code=404, detail='Token not exist')
try:
await session.delete(user_token_db)
await session.commit()
return 'OK'
except Exception as e:
await session.rollback()
raise HTTPException(status_code=500, detail=str(e))
# IN : username (str), user_token (str)
# OUT: {'issue_date': str, 'logs': str} / 'Invalid username or token' (401) / 'Token not exist' (404) / General error (500)
@app.post('/api/get_user_token_info/')
async def get_user_token_info_api(
request: Request,
username: str | None = Body(None),
user_token: str = Body(),
session: AsyncSession = Depends(get_session)
):
if await is_rate_limited(request.client.host):
raise HTTPException(status_code=429, detail='Too many requests')
if not await token_check(username, user_token):
raise HTTPException(status_code=401, detail='Invalid username or token')
user_token_db = await user_token_in_db_func(session, user_token)
if not user_token_db:
raise HTTPException(status_code=404, detail='Token not exist')
# Force data retrieval (DB can not load it properly, because it "lazy")
issue_date = await session.run_sync(lambda sess: user_token_db.issue_date)
logs = await session.run_sync(lambda sess: user_token_db.logs)
return {'issue_date': issue_date, 'logs': logs}
# IN : username (str), user_token (str)
# OUT: {
# "creator_id_type": str,
# "username": str,
# "mine_uuid": str,
# "tg_id": int,
# "balance": float,
# "tokens": "{}",
# "password": "HIDDEN",
# "creator_id": str,
# "mine_name": str,
# "ds_id": int,
# "frozen": "no"/"temporarily"/"forever",
# "last_activity": null,
# } / 'Invalid username or token' (401) / 'User not found' (404) / General error (500)
@app.post('/api/user_in_db/')
async def user_in_db_api(
request: Request,
username: str | None = Body(None),
user_token: str = Body(),
session: AsyncSession = Depends(get_session)
):
if await is_rate_limited(request.client.host):
raise HTTPException(status_code=429, detail='Too many requests')
if not await token_check(username, user_token):
raise HTTPException(status_code=401, detail='Invalid username or token')
await log(session, user_token, f'/user_in_db')
return await user_in_db(token=SYSTEM_API_TOKEN, username=username)
# IN : username (str), user_token (str), dst_username (str), amount (float)
# OUT: 'OK' / 'Invalid username or token' (401) / 'No money' (400) / 'Too low' (400)
# / 'User not found' (404) / 'Frozen temporarily' (401) / 'Frozen forever' (401)
# / General error (500)
@app.post('/api/transfer_coins/')
async def transfer_coins_api(
request: Request,
username: str = Body(),
user_token: str = Body(),
dst_username: str = Body(),
amount: float = Body(),
session: AsyncSession = Depends(get_session)
):
if await is_rate_limited(request.client.host):
raise HTTPException(status_code=429, detail='Too many requests')
if not await token_check(username, user_token):
raise HTTPException(status_code=401, detail='Invalid username or token')
await log(session, user_token, f'/transfer_coins: (dst_username: {dst_username}, amount: {amount})')
return await transfer_coins(token=SYSTEM_API_TOKEN, src_username=username
, dst_username=dst_username, amount=amount)
# IN : username (str), user_token (str)
# OUT: {
# "amount": float,
# "frozen_amount": int,
# "users": int,
# "frozen_users": int,
# "average": float,
# "median": float,
# "min": float,
# "max": float
# } / 'Invalid username or token' (401) / General error (500)
@app.post('/api/get_stats/')
async def get_stats_api(
request: Request,
username: str = Body(),
user_token: str = Body(),
session: AsyncSession = Depends(get_session)
):
if await is_rate_limited(request.client.host):
raise HTTPException(status_code=429, detail='Too many requests')
if not await token_check(username, user_token):
raise HTTPException(status_code=401, detail='Invalid username or token')
await log(session, user_token, f'/get_stats')
return await get_stats(token=SYSTEM_API_TOKEN)
# IN : username (str), user_token (str), amount (float)
# OUT: invoice_id (str) / 'Invalid username or token' (401) / 'Destination user not found' (401)
# / General error (500)
@app.post('/api/create_invoice/')
async def create_invoice_api(
request: Request,
username: str = Body(),
user_token: str = Body(),
amount: float | None = Body(None),
session: AsyncSession = Depends(get_session)
):
if await is_rate_limited(request.client.host):
raise HTTPException(status_code=429, detail='Too many requests')
if not await token_check(username, user_token):
raise HTTPException(status_code=401, detail='Invalid username or token')
await log(session, user_token, f'/create_invoice: (amount: {amount})')
return await create_invoice(token=SYSTEM_API_TOKEN, dst_username=username, amount=amount)
# IN : username (str), user_token (str), invoice_id (str)
# OUT: 'OK' / 'Invalid username or token' (401) / 'Invoice id not found' (404) / General error (500)
@app.post('/api/delete_invoice/')
async def delete_invoice_api(
request: Request,
username: str = Body(),
user_token: str = Body(),
invoice_id: str = Body(),
session: AsyncSession = Depends(get_session)
):
if await is_rate_limited(request.client.host):
raise HTTPException(status_code=429, detail='Too many requests')
if not await token_check(username, user_token):
raise HTTPException(status_code=401, detail='Invalid username or token')
await log(session, user_token, f'/delete_invoice: (id: {invoice_id})')
return await delete_invoice(token=SYSTEM_API_TOKEN, invoice_id=invoice_id)
# IN : username (str), user_token (str), invoice_id (str)
# OUT: {
# "id": str,
# "dst_username": str,
# "amount": null / float,
# "status": false/true
# } / 'Invalid username or token' (401) / 'Invoice id not found' (404) / General error (500)
@app.post('/api/get_invoice/')
async def get_invoice_api(
request: Request,
username: str = Body(),
user_token: str = Body(),
invoice_id: str = Body(),
session: AsyncSession = Depends(get_session)
):
if await is_rate_limited(request.client.host):
raise HTTPException(status_code=429, detail='Too many requests')
if not await token_check(username, user_token):
raise HTTPException(status_code=401, detail='Invalid username or token')
await log(session, user_token, f'/get_invoice: (id: {invoice_id})')
return await get_invoice(token=SYSTEM_API_TOKEN, invoice_id=invoice_id)
#------------------------- END ------------------------------
#------------------------------------------------------------
# START
#------------------------------------------------------------
if __name__ == '__main__':
import uvicorn
uvicorn.run(app, host='0.0.0.0', port=8010)
#------------------------- END ------------------------------