From 7c8b973f301b3ed387a0c3bd2b4b54a59de161c6 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Mon, 25 May 2026 11:04:05 +0800 Subject: [PATCH] fix: exclude derived subscribe completion field --- app/api/endpoints/subscribe.py | 2 ++ tests/test_subscribe_endpoint.py | 44 ++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 tests/test_subscribe_endpoint.py diff --git a/app/api/endpoints/subscribe.py b/app/api/endpoints/subscribe.py index 8365d4c9..0929db77 100644 --- a/app/api/endpoints/subscribe.py +++ b/app/api/endpoints/subscribe.py @@ -92,6 +92,8 @@ async def create_subscribe( subscribe_dict = subscribe_in.model_dump() if subscribe_in.id: subscribe_dict.pop("id", None) + # completed_episode 是响应派生字段,禁止写入持久层 + subscribe_dict.pop("completed_episode", None) sid, message = await SubscribeChain().async_add( mtype=mtype, title=title, exist_ok=True, **subscribe_dict ) diff --git a/tests/test_subscribe_endpoint.py b/tests/test_subscribe_endpoint.py new file mode 100644 index 00000000..8190a041 --- /dev/null +++ b/tests/test_subscribe_endpoint.py @@ -0,0 +1,44 @@ +import asyncio +from types import SimpleNamespace +from unittest import TestCase +from unittest.mock import AsyncMock, patch + +from app.api.endpoints.subscribe import create_subscribe +from app.schemas.subscribe import Subscribe +from app.schemas.types import MediaType + + +class SubscribeEndpointTest(TestCase): + """ + 订阅接口回归测试。 + """ + + def test_create_subscribe_excludes_completed_episode_from_write_payload(self): + """ + 新增订阅时不应把 completed_episode 派生字段传入持久化链路。 + """ + subscribe_in = Subscribe( + name="测试剧集", + year="2026", + type=MediaType.TV.value, + season=1, + total_episode=10, + lack_episode=3, + ) + + self.assertEqual(subscribe_in.completed_episode, 7) + + with patch( + "app.api.endpoints.subscribe.SubscribeChain.async_add", + new=AsyncMock(return_value=(1, "新增订阅成功")), + ) as async_add: + response = asyncio.run( + create_subscribe( + subscribe_in=subscribe_in, + current_user=SimpleNamespace(name="moviepilot-user"), + ) + ) + + self.assertTrue(response.success) + self.assertNotIn("completed_episode", async_add.await_args.kwargs) + self.assertEqual(async_add.await_args.kwargs["username"], "moviepilot-user")