Skip to content

Commit cf6fd45

Browse files
fekochKakadusrichardebeling
authored
Dropped Courses (#2262)
Co-authored-by: Jonas Dittrich <58814480+Kakadus@users.noreply.github.com> Co-authored-by: Richard Ebeling <dev@richardebeling.de>
1 parent 94b8b58 commit cf6fd45

30 files changed

+935
-104
lines changed

evap/contributor/forms.py

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ class EvaluationForm(forms.ModelForm):
1515
general_questionnaires: "forms.ModelMultipleChoiceField[Questionnaire]" = forms.ModelMultipleChoiceField(
1616
queryset=None, required=False, widget=CheckboxSelectMultiple, label=_("General questionnaires")
1717
)
18+
dropout_questionnaires: "forms.ModelMultipleChoiceField[Questionnaire]" = forms.ModelMultipleChoiceField(
19+
queryset=None,
20+
required=False,
21+
widget=CheckboxSelectMultiple,
22+
label=_("Dropout questionnaires"),
23+
)
1824
course = forms.ModelChoiceField(Course.objects.all(), disabled=True, required=False, widget=forms.HiddenInput())
1925
name_de_field = forms.CharField(label=_("Name (German)"), disabled=True, required=False)
2026
name_en_field = forms.CharField(label=_("Name (English)"), disabled=True, required=False)
@@ -28,6 +34,7 @@ class Meta:
2834
"vote_end_date",
2935
"participants",
3036
"general_questionnaires",
37+
"dropout_questionnaires",
3138
"course",
3239
)
3340
field_classes = {
@@ -46,6 +53,12 @@ def __init__(self, *args, **kwargs):
4653
.distinct()
4754
.prefetch_related("questions")
4855
)
56+
self.fields["dropout_questionnaires"].queryset = (
57+
Questionnaire.objects.dropout_questionnaires()
58+
.filter(Q(visibility=Questionnaire.Visibility.EDITORS) | Q(contributions__evaluation=self.instance))
59+
.distinct()
60+
.prefetch_related("questions")
61+
)
4962

5063
self.fields["vote_start_datetime"].localize = True
5164
self.fields["vote_end_date"].localize = True
@@ -55,9 +68,12 @@ def __init__(self, *args, **kwargs):
5568
queryset = (queryset | self.instance.participants.all()).distinct()
5669
self.fields["participants"].queryset = queryset
5770

58-
if self.instance.general_contribution:
71+
if general_contribution := self.instance.general_contribution:
5972
self.fields["general_questionnaires"].initial = [
60-
q.pk for q in self.instance.general_contribution.questionnaires.all()
73+
q.pk for q in general_contribution.questionnaires.all() if q.is_general
74+
]
75+
self.fields["dropout_questionnaires"].initial = [
76+
q.pk for q in general_contribution.questionnaires.all() if q.is_dropout
6177
]
6278

6379
if not self.instance.allow_editors_to_edit:
@@ -73,6 +89,19 @@ def clean(self):
7389
self.add_error("vote_start_datetime", "")
7490
self.add_error("vote_end_date", _("The first day of evaluation must be before the last one."))
7591

92+
# Ensure locked questionnaires cannot be deselected and only unlocked ones can be added
93+
selected_questionnaires = self.instance.general_contribution.questionnaires.filter(is_locked=True).distinct()
94+
selected_questionnaires |= self.cleaned_data.get("general_questionnaires").filter(is_locked=False)
95+
selected_questionnaires |= self.cleaned_data.get("dropout_questionnaires").filter(is_locked=False)
96+
97+
self.cleaned_data.update(
98+
general_questionnaires=selected_questionnaires.exclude(type=Questionnaire.Type.DROPOUT),
99+
dropout_questionnaires=selected_questionnaires.filter(type=Questionnaire.Type.DROPOUT),
100+
)
101+
102+
if not self.cleaned_data.get("general_questionnaires"):
103+
self.add_error("general_questionnaires", _("At least one questionnaire must be selected."))
104+
76105
def clean_vote_end_date(self):
77106
vote_end_date = self.cleaned_data.get("vote_end_date")
78107

@@ -83,22 +112,12 @@ def clean_vote_end_date(self):
83112

84113
return vote_end_date
85114

86-
def clean_general_questionnaires(self):
87-
# Ensure all locked questionnaires still have the same status (included or not)
88-
not_locked = []
89-
if self.cleaned_data.get("general_questionnaires"):
90-
not_locked = list(self.cleaned_data.get("general_questionnaires").filter(is_locked=False))
91-
92-
locked = list(self.instance.general_contribution.questionnaires.filter(is_locked=True))
93-
94-
if not not_locked + locked:
95-
self.add_error("general_questionnaires", _("At least one questionnaire must be selected."))
96-
97-
return not_locked + locked
98-
99115
def save(self, *args, **kw):
100116
evaluation = super().save(*args, **kw)
101-
evaluation.general_contribution.questionnaires.set(self.cleaned_data.get("general_questionnaires"))
117+
selected_questionnaires = self.cleaned_data.get("general_questionnaires") | self.cleaned_data.get(
118+
"dropout_questionnaires"
119+
)
120+
evaluation.general_contribution.questionnaires.set(selected_questionnaires)
102121
return evaluation
103122

104123

evap/contributor/templates/contributor_evaluation_form.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ <h5 class="card-title me-auto">{% translate 'Evaluation data' %}</h5>
7878
</div>
7979
{% endif %}
8080
</div>
81-
{% include 'evaluation_form_general_questionnaires.html' with evaluation_form=form %}
81+
{% include 'evaluation_form_fields.html' with evaluation_form=form %}
8282
</div>
8383
</div>
8484
<div class="card mb-3">

evap/contributor/tests/test_views.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,22 @@ def test_display_request_buttons(self):
272272
self.assertEqual(page.body.decode().count("Request changes"), 0)
273273
self.assertEqual(page.body.decode().count("Request creation of new account"), 2)
274274

275+
def test_questionnaire_input_hidden_if_options_empty(self):
276+
Questionnaire.objects.update(visibility=Questionnaire.Visibility.MANAGERS)
277+
278+
self.evaluation.general_contribution.questionnaires.clear()
279+
self.evaluation.save()
280+
281+
page = self.app.get(self.url, user=self.responsible, status=200)
282+
self.assertNotContains(page, "General questionnaires")
283+
self.assertNotContains(page, "Dropout questionnaires")
284+
285+
Questionnaire.objects.update(visibility=Questionnaire.Visibility.EDITORS)
286+
287+
page = self.app.get(self.url, user=self.responsible, status=200)
288+
self.assertContains(page, "General questionnaires")
289+
self.assertContains(page, "Dropout questionnaires")
290+
275291

276292
class TestContributorResultsExportView(WebTest):
277293
@classmethod

evap/contributor/views.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,9 @@ def render_preview(request, formset, evaluation_form, evaluation):
157157
request.POST = None # this prevents errors rendered in the vote form
158158

159159
preview_response = mark_safe(
160-
render_vote_page(request, evaluation, preview=True, for_rendering_in_modal=True).content.decode()
160+
render_vote_page(
161+
request, evaluation, preview=True, for_rendering_in_modal=True, dropout=False
162+
).content.decode()
161163
)
162164
raise IntegrityError # rollback transaction to discard the database writes
163165
except IntegrityError:
@@ -241,7 +243,7 @@ def evaluation_preview(request, evaluation_id):
241243
):
242244
raise PermissionDenied
243245

244-
return render_vote_page(request, evaluation, preview=True)
246+
return render_vote_page(request, evaluation, preview=True, dropout=False)
245247

246248

247249
@require_POST

0 commit comments

Comments
 (0)