diff --git a/anatomy/templates/anatomy/partials/exam_edit_fragment.html b/anatomy/templates/anatomy/partials/exam_edit_fragment.html new file mode 100644 index 00000000..5f1e4435 --- /dev/null +++ b/anatomy/templates/anatomy/partials/exam_edit_fragment.html @@ -0,0 +1,23 @@ +{% load static %} +
+
+ {% csrf_token %} +
+ {{ form.exam }} + + +
+
+
Current exams: + {% for exam in question.exams.all %} +
+ {% csrf_token %} + + + +
+ {% empty %} + No exams + {% endfor %} +
+
diff --git a/anatomy/views.py b/anatomy/views.py index 436f6051..eec8d58d 100644 --- a/anatomy/views.py +++ b/anatomy/views.py @@ -59,6 +59,21 @@ from .models import ( # HalfMarkAnswers, # IncorrectAnswers, ) +from generic.widgets import ExamSearchWidget + + +class AddExamForm(forms.Form): + exam = forms.ModelChoiceField(queryset=Exam.objects.none(), required=True, widget=ExamSearchWidget(exam_model=Exam), label="Exam to add") + + def __init__(self, *args, user=None, **kwargs): + super().__init__(*args, **kwargs) + if user is None: + qs = Exam.objects.none() + elif user.groups.filter(name="anatomy_checker").exists(): + qs = Exam.objects.all() + else: + qs = Exam.objects.filter(author__id=user.id) | Exam.objects.filter(open_access=True) + self.fields["exam"].queryset = qs.distinct() from generic.models import CidUser, Examination from generic.views import AuthorRequiredMixin, ExamCloneMixin, ExamCreateBase, ExamDeleteBase, ExamGroupsUpdateBase, ExamUpdateBase, ExamViews, GenericViewBase, UpdateQuestionMixin from reversion.views import RevisionMixin @@ -1627,44 +1642,39 @@ def question_add_exam(request, question_id: int): return HttpResponse("Invalid permissions", status=403) - if request.POST: + # POST: handle add/remove; if exam_id provided use existing behaviour + if request.method == "POST": exam_id = request.POST.get("exam_id", None) - if exam_id is None: - return HttpResponse("No exam id provided", status=400) + if exam_id: + exam = get_object_or_404(Exam, pk=exam_id) + if request.POST.get("remove", False) == "true": + question.exams.remove(exam) + else: + question.exams.add(exam) - exam = get_object_or_404(Exam, pk=exam_id) + # return updated fragment + form = AddExamForm(user=request.user) + return render(request, "anatomy/partials/exam_edit_fragment.html", {"form": form, "question": question}) - if request.POST.get("remove", False) == "true": - question.exams.remove(exam) - return HttpResponse("Question removed from exam.") + # else try to process from the search form + form = AddExamForm(request.POST, user=request.user) + if form.is_valid(): + exam = form.cleaned_data.get("exam") + if request.POST.get("remove", False) == "true": + question.exams.remove(exam) + else: + question.exams.add(exam) + + form = AddExamForm(user=request.user) + return render(request, "anatomy/partials/exam_edit_fragment.html", {"form": form, "question": question}) else: - question.exams.add(exam) + # render form with errors + return render(request, "anatomy/partials/exam_edit_fragment.html", {"form": form, "question": question}) - return HttpResponse("Question added to exam.") - else: - # Return a list of exams that we can add to the question - - exams = Exam.objects.filter(author=request.user) - exams = exams.difference(question.exams.all()) - - if not exams: - return HttpResponse("No exams available to add") - - html = "Exams to add to question:
" - for exam in exams: - html = html + (f"
" - ) - html = html + "
Exams to remove from question:
" - for exam in question.exams.all(): - html = html + (f"
" - ) - html = html + "" - - return HttpResponse(mark_safe(html)) + # GET: render the fragment with the add form and current exams + form = AddExamForm(user=request.user) + return render(request, "anatomy/partials/exam_edit_fragment.html", {"form": form, "question": question}) raise PermissionDenied()