mirror of
https://github.com/suyiiyii/nonebot-bison.git
synced 2025-06-05 19:36:43 +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) => {
|
const setLoginReducer: CaseReducer<AuthStatus, PayloadAction<TokenResp>> = (state, action) => {
|
||||||
if (action.payload.status === 200) {
|
state.login = true;
|
||||||
state.login = true;
|
state.id = action.payload.id;
|
||||||
state.id = action.payload.id;
|
state.userType = action.payload.type;
|
||||||
state.userType = action.payload.type;
|
state.token = action.payload.token;
|
||||||
state.token = action.payload.token;
|
};
|
||||||
} else {
|
|
||||||
state.login = false;
|
export const setLoginFailedReducer: CaseReducer<AuthStatus> = (state) => {
|
||||||
state.failed = true;
|
state.login = false;
|
||||||
}
|
state.failed = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const setLogoutReducer: CaseReducer<AuthStatus> = (state) => {
|
export const setLogoutReducer: CaseReducer<AuthStatus> = (state) => {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
export interface TokenResp {
|
export interface TokenResp {
|
||||||
status: number;
|
|
||||||
token: string;
|
token: string;
|
||||||
type: string;
|
type: string;
|
||||||
id: number;
|
id: number;
|
||||||
@ -44,7 +43,7 @@ export interface SubscribeResp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface StatusResp {
|
export interface StatusResp {
|
||||||
status: number;
|
ok: boolean;
|
||||||
msg: string;
|
msg: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import os
|
import os
|
||||||
from dataclasses import dataclass
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
import socketio
|
import socketio
|
||||||
|
from fastapi.applications import FastAPI
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from nonebot import get_driver, on_command
|
from nonebot import get_driver, on_command
|
||||||
from nonebot.adapters.onebot.v11 import Bot
|
from nonebot.adapters.onebot.v11 import Bot
|
||||||
@ -14,30 +14,9 @@ from nonebot.rule import to_me
|
|||||||
from nonebot.typing import T_State
|
from nonebot.typing import T_State
|
||||||
|
|
||||||
from ..plugin_config import plugin_config
|
from ..plugin_config import plugin_config
|
||||||
from ..types import WeightConfig
|
from .api import router as api_router
|
||||||
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 .token_manager import token_manager as tm
|
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()
|
STATIC_PATH = (Path(__file__).parent / "dist").resolve()
|
||||||
|
|
||||||
sio = socketio.AsyncServer(async_mode="asgi", cors_allowed_origins="*")
|
sio = socketio.AsyncServer(async_mode="asgi", cors_allowed_origins="*")
|
||||||
@ -57,90 +36,18 @@ class SinglePageApplication(StaticFiles):
|
|||||||
|
|
||||||
|
|
||||||
def register_router_fastapi(driver: Driver, socketio):
|
def register_router_fastapi(driver: Driver, socketio):
|
||||||
from fastapi import HTTPException, status
|
static_path = STATIC_PATH
|
||||||
from fastapi.param_functions import Depends
|
nonebot_app = FastAPI(
|
||||||
from fastapi.security import OAuth2PasswordBearer
|
title="nonebot-bison",
|
||||||
|
description="nonebot-bison webui and api",
|
||||||
oath_scheme = OAuth2PasswordBearer(tokenUrl="token")
|
)
|
||||||
|
nonebot_app.include_router(api_router)
|
||||||
async def get_jwt_obj(token: str = Depends(oath_scheme)):
|
nonebot_app.mount(
|
||||||
obj = load_jwt(token)
|
"/", SinglePageApplication(directory=static_path), name="bison-frontend"
|
||||||
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]
|
|
||||||
|
|
||||||
app = driver.server_app
|
app = driver.server_app
|
||||||
static_path = STATIC_PATH
|
app.mount("/bison", nonebot_app, "nonebot-bison")
|
||||||
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")
|
|
||||||
|
|
||||||
|
|
||||||
def init():
|
def init():
|
||||||
@ -156,7 +63,7 @@ def init():
|
|||||||
host = "localhost"
|
host = "localhost"
|
||||||
logger.opt(colors=True).info(
|
logger.opt(colors=True).info(
|
||||||
f"Nonebot test frontend will be running at: "
|
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
|
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 nonebot.adapters.onebot.v11.bot import Bot
|
||||||
|
|
||||||
from ..apis import check_sub_target
|
from ..apis import check_sub_target
|
||||||
@ -12,25 +17,58 @@ from ..config.db_config import SubscribeDupException
|
|||||||
from ..platform import platform_manager
|
from ..platform import platform_manager
|
||||||
from ..types import Target as T_Target
|
from ..types import Target as T_Target
|
||||||
from ..types import WeightConfig
|
from ..types import WeightConfig
|
||||||
from .jwt import pack_jwt
|
from .jwt import load_jwt, pack_jwt
|
||||||
from .token_manager import token_manager
|
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():
|
async def get_jwt_obj(token: str = Depends(oath_scheme)):
|
||||||
return {"status": 200, "text": "test"}
|
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 = {}
|
res = {}
|
||||||
for platform_name, platform in platform_manager.items():
|
for platform_name, platform in platform_manager.items():
|
||||||
res[platform_name] = {
|
res[platform_name] = PlatformConfig(
|
||||||
"platformName": platform_name,
|
platformName=platform_name,
|
||||||
"categories": platform.categories,
|
categories=platform.categories,
|
||||||
"enabledTag": platform.enable_tag,
|
enabledTag=platform.enable_tag,
|
||||||
"name": platform.name,
|
name=platform.name,
|
||||||
"hasTarget": getattr(platform, "has_target"),
|
hasTarget=getattr(platform, "has_target"),
|
||||||
}
|
)
|
||||||
return {"platformConf": res}
|
return GlobalConf(platformConf=res)
|
||||||
|
|
||||||
|
|
||||||
async def get_admin_groups(qq: int):
|
async def get_admin_groups(qq: int):
|
||||||
@ -46,7 +84,8 @@ async def get_admin_groups(qq: int):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
async def auth(token: str):
|
@router.get("/auth")
|
||||||
|
async def auth(token: str) -> TokenResp:
|
||||||
if qq_tuple := token_manager.get_user(token):
|
if qq_tuple := token_manager.get_user(token):
|
||||||
qq, nickname = qq_tuple
|
qq, nickname = qq_tuple
|
||||||
bot = nonebot.get_bot()
|
bot = nonebot.get_bot()
|
||||||
@ -66,113 +105,112 @@ async def auth(token: str):
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
ret_obj = {
|
ret_obj = TokenResp(
|
||||||
"type": "admin",
|
type="admin",
|
||||||
"name": nickname,
|
name=nickname,
|
||||||
"id": qq,
|
id=qq,
|
||||||
"token": pack_jwt(jwt_obj),
|
token=pack_jwt(jwt_obj),
|
||||||
}
|
)
|
||||||
return {"status": 200, **ret_obj}
|
return ret_obj
|
||||||
if admin_groups := await get_admin_groups(int(qq)):
|
if admin_groups := await get_admin_groups(int(qq)):
|
||||||
jwt_obj = {"id": str(qq), "type": "user", "groups": admin_groups}
|
jwt_obj = {"id": str(qq), "type": "user", "groups": admin_groups}
|
||||||
ret_obj = {
|
ret_obj = TokenResp(
|
||||||
"type": "user",
|
type="user",
|
||||||
"name": nickname,
|
name=nickname,
|
||||||
"id": qq,
|
id=qq,
|
||||||
"token": pack_jwt(jwt_obj),
|
token=pack_jwt(jwt_obj),
|
||||||
}
|
)
|
||||||
return {"status": 200, **ret_obj}
|
return ret_obj
|
||||||
else:
|
else:
|
||||||
return {"status": 400, "type": "", "name": "", "id": 0, "token": ""}
|
raise HTTPException(400, "permission denied")
|
||||||
else:
|
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"]
|
groups = jwt_obj["groups"]
|
||||||
res = {}
|
res: SubscribeResp = {}
|
||||||
for group in groups:
|
for group in groups:
|
||||||
group_id = group["id"]
|
group_id = group["id"]
|
||||||
raw_subs = await config.list_subscribe(group_id, "group")
|
raw_subs = await config.list_subscribe(group_id, "group")
|
||||||
subs = list(
|
subs = list(
|
||||||
map(
|
map(
|
||||||
lambda sub: {
|
lambda sub: SubscribeConfig(
|
||||||
"platformName": sub.target.platform_name,
|
platformName=sub.target.platform_name,
|
||||||
"targetName": sub.target.target_name,
|
targetName=sub.target.target_name,
|
||||||
"cats": sub.categories,
|
cats=sub.categories, # type: ignore
|
||||||
"tags": sub.tags,
|
tags=sub.tags, # type: ignore
|
||||||
"target": sub.target.target,
|
target=sub.target.target,
|
||||||
},
|
),
|
||||||
raw_subs,
|
raw_subs,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
res[group_id] = {"name": group["name"], "subscribes": subs}
|
res[group_id] = SubscribeGroupDetail(name=group["name"], subscribes=subs)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
async def get_target_name(platform_name: str, target: str, jwt_obj: dict):
|
@router.get("/target_name", dependencies=[Depends(get_jwt_obj)])
|
||||||
return {"targetName": await check_sub_target(platform_name, target)}
|
async def get_target_name(platformName: str, target: str):
|
||||||
|
return {"targetName": await check_sub_target(platformName, T_Target(target))}
|
||||||
|
|
||||||
|
|
||||||
async def add_group_sub(
|
@router.post("/subs", dependencies=[Depends(check_group_permission)])
|
||||||
group_number: int,
|
async def add_group_sub(groupNumber: int, req: AddSubscribeReq) -> StatusResp:
|
||||||
platform_name: str,
|
|
||||||
target: str,
|
|
||||||
target_name: str,
|
|
||||||
cats: list[int],
|
|
||||||
tags: list[str],
|
|
||||||
):
|
|
||||||
try:
|
try:
|
||||||
await config.add_subscribe(
|
await config.add_subscribe(
|
||||||
int(group_number),
|
int(groupNumber),
|
||||||
"group",
|
"group",
|
||||||
T_Target(target),
|
T_Target(req.target),
|
||||||
target_name,
|
req.targetName,
|
||||||
platform_name,
|
req.platformName,
|
||||||
cats,
|
req.cats,
|
||||||
tags,
|
req.tags,
|
||||||
)
|
)
|
||||||
return {"status": 200, "msg": ""}
|
return StatusResp(ok=True, msg="")
|
||||||
except SubscribeDupException:
|
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:
|
try:
|
||||||
await config.del_subscribe(int(group_number), "group", target, platform_name)
|
await config.del_subscribe(int(groupNumber), "group", target, platformName)
|
||||||
except (NoSuchUserException, NoSuchSubscribeException):
|
except (NoSuchUserException, NoSuchSubscribeException):
|
||||||
return {"status": 400, "msg": "删除错误"}
|
raise HTTPException(status.HTTP_400_BAD_REQUEST, "no such user or subscribe")
|
||||||
return {"status": 200, "msg": ""}
|
return StatusResp(ok=True, msg="")
|
||||||
|
|
||||||
|
|
||||||
async def update_group_sub(
|
@router.patch("/subs", dependencies=[Depends(check_group_permission)])
|
||||||
group_number: int,
|
async def update_group_sub(groupNumber: int, req: AddSubscribeReq):
|
||||||
platform_name: str,
|
|
||||||
target: str,
|
|
||||||
target_name: str,
|
|
||||||
cats: list[int],
|
|
||||||
tags: list[str],
|
|
||||||
):
|
|
||||||
try:
|
try:
|
||||||
await config.update_subscribe(
|
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):
|
except (NoSuchUserException, NoSuchSubscribeException):
|
||||||
return {"status": 400, "msg": "更新错误"}
|
raise HTTPException(status.HTTP_400_BAD_REQUEST, "no such user or subscribe")
|
||||||
return {"status": 200, "msg": ""}
|
return StatusResp(ok=True, msg="")
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/weight", dependencies=[Depends(check_is_superuser)])
|
||||||
async def get_weight_config():
|
async def get_weight_config():
|
||||||
return await config.get_all_weight_config()
|
return await config.get_all_weight_config()
|
||||||
|
|
||||||
|
|
||||||
|
@router.put("/weight", dependencies=[Depends(check_is_superuser)])
|
||||||
async def update_weigth_config(
|
async def update_weigth_config(
|
||||||
platform_name: str, target: str, weight_config: WeightConfig
|
platformName: str, target: str, weight_config: WeightConfig
|
||||||
):
|
):
|
||||||
try:
|
try:
|
||||||
await config.update_time_weight_config(
|
await config.update_time_weight_config(
|
||||||
T_Target(target), platform_name, weight_config
|
T_Target(target), platformName, weight_config
|
||||||
)
|
)
|
||||||
except NoSuchTargetException:
|
except NoSuchTargetException:
|
||||||
return {"status": 400, "msg": "该订阅不存在"}
|
raise HTTPException(status.HTTP_400_BAD_REQUEST, "no such subscribe")
|
||||||
return {"status": 200, "msg": ""}
|
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