This commit is contained in:
felinae98 2022-02-16 21:42:49 +08:00
parent a0b98f5c9c
commit 78276e51ee
No known key found for this signature in database
GPG Key ID: 00C8B010587FF610
12 changed files with 317 additions and 113 deletions

View File

@ -34,19 +34,50 @@ sidebar: auto
#### 这个平台是否有账号的概念
- `nonebot_bison.platform.platform.TargetMixin` 有账号的概念
例如Bilibili 用户,微博用户
- `nonebot_bison.platform.platform.NoTargetMixin` 没有账号的概念
例如:游戏公告,教务处公告
- 有账号的概念
例如B 用户动态,微博用户动态,网易云电台更新
- 没有账号的概念
例如:游戏公告,教务处公告
现在你已经选择了两个类,现在你需要在`src/plugins/nonebot_bison/platform`下新建一个 py 文件,
在里面新建一个类,继承你刚刚选择的两个类,重载一些关键的函数,然后……就完成了,不需要修改别的东西了。
现在你需要在`src/plugins/nonebot_bison/platform`下新建一个 py 文件,
在里面新建一个类,继承推送类型的基类,重载一些关键的函数,然后……就完成了,不需要修改别的东西了。
例如要适配微博,微博有账号,并且我希望 bot 搬运新的消息,所以微博的类应该这样定义:
任何一种订阅类型需要实现的方法/字段如下:
- `schedule_type`, `schedule_kw` 调度的参数,本质是使用 apscheduler 的[trigger 参数](https://apscheduler.readthedocs.io/en/3.x/userguide.html?highlight=trigger#choosing-the-right-scheduler-job-store-s-executor-s-and-trigger-s)`schedule_type`可以是`date`,`interval``cron`
`schedule_kw`是对应的参数,一个常见的配置是`schedule_type=interval`, `schedule_kw={'seconds':30}`
- `is_common` 是否常用,如果被标记为常用,那么和机器人交互式对话添加订阅时,会直接出现在选择列表中,否则
需要输入`全部`才会出现。
- `enabled` 是否启用
- `name` 平台的正式名称,例如`微博`
- `has_target` 平台是否有“帐号”
- `category` 平台的发布内容分类,例如 B 站包括专栏,视频,图文动态,普通动态等,如果不包含分类功能则设为`{}`
- `enable_tag` 平台发布内容是否带 Tag例如微博
- `platform_name` 唯一的,英文的识别标识,比如`weibo`
- `async get_target_name(Target) -> Optional[str]` 通常用于获取帐号的名称,如果平台没有帐号概念,可以直接返回平台的`name`
- `async parse(RawPost) -> Post`将获取到的 RawPost 处理成 Post
- `get_tags(RawPost) -> Optional[Collection[Tag]]` (可选) 从 RawPost 中提取 Tag
- `get_category(RawPos) -> Optional[Category]` (可选)从 RawPost 中提取 Category
例如要适配微博,我希望 bot 搬运新的消息,所以微博的类应该这样定义:
```python
class Weibo(NewMessage, TargetMixin):
...
class Weibo(NewMessage):
categories = {
1: "转发",
2: "视频",
3: "图文",
4: "文字",
}
enable_tag = True
platform_name = "weibo"
name = "新浪微博"
enabled = True
is_common = True
schedule_type = "interval"
schedule_kw = {"seconds": 3}
has_target = True
```
当然我们非常希望你对自己适配的平台写一些单元测试,你可以模仿`tests/platforms/test_*.py`中的内容写

76
poetry.lock generated
View File

@ -325,7 +325,7 @@ tests = ["dill", "coverage", "coveralls", "mock", "nose"]
[[package]]
name = "fastapi"
version = "0.70.1"
version = "0.73.0"
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
category = "main"
optional = false
@ -333,12 +333,12 @@ python-versions = ">=3.6.1"
[package.dependencies]
pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0"
starlette = "0.16.0"
starlette = "0.17.1"
[package.extras]
all = ["requests (>=2.24.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "itsdangerous (>=1.1.0,<3.0.0)", "pyyaml (>=5.3.1,<6.0.0)", "ujson (>=4.0.1,<5.0.0)", "orjson (>=3.2.1,<4.0.0)", "email_validator (>=1.1.1,<2.0.0)", "uvicorn[standard] (>=0.12.0,<0.16.0)"]
dev = ["python-jose[cryptography] (>=3.3.0,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.16.0)"]
doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=7.1.9,<8.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "typer-cli (>=0.0.12,<0.0.13)", "pyyaml (>=5.3.1,<6.0.0)"]
doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "typer-cli (>=0.0.12,<0.0.13)", "pyyaml (>=5.3.1,<6.0.0)"]
test = ["pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "mypy (==0.910)", "flake8 (>=3.8.3,<4.0.0)", "black (==21.9b0)", "isort (>=5.0.6,<6.0.0)", "requests (>=2.24.0,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "email_validator (>=1.1.1,<2.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "peewee (>=3.13.3,<4.0.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "orjson (>=3.2.1,<4.0.0)", "ujson (>=4.0.1,<5.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "flask (>=1.1.2,<3.0.0)", "anyio[trio] (>=3.2.1,<4.0.0)", "types-ujson (==0.1.1)", "types-orjson (==3.6.0)", "types-dataclasses (==0.1.7)"]
[[package]]
@ -564,7 +564,7 @@ jinja2 = "*"
[[package]]
name = "loguru"
version = "0.5.3"
version = "0.6.0"
description = "Python logging made (stupidly) simple"
category = "main"
optional = false
@ -575,7 +575,7 @@ colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""}
win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""}
[package.extras]
dev = ["codecov (>=2.0.15)", "colorama (>=0.3.4)", "flake8 (>=3.7.7)", "tox (>=3.9.0)", "tox-travis (>=0.12)", "pytest (>=4.6.2)", "pytest-cov (>=2.7.1)", "Sphinx (>=2.2.1)", "sphinx-autobuild (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "black (>=19.10b0)", "isort (>=5.1.1)"]
dev = ["colorama (>=0.3.4)", "docutils (==0.16)", "flake8 (>=3.7.7)", "tox (>=3.9.0)", "pytest (>=4.6.2)", "pytest-cov (>=2.7.1)", "black (>=19.10b0)", "isort (>=5.1.1)", "Sphinx (>=4.1.1)", "sphinx-autobuild (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)"]
[[package]]
name = "markupsafe"
@ -614,7 +614,7 @@ python-versions = "*"
[[package]]
name = "nb-cli"
version = "0.6.5"
version = "0.6.6"
description = "CLI for nonebot2"
category = "dev"
optional = false
@ -628,7 +628,7 @@ httpx = ">=0.18.0,<1.0.0"
nonebot2 = ">=2.0.0-beta.1,<3.0.0"
prompt-toolkit = ">=3.0.19,<4.0.0"
pyfiglet = ">=0.8.post1,<0.9"
tomlkit = ">=0.7.0,<0.8.0"
tomlkit = ">=0.9.0,<0.10.0"
wcwidth = ">=0.2.5,<0.3.0"
[package.extras]
@ -679,26 +679,26 @@ nonebot2 = ">=2.0.0.a16,<3.0.0"
[[package]]
name = "nonebot2"
version = "2.0.0b1"
version = "2.0.0b2"
description = "An asynchronous python bot framework."
category = "main"
optional = false
python-versions = ">=3.7.3,<4.0.0"
[package.dependencies]
fastapi = ">=0.70.0,<0.71.0"
loguru = ">=0.5.1,<0.6.0"
fastapi = ">=0.73.0,<0.74.0"
loguru = ">=0.6.0,<0.7.0"
pydantic = {version = ">=1.9.0,<1.10.0", extras = ["dotenv"]}
pygtrie = ">=2.4.1,<3.0.0"
tomlkit = ">=0.7.0,<0.8.0"
tomlkit = ">=0.9.0,<0.10.0"
typing-extensions = ">=3.10.0,<5.0.0"
uvicorn = {version = ">=0.15.0,<0.16.0", extras = ["standard"]}
uvicorn = {version = ">=0.17.0,<0.18.0", extras = ["standard"]}
yarl = ">=1.7.2,<2.0.0"
[package.extras]
quart = ["Quart (>=0.16.0,<0.17.0)"]
all = ["Quart (>=0.16.0,<0.17.0)", "websockets (>=9.1)", "aiohttp[speedups] (>=3.7.4,<4.0.0)", "httpx[http2] (>=0.20.0,<1.0.0)"]
websockets = ["websockets (>=9.1)"]
all = ["Quart (>=0.16.0,<0.17.0)", "websockets (>=10.0,<11.0)", "aiohttp[speedups] (>=3.7.4,<4.0.0)", "httpx[http2] (>=0.20.0,<1.0.0)"]
websockets = ["websockets (>=10.0,<11.0)"]
aiohttp = ["aiohttp[speedups] (>=3.7.4,<4.0.0)"]
httpx = ["httpx[http2] (>=0.20.0,<1.0.0)"]
@ -1183,7 +1183,7 @@ tests = ["pytest", "typeguard", "pygments", "littleutils"]
[[package]]
name = "starlette"
version = "0.16.0"
version = "0.17.1"
description = "The little ASGI library that shines."
category = "main"
optional = false
@ -1193,7 +1193,7 @@ python-versions = ">=3.6"
anyio = ">=3.0.0,<4"
[package.extras]
full = ["itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests", "graphene"]
full = ["itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests"]
[[package]]
name = "text-unidecode"
@ -1229,11 +1229,11 @@ python-versions = ">=3.6"
[[package]]
name = "tomlkit"
version = "0.7.2"
version = "0.9.2"
description = "Style preserving TOML library"
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
python-versions = ">=3.6,<4.0"
[[package]]
name = "traitlets"
@ -1293,26 +1293,26 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
[[package]]
name = "uvicorn"
version = "0.15.0"
version = "0.17.5"
description = "The lightning-fast ASGI server."
category = "main"
optional = false
python-versions = "*"
python-versions = ">=3.7"
[package.dependencies]
asgiref = ">=3.4.0"
click = ">=7.0"
colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""}
h11 = ">=0.8"
httptools = {version = ">=0.2.0,<0.3.0", optional = true, markers = "extra == \"standard\""}
httptools = {version = ">=0.2.0,<0.4.0", optional = true, markers = "extra == \"standard\""}
python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""}
PyYAML = {version = ">=5.1", optional = true, markers = "extra == \"standard\""}
uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\" and extra == \"standard\""}
watchgod = {version = ">=0.6", optional = true, markers = "extra == \"standard\""}
websockets = {version = ">=9.1", optional = true, markers = "extra == \"standard\""}
websockets = {version = ">=10.0", optional = true, markers = "extra == \"standard\""}
[package.extras]
standard = ["websockets (>=9.1)", "httptools (>=0.2.0,<0.3.0)", "watchgod (>=0.6)", "python-dotenv (>=0.13)", "PyYAML (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "colorama (>=0.4)"]
standard = ["websockets (>=10.0)", "httptools (>=0.2.0,<0.4.0)", "watchgod (>=0.6)", "python-dotenv (>=0.13)", "PyYAML (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "colorama (>=0.4)"]
[[package]]
name = "uvloop"
@ -1395,7 +1395,7 @@ multidict = ">=4.0"
[metadata]
lock-version = "1.1"
python-versions = "^3.9"
content-hash = "c67bc1707866ddff4ec0a895755734ff30821321f78a82a4038a33418723bc97"
content-hash = "2f409abbd0b4f5a528a4dc49e3f4837a4fe86dcbb26ae0a225037520f94b3101"
[metadata.files]
aiofiles = [
@ -1568,8 +1568,8 @@ expiringdict = [
{file = "expiringdict-1.2.1.tar.gz", hash = "sha256:fe2ba427220425c3c8a3d29f6d2e2985bcee323f8bcd4021e68ebefbd90d8250"},
]
fastapi = [
{file = "fastapi-0.70.1-py3-none-any.whl", hash = "sha256:5367226c7bcd7bfb2e17edaf225fd9a983095b1372281e9a3eb661336fb93748"},
{file = "fastapi-0.70.1.tar.gz", hash = "sha256:21d03979b5336375c66fa5d1f3126c6beca650d5d2166fbb78345a30d33c8d06"},
{file = "fastapi-0.73.0-py3-none-any.whl", hash = "sha256:f0a618aff5f6942862f2d3f20f39b1c037e33314d1b8207fd1c3a2cca76dfd8c"},
{file = "fastapi-0.73.0.tar.gz", hash = "sha256:dcfee92a7f9a72b5d4b7ca364bd2b009f8fc10d95ed5769be20e94f39f7e5a15"},
]
feedparser = [
{file = "feedparser-6.0.8-py3-none-any.whl", hash = "sha256:1b7f57841d9cf85074deb316ed2c795091a238adb79846bc46dccdaf80f9c59a"},
@ -1696,8 +1696,8 @@ jinja2-time = [
{file = "jinja2_time-0.2.0-py2.py3-none-any.whl", hash = "sha256:d3eab6605e3ec8b7a0863df09cc1d23714908fa61aa6986a845c20ba488b4efa"},
]
loguru = [
{file = "loguru-0.5.3-py3-none-any.whl", hash = "sha256:f8087ac396b5ee5f67c963b495d615ebbceac2796379599820e324419d53667c"},
{file = "loguru-0.5.3.tar.gz", hash = "sha256:b28e72ac7a98be3d28ad28570299a393dfcd32e5e3f6a353dec94675767b6319"},
{file = "loguru-0.6.0-py3-none-any.whl", hash = "sha256:4e2414d534a2ab57573365b3e6d0234dfb1d84b68b7f3b948e6fb743860a77c3"},
{file = "loguru-0.6.0.tar.gz", hash = "sha256:066bd06758d0a513e9836fd9c6b5a75bfb3fd36841f4b996bc60b547a309d41c"},
]
markupsafe = [
{file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"},
@ -1853,8 +1853,8 @@ mypy-extensions = [
{file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
]
nb-cli = [
{file = "nb-cli-0.6.5.tar.gz", hash = "sha256:4fba1726419a429e14371c293d2c4ffdc4544f333fead2944febf9692f927774"},
{file = "nb_cli-0.6.5-py3-none-any.whl", hash = "sha256:f19026c9f90b9edeaab8fe05db828f570005ce7baa4f49019ee1276f99754ac3"},
{file = "nb-cli-0.6.6.tar.gz", hash = "sha256:501a747dda00b2d384421634a98b136d9976d12d950d54f1e2bb3c71236ffa73"},
{file = "nb_cli-0.6.6-py3-none-any.whl", hash = "sha256:72a3929e0de4405f5dee7a43cd5358065b36b39125bc99d7dbb1d672bf7f7713"},
]
nodeenv = [
{file = "nodeenv-1.6.0-py2.py3-none-any.whl", hash = "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"},
@ -1873,8 +1873,8 @@ nonebot-plugin-help = [
{file = "nonebot_plugin_help-0.1.5-py3-none-any.whl", hash = "sha256:1c4bb626feb202515f47311e3ca9872ab6c0db5e935bc9561325fcc1a2591511"},
]
nonebot2 = [
{file = "nonebot2-2.0.0b1-py3-none-any.whl", hash = "sha256:76ee4271a0ba9b1fbdcb34c50a23df391bed00d5d32d63b7fd018685de8130a4"},
{file = "nonebot2-2.0.0b1.tar.gz", hash = "sha256:e23b6656943738a9f8559e20ac51a8c3af799a2eea01e3e2188be01959f36455"},
{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.0-py3-none-any.whl", hash = "sha256:aa0f639f3fc039803640a952b1c12088e8b1ec5a30d1632e43301f215f96de22"},
@ -2151,8 +2151,8 @@ stack-data = [
{file = "stack_data-0.1.4.tar.gz", hash = "sha256:7769ed2482ce0030e00175dd1bf4ef1e873603b6ab61cd3da443b410e64e9477"},
]
starlette = [
{file = "starlette-0.16.0-py3-none-any.whl", hash = "sha256:38eb24bf705a2c317e15868e384c1b8a12ca396e5a3c3a003db7e667c43f939f"},
{file = "starlette-0.16.0.tar.gz", hash = "sha256:e1904b5d0007aee24bdd3c43994be9b3b729f4f58e740200de1d623f8c3a8870"},
{file = "starlette-0.17.1-py3-none-any.whl", hash = "sha256:26a18cbda5e6b651c964c12c88b36d9898481cd428ed6e063f5f29c418f73050"},
{file = "starlette-0.17.1.tar.gz", hash = "sha256:57eab3cc975a28af62f6faec94d355a410634940f10b30d68d31cb5ec1b44ae8"},
]
text-unidecode = [
{file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"},
@ -2171,8 +2171,8 @@ tomli = [
{file = "tomli-1.2.3.tar.gz", hash = "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"},
]
tomlkit = [
{file = "tomlkit-0.7.2-py2.py3-none-any.whl", hash = "sha256:173ad840fa5d2aac140528ca1933c29791b79a374a0861a80347f42ec9328117"},
{file = "tomlkit-0.7.2.tar.gz", hash = "sha256:d7a454f319a7e9bd2e249f239168729327e4dd2d27b17dc68be264ad1ce36754"},
{file = "tomlkit-0.9.2-py3-none-any.whl", hash = "sha256:daf4f9c5f2fbf6b861d6adfc51940b98dee36c13e1d88749a6dc9fb280fff304"},
{file = "tomlkit-0.9.2.tar.gz", hash = "sha256:ebd982d61446af95a1e082b103e250cb9e6d152eae2581d4a07d31a70b34ab0f"},
]
traitlets = [
{file = "traitlets-5.1.1-py3-none-any.whl", hash = "sha256:2d313cc50a42cd6c277e7d7dc8d4d7fedd06a2c215f78766ae7b1a66277e0033"},
@ -2195,8 +2195,8 @@ urllib3 = [
{file = "urllib3-1.26.8.tar.gz", hash = "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c"},
]
uvicorn = [
{file = "uvicorn-0.15.0-py3-none-any.whl", hash = "sha256:17f898c64c71a2640514d4089da2689e5db1ce5d4086c2d53699bf99513421c1"},
{file = "uvicorn-0.15.0.tar.gz", hash = "sha256:d9a3c0dd1ca86728d3e235182683b4cf94cd53a867c288eaeca80ee781b2caff"},
{file = "uvicorn-0.17.5-py3-none-any.whl", hash = "sha256:8adddf629b79857b48b999ae1b14d6c92c95d4d7840bd86461f09bee75f1653e"},
{file = "uvicorn-0.17.5.tar.gz", hash = "sha256:c04a9c069111489c324f427501b3840d306c6b91a77b00affc136a840a3f45f1"},
]
uvloop = [
{file = "uvloop-0.16.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6224f1401025b748ffecb7a6e2652b17768f30b1a6a3f7b44660e5b5b690b12d"},

View File

@ -24,7 +24,7 @@ classifiers = [
[tool.poetry.dependencies]
python = "^3.9"
nonebot2 = "^2.0.0-beta.1"
nonebot2 = "^2.0.0-beta.2"
httpx = ">=0.16.1 <1.0.0"
bs4 = "^0.0.1"
tinydb = "^4.3.0"
@ -49,7 +49,7 @@ nonebug = "^0.2.0"
black = "^22.1.0"
isort = "^5.10.1"
pre-commit = "^2.17.0"
nb-cli = "^0.6.5"
nb-cli = "^0.6.6"
[build-system]
requires = ["poetry>=0.12"]

View File

@ -10,7 +10,6 @@ from nonebot.adapters.onebot.v11 import Bot
from nonebot.adapters.onebot.v11.event import GroupMessageEvent, PrivateMessageEvent
from nonebot.drivers.fastapi import Driver
from nonebot.log import logger
from nonebot.params import State
from nonebot.rule import to_me
from nonebot.typing import T_State
@ -152,9 +151,7 @@ if (STATIC_PATH / "index.html").exists():
get_token = on_command("后台管理", rule=to_me(), priority=5)
@get_token.handle()
async def send_token(
bot: "Bot", event: PrivateMessageEvent, state: T_State = State()
):
async def send_token(bot: "Bot", event: PrivateMessageEvent, state: T_State):
token = tm.get_user_token((event.get_user_id(), event.sender.nickname))
await get_token.finish(f"请访问: {plugin_config.bison_outer_url}auth/{token}")

View File

@ -1,12 +1,12 @@
from typing import Type
from nonebot import on_command
from nonebot.adapters._event import Event as AbstractEvent
from nonebot.adapters import Event as AbstractEvent
from nonebot.adapters.onebot.v11 import Bot, Event
from nonebot.adapters.onebot.v11.message import Message
from nonebot.adapters.onebot.v11.permission import GROUP_ADMIN, GROUP_OWNER
from nonebot.matcher import Matcher
from nonebot.params import Depends, State
from nonebot.params import Depends
from nonebot.permission import SUPERUSER
from nonebot.rule import to_me
from nonebot.typing import T_State
@ -42,7 +42,7 @@ async def send_help():
def do_add_sub(add_sub: Type[Matcher]):
@add_sub.handle()
async def init_promote(state: T_State = State()):
async def init_promote(state: T_State):
state["_prompt"] = (
"请输入想要订阅的平台,目前支持,请输入冒号左边的名称:\n"
+ "".join(
@ -56,7 +56,7 @@ def do_add_sub(add_sub: Type[Matcher]):
+ "要查看全部平台请输入:“全部”"
)
async def parse_platform(event: AbstractEvent, state: T_State = State()) -> None:
async def parse_platform(event: AbstractEvent, state: T_State) -> None:
if not isinstance(state["platform"], Message):
return
platform = str(event.get_message()).strip()
@ -76,7 +76,7 @@ def do_add_sub(add_sub: Type[Matcher]):
@add_sub.got(
"platform", _gen_prompt_template("{_prompt}"), [Depends(parse_platform)]
)
async def init_id(state: T_State = State()):
async def init_id(state: T_State):
if platform_manager[state["platform"]].has_target:
state[
"_prompt"
@ -87,7 +87,7 @@ def do_add_sub(add_sub: Type[Matcher]):
Target("")
)
async def parse_id(event: AbstractEvent, state: T_State = State()):
async def parse_id(event: AbstractEvent, state: T_State):
if not isinstance(state["id"], Message):
return
target = str(event.get_message()).strip()
@ -101,7 +101,7 @@ def do_add_sub(add_sub: Type[Matcher]):
await add_sub.reject("id输入错误")
@add_sub.got("id", _gen_prompt_template("{_prompt}"), [Depends(parse_id)])
async def init_cat(state: T_State = State()):
async def init_cat(state: T_State):
if not platform_manager[state["platform"]].categories:
state["cats"] = []
return
@ -109,7 +109,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 = State()):
async def parser_cats(event: AbstractEvent, state: T_State):
if not isinstance(state["cats"], Message):
return
res = []
@ -120,13 +120,13 @@ def do_add_sub(add_sub: Type[Matcher]):
state["cats"] = res
@add_sub.got("cats", _gen_prompt_template("{_prompt}"), [Depends(parser_cats)])
async def init_tag(state: T_State = State()):
async def init_tag(state: T_State):
if not platform_manager[state["platform"]].enable_tag:
state["tags"] = []
return
state["_prompt"] = '请输入要订阅的tag订阅所有tag输入"全部标签"'
async def parser_tags(event: AbstractEvent, state: T_State = State()):
async def parser_tags(event: AbstractEvent, state: T_State):
if not isinstance(state["tags"], Message):
return
if str(event.get_message()).strip() == "全部标签":
@ -135,7 +135,7 @@ def do_add_sub(add_sub: Type[Matcher]):
state["tags"] = str(event.get_message()).strip().split()
@add_sub.got("tags", _gen_prompt_template("{_prompt}"), [Depends(parser_tags)])
async def add_sub_process(event: Event, state: T_State = State()):
async def add_sub_process(event: Event, state: T_State):
config = Config()
config.add_subscribe(
state.get("_user_id") or event.group_id,
@ -151,7 +151,7 @@ def do_add_sub(add_sub: Type[Matcher]):
def do_query_sub(query_sub: Type[Matcher]):
@query_sub.handle()
async def _(event: Event, state: T_State = State()):
async def _(event: Event, state: T_State):
config: Config = Config()
sub_list = config.list_subscribe(
state.get("_user_id") or event.group_id, "group"
@ -176,7 +176,7 @@ def do_query_sub(query_sub: Type[Matcher]):
def do_del_sub(del_sub: Type[Matcher]):
@del_sub.handle()
async def send_list(bot: Bot, event: Event, state: T_State = State()):
async def send_list(bot: Bot, event: Event, state: T_State):
config: Config = Config()
sub_list = config.list_subscribe(
state.get("_user_id") or event.group_id, "group"
@ -205,7 +205,7 @@ def do_del_sub(del_sub: Type[Matcher]):
await bot.send(event=event, message=Message(await parse_text(res)))
@del_sub.receive()
async def do_del(event: Event, state: T_State = State()):
async def do_del(event: Event, state: T_State):
try:
index = int(str(event.get_message()).strip())
config = Config()
@ -220,7 +220,7 @@ def do_del_sub(del_sub: Type[Matcher]):
await del_sub.finish("删除成功")
async def parse_group_number(event: AbstractEvent, state: T_State = State()):
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()))

View File

@ -3,8 +3,8 @@ from typing import Any, Callable, Literal, NamedTuple, NewType
RawPost = NewType("RawPost", Any)
Target = NewType("Target", str)
Category = NewType("Category", int)
Tag = NewType("Tag", str)
Category = int
Tag = str
@dataclass(eq=True, frozen=True)

View File

@ -12,6 +12,7 @@ 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 = {""}
return App(monkeypatch)

View File

@ -0,0 +1 @@
{"ok":1,"data":{"isVideoCoverStyle":1,"isStarStyle":0,"userInfo":{"id":6279793937,"screen_name":"\u660e\u65e5\u65b9\u821fArknights","profile_image_url":"https:\/\/tvax4.sinaimg.cn\/crop.0.0.756.756.180\/006QZngZly8gdj05mufr9j30l00l0dq4.jpg?KID=imgbed,tva&Expires=1645010805&ssig=POD2VKV4LB","profile_url":"https:\/\/m.weibo.cn\/u\/6279793937?uid=6279793937&luicode=10000011&lfid=1005056279793937","statuses_count":1553,"verified":true,"verified_type":2,"verified_type_ext":50,"verified_reason":"\u4e0a\u6d77\u9e70\u89d2\u7f51\u7edc\u79d1\u6280\u6709\u9650\u516c\u53f8","close_blue_v":false,"description":"\u300a\u660e\u65e5\u65b9\u821f\u300b\u5b98\u65b9\u5fae\u535a\uff0c\u6b22\u8fce\u54a8\u8be2\u5ba2\u670dQQ\u670d\u52a1\u53f7\uff1a800830064","gender":"f","mbtype":12,"urank":4,"mbrank":7,"follow_me":false,"following":false,"follow_count":34,"followers_count":"145.5\u4e07","followers_count_str":"145.5\u4e07","cover_image_phone":"https:\/\/wx4.sinaimg.cn\/crop.0.0.640.640.640\/006QZngZly1gq8sa16csgj30u00u0akt.jpg","avatar_hd":"https:\/\/wx4.sinaimg.cn\/orj480\/006QZngZly8gdj05mufr9j30l00l0dq4.jpg","like":false,"like_me":false,"toolbar_menus":[{"type":"link","name":"\u804a\u5929","pic":"http:\/\/h5.sinaimg.cn\/upload\/2015\/06\/12\/2\/toolbar_icon_discuss_default.png","params":{"scheme":"sinaweibo:\/\/messagelist?uid=6279793937&nick=\u660e\u65e5\u65b9\u821fArknights"},"scheme":"https:\/\/passport.weibo.cn\/signin\/welcome?entry=mweibo&r=https%3A%2F%2Fm.weibo.cn%2Fapi%2Fcontainer%2FgetIndex%3Fcontainerid%3D1005056279793937"},{"type":"profile_follow","name":"\u5173\u6ce8","pic":"","params":{"uid":6279793937,"extparams":{"followcardid":"0001980001_6279793937_b2f217e4"}},"userInfo":{"id":6279793937,"idstr":"6279793937","screen_name":"\u660e\u65e5\u65b9\u821fArknights","profile_image_url":"https:\/\/tvax4.sinaimg.cn\/crop.0.0.756.756.50\/006QZngZly8gdj05mufr9j30l00l0dq4.jpg?KID=imgbed,tva&Expires=1645010805&ssig=pKJtZwv%2FHm","following":false,"verified":true,"verified_type":2,"remark":"","avatar_large":"https:\/\/tvax4.sinaimg.cn\/crop.0.0.756.756.180\/006QZngZly8gdj05mufr9j30l00l0dq4.jpg?KID=imgbed,tva&Expires=1645010805&ssig=POD2VKV4LB","avatar_hd":"https:\/\/tvax4.sinaimg.cn\/crop.0.0.756.756.1024\/006QZngZly8gdj05mufr9j30l00l0dq4.jpg?KID=imgbed,tva&Expires=1645010805&ssig=RBGOJz6PB6","verified_type_ext":50,"follow_me":false,"mbtype":12,"mbrank":6,"level":2,"type":1,"story_read_state":-1,"allow_msg":1,"friendships_relation":0,"close_friends_type":0,"special_follow":false}}]},"fans_scheme":"https:\/\/m.weibo.cn\/c\/attention\/visit?showmenu=0&sign=6279793937&source=MQ%3D%3D&role=NA%3D%3D&luicode=10000011&lfid=1005056279793937","follow_scheme":"https:\/\/m.weibo.cn\/c\/attention\/visit?showmenu=0&sign=6279793937&source=MA%3D%3D&role=NA%3D%3D&luicode=10000011&lfid=1005056279793937","tabsInfo":{"selectedTab":1,"tabs":[{"id":1,"tabKey":"profile","must_show":1,"hidden":0,"title":"\u7cbe\u9009","tab_type":"profile","containerid":"2302836279793937"},{"id":2,"tabKey":"weibo","must_show":1,"hidden":0,"title":"\u5fae\u535a","tab_type":"weibo","containerid":"1076036279793937","apipath":"\/profile\/statuses","tab_icon":"https:\/\/h5.sinaimg.cn\/upload\/1059\/799\/2021\/04\/01\/weibotab.png","tab_icon_dark":"https:\/\/h5.sinaimg.cn\/upload\/1059\/799\/2021\/04\/07\/weibotab_dark.png","url":"\/index\/my"},{"id":4,"tabKey":"original_video","must_show":0,"hidden":0,"title":"\u89c6\u9891","tab_type":"video","containerid":"2315676279793937"},{"id":10,"tabKey":"album","must_show":0,"hidden":0,"title":"\u76f8\u518c","tab_type":"album","containerid":"1078036279793937"}]},"profile_ext":"touid:6279793937","scheme":"sinaweibo:\/\/userinfo?uid=6279793937&_T_WM=38226655008&v_p=42&uid=6279793937&luicode=10000011&lfid=1005056279793937","showAppTips":0}}

View File

@ -0,0 +1 @@
{"ok":0,"msg":"\u8fd9\u91cc\u8fd8\u6ca1\u6709\u5185\u5bb9","data":{"cards":[]}}

52
tests/test_config.py Normal file
View File

@ -0,0 +1,52 @@
import typing
import pytest
from nonebug.app import App
if typing.TYPE_CHECKING:
import sys
sys.path.append("./src/plugins")
import nonebot_bison
from nonebot_bison.config import Config
@pytest.fixture
def config(app: App):
from nonebot_bison import config
config.start_up()
return config.Config()
def test_create_and_get(config: "Config", app: App):
from nonebot_bison import types
from nonebot_bison.types import Target
config.add_subscribe(
user="123",
user_type="group",
target="weibo_id",
target_name="weibo_name",
target_type="weibo",
cats=[],
tags=[],
)
confs = config.list_subscribe("123", "group")
assert len(confs) == 1
assert config.target_user_cache["weibo"][Target("weibo_id")] == [
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"]

View File

@ -1,52 +1,103 @@
import typing
import pytest
import respx
from httpx import Response
from nonebot.adapters.onebot.v11.event import Sender
from nonebot.adapters.onebot.v11.message import MessageSegment
from nonebug.app import App
if typing.TYPE_CHECKING:
import sys
from .platforms.utils import get_json
from .utils import fake_admin_user, fake_group_message_event
sys.path.append("./src/plugins")
import nonebot_bison
@pytest.mark.asyncio
@respx.mock
async def test_add_with_target(app: App):
from nonebot.adapters.onebot.v11.message import Message
from nonebot_bison.config import Config
from nonebot_bison.config_manager import add_sub_matcher, common_platform
from nonebot_bison.platform import platform_manager
config = Config()
config.user_target.truncate()
@pytest.fixture
def config(app: App):
from nonebot_bison import config
config.start_up()
return config.Config()
def test_create_and_get(config: "Config", app: App):
from nonebot_bison import types
from nonebot_bison.types import Target
config.add_subscribe(
user="123",
user_type="group",
target="weibo_id",
target_name="weibo_name",
target_type="weibo",
cats=[],
tags=[],
ak_list_router = respx.get(
"https://m.weibo.cn/api/container/getIndex?containerid=1005056279793937"
)
confs = config.list_subscribe("123", "group")
assert len(confs) == 1
assert config.target_user_cache["weibo"][Target("weibo_id")] == [
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=[],
ak_list_router.mock(
return_value=Response(200, json=get_json("weibo_ak_profile.json"))
)
confs = config.list_subscribe("123", "group")
assert len(confs) == 1
assert confs[0]["cats"] == ["1"]
ak_list_bad_router = respx.get(
"https://m.weibo.cn/api/container/getIndex?containerid=100505000"
)
ak_list_bad_router.mock(
return_value=Response(200, json=get_json("weibo_err_profile.json"))
)
async with app.test_matcher(add_sub_matcher) as ctx:
bot = ctx.create_bot()
event_1 = fake_group_message_event(
message=Message("添加订阅"),
sender=Sender(card="", nickname="test", role="admin"),
to_me=True,
)
ctx.receive_event(bot, event_1)
ctx.should_pass_rule()
ctx.should_call_send(
event_1,
Message(
"请输入想要订阅的平台,目前支持,请输入冒号左边的名称:\n"
+ "".join(
[
"{}{}\n".format(
platform_name, platform_manager[platform_name].name
)
for platform_name in common_platform
]
)
+ "要查看全部平台请输入:“全部”"
),
True,
)
event_2 = fake_group_message_event(
message=Message("全部"), sender=Sender(card="", nickname="test", role="admin")
)
ctx.receive_event(bot, event_2)
ctx.should_rejected()
ctx.should_call_send(
event_2,
(
"全部平台\n"
+ "\n".join(
[
"{}{}".format(platform_name, platform.name)
for platform_name, platform in platform_manager.items()
]
)
),
True,
)
event_3 = fake_group_message_event(
message=Message("weibo"), sender=fake_admin_user
)
ctx.receive_event(bot, event_3)
ctx.should_call_send(
event_3,
Message(
"请输入订阅用户的id详情查阅https://nonebot-bison.vercel.app/usage/#%E6%89%80%E6%94%AF%E6%8C%81%E5%B9%B3%E5%8F%B0%E7%9A%84uid"
),
True,
)
event_4_err = fake_group_message_event(
message=Message("000"), sender=fake_admin_user
)
import ipdb
ipdb.set_trace()
ctx.receive_event(bot, event_4_err)
ctx.should_call_send(event_4_err, "id输入错误", True)
ctx.should_rejected()
event_4_ok = fake_group_message_event(
message=Message("6279793937"), sender=fake_admin_user
)
ctx.receive_event(bot, event_4_ok)
ctx.should_call_send(event_4_ok, "id输入错误", True)

70
tests/utils.py Normal file
View File

@ -0,0 +1,70 @@
from typing import TYPE_CHECKING
from typing_extensions import Literal
if TYPE_CHECKING:
from nonebot.adapters.onebot.v11 import GroupMessageEvent, PrivateMessageEvent
def fake_group_message_event(**field) -> "GroupMessageEvent":
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message
from nonebot.adapters.onebot.v11.event import Sender
from pydantic import create_model
_Fake = create_model("_Fake", __base__=GroupMessageEvent)
class FakeEvent(_Fake):
time: int = 1000000
self_id: int = 1
post_type: Literal["message"] = "message"
sub_type: str = "normal"
user_id: int = 10
message_type: Literal["group"] = "group"
group_id: int = 10000
message_id: int = 1
message: Message = Message("test")
raw_message: str = "test"
font: int = 0
sender: Sender = Sender(
card="",
nickname="test",
role="member",
)
to_me: bool = False
class Config:
extra = "forbid"
return FakeEvent(**field)
def fake_private_message_event(**field) -> "PrivateMessageEvent":
from nonebot.adapters.onebot.v11 import Message, PrivateMessageEvent
from nonebot.adapters.onebot.v11.event import Sender
from pydantic import create_model
_Fake = create_model("_Fake", __base__=PrivateMessageEvent)
class FakeEvent(_Fake):
time: int = 1000000
self_id: int = 1
post_type: Literal["message"] = "message"
sub_type: str = "friend"
user_id: int = 10
message_type: Literal["private"] = "private"
message_id: int = 1
message: Message = Message("test")
raw_message: str = "test"
font: int = 0
sender: Sender = Sender(nickname="test")
to_me: bool = False
class Config:
extra = "forbid"
return FakeEvent(**field)
from nonebot.adapters.onebot.v11.event import Sender
fake_admin_user = Sender(nickname="test", role="admin")