From 2711d8844b1b4ef53b8d97254c602234be26ad42 Mon Sep 17 00:00:00 2001 From: snowy Date: Thu, 21 Mar 2024 14:52:02 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=8F=92=E4=BB=B6=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E9=94=99=E8=AF=AF=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + requirements.txt | 4 +- src/liteyuki_main/__init__.py | 7 +- src/liteyuki_main/loader.py | 8 +- src/plugins/liteyuki_markdowntest.py | 5 +- src/plugins/liteyuki_plugin_eventpush.py | 9 ++- src/plugins/liteyuki_plugin_npm/__init__.py | 4 +- src/plugins/liteyuki_plugin_npm/common.py | 7 +- src/plugins/liteyuki_plugin_npm/installer.py | 78 ++++++++++++-------- src/plugins/liteyuki_plugin_npm/manager.py | 30 ++++++-- src/plugins/liteyuki_plugin_user/__init__.py | 5 +- src/resources/lang/en.lang | 8 +- src/resources/lang/ja.lang | 8 +- src/resources/lang/zh-CN.lang | 12 ++- src/utils/data.py | 56 +++++++------- src/utils/data_manager.py | 8 +- src/utils/language.py | 6 +- src/utils/permission.py | 7 ++ 18 files changed, 179 insertions(+), 84 deletions(-) create mode 100644 src/utils/permission.py diff --git a/.gitignore b/.gitignore index 820e189..dab60f0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .cache/ data/ +db/ plugins/ _config.yml config.example.yml diff --git a/requirements.txt b/requirements.txt index 731c79d..196dbdc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,8 +6,10 @@ dash==2.16.1 nonebot2[fastapi]==2.2.1 nonebot-adapter-onebot==2.4.3 nonebot-plugin-alconna==0.41.0 +pip==24.0 psutil==5.9.8 pydantic==2.6.4 PyYAML~=6.0.1 typing_extensions~=4.10.0 -starlette~=0.36.3 \ No newline at end of file +starlette~=0.36.3 +pip==24.0 \ No newline at end of file diff --git a/src/liteyuki_main/__init__.py b/src/liteyuki_main/__init__.py index ec55400..060c33d 100644 --- a/src/liteyuki_main/__init__.py +++ b/src/liteyuki_main/__init__.py @@ -1,8 +1,10 @@ import nonebot from nonebot.plugin import PluginMetadata from src.utils.language import get_system_lang +from src.utils.data_manager import * from .loader import * from .webdash import * +from src.utils.config import config __author__ = "snowykami" __plugin_meta__ = PluginMetadata( @@ -10,9 +12,12 @@ __plugin_meta__ = PluginMetadata( description="轻雪主程序插件,包含了许多初始化的功能", usage="", homepage="https://github.com/snowykami/LiteyukiBot", + extra={ + "liteyuki_plugin": True, + } ) -from src.utils.config import config +auto_migrate() sys_lang = get_system_lang() nonebot.logger.info(sys_lang.get("main.current_language", LANG=sys_lang.get("language.name"))) diff --git a/src/liteyuki_main/loader.py b/src/liteyuki_main/loader.py index 4ddce8c..ea88a03 100644 --- a/src/liteyuki_main/loader.py +++ b/src/liteyuki_main/loader.py @@ -2,6 +2,7 @@ import os import nonebot.plugin +from src.utils.data_manager import InstalledPlugin, plugin_db from src.utils.language import load_from_dir from src.utils.resource import load_resource_from_dir @@ -10,4 +11,9 @@ RESOURCE_PATH = "src/resources" load_resource_from_dir(RESOURCE_PATH) nonebot.plugin.load_plugins("src/plugins") -nonebot.plugin.load_plugins("plugins") \ No newline at end of file +nonebot.plugin.load_plugins("plugins") + +installed_plugins = plugin_db.all(InstalledPlugin) +if installed_plugins: + for install_plugin in plugin_db.all(InstalledPlugin): + nonebot.load_plugin(install_plugin.module_name) \ No newline at end of file diff --git a/src/plugins/liteyuki_markdowntest.py b/src/plugins/liteyuki_markdowntest.py index b5837f6..a6fe3cb 100644 --- a/src/plugins/liteyuki_markdowntest.py +++ b/src/plugins/liteyuki_markdowntest.py @@ -52,4 +52,7 @@ __plugin_meta__ = PluginMetadata( description="用于测试Markdown的插件", usage="", homepage="https://github.com/snowykami/LiteyukiBot", -) \ No newline at end of file + extra={ + "liteyuki_plugin": True, + } +) diff --git a/src/plugins/liteyuki_plugin_eventpush.py b/src/plugins/liteyuki_plugin_eventpush.py index 78b852a..a6b8a4e 100644 --- a/src/plugins/liteyuki_plugin_eventpush.py +++ b/src/plugins/liteyuki_plugin_eventpush.py @@ -104,8 +104,8 @@ async def _(event: T_MessageEvent, bot: T_Bot): for l in str(event.message).split("\n"): msg_formatted += f"**{l.strip()}**\n" push_message = ( - f"> From {event.sender.nickname}@{push.source.session_type}.{push.source.session_id}\n> Bot {bot.self_id}\n\n" - f"{msg_formatted}") + f"> From {event.sender.nickname}@{push.source.session_type}.{push.source.session_id}\n> Bot {bot.self_id}\n\n" + f"{msg_formatted}") await send_markdown(push_message, bot2, event=event) return @@ -116,4 +116,7 @@ __plugin_meta__ = PluginMetadata( description="事件推送插件,支持单向和双向推送,支持跨Bot推送", usage="", homepage="https://github.com/snowykami/LiteyukiBot", -) \ No newline at end of file + extra={ + "liteyuki_plugin": True, + } +) diff --git a/src/plugins/liteyuki_plugin_npm/__init__.py b/src/plugins/liteyuki_plugin_npm/__init__.py index 53606cc..9bf41ca 100644 --- a/src/plugins/liteyuki_plugin_npm/__init__.py +++ b/src/plugins/liteyuki_plugin_npm/__init__.py @@ -3,7 +3,6 @@ from .manager import * from .installer import * from .helper import * - __author__ = "snowykami" __plugin_meta__ = PluginMetadata( name="轻雪插件管理", @@ -16,4 +15,7 @@ __plugin_meta__ = PluginMetadata( ), type="application", homepage="https://github.com/snowykami/LiteyukiBot", + extra={ + "liteyuki_plugin": True, + } ) diff --git a/src/plugins/liteyuki_plugin_npm/common.py b/src/plugins/liteyuki_plugin_npm/common.py index 94be014..f8b307b 100644 --- a/src/plugins/liteyuki_plugin_npm/common.py +++ b/src/plugins/liteyuki_plugin_npm/common.py @@ -1,13 +1,8 @@ from src.utils.data import Database, LiteModel -from src.utils.data_manager import plugin_db +from src.utils.data_manager import InstalledPlugin, plugin_db LNPM_COMMAND_START = "lnpm" -class InstalledPlugin(LiteModel): - module_name: str - - -plugin_db.auto_migrate(InstalledPlugin) diff --git a/src/plugins/liteyuki_plugin_npm/installer.py b/src/plugins/liteyuki_plugin_npm/installer.py index 2c047f4..5909781 100644 --- a/src/plugins/liteyuki_plugin_npm/installer.py +++ b/src/plugins/liteyuki_plugin_npm/installer.py @@ -5,26 +5,24 @@ import sys from io import StringIO from typing import Optional +import aiofiles +import aiohttp import nonebot +import pip from arclet.alconna import Arparma, MultiVar from nonebot.permission import SUPERUSER -from nonebot.utils import run_sync -from nonebot_plugin_alconna import on_alconna, Alconna, Args, Subcommand -import pip - -import aiohttp, aiofiles -from typing_extensions import Any +from nonebot_plugin_alconna import Alconna, Args, Subcommand, on_alconna from src.utils.language import get_user_lang from src.utils.message import Markdown as md, send_markdown from src.utils.resource import get_res from src.utils.typing import T_Bot, T_MessageEvent - from .common import * +from src.utils.data_manager import InstalledPlugin npm_alc = on_alconna( Alconna( - "lnpm", + ["lnpm", "插件管理"], Subcommand( "update", alias=["u"], @@ -93,40 +91,54 @@ async def _(result: Arparma, event: T_MessageEvent, bot: T_Bot): btn_install = md.button(ulang.get('npm.install'), 'lnpm install %s' % plugin.module_name) link_page = md.link(ulang.get('npm.homepage'), plugin.homepage) - reply += (f"\n{btn_install} | **{plugin.name}**\n" + reply += (f"\n{btn_install} **{plugin.name}**\n" f"\n > **{plugin.desc}**\n" - f"\n > {ulang.get('npm.author')}: {plugin.author} | {link_page}\n\n***\n") + f"\n > {ulang.get('npm.author')}: {plugin.author} {link_page}\n\n***\n") if len(rs) > max_show: - reply += f"\n{ulang.get('npm.too_many_results')}" + reply += f"\n{ulang.get('npm.too_many_results', HIDE_NUM=len(rs) - max_show)}" else: reply = ulang.get("npm.search_no_result") await send_markdown(reply, bot, event=event) elif result.subcommands.get("install"): - plugin_name: str = result.subcommands["install"].args.get("plugin_name") - r, log = npm_install(plugin_name) + plugin_module_name: str = result.subcommands["install"].args.get("plugin_name") + await npm_alc.send(ulang.get("npm.installing", NAME=plugin_module_name)) + r, log = npm_install(plugin_module_name) + log = log.replace("\\", "/") if r: - nonebot.load_plugin(plugin_name) - installed_plugin = InstalledPlugin(module_name=plugin_name) - store_plugin = await get_store_plugin(plugin_name) - plugin_db.save(installed_plugin) - await send_markdown( - f"**{ulang.get('npm.install_success', NAME=store_plugin.name)}**\n\n" - f"```\n{log}\n```", - bot, - event=event - ) + nonebot.load_plugin(plugin_module_name) # 加载插件 + installed_plugin = InstalledPlugin(module_name=plugin_module_name) # 构造插件信息模型 + store_plugin = await get_store_plugin(plugin_module_name) # 获取商店中的插件信息 + found_in_db_plugin = plugin_db.first(InstalledPlugin, "module_name = ?", plugin_module_name) # 查询数据库中是否已经安装 + if found_in_db_plugin is None: + plugin_db.save(installed_plugin) + info = ulang.get('npm.install_success', NAME=store_plugin.name).replace('_', r'\\_') # markdown转义 + await send_markdown( + f"{info}\n\n" + f"```\n{log}\n```", + bot, + event=event + ) + else: + await npm_alc.finish(ulang.get('npm.plugin_already_installed', NAME=store_plugin.name)) else: + info = ulang.get('npm.install_failed', NAME=plugin_module_name).replace('_', r'\\_') await send_markdown( - f"{ulang.get('npm.install_success', NAME=plugin_name)}\n\n" + f"{info}\n\n" f"```\n{log}\n```", bot, event=event ) elif result.subcommands.get("remove"): - plugin_name: str = result.subcommands["remove"].args.get("plugin_name") - await npm_alc.finish(ulang.get("npm.remove_success")) + plugin_module_name: str = result.subcommands["remove"].args.get("plugin_name") + found_installed_plugin: InstalledPlugin = plugin_db.first(InstalledPlugin, "module_name = ?", plugin_module_name) + if found_installed_plugin: + plugin_db.delete(InstalledPlugin, "module_name = ?", plugin_module_name) + reply = f"{ulang.get('npm.remove_success', NAME=found_installed_plugin.module_name)}" + await npm_alc.finish(reply) + else: + await npm_alc.finish(ulang.get("npm.plugin_not_installed", NAME=plugin_module_name)) async def npm_update() -> bool: @@ -212,19 +224,25 @@ def npm_install(plugin_module_name) -> tuple[bool, str]: sys.stderr = buffer mirrors = [ - "https://pypi.tuna.tsinghua.edu.cn/simple", - "https://pypi.mirrors.cqupt.edu.cn/simple/", - "https://pypi.org/simple", + "https://pypi.mirrors.cqupt.edu.cn/simple", # 重庆邮电大学 + "https://pypi.tuna.tsinghua.edu.cn/simple", # 清华大学 + "https://pypi.liteyuki.icu/simple", # 轻雪镜像 + "https://pypi.org/simple", # 官方源 ] # 使用pip安装包,对每个镜像尝试一次,成功后返回值 success = False for mirror in mirrors: try: + nonebot.logger.info(f"npm_install try mirror: {mirror}") result = pip.main(['install', plugin_module_name, "-i", mirror]) success = result == 0 - break + if success: + break + else: + nonebot.logger.warning(f"npm_install failed, try next mirror.") except Exception as e: + success = False continue diff --git a/src/plugins/liteyuki_plugin_npm/manager.py b/src/plugins/liteyuki_plugin_npm/manager.py index 49df295..3945c9e 100644 --- a/src/plugins/liteyuki_plugin_npm/manager.py +++ b/src/plugins/liteyuki_plugin_npm/manager.py @@ -2,12 +2,14 @@ import nonebot.plugin from nonebot import on_command from nonebot.permission import SUPERUSER +from src.utils.data_manager import InstalledPlugin, plugin_db from src.utils.message import Markdown as md, send_markdown +from src.utils.permission import GROUP_ADMIN, GROUP_OWNER from src.utils.typing import T_Bot, T_MessageEvent from src.utils.language import get_user_lang -list_plugins = on_command("list-plugin", aliases={"列出插件", "插件列表"}, priority=0, permission=SUPERUSER) -toggle_plugin = on_command("enable-plugin", aliases={"启用插件", "禁用插件", "disable-plugin"}, priority=0, permission=SUPERUSER) +list_plugins = on_command("list-plugin", aliases={"列出插件", "插件列表"}, priority=0) +toggle_plugin = on_command("enable-plugin", aliases={"启用插件", "停用插件", "disable-plugin"}, priority=0, permission=SUPERUSER) @list_plugins.handle() @@ -16,12 +18,24 @@ async def _(event: T_MessageEvent, bot: T_Bot): reply = f"# {lang.get('npm.loaded_plugins')} | {lang.get('npm.total', TOTAL=len(nonebot.get_loaded_plugins()))} \n***" for plugin in nonebot.get_loaded_plugins(): # 检查是否有 metadata 属性 + btn_help = md.button(lang.get('npm.help'), f'help {plugin.name}', False) + reply += f"\n{btn_help} " if plugin.metadata: - reply += (f"\n{md.button(lang.get('npm.help'), 'help %s' % plugin.name, False, False)} " - f"**{plugin.metadata.name}**\n" - f"\n > {plugin.metadata.description}\n\n***\n") + reply += (f"**{plugin.metadata.name}**\n" + f"\n > {plugin.metadata.description}") else: - reply += (f"\n{md.button(lang.get('npm.help'), 'help %s' % plugin.name, False, False)} " - f"**{plugin.name}**\n" - f"\n > {lang.get('npm.no_description')}\n\n***\n") + reply += (f"**{plugin.name}**\n" + f"\n > {lang.get('npm.no_description')}") + # if await GROUP_ADMIN(bot=bot, event=event) or await GROUP_OWNER(bot=bot, event=event) or await SUPERUSER(bot=bot, event=event): + if await GROUP_ADMIN(bot, event) or await GROUP_OWNER(bot, event) or await SUPERUSER(bot, event): + btn_enable = md.button(lang.get('npm.enable'), f'enable-plugin {plugin.module_name}') + btn_disable = md.button(lang.get('npm.disable'), f'disable-plugin {plugin.module_name}') + reply += f"\n > {btn_enable} {btn_disable}" + if await SUPERUSER(bot, event): + plugin_in_database = plugin_db.first(InstalledPlugin, 'module_name = ?', plugin.module_name) + btn_remove = ( + md.button(lang.get('npm.uninstall'), f'lnpm remove {plugin.module_name}')) if plugin_in_database else lang.get( + 'npm.uninstall') + reply += f" {btn_remove}" + reply += "\n\n***\n" await send_markdown(reply, bot, event=event) diff --git a/src/plugins/liteyuki_plugin_user/__init__.py b/src/plugins/liteyuki_plugin_user/__init__.py index 25383dd..9bb7d4c 100644 --- a/src/plugins/liteyuki_plugin_user/__init__.py +++ b/src/plugins/liteyuki_plugin_user/__init__.py @@ -8,4 +8,7 @@ __plugin_meta__ = PluginMetadata( description="用户管理插件", usage="", homepage="https://github.com/snowykami/LiteyukiBot", -) \ No newline at end of file + extra={ + "liteyuki_plugin": True, + } +) diff --git a/src/resources/lang/en.lang b/src/resources/lang/en.lang index 89a356a..368a3de 100644 --- a/src/resources/lang/en.lang +++ b/src/resources/lang/en.lang @@ -10,6 +10,8 @@ main.monitor.swap=SWAP main.monitor.disk=Disk main.monitor.usage=Usage +data_manager.migrate_success=Model {NAME} migration successful + npm.loaded_plugins=Loaded plugins npm.total=Total {TOTAL} npm.help=Help @@ -17,14 +19,18 @@ npm.disable=Disable npm.enable=Enable npm.install=Install npm.uninstall=Uninstall +npm.installing=Installing {NAME}... +npm.cannot_uninstall=Cannot uninstall npm.no_description=No description npm.store_update_success=Plugin store data updated successfully npm.store_update_failed=Plugin store data update failed npm.search_result=Search results npm.search_no_result=No result found -npm.too_many_results=Too many results found, please refine your search +npm.too_many_results=Too many results found, {HIDE_NUM} hidden, please refine your search npm.install_success={NAME} installed successfully npm.install_failed={NAME} installation failed +npm.plugin_not_installed={NAME} is not installed +npm.plugin_already_installed={NAME} is already installed npm.author=Author npm.homepage=Homepage npm.next_page=Next diff --git a/src/resources/lang/ja.lang b/src/resources/lang/ja.lang index ec48be5..66c619a 100644 --- a/src/resources/lang/ja.lang +++ b/src/resources/lang/ja.lang @@ -10,6 +10,8 @@ main.monitor.swap=スワップ main.monitor.disk=ディスク main.monitor.usage=使用率 +data_manager.migrate_success=データが正常に移行されました {NAME} + npm.loaded_plugins=読み込まれたプラグイン npm.total=合計 {TOTAL} npm.help=ヘルプ @@ -17,14 +19,18 @@ npm.disable=無効 npm.enable=有効 npm.install=インストール npm.uninstall=アンインストール +npm.installing={NAME} インストール中 +npm.cannot_uninstall=このプラグインはアンインストールできません npm.no_description=説明なし npm.store_update_success=プラグインストアのデータが正常に更新されました npm.store_update_failed=プラグインストアのデータの更新に失敗しました npm.search_result=検索結果 npm.search_no_result=検索結果がありません -npm.too_many_results=検索結果が多すぎます。ページをめくってください +npm.too_many_results=検索結果が多すぎます。{HIDE_NUM} 件の結果が非表示になりました npm.install_success={NAME} が正常にインストールされました npm.install_failed={NAME} のインストールに失敗しました +npm.plugin_not_installed={NAME} はインストールされていません +npm.plugin_already_installed={NAME} は既にインストールされています npm.author=著者 npm.homepage=ホームページ npm.next_page=次のページ diff --git a/src/resources/lang/zh-CN.lang b/src/resources/lang/zh-CN.lang index 8154477..e6ae8e9 100644 --- a/src/resources/lang/zh-CN.lang +++ b/src/resources/lang/zh-CN.lang @@ -10,6 +10,8 @@ main.monitor.swap=交换空间 main.monitor.disk=磁盘 main.monitor.usage=使用率 +data_manager.migrate_success=数据模型{NAME}迁移成功 + npm.loaded_plugins=已加载插件 npm.total=总计 {TOTAL} npm.help=帮助 @@ -17,16 +19,22 @@ npm.disable=停用 npm.enable=启用 npm.install=安装 npm.uninstall=卸载 +npm.installing=正在安装 {NAME} +npm.cannot_uninstall=无法卸载 npm.no_description=无描述 npm.store_update_success=插件商店数据更新成功 npm.store_update_failed=插件商店数据更新失败 npm.search_result=搜索结果 npm.search_no_result=无搜索结果 -npm.too_many_results=搜索结果过多,请限制关键字 +npm.too_many_results=搜索结果过多,{HIDE_NUM}已隐藏,请限制关键字 npm.install_success={NAME} 安装成功 npm.install_failed={NAME} 安装失败 +npm.remove_success={NAME} 卸载成功 +npm.remove_failed={NAME} 卸载失败 +npm.plugin_not_installed={NAME} 未安装 +npm.plugin_already_installed={NAME} 已安装,请勿重复安装 npm.author=作者 -npm.homepage=主页 +npm.homepage=项目主页 npm.next_page=下一页 npm.prev_page=上一页 diff --git a/src/utils/data.py b/src/utils/data.py index 843d06d..b0bad9d 100644 --- a/src/utils/data.py +++ b/src/utils/data.py @@ -88,12 +88,11 @@ class Database(BaseORMAdapter): } DEFAULT_TYPE = { - 'TEXT': '', - 'INTEGER': 0, - 'REAL': 0.0 + 'TEXT' : '', + 'INTEGER': 0, + 'REAL' : 0.0 } - FOREIGNID = 'FOREIGNID' JSON = 'JSON' ID = '$ID' @@ -115,6 +114,7 @@ class Database(BaseORMAdapter): Returns: """ + table_name = '' for model in args: model: type(LiteModel) # 检测并创建表,若模型未定义id字段则使用自增主键,有定义的话使用id字段,且id有可能为字符串 @@ -161,6 +161,7 @@ class Database(BaseORMAdapter): self.cursor.execute(f'ALTER TABLE {table_name} DROP COLUMN {field}') self.conn.commit() + nonebot.logger.success(f'Table {table_name} migrated successfully') def save(self, *models: LiteModel) -> int | tuple: """存储数据,检查id字段,如果有id字段则更新,没有则插入 @@ -171,9 +172,12 @@ class Database(BaseORMAdapter): Returns: id: 数据id,如果有多个数据则返回id元组 """ + ids = [] for model in models: table_name = model.__class__.__name__ + if not self._detect_for_table(table_name): + raise ValueError(f'表{table_name}不存在,请先迁移') key_list = [] value_list = [] # 处理外键,添加前缀'$IDFieldName' @@ -227,6 +231,17 @@ class Database(BaseORMAdapter): return json.dumps(return_data) + def _detect_for_table(self, table_name: str) -> bool: + """在进行增删查改前检测表是否存在 + + Args: + table_name: 表名 + + Returns: + + """ + return self.cursor.execute(f'SELECT * FROM sqlite_master WHERE type = "table" AND name = ?', (table_name,)).fetchone() + def first(self, model: type(LiteModel), conditions, *args, default: Any = None) -> LiteModel | None: """查询第一条数据 @@ -239,6 +254,10 @@ class Database(BaseORMAdapter): Returns: 数据 """ table_name = model.__name__ + + if not self._detect_for_table(table_name): + return default + self.cursor.execute(f'SELECT * FROM {table_name} WHERE {conditions}', args) if row_data := self.cursor.fetchone(): data = dict(row_data) @@ -258,7 +277,8 @@ class Database(BaseORMAdapter): """ table_name = model.__name__ - # 检测表是否存在,否则返回None + if not self._detect_for_table(table_name): + return default if conditions: self.cursor.execute(f'SELECT * FROM {table_name} WHERE {conditions}', args) @@ -281,27 +301,13 @@ class Database(BaseORMAdapter): """ table_name = model.__name__ + + if not self._detect_for_table(table_name): + return nonebot.logger.debug(f'DELETE FROM {table_name} WHERE {conditions}') self.cursor.execute(f'DELETE FROM {table_name} WHERE {conditions}', args) self.conn.commit() - def update(self, model: type(LiteModel), conditions: str, *args, operation: str): - """更新数据 - - Args: - model: 模型 - conditions: 查询条件 - *args: 参数化查询条件参数 - operation: 更新操作 - - Returns: - - """ - table_name = model.__name__ - nonebot.logger.debug(f'UPDATE {table_name} SET {operation} WHERE {conditions}') - self.cursor.execute(f'UPDATE {table_name} SET {operation} WHERE {conditions}', args) - self.conn.commit() - def convert_to_dict(self, data: dict) -> dict: """将json字符串转换为字典 @@ -318,7 +324,7 @@ class Database(BaseORMAdapter): for k, v in d.items(): if k.startswith(self.FOREIGNID): new_d[k.replace(self.FOREIGNID, '')] = load( - dict(self.cursor.execute(f'SELECT * FROM {v.split(":",2)[1]} WHERE id = ?', (v.split(":",2)[2],)).fetchone())) + dict(self.cursor.execute(f'SELECT * FROM {v.split(":", 2)[1]} WHERE id = ?', (v.split(":", 2)[2],)).fetchone())) elif k.startswith(self.JSON): new_d[k.replace(self.JSON, '')] = load(json.loads(v)) else: @@ -327,11 +333,11 @@ class Database(BaseORMAdapter): new_d = [] for i, v in enumerate(d): if isinstance(v, str) and v.startswith(self.ID): - new_d.append(load(dict(self.cursor.execute(f'SELECT * FROM {v.split(":",2)[1]} WHERE id = ?', (v.split(":",2)[2],)).fetchone()))) + new_d.append(load(dict(self.cursor.execute(f'SELECT * FROM {v.split(":", 2)[1]} WHERE id = ?', (v.split(":", 2)[2],)).fetchone()))) elif isinstance(v, BaseIterable): new_d.append(load(v)) else: new_d = d return new_d - return load(data) \ No newline at end of file + return load(data) diff --git a/src/utils/data_manager.py b/src/utils/data_manager.py index fe36b22..4e850cc 100644 --- a/src/utils/data_manager.py +++ b/src/utils/data_manager.py @@ -14,4 +14,10 @@ class User(LiteModel): lang: str = "en" -user_db.auto_migrate(User) +class InstalledPlugin(LiteModel): + module_name: str + + +def auto_migrate(): + user_db.auto_migrate(User) + plugin_db.auto_migrate(InstalledPlugin) diff --git a/src/utils/language.py b/src/utils/language.py index 2c41f96..d28f286 100644 --- a/src/utils/language.py +++ b/src/utils/language.py @@ -9,6 +9,7 @@ from typing_extensions import Any import nonebot +from src.utils.config import config from src.utils.data_manager import User, user_db _default_lang_code = "en" @@ -133,7 +134,10 @@ def get_user_lang(user_id: str) -> Language: """ 获取用户的语言代码 """ - user = user_db.first(User, "user_id = ?", user_id, default=User(user_id=user_id, username="Unknown", lang="en")) + user = user_db.first(User, "user_id = ?", user_id, default=User( + user_id=user_id, + username="Unknown", + lang=config.get("default_language", get_system_lang_code()))) return Language(user.lang) diff --git a/src/utils/permission.py b/src/utils/permission.py new file mode 100644 index 0000000..e676f16 --- /dev/null +++ b/src/utils/permission.py @@ -0,0 +1,7 @@ +from nonebot.adapters.onebot import v11 + +from src.utils.typing import T_GroupMessageEvent, T_MessageEvent + +GROUP_ADMIN = v11.GROUP_ADMIN +GROUP_OWNER = v11.GROUP_OWNER +