Files
Jacky 1f98f7152d
CI / test (push) Failing after 1m31s
v0.2 Preview: Construction Plan.
2026-08-08 21:25:27 +08:00

130 lines
4.2 KiB
Python

from copy import deepcopy
from django.shortcuts import get_object_or_404
from rest_framework import permissions, status
from rest_framework.response import Response
from rest_framework.views import APIView
from progression.services import initialize_math_identity
from .models import (
MathBTIAssessment,
MathBTIResult,
MathIdentity,
Story,
StoryRun,
)
from .services import get_run_payload, make_choice, score_mathbti, start_story
class MathBTIAssessmentView(APIView):
permission_classes = [permissions.AllowAny]
def get(self, request):
assessment = (
MathBTIAssessment.objects.filter(is_published=True).order_by("-published_at").first()
)
if assessment is None:
return Response(
{"error": {"code": "not_published", "message": "MathBTI 尚未发布"}},
status=status.HTTP_404_NOT_FOUND,
)
definition = deepcopy(assessment.definition)
for question in definition.get("questions", []):
for option in question.get("options", []):
option.pop("score", None)
definition.pop("results", None)
return Response({"version": assessment.version, "definition": definition})
class MathBTISubmitView(APIView):
permission_classes = [permissions.AllowAny]
def post(self, request):
assessment = get_object_or_404(
MathBTIAssessment,
version=request.data.get("version"),
is_published=True,
)
identity_code, axis_scores = score_mathbti(
assessment.definition,
request.data.get("answers", []),
)
identity = get_object_or_404(MathIdentity, code=identity_code)
if request.user.is_authenticated:
result = MathBTIResult.objects.create(
user=request.user,
assessment=assessment,
identity=identity,
answers=request.data.get("answers", []),
axis_scores=axis_scores,
)
initialize_math_identity(request.user, identity)
result_id = result.id
else:
result_id = None
return Response(
{
"id": result_id,
"identity": {
"code": identity.code,
"name": identity.name,
"clan": identity.clan,
"mathematician": identity.mathematician,
"description": identity.description,
"portrait": identity.portrait,
"initial_abilities": identity.initial_abilities,
},
"axis_scores": axis_scores,
},
status=status.HTTP_201_CREATED,
)
class StoryListView(APIView):
permission_classes = [permissions.AllowAny]
def get(self, request):
stories = Story.objects.filter(is_visible=True).order_by("kind", "title")
return Response(
[
{
"slug": story.slug,
"title": story.title,
"summary": story.summary,
"kind": story.kind,
"estimated_minutes": story.estimated_minutes,
"available": story.versions.filter(is_published=True).exists(),
}
for story in stories
]
)
class StoryStartView(APIView):
def post(self, request, slug):
story = get_object_or_404(Story, slug=slug, is_visible=True)
return Response(start_story(request.user, story), status=status.HTTP_201_CREATED)
class StoryRunView(APIView):
def get(self, request, run_id):
run = get_object_or_404(
StoryRun.objects.select_related("story_version__story"),
id=run_id,
user=request.user,
)
return Response(get_run_payload(run))
class StoryChoiceView(APIView):
def post(self, request, run_id):
get_object_or_404(StoryRun, id=run_id, user=request.user)
payload = make_choice(
run_id=run_id,
user=request.user,
choice_index=request.data.get("choice_index"),
idempotency_key=request.headers.get("Idempotency-Key"),
)
return Response(payload)