From 8ec712cdd0c673e75b687148c8c8870cd7f744df Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Wuyi=E6=97=A0=E7=96=91?= <444835641@qq.com>
Date: Tue, 21 Mar 2023 23:17:01 +0800
Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20=E9=BB=98=E8=AE=A4=E5=BC=80?=
=?UTF-8?q?=E5=90=AF`=E7=BD=91=E9=A1=B5=E6=8E=A7=E5=88=B6=E5=8F=B0`?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 1 +
gsuid_core/core.py | 28 +-
gsuid_core/handler.py | 5 +-
gsuid_core/webconsole/__init__.py | 29 ++
gsuid_core/webconsole/create_sv_panel.py | 284 ++++++++++++++++
gsuid_core/webconsole/html.py | 114 +++++++
gsuid_core/webconsole/login_page.py | 71 ++++
gsuid_core/webconsole/models.py | 10 +
gsuid_core/webconsole/mount_app.py | 399 +++++++++++++++++++++++
gsuid_core/webconsole/utils.py | 15 +
poetry.lock | 290 ++--------------
pyproject.toml | 5 +-
requirements.txt | 35 +-
13 files changed, 998 insertions(+), 288 deletions(-)
create mode 100644 gsuid_core/webconsole/__init__.py
create mode 100644 gsuid_core/webconsole/create_sv_panel.py
create mode 100644 gsuid_core/webconsole/html.py
create mode 100644 gsuid_core/webconsole/login_page.py
create mode 100644 gsuid_core/webconsole/models.py
create mode 100644 gsuid_core/webconsole/mount_app.py
create mode 100644 gsuid_core/webconsole/utils.py
diff --git a/.gitignore b/.gitignore
index bce2619..78d6aa0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -666,3 +666,4 @@ config.json
res_data
GsData.db
GenshinUID
+data
diff --git a/gsuid_core/core.py b/gsuid_core/core.py
index 75b0d69..0b1161a 100644
--- a/gsuid_core/core.py
+++ b/gsuid_core/core.py
@@ -1,13 +1,17 @@
import sys
import asyncio
+from typing import Dict
from pathlib import Path
import uvicorn
from msgspec import json as msgjson
+from starlette.requests import Request
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
sys.path.append(str(Path(__file__).parents[1]))
+from gsuid_core.sv import SL # noqa: E402
from gsuid_core.gss import gss # noqa: E402
+from gsuid_core.logger import logger # noqa: E402
from gsuid_core.config import core_config # noqa: E402
from gsuid_core.handler import handle_event # noqa: E402
from gsuid_core.models import MessageReceive # noqa: E402
@@ -18,7 +22,7 @@ HOST = core_config.get_config('HOST')
PORT = int(core_config.get_config('PORT'))
-@app.websocket("/ws/{bot_id}")
+@app.websocket('/ws/{bot_id}')
async def websocket_endpoint(websocket: WebSocket, bot_id: str):
bot = await gss.connect(websocket, bot_id)
@@ -39,6 +43,12 @@ async def websocket_endpoint(websocket: WebSocket, bot_id: str):
@app.on_event('startup')
async def startup_event():
+ try:
+ from gsuid_core.webconsole.__init__ import start_check
+
+ await start_check()
+ except ImportError:
+ logger.warning('未加载GenshinUID...网页控制台启动失败...')
await start_scheduler()
@@ -48,4 +58,20 @@ async def shutdown_event():
if __name__ == "__main__":
+ try:
+ from gsuid_core.webconsole.mount_app import site
+
+ @app.post('/setSV/{name}')
+ @site.auth.requires('admin')
+ async def _set_SV(request: Request, data: Dict, name: str):
+ if name in SL.lst:
+ sv = SL.lst[name]
+ data['pm'] = int(data['pm'])
+ data['black_list'] = data['black_list'].split(';')
+ sv.set(**data)
+
+ site.mount_app(app)
+ except ImportError:
+ logger.warning('未加载GenshinUID...网页控制台启动失败...')
+
uvicorn.run(app, host=HOST, port=PORT)
diff --git a/gsuid_core/handler.py b/gsuid_core/handler.py
index f24e8ba..ecf46b4 100644
--- a/gsuid_core/handler.py
+++ b/gsuid_core/handler.py
@@ -61,7 +61,10 @@ async def handle_event(ws: _Bot, msg: MessageReceive):
if (
SL.lst[sv].enabled
and user_pm <= SL.lst[sv].pm
- and msg.group_id not in SL.lst[sv].black_list
+ and (
+ msg.group_id not in SL.lst[sv].black_list
+ or msg.user_id not in SL.lst[sv].black_list
+ )
and True
if SL.lst[sv].area == 'ALL'
or (msg.group_id and SL.lst[sv].area == 'GROUP')
diff --git a/gsuid_core/webconsole/__init__.py b/gsuid_core/webconsole/__init__.py
new file mode 100644
index 0000000..1ade0b5
--- /dev/null
+++ b/gsuid_core/webconsole/__init__.py
@@ -0,0 +1,29 @@
+from sqlmodel import SQLModel
+
+from gsuid_core.logger import logger
+from gsuid_core.config import core_config
+from gsuid_core.webconsole.mount_app import site
+
+
+async def start_check():
+ # 语言本地化
+ from fastapi_user_auth import i18n as user_auth_i18n
+ from fastapi_amis_admin import i18n as admin_auth_i18n
+
+ HOST = core_config.get_config('HOST')
+ PORT = core_config.get_config('PORT')
+
+ admin_auth_i18n.set_language('zh_CN')
+ user_auth_i18n.set_language('zh_CN')
+
+ logger.info('尝试挂载WebConsole')
+ await site.auth.db.async_run_sync(
+ SQLModel.metadata.create_all, is_session=False # type:ignore
+ )
+ await site.db.async_run_sync(
+ SQLModel.metadata.create_all, is_session=False # type:ignore
+ ) # type:ignore
+ # 创建默认测试用户, 请及时修改密码!!!
+ await site.auth.create_role_user('admin')
+
+ logger.info(('WebConsole挂载成功:' f'http://{HOST}:{PORT}/genshinuid'))
diff --git a/gsuid_core/webconsole/create_sv_panel.py b/gsuid_core/webconsole/create_sv_panel.py
new file mode 100644
index 0000000..b1cfa11
--- /dev/null
+++ b/gsuid_core/webconsole/create_sv_panel.py
@@ -0,0 +1,284 @@
+from typing import List, Literal
+
+from gsuid_core.sv import SL
+
+
+def get_sv_panel(
+ name: str = '',
+ pm: int = 3,
+ priority: int = 5,
+ enabled: bool = True,
+ area: Literal['GROUP', 'DIRECT', 'ALL'] = 'ALL',
+ black_list: List = [],
+):
+ api = f'/setSV/{name}'
+ card = {
+ "type": "service",
+ "body": {
+ 'type': 'card',
+ 'header': {'title': '', 'subTitle': ''},
+ 'body': [
+ {
+ 'type': 'flex',
+ 'className': 'p-1',
+ 'items': [
+ {
+ 'type': 'container',
+ 'size': 'xs',
+ 'style': {
+ 'position': 'static',
+ 'display': 'block',
+ 'flex': '1 1 auto',
+ 'flexGrow': 1,
+ 'flexBasis': 'auto',
+ },
+ 'wrapperBody': False,
+ 'isFixedHeight': False,
+ 'isFixedWidth': False,
+ 'id': 'u:bafbdfce89c2',
+ 'body': [
+ {
+ 'type': 'tpl',
+ 'tpl': name,
+ 'inline': True,
+ 'wrapperComponent': '',
+ 'id': 'u:cd523cbd8f0c',
+ 'style': {
+ 'fontFamily': '',
+ 'fontSize': 25,
+ },
+ },
+ {
+ 'type': 'switch',
+ 'label': '总开关',
+ 'option': '开启/关闭功能',
+ 'name': 'enabled',
+ 'falseValue': False,
+ 'trueValue': True,
+ 'id': 'u:d739bc85f307',
+ 'value': enabled,
+ },
+ ],
+ },
+ {
+ 'type': 'container',
+ 'size': 'xs',
+ 'style': {
+ 'position': 'static',
+ 'display': 'block',
+ 'flex': '1 1 auto',
+ 'flexGrow': 1,
+ 'flexBasis': 'auto',
+ },
+ 'wrapperBody': False,
+ 'isFixedHeight': False,
+ 'isFixedWidth': False,
+ 'id': 'u:80670a4807f2',
+ },
+ {
+ 'type': 'container',
+ 'body': [],
+ 'size': 'xs',
+ 'style': {
+ 'position': 'static',
+ 'display': 'block',
+ 'flex': '1 1 auto',
+ 'flexGrow': 1,
+ 'flexBasis': 'auto',
+ },
+ 'wrapperBody': False,
+ 'isFixedHeight': False,
+ 'isFixedWidth': False,
+ 'id': 'u:f24811f21e93',
+ },
+ ],
+ 'style': {'position': 'static'},
+ 'direction': 'row',
+ 'justify': 'flex-start',
+ 'alignItems': 'stretch',
+ 'id': 'u:2a2b198f141b',
+ 'label': '',
+ },
+ {
+ 'type': 'flex',
+ 'className': 'p-1',
+ 'items': [
+ {
+ 'type': 'container',
+ 'body': [
+ {
+ 'type': 'select',
+ 'label': '权限控制',
+ 'name': 'pm',
+ 'options': [
+ {'label': '超级管理员', 'value': '1'},
+ {'label': '管理员', 'value': '2'},
+ {'label': '正常', 'value': '3'},
+ {'label': '几乎所有人', 'value': '4'},
+ {'label': '所有人', 'value': '5'},
+ ],
+ 'id': 'u:c71f20b605d4',
+ 'multiple': False,
+ 'value': str(pm),
+ }
+ ],
+ 'size': 'xs',
+ 'style': {
+ 'position': 'static',
+ 'display': 'block',
+ 'flex': '1 1 auto',
+ 'flexGrow': 1,
+ 'flexBasis': 'auto',
+ },
+ 'wrapperBody': False,
+ 'isFixedHeight': False,
+ 'isFixedWidth': False,
+ 'id': 'u:bafbdfce89c2',
+ },
+ {
+ 'type': 'container',
+ 'body': [
+ {
+ 'type': 'input-number',
+ 'label': '命令优先级',
+ 'name': 'priority',
+ 'keyboard': True,
+ 'id': 'u:0b72c9b8086d',
+ 'step': 1,
+ 'value': priority,
+ }
+ ],
+ 'size': 'xs',
+ 'style': {
+ 'position': 'static',
+ 'display': 'block',
+ 'flex': '1 1 auto',
+ 'flexGrow': 1,
+ 'flexBasis': 'auto',
+ },
+ 'wrapperBody': False,
+ 'isFixedHeight': False,
+ 'isFixedWidth': False,
+ 'id': 'u:80670a4807f2',
+ },
+ {
+ 'type': 'container',
+ 'body': [
+ {
+ 'type': 'select',
+ 'label': '作用范围',
+ 'name': 'area',
+ 'options': [
+ {'label': '全局', 'value': 'ALL'},
+ {'label': '仅限私聊', 'value': 'DIRECT'},
+ {'label': '仅限群聊', 'value': 'GROUP'},
+ ],
+ 'id': 'u:88e66f806556',
+ 'multiple': False,
+ 'value': area,
+ }
+ ],
+ 'size': 'xs',
+ 'style': {
+ 'position': 'static',
+ 'display': 'block',
+ 'flex': '1 1 auto',
+ 'flexGrow': 1,
+ 'flexBasis': 'auto',
+ },
+ 'wrapperBody': False,
+ 'isFixedHeight': False,
+ 'isFixedWidth': False,
+ 'id': 'u:f24811f21e93',
+ },
+ ],
+ 'style': {'position': 'static'},
+ 'direction': 'row',
+ 'justify': 'flex-start',
+ 'alignItems': 'stretch',
+ 'id': 'u:2a2b198f141b',
+ 'label': '',
+ },
+ {
+ 'type': 'flex',
+ 'className': 'p-1',
+ 'items': [
+ {
+ 'type': 'container',
+ 'size': 'xs',
+ 'body': [
+ {
+ 'type': 'input-text',
+ 'label': '黑名单(以;为分割)',
+ 'name': 'black_list',
+ 'id': 'u:ab168d425936',
+ 'value': ';'.join(black_list),
+ }
+ ],
+ 'wrapperBody': False,
+ 'style': {'flex': '0 0 auto', 'display': 'block'},
+ 'id': 'u:48c938f71548',
+ }
+ ],
+ 'direction': 'column',
+ 'justify': 'center',
+ 'alignItems': 'stretch',
+ 'id': 'u:a7b2f1bbc0a8',
+ 'label': '',
+ },
+ ],
+ 'actions': [
+ {
+ 'type': 'button',
+ 'label': '确认修改',
+ 'id': 'u:5784cfaa5c0a',
+ 'actionType': 'ajax',
+ 'api': api,
+ 'onEvent': {
+ 'click': {
+ 'weight': 0,
+ 'actions': [
+ {
+ 'args': {
+ 'msgType': 'success',
+ 'position': 'top-center',
+ 'closeButton': True,
+ 'showIcon': True,
+ 'msg': '成功设置!',
+ 'timeout': 100,
+ },
+ 'actionType': 'toast',
+ }
+ ],
+ }
+ },
+ }
+ ],
+ 'id': 'u:69b06813bfbe',
+ },
+ "id": "u:4c2981f6a055",
+ }
+
+ return card
+
+
+def get_sv_page():
+ page = {
+ 'type': 'page',
+ 'title': '功能管理',
+ 'body': [],
+ 'id': 'u:a9be7e0dc676',
+ }
+ for sv_name in SL.lst:
+ sv = SL.lst[sv_name]
+ panel = get_sv_panel(
+ sv.name,
+ sv.pm,
+ sv.priority,
+ sv.enabled,
+ sv.area, # type:ignore
+ sv.black_list,
+ )
+ page['body'].append(panel)
+
+ return page
diff --git a/gsuid_core/webconsole/html.py b/gsuid_core/webconsole/html.py
new file mode 100644
index 0000000..1d81d4d
--- /dev/null
+++ b/gsuid_core/webconsole/html.py
@@ -0,0 +1,114 @@
+import fastapi_amis_admin
+
+from gsuid_core.plugins.GenshinUID.GenshinUID.version import GenshinUID_version
+
+login_html = '''
+
+
+
+
+
+GsCore WebConsole
+
+
+'''
+
+footer_html = f'''
+
+
+
+'''
+
+gsuid_webconsole_help = '''
+## 初次使用
+
+欢迎进入网页控制台!
+
+Admin账户可以通过左侧的选项进入不同的数据库直接修改,**首次登陆的Admin账户别忘了修改你的密码!**
+
+普通账户可以通过左侧的选项进行绑定CK或者SK
+
+未来还会加入更多功能!
+
+## 丨我该如何获取Cookies?[#92](https://github.com/KimigaiiWuyi/GenshinUID/issues/92)
+([@RemKeeper](https://github.com/RemKeeper))
+
+```js
+var cookie = document.cookie;
+var Str_Num = cookie.indexOf('_MHYUUID=');
+cookie = cookie.substring(Str_Num);
+var ask = confirm('Cookie:' + cookie + '按确认,然后粘贴至Cookies或者Login_ticket选框内');
+if (ask == true) {
+ copy(cookie);
+ msg = cookie
+} else {
+ msg = 'Cancel'
+}
+```
+
+1. 复制上面全部代码,然后打开[米游社BBS](https://bbs.mihoyo.com/ys/)
+2. 在页面上右键检查或者Ctrl+Shift+i
+3. 选择控制台(Console),粘贴,回车,在弹出的窗口点确认(点完自动复制)
+4. 然后在和机器人的私聊窗口,粘贴发送即可
+
+**警告:Cookies属于个人隐私,其效用相当于账号密码,请勿随意公开!**
+
+## 丨获取米游社Stoken([AutoMihoyoBBS](https://github.com/Womsxd/AutoMihoyoBBS))
+
+```js
+var cookie = document.cookie;
+var ask = confirm('Cookie:' + cookie + '按确认,然后粘贴至Cookies或者Login_ticket选框内');
+if (ask == true) {
+ copy(cookie);
+ msg = cookie
+} else {
+ msg = 'Cancel'
+}
+```
+
+1. 复制上面全部代码,然后打开[米游社账户登录界面](http://user.mihoyo.com/)
+2. 在页面上右键检查或者Ctrl+Shift+i
+3. 选择控制台(Console),粘贴,回车,在弹出的窗口点确认(点完自动复制)
+4. 然后在和机器人的私聊窗口,粘贴发送即可
+
+**警告:Cookies属于个人隐私,其效用相当于账号密码,请勿随意公开!**
+
+## 获取CK通则
+
+**如果获取到的Cookies字段不全,无法通过校验**
+**推荐重新登陆米游社再进行获取**
+
+## 网页端 #92 [@RemKeeper](https://github.com/RemKeeper)
+[通过网页控制台简易获取Cookies](https://github.com/KimigaiiWuyi/GenshinUID/issues/92)
+## 安卓 [@shirokurakana](https://github.com/shirokurakana)
+[通过额外APP获取Cookies](https://github.com/KimigaiiWuyi/GenshinUID/issues/203)
+## IOS [@741807012](https://github.com/741807012)
+[通过快捷指令获取Cookies](https://github.com/KimigaiiWuyi/GenshinUID/issues/201)
+'''
diff --git a/gsuid_core/webconsole/login_page.py b/gsuid_core/webconsole/login_page.py
new file mode 100644
index 0000000..459018e
--- /dev/null
+++ b/gsuid_core/webconsole/login_page.py
@@ -0,0 +1,71 @@
+import contextlib
+
+from fastapi import Request
+from fastapi_user_auth.auth import AuthRouter
+from starlette.responses import RedirectResponse
+from fastapi_user_auth import admin as user_auth_admin
+from fastapi_amis_admin.admin import admin as amis_admin
+from fastapi_amis_admin.amis.components import App, Tpl, Grid, Html, Page
+
+from gsuid_core.webconsole.utils import overrides
+from gsuid_core.webconsole.html import login_html, footer_html
+
+
+@overrides(user_auth_admin)
+def attach_page_head(page: Page) -> Page:
+ page.body = [
+ Html(html=login_html),
+ Grid(
+ columns=[
+ {'body': [page.body], 'lg': 3, 'md': 4, 'valign': 'middle'}
+ ],
+ align='center',
+ valign='middle',
+ ),
+ ]
+ return page
+
+
+@overrides(amis_admin.AdminApp)
+async def _get_page_as_app(self, request: Request) -> App:
+ app = App()
+ app.brandName = self.site.settings.site_title
+ app.header = Tpl(
+ className='w-full',
+ tpl='''
+
+ ''',
+ ) # type: ignore
+ app.footer = footer_html
+ children = await self.get_page_schema_children(request)
+ app.pages = [{'children': children}] if children else [] # type: ignore
+ return app
+
+
+@property
+@overrides(AuthRouter)
+def route_logout(self):
+ @self.auth.requires()
+ async def user_logout(request: Request):
+ token_value = request.auth.backend.get_user_token(request=request)
+ with contextlib.suppress(Exception):
+ await self.auth.backend.token_store.destroy_token(
+ token=token_value
+ )
+ response = RedirectResponse(url="/genshinuid")
+ response.delete_cookie("Authorization")
+ return response
+
+ return user_logout
+
+
+amis_admin.AdminApp._get_page_as_app = _get_page_as_app
+user_auth_admin.attach_page_head = attach_page_head
+AuthRouter.route_logout = route_logout # type:ignore
diff --git a/gsuid_core/webconsole/models.py b/gsuid_core/webconsole/models.py
new file mode 100644
index 0000000..cec5687
--- /dev/null
+++ b/gsuid_core/webconsole/models.py
@@ -0,0 +1,10 @@
+from fastapi_user_auth.auth.models import User
+from fastapi_amis_admin.models.fields import Field
+
+
+class WebUser(User, table=True):
+ bot_id: str = Field(None, title='用户平台') # type:ignore
+ user_id: str = Field(None, title='用户ID') # type:ignore
+ parent_id: int = Field(
+ None, title='Superior', foreign_key='auth_user.id'
+ ) # type:ignore
diff --git a/gsuid_core/webconsole/mount_app.py b/gsuid_core/webconsole/mount_app.py
new file mode 100644
index 0000000..93b7115
--- /dev/null
+++ b/gsuid_core/webconsole/mount_app.py
@@ -0,0 +1,399 @@
+# flake8: noqa
+import platform
+from typing import Any, Callable, Optional
+
+from starlette import status
+from pydantic import BaseModel
+from fastapi_user_auth.auth import Auth
+from fastapi_amis_admin import amis, admin
+from fastapi_user_auth.app import UserAuthApp
+from sqlalchemy_database import AsyncDatabase
+from fastapi_amis_admin.crud import BaseApiOut
+from fastapi_user_auth.site import AuthAdminSite
+from fastapi_amis_admin.models.fields import Field
+from fastapi_amis_admin.admin.site import APIDocsApp
+from fastapi_amis_admin.admin.settings import Settings
+from fastapi_user_auth.auth.models import UserRoleLink
+from fastapi_amis_admin.utils.translation import i18n as _
+from fastapi import Depends, FastAPI, Request, HTTPException
+from sqlalchemy.ext.asyncio import AsyncEngine, create_async_engine
+from fastapi_amis_admin.amis.constants import LevelEnum, DisplayModeEnum
+from fastapi_user_auth.admin import (
+ FormAdmin,
+ UserRegFormAdmin,
+ UserLoginFormAdmin,
+)
+from fastapi_amis_admin.amis.components import (
+ App,
+ Form,
+ Grid,
+ Page,
+ Alert,
+ Action,
+ Property,
+ ActionType,
+ Horizontal,
+ PageSchema,
+ ButtonToolbar,
+)
+
+from gsuid_core.data_store import get_res_path
+from gsuid_core.webconsole.models import WebUser
+from gsuid_core.webconsole.html import gsuid_webconsole_help
+from gsuid_core.webconsole.create_sv_panel import get_sv_page
+from gsuid_core.plugins.GenshinUID.GenshinUID.utils.database import db_url
+from gsuid_core.plugins.GenshinUID.GenshinUID.version import GenshinUID_version
+from gsuid_core.plugins.GenshinUID.GenshinUID.genshinuid_user.add_ck import (
+ _deal_ck,
+)
+from gsuid_core.webconsole.login_page import ( # noqa # 不要删
+ AuthRouter,
+ amis_admin,
+ user_auth_admin,
+)
+from gsuid_core.plugins.GenshinUID.GenshinUID.gsuid_utils.database.models import (
+ GsBind,
+ GsPush,
+ GsUser,
+ GsCache,
+)
+
+
+class GsLoginFormAdmin(UserLoginFormAdmin):
+ @property
+ def route_page(self) -> Callable:
+ async def route(
+ request: Request, result=Depends(super(FormAdmin, self).route_page)
+ ):
+ if request.user:
+ raise HTTPException(
+ status_code=status.HTTP_307_TEMPORARY_REDIRECT,
+ detail='已经登陆过啦~',
+ headers={
+ 'location': request.query_params.get('redirect')
+ or '/genshinuid'
+ },
+ )
+ return result
+
+ return route
+
+ async def get_form(self, request: Request) -> Form:
+ form = await super(user_auth_admin.UserLoginFormAdmin, self).get_form(
+ request
+ )
+ form.body.sort(
+ key=lambda form_item: form_item.type, reverse=True # type: ignore
+ )
+ form.update_from_kwargs(
+ title='',
+ mode=DisplayModeEnum.horizontal,
+ submitText=_('登陆'),
+ actionsClassName='no-border m-none p-none',
+ panelClassName='',
+ wrapWithPanel=True,
+ horizontal=Horizontal(left=3, right=9),
+ actions=[
+ ButtonToolbar(
+ buttons=[
+ ActionType.Link(
+ actionType='link',
+ link=f'{self.router_path}/reg',
+ label=_('Sign up'),
+ ),
+ Action(
+ actionType='submit',
+ label=_('Sign in'),
+ level=LevelEnum.primary,
+ ),
+ ]
+ )
+ ],
+ )
+ form.redirect = request.query_params.get('redirect') or '/genshinuid'
+ return form
+
+
+class GsUserRegFormAdmin(UserRegFormAdmin):
+ async def get_form(self, request: Request) -> Form:
+ form = await super().get_form(request)
+ form.redirect = request.query_params.get('redirect') or '/genshinuid'
+ form.update_from_kwargs(
+ title='',
+ mode=DisplayModeEnum.horizontal,
+ submitText=_('注册'),
+ actionsClassName='no-border m-none p-none',
+ panelClassName='',
+ wrapWithPanel=True,
+ horizontal=Horizontal(left=3, right=9),
+ actions=[
+ ButtonToolbar(
+ buttons=[
+ ActionType.Link(
+ actionType='link',
+ link=f'{self.router_path}/login',
+ label=_('登陆'),
+ ),
+ Action(
+ actionType='submit',
+ label=_('注册'),
+ level=LevelEnum.primary,
+ ),
+ ]
+ )
+ ],
+ )
+
+ return form
+
+
+class GsUserAuthApp(UserAuthApp):
+ UserLoginFormAdmin = GsLoginFormAdmin
+ UserRegFormAdmin = GsUserRegFormAdmin
+
+
+class GsAuthAdminSite(AuthAdminSite):
+ UserAuthApp = GsUserAuthApp
+
+
+# 自定义后台管理站点
+class GsAdminSite(GsAuthAdminSite):
+ def __init__(
+ self,
+ settings: Settings,
+ fastapi: FastAPI = None, # type: ignore
+ engine: AsyncEngine = None, # type: ignore
+ auth: Auth = None, # type: ignore
+ ):
+ super().__init__(settings, fastapi, engine, auth)
+
+ async def get_page(self, request: Request) -> App:
+ app = await super().get_page(request)
+ app.brandName = 'GsCore网页控制台'
+ app.logo = 'https://s2.loli.net/2022/01/31/kwCIl3cF1Z2GxnR.png'
+ return app
+
+
+settings = Settings(
+ database_url_async=f'sqlite+aiosqlite:///{db_url}',
+ database_url='',
+ site_path='/genshinuid',
+ site_icon='https://s2.loli.net/2022/01/31/kwCIl3cF1Z2GxnR.png',
+ site_title='GsCore - 网页控制台',
+ language='zh_CN',
+ amis_theme='ang',
+)
+
+site = GsAdminSite(settings)
+site.auth.user_model = WebUser
+
+
+@site.register_admin
+class AmisPageAdmin(admin.PageAdmin):
+ page_schema = '入门使用'
+ page = Page.parse_obj(
+ {
+ 'type': 'page',
+ 'body': {
+ 'type': 'markdown',
+ 'value': f'{gsuid_webconsole_help}',
+ },
+ }
+ )
+
+
+@site.register_admin
+class UserBindFormAdmin(admin.FormAdmin):
+ page_schema = PageSchema(label='绑定CK或SK', icon='fa fa-link') # type: ignore
+
+ async def get_form(self, request: Request) -> Form:
+ form = await super().get_form(request)
+ form.body.sort(key=lambda form_item: form_item.type, reverse=True) # type: ignore
+ form.update_from_kwargs(
+ title='',
+ mode=DisplayModeEnum.horizontal,
+ submitText='绑定',
+ actionsClassName='no-border m-none p-none',
+ panelClassName='',
+ wrapWithPanel=True,
+ horizontal=Horizontal(left=3, right=9),
+ actions=[
+ ButtonToolbar(
+ buttons=[
+ Action(
+ actionType='submit',
+ label='绑定',
+ level=LevelEnum.primary,
+ )
+ ]
+ )
+ ],
+ )
+ return form
+
+ async def get_page(self, request: Request) -> Page:
+ page = await super().get_page(request)
+ page.body = [
+ Alert(
+ level='warning',
+ body='CK获取可查看左侧栏 [入门使用] 相关细则!',
+ ),
+ amis.Divider(),
+ Grid(
+ columns=[
+ {
+ 'body': [page.body],
+ 'lg': 10,
+ 'md': 10,
+ 'valign': 'middle',
+ }
+ ],
+ align='center',
+ valign='middle',
+ ),
+ ]
+ return page
+
+ # 创建表单数据模型
+ class schema(BaseModel):
+ bot_id: str = Field(..., title='平台ID') # type: ignore
+ user_id: str = Field(..., title='用户ID', min_length=3, max_length=30) # type: ignore
+ cookie: str = Field(..., title='Cookie或者Login_ticket') # type: ignore
+
+ # 处理表单提交数据
+ async def handle(
+ self, request: Request, data: schema, **kwargs
+ ) -> BaseApiOut[Any]:
+ try:
+ im = await _deal_ck(data.bot_id, data.cookie, data.user_id)
+ except Exception:
+ return BaseApiOut(status=-1, msg='你输入的CK可能已经失效,请按照[入门使用]进行操作!')
+ ok_num = im.count('成功')
+ if ok_num < 1:
+ return BaseApiOut(status=-1, msg=im)
+ else:
+ return BaseApiOut(msg=im)
+
+
+class GsAdminModel(admin.ModelAdmin):
+ async def has_page_permission(
+ self,
+ request: Request,
+ obj: Optional[admin.ModelAdmin] = None,
+ action: Optional[str] = None,
+ ) -> bool:
+ return await super().has_page_permission(
+ request
+ ) and await request.auth.requires(roles='admin', response=False)(
+ request
+ )
+
+
+@site.register_admin
+class UserAuth(GsAdminModel):
+ pk_name = 'user_id'
+ page_schema = PageSchema(label='用户授权', icon='fa fa-user-o')
+
+ # 配置管理模型
+ model = UserRoleLink
+
+
+@site.register_admin
+class CKadmin(GsAdminModel):
+ pk_name = 'id'
+ page_schema = PageSchema(label='CK管理', icon='fa fa-database')
+
+ # 配置管理模型
+ model = GsUser
+
+
+@site.register_admin
+class pushadmin(GsAdminModel):
+ pk_name = 'id'
+ page_schema = PageSchema(label='推送管理', icon='fa fa-bullhorn')
+
+ # 配置管理模型
+ model = GsPush
+
+
+@site.register_admin
+class cacheadmin(GsAdminModel):
+ pk_name = 'id'
+ page_schema = PageSchema(label='缓存管理', icon='fa fa-recycle')
+
+ # 配置管理模型
+ model = GsCache
+
+
+@site.register_admin
+class bindadmin(GsAdminModel):
+ pk_name = 'id'
+ page_schema = PageSchema(label='绑定管理', icon='fa fa-users')
+
+ # 配置管理模型
+ model = GsBind
+
+
+# 注册自定义首页
+@site.register_admin
+class MyHomeAdmin(admin.HomeAdmin):
+ group_schema = None
+ page_schema = PageSchema(
+ label=('主页'),
+ icon='fa fa-home',
+ url='/home',
+ isDefaultPage=True,
+ sort=100,
+ )
+ page_path = '/home'
+
+ async def get_page(self, request: Request) -> Page:
+ page = await super().get_page(request)
+ page.body = [
+ Alert(
+ level='warning',
+ body=' 警告: 初始admin账号请务必前往「用户授权」➡「用户管理」处修改密码!',
+ ),
+ amis.Divider(),
+ Property(
+ title='GenshinUID Info',
+ column=4,
+ items=[
+ Property.Item(label='system', content=platform.system()),
+ Property.Item(
+ label='python', content=platform.python_version()
+ ),
+ Property.Item(label='version', content=GenshinUID_version),
+ Property.Item(label='license', content='GPLv3'),
+ ],
+ ),
+ ]
+ return page
+
+
+@site.register_admin
+class SVManagePage(admin.PageAdmin):
+ page_schema = PageSchema(
+ label=('修改配置'),
+ icon='fa fa-sliders',
+ url='/SVmanage',
+ isDefaultPage=True,
+ sort=100,
+ )
+ page = Page.parse_obj(get_sv_page())
+
+ async def has_page_permission(
+ self,
+ request: Request,
+ obj: Optional[admin.ModelAdmin] = None,
+ action: Optional[str] = None,
+ ) -> bool:
+ return await super().has_page_permission(
+ request
+ ) and await request.auth.requires(roles='admin', response=False)(
+ request
+ )
+
+
+# 取消注册默认管理类
+site.unregister_admin(admin.HomeAdmin, APIDocsApp)
diff --git a/gsuid_core/webconsole/utils.py b/gsuid_core/webconsole/utils.py
new file mode 100644
index 0000000..e2f17a7
--- /dev/null
+++ b/gsuid_core/webconsole/utils.py
@@ -0,0 +1,15 @@
+from typing import TypeVar, Callable
+
+T_Wrapped = TypeVar("T_Wrapped", bound=Callable)
+
+
+def overrides(InterfaceClass: object) -> Callable[[T_Wrapped], T_Wrapped]:
+ """标记一个方法为父类 interface 的 implement"""
+
+ def overrider(func: T_Wrapped) -> T_Wrapped:
+ assert func.__name__ in dir(
+ InterfaceClass
+ ), f"Error method: {func.__name__}"
+ return func
+
+ return overrider
diff --git a/poetry.lock b/poetry.lock
index 31a5a91..77f9813 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,4 +1,4 @@
-# This file is automatically @generated by Poetry and should not be changed by hand.
+# This file is automatically @generated by Poetry 1.4.0 and should not be changed by hand.
[[package]]
name = "aiofiles"
@@ -169,36 +169,6 @@ doc = ["packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"]
test = ["contextlib2", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "uvloop (>=0.15)"]
trio = ["trio (>=0.16,<0.22)"]
-[[package]]
-name = "apscheduler"
-version = "3.10.1"
-description = "In-process task scheduler with Cron-like capabilities"
-category = "main"
-optional = false
-python-versions = ">=3.6"
-files = [
- {file = "APScheduler-3.10.1-py3-none-any.whl", hash = "sha256:e813ad5ada7aff36fb08cdda746b520531eaac7757832abc204868ba78e0c8f6"},
- {file = "APScheduler-3.10.1.tar.gz", hash = "sha256:0293937d8f6051a0f493359440c1a1b93e882c57daf0197afeff0e727777b96e"},
-]
-
-[package.dependencies]
-pytz = "*"
-setuptools = ">=0.7"
-six = ">=1.4.0"
-tzlocal = ">=2.0,<3.0.0 || >=4.0.0"
-
-[package.extras]
-doc = ["sphinx", "sphinx-rtd-theme"]
-gevent = ["gevent"]
-mongodb = ["pymongo (>=3.0)"]
-redis = ["redis (>=3.0)"]
-rethinkdb = ["rethinkdb (>=2.4.0)"]
-sqlalchemy = ["sqlalchemy (>=1.4)"]
-testing = ["pytest", "pytest-asyncio", "pytest-cov", "pytest-tornado5"]
-tornado = ["tornado (>=4.3)"]
-twisted = ["twisted"]
-zookeeper = ["kazoo"]
-
[[package]]
name = "async-timeout"
version = "4.0.2"
@@ -230,35 +200,6 @@ docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-
tests = ["attrs[tests-no-zope]", "zope.interface"]
tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"]
-[[package]]
-name = "backports-zoneinfo"
-version = "0.2.1"
-description = "Backport of the standard library zoneinfo module"
-category = "main"
-optional = false
-python-versions = ">=3.6"
-files = [
- {file = "backports.zoneinfo-0.2.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc"},
- {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722"},
- {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1c5742112073a563c81f786e77514969acb58649bcdf6cdf0b4ed31a348d4546"},
- {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win32.whl", hash = "sha256:e8236383a20872c0cdf5a62b554b27538db7fa1bbec52429d8d106effbaeca08"},
- {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8439c030a11780786a2002261569bdf362264f605dfa4d65090b64b05c9f79a7"},
- {file = "backports.zoneinfo-0.2.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac"},
- {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:17746bd546106fa389c51dbea67c8b7c8f0d14b5526a579ca6ccf5ed72c526cf"},
- {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5c144945a7752ca544b4b78c8c41544cdfaf9786f25fe5ffb10e838e19a27570"},
- {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win32.whl", hash = "sha256:e55b384612d93be96506932a786bbcde5a2db7a9e6a4bb4bffe8b733f5b9036b"},
- {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a76b38c52400b762e48131494ba26be363491ac4f9a04c1b7e92483d169f6582"},
- {file = "backports.zoneinfo-0.2.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:8961c0f32cd0336fb8e8ead11a1f8cd99ec07145ec2931122faaac1c8f7fd987"},
- {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e81b76cace8eda1fca50e345242ba977f9be6ae3945af8d46326d776b4cf78d1"},
- {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7b0a64cda4145548fed9efc10322770f929b944ce5cee6c0dfe0c87bf4c0c8c9"},
- {file = "backports.zoneinfo-0.2.1-cp38-cp38-win32.whl", hash = "sha256:1b13e654a55cd45672cb54ed12148cd33628f672548f373963b0bff67b217328"},
- {file = "backports.zoneinfo-0.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:4a0f800587060bf8880f954dbef70de6c11bbe59c673c3d818921f042f9954a6"},
- {file = "backports.zoneinfo-0.2.1.tar.gz", hash = "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2"},
-]
-
-[package.extras]
-tzdata = ["tzdata"]
-
[[package]]
name = "bcrypt"
version = "4.0.1"
@@ -296,14 +237,14 @@ typecheck = ["mypy"]
[[package]]
name = "beautifulsoup4"
-version = "4.11.2"
+version = "4.12.0"
description = "Screen-scraping library"
category = "main"
optional = false
python-versions = ">=3.6.0"
files = [
- {file = "beautifulsoup4-4.11.2-py3-none-any.whl", hash = "sha256:0e79446b10b3ecb499c1556f7e228a53e64a2bfcebd455f370d8927cb5b59e39"},
- {file = "beautifulsoup4-4.11.2.tar.gz", hash = "sha256:bc4bdda6717de5a2987436fb8d72f45dc90dd856bdfd512a1314ce90349a0106"},
+ {file = "beautifulsoup4-4.12.0-py3-none-any.whl", hash = "sha256:2130a5ad7f513200fae61a17abb5e338ca980fa28c439c0571014bc0217e9591"},
+ {file = "beautifulsoup4-4.12.0.tar.gz", hash = "sha256:c5fceeaec29d09c84970e47c65f2f0efe57872f7cff494c9691a26ec0ff13234"},
]
[package.dependencies]
@@ -548,19 +489,19 @@ files = [
[[package]]
name = "fastapi"
-version = "0.94.0"
+version = "0.95.0"
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
- {file = "fastapi-0.94.0-py3-none-any.whl", hash = "sha256:898d7f6616dea49e78fa00e34401f9ace238fc670aafe4e30a16a384e3a671e1"},
- {file = "fastapi-0.94.0.tar.gz", hash = "sha256:08ce0bc6f381ef1b6431e84a31d26eca0b60d6e1ac575adba4af95cc5a36cb62"},
+ {file = "fastapi-0.95.0-py3-none-any.whl", hash = "sha256:daf73bbe844180200be7966f68e8ec9fd8be57079dff1bacb366db32729e6eb5"},
+ {file = "fastapi-0.95.0.tar.gz", hash = "sha256:99d4fdb10e9dd9a24027ac1d0bd4b56702652056ca17a6c8721eec4ad2f14e18"},
]
[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.26.0,<0.27.0"
+starlette = ">=0.26.1,<0.27.0"
[package.extras]
all = ["email-validator (>=1.1.1)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"]
@@ -570,14 +511,14 @@ test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==23.1.0)", "coverage[toml] (>=6
[[package]]
name = "fastapi-amis-admin"
-version = "0.5.0"
+version = "0.5.1"
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"
optional = false
python-versions = ">=3.7"
files = [
- {file = "fastapi_amis_admin-0.5.0-py3-none-any.whl", hash = "sha256:82f232c27b277d83f8829c1be07ec64ebbc94acf6bfd6fadf30c1f9fc9ed2704"},
- {file = "fastapi_amis_admin-0.5.0.tar.gz", hash = "sha256:f17d9cba8e2b32374d5a6f6576b98867d5777668a92885663a01b7a0faf206ff"},
+ {file = "fastapi_amis_admin-0.5.1-py3-none-any.whl", hash = "sha256:7cb65e6389c8f132152fd185cb8832d63a2401689db92b2e0fc2cb9d8d22969c"},
+ {file = "fastapi_amis_admin-0.5.1.tar.gz", hash = "sha256:da4d11fc1f68bb48c817e02b477b5673e4d8e42dfec28e29eabd3937f2b35a36"},
]
[package.dependencies]
@@ -623,19 +564,19 @@ test = ["aiosqlite (>=0.15.0)", "jinja2 (>=2.11.2,<4.0.0)", "pytest (>=6.2.4)",
[[package]]
name = "filelock"
-version = "3.9.0"
+version = "3.10.0"
description = "A platform independent file lock."
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
- {file = "filelock-3.9.0-py3-none-any.whl", hash = "sha256:f58d535af89bb9ad5cd4df046f741f8553a418c01a7856bf0d173bbc9f6bd16d"},
- {file = "filelock-3.9.0.tar.gz", hash = "sha256:7b319f24340b51f55a2bf7a12ac0755a9b03e718311dac567a0f4f7fabd2f5de"},
+ {file = "filelock-3.10.0-py3-none-any.whl", hash = "sha256:e90b34656470756edf8b19656785c5fea73afa1953f3e1b0d645cef11cab3182"},
+ {file = "filelock-3.10.0.tar.gz", hash = "sha256:3199fd0d3faea8b911be52b663dfccceb84c95949dd13179aa21436d1a79c4ce"},
]
[package.extras]
-docs = ["furo (>=2022.12.7)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"]
-testing = ["covdefaults (>=2.2.2)", "coverage (>=7.0.1)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-timeout (>=2.1)"]
+docs = ["furo (>=2022.12.7)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"]
+testing = ["covdefaults (>=2.3)", "coverage (>=7.2.1)", "pytest (>=7.2.2)", "pytest-cov (>=4)", "pytest-timeout (>=2.1)"]
[[package]]
name = "flake8"
@@ -902,14 +843,14 @@ socks = ["socksio (>=1.0.0,<2.0.0)"]
[[package]]
name = "identify"
-version = "2.5.20"
+version = "2.5.21"
description = "File identification library for Python"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
- {file = "identify-2.5.20-py2.py3-none-any.whl", hash = "sha256:5dfef8a745ca4f2c95f27e9db74cb4c8b6d9916383988e8791f3595868f78a33"},
- {file = "identify-2.5.20.tar.gz", hash = "sha256:c8b288552bc5f05a08aff09af2f58e6976bf8ac87beb38498a0e3d98ba64eb18"},
+ {file = "identify-2.5.21-py2.py3-none-any.whl", hash = "sha256:69edcaffa8e91ae0f77d397af60f148b6b45a8044b2cc6d99cafa5b04793ff00"},
+ {file = "identify-2.5.21.tar.gz", hash = "sha256:7671a05ef9cfaf8ff63b15d45a91a1147a03aaccb2976d4e9bd047cbbc508471"},
]
[package.extras]
@@ -993,25 +934,6 @@ typing-inspect = ">=0.4.0"
[package.extras]
dev = ["Sphinx (>=5.1.1)", "black (==22.10.0)", "coverage (>=4.5.4)", "fixit (==0.1.1)", "flake8 (>=3.7.8,<5)", "hypothesis (>=4.36.0)", "hypothesmith (>=0.0.4)", "jinja2 (==3.1.2)", "jupyter (>=1.0.0)", "maturin (>=0.8.3,<0.14)", "nbsphinx (>=0.4.2)", "prompt-toolkit (>=2.0.9)", "pyre-check (==0.9.9)", "setuptools-rust (>=1.5.2)", "setuptools-scm (>=6.0.1)", "slotscheck (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "ufmt (==2.0.1)", "usort (==1.0.5)"]
-[[package]]
-name = "loguru"
-version = "0.6.0"
-description = "Python logging made (stupidly) simple"
-category = "main"
-optional = false
-python-versions = ">=3.5"
-files = [
- {file = "loguru-0.6.0-py3-none-any.whl", hash = "sha256:4e2414d534a2ab57573365b3e6d0234dfb1d84b68b7f3b948e6fb743860a77c3"},
- {file = "loguru-0.6.0.tar.gz", hash = "sha256:066bd06758d0a513e9836fd9c6b5a75bfb3fd36841f4b996bc60b547a309d41c"},
-]
-
-[package.dependencies]
-colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""}
-win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""}
-
-[package.extras]
-dev = ["Sphinx (>=4.1.1)", "black (>=19.10b0)", "colorama (>=0.3.4)", "docutils (==0.16)", "flake8 (>=3.7.7)", "isort (>=5.1.1)", "pytest (>=4.6.2)", "pytest-cov (>=2.7.1)", "sphinx-autobuild (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "tox (>=3.9.0)"]
-
[[package]]
name = "lxml"
version = "4.9.2"
@@ -1274,50 +1196,6 @@ files = [
[package.dependencies]
setuptools = "*"
-[[package]]
-name = "nonebot-plugin-apscheduler"
-version = "0.2.0"
-description = "APScheduler Support for NoneBot2"
-category = "main"
-optional = false
-python-versions = ">=3.8,<4.0"
-files = [
- {file = "nonebot-plugin-apscheduler-0.2.0.tar.gz", hash = "sha256:7b63e99a611b657533b48fcf1f8c6627c18c2eb3fa820a906cd4ec4666c0ceb0"},
- {file = "nonebot_plugin_apscheduler-0.2.0-py3-none-any.whl", hash = "sha256:9285ee84ca1cfa4db73c86cedb5911bbbd25a21ec0cd5f22447cd12f89e48fb4"},
-]
-
-[package.dependencies]
-apscheduler = ">=3.7.0,<4.0.0"
-nonebot2 = ">=2.0.0-rc.1,<3.0.0"
-
-[[package]]
-name = "nonebot2"
-version = "2.0.0rc3"
-description = "An asynchronous python bot framework."
-category = "main"
-optional = false
-python-versions = ">=3.8,<4.0"
-files = [
- {file = "nonebot2-2.0.0rc3-py3-none-any.whl", hash = "sha256:6596e9837e95e99a6cfa7c4e21d75a54a5f3529d34f30454136ebfef6aa374f4"},
- {file = "nonebot2-2.0.0rc3.tar.gz", hash = "sha256:a16da07b7c764d536cbdf9bcb86eb7cc21b1d254c966552ec5d20e0cb303cec2"},
-]
-
-[package.dependencies]
-loguru = ">=0.6.0,<0.7.0"
-pydantic = {version = ">=1.10.0,<2.0.0", extras = ["dotenv"]}
-pygtrie = ">=2.4.1,<3.0.0"
-tomlkit = ">=0.10.0,<1.0.0"
-typing-extensions = ">=3.10.0,<5.0.0"
-yarl = ">=1.7.2,<2.0.0"
-
-[package.extras]
-aiohttp = ["aiohttp[speedups] (>=3.7.4,<4.0.0)"]
-all = ["Quart (>=0.18.0,<1.0.0)", "aiohttp[speedups] (>=3.7.4,<4.0.0)", "fastapi (>=0.87.0,!=0.89.0,<1.0.0)", "httpx[http2] (>=0.20.0,<1.0.0)", "uvicorn[standard] (>=0.20.0,<1.0.0)", "websockets (>=10.0,<11.0)"]
-fastapi = ["fastapi (>=0.87.0,!=0.89.0,<1.0.0)", "uvicorn[standard] (>=0.20.0,<1.0.0)"]
-httpx = ["httpx[http2] (>=0.20.0,<1.0.0)"]
-quart = ["Quart (>=0.18.0,<1.0.0)", "uvicorn[standard] (>=0.20.0,<1.0.0)"]
-websockets = ["websockets (>=10.0,<11.0)"]
-
[[package]]
name = "openpyxl"
version = "3.1.2"
@@ -1567,7 +1445,6 @@ files = [
]
[package.dependencies]
-python-dotenv = {version = ">=0.10.4", optional = true, markers = "extra == \"dotenv\""}
typing-extensions = ">=4.2.0"
[package.extras]
@@ -1586,18 +1463,6 @@ files = [
{file = "pyflakes-3.0.1.tar.gz", hash = "sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd"},
]
-[[package]]
-name = "pygtrie"
-version = "2.5.0"
-description = "A pure Python trie data structure implementation."
-category = "main"
-optional = false
-python-versions = "*"
-files = [
- {file = "pygtrie-2.5.0-py3-none-any.whl", hash = "sha256:8795cda8105493d5ae159a5bef313ff13156c5d4d72feddefacaad59f8c8ce16"},
- {file = "pygtrie-2.5.0.tar.gz", hash = "sha256:203514ad826eb403dab1d2e2ddd034e0d1534bbe4dbe0213bb0593f66beba4e2"},
-]
-
[[package]]
name = "pypng"
version = "0.20220715.0"
@@ -1610,21 +1475,6 @@ files = [
{file = "pypng-0.20220715.0.tar.gz", hash = "sha256:739c433ba96f078315de54c0db975aee537cbc3e1d0ae4ed9aab0ca1e427e2c1"},
]
-[[package]]
-name = "python-dotenv"
-version = "1.0.0"
-description = "Read key-value pairs from a .env file and set them as environment variables"
-category = "main"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "python-dotenv-1.0.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"},
- {file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"},
-]
-
-[package.extras]
-cli = ["click (>=5.0)"]
-
[[package]]
name = "python-multipart"
version = "0.0.6"
@@ -1640,34 +1490,6 @@ files = [
[package.extras]
dev = ["atomicwrites (==1.2.1)", "attrs (==19.2.0)", "coverage (==6.5.0)", "hatch", "invoke (==1.7.3)", "more-itertools (==4.3.0)", "pbr (==4.3.0)", "pluggy (==1.0.0)", "py (==1.11.0)", "pytest (==7.2.0)", "pytest-cov (==4.0.0)", "pytest-timeout (==2.1.0)", "pyyaml (==5.1)"]
-[[package]]
-name = "pytz"
-version = "2022.7.1"
-description = "World timezone definitions, modern and historical"
-category = "main"
-optional = false
-python-versions = "*"
-files = [
- {file = "pytz-2022.7.1-py2.py3-none-any.whl", hash = "sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a"},
- {file = "pytz-2022.7.1.tar.gz", hash = "sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0"},
-]
-
-[[package]]
-name = "pytz-deprecation-shim"
-version = "0.1.0.post0"
-description = "Shims to make deprecation of pytz easier"
-category = "main"
-optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
-files = [
- {file = "pytz_deprecation_shim-0.1.0.post0-py2.py3-none-any.whl", hash = "sha256:8314c9692a636c8eb3bda879b9f119e350e93223ae83e70e80c31675a0fdc1a6"},
- {file = "pytz_deprecation_shim-0.1.0.post0.tar.gz", hash = "sha256:af097bae1b616dde5c5744441e2ddc69e74dfdcb0c263129610d85b87445a59d"},
-]
-
-[package.dependencies]
-"backports.zoneinfo" = {version = "*", markers = "python_version >= \"3.6\" and python_version < \"3.9\""}
-tzdata = {version = "*", markers = "python_version >= \"3.6\""}
-
[[package]]
name = "pyyaml"
version = "6.0"
@@ -1803,7 +1625,7 @@ six = ">=1.9.0"
name = "setuptools"
version = "67.6.0"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
-category = "main"
+category = "dev"
optional = false
python-versions = ">=3.7"
files = [
@@ -1916,7 +1738,7 @@ files = [
]
[package.dependencies]
-greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"}
+greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and platform_machine == \"aarch64\" or python_version >= \"3\" and platform_machine == \"ppc64le\" or python_version >= \"3\" and platform_machine == \"x86_64\" or python_version >= \"3\" and platform_machine == \"amd64\" or python_version >= \"3\" and platform_machine == \"AMD64\" or python_version >= \"3\" and platform_machine == \"win32\" or python_version >= \"3\" and platform_machine == \"WIN32\""}
[package.extras]
aiomysql = ["aiomysql", "greenlet (!=0.4.17)"]
@@ -2011,14 +1833,14 @@ test = ["pytest (>=7.1.3)"]
[[package]]
name = "starlette"
-version = "0.26.0.post1"
+version = "0.26.1"
description = "The little ASGI library that shines."
category = "main"
optional = false
python-versions = ">=3.7"
files = [
- {file = "starlette-0.26.0.post1-py3-none-any.whl", hash = "sha256:5b80b546ed60d43da45f80113c05ff9f4c44fae95ee884945958eba685c56253"},
- {file = "starlette-0.26.0.post1.tar.gz", hash = "sha256:af0e54d08afed70fcbc53ae01e71c9c62c8ab038ff8cfd3f7477bf0f086b5ab4"},
+ {file = "starlette-0.26.1-py3-none-any.whl", hash = "sha256:e87fce5d7cbdde34b76f0ac69013fd9d190d581d80681493016666e6f96c6d5e"},
+ {file = "starlette-0.26.1.tar.gz", hash = "sha256:41da799057ea8620e4667a3e69a5b1923ebd32b1819c8fa75634bbe8d8bea9bd"},
]
[package.dependencies]
@@ -2044,7 +1866,7 @@ files = [
name = "tomlkit"
version = "0.11.6"
description = "Style preserving TOML library"
-category = "main"
+category = "dev"
optional = false
python-versions = ">=3.6"
files = [
@@ -2101,39 +1923,6 @@ files = [
mypy-extensions = ">=0.3.0"
typing-extensions = ">=3.7.4"
-[[package]]
-name = "tzdata"
-version = "2022.7"
-description = "Provider of IANA time zone data"
-category = "main"
-optional = false
-python-versions = ">=2"
-files = [
- {file = "tzdata-2022.7-py2.py3-none-any.whl", hash = "sha256:2b88858b0e3120792a3c0635c23daf36a7d7eeeca657c323da299d2094402a0d"},
- {file = "tzdata-2022.7.tar.gz", hash = "sha256:fe5f866eddd8b96e9fcba978f8e503c909b19ea7efda11e52e39494bad3a7bfa"},
-]
-
-[[package]]
-name = "tzlocal"
-version = "4.2"
-description = "tzinfo object for the local timezone"
-category = "main"
-optional = false
-python-versions = ">=3.6"
-files = [
- {file = "tzlocal-4.2-py3-none-any.whl", hash = "sha256:89885494684c929d9191c57aa27502afc87a579be5cdd3225c77c463ea043745"},
- {file = "tzlocal-4.2.tar.gz", hash = "sha256:ee5842fa3a795f023514ac2d801c4a81d1743bbe642e3940143326b3a00addd7"},
-]
-
-[package.dependencies]
-"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""}
-pytz-deprecation-shim = "*"
-tzdata = {version = "*", markers = "platform_system == \"Windows\""}
-
-[package.extras]
-devenv = ["black", "pyroma", "pytest-cov", "zest.releaser"]
-test = ["pytest (>=4.3)", "pytest-mock (>=3.3)"]
-
[[package]]
name = "urllib3"
version = "1.26.15"
@@ -2153,14 +1942,14 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
[[package]]
name = "uvicorn"
-version = "0.21.0"
+version = "0.21.1"
description = "The lightning-fast ASGI server."
category = "main"
optional = false
python-versions = ">=3.7"
files = [
- {file = "uvicorn-0.21.0-py3-none-any.whl", hash = "sha256:e69e955cb621ae7b75f5590a814a4fcbfb14cb8f44a36dfe3c5c75ab8aee3ad5"},
- {file = "uvicorn-0.21.0.tar.gz", hash = "sha256:8635a388062222082f4b06225b867b74a7e4ef942124453d4d1d1a5cb3750932"},
+ {file = "uvicorn-0.21.1-py3-none-any.whl", hash = "sha256:e47cac98a6da10cd41e6fd036d472c6f58ede6c5dbee3dbee3ef7a100ed97742"},
+ {file = "uvicorn-0.21.1.tar.gz", hash = "sha256:0fac9cb342ba099e0d582966005f3fdba5b0290579fed4a6266dc702ca7bb032"},
]
[package.dependencies]
@@ -2172,14 +1961,14 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)",
[[package]]
name = "virtualenv"
-version = "20.20.0"
+version = "20.21.0"
description = "Virtual Python Environment builder"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
- {file = "virtualenv-20.20.0-py3-none-any.whl", hash = "sha256:3c22fa5a7c7aa106ced59934d2c20a2ecb7f49b4130b8bf444178a16b880fa45"},
- {file = "virtualenv-20.20.0.tar.gz", hash = "sha256:a8a4b8ca1e28f864b7514a253f98c1d62b64e31e77325ba279248c65fb4fcef4"},
+ {file = "virtualenv-20.21.0-py3-none-any.whl", hash = "sha256:31712f8f2a17bd06234fa97fdf19609e789dd4e3e4bf108c3da71d710651adbc"},
+ {file = "virtualenv-20.21.0.tar.gz", hash = "sha256:f50e3e60f990a0757c9b68333c9fdaa72d7188caa417f96af9e52407831a3b68"},
]
[package.dependencies]
@@ -2270,21 +2059,6 @@ files = [
{file = "websockets-10.4.tar.gz", hash = "sha256:eef610b23933c54d5d921c92578ae5f89813438fded840c2e9809d378dc765d3"},
]
-[[package]]
-name = "win32-setctime"
-version = "1.1.0"
-description = "A small Python utility to set file creation time on Windows"
-category = "main"
-optional = false
-python-versions = ">=3.5"
-files = [
- {file = "win32_setctime-1.1.0-py3-none-any.whl", hash = "sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad"},
- {file = "win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"},
-]
-
-[package.extras]
-dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"]
-
[[package]]
name = "yarl"
version = "1.8.2"
@@ -2376,4 +2150,4 @@ multidict = ">=4.0"
[metadata]
lock-version = "2.0"
python-versions = "^3.8.1"
-content-hash = "ba81e4086af98ac3117b3ac99a19d8d7915cc893a5a08cc52a27300c92c4395b"
+content-hash = "cc565e9b9975fa6d8e1e0117da4cc877a9f62502708b3b507857b744f48c63f6"
diff --git a/pyproject.toml b/pyproject.toml
index 568db81..7a79b9a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -22,12 +22,11 @@ aiohttp = ">=3.8.1"
sqlalchemy = ">=1.4.39,<2.0.0"
pillow = ">=9.2.0"
aiosqlite = ">=0.17.0"
-nonebot-plugin-apscheduler = ">=0.1.4"
aiofiles = ">=0.8.0"
sqlmodel = ">=0.0.8"
gitpython = ">=3.1.27"
-fastapi-amis-admin = ">=0.2.1"
-fastapi-user-auth = ">=0.2.1"
+fastapi-amis-admin = ">=0.5.0"
+fastapi-user-auth = ">=0.5.0"
qrcode = {extras = ["pil"], version = "^7.3.1"}
msgspec = ">= 0.13.1"
uvicorn = ">=0.20.0"
diff --git a/requirements.txt b/requirements.txt
index f3ddf0a..e590fa0 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,22 +3,20 @@ aiohttp==3.8.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0
aiosignal==1.3.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
aiosqlite==0.18.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
anyio==3.6.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
-apscheduler==3.10.1 ; python_full_version >= "3.8.1" and python_version < "4.0"
async-timeout==4.0.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
attrs==22.2.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
-backports-zoneinfo==0.2.1 ; python_full_version >= "3.8.1" and python_version < "3.9"
bcrypt==4.0.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
-beautifulsoup4==4.11.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
+beautifulsoup4==4.12.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
certifi==2022.12.7 ; python_full_version >= "3.8.1" and python_version < "4"
charset-normalizer==3.1.0 ; python_full_version >= "3.8.1" and python_version < "4"
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_version < "4.0" and platform_system == "Windows" or python_full_version >= "3.8.1" and python_version < "4.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"
dnspython==2.3.0 ; python_full_version >= "3.8.1" and python_version < "4.0"
email-validator==1.3.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
et-xmlfile==1.1.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
-fastapi-amis-admin==0.5.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
+fastapi-amis-admin==0.5.1 ; 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.94.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
+fastapi==0.95.0 ; 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"
gitdb==4.0.10 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
gitpython==3.1.31 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
@@ -27,29 +25,20 @@ h11==0.14.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
httpcore==0.16.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
httpx==0.23.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
idna==3.4 ; python_full_version >= "3.8.1" and python_version < "4"
-loguru==0.6.0 ; python_full_version >= "3.8.1" and python_version < "4.0"
lxml==4.9.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
msgspec==0.13.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
-multidict==6.0.4 ; python_full_version >= "3.8.1" and python_version < "4.0"
-nonebot-plugin-apscheduler==0.2.0 ; python_full_version >= "3.8.1" and python_version < "4.0"
-nonebot2==2.0.0rc3 ; python_full_version >= "3.8.1" and python_version < "4.0"
+multidict==6.0.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
openpyxl==3.1.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
passlib==1.7.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
pillow==9.4.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
pydantic==1.10.6 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
-pydantic[dotenv]==1.10.6 ; python_full_version >= "3.8.1" and python_version < "4.0"
-pygtrie==2.5.0 ; python_full_version >= "3.8.1" and python_version < "4.0"
pypng==0.20220715.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
-python-dotenv==1.0.0 ; python_full_version >= "3.8.1" and python_version < "4.0"
python-multipart==0.0.6 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
-pytz-deprecation-shim==0.1.0.post0 ; python_full_version >= "3.8.1" and python_version < "4.0"
-pytz==2022.7.1 ; python_full_version >= "3.8.1" and python_version < "4.0"
qrcode[pil]==7.4.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
requests==2.28.2 ; python_full_version >= "3.8.1" and python_version < "4"
rfc3986[idna2008]==1.5.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
rollbar==0.16.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
-setuptools==67.6.0 ; python_full_version >= "3.8.1" and python_version < "4.0"
-six==1.16.0 ; python_full_version >= "3.8.1" and python_version < "4.0"
+six==1.16.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
smmap==5.0.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
sniffio==1.3.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
soupsieve==2.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
@@ -58,13 +47,9 @@ sqlalchemy2-stubs==0.0.2a32 ; python_full_version >= "3.8.1" and python_full_ver
sqlalchemy==1.4.41 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
sqlmodel==0.0.8 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
sqlmodelx==0.0.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
-starlette==0.26.0.post1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
-tomlkit==0.11.6 ; python_full_version >= "3.8.1" and python_version < "4.0"
-typing-extensions==4.5.0 ; python_full_version >= "3.8.1" and python_version < "4.0"
-tzdata==2022.7 ; python_full_version >= "3.8.1" and python_version < "4.0"
-tzlocal==4.2 ; python_full_version >= "3.8.1" and python_version < "4.0"
+starlette==0.26.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
+typing-extensions==4.5.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
urllib3==1.26.15 ; python_full_version >= "3.8.1" and python_version < "4"
-uvicorn==0.21.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
+uvicorn==0.21.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
websockets==10.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
-win32-setctime==1.1.0 ; python_full_version >= "3.8.1" and python_version < "4.0" and sys_platform == "win32"
-yarl==1.8.2 ; python_full_version >= "3.8.1" and python_version < "4.0"
+yarl==1.8.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"