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 = ''' +

+ + GenshinUID + +

+

GsCore WebConsole

+

+ ✨基于 + + HoshinoBot + + / + NoneBot2 + / + QQ官方频道Bot + 的原神多功能插件✨ +

+
+ + 安装文档   ·   + 指令列表   ·   + 常见问题 +
+''' + +footer_html = f''' +

+

Copyright © 2021 - 2022 + GenshinUID {GenshinUID_version} + + X + + fastapi_amis_admin {fastapi_amis_admin.__version__} + +
+

+''' + +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"