chore: 清理敏感与开发文档,仅同步代码

- 永久忽略并从仓库移除 开发文档/
- 移除并忽略 .env 与小程序私有配置
- 同步小程序/管理端/API与脚本改动

Made-with: Cursor
This commit is contained in:
卡若
2026-03-17 17:50:12 +08:00
parent 868b0a10d9
commit 76965adb23
443 changed files with 24175 additions and 64154 deletions

View File

@@ -0,0 +1,19 @@
# 管理端测试 (web)
> 管理后台功能测试用例。对应 soul-adminAPI 路径:`/api/admin/*`、`/api/db/*`
---
## 测试范围
- 内容管理(文章、章节、书籍 CRUD
- 用户管理
- 订单、提现
- VIP 角色、推广设置
- 导师、导师预约、二维码、站点、支付配置
---
## 用例编写
在此目录下新增 `.md` 或测试脚本,按场景组织用例。

View File

@@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
"""web 专用 fixtures继承 scripts/test/conftest.py"""

View File

@@ -0,0 +1,42 @@
# -*- coding: utf-8 -*-
"""
管理端鉴权测试。POST /api/admin 登录GET /api/admin 鉴权检查。
"""
import pytest
import requests
from util import admin_headers
def test_admin_login(base_url):
"""POST /api/admin 登录成功"""
r = requests.post(
f"{base_url}/api/admin",
json={"username": "admin", "password": "admin123"},
timeout=10,
)
assert r.status_code == 200
data = r.json()
assert data.get("success") is True
assert "token" in data
assert "user" in data
def test_admin_check_with_token(admin_token, base_url):
"""GET /api/admin 带 token 鉴权通过"""
if not admin_token:
pytest.skip("admin 登录失败,跳过鉴权测试")
r = requests.get(
f"{base_url}/api/admin",
headers=admin_headers(admin_token),
timeout=10,
)
assert r.status_code == 200
data = r.json()
assert data.get("success") is True
def test_admin_check_without_token(base_url):
"""GET /api/admin 无 token 返回 401"""
r = requests.get(f"{base_url}/api/admin", timeout=10)
assert r.status_code == 401

View File

@@ -0,0 +1,121 @@
# -*- coding: utf-8 -*-
"""
文件上传测试。POST /api/upload 上传图片DELETE /api/upload 删除。
验证本地存储OSS 未配置时)、响应格式、删除流程。
"""
import io
import pytest
import requests
# 最小有效 JPEG1x1 像素,约 100 字节)
_MIN_JPEG = (
b"\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00"
b"\xff\xdb\x00C\x00\x08\x06\x06\x07\x06\x05\x08\x07\x07\x07\t\t\x08\n\x0c\x14\r\x0c\x0b\x0b\x0c\x19\x12\x13\x0f\x14\x1d\x1a\x1f\x1e\x1d\x1a\x1c\x1c"
b" $.' \",#\x1c\x1c(7),01444\x1f'9=82<.342\xff\xc0\x00\x0b\x08\x00\x01\x00\x01\x01\x01\x11\x00\xff\xc4\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\xff\xda\x00\x08\x01\x01\x00\x00\x00?\x00\xfe\x02\x1f\xff\xd9"
)
def test_upload_post_success(base_url):
"""POST /api/upload 上传图片成功,返回 url、fileName、size、type"""
files = {"file": ("test_upload.jpg", io.BytesIO(_MIN_JPEG), "image/jpeg")}
data = {"folder": "test"}
r = requests.post(
f"{base_url}/api/upload",
files=files,
data=data,
timeout=10,
)
assert r.status_code == 200, f"期望 200实际 {r.status_code}: {r.text}"
body = r.json()
assert body.get("success") is True, body
assert "url" in body, body
assert body["url"], "url 不应为空"
data_out = body.get("data", {})
assert "url" in data_out
assert "fileName" in data_out
assert "size" in data_out
assert data_out["size"] == len(_MIN_JPEG)
assert "type" in data_out
assert "image" in str(data_out.get("type", "")).lower()
def test_upload_post_with_admin_token(base_url, admin_token):
"""POST /api/upload 带管理端 token 也可上传(接口不强制鉴权)"""
if not admin_token:
pytest.skip("admin 登录失败")
files = {"file": ("avatar.jpg", io.BytesIO(_MIN_JPEG), "image/jpeg")}
# multipart 上传不设 Content-Type让 requests 自动带 boundary
headers = {"Authorization": f"Bearer {admin_token}"}
r = requests.post(
f"{base_url}/api/upload",
files=files,
headers=headers,
timeout=10,
)
assert r.status_code == 200
body = r.json()
assert body.get("success") is True
assert body.get("url")
def test_upload_post_no_file(base_url):
"""POST /api/upload 无 file 返回 400"""
r = requests.post(
f"{base_url}/api/upload",
data={"folder": "test"},
timeout=10,
)
assert r.status_code == 400
body = r.json()
assert body.get("success") is False
assert "error" in body or "请选择" in body.get("error", "")
def test_upload_post_invalid_type(base_url):
"""POST /api/upload 非图片格式返回 400"""
files = {"file": ("test.txt", io.BytesIO(b"hello"), "text/plain")}
r = requests.post(
f"{base_url}/api/upload",
files=files,
timeout=10,
)
assert r.status_code == 400
body = r.json()
assert body.get("success") is False
def test_upload_delete_local(base_url):
"""DELETE /api/upload 删除本地文件:先上传再删除"""
# 1. 上传
files = {"file": ("del_test.jpg", io.BytesIO(_MIN_JPEG), "image/jpeg")}
r1 = requests.post(
f"{base_url}/api/upload",
files=files,
data={"folder": "test"},
timeout=10,
)
assert r1.status_code == 200
url = r1.json().get("url")
assert url, "上传应返回 url"
# path 支持 /uploads/xxx 或含 /uploads/ 的完整 URL
path = url
# 2. 删除
r2 = requests.delete(
f"{base_url}/api/upload",
params={"path": path},
timeout=10,
)
assert r2.status_code == 200
body = r2.json()
assert body.get("success") is True
assert "删除成功" in body.get("message", "")
def test_upload_delete_no_path(base_url):
"""DELETE /api/upload 无 path 返回 400"""
r = requests.delete(f"{base_url}/api/upload", timeout=10)
assert r.status_code == 400
body = r.json()
assert body.get("success") is False