107 lines
3.6 KiB
Python
107 lines
3.6 KiB
Python
from django.shortcuts import get_object_or_404
|
|
from rest_framework import permissions, status, viewsets
|
|
from rest_framework.response import Response
|
|
from rest_framework.views import APIView
|
|
|
|
from .models import LatexAttempt, LatexCourse, LatexExercise
|
|
from .serializers import FormulaDocumentSerializer
|
|
|
|
|
|
class FormulaDocumentViewSet(viewsets.ModelViewSet):
|
|
serializer_class = FormulaDocumentSerializer
|
|
|
|
def get_queryset(self):
|
|
return self.request.user.formulas.all()
|
|
|
|
|
|
class CourseListView(APIView):
|
|
permission_classes = [permissions.AllowAny]
|
|
|
|
def get(self, request):
|
|
courses = LatexCourse.objects.filter(is_published=True).prefetch_related(
|
|
"lessons__exercises"
|
|
)
|
|
return Response(
|
|
[
|
|
{
|
|
"slug": course.slug,
|
|
"title": course.title,
|
|
"description": course.description,
|
|
"lessons": [
|
|
{
|
|
"slug": lesson.slug,
|
|
"title": lesson.title,
|
|
"content": lesson.content,
|
|
"example_source": lesson.example_source,
|
|
"exercise_count": lesson.exercises.count(),
|
|
}
|
|
for lesson in course.lessons.all()
|
|
],
|
|
}
|
|
for course in courses
|
|
]
|
|
)
|
|
|
|
|
|
class ExerciseSubmitView(APIView):
|
|
@staticmethod
|
|
def normalize(source):
|
|
source = source or ""
|
|
text_commands = (r"\text", r"\mbox", r"\textrm", r"\textsf", r"\texttt")
|
|
normalized = []
|
|
index = 0
|
|
while index < len(source):
|
|
command = next(
|
|
(item for item in text_commands if source.startswith(item, index)),
|
|
None,
|
|
)
|
|
if command is None:
|
|
if not source[index].isspace():
|
|
normalized.append(source[index])
|
|
index += 1
|
|
continue
|
|
|
|
command_end = index + len(command)
|
|
group_start = command_end
|
|
while group_start < len(source) and source[group_start].isspace():
|
|
group_start += 1
|
|
if group_start >= len(source) or source[group_start] != "{":
|
|
normalized.append(command)
|
|
index = command_end
|
|
continue
|
|
|
|
depth = 0
|
|
group_end = group_start
|
|
while group_end < len(source):
|
|
if source[group_end] == "{":
|
|
depth += 1
|
|
elif source[group_end] == "}":
|
|
depth -= 1
|
|
if depth == 0:
|
|
group_end += 1
|
|
break
|
|
group_end += 1
|
|
normalized.append(command)
|
|
normalized.append(source[group_start:group_end])
|
|
index = group_end
|
|
return "".join(normalized)
|
|
|
|
def post(self, request, exercise_id):
|
|
exercise = get_object_or_404(LatexExercise, id=exercise_id)
|
|
submitted = str(request.data.get("source", ""))[:50_000]
|
|
is_correct = self.normalize(submitted) == self.normalize(exercise.expected_source)
|
|
LatexAttempt.objects.create(
|
|
user=request.user,
|
|
exercise=exercise,
|
|
submitted_source=submitted,
|
|
is_correct=is_correct,
|
|
)
|
|
return Response(
|
|
{
|
|
"is_correct": is_correct,
|
|
"expected_source": exercise.expected_source if not is_correct else None,
|
|
"explanation": exercise.explanation,
|
|
},
|
|
status=status.HTTP_201_CREATED,
|
|
)
|