Commit 0026ad27 authored by 陈涛's avatar 陈涛

Merge remote-tracking branch 'origin/main'

parents 9f58969b f15fd310
from fastapi import APIRouter
from api import bill, nav, fund, group, node, scheduler, price
from api import bill, nav, fund, group, node, scheduler, price, permission
api_router = APIRouter()
......@@ -10,3 +10,4 @@ api_router.include_router(node.router, prefix="/node", tags=["节点"])
api_router.include_router(group.router, prefix="/group", tags=["用户分组"])
api_router.include_router(price.router, prefix="/price", tags=["报价"])
api_router.include_router(scheduler.router, prefix="/scheduler", tags=["定时任务"])
api_router.include_router(permission.router, prefix="/permission", tags=["权限"])
......@@ -5,11 +5,14 @@ from motor.core import AgnosticCollection
from dependencies import get_current_user, get_fund_collect, get_bill_collect
from model import Response, Page, PageResponse, SortParams, FilterTime
from model.bill import PCFBill, ExchangeBill, AdjustBill, StakingBill
from model.node import BaseNode
from schema.bill import CreatePCFBill, PCFBillType, CreateExchangeBill, CreateAdjustBill, CreateStakingBill, \
UpdatePCFBill, UpdateExchangeBill, UpdateStakingBill, UpdateAdjustBill, AllBillType
from schema.fund import FundStatus
from schema.node import BindNode
from service.beacon import BeaconChaService
from service.bill import update_bill
from service.fund import query_fund_assets, update_fund
from service.fund import query_fund_assets_and_nodes, update_fund
from tools.jwt_tools import User
router = APIRouter()
......@@ -28,8 +31,10 @@ async def create_pcf(
):
delta_volume = create_pcf_bill.volume if create_pcf_bill.bill_type == PCFBillType.sub else -create_pcf_bill.volume
assets, adjust_assets, pending_assets, staking_assets = await query_fund_assets(fund_collect, create_pcf_bill.fund_id, user.id,
FundStatus.active)
assets, adjust_assets, pending_assets, staking_assets, nodes = await query_fund_assets_and_nodes(fund_collect,
create_pcf_bill.fund_id,
user.id,
FundStatus.active)
assets.setdefault(create_pcf_bill.currency, 0)
# 如果是赎回 判断余额是否够
assert assets[create_pcf_bill.currency] + delta_volume >= 0, "余额不足"
......@@ -51,10 +56,10 @@ async def create_exchange(
fund_collect: AgnosticCollection = Depends(get_fund_collect),
bill_collect: AgnosticCollection = Depends(get_bill_collect),
):
assets, adjust_assets, pending_assets, staking_assets = await query_fund_assets(fund_collect,
create_exchange_bill.fund_id,
user.id,
FundStatus.active)
assets, adjust_assets, pending_assets, staking_assets, nodes = await query_fund_assets_and_nodes(fund_collect,
create_exchange_bill.fund_id,
user.id,
FundStatus.active)
assets.setdefault(create_exchange_bill.output_currency, 0)
assets.setdefault(create_exchange_bill.input_currency, 0)
assert assets[
......@@ -83,9 +88,10 @@ async def create_adjust(
fund_collect: AgnosticCollection = Depends(get_fund_collect),
bill_collect: AgnosticCollection = Depends(get_bill_collect),
):
assets, adjust_assets, pending_assets, staking_assets = await query_fund_assets(fund_collect,
create_adjust_bill.fund_id, user.id,
FundStatus.active)
assets, adjust_assets, pending_assets, staking_assets, nodes = await query_fund_assets_and_nodes(fund_collect,
create_adjust_bill.fund_id,
user.id,
FundStatus.active)
adjust_assets.setdefault(create_adjust_bill.currency, 0)
adjust_assets.setdefault('fund_share', 0)
adjust_assets[create_adjust_bill.currency] += create_adjust_bill.volume
......@@ -107,18 +113,30 @@ async def create_staking_api(
create_staking_bill: CreateStakingBill,
user: User = Depends(get_current_user),
bill_collect: AgnosticCollection = Depends(get_bill_collect),
fund_collect: AgnosticCollection = Depends(get_fund_collect)
fund_collect: AgnosticCollection = Depends(get_fund_collect),
beacon_service: BeaconChaService = Depends(BeaconChaService)
):
assets, adjust_assets, pending_assets, staking_assets = await query_fund_assets(fund_collect,
user_id=user.id,
fund_id=create_staking_bill.fund_id,
fund_status=FundStatus.active)
assets, adjust_assets, pending_assets, staking_assets, nodes = await query_fund_assets_and_nodes(fund_collect,
user_id=user.id,
fund_id=create_staking_bill.fund_id,
fund_status=FundStatus.active)
assert assets.get(create_staking_bill.currency, 0) >= create_staking_bill.volume, '余额不足'
assets[create_staking_bill.currency] -= create_staking_bill.volume
# 防止增加的币种没有 设置默认值
pending_assets.setdefault(create_staking_bill.currency, 0)
pending_assets[create_staking_bill.currency] += create_staking_bill.volume
await update_fund(fund_collect, create_staking_bill.fund_id, pending_assets=pending_assets, assets=assets)
bind_node = BindNode(**create_staking_bill.dict())
node_detail = await beacon_service.get_validator(index_or_pubkey=bind_node.pub_key)
db_data = BaseNode(**bind_node.dict(), index=node_detail.validator_index)
# 如果已经质押过该节点 直接添加数量
if bind_node.pub_key in nodes:
nodes[bind_node.pub_key]['volume'] += db_data.volume
else:
nodes[bind_node.pub_key] = db_data.dict()
await update_fund(fund_collect, create_staking_bill.fund_id, pending_assets=pending_assets, assets=assets,
nodes=nodes)
# 添加账目
staking_bill = StakingBill(user_id=user.id, **create_staking_bill.dict())
......
from motor.core import AgnosticCollection
import dependencies
from exception.db import ExistDataError, NotFundError
from model import BaseResponse, Response, PageResponse, Page
from fastapi import APIRouter, Depends, Query
from model.permission import Role, UserInfo
from schema.permission import CreateRole, CreateUserInfo
from schema.beacon import Validator, ValidatorDeposit, ValidatorBlock, ValidatorIncome, Epoch
from service.beacon import BeaconChaService
from tools.jwt_tools import User
router = APIRouter()
# @router.post('/',
# response_model=BaseResponse,
# summary='添加权限',
# description='添加权限')
# async def add_permission(
# permission: CreatePermission,
# # user: User = Depends(dependencies.get_current_user),
# permission_collect: AgnosticCollection = Depends(dependencies.get_permission_collect)
# ):
# data = await permission_collect.find_one({'name': permission.name, 'group': permission.group})
# if not data:
# db_data = Permission(**permission.dict())
# await permission_collect.insert_one(db_data.dict())
# return Response[Permission](data=db_data)
# else:
# raise ExistDataError(message='该分组下已存在此权限')
@router.post('/role',
response_model=BaseResponse,
summary='添加角色',
description='添加角色')
async def add_role(
role: CreateRole,
# user: User = Depends(dependencies.get_current_user),
permission_collect: AgnosticCollection = Depends(dependencies.get_permission_collect)
):
data = await permission_collect.find_one({'name': role.name, 'org_id': role.org_id})
if not data:
db_data = Role(**role.dict())
await permission_collect.insert_one(db_data.dict())
return Response[Role](data=db_data)
else:
raise ExistDataError(message='该机构下已存在此角色')
......@@ -55,6 +55,10 @@ def get_nav_collect(mongodb_manager: AioMongodbManager = Depends(get_mongodb_man
return mongodb_manager.get_client(name='pyfund', db='pyfund', collect='nav')
def get_permission_collect(mongodb_manager: AioMongodbManager = Depends(get_mongodb_manager)) -> AgnosticCollection:
return mongodb_manager.get_client(name='pyfund', db='pyfund', collect='permission')
# 获取redis Client
def get_cmc_price_redis(redis_manager: AioRedisManager = Depends(get_redis_manager)) -> AioRedisManager:
return redis_manager.get_client(name='cmc_price')
......@@ -17,7 +17,7 @@ from exception import MyException
from model import ErrorResponse
from service.beacon import BeaconChaService
from service.price import CMCPrice
from service.scheduler import update_staking_bill_status_task
from service.scheduler import update_staking_node_status_task
from tools.jwt_tools import get_identify_key
from tools.scheduler import create_scheduler
......@@ -86,7 +86,7 @@ async def startup():
)
app.state.scheduler.add_job(
update_staking_bill_status_task,
update_staking_node_status_task,
args=(BeaconChaService(), app.state.mongodb_manager,),
id='update_staking_bill_status',
trigger=interval.IntervalTrigger(minutes=1, timezone=pytz.UTC),
......
from typing import List, Dict
from pydantic import Field
from model import MyBaseModel
class PermissionTable(MyBaseModel):
fund_id: str = Field(..., description='基金id')
data: Dict[str, List[str]] = Field({}, description='权限表')
class Role(MyBaseModel):
name: str = Field(..., description='角色名')
fund_id: str = Field(..., description='基金id')
system: bool = Field(False, description='系统创建')
permissions: Dict[str, List[str]] = Field({}, description='拥有权限')
remark: str = Field(None, description='备注')
class UserInfo(MyBaseModel):
fund_id: str = Field(..., description='基金id')
email: str = Field(..., description='用户中心email')
role: List[str] = Field([], description='角色')
......@@ -58,6 +58,7 @@ class ValidatorIncome(BaseModel):
performancetoday: float = Field(None, title="当日收益")
performancetotal: float = Field(None, title="总收益")
class Epoch(BaseModel):
attestations_count: int = Field(None, title="证明计数")
average_validator_balance: float = Field(None, title="平均节点余额")
......
from typing import List, Dict
from pydantic import Field, BaseModel
class PermissionItem:
def __init__(self, code, label, children):
self.code = code
self.label = label
self.children = children
def dict(self):
return {
"code": self.code,
"label": self.label,
"children": self.children
}
default_permission_table = [
{
"code": 'data_permission',
"label": "数据管理权限",
"children": [
# 基金管理
{
"code": "fund",
"label": '基金管理',
"children": [
{
"code": "query_info",
"label": "查询基金基础信息"
},
{
"code": "update_info",
"label": "更新基金基础信息"
},
{
"code": "query_list",
"label": "查询基金列表"
},
{
"code": "bill_page",
"label": "访问账目页面"
},
]
},
# 质押节点
{
"code": "node",
"label": '质押节点',
"children": [
{
"code": "bind_node",
"label": "绑定节点"
},
{
"code": "untie_node",
"label": "解绑节点"
},
{
"code": "query_node",
"label": "查询节点"
}
]
},
# 账目-申购/赎回
{
"code": "sub_redeem_bill",
"label": '账目-申购/赎回',
"children": [
{
"code": "add",
"label": "添加"
},
{
"code": "delete",
"label": "删除"
},
{
"code": "edit",
"label": "修改"
},
{
"code": "query",
"label": "查询"
},
]
},
# 账目-换币
{
"code": "swap_bill",
"label": '账目-换币',
"children": [
{
"code": "add",
"label": "添加"
},
{
"code": "delete",
"label": "删除"
},
{
"code": "edit",
"label": "修改"
},
{
"code": "query",
"label": "查询"
},
]
},
# 账目-质押
{
"code": "staking_bill",
"label": '账目-质押',
"children": [
{
"code": "add",
"label": "添加"
},
{
"code": "delete",
"label": "删除"
},
{
"code": "edit",
"label": "修改"
},
{
"code": "query",
"label": "查询"
},
]
},
# 账目-调整账户
{
"code": "adjust_bill",
"label": '账目-调整账户',
"children": [
{
"code": "add",
"label": "添加"
},
{
"code": "delete",
"label": "删除"
},
{
"code": "edit",
"label": "修改"
},
{
"code": "query",
"label": "查询"
},
]
},
# 净值管理
{
"code": "nav",
"label": '净值管理',
"children": [
{
"code": "recalculate",
"label": "基金重新计算净值"
},
{
"code": "add",
"label": "新增"
},
{
"code": "delete",
"label": "删除"
},
{
"code": "edit",
"label": "修改"
},
{
"code": "query",
"label": "查询"
},
]
},
]
},
{
"code": 'role_permission',
"label": "角色管理权限",
"children": [
# 角色的管理
{
"code": "role",
"label": '角色管理',
"children": [
{
"code": "add",
"label": "添加"
},
{
"code": "delete",
"label": "删除"
},
{
"code": "edit",
"label": "修改"
},
{
"code": "query",
"label": "查询"
},
]
},
]
},
{
"code": 'member_permission',
"label": "人员管理权限",
"children": [
# 基金经理人员的管理
{
"code": "fund_manager",
"label": '基金经理',
"children": [
{
"code": "add",
"label": "添加"
},
{
"code": "delete",
"label": "删除"
},
{
"code": "edit",
"label": "修改"
},
{
"code": "query",
"label": "查询"
},
]
},
# 基金经理助理
{
"code": "fund_manager_assistant",
"label": '基金经理助理',
"children": [
{
"code": "add",
"label": "添加"
},
{
"code": "delete",
"label": "删除"
},
{
"code": "edit",
"label": "修改"
},
{
"code": "query",
"label": "查询"
},
]
},
]
}
]
default_role_table = [
{
"name": 'admin',
"label": "基金创建人",
"role": ['all']
},
{
"name": 'fund_manager',
"label": "基金经理",
"role": ['all']
},
{
"name": 'fund_manager_assistant',
"label": "基金经理助理",
"role": []
}
]
data = []
for item in default_permission_table:
for i in item['children']:
base_code = i['code']
for x in i['children']:
data.append(f'{base_code}.{x["code"]}')
print(data)
# 接口请求模型 创建
class CreatePermissionTable(BaseModel):
fund_id: str = Field(..., description='基金id')
data: Dict[str, List[str]] = Field(default_permission_table, description='权限表')
class CreateRole(BaseModel):
name: str = Field(..., description='角色名')
fund_id: str = Field(..., description='基金id')
permissions: Dict[str, List[str]] = Field({}, description='拥有权限')
remark: str = Field(None, description='备注')
class CreateUserInfo(BaseModel):
fund_id: str = Field(..., description='基金id')
email: str = Field(..., description='用户中心email')
role: List[str] = Field([], description='角色')
......@@ -5,7 +5,8 @@ from schema.fund import FundStatus
from tools.time_helper import utc_now_timestamp
async def query_fund_assets(fund_collect, fund_id, user_id=None, fund_status=None) -> Tuple[dict, dict, dict, dict]:
async def query_fund_assets_and_nodes(fund_collect, fund_id, user_id=None, fund_status=None) -> Tuple[
dict, dict, dict, dict, dict]:
query = {'id': fund_id}
if user_id:
query.update({"user_id": user_id})
......@@ -14,12 +15,12 @@ async def query_fund_assets(fund_collect, fund_id, user_id=None, fund_status=Non
fund = await fund_collect.find_one(query)
if not fund:
raise NotFundError()
return fund['assets'], fund['adjust_assets'], fund['pending_assets'], fund['staking_assets']
return fund['assets'], fund['adjust_assets'], fund['pending_assets'], fund['staking_assets'], fund['nodes']
# 修改资产
async def update_fund(fund_collect, fund_id, *, assets=None, adjust_assets=None, pending_assets=None,
staking_assets=None, node=None):
staking_assets=None, nodes=None):
"""
更新fund相关信息
:param fund_collect:
......@@ -28,7 +29,7 @@ async def update_fund(fund_collect, fund_id, *, assets=None, adjust_assets=None,
:param adjust_assets: {"ETH":2 }
:param pending_assets: {"ETH":2 }
:param staking_assets: {"ETH":2 }
:param node: # 更新节点aaa 状态 { "nodes.aaa.status": NodeStatus.Finish }
:param nodes: # 更新节点aaa 状态 { "nodes.aaa.status": NodeStatus.Finish }
:return:
"""
query = {'id': fund_id}
......@@ -41,6 +42,6 @@ async def update_fund(fund_collect, fund_id, *, assets=None, adjust_assets=None,
update_data.update({"pending_assets": pending_assets})
if staking_assets:
update_data.update({"staking_assets": staking_assets})
if node:
update_data.update(node)
if nodes:
update_data.update({'nodes': nodes})
await fund_collect.update_one(query, {"$set": update_data})
......@@ -6,7 +6,7 @@ from exception.db import NotFundError
from model.bill import StakingBill
from schema.fund import FundStatus
from schema.node import NodeStatus
from service.fund import query_fund_assets, update_fund
from service.fund import query_fund_assets_and_nodes, update_fund
from service.nav import calculate_nav
from loguru import logger
from pymongo import ReturnDocument
......@@ -69,7 +69,7 @@ async def calculate_nav_task(fund_id=None):
await calculate_nav(fund_id)
async def update_staking_bill_status_task(beacon_service: BeaconChaService, mongodb_manager: AioMongodbManager):
async def update_staking_node_status_task(beacon_service: BeaconChaService, mongodb_manager: AioMongodbManager):
bill_collect = get_bill_collect(mongodb_manager)
data = bill_collect.find({'bill_type': AllBillType.staking, "status": StakingBillStatus.pending})
staking_bill_list = await data.to_list(length=None)
......@@ -95,15 +95,17 @@ async def update_staking_bill_status_task(beacon_service: BeaconChaService, mong
if status == StakingBillStatus.finish:
# 更新fund状态
fund_collect = get_fund_collect(mongodb_manager)
assets, adjust_assets, pending_assets, staking_assets = await query_fund_assets(fund_collect,
bill_item.fund_id,
fund_status=FundStatus.active)
assets, adjust_assets, pending_assets, staking_assets, nodes = await query_fund_assets_and_nodes(
fund_collect,
bill_item.fund_id,
fund_status=FundStatus.active)
staking_assets.setdefault(bill_item.currency, 0)
staking_assets[bill_item.currency] += bill_item.volume
pending_assets[bill_item.currency] -= bill_item.volume
nodes[bill_item.pub_key]['status'] = NodeStatus.active
await update_fund(fund_collect, bill_item.fund_id, pending_assets=pending_assets,
staking_assets=staking_assets,
node={f"nodes.{bill_item.pub_key}.status": NodeStatus.active})
nodes=nodes)
logger.info(f"[更新质押账单状态任务] [已更新] [{bill_item.id}] {status}")
else:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment