From 82a13ceb6622b4ffc21e8496a8f08368d1d3a49d Mon Sep 17 00:00:00 2001 From: felinae98 <731499577@qq.com> Date: Mon, 29 Nov 2021 12:10:54 +0800 Subject: [PATCH] finish first admin frontend --- admin-frontend/package.json | 2 +- admin-frontend/src/api/config.ts | 5 ++ .../addSubsModal.tsx} | 64 +++++++++++++------ admin-frontend/src/component/inputTag.tsx | 5 ++ .../src/component/subscribeCard.tsx | 16 +++-- .../src/pages/admin/configPage/index.tsx | 8 +-- .../nonebot_bison/admin_page/__init__.py | 9 ++- src/plugins/nonebot_bison/admin_page/api.py | 12 ++++ src/plugins/nonebot_bison/config.py | 21 +++++- tests/test_config_manager.py | 12 ++++ 10 files changed, 123 insertions(+), 31 deletions(-) rename admin-frontend/src/{pages/admin/configPage/AddSubsModal.tsx => component/addSubsModal.tsx} (74%) diff --git a/admin-frontend/package.json b/admin-frontend/package.json index dd0e164..dddd2ee 100644 --- a/admin-frontend/package.json +++ b/admin-frontend/package.json @@ -3,7 +3,7 @@ "version": "0.1.0", "private": true, "homepage": "bison", - "proxy": "http://localhost:8080", + "proxy": "http://127.0.0.1:8080", "dependencies": { "@ant-design/icons": "^4.6.4", "@testing-library/jest-dom": "^5.11.4", diff --git a/admin-frontend/src/api/config.ts b/admin-frontend/src/api/config.ts index ea88904..3286f74 100644 --- a/admin-frontend/src/api/config.ts +++ b/admin-frontend/src/api/config.ts @@ -31,3 +31,8 @@ export async function delSubscribe(groupNumber: string, platformName: string, ta const res = await axios.delete(`${baseUrl}subs`, {params: {groupNumber, platformName, target}}); return res.data; } + +export async function updateSubscribe(groupNumber: string, req: SubscribeConfig) { + return axios.patch(`${baseUrl}subs`, req, {params: {groupNumber}}) + .then(res => res.data); +} diff --git a/admin-frontend/src/pages/admin/configPage/AddSubsModal.tsx b/admin-frontend/src/component/addSubsModal.tsx similarity index 74% rename from admin-frontend/src/pages/admin/configPage/AddSubsModal.tsx rename to admin-frontend/src/component/addSubsModal.tsx index 22f70cf..a1238d8 100644 --- a/admin-frontend/src/pages/admin/configPage/AddSubsModal.tsx +++ b/admin-frontend/src/component/addSubsModal.tsx @@ -1,9 +1,9 @@ -import { Form, Input, Modal, Select, Tag } from 'antd'; -import React, { useContext, useState } from "react"; -import { addSubscribe, getTargetName } from 'src/api/config'; -import { InputTag } from 'src/component/inputTag'; -import { GlobalConfContext } from "src/utils/context"; -import { CategoryConfig } from 'src/utils/type'; +import {Form, Input, Modal, Select, Tag} from 'antd'; +import React, {useContext, useEffect, useState} from "react"; +import {addSubscribe, getTargetName, updateSubscribe} from 'src/api/config'; +import {InputTag} from 'src/component/inputTag'; +import {GlobalConfContext} from "src/utils/context"; +import {CategoryConfig, SubscribeConfig} from 'src/utils/type'; interface InputTagCustomProp { value?: Array<string>, @@ -18,6 +18,11 @@ function InputTagCustom(prop: InputTagCustomProp) { prop.onChange(newVal); } } + useEffect(() => { + if (prop.value) { + setValue(prop.value); + } + }, [prop.value]) return ( <> { @@ -38,14 +43,18 @@ interface AddModalProp { groupNumber: string, setShowModal: (s: boolean) => void, refresh: () => void + initVal?: SubscribeConfig } -export function AddModal(prop: AddModalProp) { +export function AddModal({ + showModal, groupNumber, setShowModal, refresh, initVal +}: AddModalProp) { const [ confirmLoading, setConfirmLoading ] = useState<boolean>(false); const { platformConf } = useContext(GlobalConfContext); const [ hasTarget, setHasTarget ] = useState(false); const [ categories, setCategories ] = useState({} as CategoryConfig); const [ enabledTag, setEnableTag ] = useState(false); const [ form ] = Form.useForm(); + const [ inited, setInited ] = useState(false); const changePlatformSelect = (platform: string) => { setHasTarget(_ => platformConf[platform].hasTarget); setCategories(_ => platformConf[platform].categories); @@ -74,23 +83,42 @@ export function AddModal(prop: AddModalProp) { if (newVal.target === '') { newVal.target = 'default' } - addSubscribe(prop.groupNumber, newVal) - .then(() => { - setConfirmLoading(false); - prop.setShowModal(false); - prop.refresh(); - }); + if (initVal) { // patch + updateSubscribe(groupNumber, newVal) + .then(() => { + setConfirmLoading(false); + setShowModal(false); + form.resetFields(); + refresh(); + }); + } else { + addSubscribe(groupNumber, newVal) + .then(() => { + setConfirmLoading(false); + setShowModal(false); + form.resetFields(); + refresh(); + }); + } } const handleModleFinish = () => { form.submit(); setConfirmLoading(() => true); } - - return <Modal title="添加订阅" visible={prop.showModal} - confirmLoading={confirmLoading} onCancel={() => prop.setShowModal(false)} + useEffect(() => { + if (initVal && !inited) { + const platformName = initVal.platformName; + setHasTarget(platformConf[platformName].hasTarget); + setCategories(platformConf[platformName].categories); + setEnableTag(platformConf[platformName].enabledTag); + setInited(true) + form.setFieldsValue(initVal) + } + }, [initVal, form, platformConf, inited]) + return <Modal title="添加订阅" visible={showModal} + confirmLoading={confirmLoading} onCancel={() => setShowModal(false)} onOk={handleModleFinish}> - <Form form={form} labelCol={{ span: 6 }} name="b" onFinish={handleSubmit} - initialValues={{tags: [], cats: []}}> + <Form form={form} labelCol={{ span: 6 }} name="b" onFinish={handleSubmit} > <Form.Item label="平台" name="platformName" rules={[]}> <Select style={{ width: '80%' }} onChange={changePlatformSelect}> {Object.keys(platformConf).map(platformName => diff --git a/admin-frontend/src/component/inputTag.tsx b/admin-frontend/src/component/inputTag.tsx index 140e46a..9408a61 100644 --- a/admin-frontend/src/component/inputTag.tsx +++ b/admin-frontend/src/component/inputTag.tsx @@ -18,6 +18,11 @@ export function InputTag(prop: InputTagProp) { const [ editInputValue, setEditInputValue ] = useState(''); const inputRef = useRef(null as any); const editInputRef = useRef(null as any); + useEffect(() => { + if (prop.value) { + setValue(prop.value); + } + }, [prop.value]) useEffect(() => { if (inputVisible) { inputRef.current.focus() diff --git a/admin-frontend/src/component/subscribeCard.tsx b/admin-frontend/src/component/subscribeCard.tsx index 62dbb1b..1f5b407 100644 --- a/admin-frontend/src/component/subscribeCard.tsx +++ b/admin-frontend/src/component/subscribeCard.tsx @@ -1,10 +1,11 @@ -import {CopyOutlined, DeleteOutlined} from '@ant-design/icons'; +import {CopyOutlined, DeleteOutlined, EditOutlined} from '@ant-design/icons'; import {Card, Col, Form, message, Popconfirm, Select, Tag, Tooltip} from 'antd'; import Modal from 'antd/lib/modal/Modal'; import React, {useContext, useState} from "react"; import {addSubscribe, delSubscribe} from 'src/api/config'; import {GlobalConfContext} from "src/utils/context"; import {PlatformConfig, SubscribeConfig, SubscribeResp} from 'src/utils/type'; +import {AddModal} from './addSubsModal'; interface CopyModalProp { setShowModal: (modalShow: boolean) => void @@ -30,6 +31,7 @@ function CopyModal({setShowModal,config, setConfirmLoading(true) postReqs(selectedGroups, config).then(() => { setConfirmLoading(false) + setShowModal(false) return reload() }) } @@ -57,6 +59,7 @@ interface SubscribeCardProp { export function SubscribeCard({groupNumber, config, reload, groupSubscribes}: SubscribeCardProp) { const globalConf = useContext(GlobalConfContext); const [showModal, setShowModal] = useState(false) + const [showEditModal, setShowEditModal] = useState(false) const platformConf = globalConf.platformConf[config.platformName] as PlatformConfig; const handleDelete = (groupNumber: string, platformName: string, target: string) => () => { delSubscribe(groupNumber, platformName, target).then(() => { @@ -67,13 +70,16 @@ export function SubscribeCard({groupNumber, config, reload, groupSubscribes}: Su <Col span={6} key={`${config.platformName}-${config.target}`}> <Card title={`${platformConf.name} - ${config.targetName}`} actions={[ + <Tooltip title="编辑"> + <EditOutlined onClick={()=>{setShowEditModal(state => !state)}}/> + </Tooltip>, + <Tooltip title="添加到其他群"> + <CopyOutlined onClick={()=>{setShowModal(state => !state)}}/> + </Tooltip>, <Popconfirm title={`确定要删除 ${platformConf.name} - ${config.targetName}`} onConfirm={handleDelete(groupNumber, config.platformName, config.target || 'default')}> <Tooltip title="删除" ><DeleteOutlined /></Tooltip> </Popconfirm>, - <Tooltip title="添加到其他群"> - <CopyOutlined onClick={()=>{setShowModal(state => !state)}}/> - </Tooltip> ]}> <Form labelCol={{ span: 6 }}> <Form.Item label="订阅类型"> @@ -89,6 +95,8 @@ export function SubscribeCard({groupNumber, config, reload, groupSubscribes}: Su </Card> <CopyModal setShowModal={setShowModal} reload={reload} currentGroupNumber={groupNumber} showModal={showModal} config={config} groups={groupSubscribes}/> + <AddModal showModal={showEditModal} setShowModal={setShowEditModal} + groupNumber={groupNumber} refresh={reload} initVal={config}/> </Col> ) } diff --git a/admin-frontend/src/pages/admin/configPage/index.tsx b/admin-frontend/src/pages/admin/configPage/index.tsx index a6cfacc..66b1160 100644 --- a/admin-frontend/src/pages/admin/configPage/index.tsx +++ b/admin-frontend/src/pages/admin/configPage/index.tsx @@ -3,7 +3,7 @@ import React, {ReactElement, useEffect, useState} from "react"; import {getSubscribe} from 'src/api/config'; import {SubscribeCard} from 'src/component/subscribeCard'; import {SubscribeResp} from 'src/utils/type'; -import {AddModal} from './AddSubsModal'; +import {AddModal} from 'src/component/addSubsModal'; interface ConfigPageProp { tab: string @@ -34,11 +34,11 @@ export function ConfigPage(prop: ConfigPageProp) { for (let key of Object.keys(configData)) { let value = configData[key]; groups.push( - <Collapse.Panel header={ + <Collapse.Panel key={key} header={ <span>{`${key} - ${value.name}`}<Button style={{float: "right"}} onClick={clickNew(key)}>添加</Button></span> - } key={key}> + }> <Row gutter={{ xs: 8, sm: 16, md: 24, lg: 32 }} align="middle"> - {value.subscribes.map((subs) => <SubscribeCard + {value.subscribes.map((subs, idx) => <SubscribeCard key={idx} groupNumber={key} config={subs} groupSubscribes={configData} reload={loadData} />)} </Row> diff --git a/src/plugins/nonebot_bison/admin_page/__init__.py b/src/plugins/nonebot_bison/admin_page/__init__.py index 4a3e845..f880516 100644 --- a/src/plugins/nonebot_bison/admin_page/__init__.py +++ b/src/plugins/nonebot_bison/admin_page/__init__.py @@ -18,7 +18,7 @@ import functools from starlette.requests import Request -from .api import del_group_sub, test, get_global_conf, auth, get_subs_info, get_target_name, add_group_sub +from .api import del_group_sub, test, get_global_conf, auth, get_subs_info, get_target_name, add_group_sub, update_group_sub from .token_manager import token_manager as tm from .jwt import load_jwt from ..plugin_config import plugin_config @@ -72,7 +72,7 @@ def register_router_fastapi(driver: Driver, socketio): platformName: str target: str targetName: str - cats: list[str] + cats: list[int] tags: list[str] app = driver.server_app @@ -91,7 +91,10 @@ 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.cats, tags=req.tags) - + @app.patch(SUBSCRIBE_URL, dependencies=[Depends(check_group_permission)]) + async def _update_group_subs(groupNumber: str, 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: str, target: str, platformName: str): return await del_group_sub(groupNumber, platformName, target) diff --git a/src/plugins/nonebot_bison/admin_page/api.py b/src/plugins/nonebot_bison/admin_page/api.py index dcedbce..e23a669 100644 --- a/src/plugins/nonebot_bison/admin_page/api.py +++ b/src/plugins/nonebot_bison/admin_page/api.py @@ -100,3 +100,15 @@ async def del_group_sub(group_number: str, platform_name: str, target: str): except (NoSuchUserException, NoSuchSubscribeException): return { 'status': 400, 'msg': '删除错误' } return { 'status': 200, 'msg': '' } + + +async def update_group_sub(group_number: str, platform_name: str, target: str, + target_name: str, cats: list[str], tags: list[str]): + config = Config() + try: + config.update_subscribe(int(group_number), 'group', + target, target_name, platform_name, cats, tags) + except (NoSuchUserException, NoSuchSubscribeException): + return { 'status': 400, 'msg': '更新错误' } + return { 'status': 200, 'msg': '' } + diff --git a/src/plugins/nonebot_bison/config.py b/src/plugins/nonebot_bison/config.py index d34af47..3afa955 100644 --- a/src/plugins/nonebot_bison/config.py +++ b/src/plugins/nonebot_bison/config.py @@ -6,10 +6,10 @@ from typing import DefaultDict, Mapping import nonebot from tinydb import Query, TinyDB +from .platform import platform_manager from .plugin_config import plugin_config from .types import Target, User from .utils import Singleton -from .platform import platform_manager supported_target_type = platform_manager.keys() @@ -86,6 +86,25 @@ class Config(metaclass=Singleton): return raise NoSuchSubscribeException() + def update_subscribe(self, user, user_type, target, target_name, target_type, cats, tags): + user_query = Query() + query = (user_query.user == user) & (user_query.user_type == user_type) + if (user_data := self.user_target.get(query)): + # update + subs: list = user_data.get('subs', []) + find_flag = False + for item in subs: + if item['target'] == target and item['target_type'] == target_type: + item['target_name'], item['cats'], item['tags'] = \ + target_name, cats, tags + find_flag = True + break + if not find_flag: + raise NoSuchSubscribeException() + self.user_target.update({"subs": subs}, query) + else: + raise NoSuchUserException() + def update_send_cache(self): res = {target_type: defaultdict(list) for target_type in supported_target_type} cat_res = {target_type: defaultdict(lambda: defaultdict(list)) for target_type in supported_target_type} diff --git a/tests/test_config_manager.py b/tests/test_config_manager.py index cff94fa..5ae7fe2 100644 --- a/tests/test_config_manager.py +++ b/tests/test_config_manager.py @@ -24,3 +24,15 @@ def test_create_and_get(config: 'nonebot_bison.config.Config', plugin_module: 'n assert(len(confs) == 1) assert(config.target_user_cache['weibo']['weibo_id'] == \ [plugin_module.types.User('123', 'group')]) + assert(confs[0]['cats'] == []) + config.update_subscribe( + user='123', + user_type='group', + target='weibo_id', + target_name='weibo_name', + target_type='weibo', + cats=['1'], + tags=[]) + confs = config.list_subscribe('123', 'group') + assert(len(confs) == 1) + assert(confs[0]['cats'] == ['1'])