- 新增图像生成接口,支持试用、积分和自定义API Key模式 - 实现生成图片结果异步上传至MinIO存储,带重试机制 - 优化积分预扣除和异常退还逻辑,保障用户积分准确 - 添加获取生成历史记录接口,支持时间范围和分页 - 提供本地字典配置接口,支持模型、比例、提示模板和尺寸 - 实现图片批量上传接口,支持S3兼容对象存储 feat(admin): 增加管理员角色管理与权限分配接口 - 实现角色列表查询、角色创建、更新及删除功能 - 增加权限列表查询接口 - 实现用户角色分配接口,便于统一管理用户权限 - 增加系统字典增删查改接口,支持分类过滤和排序 - 权限控制全面覆盖管理接口,保证安全访问 feat(auth): 完善用户登录注册及权限相关接口与页面 - 实现手机号验证码发送及校验功能,保障注册安全 - 支持手机号注册、登录及退出接口,集成日志记录 - 增加修改密码功能,验证原密码后更新 - 提供动态导航菜单接口,基于权限展示不同菜单 - 实现管理界面路由及日志、角色、字典管理页面访问权限控制 - 添加系统日志查询接口,支持关键词和等级筛选 feat(app): 初始化Flask应用并配置蓝图与数据库 - 创建应用程序工厂,加载配置,初始化数据库和Redis客户端 - 注册认证、API及管理员蓝图,整合路由 - 根路由渲染主页模板 - 应用上下文中自动创建数据库表,保证运行环境准备完毕 feat(database): 提供数据库创建与迁移支持脚本 - 新增数据库创建脚本,支持自动检测是否已存在 - 添加数据库表初始化脚本,支持创建和删除所有表 - 实现RBAC权限初始化,包含基础权限和角色创建 - 新增字段手动修复脚本,添加用户API Key和积分字段 - 强制迁移脚本支持清理连接和修复表结构,初始化默认数据及角色分配 feat(config): 新增系统配置参数 - 配置数据库、Redis、Session和MinIO相关参数 - 添加AI接口地址及试用Key配置 - 集成阿里云短信服务配置及开发模式相关参数 feat(extensions): 初始化数据库、Redis和MinIO客户端 - 创建全局SQLAlchemy数据库实例和Redis客户端 - 配置基于boto3的MinIO兼容S3客户端 chore(logs): 添加示例系统日志文件 - 记录用户请求、验证码发送成功与失败的日志信息
195 lines
6.2 KiB
Python
195 lines
6.2 KiB
Python
"""A small application that can be used to test a WSGI server and check
|
|
it for WSGI compliance.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib.metadata
|
|
import os
|
|
import sys
|
|
import typing as t
|
|
from textwrap import wrap
|
|
|
|
from markupsafe import escape
|
|
|
|
from .wrappers.request import Request
|
|
from .wrappers.response import Response
|
|
|
|
TEMPLATE = """\
|
|
<!doctype html>
|
|
<html lang=en>
|
|
<title>WSGI Information</title>
|
|
<style type="text/css">
|
|
@import url(https://fonts.googleapis.com/css?family=Ubuntu);
|
|
|
|
body { font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
|
|
'Verdana', sans-serif; background-color: white; color: #000;
|
|
font-size: 15px; text-align: center; }
|
|
div.box { text-align: left; width: 45em; margin: auto; padding: 50px 0;
|
|
background-color: white; }
|
|
h1, h2 { font-family: 'Ubuntu', 'Lucida Grande', 'Lucida Sans Unicode',
|
|
'Geneva', 'Verdana', sans-serif; font-weight: normal; }
|
|
h1 { margin: 0 0 30px 0; }
|
|
h2 { font-size: 1.4em; margin: 1em 0 0.5em 0; }
|
|
table { width: 100%%; border-collapse: collapse; border: 1px solid #AFC5C9 }
|
|
table th { background-color: #AFC1C4; color: white; font-size: 0.72em;
|
|
font-weight: normal; width: 18em; vertical-align: top;
|
|
padding: 0.5em 0 0.1em 0.5em; }
|
|
table td { border: 1px solid #AFC5C9; padding: 0.1em 0 0.1em 0.5em; }
|
|
code { font-family: 'Consolas', 'Monaco', 'Bitstream Vera Sans Mono',
|
|
monospace; font-size: 0.7em; }
|
|
ul li { line-height: 1.5em; }
|
|
ul.path { font-size: 0.7em; margin: 0 -30px; padding: 8px 30px;
|
|
list-style: none; background: #E8EFF0; }
|
|
ul.path li { line-height: 1.6em; }
|
|
li.virtual { color: #999; text-decoration: underline; }
|
|
li.exp { background: white; }
|
|
</style>
|
|
<div class="box">
|
|
<h1>WSGI Information</h1>
|
|
<p>
|
|
This page displays all available information about the WSGI server and
|
|
the underlying Python interpreter.
|
|
<h2 id="python-interpreter">Python Interpreter</h2>
|
|
<table>
|
|
<tr>
|
|
<th>Python Version
|
|
<td>%(python_version)s
|
|
<tr>
|
|
<th>Platform
|
|
<td>%(platform)s [%(os)s]
|
|
<tr>
|
|
<th>API Version
|
|
<td>%(api_version)s
|
|
<tr>
|
|
<th>Byteorder
|
|
<td>%(byteorder)s
|
|
<tr>
|
|
<th>Werkzeug Version
|
|
<td>%(werkzeug_version)s
|
|
</table>
|
|
<h2 id="wsgi-environment">WSGI Environment</h2>
|
|
<table>%(wsgi_env)s</table>
|
|
<h2 id="installed-eggs">Installed Eggs</h2>
|
|
<p>
|
|
The following python packages were installed on the system as
|
|
Python eggs:
|
|
<ul>%(python_eggs)s</ul>
|
|
<h2 id="sys-path">System Path</h2>
|
|
<p>
|
|
The following paths are the current contents of the load path. The
|
|
following entries are looked up for Python packages. Note that not
|
|
all items in this path are folders. Gray and underlined items are
|
|
entries pointing to invalid resources or used by custom import hooks
|
|
such as the zip importer.
|
|
<p>
|
|
Items with a bright background were expanded for display from a relative
|
|
path. If you encounter such paths in the output you might want to check
|
|
your setup as relative paths are usually problematic in multithreaded
|
|
environments.
|
|
<ul class="path">%(sys_path)s</ul>
|
|
</div>
|
|
"""
|
|
|
|
|
|
def iter_sys_path() -> t.Iterator[tuple[str, bool, bool]]:
|
|
if os.name == "posix":
|
|
|
|
def strip(x: str) -> str:
|
|
prefix = os.path.expanduser("~")
|
|
if x.startswith(prefix):
|
|
x = f"~{x[len(prefix) :]}"
|
|
return x
|
|
|
|
else:
|
|
|
|
def strip(x: str) -> str:
|
|
return x
|
|
|
|
cwd = os.path.abspath(os.getcwd())
|
|
for item in sys.path:
|
|
path = os.path.join(cwd, item or os.path.curdir)
|
|
yield strip(os.path.normpath(path)), not os.path.isdir(path), path != item
|
|
|
|
|
|
@Request.application
|
|
def test_app(req: Request) -> Response:
|
|
"""Simple test application that dumps the environment. You can use
|
|
it to check if Werkzeug is working properly:
|
|
|
|
.. sourcecode:: pycon
|
|
|
|
>>> from werkzeug.serving import run_simple
|
|
>>> from werkzeug.testapp import test_app
|
|
>>> run_simple('localhost', 3000, test_app)
|
|
* Running on http://localhost:3000/
|
|
|
|
The application displays important information from the WSGI environment,
|
|
the Python interpreter and the installed libraries.
|
|
"""
|
|
try:
|
|
import pkg_resources
|
|
except ImportError:
|
|
eggs: t.Iterable[t.Any] = ()
|
|
else:
|
|
eggs = sorted(
|
|
pkg_resources.working_set,
|
|
key=lambda x: x.project_name.lower(),
|
|
)
|
|
python_eggs = []
|
|
for egg in eggs:
|
|
try:
|
|
version = egg.version
|
|
except (ValueError, AttributeError):
|
|
version = "unknown"
|
|
python_eggs.append(
|
|
f"<li>{escape(egg.project_name)} <small>[{escape(version)}]</small>"
|
|
)
|
|
|
|
wsgi_env = []
|
|
sorted_environ = sorted(req.environ.items(), key=lambda x: repr(x[0]).lower())
|
|
for key, value in sorted_environ:
|
|
value = "".join(wrap(str(escape(repr(value)))))
|
|
wsgi_env.append(f"<tr><th>{escape(key)}<td><code>{value}</code>")
|
|
|
|
sys_path = []
|
|
for item, virtual, expanded in iter_sys_path():
|
|
css = []
|
|
if virtual:
|
|
css.append("virtual")
|
|
if expanded:
|
|
css.append("exp")
|
|
class_str = f' class="{" ".join(css)}"' if css else ""
|
|
sys_path.append(f"<li{class_str}>{escape(item)}")
|
|
|
|
context = {
|
|
"python_version": "<br>".join(escape(sys.version).splitlines()),
|
|
"platform": escape(sys.platform),
|
|
"os": escape(os.name),
|
|
"api_version": sys.api_version,
|
|
"byteorder": sys.byteorder,
|
|
"werkzeug_version": _get_werkzeug_version(),
|
|
"python_eggs": "\n".join(python_eggs),
|
|
"wsgi_env": "\n".join(wsgi_env),
|
|
"sys_path": "\n".join(sys_path),
|
|
}
|
|
return Response(TEMPLATE % context, mimetype="text/html")
|
|
|
|
|
|
_werkzeug_version = ""
|
|
|
|
|
|
def _get_werkzeug_version() -> str:
|
|
global _werkzeug_version
|
|
|
|
if not _werkzeug_version:
|
|
_werkzeug_version = importlib.metadata.version("werkzeug")
|
|
|
|
return _werkzeug_version
|
|
|
|
|
|
if __name__ == "__main__":
|
|
from .serving import run_simple
|
|
|
|
run_simple("localhost", 5000, test_app, use_reloader=True)
|