130 lines
4.2 KiB
Python
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)
|