fix(api): return avatar filename in data

This commit is contained in:
jxxghp
2026-08-06 23:36:34 +08:00
parent a52e1fdc1c
commit 5654512d41
5 changed files with 48 additions and 5 deletions
+1 -1
View File
@@ -119,7 +119,7 @@ async def upload_avatar(
if not user: if not user:
return schemas.Response(success=False, message="用户不存在") return schemas.Response(success=False, message="用户不存在")
await user.async_update(db, {"avatar": f"data:image/ico;base64,{file_base64}"}) await user.async_update(db, {"avatar": f"data:image/ico;base64,{file_base64}"})
return schemas.Response(success=True, message=file.filename) return schemas.Response(success=True, data={"filename": file.filename})
@router.get("/config/{key}", summary="查询用户配置", response_model=schemas.Response) @router.get("/config/{key}", summary="查询用户配置", response_model=schemas.Response)
+1 -1
View File
@@ -124,7 +124,7 @@ MoviePilot 也提供普通 REST API 给前端和自动化客户端使用。所
通用 REST 响应包含 `success``message``message_i18n``data` 字段。为兼容 App 和第三方客户端,`message` 继续保留原中文或原始后端文本;新版前端可发送 `X-MoviePilot-Locale: zh-CN|zh-TW|en-US``Accept-Language`,并优先展示 `message_i18n`。未提供语言头或翻译缺失时,`message_i18n` 会回退为原文本。 通用 REST 响应包含 `success``message``message_i18n``data` 字段。为兼容 App 和第三方客户端,`message` 继续保留原中文或原始后端文本;新版前端可发送 `X-MoviePilot-Locale: zh-CN|zh-TW|en-US``Accept-Language`,并优先展示 `message_i18n`。未提供语言头或翻译缺失时,`message_i18n` 会回退为原文本。
`GET /api/v1/login/wallpaper` 及对应的 v2 路径会将壁纸 URL 放在 `data` 字段中`message` 不再承载业务数据。 `GET /api/v1/login/wallpaper` 及对应的 v2 路径会将壁纸 URL 放在 `data` 字段中`POST /api/v1/user/avatar/{user_id}` 及对应的 v2 路径会以 `data.filename` 返回原始文件名。上述接口的 `message` 不再承载业务数据。
FastAPI 的 HTTP 异常在 v1、v2 均统一使用 `message`,不再返回顶层 `detail` / `detail_i18n` FastAPI 的 HTTP 异常在 v1、v2 均统一使用 `message`,不再返回顶层 `detail` / `detail_i18n`
+2 -2
View File
@@ -1,6 +1,6 @@
--- ---
name: moviepilot-api name: moviepilot-api
version: 8 version: 9
description: >- description: >-
Use this skill when you need to call MoviePilot REST API endpoints directly Use this skill when you need to call MoviePilot REST API endpoints directly
with the bundled Python client. Covers MoviePilot HTTP endpoints across media with the bundled Python client. Covers MoviePilot HTTP endpoints across media
@@ -501,7 +501,7 @@ The list endpoint returns local cache totals plus `shared_recognized` and
| GET | `/api/v1/user/{username}` | User detail | | GET | `/api/v1/user/{username}` | User detail |
| DELETE | `/api/v1/user/id/{user_id}` | Delete user by ID | | DELETE | `/api/v1/user/id/{user_id}` | Delete user by ID |
| DELETE | `/api/v1/user/name/{user_name}` | Delete user by username | | DELETE | `/api/v1/user/name/{user_name}` | Delete user by username |
| POST | `/api/v1/user/avatar/{user_id}` | Upload avatar. Body: multipart/form-data | | POST | `/api/v1/user/avatar/{user_id}` | Upload avatar. Body: multipart/form-data; original filename is returned in `data.filename` |
| GET | `/api/v1/user/config/{key}` | Get user config | | GET | `/api/v1/user/config/{key}` | Get user config |
| POST | `/api/v1/user/config/{key}` | Update user config | | POST | `/api/v1/user/config/{key}` | Update user config |
+43
View File
@@ -284,3 +284,46 @@ def test_upload_avatar_rejects_other_user_for_non_superuser():
assert exc_info.value.status_code == 400 assert exc_info.value.status_code == 400
assert exc_info.value.detail == "用户权限不足" assert exc_info.value.detail == "用户权限不足"
def test_upload_avatar_returns_filename_in_data(monkeypatch):
"""头像上传成功时应通过 data 返回文件名,message 只保留消息文本。"""
class FakeUser:
"""记录头像更新内容的用户桩。"""
def __init__(self):
self.values = None
async def async_update(self, db: object, values: dict[str, str]) -> None:
"""记录待写入的头像数据。"""
self.values = values
class FakeUserModel:
"""返回固定用户的模型桩。"""
@classmethod
async def async_get(cls, db: object, user_id: int) -> FakeUser:
"""按用户 ID 返回测试用户。"""
assert user_id == 1
return fake_user
fake_user = FakeUser()
current_user = SimpleNamespace(id=1, is_superuser=False)
upload_file = SimpleNamespace(file=io.BytesIO(b"avatar"), filename="avatar.png")
monkeypatch.setattr(user_endpoint, "User", FakeUserModel)
response = asyncio.run(
user_endpoint.upload_avatar(
user_id=1,
db=object(),
file=upload_file,
current_user=current_user,
)
)
assert response.success is True
assert response.data == {"filename": "avatar.png"}
assert response.message is None
assert response.message_i18n is None
assert fake_user.values == {"avatar": "data:image/ico;base64,b'YXZhdGFy'"}
+1 -1
View File
@@ -23,7 +23,7 @@ def test_modified_builtin_skills_have_incremented_versions() -> None:
"""本次修改过的内置技能必须递增版本,确保用户端同步更新。""" """本次修改过的内置技能必须递增版本,确保用户端同步更新。"""
expected_versions = { expected_versions = {
"database-operation": "3", "database-operation": "3",
"moviepilot-api": "8", "moviepilot-api": "9",
"moviepilot-cli": "6", "moviepilot-cli": "6",
"moviepilot-update": "3", "moviepilot-update": "3",
"transfer-failed-retry": "2", "transfer-failed-retry": "2",