This commit is contained in:
wuaho 2021-05-17 18:44:34 +08:00
parent 182799e6f7
commit cc535a46a8
17 changed files with 265 additions and 44 deletions

View File

@ -8,6 +8,7 @@ from .endpoints import report
from .endpoints import authority
from .endpoints import table_struct
from .endpoints import query
from .endpoints import data_auth
api_router = APIRouter()
@ -19,6 +20,7 @@ api_router.include_router(dashboard.router, tags=["看板接口"], prefix='/dash
api_router.include_router(report.router, tags=["报表接口"], prefix='/report')
api_router.include_router(authority.router, tags=["权限管理接口"], prefix='/authority')
api_router.include_router(data_auth.router, tags=["数据权限"], prefix='/data_auth')
api_router.include_router(table_struct.router, tags=["表结构"], prefix='/table_struct')

View File

@ -7,6 +7,7 @@ from core.security import get_password_hash
from db import get_database
from api import deps
from db.ckdb import CKDrive, get_ck_db
from utils import casbin_enforcer
router = APIRouter()
@ -32,6 +33,61 @@ async def api_list(request: Request,
return schemas.Msg(code=0, msg='ok', data=res)
@router.post('/set_data_auth')
async def set_data_auth(request: Request,
data_id: schemas.DataAuthSet,
game: str = Depends(deps.get_game_project),
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""设置用户数据权限"""
await crud.authority.set_data_auth(db, data_id, game=game)
return schemas.Msg(code=0, msg='ok', data=data_id)
@router.get('/get_user_data_auth')
async def get_user_data_auth(request: Request,
game: str = Depends(deps.get_game_project),
db: AsyncIOMotorDatabase = Depends(get_database),
ck: CKDrive = Depends(get_ck_db),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""获取当前用户数据权限"""
data_auth = await crud.authority.get_data_auth(db, username=request.user.name, game=game)
if not data_auth:
values = await ck.distinct(game, 'event', '#event_name')
return schemas.Msg(code=0, msg='ok', data={
'data': values,
'game': game,
'name': '全部事件'
})
data_auth_id = data_auth['data_auth_id']
data = await crud.data_auth.get(data_auth_id)
return schemas.Msg(code=0, msg='ok', data=data)
@router.get('/get_users_data_auth')
async def get_users_data_auth(request: Request,
game: str = Depends(deps.get_game_project),
db: AsyncIOMotorDatabase = Depends(get_database),
ck: CKDrive = Depends(get_ck_db),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""获取当前项目所有用户数据权限"""
# data_auth = await crud.authority.get_data_auth(db, username=request.user.name, game=game)
# if not data_auth:
# values = await ck.distinct(game, 'event', '#event_name')
# return schemas.Msg(code=0, msg='ok', data={
# 'data': values,
# 'game': game,
# 'name': '全部事件'
# })
# data_auth_id = data_auth['data_auth_id']
# data = await crud.data_auth.get(data_auth_id)
return schemas.Msg(code=0, msg='ok')
@router.post("/add_role")
async def add_role(request: Request,
data_in: schemas.CasbinRoleCreate,
@ -40,6 +96,10 @@ async def add_role(request: Request,
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""创建角色"""
# 不允许角色名和用户名一样
if await crud.user.get_by_user(db, name=data_in.role_name):
return schemas.Msg(code=-1, msg='请改个名字')
role_dom = game
api_dict = dict()
for r in request.app.routes:
@ -66,6 +126,11 @@ async def add_sys_role(request: Request,
) -> schemas.Msg:
"""创建系统角色"""
api_dict = dict()
# 不允许角色名和用户名一样
if await crud.user.get_by_user(db, name=data_in.role_name):
return schemas.Msg(code=-1, msg='请改个名字')
for r in request.app.routes:
api_dict[r.path] = r.description if hasattr(r, 'description') else r.name
# 角色有的接口权限
@ -89,6 +154,9 @@ async def add_account(request: Request,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
roles = casbin_enforcer.get_all_roles()
if set(data_in.accounts) & set(roles):
return schemas.Msg(code=-1, msg='已存在', data=list(set(data_in.accounts) & set(roles)))
"""创建账号 并设置角色"""
for item in data_in.accounts:
account = schemas.UserCreate(name=item.username, password=settings.DEFAULT_PASSWORD)
@ -103,20 +171,6 @@ async def add_account(request: Request,
return schemas.Msg(code=0, msg='ok')
@router.get("/data_authority")
async def data_authority(request: Request,
db: AsyncIOMotorDatabase = Depends(get_database),
game: str = Depends(deps.get_game_project),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""获取数据权限"""
# todo 这是假数据
data = [{'title': '全部事件', 'check_event_num': 100, 'total_event_num': 100, 'update_time': '2021-05-12 18:49:19'}]
return schemas.Msg(code=0, msg='ok', data=data)
@router.get("/all_role")
async def all_role(request: Request,
db: AsyncIOMotorDatabase = Depends(get_database),
@ -125,18 +179,30 @@ async def all_role(request: Request,
) -> schemas.Msg:
"""获取所有角色"""
app = request.app
api_data = {}
for r in app.routes:
title = r.tags[0] if hasattr(r, 'description') else None
if not title:
continue
api_data[r.path] = {
'api': r.path,
'title': title,
'name': r.description if hasattr(r, 'description') else r.name
}
"""获取域内所有角色"""
roles = await crud.authority.find_many(db, role_name={'$exists': 1}, game=game)
dom_data = [{'role': item['v1'], 'name': item['role_name']} for item in roles]
dom_data = [{'role': item['v1'], 'name': item['role_name'], 'id': str(item['_id'])} for item in roles]
for item in dom_data:
q = await crud.authority.get_role_dom_authority(db, item['role'], game)
q = await crud.authority.get_role_dom_authority(db, item['role'], game, api_data)
item['authority'] = q
# 获取系统角色
roles = await crud.authority.find_many(db, role_name={'$exists': 1}, game='*')
sys_data = [{'role': item['v1'], 'name': item['role_name']} for item in roles]
sys_data = [{'role': item['v1'], 'name': item['role_name'], 'id': str(item['_id'])} for item in roles]
for item in sys_data:
q = await crud.authority.get_role_dom_authority(db, item['role'], dom='*')
q = await crud.authority.get_role_dom_authority(db, item['role'], dom='*', api_data=api_data)
item['authority'] = q
data = {

View File

@ -0,0 +1,39 @@
import pymongo
from fastapi import APIRouter, Depends, Request
from motor.motor_asyncio import AsyncIOMotorDatabase
import crud, schemas
from core.config import settings
from core.security import get_password_hash
from db import get_database
from api import deps
from utils import casbin_enforcer
router = APIRouter()
@router.post('/add_data_auth')
async def add_data_auth(request: Request,
data_id: schemas.DataAuthCreate,
game: str = Depends(deps.get_game_project),
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""创建数据权限"""
await crud.data_auth.create(db, data_id, game)
return schemas.Msg(code=0, msg='ok', data=data_id)
@router.get("/data_auth")
async def data_authority(request: Request,
db: AsyncIOMotorDatabase = Depends(get_database),
game: str = Depends(deps.get_game_project),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""获取前项目数据权限"""
data = await crud.data_auth.get_game_data_auth(db, game)
for item in data:
item['id'] = str(item['_id'])
del item['_id']
return schemas.Msg(code=0, msg='ok', data=data)

View File

@ -20,7 +20,6 @@ async def create(
await crud.folder.create(db, data_in, user_id=current_user.id)
except pymongo.errors.DuplicateKeyError:
return schemas.Msg(code=-1, msg='文件夹已存在', data='文件夹已存在')
# todo 建默认文件夹
return schemas.Msg(code=0, msg='ok', data='创建成功')

View File

@ -15,16 +15,35 @@ router = APIRouter()
@router.post("/create")
async def create(
request: Request,
data_in: ProjectCreate,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)
) -> schemas.Msg:
"""创建项目"""
try:
await crud.project.create(db, data_in, user_id=current_user.id)
res_project = await crud.project.create(db, data_in, current_user=request.user)
except pymongo.errors.DuplicateKeyError:
return schemas.Msg(code=-1, msg='项目名已存在', data='项目名已存在')
# todo 建默认文件夹
folder = schemas.FolderCreate(
name='未分组',
project_id=res_project.inserted_id,
cat='kanban',
pid=res_project.inserted_id,
)
await crud.folder.create(db, folder, user_id=current_user.id)
folder = schemas.FolderCreate(
name='共享给我的',
project_id=res_project.inserted_id,
cat='kanban',
pid=res_project.inserted_id,
)
await crud.folder.create(db, folder, user_id=current_user.id)
# 创建全部数据权限
data_auth = schemas.DataAuthCreate(name='全部', data=['*'])
await crud.data_auth.create(db, data_auth, data_in.game)
# 新建项目管理员权限
role_name = f'{data_in.game}_admin'
@ -43,25 +62,25 @@ async def read_project(request: Request,
current_user: schemas.UserDB = Depends(deps.get_current_user)
):
"""查看自己拥有的项目"""
res = await crud.project.read_project(db, user_id=current_user.id)
res = await crud.project.read_project(db, username=request.user.username)
return schemas.Msg(code=0, msg='ok', data=res)
@router.post("/detail")
@router.get("/detail")
async def read_project(request: Request,
game: str,
data_in: schemas.ProjectDetail,
db: AsyncIOMotorDatabase = Depends(get_database),
ck: CKDrive = Depends(get_ck_db),
current_user: schemas.UserDB = Depends(deps.get_current_user)
):
"""查看项目信息"""
res = await crud.project.read_project(db, user_id=current_user.id, _id=data_in.project_id)
res = await crud.project.read_project(db, username=request.user.username, game=game)
if res:
res = res[0]
event_count = await ck.count(game, 'event')
user_count = await ck.count(game, 'user_view')
event_type_count = await ck.distinct_count(game, 'event')
event_type_count = await ck.distinct_count(game, 'event', '#event_name')
event_attr_count = await ck.field_count(db=game, tb='event')
user_attr_count = await ck.field_count(db=game, tb='user_view')
@ -75,6 +94,7 @@ async def read_project(request: Request,
@router.post("/rename")
async def rename_project(request: Request,
game: str,
data_in: schemas.ProjectRename,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.UserDB = Depends(deps.get_current_user)

View File

@ -74,12 +74,26 @@ async def reset_password(request: Request,
current_user: schemas.User = Depends(deps.get_current_user)
) -> Any:
"""
修改密码
修改其他人密码
"""
await crud.user.reset_password(db, data_in)
return schemas.Msg(code=0, msg='ok')
@router.post("/reset_my_password")
async def reset_password(request: Request,
game: str,
data_in: schemas.UserRestMyPassword,
db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.User = Depends(deps.get_current_user)
) -> Any:
"""
修改自己的密码
"""
await crud.user.reset_password(db, schemas.UserRestPassword(username=current_user.name, password=data_in.password))
return schemas.Msg(code=0, msg='ok')
@router.get("/all_account")
async def all_account(page: int = 1, limit: int = 10, db: AsyncIOMotorDatabase = Depends(get_database),
current_user: schemas.User = Depends(deps.get_current_user)

View File

@ -10,6 +10,7 @@ import utils
from core import security
from core.config import settings
from db import get_database
from db.ckdb import CKDrive, get_ck_db
reusable_oauth2 = OAuth2PasswordBearer(
tokenUrl=f"{settings.API_V1_STR}/user/login"
@ -59,3 +60,4 @@ async def get_game_project(game: str, db: AsyncIOMotorDatabase = Depends(get_dat
detail='没有该项目'
)
return game

View File

@ -5,3 +5,4 @@ from .crud_space import space
from .crud_dashboard import dashboard
from .crud_report import report
from .crud_authority import authority
from .crud_data_auth import data_auth

View File

@ -13,8 +13,8 @@ class CRUDBase:
async def find_one(self, db, filter=None, *args, **kwargs):
return (await db[self.coll_name].find_one(filter, *args, **kwargs)) or dict()
async def read_have(self, db, user_id: str, **kwargs):
where = {'members': user_id}
async def read_have(self, db, v: str, **kwargs):
where = {'members': v}
where.update(kwargs)
cursor = db[self.coll_name].find(where)
return await cursor.to_list(length=9999)

View File

@ -1,3 +1,5 @@
from copy import deepcopy
import pymongo
from motor.motor_asyncio import AsyncIOMotorDatabase
@ -29,17 +31,42 @@ class CRUDAuthority(CRUDBase):
data.update(kwargs)
await self.update_one(db, data, {'$set': data}, upsert=True)
# async def get_all_role(self, db):
# # todo 避免与用户同名
# await self.find_many(db, ptype='p')
async def get_all_dom_role(self, db, dom):
pass
async def get_role_dom_authority(self, db, role, dom):
data = await self.find_many(db, v0=role, v1=dom)
res = []
for item in data:
res.append({
'api': item['v2'],
'api_name': item.get('api_name', item['v2'])
})
async def get_role_dom_authority(self, db, role, dom, api_data):
selected_api = {item['v2'] for item in await self.find_many(db, v0=role, v1=dom)}
anonymous_api = {item['v2'] for item in await self.find_many(db, v0='anonymous')}
api_data = deepcopy(api_data)
for api, data in api_data.items():
if api in selected_api or '*' in selected_api or api in anonymous_api:
data['selected'] = True
else:
data['selected'] = False
res = {}
for api, item in api_data.items():
res.setdefault(item['title'], list())
res[item['title']].append(item)
return res
async def set_data_auth(self, db: AsyncIOMotorDatabase, data_in, game):
v0 = data_in.username
v2 = game
data_auth_id = data_in.data
await self.update_one(db, {'ptype': 'g', 'v0': v0, 'v2': v2}, {'$set': {'data_auth_id': data_auth_id}},
upsert=True)
async def get_data_auth(self, db, username, game):
v0 = username
v2 = game
res = await self.find_one(db, {'ptype': 'g', 'v0': v0, 'v2': v2}, {'_id': 0, 'data_auth_id': 1})
return res
async def create_index(self, db: AsyncIOMotorDatabase):

26
crud/crud_data_auth.py Normal file
View File

@ -0,0 +1,26 @@
import pymongo
from motor.motor_asyncio import AsyncIOMotorDatabase
from crud.base import CRUDBase
from schemas import *
__all__ = 'data_auth',
class CRUDDataAuth(CRUDBase):
async def create(self, db: AsyncIOMotorDatabase, obj_in: DataAuthCreate, game):
data = obj_in.dict()
data['game'] = game
await self.update_one(db, data, {'$set': data}, upsert=True)
async def get_game_data_auth(self, db, game):
return await self.find_many(db, game=game)
async def create_index(self, db: AsyncIOMotorDatabase):
await db[self.coll_name].create_index(
[('game', pymongo.DESCENDING), ('name', pymongo.DESCENDING)],
unique=True)
data_auth = CRUDDataAuth('data_auth')

View File

@ -19,7 +19,7 @@ class CRUDFolder(CRUDBase):
await db[self.coll_name].insert_one(db_obj.dict(by_alias=True))
async def read_folder(self, db, user_id, project_id, cat):
return await self.read_have(db, user_id=user_id, project_id=project_id, cat=cat)
return await self.read_have(db, user_id, project_id=project_id, cat=cat)
async def create_index(self, db: AsyncIOMotorDatabase):
await db[self.coll_name].create_index(

View File

@ -8,15 +8,17 @@ __all__ = 'project',
class CRUDProject(CRUDBase):
async def create(self, db: AsyncIOMotorDatabase, obj_in: ProjectCreate, user_id: str):
async def create(self, db: AsyncIOMotorDatabase, obj_in: ProjectCreate, current_user):
db_obj = ProjectDB(
**obj_in.dict(), user_id=user_id, members=[user_id],
**obj_in.dict(), user_id=current_user.id, members=[current_user.username],
_id=uuid.uuid1().hex
)
return await db[self.coll_name].insert_one(db_obj.dict(by_alias=True))
async def read_project(self, db: AsyncIOMotorDatabase, user_id: str, **kwargs):
return await self.read_have(db, user_id=user_id, **kwargs)
async def read_project(self, db: AsyncIOMotorDatabase, username: str, **kwargs):
return await self.read_have(db, username, **kwargs)
async def add_members(self, db: AsyncIOMotorDatabase, obj_in: ProjectMember):
p = await self.get(db, obj_in.project_id)

View File

@ -20,8 +20,8 @@ class CKDrive:
res = await self.execute(sql)
return res[0]['count']
async def distinct_count(self, db: str, tb: str):
sql = f'select count(distinct `#event_name`) as `count` from {db}.{tb}'
async def distinct_count(self, db: str, tb: str, field: str):
sql = f'select count(distinct `{field}`) as `count` from {db}.{tb}'
res = await self.execute(sql)
return res[0]['count']
@ -30,6 +30,11 @@ class CKDrive:
res = await self.execute(sql)
return res[0]['count']
async def distinct(self, db: str, tb: str, field: str):
sql = f'select distinct `{field}` as v from {db}.{tb}'
res = await self.execute(sql)
return res[0]['v']
ckdb = CKDrive()

View File

@ -7,5 +7,6 @@ from .dashboard import *
from .report import *
from .authotity import *
from .table_struct import *
from .data_auth import *
from .sql import *

15
schemas/data_auth.py Normal file
View File

@ -0,0 +1,15 @@
from typing import List
from pydantic import BaseModel
class DataAuthCreate(BaseModel):
name: str
data: List[str] = []
class DataAuthSet(BaseModel):
username: str
data_auth_id: str

View File

@ -30,6 +30,8 @@ class UserRestPassword(BaseModel):
username: str = ...
password: str = ...
class UserRestMyPassword(BaseModel):
password: str = ...
class UserCreate(UserBase):
password: str