Implement edit answer functionality with HTMX support; add new endpoint and template for editing stored answers in the marking UI.
This commit is contained in:
+86
-1
@@ -818,6 +818,24 @@ def mark2_toggle_answer(request):
|
||||
"incorrect": Answer.MarkOptions.INCORRECT,
|
||||
}
|
||||
|
||||
# Support clearing a stored answer (delete) via 'clear'
|
||||
exam_pk = request.POST.get('exam_pk')
|
||||
sk = request.POST.get('sk')
|
||||
|
||||
if newmark == 'clear':
|
||||
a = Answer.objects.filter(answer_compare__iexact=answer_text, question_id=question.pk).first()
|
||||
if a is not None:
|
||||
# permission: ensure user can edit this answer
|
||||
if not a.can_edit(request.user):
|
||||
return JsonResponse({"status": "error", "message": "forbidden"}, status=403)
|
||||
a.delete()
|
||||
if request.htmx and exam_pk and sk is not None:
|
||||
try:
|
||||
return mark2_exam_marked(request, int(exam_pk), int(sk))
|
||||
except Exception:
|
||||
return JsonResponse({"status": "ok"})
|
||||
return JsonResponse({"status": "ok"})
|
||||
|
||||
if newmark not in mark_map:
|
||||
return JsonResponse({"status": "error", "message": "invalid mark"}, status=400)
|
||||
|
||||
@@ -833,6 +851,12 @@ def mark2_toggle_answer(request):
|
||||
a.status = status_val
|
||||
a.save()
|
||||
|
||||
if request.htmx and exam_pk and sk is not None:
|
||||
try:
|
||||
return mark2_exam_marked(request, int(exam_pk), int(sk))
|
||||
except Exception:
|
||||
return JsonResponse({"status": "ok"})
|
||||
|
||||
return JsonResponse({"status": "ok"})
|
||||
|
||||
|
||||
@@ -879,10 +903,71 @@ def mark2_exam_marked(request, exam_pk, sk):
|
||||
else:
|
||||
items.sort(key=lambda x: x.get('count', 0), reverse=True)
|
||||
|
||||
context = {'exam': exam, 'question': question, 'items': items}
|
||||
context = {'exam': exam, 'question': question, 'items': items, 'sk': sk}
|
||||
return render(request, 'anatomy/partials/mark2_exam_marked_fragment.html', context)
|
||||
|
||||
|
||||
@login_required
|
||||
def mark2_edit_answer(request):
|
||||
"""HTMX-friendly endpoint to edit/create a stored Answer for a question.
|
||||
|
||||
GET: returns a small form fragment.
|
||||
POST: updates/creates the Answer and, if exam_pk/sk provided, returns the
|
||||
refreshed exam-marked fragment so the UI updates in-place.
|
||||
"""
|
||||
if request.method == 'GET' and request.htmx:
|
||||
question_pk = request.GET.get('question_pk')
|
||||
original = request.GET.get('original', '')
|
||||
exam_pk = request.GET.get('exam_pk')
|
||||
sk = request.GET.get('sk')
|
||||
question = get_object_or_404(AnatomyQuestion, pk=question_pk)
|
||||
# Try to find an existing Answer by compare
|
||||
existing = question.answers.filter(answer_compare__iexact=original).first()
|
||||
context = {
|
||||
'question': question,
|
||||
'original': original,
|
||||
'existing': existing,
|
||||
'exam_pk': exam_pk,
|
||||
'sk': sk,
|
||||
}
|
||||
return render(request, 'anatomy/partials/mark2_edit_answer_fragment.html', context)
|
||||
|
||||
if request.method == 'POST' and request.htmx:
|
||||
question_pk = request.POST.get('question_pk')
|
||||
original = request.POST.get('original', '')
|
||||
new_text = request.POST.get('new_answer', '').strip()
|
||||
exam_pk = request.POST.get('exam_pk')
|
||||
sk = request.POST.get('sk')
|
||||
|
||||
if not question_pk or not new_text:
|
||||
return HttpResponse('Missing parameters', status=400)
|
||||
|
||||
question = get_object_or_404(AnatomyQuestion, pk=question_pk)
|
||||
|
||||
a = question.answers.filter(answer_compare__iexact=original).first()
|
||||
if a is None:
|
||||
a = Answer()
|
||||
a.question = question
|
||||
a.answer = new_text
|
||||
else:
|
||||
a.answer = new_text
|
||||
|
||||
a.save()
|
||||
|
||||
# If we have exam context, refresh the exam-marked fragment for that question
|
||||
if exam_pk and sk is not None:
|
||||
# delegate to mark2_exam_marked to re-render the card
|
||||
try:
|
||||
return mark2_exam_marked(request, int(exam_pk), int(sk))
|
||||
except Exception:
|
||||
return HttpResponse('OK')
|
||||
|
||||
return HttpResponse('OK')
|
||||
|
||||
# Fallback: forbidden for non-HTMX or other methods
|
||||
raise PermissionDenied()
|
||||
|
||||
|
||||
@login_required
|
||||
def mark2_question_marked(request, pk):
|
||||
"""Return a partial listing of all stored Answer choices for this question (grouped by status)."""
|
||||
|
||||
Reference in New Issue
Block a user