Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assign contributor questionnaires per course type #2373

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 14 additions & 9 deletions evap/staff/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -917,20 +917,25 @@ class QuestionnairesAssignForm(forms.Form):
def __init__(self, *args, course_types, **kwargs):
super().__init__(*args, **kwargs)

for course_type in course_types:
self.fields[course_type.name] = forms.ModelMultipleChoiceField(
required=False,
queryset=Questionnaire.objects.general_questionnaires().exclude(
visibility=Questionnaire.Visibility.HIDDEN
),
)
contributor_questionnaires = Questionnaire.objects.contributor_questionnaires().exclude(
visibility=Questionnaire.Visibility.HIDDEN
)
self.fields["all-contributors"] = forms.ModelMultipleChoiceField(
label=_("All contributors"), required=False, queryset=contributor_questionnaires
general_questionnaires = Questionnaire.objects.general_questionnaires().exclude(
visibility=Questionnaire.Visibility.HIDDEN
)

for course_type in course_types:
self.fields["general-" + str(course_type.id)] = forms.ModelMultipleChoiceField(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think f-strings are more concise here, below, in the test and the other view

Suggested change
self.fields["general-" + str(course_type.id)] = forms.ModelMultipleChoiceField(
self.fields[f"general-{course_type.id}"] = forms.ModelMultipleChoiceField(

label=course_type.name,
required=False,
queryset=general_questionnaires,
)
self.fields["contributor-" + str(course_type.id)] = forms.ModelMultipleChoiceField(
label=course_type.name,
required=False,
queryset=contributor_questionnaires,
)


class UserForm(forms.ModelForm):
is_manager = forms.BooleanField(required=False, label=_("Manager"))
Expand Down
32 changes: 28 additions & 4 deletions evap/staff/templates/staff_semester_questionnaire_assign_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,34 @@ <h3>{% translate 'Assign questionnaires' %}</h3>
{% csrf_token %}
<div class="card mb-3">
<div class="card-body">
<p>{% translate 'Select the questionnaires which shall be assigned each of these course types and the contributors. This will only change evaluations in preparation. If you do select nothing, the currently applied questionnaires for the corresponding course type or contributor will not be changed.' %}</p>
<fieldset>
{% include 'bootstrap_form.html' with form=form %}
</fieldset>
<p>{% translate 'Select the questionnaires to be used for each course type. This will only change evaluations in preparation. Selecting nothing will not change the currently used questionnaires.' %}</p>
{% include 'bootstrap_form_errors.html' with errors=form.non_field_errors %}
<div class="row">
<div class="col-md-6">
<div class="card">
<div class="card-body">
<h4 class="card-title">{% translate 'General' %}</h4>
<fieldset>
{% for field in general_fields %}
{% include 'bootstrap_form_field.html' with field=field %}
{% endfor %}
</fieldset>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-body">
<h4 class="card-title">{% translate 'Contributors' %}</h4>
<fieldset>
{% for field in contributor_fields %}
{% include 'bootstrap_form_field.html' with field=field %}
{% endfor %}
</fieldset>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card card-submit-area text-center mb-3">
Expand Down
151 changes: 80 additions & 71 deletions evap/staff/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -911,12 +911,13 @@ def setUpTestData(cls):
cls.semester = baker.make(Semester)
cls.url = f"/staff/semester/{cls.semester.pk}/assign"

lecture_type = baker.make(CourseType, name_de="Vorlesung", name_en="Lecture")
seminar_type = baker.make(CourseType, name_de="Seminar", name_en="Seminar")
cls.questionnaire = baker.make(Questionnaire, type=Questionnaire.Type.TOP)
cls.lecture_type = baker.make(CourseType, name_de="Vorlesung", name_en="Lecture")
cls.seminar_type = baker.make(CourseType, name_de="Seminar", name_en="Seminar")
cls.questionnaire_general = baker.make(Questionnaire, type=Questionnaire.Type.TOP)
cls.questionnaire_contributor = baker.make(Questionnaire, type=Questionnaire.Type.CONTRIBUTOR)

evaluation1 = baker.make(Evaluation, course__type=seminar_type, course__semester=cls.semester)
evaluation2 = baker.make(Evaluation, course__type=lecture_type, course__semester=cls.semester)
evaluation1 = baker.make(Evaluation, course__type=cls.seminar_type, course__semester=cls.semester)
evaluation2 = baker.make(Evaluation, course__type=cls.lecture_type, course__semester=cls.semester)
baker.make(
Contribution,
contributor=baker.make(UserProfile),
Expand All @@ -928,16 +929,85 @@ def setUpTestData(cls):
_bulk_create=True,
)

def test_assign_questionnaires(self):
def test_assign_questionnaires(self) -> None:
page = self.app.get(self.url, user=self.manager)
assign_form = page.forms["questionnaire-assign-form"]
assign_form["Seminar"] = [self.questionnaire.pk]
assign_form["Lecture"] = [self.questionnaire.pk]
assign_form["general-" + str(self.seminar_type.id)] = [self.questionnaire_general.pk]
assign_form["contributor-" + str(self.lecture_type.id)] = [self.questionnaire_contributor.pk]
page = assign_form.submit().follow()

for evaluation in self.semester.evaluations.all():
self.assertEqual(evaluation.general_contribution.questionnaires.count(), 1)
self.assertEqual(evaluation.general_contribution.questionnaires.get(), self.questionnaire)
if evaluation.course.type == self.seminar_type:
self.assertEqual(evaluation.general_contribution.questionnaires.count(), 1)
self.assertEqual(evaluation.general_contribution.questionnaires.get(), self.questionnaire_general)
Comment on lines +941 to +942
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.assertEqual(evaluation.general_contribution.questionnaires.count(), 1)
self.assertEqual(evaluation.general_contribution.questionnaires.get(), self.questionnaire_general)
self.assertQuerySetEqual(evaluation.general_contribution.questionnaires, [self.questionnaire_general])

maybe also below?

for contribution in evaluation.contributions.exclude(contributor=None): # contributions without general
self.assertEqual(contribution.questionnaires.count(), 0)
if evaluation.course.type == self.lecture_type:
self.assertEqual(evaluation.general_contribution.questionnaires.count(), 0)
for contribution in evaluation.contributions.exclude(contributor=None):
self.assertEqual(contribution.questionnaires.count(), 1)
self.assertEqual(contribution.questionnaires.get(), self.questionnaire_contributor)


class TestSemesterQuestionnaireAssignment(WebTestStaffMode):
@classmethod
def setUpTestData(cls):
cls.manager = make_manager()
semester = baker.make(Semester)
cls.url = f"/staff/semester/{semester.pk}/assign"

cls.course_type_1 = baker.make(CourseType)
cls.course_type_2 = baker.make(CourseType)
cls.responsible = baker.make(UserProfile)
cls.questionnaire_1 = baker.make(Questionnaire, type=Questionnaire.Type.TOP)
cls.questionnaire_2 = baker.make(Questionnaire, type=Questionnaire.Type.TOP)
cls.questionnaire_responsible = baker.make(Questionnaire, type=Questionnaire.Type.CONTRIBUTOR)
cls.evaluation_1 = baker.make(
Evaluation,
course=baker.make(Course, semester=semester, type=cls.course_type_1, responsibles=[cls.responsible]),
)
cls.evaluation_2 = baker.make(
Evaluation,
course=baker.make(Course, semester=semester, type=cls.course_type_2, responsibles=[cls.responsible]),
)
baker.make(
Contribution,
contributor=cls.responsible,
evaluation=cls.evaluation_1,
role=Contribution.Role.EDITOR,
textanswer_visibility=Contribution.TextAnswerVisibility.GENERAL_TEXTANSWERS,
)
baker.make(
Contribution,
contributor=cls.responsible,
evaluation=cls.evaluation_2,
role=Contribution.Role.EDITOR,
textanswer_visibility=Contribution.TextAnswerVisibility.GENERAL_TEXTANSWERS,
)

def test_questionnaire_assignment(self):
page = self.app.get(self.url, user=self.manager, status=200)
form = page.forms["questionnaire-assign-form"]
form["general-" + str(self.course_type_1.id)] = [self.questionnaire_1.pk, self.questionnaire_2.pk]
form["general-" + str(self.course_type_2.id)] = [self.questionnaire_2.pk]
form["contributor-" + str(self.course_type_1.id)] = [self.questionnaire_responsible.pk]

response = form.submit().follow()
self.assertIn("Successfully", str(response))

self.assertEqual(
set(self.evaluation_1.general_contribution.questionnaires.all()),
{self.questionnaire_1, self.questionnaire_2},
)
self.assertEqual(set(self.evaluation_2.general_contribution.questionnaires.all()), {self.questionnaire_2})
self.assertEqual(
set(self.evaluation_1.contributions.get(contributor=self.responsible).questionnaires.all()),
{self.questionnaire_responsible},
)
self.assertEqual(
set(self.evaluation_2.contributions.get(contributor=self.responsible).questionnaires.all()),
set(),
)


class TestSemesterPreparationReminderView(WebTestStaffModeWith200Check):
Expand Down Expand Up @@ -3801,67 +3871,6 @@ def test_import_names_duplicated_error(self):
self.assertContains(response, "Import name &quot;M&quot; is duplicated.")


class TestSemesterQuestionnaireAssignment(WebTestStaffMode):
@classmethod
def setUpTestData(cls):
cls.manager = make_manager()
semester = baker.make(Semester)
cls.url = f"/staff/semester/{semester.pk}/assign"

cls.course_type_1 = baker.make(CourseType)
cls.course_type_2 = baker.make(CourseType)
cls.responsible = baker.make(UserProfile)
cls.questionnaire_1 = baker.make(Questionnaire, type=Questionnaire.Type.TOP)
cls.questionnaire_2 = baker.make(Questionnaire, type=Questionnaire.Type.TOP)
cls.questionnaire_responsible = baker.make(Questionnaire, type=Questionnaire.Type.CONTRIBUTOR)
cls.evaluation_1 = baker.make(
Evaluation,
course=baker.make(Course, semester=semester, type=cls.course_type_1, responsibles=[cls.responsible]),
)
cls.evaluation_2 = baker.make(
Evaluation,
course=baker.make(Course, semester=semester, type=cls.course_type_2, responsibles=[cls.responsible]),
)
baker.make(
Contribution,
contributor=cls.responsible,
evaluation=cls.evaluation_1,
role=Contribution.Role.EDITOR,
textanswer_visibility=Contribution.TextAnswerVisibility.GENERAL_TEXTANSWERS,
)
baker.make(
Contribution,
contributor=cls.responsible,
evaluation=cls.evaluation_2,
role=Contribution.Role.EDITOR,
textanswer_visibility=Contribution.TextAnswerVisibility.GENERAL_TEXTANSWERS,
)

def test_questionnaire_assignment(self):
page = self.app.get(self.url, user=self.manager, status=200)
form = page.forms["questionnaire-assign-form"]
form[self.course_type_1.name] = [self.questionnaire_1.pk, self.questionnaire_2.pk]
form[self.course_type_2.name] = [self.questionnaire_2.pk]
form["all-contributors"] = [self.questionnaire_responsible.pk]

response = form.submit().follow()
self.assertIn("Successfully", str(response))

self.assertEqual(
set(self.evaluation_1.general_contribution.questionnaires.all()),
{self.questionnaire_1, self.questionnaire_2},
)
self.assertEqual(set(self.evaluation_2.general_contribution.questionnaires.all()), {self.questionnaire_2})
self.assertEqual(
set(self.evaluation_1.contributions.get(contributor=self.responsible).questionnaires.all()),
{self.questionnaire_responsible},
)
self.assertEqual(
set(self.evaluation_2.contributions.get(contributor=self.responsible).questionnaires.all()),
{self.questionnaire_responsible},
)


class TestSemesterActiveStateBehaviour(WebTestStaffMode):
url = "/staff/semester/make_active"
csrf_checks = False
Expand Down
24 changes: 19 additions & 5 deletions evap/staff/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -903,19 +903,33 @@ def semester_questionnaire_assign(request, semester_id):
course_types = CourseType.objects.filter(courses__evaluations__in=evaluations)
form = QuestionnairesAssignForm(request.POST or None, course_types=course_types)

general_fields = [field for field in form if field.name.startswith("general-")]
contributor_fields = [field for field in form if field.name.startswith("contributor-")]

if form.is_valid():
for evaluation in evaluations:
if form.cleaned_data[evaluation.course.type.name]:
evaluation.general_contribution.questionnaires.set(form.cleaned_data[evaluation.course.type.name])
if form.cleaned_data["all-contributors"]:
if form.cleaned_data["general-" + str(evaluation.course.type.id)]:
evaluation.general_contribution.questionnaires.set(
form.cleaned_data["general-" + str(evaluation.course.type.id)]
)
if form.cleaned_data["contributor-" + str(evaluation.course.type.id)]:
for contribution in evaluation.contributions.exclude(contributor=None):
contribution.questionnaires.set(form.cleaned_data["all-contributors"])
contribution.questionnaires.set(form.cleaned_data["contributor-" + str(evaluation.course.type.id)])
evaluation.save()

messages.success(request, _("Successfully assigned questionnaires."))
return redirect("staff:semester_view", semester_id)

return render(request, "staff_semester_questionnaire_assign_form.html", {"semester": semester, "form": form})
return render(
request,
"staff_semester_questionnaire_assign_form.html",
{
"semester": semester,
"form": form,
"general_fields": general_fields,
"contributor_fields": contributor_fields,
},
)


@manager_required
Expand Down
Loading