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

View File

@@ -119,7 +119,7 @@ async def upload_avatar(
if not user:
return schemas.Response(success=False, message="用户不存在")
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)

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` 会回退为原文本。
`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`

View File

@@ -1,6 +1,6 @@
---
name: moviepilot-api
version: 8
version: 9
description: >-
Use this skill when you need to call MoviePilot REST API endpoints directly
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 |
| DELETE | `/api/v1/user/id/{user_id}` | Delete user by ID |
| 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 |
| POST | `/api/v1/user/config/{key}` | Update user config |

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.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'"}

View File

@@ -23,7 +23,7 @@ def test_modified_builtin_skills_have_incremented_versions() -> None:
"""本次修改过的内置技能必须递增版本,确保用户端同步更新。"""
expected_versions = {
"database-operation": "3",
"moviepilot-api": "8",
"moviepilot-api": "9",
"moviepilot-cli": "6",
"moviepilot-update": "3",
"transfer-failed-retry": "2",