网页控制台新增插件管理

This commit is contained in:
Wuyi无疑 2023-05-06 01:04:53 +08:00
parent 54bf5df9c1
commit b26fe93a19
11 changed files with 173 additions and 31 deletions

8
.gitignore vendored
View File

@ -665,10 +665,8 @@ FodyWeavers.xsd
config.json config.json
res_data res_data
GsData.db GsData.db
GenshinUID
StarRailUID
data data
plugins/* gsuid_core/plugins/*
!plugins/core_command !gsuid_core/plugins/core_command
!plugins/gs_test.py !gsuid_core/plugins/gs_test.py
logs logs

View File

@ -23,6 +23,14 @@ from gsuid_core.utils.plugins_config.models import ( # noqa: E402
from gsuid_core.utils.plugins_config.gs_config import ( # noqa: E402 from gsuid_core.utils.plugins_config.gs_config import ( # noqa: E402
all_config_list, all_config_list,
) )
from gsuid_core.utils.plugins_update._plugins import ( # noqa: E402
check_status,
check_plugins,
install_plugin,
update_plugins,
check_can_update,
get_plugins_list,
)
app = FastAPI() app = FastAPI()
HOST = core_config.get_config('HOST') HOST = core_config.get_config('HOST')
@ -95,6 +103,47 @@ def main():
value = data[name] value = data[name]
all_config_list[config_name].set_config(name, value) all_config_list[config_name].set_config(name, value)
@app.get('/genshinuid/api/getPlugins')
@site.auth.requires('admin')
async def _get_plugins(request: Request):
tasks = []
plugins_list = await get_plugins_list()
for name in plugins_list:
plugin = plugins_list[name]
link = plugin['link']
plugin_name = link.split('/')[-1]
# git_path = f'{proxy_url}{link}.git'
sample = {
'label': plugin_name,
'key': name,
'status': check_status(plugin_name),
'remark': plugin['info'],
}
tasks.append(sample)
return tasks
@app.post('/genshinuid/api/updatePlugins')
@site.auth.requires('admin')
async def _update_plugins(request: Request, data: Dict):
repo = check_plugins(data['label'])
if repo:
if check_can_update(repo):
try:
update_plugins(data['label'])
retcode = 0
except: # noqa:E722
retcode = -1
else:
retcode = 0
else:
try:
retcode = await install_plugin(data['key'])
retcode = 0
except: # noqa:E722
retcode = -1
return {'status': retcode, 'msg': '', 'data': {}}
site.mount_app(app) site.mount_app(app)
uvicorn.run( uvicorn.run(
@ -102,23 +151,23 @@ def main():
host=HOST, host=HOST,
port=PORT, port=PORT,
log_config={ log_config={
"version": 1, 'version': 1,
"disable_existing_loggers": False, 'disable_existing_loggers': False,
"handlers": { 'handlers': {
"default": { 'default': {
"class": "gsuid_core.logger.LoguruHandler", 'class': 'gsuid_core.logger.LoguruHandler',
}, },
}, },
"loggers": { 'loggers': {
"uvicorn.error": {"handlers": ["default"], "level": "INFO"}, 'uvicorn.error': {'handlers': ['default'], 'level': 'INFO'},
"uvicorn.access": { 'uvicorn.access': {
"handlers": ["default"], 'handlers': ['default'],
"level": "INFO", 'level': 'INFO',
}, },
}, },
}, },
) )
if __name__ == "__main__": if __name__ == '__main__':
main() main()

View File

@ -1,8 +1,7 @@
from gsuid_core.sv import SV from gsuid_core.sv import SV
from gsuid_core.bot import Bot from gsuid_core.bot import Bot
from gsuid_core.models import Event from gsuid_core.models import Event
from gsuid_core.utils.plugins_update._plugins import (
from ._plugins import (
refresh_list, refresh_list,
update_plugins, update_plugins,
get_plugins_url, get_plugins_url,

View File

@ -231,6 +231,10 @@ async def _deal_ck(bot_id: str, mes: str, user_id: str) -> str:
if is_add_stoken: if is_add_stoken:
im_list.append(f'添加Stoken成功,stuid={account_id},stoken={stoken}') im_list.append(f'添加Stoken成功,stuid={account_id},stoken={stoken}')
if uid is None:
uid = '0'
await sqla.insert_user_data( await sqla.insert_user_data(
user_id, uid, sr_uid, account_cookie, app_cookie user_id, uid, sr_uid, account_cookie, app_cookie
) )

View File

@ -2,7 +2,7 @@ from typing import Dict, List, Union, Optional
import aiohttp import aiohttp
from git.repo import Repo from git.repo import Repo
from git.exc import GitCommandError from git.exc import GitCommandError, InvalidGitRepositoryError
from gsuid_core.logger import logger from gsuid_core.logger import logger
@ -27,6 +27,12 @@ async def refresh_list() -> List[str]:
return refresh_list return refresh_list
async def get_plugins_list() -> Dict[str, Dict[str, str]]:
if not plugins_list:
await refresh_list()
return plugins_list
async def get_plugins_url(name: str) -> Optional[Dict[str, str]]: async def get_plugins_url(name: str) -> Optional[Dict[str, str]]:
if not plugins_list: if not plugins_list:
await refresh_list() await refresh_list()
@ -50,9 +56,54 @@ def install_plugins(plugins: Dict[str, str]) -> str:
if path.exists(): if path.exists():
return '该插件已经安装过了!' return '该插件已经安装过了!'
Repo.clone_from(git_path, path, single_branch=True, depth=1) Repo.clone_from(git_path, path, single_branch=True, depth=1)
logger.info(f'插件{plugin_name}安装成功!')
return f'插件{plugin_name}安装成功!发送[gs重启]以应用!' return f'插件{plugin_name}安装成功!发送[gs重启]以应用!'
async def install_plugin(plugin_name: str) -> int:
url = await get_plugins_url(plugin_name)
if url is None:
return -1
install_plugins(url)
return 0
def check_plugins(plugin_name: str) -> Optional[Repo]:
path = PLUGINS_PATH / plugin_name
if path.exists():
try:
repo = Repo(path)
except InvalidGitRepositoryError:
return None
return repo
else:
return None
def check_can_update(repo: Repo) -> bool:
try:
remote = repo.remote() # 获取远程仓库
remote.fetch() # 从远程获取最新版本
except GitCommandError as e:
logger.error(f'发生Git命令错误{e}!')
return False
local_commit = repo.commit() # 获取本地最新提交
remote_commit = remote.fetch()[0].commit # 获取远程最新提交
if local_commit.hexsha == remote_commit.hexsha: # 比较本地和远程的提交哈希值
return False
return True
def check_status(plugin_name: str) -> int:
repo = check_plugins(plugin_name)
if repo is None:
return 3
if check_can_update(repo):
return 1
else:
return 4
def update_plugins( def update_plugins(
plugin_name: str, plugin_name: str,
level: int = 0, level: int = 0,
@ -66,10 +117,9 @@ def update_plugins(
plugin_name = _name plugin_name = _name
break break
path = PLUGINS_PATH / plugin_name repo = check_plugins(plugin_name)
if not path.exists(): if not repo:
return '更新失败, 不存在该插件!' return '更新失败, 不存在该插件!'
repo = Repo(path) # type: ignore
o = repo.remotes.origin o = repo.remotes.origin
if level >= 2: if level >= 2:

View File

@ -7,4 +7,4 @@ plugins_lib = 'https://docs.gsuid.gbots.work/plugin_list.json'
proxy_url = 'https://ghproxy.com/' proxy_url = 'https://ghproxy.com/'
PLUGINS_PATH = Path(__file__).parents[2] PLUGINS_PATH = Path(__file__).parents[2] / 'plugins'

View File

@ -0,0 +1,20 @@
def get_tasks_panel():
return {
'type': 'tasks',
'name': 'tasks',
'items': [{'label': '加载中, 请稍等...', 'key': 'wait', 'status': 2}],
'id': 'u:571849ba0356',
'initialStatusCode': 0,
'readyStatusCode': 1,
'loadingStatusCode': 2,
'errorStatusCode': 3,
'finishStatusCode': 4,
'canRetryStatusCode': 5,
'statusTextMap': ['未开始', '可更新', '安装中', '未安装', '已最新', '出错'],
'taskNameLabel': '插件列表',
'operationLabel': '操作',
'remarkLabel': '备注说明',
'btnText': '安装/更新',
'submitApi': 'post:/genshinuid/api/updatePlugins',
'checkApi': 'get:/genshinuid/api/getPlugins',
}

View File

@ -1,3 +1,5 @@
from typing import TypedDict
from fastapi_user_auth.auth.models import User from fastapi_user_auth.auth.models import User
from fastapi_amis_admin.models.fields import Field from fastapi_amis_admin.models.fields import Field
@ -8,3 +10,10 @@ class WebUser(User, table=True):
parent_id: int = Field( parent_id: int = Field(
None, title='Superior', foreign_key='auth_user.id' None, title='Superior', foreign_key='auth_user.id'
) # type:ignore ) # type:ignore
class Task(TypedDict):
label: str
key: str
status: int
remark: str

View File

@ -43,6 +43,7 @@ from gsuid_core.utils.cookie_manager.add_ck import _deal_ck
from gsuid_core.webconsole.html import gsuid_webconsole_help from gsuid_core.webconsole.html import gsuid_webconsole_help
from gsuid_core.webconsole.create_sv_panel import get_sv_page from gsuid_core.webconsole.create_sv_panel import get_sv_page
from gsuid_core.version import __version__ as GenshinUID_version from gsuid_core.version import __version__ as GenshinUID_version
from gsuid_core.webconsole.create_task_panel import get_tasks_panel
from gsuid_core.webconsole.create_config_panel import get_config_page from gsuid_core.webconsole.create_config_panel import get_config_page
from gsuid_core.utils.database.models import GsBind, GsPush, GsUser, GsCache from gsuid_core.utils.database.models import GsBind, GsPush, GsUser, GsCache
from gsuid_core.webconsole.login_page import ( # noqa # 不要删 from gsuid_core.webconsole.login_page import ( # noqa # 不要删
@ -395,7 +396,7 @@ class SVManagePage(GsAdminPage):
class ConfigManagePage(GsAdminPage): class ConfigManagePage(GsAdminPage):
page_schema = PageSchema( page_schema = PageSchema(
label=('修改设定'), label=('修改设定'),
icon='fa fa-sliders', icon='fa fa-cogs',
url='/ConfigManage', url='/ConfigManage',
isDefaultPage=True, isDefaultPage=True,
sort=100, sort=100,
@ -403,5 +404,17 @@ class ConfigManagePage(GsAdminPage):
page = Page.parse_obj(get_config_page()) page = Page.parse_obj(get_config_page())
@site.register_admin
class PluginsManagePage(GsAdminPage):
page_schema = PageSchema(
label=('插件管理'),
icon='fa fa-puzzle-piece',
url='/ConfigManage',
isDefaultPage=True,
sort=100,
)
page = Page.parse_obj(get_tasks_panel())
# 取消注册默认管理类 # 取消注册默认管理类
site.unregister_admin(admin.HomeAdmin, APIDocsApp) site.unregister_admin(admin.HomeAdmin, APIDocsApp)

12
poetry.lock generated
View File

@ -667,14 +667,14 @@ reference = "mirrors"
[[package]] [[package]]
name = "fastapi-amis-admin" name = "fastapi-amis-admin"
version = "0.5.5" version = "0.5.6"
description = "FastAPI-Amis-Admin is a high-performance, efficient and easily extensible FastAPI admin framework. Inspired by Django-admin, and has as many powerful functions as Django-admin." description = "FastAPI-Amis-Admin is a high-performance, efficient and easily extensible FastAPI admin framework. Inspired by Django-admin, and has as many powerful functions as Django-admin."
category = "main" category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "fastapi_amis_admin-0.5.5-py3-none-any.whl", hash = "sha256:8faeece0962a7db0f807e68c09fa45ed75e79ba55c9990e734de486ee6bbf4c1"}, {file = "fastapi_amis_admin-0.5.6-py3-none-any.whl", hash = "sha256:df9160d4b28f2a2165c17ec678eddc2bfe7323c77c9dfdd8217a7e8b6895e99d"},
{file = "fastapi_amis_admin-0.5.5.tar.gz", hash = "sha256:b3c57f42fad800906cb39e0d1ea67d597747c09875ae74f20fda1d516e8b2580"}, {file = "fastapi_amis_admin-0.5.6.tar.gz", hash = "sha256:8bcb74d11d4e1b605b2d3eccecf308a6c5ffce65d4d8bef300de6764f0b64107"},
] ]
[package.dependencies] [package.dependencies]
@ -1054,14 +1054,14 @@ reference = "mirrors"
[[package]] [[package]]
name = "identify" name = "identify"
version = "2.5.23" version = "2.5.24"
description = "File identification library for Python" description = "File identification library for Python"
category = "dev" category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "identify-2.5.23-py2.py3-none-any.whl", hash = "sha256:17d9351c028a781456965e781ed2a435755cac655df1ebd930f7186b54399312"}, {file = "identify-2.5.24-py2.py3-none-any.whl", hash = "sha256:986dbfb38b1140e763e413e6feb44cd731faf72d1909543178aa79b0e258265d"},
{file = "identify-2.5.23.tar.gz", hash = "sha256:50b01b9d5f73c6b53e5fa2caf9f543d3e657a9d0bbdeb203ebb8d45960ba7433"}, {file = "identify-2.5.24.tar.gz", hash = "sha256:0aac67d5b4812498056d28a9a512a483f5085cc28640b02b258a59dac34301d4"},
] ]
[package.extras] [package.extras]

View File

@ -17,7 +17,7 @@ click==8.1.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
colorama==0.4.6 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" and platform_system == "Windows" or python_full_version >= "3.8.1" and python_full_version < "4.0.0" and sys_platform == "win32" colorama==0.4.6 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" and platform_system == "Windows" or python_full_version >= "3.8.1" and python_full_version < "4.0.0" and sys_platform == "win32"
dnspython==2.3.0 ; python_full_version >= "3.8.1" and python_version < "4.0" dnspython==2.3.0 ; python_full_version >= "3.8.1" and python_version < "4.0"
email-validator==2.0.0.post2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" email-validator==2.0.0.post2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
fastapi-amis-admin==0.5.5 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" fastapi-amis-admin==0.5.6 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
fastapi-user-auth==0.5.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" fastapi-user-auth==0.5.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
fastapi==0.95.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" fastapi==0.95.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
frozenlist==1.3.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" frozenlist==1.3.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"