mirror of
https://github.com/suyiiyii/nonebot-bison.git
synced 2025-06-04 02:26:11 +08:00
♻️ refactor api code
This commit is contained in:
parent
410cac1af3
commit
0ebbdd2c0d
@ -30,15 +30,15 @@ export const login = createAsyncThunk(
|
||||
);
|
||||
|
||||
const setLoginReducer: CaseReducer<AuthStatus, PayloadAction<TokenResp>> = (state, action) => {
|
||||
if (action.payload.status === 200) {
|
||||
state.login = true;
|
||||
state.id = action.payload.id;
|
||||
state.userType = action.payload.type;
|
||||
state.token = action.payload.token;
|
||||
} else {
|
||||
state.login = false;
|
||||
state.failed = true;
|
||||
}
|
||||
state.login = true;
|
||||
state.id = action.payload.id;
|
||||
state.userType = action.payload.type;
|
||||
state.token = action.payload.token;
|
||||
};
|
||||
|
||||
export const setLoginFailedReducer: CaseReducer<AuthStatus> = (state) => {
|
||||
state.login = false;
|
||||
state.failed = true;
|
||||
};
|
||||
|
||||
export const setLogoutReducer: CaseReducer<AuthStatus> = (state) => {
|
||||
|
@ -1,5 +1,4 @@
|
||||
export interface TokenResp {
|
||||
status: number;
|
||||
token: string;
|
||||
type: string;
|
||||
id: number;
|
||||
@ -44,7 +43,7 @@ export interface SubscribeResp {
|
||||
}
|
||||
|
||||
export interface StatusResp {
|
||||
status: number;
|
||||
ok: boolean;
|
||||
msg: string;
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Union
|
||||
|
||||
import socketio
|
||||
from fastapi.applications import FastAPI
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from nonebot import get_driver, on_command
|
||||
from nonebot.adapters.onebot.v11 import Bot
|
||||
@ -14,30 +14,9 @@ from nonebot.rule import to_me
|
||||
from nonebot.typing import T_State
|
||||
|
||||
from ..plugin_config import plugin_config
|
||||
from ..types import WeightConfig
|
||||
from .api import (
|
||||
add_group_sub,
|
||||
auth,
|
||||
del_group_sub,
|
||||
get_global_conf,
|
||||
get_subs_info,
|
||||
get_target_name,
|
||||
get_weight_config,
|
||||
test,
|
||||
update_group_sub,
|
||||
update_weigth_config,
|
||||
)
|
||||
from .jwt import load_jwt
|
||||
from .api import router as api_router
|
||||
from .token_manager import token_manager as tm
|
||||
|
||||
URL_BASE = "/bison/"
|
||||
GLOBAL_CONF_URL = f"{URL_BASE}api/global_conf"
|
||||
AUTH_URL = f"{URL_BASE}api/auth"
|
||||
SUBSCRIBE_URL = f"{URL_BASE}api/subs"
|
||||
GET_TARGET_NAME_URL = f"{URL_BASE}api/target_name"
|
||||
WEIGHT_URL = f"{URL_BASE}api/weight"
|
||||
TEST_URL = f"{URL_BASE}test"
|
||||
|
||||
STATIC_PATH = (Path(__file__).parent / "dist").resolve()
|
||||
|
||||
sio = socketio.AsyncServer(async_mode="asgi", cors_allowed_origins="*")
|
||||
@ -57,90 +36,18 @@ class SinglePageApplication(StaticFiles):
|
||||
|
||||
|
||||
def register_router_fastapi(driver: Driver, socketio):
|
||||
from fastapi import HTTPException, status
|
||||
from fastapi.param_functions import Depends
|
||||
from fastapi.security import OAuth2PasswordBearer
|
||||
|
||||
oath_scheme = OAuth2PasswordBearer(tokenUrl="token")
|
||||
|
||||
async def get_jwt_obj(token: str = Depends(oath_scheme)):
|
||||
obj = load_jwt(token)
|
||||
if not obj:
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED)
|
||||
return obj
|
||||
|
||||
async def check_group_permission(
|
||||
groupNumber: int, token_obj: dict = Depends(get_jwt_obj)
|
||||
):
|
||||
groups = token_obj["groups"]
|
||||
for group in groups:
|
||||
if int(groupNumber) == group["id"]:
|
||||
return
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN)
|
||||
|
||||
async def check_is_superuser(token_obj: dict = Depends(get_jwt_obj)):
|
||||
if token_obj.get("type") != "admin":
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN)
|
||||
|
||||
@dataclass
|
||||
class AddSubscribeReq:
|
||||
platformName: str
|
||||
target: str
|
||||
targetName: str
|
||||
cats: list[int]
|
||||
tags: list[str]
|
||||
static_path = STATIC_PATH
|
||||
nonebot_app = FastAPI(
|
||||
title="nonebot-bison",
|
||||
description="nonebot-bison webui and api",
|
||||
)
|
||||
nonebot_app.include_router(api_router)
|
||||
nonebot_app.mount(
|
||||
"/", SinglePageApplication(directory=static_path), name="bison-frontend"
|
||||
)
|
||||
|
||||
app = driver.server_app
|
||||
static_path = STATIC_PATH
|
||||
app.get(TEST_URL)(test)
|
||||
app.get(GLOBAL_CONF_URL)(get_global_conf)
|
||||
app.get(AUTH_URL)(auth)
|
||||
|
||||
@app.get(SUBSCRIBE_URL)
|
||||
async def subs(jwt_obj: dict = Depends(get_jwt_obj)):
|
||||
return await get_subs_info(jwt_obj)
|
||||
|
||||
@app.get(GET_TARGET_NAME_URL)
|
||||
async def _get_target_name(
|
||||
platformName: str, target: str, jwt_obj: dict = Depends(get_jwt_obj)
|
||||
):
|
||||
return await get_target_name(platformName, target, jwt_obj)
|
||||
|
||||
@app.post(SUBSCRIBE_URL, dependencies=[Depends(check_group_permission)])
|
||||
async def _add_group_subs(groupNumber: int, req: AddSubscribeReq):
|
||||
return await add_group_sub(
|
||||
group_number=groupNumber,
|
||||
platform_name=req.platformName,
|
||||
target=req.target,
|
||||
target_name=req.targetName,
|
||||
cats=req.cats,
|
||||
tags=req.tags,
|
||||
)
|
||||
|
||||
@app.patch(SUBSCRIBE_URL, dependencies=[Depends(check_group_permission)])
|
||||
async def _update_group_subs(groupNumber: int, req: AddSubscribeReq):
|
||||
return await update_group_sub(
|
||||
group_number=groupNumber,
|
||||
platform_name=req.platformName,
|
||||
target=req.target,
|
||||
target_name=req.targetName,
|
||||
cats=req.cats,
|
||||
tags=req.tags,
|
||||
)
|
||||
|
||||
@app.delete(SUBSCRIBE_URL, dependencies=[Depends(check_group_permission)])
|
||||
async def _del_group_subs(groupNumber: int, target: str, platformName: str):
|
||||
return await del_group_sub(groupNumber, platformName, target)
|
||||
|
||||
@app.get(WEIGHT_URL, dependencies=[Depends(check_is_superuser)])
|
||||
async def _get_weight_config():
|
||||
return await get_weight_config()
|
||||
|
||||
@app.put(WEIGHT_URL, dependencies=[Depends(check_is_superuser)])
|
||||
async def _update_weight_config(platform_name: str, target: str, req: WeightConfig):
|
||||
return await update_weigth_config(platform_name, target, req)
|
||||
|
||||
app.mount(URL_BASE, SinglePageApplication(directory=static_path), name="bison")
|
||||
app.mount("/bison", nonebot_app, "nonebot-bison")
|
||||
|
||||
|
||||
def init():
|
||||
@ -156,7 +63,7 @@ def init():
|
||||
host = "localhost"
|
||||
logger.opt(colors=True).info(
|
||||
f"Nonebot test frontend will be running at: "
|
||||
f"<b><u>http://{host}:{port}{URL_BASE}</u></b>"
|
||||
f"<b><u>http://{host}:{port}/bison</u></b>"
|
||||
)
|
||||
|
||||
|
||||
|
@ -1,4 +1,9 @@
|
||||
import nonebot
|
||||
from fastapi import status
|
||||
from fastapi.exceptions import HTTPException
|
||||
from fastapi.param_functions import Depends
|
||||
from fastapi.routing import APIRouter
|
||||
from fastapi.security.oauth2 import OAuth2PasswordBearer
|
||||
from nonebot.adapters.onebot.v11.bot import Bot
|
||||
|
||||
from ..apis import check_sub_target
|
||||
@ -12,25 +17,58 @@ from ..config.db_config import SubscribeDupException
|
||||
from ..platform import platform_manager
|
||||
from ..types import Target as T_Target
|
||||
from ..types import WeightConfig
|
||||
from .jwt import pack_jwt
|
||||
from .jwt import load_jwt, pack_jwt
|
||||
from .token_manager import token_manager
|
||||
from .types import (
|
||||
AddSubscribeReq,
|
||||
GlobalConf,
|
||||
PlatformConfig,
|
||||
StatusResp,
|
||||
SubscribeConfig,
|
||||
SubscribeGroupDetail,
|
||||
SubscribeResp,
|
||||
TokenResp,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/api", tags=["api"])
|
||||
|
||||
oath_scheme = OAuth2PasswordBearer(tokenUrl="token")
|
||||
|
||||
|
||||
async def test():
|
||||
return {"status": 200, "text": "test"}
|
||||
async def get_jwt_obj(token: str = Depends(oath_scheme)):
|
||||
obj = load_jwt(token)
|
||||
if not obj:
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED)
|
||||
return obj
|
||||
|
||||
|
||||
async def get_global_conf():
|
||||
async def check_group_permission(
|
||||
groupNumber: int, token_obj: dict = Depends(get_jwt_obj)
|
||||
):
|
||||
groups = token_obj["groups"]
|
||||
for group in groups:
|
||||
if int(groupNumber) == group["id"]:
|
||||
return
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN)
|
||||
|
||||
|
||||
async def check_is_superuser(token_obj: dict = Depends(get_jwt_obj)):
|
||||
if token_obj.get("type") != "admin":
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN)
|
||||
|
||||
|
||||
@router.get("/global_conf")
|
||||
async def get_global_conf() -> GlobalConf:
|
||||
res = {}
|
||||
for platform_name, platform in platform_manager.items():
|
||||
res[platform_name] = {
|
||||
"platformName": platform_name,
|
||||
"categories": platform.categories,
|
||||
"enabledTag": platform.enable_tag,
|
||||
"name": platform.name,
|
||||
"hasTarget": getattr(platform, "has_target"),
|
||||
}
|
||||
return {"platformConf": res}
|
||||
res[platform_name] = PlatformConfig(
|
||||
platformName=platform_name,
|
||||
categories=platform.categories,
|
||||
enabledTag=platform.enable_tag,
|
||||
name=platform.name,
|
||||
hasTarget=getattr(platform, "has_target"),
|
||||
)
|
||||
return GlobalConf(platformConf=res)
|
||||
|
||||
|
||||
async def get_admin_groups(qq: int):
|
||||
@ -46,7 +84,8 @@ async def get_admin_groups(qq: int):
|
||||
return res
|
||||
|
||||
|
||||
async def auth(token: str):
|
||||
@router.get("/auth")
|
||||
async def auth(token: str) -> TokenResp:
|
||||
if qq_tuple := token_manager.get_user(token):
|
||||
qq, nickname = qq_tuple
|
||||
bot = nonebot.get_bot()
|
||||
@ -66,113 +105,112 @@ async def auth(token: str):
|
||||
)
|
||||
),
|
||||
}
|
||||
ret_obj = {
|
||||
"type": "admin",
|
||||
"name": nickname,
|
||||
"id": qq,
|
||||
"token": pack_jwt(jwt_obj),
|
||||
}
|
||||
return {"status": 200, **ret_obj}
|
||||
ret_obj = TokenResp(
|
||||
type="admin",
|
||||
name=nickname,
|
||||
id=qq,
|
||||
token=pack_jwt(jwt_obj),
|
||||
)
|
||||
return ret_obj
|
||||
if admin_groups := await get_admin_groups(int(qq)):
|
||||
jwt_obj = {"id": str(qq), "type": "user", "groups": admin_groups}
|
||||
ret_obj = {
|
||||
"type": "user",
|
||||
"name": nickname,
|
||||
"id": qq,
|
||||
"token": pack_jwt(jwt_obj),
|
||||
}
|
||||
return {"status": 200, **ret_obj}
|
||||
ret_obj = TokenResp(
|
||||
type="user",
|
||||
name=nickname,
|
||||
id=qq,
|
||||
token=pack_jwt(jwt_obj),
|
||||
)
|
||||
return ret_obj
|
||||
else:
|
||||
return {"status": 400, "type": "", "name": "", "id": 0, "token": ""}
|
||||
raise HTTPException(400, "permission denied")
|
||||
else:
|
||||
return {"status": 400, "type": "", "name": "", "id": 0, "token": ""}
|
||||
raise HTTPException(400, "code error")
|
||||
|
||||
|
||||
async def get_subs_info(jwt_obj: dict):
|
||||
@router.get("/subs")
|
||||
async def get_subs_info(jwt_obj: dict = Depends(get_jwt_obj)) -> SubscribeResp:
|
||||
groups = jwt_obj["groups"]
|
||||
res = {}
|
||||
res: SubscribeResp = {}
|
||||
for group in groups:
|
||||
group_id = group["id"]
|
||||
raw_subs = await config.list_subscribe(group_id, "group")
|
||||
subs = list(
|
||||
map(
|
||||
lambda sub: {
|
||||
"platformName": sub.target.platform_name,
|
||||
"targetName": sub.target.target_name,
|
||||
"cats": sub.categories,
|
||||
"tags": sub.tags,
|
||||
"target": sub.target.target,
|
||||
},
|
||||
lambda sub: SubscribeConfig(
|
||||
platformName=sub.target.platform_name,
|
||||
targetName=sub.target.target_name,
|
||||
cats=sub.categories, # type: ignore
|
||||
tags=sub.tags, # type: ignore
|
||||
target=sub.target.target,
|
||||
),
|
||||
raw_subs,
|
||||
)
|
||||
)
|
||||
res[group_id] = {"name": group["name"], "subscribes": subs}
|
||||
res[group_id] = SubscribeGroupDetail(name=group["name"], subscribes=subs)
|
||||
return res
|
||||
|
||||
|
||||
async def get_target_name(platform_name: str, target: str, jwt_obj: dict):
|
||||
return {"targetName": await check_sub_target(platform_name, target)}
|
||||
@router.get("/target_name", dependencies=[Depends(get_jwt_obj)])
|
||||
async def get_target_name(platformName: str, target: str):
|
||||
return {"targetName": await check_sub_target(platformName, T_Target(target))}
|
||||
|
||||
|
||||
async def add_group_sub(
|
||||
group_number: int,
|
||||
platform_name: str,
|
||||
target: str,
|
||||
target_name: str,
|
||||
cats: list[int],
|
||||
tags: list[str],
|
||||
):
|
||||
@router.post("/subs", dependencies=[Depends(check_group_permission)])
|
||||
async def add_group_sub(groupNumber: int, req: AddSubscribeReq) -> StatusResp:
|
||||
try:
|
||||
await config.add_subscribe(
|
||||
int(group_number),
|
||||
int(groupNumber),
|
||||
"group",
|
||||
T_Target(target),
|
||||
target_name,
|
||||
platform_name,
|
||||
cats,
|
||||
tags,
|
||||
T_Target(req.target),
|
||||
req.targetName,
|
||||
req.platformName,
|
||||
req.cats,
|
||||
req.tags,
|
||||
)
|
||||
return {"status": 200, "msg": ""}
|
||||
return StatusResp(ok=True, msg="")
|
||||
except SubscribeDupException:
|
||||
return {"status": 403, "msg": ""}
|
||||
raise HTTPException(status.HTTP_400_BAD_REQUEST, "subscribe duplicated")
|
||||
|
||||
|
||||
async def del_group_sub(group_number: int, platform_name: str, target: str):
|
||||
@router.delete("/subs", dependencies=[Depends(check_group_permission)])
|
||||
async def del_group_sub(groupNumber: int, platformName: str, target: str):
|
||||
try:
|
||||
await config.del_subscribe(int(group_number), "group", target, platform_name)
|
||||
await config.del_subscribe(int(groupNumber), "group", target, platformName)
|
||||
except (NoSuchUserException, NoSuchSubscribeException):
|
||||
return {"status": 400, "msg": "删除错误"}
|
||||
return {"status": 200, "msg": ""}
|
||||
raise HTTPException(status.HTTP_400_BAD_REQUEST, "no such user or subscribe")
|
||||
return StatusResp(ok=True, msg="")
|
||||
|
||||
|
||||
async def update_group_sub(
|
||||
group_number: int,
|
||||
platform_name: str,
|
||||
target: str,
|
||||
target_name: str,
|
||||
cats: list[int],
|
||||
tags: list[str],
|
||||
):
|
||||
@router.patch("/subs", dependencies=[Depends(check_group_permission)])
|
||||
async def update_group_sub(groupNumber: int, req: AddSubscribeReq):
|
||||
try:
|
||||
await config.update_subscribe(
|
||||
int(group_number), "group", target, target_name, platform_name, cats, tags
|
||||
int(groupNumber),
|
||||
"group",
|
||||
req.target,
|
||||
req.targetName,
|
||||
req.platformName,
|
||||
req.cats,
|
||||
req.tags,
|
||||
)
|
||||
except (NoSuchUserException, NoSuchSubscribeException):
|
||||
return {"status": 400, "msg": "更新错误"}
|
||||
return {"status": 200, "msg": ""}
|
||||
raise HTTPException(status.HTTP_400_BAD_REQUEST, "no such user or subscribe")
|
||||
return StatusResp(ok=True, msg="")
|
||||
|
||||
|
||||
@router.get("/weight", dependencies=[Depends(check_is_superuser)])
|
||||
async def get_weight_config():
|
||||
return await config.get_all_weight_config()
|
||||
|
||||
|
||||
@router.put("/weight", dependencies=[Depends(check_is_superuser)])
|
||||
async def update_weigth_config(
|
||||
platform_name: str, target: str, weight_config: WeightConfig
|
||||
platformName: str, target: str, weight_config: WeightConfig
|
||||
):
|
||||
try:
|
||||
await config.update_time_weight_config(
|
||||
T_Target(target), platform_name, weight_config
|
||||
T_Target(target), platformName, weight_config
|
||||
)
|
||||
except NoSuchTargetException:
|
||||
return {"status": 400, "msg": "该订阅不存在"}
|
||||
return {"status": 200, "msg": ""}
|
||||
raise HTTPException(status.HTTP_400_BAD_REQUEST, "no such subscribe")
|
||||
return StatusResp(ok=True, msg="")
|
||||
|
52
src/plugins/nonebot_bison/admin_page/types.py
Normal file
52
src/plugins/nonebot_bison/admin_page/types.py
Normal file
@ -0,0 +1,52 @@
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class PlatformConfig(BaseModel):
|
||||
name: str
|
||||
categories: dict[int, str]
|
||||
enabledTag: bool
|
||||
platformName: str
|
||||
hasTarget: bool
|
||||
|
||||
|
||||
AllPlatformConf = dict[str, PlatformConfig]
|
||||
|
||||
|
||||
class GlobalConf(BaseModel):
|
||||
platformConf: AllPlatformConf
|
||||
|
||||
|
||||
class TokenResp(BaseModel):
|
||||
token: str
|
||||
type: str
|
||||
id: int
|
||||
name: str
|
||||
|
||||
|
||||
class SubscribeConfig(BaseModel):
|
||||
platformName: str
|
||||
target: str
|
||||
targetName: str
|
||||
cats: list[int]
|
||||
tags: list[str]
|
||||
|
||||
|
||||
class SubscribeGroupDetail(BaseModel):
|
||||
name: str
|
||||
subscribes: list[SubscribeConfig]
|
||||
|
||||
|
||||
SubscribeResp = dict[str, SubscribeGroupDetail]
|
||||
|
||||
|
||||
class AddSubscribeReq(BaseModel):
|
||||
platformName: str
|
||||
target: str
|
||||
targetName: str
|
||||
cats: list[int]
|
||||
tags: list[str]
|
||||
|
||||
|
||||
class StatusResp(BaseModel):
|
||||
ok: bool
|
||||
msg: str
|
Loading…
x
Reference in New Issue
Block a user