From 03576a0ab6e14c34afbc15c62e13f2290a39170e Mon Sep 17 00:00:00 2001 From: felinae98 <731499577@qq.com> Date: Mon, 22 Nov 2021 16:46:46 +0800 Subject: [PATCH] unfinish --- Dockerfile | 6 +++ admin-frontend/src/api/config.ts | 4 +- admin-frontend/src/pages/admin.tsx | 45 +++++++++++++++++-- admin-frontend/src/utils/type.ts | 10 +---- pyproject.toml | 1 - .../nonebot_bison/admin_page/__init__.py | 30 ++++++++----- src/plugins/nonebot_bison/admin_page/api.py | 23 ++++++++++ 7 files changed, 92 insertions(+), 27 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8155b1e..6d2e161 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,8 @@ +FROM node:16 as frontend +ADD . /app +WORKDIR /app/admin-frontend +RUN yarn && yarn build + FROM python:3.9 RUN python3 -m pip install poetry && poetry config virtualenvs.create false WORKDIR /app @@ -6,5 +11,6 @@ RUN poetry install --no-root --no-dev # RUN PYPPETEER_DOWNLOAD_HOST='http://npm.taobao.org/mirrors' pyppeteer-install ADD src /app/src ADD bot.py /app/ +COPY --from=frontend /app/src/plugins/nonebot_bison/admin_page/dist /app/src/plugins/nonebot_bison/admin_page/dist ENV HOST=0.0.0.0 CMD ["python", "bot.py"] diff --git a/admin-frontend/src/api/config.ts b/admin-frontend/src/api/config.ts index 7854058..ea88904 100644 --- a/admin-frontend/src/api/config.ts +++ b/admin-frontend/src/api/config.ts @@ -1,5 +1,5 @@ import axios from "axios"; -import { GlobalConf, TokenResp, SubscribeResp, TargetNameResp, CreateSubscribeReq } from "../utils/type"; +import { GlobalConf, TokenResp, SubscribeResp, TargetNameResp, SubscribeConfig } from "../utils/type"; import { baseUrl } from './utils'; export async function getGlobalConf(): Promise { @@ -22,7 +22,7 @@ export async function getTargetName(platformName: string, target: string): Promi return res.data; } -export async function addSubscribe(groupNumber: string, req: CreateSubscribeReq) { +export async function addSubscribe(groupNumber: string, req: SubscribeConfig) { const res = await axios.post(`${baseUrl}subs`, req, {params: {groupNumber}}) return res.data; } diff --git a/admin-frontend/src/pages/admin.tsx b/admin-frontend/src/pages/admin.tsx index 3fe40e9..fb66804 100644 --- a/admin-frontend/src/pages/admin.tsx +++ b/admin-frontend/src/pages/admin.tsx @@ -1,7 +1,7 @@ -import React, { ReactElement, useContext, useEffect, useState } from "react"; +import React, { FC, ReactElement, ReactNode, useContext, useEffect, useState } from "react"; import { LoginContext, GlobalConfContext } from "../utils/context"; import { Layout, Menu, Empty, Collapse, Card, Tag, Row, Col, Form, Tooltip, Button, Modal, Select, - Input, Popconfirm} from 'antd'; + Input, Popconfirm, message } from 'antd'; import { SubscribeConfig, SubscribeResp, PlatformConfig, CategoryConfig } from '../utils/type'; import { SettingOutlined, BugOutlined, DeleteOutlined, CopyOutlined } from '@ant-design/icons'; import { getSubscribe, getTargetName, addSubscribe, delSubscribe } from '../api/config'; @@ -74,7 +74,9 @@ function ConfigPage(prop: ConfigPageProp) { onConfirm={handleDelete(groupNumber, config.platformName, config.target || 'default')}> , - + + + ]}>
@@ -119,6 +121,43 @@ function ConfigPage(prop: ConfigPageProp) { } } +interface TargetGroupSelectionProp { + config: SubscribeConfig, + groups: SubscribeResp + children: ReactNode +} +function TargetGroupSelection({ config, groups, children }: TargetGroupSelectionProp) { + let [ selectedGroups, setSelectGroups ] = useState>([]); + const submitCopy = () => { + let promise = null + for (let selectGroup of selectedGroups) { + if (! promise) { + promise = addSubscribe(selectGroup, config) + } else { + promise = promise.then(() => addSubscribe(selectGroup, config)) + } + } + if (promise) { + promise.then(() => message.success("复制订阅成功")) + } + return promise; + } + return <> + ) => setSelectGroups(value)}> + { + Object.keys(groups).map((groupNumber) => + + {`${groupNumber} - ${groups[groupNumber].name}`} + ) + } + + } onConfirm={submitCopy} > + { children } + + +} + interface InputTagCustomProp { value?: Array, onChange?: (value: Array) => void, diff --git a/admin-frontend/src/utils/type.ts b/admin-frontend/src/utils/type.ts index 3fe0ea0..fc4a838 100644 --- a/admin-frontend/src/utils/type.ts +++ b/admin-frontend/src/utils/type.ts @@ -19,7 +19,7 @@ export type LoginContextType = { export interface SubscribeConfig { platformName: string - target?: string + target: string targetName: string cats: Array tags: Array @@ -66,11 +66,3 @@ export interface SubscribeResp { export interface TargetNameResp { targetName: string } - -export interface CreateSubscribeReq { - platformName: string, - targetName: string, - target: string, - categories: Array, - tags: Array -} diff --git a/pyproject.toml b/pyproject.toml index ddeb53b..8193608 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,7 +33,6 @@ expiringdict = "^1.2.1" pyjwt = "^2.1.0" aiofiles = "^0.7.0" python-socketio = "^5.4.0" -jinja2 = "^3.0.1" [tool.poetry.dev-dependencies] ipdb = "^0.13.4" diff --git a/src/plugins/nonebot_bison/admin_page/__init__.py b/src/plugins/nonebot_bison/admin_page/__init__.py index 81b576e..01a1566 100644 --- a/src/plugins/nonebot_bison/admin_page/__init__.py +++ b/src/plugins/nonebot_bison/admin_page/__init__.py @@ -1,5 +1,7 @@ from dataclasses import dataclass from pathlib import Path +import os +from typing import Union from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates @@ -31,6 +33,17 @@ TEST_URL = f'{URL_BASE}test' sio = socketio.AsyncServer(async_mode="asgi", cors_allowed_origins="*") socket_app = socketio.ASGIApp(sio, socketio_path="socket") +class SinglePageApplication(StaticFiles): + + def __init__(self, directory: os.PathLike, index='index.html'): + self.index = index + super().__init__(directory=directory, packages=None, html=True, check_dir=True) + + async def lookup_path(self, path: str) -> tuple[str, Union[os.stat_result, None]]: + full_path, stat_res = await super().lookup_path(path) + if stat_res is None: + return await super().lookup_path(self.index) + return (full_path, stat_res) def register_router_fastapi(driver: Driver, socketio): from fastapi.security import OAuth2PasswordBearer @@ -61,7 +74,7 @@ def register_router_fastapi(driver: Driver, socketio): tags: list[str] app = driver.server_app - static_path = str((Path(__file__).parent / "dist").resolve()) + static_path = (Path(__file__).parent / "dist").resolve() app.get(TEST_URL)(test) app.get(GLOBAL_CONF_URL)(get_global_conf) app.get(AUTH_URL)(auth) @@ -76,15 +89,12 @@ def register_router_fastapi(driver: Driver, socketio): async def _add_group_subs(groupNumber: str, req: AddSubscribeReq): return await add_group_sub(group_number=groupNumber, platform_name=req.platformName, target=req.target, target_name=req.targetName, cats=req.categories, tags=req.tags) + @app.delete(SUBSCRIBE_URL, dependencies=[Depends(check_group_permission)]) async def _del_group_subs(groupNumber: str, target: str, platformName: str): return await del_group_sub(groupNumber, platformName, target) - app.mount(URL_BASE, StaticFiles(directory=static_path, html=True), name="bison") - templates = Jinja2Templates(directory=static_path) - @app.get(f'{URL_BASE}{{rest_path:path}}') - async def serve_sap(request: Request, rest_path: str): - return templates.TemplateResponse("index.html", {"request": request}) + app.mount(URL_BASE, SinglePageApplication(directory=static_path), name="bison") def init(): @@ -108,10 +118,6 @@ get_token = on_command('后台管理', rule=to_me(), priority=5) @get_token.handle() async def send_token(bot: "Bot", event: PrivateMessageEvent, state: T_State): driver = nonebot.get_driver() - superusers = driver.config.superusers - if event.get_user_id() not in superusers: - await get_token.finish('你不是管理员') - else: - token = tm.get_user_token((event.get_user_id(), event.sender.nickname)) - await get_token.finish(f'请访问: {plugin_config.bison_outer_url}auth/{token}') + token = tm.get_user_token((event.get_user_id(), event.sender.nickname)) + await get_token.finish(f'请访问: {plugin_config.bison_outer_url}auth/{token}') diff --git a/src/plugins/nonebot_bison/admin_page/api.py b/src/plugins/nonebot_bison/admin_page/api.py index de737c1..dcedbce 100644 --- a/src/plugins/nonebot_bison/admin_page/api.py +++ b/src/plugins/nonebot_bison/admin_page/api.py @@ -20,6 +20,17 @@ async def get_global_conf(): } return { 'platformConf': res } +async def get_admin_groups(qq: int): + bot = nonebot.get_bot() + groups = await bot.call_api('get_group_list') + res = [] + for group in groups: + group_id = group['group_id'] + users = await bot.call_api('get_group_member_list', group_id=group_id) + for user in users: + if user['user_id'] == qq and user['role'] in ('owner', 'admin'): + res.append({'id': group_id, 'name': group['group_name']}) + return res async def auth(token: str): if qq_tuple := token_manager.get_user(token): @@ -41,6 +52,18 @@ async def auth(token: str): 'token': pack_jwt(jwt_obj) } return { 'status': 200, **ret_obj } + if admin_groups := await get_admin_groups(int(qq)): + jwt_obj = { + 'id': str(qq), + 'groups': admin_groups + } + ret_obj = { + 'type': 'user', + 'name': nickname, + 'id': str(qq), + 'token': pack_jwt(jwt_obj) + } + return { 'status': 200, **ret_obj } else: return { 'status': 400, 'type': '', 'name': '', 'id': '', 'token': '' } else: