diff --git a/generic/forms.py b/generic/forms.py index 3804798d..81056838 100755 --- a/generic/forms.py +++ b/generic/forms.py @@ -11,6 +11,7 @@ from django.forms import ( DateField, SplitDateTimeField, SplitDateTimeWidget, + Select, ) from django.forms import inlineformset_factory from atlas.models import CaseCollection @@ -26,6 +27,7 @@ from generic.models import ( UserGrades, UserProfile, UserUserGroup, + QuestionReview ) from django.contrib.admin.widgets import FilteredSelectMultiple @@ -831,4 +833,18 @@ class UsersAutocompleteForm(Form): )) -autocomplete_register(UserAutocomplete) \ No newline at end of file +autocomplete_register(UserAutocomplete) + +class QuestionReviewForm(ModelForm): + class Meta: + model = QuestionReview + fields = ["status", "comment"] + widgets = { + "status": Select(attrs={"class": "form-select form-select-sm"}), + "comment": TextInput(attrs={"class": "form-control form-control-sm", "placeholder": "Comment (optional)"}), + } + + def __init__(self, *args, **kwargs): + # Accept an optional `user` for future validation/use + self.user = kwargs.pop("user", None) + super().__init__(*args, **kwargs) \ No newline at end of file diff --git a/generic/templates/generic/partials/question_review_form.html b/generic/templates/generic/partials/question_review_form.html index a362f02b..879c95e1 100644 --- a/generic/templates/generic/partials/question_review_form.html +++ b/generic/templates/generic/partials/question_review_form.html @@ -4,15 +4,13 @@ hx-swap="innerHTML" class="d-flex gap-2 align-items-start"> {% csrf_token %} +
- + {{ form.status }}
- + + {{ form.comment }} +
diff --git a/generic/views.py b/generic/views.py index 07978ddf..95746ae7 100644 --- a/generic/views.py +++ b/generic/views.py @@ -2956,6 +2956,7 @@ class GenericViewBase: """ from django.contrib.contenttypes.models import ContentType from generic.models import QuestionReview + from .forms import QuestionReviewForm logger.debug("question_set_review called") @@ -2971,23 +2972,31 @@ class GenericViewBase: # form is blank for creating a fresh review. if request.method == "GET" and request.GET.get("edit"): if request.GET.get("new"): - return render(request, "generic/partials/question_review_form.html", {"question": question, "latest": None, "app_name": self.app_name}) - return render(request, "generic/partials/question_review_form.html", {"question": question, "latest": latest, "app_name": self.app_name}) + form = QuestionReviewForm() + return render(request, "generic/partials/question_review_form.html", {"question": question, "latest": None, "form": form, "app_name": self.app_name}) + # Prefill the form with the latest review values (but we'll create a new review on POST) + if latest: + form = QuestionReviewForm(initial={"status": latest.status, "comment": latest.comment}) + else: + form = QuestionReviewForm() + return render(request, "generic/partials/question_review_form.html", {"question": question, "latest": latest, "form": form, "app_name": self.app_name}) if request.method == "POST": # Require login to post a review if not request.user.is_authenticated: return HttpResponse(status=403) - status = request.POST.get("status") - comment = request.POST.get("comment", "") + form = QuestionReviewForm(request.POST, user=request.user) + if not form.is_valid(): + # Render the form back with errors + return render(request, "generic/partials/question_review_form.html", {"question": question, "latest": latest, "form": form, "app_name": self.app_name}) review = QuestionReview.objects.create( content_type=ct, object_id=question.pk, author=request.user, - status=status, - comment=comment, + status=form.cleaned_data["status"], + comment=form.cleaned_data.get("comment", ""), ) return render(request, "generic/partials/question_review_block.html", {"review": review, "question": question, "app_name": self.app_name}) @@ -2996,7 +3005,12 @@ class GenericViewBase: if latest: return render(request, "generic/partials/question_review_block.html", {"review": latest, "question": question, "app_name": self.app_name}) else: - return render(request, "generic/partials/question_review_form.html", {"question": question, "latest": latest, "app_name": self.app_name}) + # Ensure a form is available for the template + if latest: + form = QuestionReviewForm(initial={"status": latest.status, "comment": latest.comment}) + else: + form = QuestionReviewForm() + return render(request, "generic/partials/question_review_form.html", {"question": question, "latest": latest, "form": form, "app_name": self.app_name}) def question_reviews_list(self, request, pk): """Return a partial listing all QuestionReview instances for a question."""