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

Participants editable by editors #1639

Merged
Merged
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
11 changes: 10 additions & 1 deletion evap/contributor/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from django.forms.widgets import CheckboxSelectMultiple
from django.utils.translation import gettext_lazy as _

from evap.evaluation.forms import UserModelChoiceField
from evap.evaluation.forms import UserModelChoiceField, UserModelMultipleChoiceField
from evap.evaluation.models import Course, Evaluation, Questionnaire, UserProfile
from evap.evaluation.tools import vote_end_datetime
from evap.staff.forms import ContributionForm
Expand All @@ -26,9 +26,13 @@ class Meta:
"name_en_field",
"vote_start_datetime",
"vote_end_date",
"participants",
"general_questionnaires",
"course",
)
field_classes = {
"participants": UserModelMultipleChoiceField,
}

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
Expand All @@ -45,6 +49,11 @@ def __init__(self, *args, **kwargs):
self.fields["vote_start_datetime"].localize = True
self.fields["vote_end_date"].localize = True

queryset = UserProfile.objects.exclude(is_active=False)
if self.instance.pk is not None:
queryset = (queryset | self.instance.participants.all()).distinct()
self.fields["participants"].queryset = queryset

if self.instance.general_contribution:
self.fields["general_questionnaires"].initial = [
q.pk for q in self.instance.general_contribution.questionnaires.all()
Expand Down
36 changes: 9 additions & 27 deletions evap/contributor/templates/contributor_evaluation_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,15 @@ <h5 class="card-title">{% trans 'Course data' %}</h5>
<div class="card-body">
<div class="d-flex">
<h5 class="card-title me-auto">{% trans 'Evaluation data' %}</h5>
{% if not evaluation.allow_editors_to_edit %}
{% if evaluation.allow_editors_to_edit %}
<div>
<button type="button" class="btn btn-sm btn-light" onclick="changeEvaluationRequestModalShow();" id="changeEvaluationRequestModalButton">
<button type="button" class="btn btn-sm btn-light mb-3" onclick="createAccountRequestModalShow();" id="createAccountRequestModalButtonInEvaluationForm">
{% trans 'Request creation of new account' %}
</button>
</div>
{% else %}
<div>
<button type="button" class="btn btn-sm btn-light" onclick="changeEvaluationRequestModalShow();" id="changeEvaluationDataRequestModalButton">
{% trans 'Request changes' %}
</button>
</div>
Expand All @@ -80,26 +86,6 @@ <h5 class="card-title me-auto">{% trans 'Evaluation data' %}</h5>
</div>
</div>

<div class="card mb-3">
<div class="card-body">
<fieldset>
<div class="d-flex">
<h5 class="card-title me-auto">{% trans 'Participants' %}</h5>
<div>
<button type="button" class="btn btn-sm btn-light" onclick="changeParticipantRequestModalShow();" id="changeParticipantRequestModalButton">
{% trans 'Request changes' %}
</button>
</div>
</div>
<p>{% trans 'These people will be invited for the evaluation. Please let us know if this data is not correct.' %}</p>
<ul>
{% for p in evaluation.participants.all|dictsort:'last_name' %}
<li>{{ p.full_name }}</li>
{% endfor %}
</ul>
</fieldset>
</div>
</div>
<div class="card card-submit-area card-submit-area-3 text-center mb-3">
<div class="card-body">
{% if editable %}
Expand Down Expand Up @@ -147,11 +133,7 @@ <h5 class="modal-title" id="previewModalLabel">{% trans 'Preview' %}</h5>
};
</script>

{% blocktrans asvar title with evaluation_name=evaluation.full_name|safe %}Request participant changes for {{ evaluation_name }}{% endblocktrans %}
{% trans 'Please tell us what changes to the participants list we should make.' as teaser %}
{% include 'contact_modal.html' with modal_id='changeParticipantRequestModal' user=request.user title=title teaser=teaser %}

{% trans 'Request account creation' as title %}
{% blocktrans asvar title with evaluation_name=evaluation.full_name|safe %}Request account creation for {{ evaluation_name }}{% endblocktrans %}
{% trans 'Please tell us which new account we should create. We need the name and email for all new accounts.' as teaser %}
{% include 'contact_modal.html' with modal_id='createAccountRequestModal' user=request.user title=title teaser=teaser %}

Expand Down
20 changes: 19 additions & 1 deletion evap/contributor/tests/test_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from model_bakery import baker

from evap.contributor.forms import EditorContributionForm, EvaluationForm
from evap.evaluation.models import Contribution, Evaluation, Questionnaire, UserProfile
from evap.evaluation.models import Contribution, Degree, Evaluation, Questionnaire, UserProfile
from evap.evaluation.tests.tools import WebTest, get_form_data_from_instance
from evap.staff.forms import ContributionFormSet

Expand All @@ -21,6 +21,24 @@ def test_fields_disabled_when_editors_disallowed_to_edit(self):
form = EvaluationForm(instance=evaluation)
self.assertTrue(all(form.fields[field].disabled for field in form.fields))

def test_edit_participants(self):
student = baker.make(UserProfile)
evaluation = baker.make(Evaluation, course__degrees=[baker.make(Degree)], participants=[student])
evaluation.general_contribution.questionnaires.set([baker.make(Questionnaire)])

form_data = get_form_data_from_instance(EvaluationForm, evaluation)
form = EvaluationForm(form_data, instance=evaluation)
self.assertEqual(len(form["participants"].initial), 1)

form_data["participants"].remove(student.pk)
EvaluationForm(form_data, instance=evaluation).save()
self.assertEqual(evaluation.num_participants, 0)

form_data["participants"].append(student.pk)
EvaluationForm(form_data, instance=evaluation).save()
del evaluation.num_participants # discard cached property
richardebeling marked this conversation as resolved.
Show resolved Hide resolved
self.assertEqual(evaluation.num_participants, 1)


class ContributionFormsetTests(TestCase):
def test_managers_only(self):
Expand Down
15 changes: 14 additions & 1 deletion evap/contributor/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ def test_contact_modal_escape(self):
self.evaluation.save()
page = self.app.get(self.url, user=self.responsible, status=200)

self.assertIn("changeParticipantRequestModalLabel", page)
self.assertIn("changeEvaluationRequestModalLabel", page)

self.assertNotIn("Adam &amp;amp; Eve", page)
self.assertIn("Adam &amp; Eve", page)
Expand All @@ -258,3 +258,16 @@ def test_information_message(self):
"Please review the evaluation's details below, add all contributors and select suitable questionnaires. "
"Once everything is okay, please approve the evaluation on the bottom of the page.",
)

def test_display_request_buttons(self):
self.evaluation.allow_editors_to_edit = False
self.evaluation.save()
page = self.app.get(self.url, user=self.responsible)
self.assertEqual(page.body.decode().count("Request changes"), 1)
self.assertEqual(page.body.decode().count("Request creation of new account"), 1)

self.evaluation.allow_editors_to_edit = True
self.evaluation.save()
page = self.app.get(self.url, user=self.responsible)
self.assertEqual(page.body.decode().count("Request changes"), 0)
self.assertEqual(page.body.decode().count("Request creation of new account"), 2)
2 changes: 2 additions & 0 deletions evap/evaluation/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ def label_from_instance(self, obj):


class UserModelMultipleChoiceField(forms.ModelMultipleChoiceField):
widget = forms.SelectMultiple(attrs={"data-selection-css-class": "user-multi-select"})

def label_from_instance(self, obj):
return obj.full_name_with_additional_info

Expand Down
5 changes: 4 additions & 1 deletion evap/staff/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,10 @@ def __init__(self, *args, **kwargs):
Questionnaire.objects.general_questionnaires().filter(visible_questionnaires).distinct()
)

self.fields["participants"].queryset = UserProfile.objects.exclude(is_active=False)
queryset = UserProfile.objects.exclude(is_active=False)
if self.instance.pk is not None:
queryset = (queryset | self.instance.participants.all()).distinct()
self.fields["participants"].queryset = queryset

if self.instance.general_contribution:
self.fields["general_questionnaires"].initial = [
Expand Down
23 changes: 23 additions & 0 deletions evap/staff/tests/test_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -954,6 +954,29 @@ def test_unused_questionnaire_visibility(self):
form = EvaluationForm(instance=evaluation, semester=evaluation.course.semester)
self.assertIn(questionnaire, form.fields["general_questionnaires"].queryset)

def test_inactive_participants_remain(self):
student = baker.make(UserProfile, is_active=False)
evaluation = baker.make(Evaluation, course__degrees=[baker.make(Degree)], participants=[student])

form_data = get_form_data_from_instance(EvaluationForm, evaluation)
form = EvaluationForm(form_data, instance=evaluation)
self.assertEqual(len(form["participants"]), 1)

def test_inactive_participants_not_in_queryset(self):
evaluation = baker.make(Evaluation, course__degrees=[baker.make(Degree)])

form_data = get_form_data_from_instance(EvaluationForm, evaluation)
form = EvaluationForm(form_data, instance=evaluation)
self.assertEqual(form.fields["participants"].queryset.count(), 0)

baker.make(UserProfile, is_active=True)
form = EvaluationForm(form_data, instance=evaluation)
self.assertEqual(form.fields["participants"].queryset.count(), 1)

baker.make(UserProfile, is_active=False)
form = EvaluationForm(form_data, instance=evaluation)
self.assertEqual(form.fields["participants"].queryset.count(), 1)


class EvaluationCopyFormTests(TestCase):
@classmethod
Expand Down
12 changes: 12 additions & 0 deletions evap/static/scss/_adjustments.scss
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,18 @@ $alert-colors: (
white-space: normal;
}

.user-multi-select {
knollengewaechs marked this conversation as resolved.
Show resolved Hide resolved
padding-right: 36px !important;
janno42 marked this conversation as resolved.
Show resolved Hide resolved

li {
width: 100%;
}
}

.select2-container:not(.select2-container--disabled) .user-multi-select.select2-selection--multiple .select2-selection__choice {
background-color: $lighter-gray;
}

janno42 marked this conversation as resolved.
Show resolved Hide resolved
.select2-container .select2-search--inline {
&, > input {
// When inputting long items, the input should not grow beyond the size of the selection
Expand Down