From e5479c0dc60080175a85684d7022076a9428249d Mon Sep 17 00:00:00 2001 From: felinae98 <731499577@qq.com> Date: Fri, 25 Feb 2022 17:28:45 +0800 Subject: [PATCH 1/6] install root in dockerfile --- docker/Dockerfile_with_frontend | 2 +- docker/Dockerfile_with_frontend_sentry | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile_with_frontend b/docker/Dockerfile_with_frontend index 69ad203..ec5b8f3 100644 --- a/docker/Dockerfile_with_frontend +++ b/docker/Dockerfile_with_frontend @@ -10,7 +10,7 @@ RUN apt-get update && apt-get install -y xvfb fonts-noto-color-emoji ttf-unifont libxdamage1 libxext6 libxfixes3 libxrandr2 libxshmfence1 \ && rm -rf /var/lib/apt/lists/* COPY ./pyproject.toml ./poetry.lock* /app/ -RUN poetry install --no-root --no-dev +RUN poetry install --no-dev RUN playwright install chromium ADD src /app/src ADD bot.py /app/ diff --git a/docker/Dockerfile_with_frontend_sentry b/docker/Dockerfile_with_frontend_sentry index c14f88a..e947337 100644 --- a/docker/Dockerfile_with_frontend_sentry +++ b/docker/Dockerfile_with_frontend_sentry @@ -12,7 +12,7 @@ RUN apt-get update && apt-get install -y xvfb fonts-noto-color-emoji ttf-unifont COPY ./pyproject.toml ./poetry.lock* ./bot.py /app/ RUN poetry add nonebot-plugin-sentry && \ sed '/nonebot.load_builtin_plugins("echo")/a nonebot.load_plugin("nonebot_plugin_sentry")' -i bot.py -RUN poetry install --no-root --no-dev +RUN poetry install --no-dev RUN playwright install chromium ADD src /app/src ENV HOST=0.0.0.0 From 0c4a85481db7cb81ebd20636058ccd9c91662d33 Mon Sep 17 00:00:00 2001 From: felinae98 <731499577@qq.com> Date: Sun, 27 Feb 2022 17:06:39 +0800 Subject: [PATCH 2/6] remove help plugin dependence --- poetry.lock | 33 +-------------------------------- pyproject.toml | 1 - 2 files changed, 1 insertion(+), 33 deletions(-) diff --git a/poetry.lock b/poetry.lock index 3d38f3f..beee8da 100644 --- a/poetry.lock +++ b/poetry.lock @@ -674,17 +674,6 @@ category = "dev" optional = false python-versions = "*" -[[package]] -name = "nonebot-adapter-cqhttp" -version = "2.0.0b1" -description = "OneBot(CQHTTP) adapter for nonebot2" -category = "main" -optional = false -python-versions = ">=3.7.3,<4.0.0" - -[package.dependencies] -nonebot-adapter-onebot = "*" - [[package]] name = "nonebot-adapter-onebot" version = "2.0.0b1" @@ -696,18 +685,6 @@ python-versions = ">=3.7.3,<4.0.0" [package.dependencies] nonebot2 = ">=2.0.0-beta.1,<3.0.0" -[[package]] -name = "nonebot-plugin-help" -version = "0.1.5" -description = "A general help lister for nonebot2 plugins" -category = "main" -optional = false -python-versions = ">=3.7.3,<4.0.0" - -[package.dependencies] -nonebot-adapter-cqhttp = ">=2.0.0a16,<3.0.0" -nonebot2 = ">=2.0.0.a16,<3.0.0" - [[package]] name = "nonebot-plugin-htmlrender" version = "0.0.4.4" @@ -1478,7 +1455,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest- [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "f88c634c00a931916dac64439956d6ce31a2de0640a5f65c790008f7d6717123" +content-hash = "7dbb53c4a2386da480678e34620664651cf61dd754dd3dae7b6e8e8a56c04b9d" [metadata.files] aiofiles = [ @@ -1931,18 +1908,10 @@ nodeenv = [ {file = "nodeenv-1.6.0-py2.py3-none-any.whl", hash = "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"}, {file = "nodeenv-1.6.0.tar.gz", hash = "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b"}, ] -nonebot-adapter-cqhttp = [ - {file = "nonebot-adapter-cqhttp-2.0.0b1.tar.gz", hash = "sha256:57a27c5c6b47bd77dbaddaf063738c0548110424f559deca2e37654814f122d0"}, - {file = "nonebot_adapter_cqhttp-2.0.0b1-py3-none-any.whl", hash = "sha256:09433d0d91cfbae42acd1e1ffab96d51e8949ed979d39eff142916fcc27698ab"}, -] nonebot-adapter-onebot = [ {file = "nonebot-adapter-onebot-2.0.0b1.tar.gz", hash = "sha256:9dad770371e577fead096ceacacc43b3ef304a8e238e8fff1163eefc4e947a75"}, {file = "nonebot_adapter_onebot-2.0.0b1-py3-none-any.whl", hash = "sha256:ca1375de1dd503a5ab20440445026195b587e05a2b18ae8df9b6ab17c9e857b5"}, ] -nonebot-plugin-help = [ - {file = "nonebot-plugin-help-0.1.5.tar.gz", hash = "sha256:2ef8c0f8b578c7941e364396532749cabb4d52872ddc4a0419db3cd103223e60"}, - {file = "nonebot_plugin_help-0.1.5-py3-none-any.whl", hash = "sha256:1c4bb626feb202515f47311e3ca9872ab6c0db5e935bc9561325fcc1a2591511"}, -] nonebot-plugin-htmlrender = [ {file = "nonebot-plugin-htmlrender-0.0.4.4.tar.gz", hash = "sha256:da278a9a0dfb6b268083c3223e385d153d34c933cbf21e3c4948724d5c28d8ff"}, {file = "nonebot_plugin_htmlrender-0.0.4.4-py3-none-any.whl", hash = "sha256:e3dbb2bb7afd529b3958aedefab42570a28e924ef7417f0e57c734037def37a4"}, diff --git a/pyproject.toml b/pyproject.toml index 262c658..cb70049 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,6 @@ expiringdict = "^1.2.1" pyjwt = "^2.1.0" aiofiles = "^0.8.0" python-socketio = "^5.4.0" -nonebot-plugin-help = "^0.1.5" nonebot-adapter-onebot = "^2.0.0-beta.1" nonebot-plugin-htmlrender = "^0.0.4" From cc44e4588739e68c1edaea5fcd9a2ee17680160d Mon Sep 17 00:00:00 2001 From: felinae98 <731499577@qq.com> Date: Wed, 2 Mar 2022 11:33:14 +0800 Subject: [PATCH 3/6] update group admin --- poetry.lock | 51 ++--- pyproject.toml | 7 +- src/plugins/nonebot_bison/config_manager.py | 218 ++++++++++++++++---- src/plugins/nonebot_bison/types.py | 2 +- tests/conftest.py | 25 ++- tests/test_config_manager.py | 14 ++ tests/test_config_manager_admin.py | 45 ++++ tests/utils.py | 1 + 8 files changed, 289 insertions(+), 74 deletions(-) create mode 100644 tests/test_config_manager_admin.py diff --git a/poetry.lock b/poetry.lock index beee8da..69aae51 100644 --- a/poetry.lock +++ b/poetry.lock @@ -735,15 +735,21 @@ version = "0.2.1" description = "nonebot2 test framework" category = "dev" optional = false -python-versions = ">=3.7.3,<4.0.0" +python-versions = "^3.7.3" +develop = false [package.dependencies] -asgiref = ">=3.4.0,<4.0.0" -async-asgi-testclient = ">=1.4.8,<2.0.0" -nonebot2 = ">=2.0.0-beta.1,<3.0.0" -pytest = ">=6.2.5,<7.0.0" -pytest-asyncio = ">=0.16.0,<0.17.0" -typing-extensions = ">=4.0.0,<5.0.0" +asgiref = "^3.4.0" +async-asgi-testclient = "^1.4.8" +nonebot2 = "^2.0.0-beta.1" +pytest = "^7.0.0" +typing-extensions = "^4.0.0" + +[package.source] +type = "git" +url = "https://github.com/nonebot/nonebug.git" +reference = "40fcd4f" +resolved_reference = "40fcd4f3eff8f4b2118e95938fabc3d77ff6819c" [[package]] name = "packaging" @@ -988,7 +994,7 @@ diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "pytest" -version = "6.2.5" +version = "7.0.1" description = "pytest: simple powerful testing with Python" category = "dev" optional = false @@ -1002,24 +1008,24 @@ iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" py = ">=1.8.2" -toml = "*" +tomli = ">=1.0.0" [package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] [[package]] name = "pytest-asyncio" -version = "0.16.0" -description = "Pytest support for asyncio." +version = "0.18.1" +description = "Pytest support for asyncio" category = "dev" optional = false -python-versions = ">= 3.6" +python-versions = ">=3.7" [package.dependencies] -pytest = ">=5.4.0" +pytest = ">=6.1.0" [package.extras] -testing = ["coverage", "hypothesis (>=5.7.1)"] +testing = ["coverage (==6.2)", "hypothesis (>=5.7.1)", "flaky (>=3.5.0)", "mypy (==0.931)"] [[package]] name = "pytest-cov" @@ -1455,7 +1461,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest- [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "7dbb53c4a2386da480678e34620664651cf61dd754dd3dae7b6e8e8a56c04b9d" +content-hash = "4a0d093b99ca03d9e9effe113ccd85daf9242c0a95f2336d2af8fcc7e764b6ce" [metadata.files] aiofiles = [ @@ -1920,10 +1926,7 @@ nonebot2 = [ {file = "nonebot2-2.0.0b2-py3-none-any.whl", hash = "sha256:8166490311b607f8fbf5e31934b005e29f6d39ff222a6771ec36c9456ec337ec"}, {file = "nonebot2-2.0.0b2.tar.gz", hash = "sha256:2950f27a62f2a98b2abf3128c19d898a24c2867e70fb5c6af231eadf558b18a8"}, ] -nonebug = [ - {file = "nonebug-0.2.1-py3-none-any.whl", hash = "sha256:f4d59effd50e400ee866df57902e4d749227a76857be26a0607fc2a5f6a05f7c"}, - {file = "nonebug-0.2.1.tar.gz", hash = "sha256:2f363bd5d65081c802b7b19a72b07ada1ad8e61968cf313176f38a5cf97e84e2"}, -] +nonebug = [] packaging = [ {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, @@ -2093,12 +2096,12 @@ pyparsing = [ {file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"}, ] pytest = [ - {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, - {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, + {file = "pytest-7.0.1-py3-none-any.whl", hash = "sha256:9ce3ff477af913ecf6321fe337b93a2c0dcf2a0a1439c43f5452112c1e4280db"}, + {file = "pytest-7.0.1.tar.gz", hash = "sha256:e30905a0c131d3d94b89624a1cc5afec3e0ba2fbdb151867d8e0ebd49850f171"}, ] pytest-asyncio = [ - {file = "pytest-asyncio-0.16.0.tar.gz", hash = "sha256:7496c5977ce88c34379df64a66459fe395cd05543f0a2f837016e7144391fcfb"}, - {file = "pytest_asyncio-0.16.0-py3-none-any.whl", hash = "sha256:5f2a21273c47b331ae6aa5b36087047b4899e40f03f18397c0e65fa5cca54e9b"}, + {file = "pytest-asyncio-0.18.1.tar.gz", hash = "sha256:c43fcdfea2335dd82ffe0f2774e40285ddfea78a8e81e56118d47b6a90fbb09e"}, + {file = "pytest_asyncio-0.18.1-py3-none-any.whl", hash = "sha256:c9ec48e8bbf5cc62755e18c4d8bc6907843ec9c5f4ac8f61464093baeba24a7e"}, ] pytest-cov = [ {file = "pytest-cov-3.0.0.tar.gz", hash = "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"}, diff --git a/pyproject.toml b/pyproject.toml index cb70049..1a2b388 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,11 +40,11 @@ nonebot-plugin-htmlrender = "^0.0.4" [tool.poetry.dev-dependencies] ipdb = "^0.13.4" -pytest = "^6.2.4" -pytest-asyncio = "^0.16" +pytest = "^7.0.1" +pytest-asyncio = "^0.18.1" respx = "^0.19.0" pytest-cov = "^3.0.0" -nonebug = "^0.2.0" +nonebug = {git = "https://github.com/nonebot/nonebug.git", rev = "40fcd4f"} black = "^22.1.0" isort = "^5.10.1" pre-commit = "^2.17.0" @@ -59,6 +59,7 @@ markers = [ "compare: compare fetching result with rsshub", "render: render img by chrome" ] +asyncio_mode = "auto" [tool.black] line-length = 88 diff --git a/src/plugins/nonebot_bison/config_manager.py b/src/plugins/nonebot_bison/config_manager.py index 7836121..ee5ebf9 100644 --- a/src/plugins/nonebot_bison/config_manager.py +++ b/src/plugins/nonebot_bison/config_manager.py @@ -1,13 +1,18 @@ -from typing import Type +import asyncio +from asyncio.tasks import Task +from datetime import datetime +from typing import Optional, Type from nonebot import on_command -from nonebot.adapters import Event as AbstractEvent -from nonebot.adapters.onebot.v11 import Bot, Event +from nonebot.adapters.onebot.v11 import Bot, Event, MessageEvent +from nonebot.adapters.onebot.v11.event import GroupMessageEvent, PrivateMessageEvent from nonebot.adapters.onebot.v11.message import Message from nonebot.adapters.onebot.v11.permission import GROUP_ADMIN, GROUP_OWNER +from nonebot.internal.params import ArgStr from nonebot.internal.rule import Rule +from nonebot.log import logger from nonebot.matcher import Matcher -from nonebot.params import Depends, EventToMe +from nonebot.params import Depends, EventMessage, EventPlainText, EventToMe from nonebot.permission import SUPERUSER from nonebot.rule import to_me from nonebot.typing import T_State @@ -15,7 +20,7 @@ from nonebot.typing import T_State from .config import Config from .platform import check_sub_target, platform_manager from .plugin_config import plugin_config -from .types import Category, Target +from .types import Category, Target, User from .utils import parse_text @@ -44,7 +49,28 @@ common_platform = [ ] +def ensure_user_info(matcher: Type[Matcher]): + async def _check_user_info(state: T_State): + if not state.get("target_user_info"): + await matcher.finish( + "No target_user_info set, this shouldn't happen, please issue" + ) + + return _check_user_info + + +async def set_target_user_info(event: MessageEvent, state: T_State): + if isinstance(event, GroupMessageEvent): + user = User(event.group_id, "group") + state["target_user_info"] = user + elif isinstance(event, PrivateMessageEvent): + user = User(event.user_id, "private") + state["target_user_info"] = user + + def do_add_sub(add_sub: Type[Matcher]): + add_sub.handle()(ensure_user_info(add_sub)) + @add_sub.handle() async def init_promote(state: T_State): state["_prompt"] = ( @@ -60,7 +86,7 @@ def do_add_sub(add_sub: Type[Matcher]): + "要查看全部平台请输入:“全部”" ) - async def parse_platform(event: AbstractEvent, state: T_State) -> None: + async def parse_platform(event: MessageEvent, state: T_State) -> None: if not isinstance(state["platform"], Message): return platform = str(event.get_message()).strip() @@ -91,7 +117,7 @@ def do_add_sub(add_sub: Type[Matcher]): Target("") ) - async def parse_id(event: AbstractEvent, state: T_State): + async def parse_id(event: MessageEvent, state: T_State): if not isinstance(state["id"], Message): return target = str(event.get_message()).strip() @@ -113,7 +139,7 @@ def do_add_sub(add_sub: Type[Matcher]): " ".join(list(platform_manager[state["platform"]].categories.values())) ) - async def parser_cats(event: AbstractEvent, state: T_State): + async def parser_cats(event: MessageEvent, state: T_State): if not isinstance(state["cats"], Message): return res = [] @@ -130,7 +156,7 @@ def do_add_sub(add_sub: Type[Matcher]): return state["_prompt"] = '请输入要订阅的tag,订阅所有tag输入"全部标签"' - async def parser_tags(event: AbstractEvent, state: T_State): + async def parser_tags(event: MessageEvent, state: T_State): if not isinstance(state["tags"], Message): return if str(event.get_message()).strip() == "全部标签": @@ -141,9 +167,13 @@ def do_add_sub(add_sub: Type[Matcher]): @add_sub.got("tags", _gen_prompt_template("{_prompt}"), [Depends(parser_tags)]) async def add_sub_process(event: Event, state: T_State): config = Config() + user = state.get("target_user_info") + assert isinstance(user, User) config.add_subscribe( - state.get("_user_id") or event.group_id, - user_type="group", + # state.get("_user_id") or event.group_id, + # user_type="group", + user=user.user, + user_type=user.user_type, target=state["id"], target_name=state["name"], target_type=state["platform"], @@ -154,11 +184,17 @@ def do_add_sub(add_sub: Type[Matcher]): def do_query_sub(query_sub: Type[Matcher]): + query_sub.handle()(ensure_user_info(query_sub)) + @query_sub.handle() - async def _(event: Event, state: T_State): + async def _(state: T_State): config: Config = Config() + user_info = state["target_user_info"] + assert isinstance(user_info, User) sub_list = config.list_subscribe( - state.get("_user_id") or event.group_id, "group" + # state.get("_user_id") or event.group_id, "group" + user_info.user, + user_info.user_type, ) res = "订阅的帐号为:\n" for sub in sub_list: @@ -179,11 +215,17 @@ def do_query_sub(query_sub: Type[Matcher]): def do_del_sub(del_sub: Type[Matcher]): + del_sub.handle()(ensure_user_info(del_sub)) + @del_sub.handle() async def send_list(bot: Bot, event: Event, state: T_State): config: Config = Config() + user_info = state["target_user_info"] + assert isinstance(user_info, User) sub_list = config.list_subscribe( - state.get("_user_id") or event.group_id, "group" + # state.get("_user_id") or event.group_id, "group" + user_info.user, + user_info.user_type, ) res = "订阅的帐号为:\n" state["sub_table"] = {} @@ -213,9 +255,13 @@ def do_del_sub(del_sub: Type[Matcher]): try: index = int(str(event.get_message()).strip()) config = Config() + user_info = state["target_user_info"] + assert isinstance(user_info, User) config.del_subscribe( - state.get("_user_id") or event.group_id, - "group", + # state.get("_user_id") or event.group_id, + # "group", + user_info.user, + user_info.user_type, **state["sub_table"][index], ) except Exception as e: @@ -224,41 +270,19 @@ def do_del_sub(del_sub: Type[Matcher]): await del_sub.finish("删除成功") -async def parse_group_number(event: AbstractEvent, state: T_State): - if not isinstance(state["_user_id"], Message): - return - state["_user_id"] = int(str(event.get_message())) - - add_sub_matcher = on_command( "添加订阅", rule=configurable_to_me, permission=GROUP_ADMIN | GROUP_OWNER | SUPERUSER, priority=5, ) +add_sub_matcher.handle()(set_target_user_info) do_add_sub(add_sub_matcher) -manage_add_sub_matcher = on_command("管理-添加订阅", permission=SUPERUSER, priority=5) - - -@manage_add_sub_matcher.got("_user_id", "群号", [Depends(parse_group_number)]) -async def add_sub_handle(): - pass - - -do_add_sub(manage_add_sub_matcher) query_sub_matcher = on_command("查询订阅", rule=configurable_to_me, priority=5) +query_sub_matcher.handle()(set_target_user_info) do_query_sub(query_sub_matcher) -manage_query_sub_matcher = on_command("管理-查询订阅", permission=SUPERUSER, priority=5) - - -@manage_query_sub_matcher.got("_user_id", "群号", [Depends(parse_group_number)]) -async def query_sub_handle(): - pass - - -do_query_sub(manage_query_sub_matcher) del_sub_matcher = on_command( @@ -267,13 +291,117 @@ del_sub_matcher = on_command( permission=GROUP_ADMIN | GROUP_OWNER | SUPERUSER, priority=5, ) +del_sub_matcher.handle()(set_target_user_info) do_del_sub(del_sub_matcher) -manage_del_sub_matcher = on_command("管理-删除订阅", permission=SUPERUSER, priority=5) + +group_manage_matcher = on_command("群管理") -@manage_del_sub_matcher.got("_user_id", "群号", [Depends(parse_group_number)]) -async def del_sub_handle(): - pass +@group_manage_matcher.handle() +async def send_group_list(bot: Bot, state: T_State): + groups = await bot.call_api("get_group_list") + res_text = "请选择需要管理的群:\n" + group_number_idx = {} + for idx, group in enumerate(groups, 1): + group_number_idx[idx] = group["group_id"] + res_text += f'{idx}. {group["group_id"]} - {group["group_name"]}\n' + res_text += "请输入左侧序号" + # await group_manage_matcher.send(res_text) + state["_prompt"] = res_text + state["group_number_idx"] = group_number_idx -do_del_sub(manage_del_sub_matcher) +async def _parse_group_idx(state: T_State, event_msg: str = EventPlainText()): + if not isinstance(state["group_idx"], Message): + return + group_number_idx: Optional[dict[int, int]] = state.get("group_number_idx") + assert group_number_idx + try: + idx = int(event_msg) + assert idx in group_number_idx.keys() + state["group_idx"] = idx + except: + await group_manage_matcher.reject("请输入正确序号") + + +@group_manage_matcher.got( + "group_idx", _gen_prompt_template("{_prompt}"), [Depends(_parse_group_idx)] +) +async def do_choose_group_number(state: T_State): + group_number_idx: dict[int, int] = state["group_number_idx"] + idx: int = state["group_idx"] + group_id = group_number_idx[idx] + state["target_user_info"] = User(user=group_id, user_type="group") + + +async def _check_command(event_msg: str = EventPlainText()): + if event_msg not in {"添加订阅", "查询订阅", "删除订阅"}: + await group_manage_matcher.reject("请输入正确的命令") + return + + +@group_manage_matcher.got( + "command", "请输入需要使用的命令:添加订阅,查询订阅,删除订阅", [Depends(_check_command)] +) +async def do_dispatch_command( + bot: Bot, + event: MessageEvent, + state: T_State, + matcher: Matcher, + command: str = ArgStr(), +): + permission = await matcher.update_permission(bot, event) + new_matcher = Matcher.new( + "message", + Rule(), + permission, + None, + True, + priority=0, + block=True, + plugin=matcher.plugin, + module=matcher.module, + expire_time=datetime.now() + bot.config.session_expire_timeout, + default_state=matcher.state, + default_type_updater=matcher.__class__._default_type_updater, + default_permission_updater=matcher.__class__._default_permission_updater, + ) + if command == "查询订阅": + do_query_sub(new_matcher) + elif command == "添加订阅": + do_add_sub(new_matcher) + else: + do_del_sub(new_matcher) + new_matcher_ins = new_matcher() + asyncio.create_task(new_matcher_ins.run(bot, event, state)) + + +test_matcher = on_command("testtt") + + +@test_matcher.handle() +async def _handler(bot: Bot, event: Event, matcher: Matcher, state: T_State): + permission = await matcher.update_permission(bot, event) + new_matcher = Matcher.new( + "message", + Rule(), + permission, + None, + True, + priority=0, + block=True, + plugin=matcher.plugin, + module=matcher.module, + expire_time=datetime.now() + bot.config.session_expire_timeout, + default_state=matcher.state, + default_type_updater=matcher.__class__._default_type_updater, + default_permission_updater=matcher.__class__._default_permission_updater, + ) + + async def h(): + logger.warning("yes") + await new_matcher.send("666") + + new_matcher.handle()(h) + new_matcher_ins = new_matcher() + await new_matcher_ins.run(bot, event, state) diff --git a/src/plugins/nonebot_bison/types.py b/src/plugins/nonebot_bison/types.py index f447f38..734d877 100644 --- a/src/plugins/nonebot_bison/types.py +++ b/src/plugins/nonebot_bison/types.py @@ -9,7 +9,7 @@ Tag = str @dataclass(eq=True, frozen=True) class User: - user: str + user: int user_type: Literal["group", "private"] diff --git a/tests/conftest.py b/tests/conftest.py index 0fb5aca..18a0691 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,3 +1,4 @@ +import asyncio import typing from pathlib import Path @@ -13,6 +14,9 @@ async def app(nonebug_init: None, tmp_path: Path, monkeypatch: pytest.MonkeyPatc config = nonebot.get_driver().config config.bison_config_path = str(tmp_path) config.command_start = {""} + config.superusers = {"10001"} + config.log_level = "TRACE" + config.bison_filter_log = False return App(monkeypatch) @@ -20,5 +24,24 @@ async def app(nonebug_init: None, tmp_path: Path, monkeypatch: pytest.MonkeyPatc def dummy_user_subinfo(app: App): from nonebot_bison.types import User, UserSubInfo - user = User("123", "group") + user = User(123, "group") return UserSubInfo(user=user, category_getter=lambda _: [], tag_getter=lambda _: []) + + +@pytest.fixture +def task_watchdog(request): + def cancel_test_on_exception(task: asyncio.Task): + def maybe_cancel_clbk(t: asyncio.Task): + exception = t.exception() + if exception is None: + return + + for task in asyncio.all_tasks(): + coro = task.get_coro() + if coro.__qualname__ == request.function.__qualname__: + task.cancel() + return + + task.add_done_callback(maybe_cancel_clbk) + + return cancel_test_on_exception diff --git a/tests/test_config_manager.py b/tests/test_config_manager.py index 160563d..771170a 100644 --- a/tests/test_config_manager.py +++ b/tests/test_config_manager.py @@ -453,3 +453,17 @@ async def test_del_sub(app: App): ctx.should_finished() subs = config.list_subscribe(10000, "group") assert len(subs) == 0 + + +async def test_test(app: App): + from nonebot.adapters.onebot.v11.bot import Bot + from nonebot.adapters.onebot.v11.message import Message + from nonebot_bison.config_manager import test_matcher + + async with app.test_matcher(test_matcher) as ctx: + bot = ctx.create_bot(base=Bot) + event = fake_group_message_event(message=Message("testtt")) + ctx.receive_event(bot, event) + ctx.should_pass_permission() + ctx.should_pass_rule() + ctx.should_call_send(event, "666", True) diff --git a/tests/test_config_manager_admin.py b/tests/test_config_manager_admin.py new file mode 100644 index 0000000..fc6581d --- /dev/null +++ b/tests/test_config_manager_admin.py @@ -0,0 +1,45 @@ +from nonebug import App + +from .utils import fake_admin_user, fake_private_message_event, fake_superuser + + +async def test_query(app: App): + from nonebot.adapters.onebot.v11.bot import Bot + from nonebot.adapters.onebot.v11.message import Message + from nonebot_bison.config_manager import group_manage_matcher + + async with app.test_matcher(group_manage_matcher) as ctx: + bot = ctx.create_bot(base=Bot) + event = fake_private_message_event( + message=Message("群管理"), sender=fake_superuser + ) + ctx.receive_event(bot, event) + ctx.should_pass_rule() + ctx.should_pass_permission() + ctx.should_call_api( + "get_group_list", {}, [{"group_id": 101, "group_name": "test group"}] + ) + ctx.should_call_send( + event, Message("请选择需要管理的群:\n1. 101 - test group\n请输入左侧序号"), True + ) + event_1_err = fake_private_message_event( + message=Message("0"), sender=fake_superuser + ) + ctx.receive_event(bot, event_1_err) + ctx.should_rejected() + ctx.should_call_send(event_1_err, "请输入正确序号", True) + event_1_ok = fake_private_message_event( + message=Message("1"), sender=fake_superuser + ) + ctx.receive_event(bot, event_1_ok) + ctx.should_call_send(event_1_ok, "请输入需要使用的命令:添加订阅,查询订阅,删除订阅", True) + event_2_err = fake_private_message_event( + message=Message("222"), sender=fake_superuser + ) + ctx.receive_event(bot, event_2_err) + ctx.should_rejected() + ctx.should_call_send(event_2_err, "请输入正确的命令", True) + event_2_ok = fake_private_message_event( + message=Message("查询订阅"), sender=fake_superuser + ) + ctx.receive_event(bot, event_2_ok) diff --git a/tests/utils.py b/tests/utils.py index 1212a20..a31b67e 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -68,3 +68,4 @@ def fake_private_message_event(**field) -> "PrivateMessageEvent": from nonebot.adapters.onebot.v11.event import Sender fake_admin_user = Sender(nickname="test", role="admin") +fake_superuser = Sender(user_id=10001, nickname="superuser") From d231ed123cc7fe4e828da3a0e028b26f011496ab Mon Sep 17 00:00:00 2001 From: felinae98 <731499577@qq.com> Date: Sun, 6 Mar 2022 22:40:39 +0800 Subject: [PATCH 4/6] mark flaky --- poetry.lock | 14 +++++++++++++- pyproject.toml | 1 + tests/test_merge_pic.py | 13 +++++++------ 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/poetry.lock b/poetry.lock index 69aae51..5ceada2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -364,6 +364,14 @@ python-versions = ">=3.7" docs = ["furo (>=2021.8.17b43)", "sphinx (>=4.1)", "sphinx-autodoc-typehints (>=1.12)"] testing = ["covdefaults (>=1.2.0)", "coverage (>=4)", "pytest (>=4)", "pytest-cov", "pytest-timeout (>=1.4.2)"] +[[package]] +name = "flaky" +version = "3.7.0" +description = "Plugin for nose or pytest that automatically reruns flaky tests." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + [[package]] name = "greenlet" version = "1.1.2" @@ -1461,7 +1469,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest- [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "4a0d093b99ca03d9e9effe113ccd85daf9242c0a95f2336d2af8fcc7e764b6ce" +content-hash = "48207f450bd3f15faf69721a1b2daed6b15aa5e23ff94a6ab05036f37d844d73" [metadata.files] aiofiles = [ @@ -1645,6 +1653,10 @@ filelock = [ {file = "filelock-3.6.0-py3-none-any.whl", hash = "sha256:f8314284bfffbdcfa0ff3d7992b023d4c628ced6feb957351d4c48d059f56bc0"}, {file = "filelock-3.6.0.tar.gz", hash = "sha256:9cd540a9352e432c7246a48fe4e8712b10acb1df2ad1f30e8c070b82ae1fed85"}, ] +flaky = [ + {file = "flaky-3.7.0-py2.py3-none-any.whl", hash = "sha256:d6eda73cab5ae7364504b7c44670f70abed9e75f77dd116352f662817592ec9c"}, + {file = "flaky-3.7.0.tar.gz", hash = "sha256:3ad100780721a1911f57a165809b7ea265a7863305acb66708220820caf8aa0d"}, +] greenlet = [ {file = "greenlet-1.1.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:58df5c2a0e293bf665a51f8a100d3e9956febfbf1d9aaf8c0677cf70218910c6"}, {file = "greenlet-1.1.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:aec52725173bd3a7b56fe91bc56eccb26fbdff1386ef123abb63c84c5b43b63a"}, diff --git a/pyproject.toml b/pyproject.toml index 1a2b388..1c9bf56 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,6 +49,7 @@ black = "^22.1.0" isort = "^5.10.1" pre-commit = "^2.17.0" nb-cli = "^0.6.6" +flaky = "^3.7.0" [build-system] requires = ["poetry>=0.12"] diff --git a/tests/test_merge_pic.py b/tests/test_merge_pic.py index 9e1a34b..09b7a95 100644 --- a/tests/test_merge_pic.py +++ b/tests/test_merge_pic.py @@ -1,6 +1,7 @@ import typing import pytest +from flaky import flaky from nonebug.app import App if typing.TYPE_CHECKING: @@ -40,7 +41,7 @@ merge_source_9_2 = [ ] -@pytest.mark.asyncio +@flaky async def test_9_merge(app: App): from nonebot_bison.post import Post @@ -50,7 +51,7 @@ async def test_9_merge(app: App): await post.generate_messages() -@pytest.mark.asyncio +@flaky async def test_9_merge_2(app: App): from nonebot_bison.post import Post @@ -60,7 +61,7 @@ async def test_9_merge_2(app: App): await post.generate_messages() -@pytest.mark.asyncio +@flaky async def test_6_merge(app: App): from nonebot_bison.post import Post @@ -69,7 +70,7 @@ async def test_6_merge(app: App): assert len(post.pics) == 5 -@pytest.mark.asyncio +@flaky async def test_3_merge(app: App): from nonebot_bison.post import Post @@ -78,7 +79,7 @@ async def test_3_merge(app: App): assert len(post.pics) == 5 -@pytest.mark.asyncio +@flaky async def test_6_merge_only(app: App): from nonebot_bison.post import Post @@ -87,7 +88,7 @@ async def test_6_merge_only(app: App): assert len(post.pics) == 1 -@pytest.mark.asyncio +@flaky async def test_3_merge_only(app: App): from nonebot_bison.post import Post From 1e48bc3c2a1fdb50dc1b23310af38d7922fe28fa Mon Sep 17 00:00:00 2001 From: felinae98 <731499577@qq.com> Date: Mon, 7 Mar 2022 13:24:11 +0800 Subject: [PATCH 5/6] fix docker build error --- docker/Dockerfile_with_frontend | 2 +- docker/Dockerfile_with_frontend_sentry | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile_with_frontend b/docker/Dockerfile_with_frontend index ec5b8f3..d2860b8 100644 --- a/docker/Dockerfile_with_frontend +++ b/docker/Dockerfile_with_frontend @@ -10,7 +10,7 @@ RUN apt-get update && apt-get install -y xvfb fonts-noto-color-emoji ttf-unifont libxdamage1 libxext6 libxfixes3 libxrandr2 libxshmfence1 \ && rm -rf /var/lib/apt/lists/* COPY ./pyproject.toml ./poetry.lock* /app/ -RUN poetry install --no-dev +RUN poetry install --no-dev --no-root RUN playwright install chromium ADD src /app/src ADD bot.py /app/ diff --git a/docker/Dockerfile_with_frontend_sentry b/docker/Dockerfile_with_frontend_sentry index e947337..4844dd2 100644 --- a/docker/Dockerfile_with_frontend_sentry +++ b/docker/Dockerfile_with_frontend_sentry @@ -12,7 +12,7 @@ RUN apt-get update && apt-get install -y xvfb fonts-noto-color-emoji ttf-unifont COPY ./pyproject.toml ./poetry.lock* ./bot.py /app/ RUN poetry add nonebot-plugin-sentry && \ sed '/nonebot.load_builtin_plugins("echo")/a nonebot.load_plugin("nonebot_plugin_sentry")' -i bot.py -RUN poetry install --no-dev +RUN poetry install --no-dev --no-root RUN playwright install chromium ADD src /app/src ENV HOST=0.0.0.0 From 2638070098d6114257db5e6ab74b48f637147f16 Mon Sep 17 00:00:00 2001 From: felinae98 <731499577@qq.com> Date: Tue, 8 Mar 2022 11:39:20 +0800 Subject: [PATCH 6/6] update ci file --- .circleci/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/main.yml b/.circleci/main.yml index fae7a0f..0e5e293 100644 --- a/.circleci/main.yml +++ b/.circleci/main.yml @@ -14,7 +14,7 @@ orbs: node: circleci/node@4.7.0 # poetry: frameio/poetry@0.21.0 swissknife: roopakv/swissknife@0.59.0 - docker: circleci/docker@1.7.0 + docker: circleci/docker@2.0.2 docker-cache: cci-x/docker-registry-image-cache@0.2.0 codecov: codecov/codecov@3.2.2