diff --git a/pyproject.toml b/pyproject.toml index b8deb962..b3cd33a0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -127,7 +127,7 @@ win32-setctime = "1.1.0" wordcloud = "1.8.2.2" [tool.nonebot] -plugins = ["nonebot_plugin_guild_patch"] +plugins = ["nonebot_plugin_guild_patch", "nonebot_bison"] plugin_dirs = ["src/plugins"] adapters = [{name = "OneBot V11", module_name = "nonebot.adapters.onebot.v11", project_link = "nonebot-adapter-onebot", desc = "OneBot V11 协议"}] diff --git a/src/plugins/nonebot_bison/__init__.py b/src/plugins/nonebot_bison/__init__.py deleted file mode 100644 index 90da7a1a..00000000 --- a/src/plugins/nonebot_bison/__init__.py +++ /dev/null @@ -1,47 +0,0 @@ -from nonebot.plugin import PluginMetadata, require - -require("nonebot_plugin_apscheduler") -require("nonebot_plugin_datastore") -require("nonebot_plugin_saa") - -import nonebot_plugin_saa - -from .plugin_config import PlugConfig, plugin_config -from . import post, send, theme, types, utils, config, platform, bootstrap, scheduler, admin_page, sub_manager - -__help__version__ = "0.8.2" -nonebot_plugin_saa.enable_auto_select_bot() - -__help__plugin__name__ = "nonebot_bison" -__usage__ = ( - "本bot可以提供b站、微博等社交媒体的消息订阅,详情请查看本bot文档," - f"或者{'at本bot' if plugin_config.bison_to_me else '' }发送“添加订阅”订阅第一个帐号," - "发送“查询订阅”或“删除订阅”管理订阅" -) - -__supported_adapters__ = nonebot_plugin_saa.__plugin_meta__.supported_adapters - -__plugin_meta__ = PluginMetadata( - name="Bison", - description="通用订阅推送插件", - usage=__usage__, - type="application", - homepage="https://github.com/felinae98/nonebot-bison", - config=PlugConfig, - supported_adapters=__supported_adapters__, - extra={"version": __help__version__, "docs": "https://nonebot-bison.netlify.app/"}, -) - -__all__ = [ - "admin_page", - "bootstrap", - "config", - "sub_manager", - "post", - "scheduler", - "send", - "platform", - "types", - "utils", - "theme", -] diff --git a/src/plugins/nonebot_bison/admin_page/__init__.py b/src/plugins/nonebot_bison/admin_page/__init__.py deleted file mode 100644 index 4c2d4e68..00000000 --- a/src/plugins/nonebot_bison/admin_page/__init__.py +++ /dev/null @@ -1,94 +0,0 @@ -import os -from pathlib import Path -from typing import TYPE_CHECKING - -from nonebot.log import logger -from nonebot.rule import to_me -from nonebot.typing import T_State -from nonebot import get_driver, on_command -from nonebot.adapters.onebot.v11 import Bot -from nonebot.adapters.onebot.v11.event import PrivateMessageEvent - -from .api import router as api_router -from ..plugin_config import plugin_config -from .token_manager import token_manager as tm - -if TYPE_CHECKING: - from nonebot.drivers.fastapi import Driver - - -STATIC_PATH = (Path(__file__).parent / "dist").resolve() - - -def init_fastapi(driver: "Driver"): - import socketio - from fastapi.applications import FastAPI - from fastapi.staticfiles import StaticFiles - - 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) - - def lookup_path(self, path: str) -> tuple[str, os.stat_result | None]: - full_path, stat_res = super().lookup_path(path) - if stat_res is None: - return super().lookup_path(self.index) - return (full_path, stat_res) - - def register_router_fastapi(driver: "Driver", socketio): - static_path = STATIC_PATH - nonebot_app = FastAPI( - title="nonebot-bison", - description="nonebot-bison webui and api", - ) - nonebot_app.include_router(api_router) - nonebot_app.mount("/", SinglePageApplication(directory=static_path), name="bison-frontend") - - app = driver.server_app - app.mount("/bison", nonebot_app, "nonebot-bison") - - register_router_fastapi(driver, socket_app) - host = str(driver.config.host) - port = driver.config.port - if host in ["0.0.0.0", "127.0.0.1"]: - host = "localhost" - logger.opt(colors=True).info(f"Nonebot Bison frontend will be running at: http://{host}:{port}/bison") - logger.opt(colors=True).info("该页面不能被直接访问,请私聊bot 后台管理 以获取可访问地址") - - -def register_get_token_handler(): - get_token = on_command("后台管理", rule=to_me(), priority=5, aliases={"管理后台"}) - - @get_token.handle() - 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.outer_url / 'auth' / token}") - - get_token.__help__name__ = "获取后台管理地址" # type: ignore - get_token.__help__info__ = "获取管理bot后台的地址,该地址会在一段时间过后过期,请不要泄漏该地址" # type: ignore - - -def get_fastapi_driver() -> "Driver | None": - try: - from nonebot.drivers.fastapi import Driver - - if (driver := get_driver()) and isinstance(driver, Driver): - return driver - return None - - except ImportError: - return None - - -if (STATIC_PATH / "index.html").exists(): - if driver := get_fastapi_driver(): - init_fastapi(driver) - register_get_token_handler() - else: - logger.warning("your driver is not fastapi, webui feature will be disabled") -else: - logger.warning("Frontend file not found, please compile it or use docker or pypi version") diff --git a/src/plugins/nonebot_bison/admin_page/api.py b/src/plugins/nonebot_bison/admin_page/api.py deleted file mode 100644 index afe834e0..00000000 --- a/src/plugins/nonebot_bison/admin_page/api.py +++ /dev/null @@ -1,199 +0,0 @@ -import nonebot -from fastapi import status -from fastapi.routing import APIRouter -from fastapi.param_functions import Depends -from fastapi.exceptions import HTTPException -from nonebot_plugin_saa import TargetQQGroup -from nonebot_plugin_saa.auto_select_bot import get_bot -from fastapi.security.oauth2 import OAuth2PasswordBearer - -from ..types import WeightConfig -from ..apis import check_sub_target -from .jwt import load_jwt, pack_jwt -from ..types import Target as T_Target -from ..utils.get_bot import get_groups -from ..platform import platform_manager -from .token_manager import token_manager -from ..config.db_config import SubscribeDupException -from ..config import NoSuchUserException, NoSuchTargetException, NoSuchSubscribeException, config -from .types import ( - TokenResp, - GlobalConf, - StatusResp, - SubscribeResp, - PlatformConfig, - AddSubscribeReq, - SubscribeConfig, - SubscribeGroupDetail, -) - -router = APIRouter(prefix="/api", tags=["api"]) - -oath_scheme = OAuth2PasswordBearer(tokenUrl="token") - - -async def get_jwt_obj(token: str = Depends(oath_scheme)): - obj = load_jwt(token) - 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) - - -@router.get("/global_conf") -async def get_global_conf() -> GlobalConf: - res = {} - for platform_name, platform in platform_manager.items(): - res[platform_name] = PlatformConfig( - platformName=platform_name, - categories=platform.categories, - enabledTag=platform.enable_tag, - name=platform.name, - hasTarget=getattr(platform, "has_target"), - ) - return GlobalConf(platformConf=res) - - -async def get_admin_groups(qq: int): - res = [] - for group in await get_groups(): - group_id = group["group_id"] - bot = get_bot(TargetQQGroup(group_id=group_id)) - if not bot: - continue - users = await bot.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 - - -@router.get("/auth") -async def auth(token: str) -> TokenResp: - if qq_tuple := token_manager.get_user(token): - qq, nickname = qq_tuple - if str(qq) in nonebot.get_driver().config.superusers: - jwt_obj = { - "id": qq, - "type": "admin", - "groups": [ - { - "id": info["group_id"], - "name": info["group_name"], - } - for info in await get_groups() - ], - } - ret_obj = TokenResp( - type="admin", - name=nickname, - id=qq, - token=pack_jwt(jwt_obj), - ) - return ret_obj - if admin_groups := await get_admin_groups(int(qq)): - jwt_obj = {"id": str(qq), "type": "user", "groups": admin_groups} - ret_obj = TokenResp( - type="user", - name=nickname, - id=qq, - token=pack_jwt(jwt_obj), - ) - return ret_obj - else: - raise HTTPException(400, "permission denied") - else: - raise HTTPException(400, "code error") - - -@router.get("/subs") -async def get_subs_info(jwt_obj: dict = Depends(get_jwt_obj)) -> SubscribeResp: - groups = jwt_obj["groups"] - res: SubscribeResp = {} - for group in groups: - group_id = group["id"] - raw_subs = await config.list_subscribe(TargetQQGroup(group_id=group_id)) - subs = [ - SubscribeConfig( - platformName=sub.target.platform_name, - targetName=sub.target.target_name, - cats=sub.categories, - tags=sub.tags, - target=sub.target.target, - ) - for sub in raw_subs - ] - res[group_id] = SubscribeGroupDetail(name=group["name"], subscribes=subs) - return res - - -@router.get("/target_name", dependencies=[Depends(get_jwt_obj)]) -async def get_target_name(platformName: str, target: str): - return {"targetName": await check_sub_target(platformName, T_Target(target))} - - -@router.post("/subs", dependencies=[Depends(check_group_permission)]) -async def add_group_sub(groupNumber: int, req: AddSubscribeReq) -> StatusResp: - try: - await config.add_subscribe( - TargetQQGroup(group_id=groupNumber), - T_Target(req.target), - req.targetName, - req.platformName, - req.cats, - req.tags, - ) - return StatusResp(ok=True, msg="") - except SubscribeDupException: - raise HTTPException(status.HTTP_400_BAD_REQUEST, "subscribe duplicated") - - -@router.delete("/subs", dependencies=[Depends(check_group_permission)]) -async def del_group_sub(groupNumber: int, platformName: str, target: str): - try: - await config.del_subscribe(TargetQQGroup(group_id=groupNumber), target, platformName) - except (NoSuchUserException, NoSuchSubscribeException): - raise HTTPException(status.HTTP_400_BAD_REQUEST, "no such user or subscribe") - return StatusResp(ok=True, msg="") - - -@router.patch("/subs", dependencies=[Depends(check_group_permission)]) -async def update_group_sub(groupNumber: int, req: AddSubscribeReq): - try: - await config.update_subscribe( - TargetQQGroup(group_id=groupNumber), - req.target, - req.targetName, - req.platformName, - req.cats, - req.tags, - ) - except (NoSuchUserException, NoSuchSubscribeException): - raise HTTPException(status.HTTP_400_BAD_REQUEST, "no such user or subscribe") - return StatusResp(ok=True, msg="") - - -@router.get("/weight", dependencies=[Depends(check_is_superuser)]) -async def get_weight_config(): - return await config.get_all_weight_config() - - -@router.put("/weight", dependencies=[Depends(check_is_superuser)]) -async def update_weigth_config(platformName: str, target: str, weight_config: WeightConfig): - try: - await config.update_time_weight_config(T_Target(target), platformName, weight_config) - except NoSuchTargetException: - raise HTTPException(status.HTTP_400_BAD_REQUEST, "no such subscribe") - return StatusResp(ok=True, msg="") diff --git a/src/plugins/nonebot_bison/admin_page/dist/.gitkeep b/src/plugins/nonebot_bison/admin_page/dist/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/plugins/nonebot_bison/admin_page/dist/asset-manifest.json b/src/plugins/nonebot_bison/admin_page/dist/asset-manifest.json deleted file mode 100644 index b18930bf..00000000 --- a/src/plugins/nonebot_bison/admin_page/dist/asset-manifest.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "files": { - "main.css": "/bison/static/css/main.0c26bbf1.css", - "main.js": "/bison/static/js/main.4b16c60f.js", - "static/js/488.2a94df72.chunk.js": "/bison/static/js/488.2a94df72.chunk.js", - "index.html": "/bison/index.html", - "main.0c26bbf1.css.map": "/bison/static/css/main.0c26bbf1.css.map", - "main.4b16c60f.js.map": "/bison/static/js/main.4b16c60f.js.map", - "488.2a94df72.chunk.js.map": "/bison/static/js/488.2a94df72.chunk.js.map" - }, - "entrypoints": [ - "static/css/main.0c26bbf1.css", - "static/js/main.4b16c60f.js" - ] -} \ No newline at end of file diff --git a/src/plugins/nonebot_bison/admin_page/dist/favicon.ico b/src/plugins/nonebot_bison/admin_page/dist/favicon.ico deleted file mode 100644 index 354202a4..00000000 Binary files a/src/plugins/nonebot_bison/admin_page/dist/favicon.ico and /dev/null differ diff --git a/src/plugins/nonebot_bison/admin_page/dist/index.html b/src/plugins/nonebot_bison/admin_page/dist/index.html deleted file mode 100644 index 8076f154..00000000 --- a/src/plugins/nonebot_bison/admin_page/dist/index.html +++ /dev/null @@ -1 +0,0 @@ -