add showcase manage

This commit is contained in:
2026-05-01 08:24:30 -06:00
parent 17948a69f3
commit 99ec8cdf02
3 changed files with 432 additions and 4 deletions

View File

@@ -17,16 +17,23 @@ from django.db.models import (
Q,
Subquery,
)
from account.decorators import admin_required
from prompt.models import Conversation, Message
from .schemas import (
AwardItemIn,
AwardItemManageOut,
AwardItemUpdateIn,
AwardManageIn,
AwardManageOut,
FlagIn,
FlagStats,
AwardOut,
PromptRoundOut,
ShowcaseDetailOut,
ShowcaseItemOut,
ShowcaseSubmissionLookupOut,
SubmissionCountBucket,
SubmissionFilter,
SubmissionIn,
@@ -45,6 +52,67 @@ from account.models import RoleChoices, User
router = Router()
def _validate_item_ordering(value: str):
if value not in ItemOrdering.values:
raise HttpError(400, "无效的作品排序方式")
def _award_manage_out(award: Award):
return {
"id": award.id,
"name": award.name,
"description": award.description,
"sort_order": award.sort_order,
"is_active": award.is_active,
"item_ordering": award.item_ordering,
"item_count": getattr(award, "item_count", None)
if getattr(award, "item_count", None) is not None
else award.submission_awards.count(),
}
def _award_item_ordering(award: Award):
ordering_map = {
ItemOrdering.MANUAL: ("sort_order", "id"),
ItemOrdering.AWARDED_AT: ("-awarded_at", "sort_order", "id"),
ItemOrdering.SCORE: ("-submission__score", "sort_order", "id"),
ItemOrdering.VIEW_COUNT: ("-submission__view_count", "sort_order", "id"),
}
return ordering_map.get(award.item_ordering, ("sort_order", "id"))
def _award_item_manage_out(item: SubmissionAward):
has_prompt_chain = getattr(item, "has_prompt_chain", None)
if has_prompt_chain is None:
has_prompt_chain = Message.objects.filter(
submission_id=item.submission_id
).exists()
return {
"id": item.id,
"submission_id": item.submission_id,
"username": item.submission.user.username,
"task_title": item.submission.task.title,
"task_display": item.submission.task.display,
"score": item.submission.score,
"view_count": item.submission.view_count,
"sort_order": item.sort_order,
"awarded_at": item.awarded_at,
"has_prompt_chain": has_prompt_chain,
}
def _showcase_submission_lookup_out(submission: Submission):
return {
"submission_id": submission.id,
"username": submission.user.username,
"task_title": submission.task.title,
"task_display": submission.task.display,
"score": submission.score,
"view_count": submission.view_count,
"has_prompt_chain": Message.objects.filter(submission=submission).exists(),
}
@router.post("/")
@login_required
def create_submission(request, payload: SubmissionIn):
@@ -457,10 +525,141 @@ def list_showcase(request):
return result
@router.get("/showcase/manage/awards", response=List[AwardManageOut])
@admin_required
def list_manage_awards(request):
awards = Award.objects.annotate(
item_count=Count("submission_awards")
).order_by("sort_order", "id")
return [_award_manage_out(award) for award in awards]
@router.post("/showcase/manage/awards", response=AwardManageOut)
@admin_required
def create_manage_award(request, payload: AwardManageIn):
_validate_item_ordering(payload.item_ordering)
award = Award.objects.create(**payload.dict())
award.item_count = 0
return _award_manage_out(award)
@router.put("/showcase/manage/awards/{award_id}", response=AwardManageOut)
@admin_required
def update_manage_award(request, award_id: int, payload: AwardManageIn):
_validate_item_ordering(payload.item_ordering)
award = get_object_or_404(Award, id=award_id)
award.name = payload.name
award.description = payload.description
award.sort_order = payload.sort_order
award.is_active = payload.is_active
award.item_ordering = payload.item_ordering
award.save(
update_fields=[
"name",
"description",
"sort_order",
"is_active",
"item_ordering",
]
)
award.item_count = award.submission_awards.count()
return _award_manage_out(award)
@router.delete("/showcase/manage/awards/{award_id}")
@admin_required
def delete_manage_award(request, award_id: int):
award = get_object_or_404(Award, id=award_id)
award.delete()
return {"message": "删除成功"}
@router.get(
"/showcase/manage/submissions/{submission_id}",
response=ShowcaseSubmissionLookupOut,
)
@admin_required
def get_manage_submission(request, submission_id: UUID):
submission = get_object_or_404(
Submission.objects.select_related("user", "task"),
id=submission_id,
)
return _showcase_submission_lookup_out(submission)
@router.get(
"/showcase/manage/awards/{award_id}/items",
response=List[AwardItemManageOut],
)
@admin_required
def list_manage_award_items(request, award_id: int):
award = get_object_or_404(Award, id=award_id)
items = (
SubmissionAward.objects.filter(award=award)
.select_related("submission", "submission__user", "submission__task")
.annotate(
has_prompt_chain=Exists(
Message.objects.filter(submission_id=OuterRef("submission_id"))
)
)
.order_by(*_award_item_ordering(award))
)
return [_award_item_manage_out(item) for item in items]
@router.post(
"/showcase/manage/awards/{award_id}/items",
response=AwardItemManageOut,
)
@admin_required
def create_manage_award_item(request, award_id: int, payload: AwardItemIn):
award = get_object_or_404(Award, id=award_id)
submission = get_object_or_404(
Submission.objects.select_related("user", "task"),
id=payload.submission_id,
)
item, created = SubmissionAward.objects.get_or_create(
award=award,
submission=submission,
defaults={"sort_order": payload.sort_order},
)
if not created:
raise HttpError(400, "该作品已在奖项中")
item.submission = submission
return _award_item_manage_out(item)
@router.put("/showcase/manage/items/{item_id}", response=AwardItemManageOut)
@admin_required
def update_manage_award_item(request, item_id: int, payload: AwardItemUpdateIn):
item = get_object_or_404(
SubmissionAward.objects.select_related(
"submission",
"submission__user",
"submission__task",
),
id=item_id,
)
item.sort_order = payload.sort_order
item.save(update_fields=["sort_order"])
return _award_item_manage_out(item)
@router.delete("/showcase/manage/items/{item_id}")
@admin_required
def delete_manage_award_item(request, item_id: int):
item = get_object_or_404(SubmissionAward, id=item_id)
item.delete()
return {"message": "删除成功"}
@router.get("/showcase/{submission_id}/", response=ShowcaseDetailOut)
@login_required
def get_showcase_detail(request, submission_id: UUID):
if not SubmissionAward.objects.filter(submission_id=submission_id).exists():
if not SubmissionAward.objects.filter(
submission_id=submission_id,
award__is_active=True,
).exists():
raise HttpError(404, "作品不存在或未授奖")
sub = get_object_or_404(
@@ -470,6 +669,7 @@ def get_showcase_detail(request, submission_id: UUID):
has_chain = Message.objects.filter(submission=sub).exists()
award_names = list(
SubmissionAward.objects.filter(submission=sub)
.filter(award__is_active=True)
.select_related("award")
.values_list("award__name", flat=True)
)
@@ -529,7 +729,10 @@ def _build_prompt_rounds(source_msg: Message):
@router.get("/showcase/{submission_id}/prompt-chain/", response=List[PromptRoundOut])
@login_required
def get_showcase_prompt_chain(request, submission_id: UUID):
if not SubmissionAward.objects.filter(submission_id=submission_id).exists():
if not SubmissionAward.objects.filter(
submission_id=submission_id,
award__is_active=True,
).exists():
raise HttpError(404, "作品不存在或未授奖")
sub = get_object_or_404(Submission, id=submission_id)
@@ -624,4 +827,3 @@ def update_flag(request, submission_id: UUID, payload: FlagIn):
submission.flag = payload.flag
submission.save(update_fields=["flag"])
return {"flag": submission.flag}