fix(assets): 手动送审如实回报,送不出去返回 503 而非空态
submit_asset_for_review 改为返回 bool(是否真进入审核);submit-review 端点据此: 当审核服务未启用/未配 SDK/火山未回 Id/调用异常导致没真正送出去,且素材非终态时, 返回 503「审核服务暂不可用」而不是空 review_status —— 否则前端会把「没送出去」 误显示成「审核中」,刷新就打回灰盾(待审核)。新增 503/200 两条回归测试。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -59,26 +59,30 @@ def get_or_create_team_group(team) -> AssetReviewGroup:
|
|||||||
return grp
|
return grp
|
||||||
|
|
||||||
|
|
||||||
def submit_asset_for_review(asset: Asset) -> None:
|
def submit_asset_for_review(asset: Asset) -> bool:
|
||||||
"""真人资产静默送审:建组(若无)→ 传素材 → 标 processing。出错只记日志,不抛。"""
|
"""真人资产送审:建组(若无)→ 传素材 → 标 processing。出错只记日志,不抛。
|
||||||
|
返回是否真正进入审核(True=已标 processing;False=未送审/未配置/失败),
|
||||||
|
供手动兜底端点据此如实回报,避免前端把「没送出去」误显示成「审核中」。"""
|
||||||
if not assets_client.is_enabled() or asset.category not in Asset.REVIEW_CATEGORIES:
|
if not assets_client.is_enabled() or asset.category not in Asset.REVIEW_CATEGORIES:
|
||||||
return
|
return False
|
||||||
url = _asset_url(asset)
|
url = _asset_url(asset)
|
||||||
if not url:
|
if not url:
|
||||||
return
|
return False
|
||||||
try:
|
try:
|
||||||
grp = get_or_create_team_group(asset.team)
|
grp = get_or_create_team_group(asset.team)
|
||||||
remote_id = assets_client.create_asset(group_id=grp.remote_group_id, image_url=url, name=(asset.name or "person")[:64])
|
remote_id = assets_client.create_asset(group_id=grp.remote_group_id, image_url=url, name=(asset.name or "person")[:64])
|
||||||
if not remote_id:
|
if not remote_id:
|
||||||
# 火山没回 Id:不要标 processing(否则 remote_id 为空、poll 永远早退、卡死黄),留空可重试
|
# 火山没回 Id:不要标 processing(否则 remote_id 为空、poll 永远早退、卡死黄),留空可重试
|
||||||
logger.warning("create_asset 返回空 id,asset %s 暂不送审(可重试)", asset.id)
|
logger.warning("create_asset 返回空 id,asset %s 暂不送审(可重试)", asset.id)
|
||||||
return
|
return False
|
||||||
asset.review_remote_id = remote_id
|
asset.review_remote_id = remote_id
|
||||||
asset.review_status = "processing"
|
asset.review_status = "processing"
|
||||||
asset.review_error = ""
|
asset.review_error = ""
|
||||||
asset.save(update_fields=["review_remote_id", "review_status", "review_error", "updated_at"])
|
asset.save(update_fields=["review_remote_id", "review_status", "review_error", "updated_at"])
|
||||||
|
return True
|
||||||
except Exception as exc: # noqa: BLE001
|
except Exception as exc: # noqa: BLE001
|
||||||
logger.warning("submit_asset_for_review failed for asset %s: %s", asset.id, exc)
|
logger.warning("submit_asset_for_review failed for asset %s: %s", asset.id, exc)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def poll_asset_review(asset: Asset) -> str:
|
def poll_asset_review(asset: Asset) -> str:
|
||||||
|
|||||||
@@ -162,6 +162,27 @@ class SubmitReviewTests(TestCase):
|
|||||||
res = self.client.post(f"/api/assets/{self.product.id}/submit-review/")
|
res = self.client.post(f"/api/assets/{self.product.id}/submit-review/")
|
||||||
self.assertEqual(res.status_code, 400)
|
self.assertEqual(res.status_code, 400)
|
||||||
|
|
||||||
|
def test_submit_review_503_when_submission_did_not_start(self):
|
||||||
|
"""送审没真正发出去(服务未启用/未配 SDK/火山未回 Id),且素材非终态 → 503,
|
||||||
|
review_status 仍为空。这样前端不会把「没送出去」误显示成「审核中」(刷新即打回原形)。"""
|
||||||
|
with patch("apps.assets.review.submit_asset_for_review", return_value=False) as sub:
|
||||||
|
res = self.client.post(f"/api/assets/{self.person.id}/submit-review/")
|
||||||
|
sub.assert_called_once()
|
||||||
|
self.assertEqual(res.status_code, 503)
|
||||||
|
self.assertEqual(res.json().get("review_status"), "")
|
||||||
|
|
||||||
|
def test_submit_review_200_when_started(self):
|
||||||
|
"""真正进入审核(processing)→ 200 + 真态,供前端落 processing。"""
|
||||||
|
def _mark_processing(asset):
|
||||||
|
asset.review_status = "processing"
|
||||||
|
asset.save(update_fields=["review_status"])
|
||||||
|
return True
|
||||||
|
|
||||||
|
with patch("apps.assets.review.submit_asset_for_review", side_effect=_mark_processing):
|
||||||
|
res = self.client.post(f"/api/assets/{self.person.id}/submit-review/")
|
||||||
|
self.assertEqual(res.status_code, 200)
|
||||||
|
self.assertEqual(res.json().get("review_status"), "processing")
|
||||||
|
|
||||||
|
|
||||||
class ReviewScopeTests(TestCase):
|
class ReviewScopeTests(TestCase):
|
||||||
"""送审范围 = 角色定妆照(person)/ 三视图(tri_view)/ 分镜图(storyboard);图片趴不送审。"""
|
"""送审范围 = 角色定妆照(person)/ 三视图(tri_view)/ 分镜图(storyboard);图片趴不送审。"""
|
||||||
|
|||||||
@@ -125,8 +125,15 @@ class AssetViewSet(TeamScopedViewSetMixin, ModelViewSet):
|
|||||||
asset = self.get_object() # team-scoped + is_deleted 过滤
|
asset = self.get_object() # team-scoped + is_deleted 过滤
|
||||||
if asset.category not in Asset.REVIEW_CATEGORIES:
|
if asset.category not in Asset.REVIEW_CATEGORIES:
|
||||||
return Response({"detail": "该素材无需审核"}, status=status.HTTP_400_BAD_REQUEST)
|
return Response({"detail": "该素材无需审核"}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
submit_asset_for_review(asset)
|
started = submit_asset_for_review(asset)
|
||||||
asset.refresh_from_db()
|
asset.refresh_from_db()
|
||||||
|
# 没真正送出去(审核服务未启用/未配置 SDK/火山未回 Id/调用异常),且素材也不是已终态:
|
||||||
|
# 如实回报 503,别返回空 review_status —— 否则前端会把「没送出去」误显示成「审核中」,刷新就打回原形。
|
||||||
|
if not started and asset.review_status not in ("processing", "active", "failed"):
|
||||||
|
return Response(
|
||||||
|
{"detail": "审核服务暂不可用,请稍后重试", "review_status": asset.review_status or ""},
|
||||||
|
status=status.HTTP_503_SERVICE_UNAVAILABLE,
|
||||||
|
)
|
||||||
return Response({"review_status": asset.review_status, "review_error": asset.review_error or ""})
|
return Response({"review_status": asset.review_status, "review_error": asset.review_error or ""})
|
||||||
|
|
||||||
@action(detail=False, methods=["get"], url_path="video-packs")
|
@action(detail=False, methods=["get"], url_path="video-packs")
|
||||||
|
|||||||
Reference in New Issue
Block a user