1
0
forked from bot/app

fix: 插件列表显示错误问题

This commit is contained in:
远野千束 2024-03-21 14:52:02 +08:00
parent 933979ceaa
commit 2711d8844b
18 changed files with 179 additions and 84 deletions

1
.gitignore vendored
View File

@ -2,6 +2,7 @@
.cache/ .cache/
data/ data/
db/
plugins/ plugins/
_config.yml _config.yml
config.example.yml config.example.yml

View File

@ -6,8 +6,10 @@ dash==2.16.1
nonebot2[fastapi]==2.2.1 nonebot2[fastapi]==2.2.1
nonebot-adapter-onebot==2.4.3 nonebot-adapter-onebot==2.4.3
nonebot-plugin-alconna==0.41.0 nonebot-plugin-alconna==0.41.0
pip==24.0
psutil==5.9.8 psutil==5.9.8
pydantic==2.6.4 pydantic==2.6.4
PyYAML~=6.0.1 PyYAML~=6.0.1
typing_extensions~=4.10.0 typing_extensions~=4.10.0
starlette~=0.36.3 starlette~=0.36.3
pip==24.0

View File

@ -1,8 +1,10 @@
import nonebot import nonebot
from nonebot.plugin import PluginMetadata from nonebot.plugin import PluginMetadata
from src.utils.language import get_system_lang from src.utils.language import get_system_lang
from src.utils.data_manager import *
from .loader import * from .loader import *
from .webdash import * from .webdash import *
from src.utils.config import config
__author__ = "snowykami" __author__ = "snowykami"
__plugin_meta__ = PluginMetadata( __plugin_meta__ = PluginMetadata(
@ -10,9 +12,12 @@ __plugin_meta__ = PluginMetadata(
description="轻雪主程序插件,包含了许多初始化的功能", description="轻雪主程序插件,包含了许多初始化的功能",
usage="", usage="",
homepage="https://github.com/snowykami/LiteyukiBot", homepage="https://github.com/snowykami/LiteyukiBot",
extra={
"liteyuki_plugin": True,
}
) )
from src.utils.config import config auto_migrate()
sys_lang = get_system_lang() sys_lang = get_system_lang()
nonebot.logger.info(sys_lang.get("main.current_language", LANG=sys_lang.get("language.name"))) nonebot.logger.info(sys_lang.get("main.current_language", LANG=sys_lang.get("language.name")))

View File

@ -2,6 +2,7 @@ import os
import nonebot.plugin import nonebot.plugin
from src.utils.data_manager import InstalledPlugin, plugin_db
from src.utils.language import load_from_dir from src.utils.language import load_from_dir
from src.utils.resource import load_resource_from_dir from src.utils.resource import load_resource_from_dir
@ -11,3 +12,8 @@ load_resource_from_dir(RESOURCE_PATH)
nonebot.plugin.load_plugins("src/plugins") nonebot.plugin.load_plugins("src/plugins")
nonebot.plugin.load_plugins("plugins") 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)

View File

@ -52,4 +52,7 @@ __plugin_meta__ = PluginMetadata(
description="用于测试Markdown的插件", description="用于测试Markdown的插件",
usage="", usage="",
homepage="https://github.com/snowykami/LiteyukiBot", homepage="https://github.com/snowykami/LiteyukiBot",
extra={
"liteyuki_plugin": True,
}
) )

View File

@ -104,8 +104,8 @@ async def _(event: T_MessageEvent, bot: T_Bot):
for l in str(event.message).split("\n"): for l in str(event.message).split("\n"):
msg_formatted += f"**{l.strip()}**\n" msg_formatted += f"**{l.strip()}**\n"
push_message = ( push_message = (
f"> From {event.sender.nickname}@{push.source.session_type}.{push.source.session_id}\n> Bot {bot.self_id}\n\n" f"> From {event.sender.nickname}@{push.source.session_type}.{push.source.session_id}\n> Bot {bot.self_id}\n\n"
f"{msg_formatted}") f"{msg_formatted}")
await send_markdown(push_message, bot2, event=event) await send_markdown(push_message, bot2, event=event)
return return
@ -116,4 +116,7 @@ __plugin_meta__ = PluginMetadata(
description="事件推送插件支持单向和双向推送支持跨Bot推送", description="事件推送插件支持单向和双向推送支持跨Bot推送",
usage="", usage="",
homepage="https://github.com/snowykami/LiteyukiBot", homepage="https://github.com/snowykami/LiteyukiBot",
extra={
"liteyuki_plugin": True,
}
) )

View File

@ -3,7 +3,6 @@ from .manager import *
from .installer import * from .installer import *
from .helper import * from .helper import *
__author__ = "snowykami" __author__ = "snowykami"
__plugin_meta__ = PluginMetadata( __plugin_meta__ = PluginMetadata(
name="轻雪插件管理", name="轻雪插件管理",
@ -16,4 +15,7 @@ __plugin_meta__ = PluginMetadata(
), ),
type="application", type="application",
homepage="https://github.com/snowykami/LiteyukiBot", homepage="https://github.com/snowykami/LiteyukiBot",
extra={
"liteyuki_plugin": True,
}
) )

View File

@ -1,13 +1,8 @@
from src.utils.data import Database, LiteModel 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" LNPM_COMMAND_START = "lnpm"
class InstalledPlugin(LiteModel):
module_name: str
plugin_db.auto_migrate(InstalledPlugin)

View File

@ -5,26 +5,24 @@ import sys
from io import StringIO from io import StringIO
from typing import Optional from typing import Optional
import aiofiles
import aiohttp
import nonebot import nonebot
import pip
from arclet.alconna import Arparma, MultiVar from arclet.alconna import Arparma, MultiVar
from nonebot.permission import SUPERUSER from nonebot.permission import SUPERUSER
from nonebot.utils import run_sync from nonebot_plugin_alconna import Alconna, Args, Subcommand, on_alconna
from nonebot_plugin_alconna import on_alconna, Alconna, Args, Subcommand
import pip
import aiohttp, aiofiles
from typing_extensions import Any
from src.utils.language import get_user_lang from src.utils.language import get_user_lang
from src.utils.message import Markdown as md, send_markdown from src.utils.message import Markdown as md, send_markdown
from src.utils.resource import get_res from src.utils.resource import get_res
from src.utils.typing import T_Bot, T_MessageEvent from src.utils.typing import T_Bot, T_MessageEvent
from .common import * from .common import *
from src.utils.data_manager import InstalledPlugin
npm_alc = on_alconna( npm_alc = on_alconna(
Alconna( Alconna(
"lnpm", ["lnpm", "插件管理"],
Subcommand( Subcommand(
"update", "update",
alias=["u"], 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) btn_install = md.button(ulang.get('npm.install'), 'lnpm install %s' % plugin.module_name)
link_page = md.link(ulang.get('npm.homepage'), plugin.homepage) 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 > **{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: 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: else:
reply = ulang.get("npm.search_no_result") reply = ulang.get("npm.search_no_result")
await send_markdown(reply, bot, event=event) await send_markdown(reply, bot, event=event)
elif result.subcommands.get("install"): elif result.subcommands.get("install"):
plugin_name: str = result.subcommands["install"].args.get("plugin_name") plugin_module_name: str = result.subcommands["install"].args.get("plugin_name")
r, log = npm_install(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: if r:
nonebot.load_plugin(plugin_name) nonebot.load_plugin(plugin_module_name) # 加载插件
installed_plugin = InstalledPlugin(module_name=plugin_name) installed_plugin = InstalledPlugin(module_name=plugin_module_name) # 构造插件信息模型
store_plugin = await get_store_plugin(plugin_name) store_plugin = await get_store_plugin(plugin_module_name) # 获取商店中的插件信息
plugin_db.save(installed_plugin) found_in_db_plugin = plugin_db.first(InstalledPlugin, "module_name = ?", plugin_module_name) # 查询数据库中是否已经安装
await send_markdown( if found_in_db_plugin is None:
f"**{ulang.get('npm.install_success', NAME=store_plugin.name)}**\n\n" plugin_db.save(installed_plugin)
f"```\n{log}\n```", info = ulang.get('npm.install_success', NAME=store_plugin.name).replace('_', r'\\_') # markdown转义
bot, await send_markdown(
event=event 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: else:
info = ulang.get('npm.install_failed', NAME=plugin_module_name).replace('_', r'\\_')
await send_markdown( await send_markdown(
f"{ulang.get('npm.install_success', NAME=plugin_name)}\n\n" f"{info}\n\n"
f"```\n{log}\n```", f"```\n{log}\n```",
bot, bot,
event=event event=event
) )
elif result.subcommands.get("remove"): elif result.subcommands.get("remove"):
plugin_name: str = result.subcommands["remove"].args.get("plugin_name") plugin_module_name: str = result.subcommands["remove"].args.get("plugin_name")
await npm_alc.finish(ulang.get("npm.remove_success")) 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: async def npm_update() -> bool:
@ -212,19 +224,25 @@ def npm_install(plugin_module_name) -> tuple[bool, str]:
sys.stderr = buffer sys.stderr = buffer
mirrors = [ mirrors = [
"https://pypi.tuna.tsinghua.edu.cn/simple", "https://pypi.mirrors.cqupt.edu.cn/simple", # 重庆邮电大学
"https://pypi.mirrors.cqupt.edu.cn/simple/", "https://pypi.tuna.tsinghua.edu.cn/simple", # 清华大学
"https://pypi.org/simple", "https://pypi.liteyuki.icu/simple", # 轻雪镜像
"https://pypi.org/simple", # 官方源
] ]
# 使用pip安装包对每个镜像尝试一次成功后返回值 # 使用pip安装包对每个镜像尝试一次成功后返回值
success = False success = False
for mirror in mirrors: for mirror in mirrors:
try: try:
nonebot.logger.info(f"npm_install try mirror: {mirror}")
result = pip.main(['install', plugin_module_name, "-i", mirror]) result = pip.main(['install', plugin_module_name, "-i", mirror])
success = result == 0 success = result == 0
break if success:
break
else:
nonebot.logger.warning(f"npm_install failed, try next mirror.")
except Exception as e: except Exception as e:
success = False success = False
continue continue

View File

@ -2,12 +2,14 @@ import nonebot.plugin
from nonebot import on_command from nonebot import on_command
from nonebot.permission import SUPERUSER 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.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.typing import T_Bot, T_MessageEvent
from src.utils.language import get_user_lang from src.utils.language import get_user_lang
list_plugins = on_command("list-plugin", aliases={"列出插件", "插件列表"}, 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) toggle_plugin = on_command("enable-plugin", aliases={"启用插件", "用插件", "disable-plugin"}, priority=0, permission=SUPERUSER)
@list_plugins.handle() @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***" 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(): for plugin in nonebot.get_loaded_plugins():
# 检查是否有 metadata 属性 # 检查是否有 metadata 属性
btn_help = md.button(lang.get('npm.help'), f'help {plugin.name}', False)
reply += f"\n{btn_help} "
if plugin.metadata: if plugin.metadata:
reply += (f"\n{md.button(lang.get('npm.help'), 'help %s' % plugin.name, False, False)} " reply += (f"**{plugin.metadata.name}**\n"
f"**{plugin.metadata.name}**\n" f"\n > {plugin.metadata.description}")
f"\n > {plugin.metadata.description}\n\n***\n")
else: else:
reply += (f"\n{md.button(lang.get('npm.help'), 'help %s' % plugin.name, False, False)} " reply += (f"**{plugin.name}**\n"
f"**{plugin.name}**\n" f"\n > {lang.get('npm.no_description')}")
f"\n > {lang.get('npm.no_description')}\n\n***\n") # 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) await send_markdown(reply, bot, event=event)

View File

@ -8,4 +8,7 @@ __plugin_meta__ = PluginMetadata(
description="用户管理插件", description="用户管理插件",
usage="", usage="",
homepage="https://github.com/snowykami/LiteyukiBot", homepage="https://github.com/snowykami/LiteyukiBot",
extra={
"liteyuki_plugin": True,
}
) )

View File

@ -10,6 +10,8 @@ main.monitor.swap=SWAP
main.monitor.disk=Disk main.monitor.disk=Disk
main.monitor.usage=Usage main.monitor.usage=Usage
data_manager.migrate_success=Model {NAME} migration successful
npm.loaded_plugins=Loaded plugins npm.loaded_plugins=Loaded plugins
npm.total=Total {TOTAL} npm.total=Total {TOTAL}
npm.help=Help npm.help=Help
@ -17,14 +19,18 @@ npm.disable=Disable
npm.enable=Enable npm.enable=Enable
npm.install=Install npm.install=Install
npm.uninstall=Uninstall npm.uninstall=Uninstall
npm.installing=Installing {NAME}...
npm.cannot_uninstall=Cannot uninstall
npm.no_description=No description npm.no_description=No description
npm.store_update_success=Plugin store data updated successfully npm.store_update_success=Plugin store data updated successfully
npm.store_update_failed=Plugin store data update failed npm.store_update_failed=Plugin store data update failed
npm.search_result=Search results npm.search_result=Search results
npm.search_no_result=No result found 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_success={NAME} installed successfully
npm.install_failed={NAME} installation failed 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.author=Author
npm.homepage=Homepage npm.homepage=Homepage
npm.next_page=Next npm.next_page=Next

View File

@ -10,6 +10,8 @@ main.monitor.swap=スワップ
main.monitor.disk=ディスク main.monitor.disk=ディスク
main.monitor.usage=使用率 main.monitor.usage=使用率
data_manager.migrate_success=データが正常に移行されました {NAME}
npm.loaded_plugins=読み込まれたプラグイン npm.loaded_plugins=読み込まれたプラグイン
npm.total=合計 {TOTAL} npm.total=合計 {TOTAL}
npm.help=ヘルプ npm.help=ヘルプ
@ -17,14 +19,18 @@ npm.disable=無効
npm.enable=有効 npm.enable=有効
npm.install=インストール npm.install=インストール
npm.uninstall=アンインストール npm.uninstall=アンインストール
npm.installing={NAME} インストール中
npm.cannot_uninstall=このプラグインはアンインストールできません
npm.no_description=説明なし npm.no_description=説明なし
npm.store_update_success=プラグインストアのデータが正常に更新されました npm.store_update_success=プラグインストアのデータが正常に更新されました
npm.store_update_failed=プラグインストアのデータの更新に失敗しました npm.store_update_failed=プラグインストアのデータの更新に失敗しました
npm.search_result=検索結果 npm.search_result=検索結果
npm.search_no_result=検索結果がありません npm.search_no_result=検索結果がありません
npm.too_many_results=検索結果が多すぎます。ページをめくってください npm.too_many_results=検索結果が多すぎます。{HIDE_NUM} 件の結果が非表示になりました
npm.install_success={NAME} が正常にインストールされました npm.install_success={NAME} が正常にインストールされました
npm.install_failed={NAME} のインストールに失敗しました npm.install_failed={NAME} のインストールに失敗しました
npm.plugin_not_installed={NAME} はインストールされていません
npm.plugin_already_installed={NAME} は既にインストールされています
npm.author=著者 npm.author=著者
npm.homepage=ホームページ npm.homepage=ホームページ
npm.next_page=次のページ npm.next_page=次のページ

View File

@ -10,6 +10,8 @@ main.monitor.swap=交换空间
main.monitor.disk=磁盘 main.monitor.disk=磁盘
main.monitor.usage=使用率 main.monitor.usage=使用率
data_manager.migrate_success=数据模型{NAME}迁移成功
npm.loaded_plugins=已加载插件 npm.loaded_plugins=已加载插件
npm.total=总计 {TOTAL} npm.total=总计 {TOTAL}
npm.help=帮助 npm.help=帮助
@ -17,16 +19,22 @@ npm.disable=停用
npm.enable=启用 npm.enable=启用
npm.install=安装 npm.install=安装
npm.uninstall=卸载 npm.uninstall=卸载
npm.installing=正在安装 {NAME}
npm.cannot_uninstall=无法卸载
npm.no_description=无描述 npm.no_description=无描述
npm.store_update_success=插件商店数据更新成功 npm.store_update_success=插件商店数据更新成功
npm.store_update_failed=插件商店数据更新失败 npm.store_update_failed=插件商店数据更新失败
npm.search_result=搜索结果 npm.search_result=搜索结果
npm.search_no_result=无搜索结果 npm.search_no_result=无搜索结果
npm.too_many_results=搜索结果过多,请限制关键字 npm.too_many_results=搜索结果过多,{HIDE_NUM}已隐藏,请限制关键字
npm.install_success={NAME} 安装成功 npm.install_success={NAME} 安装成功
npm.install_failed={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.author=作者
npm.homepage=主页 npm.homepage=项目主页
npm.next_page=下一页 npm.next_page=下一页
npm.prev_page=上一页 npm.prev_page=上一页

View File

@ -88,12 +88,11 @@ class Database(BaseORMAdapter):
} }
DEFAULT_TYPE = { DEFAULT_TYPE = {
'TEXT': '', 'TEXT' : '',
'INTEGER': 0, 'INTEGER': 0,
'REAL': 0.0 'REAL' : 0.0
} }
FOREIGNID = 'FOREIGNID' FOREIGNID = 'FOREIGNID'
JSON = 'JSON' JSON = 'JSON'
ID = '$ID' ID = '$ID'
@ -115,6 +114,7 @@ class Database(BaseORMAdapter):
Returns: Returns:
""" """
table_name = ''
for model in args: for model in args:
model: type(LiteModel) model: type(LiteModel)
# 检测并创建表若模型未定义id字段则使用自增主键有定义的话使用id字段且id有可能为字符串 # 检测并创建表若模型未定义id字段则使用自增主键有定义的话使用id字段且id有可能为字符串
@ -161,6 +161,7 @@ class Database(BaseORMAdapter):
self.cursor.execute(f'ALTER TABLE {table_name} DROP COLUMN {field}') self.cursor.execute(f'ALTER TABLE {table_name} DROP COLUMN {field}')
self.conn.commit() self.conn.commit()
nonebot.logger.success(f'Table {table_name} migrated successfully')
def save(self, *models: LiteModel) -> int | tuple: def save(self, *models: LiteModel) -> int | tuple:
"""存储数据检查id字段如果有id字段则更新没有则插入 """存储数据检查id字段如果有id字段则更新没有则插入
@ -171,9 +172,12 @@ class Database(BaseORMAdapter):
Returns: Returns:
id: 数据id如果有多个数据则返回id元组 id: 数据id如果有多个数据则返回id元组
""" """
ids = [] ids = []
for model in models: for model in models:
table_name = model.__class__.__name__ table_name = model.__class__.__name__
if not self._detect_for_table(table_name):
raise ValueError(f'{table_name}不存在,请先迁移')
key_list = [] key_list = []
value_list = [] value_list = []
# 处理外键,添加前缀'$IDFieldName' # 处理外键,添加前缀'$IDFieldName'
@ -227,6 +231,17 @@ class Database(BaseORMAdapter):
return json.dumps(return_data) 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: def first(self, model: type(LiteModel), conditions, *args, default: Any = None) -> LiteModel | None:
"""查询第一条数据 """查询第一条数据
@ -239,6 +254,10 @@ class Database(BaseORMAdapter):
Returns: 数据 Returns: 数据
""" """
table_name = model.__name__ 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) self.cursor.execute(f'SELECT * FROM {table_name} WHERE {conditions}', args)
if row_data := self.cursor.fetchone(): if row_data := self.cursor.fetchone():
data = dict(row_data) data = dict(row_data)
@ -258,7 +277,8 @@ class Database(BaseORMAdapter):
""" """
table_name = model.__name__ table_name = model.__name__
# 检测表是否存在否则返回None if not self._detect_for_table(table_name):
return default
if conditions: if conditions:
self.cursor.execute(f'SELECT * FROM {table_name} WHERE {conditions}', args) self.cursor.execute(f'SELECT * FROM {table_name} WHERE {conditions}', args)
@ -281,27 +301,13 @@ class Database(BaseORMAdapter):
""" """
table_name = model.__name__ table_name = model.__name__
if not self._detect_for_table(table_name):
return
nonebot.logger.debug(f'DELETE FROM {table_name} WHERE {conditions}') nonebot.logger.debug(f'DELETE FROM {table_name} WHERE {conditions}')
self.cursor.execute(f'DELETE FROM {table_name} WHERE {conditions}', args) self.cursor.execute(f'DELETE FROM {table_name} WHERE {conditions}', args)
self.conn.commit() 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: def convert_to_dict(self, data: dict) -> dict:
"""将json字符串转换为字典 """将json字符串转换为字典
@ -318,7 +324,7 @@ class Database(BaseORMAdapter):
for k, v in d.items(): for k, v in d.items():
if k.startswith(self.FOREIGNID): if k.startswith(self.FOREIGNID):
new_d[k.replace(self.FOREIGNID, '')] = load( 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): elif k.startswith(self.JSON):
new_d[k.replace(self.JSON, '')] = load(json.loads(v)) new_d[k.replace(self.JSON, '')] = load(json.loads(v))
else: else:
@ -327,7 +333,7 @@ class Database(BaseORMAdapter):
new_d = [] new_d = []
for i, v in enumerate(d): for i, v in enumerate(d):
if isinstance(v, str) and v.startswith(self.ID): 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): elif isinstance(v, BaseIterable):
new_d.append(load(v)) new_d.append(load(v))
else: else:

View File

@ -14,4 +14,10 @@ class User(LiteModel):
lang: str = "en" 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)

View File

@ -9,6 +9,7 @@ from typing_extensions import Any
import nonebot import nonebot
from src.utils.config import config
from src.utils.data_manager import User, user_db from src.utils.data_manager import User, user_db
_default_lang_code = "en" _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) return Language(user.lang)

7
src/utils/permission.py Normal file
View File

@ -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