@@ -0,0 +1,106 @@
|
||||
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,
|
||||
)
|
||||
Reference in New Issue
Block a user