internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: e-valuation/EvaP

Issue:
Menu bar hides content
The navigation on top of the page hides parts of the content if its size increases. This happens in smaller browser windows, where the navigation bar has more than one line but is not yet compressed into a single icon.
The content should always be visible.

![capture](https://cloud.githubusercontent.com/assets/1781719/5887235/763386a4-a3c4-11e4-8b93-c2999d8ca74a.PNG)



Discussion:

Resolving patch:
diff --git a/evap/settings.py b/evap/settings.py
--- a/evap/settings.py
+++ b/evap/settings.py
@@ -172,6 +172,7 @@
     'evap.contributor',
     'evap.rewards',
     'evap.grades',
+    'compressor',
     'django_extensions',
 )
 
@@ -275,6 +276,12 @@
     os.path.join(BASE_DIR, "static"),
 )
 
+STATICFILES_FINDERS = (
+    "django.contrib.staticfiles.finders.FileSystemFinder",
+    "django.contrib.staticfiles.finders.AppDirectoriesFinder",
+    "compressor.finders.CompressorFinder",
+)
+
 # Absolute path to the directory static files should be collected to.
 STATIC_ROOT = os.path.join(BASE_DIR, "static_collected")
 
@@ -291,8 +298,17 @@
 # see https://github.com/johnsensible/django-sendfile for further information
 SENDFILE_BACKEND = 'sendfile.backends.simple'
 
+
 ### Other
 
+# django-compressor settings
+COMPRESS_ENABLED = not DEBUG
+COMPRESS_OFFLINE = False
+COMPRESS_PRECOMPILERS = (
+    ('text/less', 'lessc {infile} {outfile}'),
+)
+COMPRESS_CACHEABLE_PRECOMPILERS = ('text/less',)
+
 # Apply the correct bootstrap css class to django's error messages
 MESSAGE_TAGS = {
     messages.ERROR: 'danger',


Test patch:
diff --git a/deployment/testing_environment/manifests/site.pp b/deployment/testing_environment/manifests/site.pp
--- a/deployment/testing_environment/manifests/site.pp
+++ b/deployment/testing_environment/manifests/site.pp
@@ -16,6 +16,17 @@
     package { ['python3', 'python3-dev', 'python3-pip', 'libxslt1-dev', 'zlib1g-dev', 'gettext']:
         ensure => installed,
     } ->
+    package { ['nodejs', 'npm']:
+        ensure => installed,
+    } ->
+    exec { "node-symlink":
+        provider => shell,
+        command => 'ln -f -s /usr/bin/nodejs /usr/bin/node'
+    } ->
+    exec { "install less":
+        provider => shell,
+        command => 'npm install -g less'
+    }
 
 
     class { 'postgresql::globals':
Repository: e-valuation/EvaP

Issue:
Allow to exclude courses from grader view
It should be possible to exclude courses from the semester overview on the grading page.
Single results should never be listed on the page and there should be a new attribute for each course defining whether the course is shown for graders or not.
This must also include a symbol for staff users, showing them that this course can't get grade documents.



Discussion:

Resolving patch:
diff --git a/evap/grades/views.py b/evap/grades/views.py
--- a/evap/grades/views.py
+++ b/evap/grades/views.py
@@ -42,7 +42,7 @@ def prefetch_data(courses):
 def semester_view(request, semester_id):
     semester = get_object_or_404(Semester, id=semester_id)
 
-    courses = semester.course_set.exclude(state='new')
+    courses = semester.course_set.filter(is_graded=True).exclude(state='new')
     courses = prefetch_data(courses)
 
     template_data = dict(


Test patch:
Repository: e-valuation/EvaP

Issue:
Remove single results from course list in user form
On the user editing page, single results should not be listed in the course list (Courses participating in (active semester)).



Discussion:

Resolving patch:
diff --git a/evap/staff/forms.py b/evap/staff/forms.py
--- a/evap/staff/forms.py
+++ b/evap/staff/forms.py
@@ -380,6 +380,8 @@ def __init__(self, *args, **kwargs):
         self.fields['cc_users'].required = False
         self.fields['cc_users'].queryset = all_users
         courses_of_current_semester = Course.objects.filter(semester=Semester.active_semester())
+        excludes = [x.id for x in courses_of_current_semester if x.is_single_result()]
+        courses_of_current_semester = courses_of_current_semester.exclude(id__in=excludes)
         self.fields['courses_participating_in'].queryset = courses_of_current_semester
         self.fields['courses_participating_in'].initial = courses_of_current_semester.filter(participants=self.instance) if self.instance.pk else ()
         self.fields['courses_participating_in'].label = _("Courses participating in (active semester)")


Test patch:
Repository: e-valuation/EvaP

Issue:
Remove single results from export
When exporting a semester with single results a `ZeroDevisionError` occurs, because there are no participants.
Single results should not be part of the semester export.



Discussion:

Resolving patch:
diff --git a/evap/results/exporters.py b/evap/results/exporters.py
--- a/evap/results/exporters.py
+++ b/evap/results/exporters.py
@@ -72,6 +72,8 @@ def deviation_to_style(self, deviation):
     def export(self, response, ignore_not_enough_answers=False):
         courses_with_results = list()
         for course in self.semester.course_set.filter(state="published").all():
+            if course.is_single_result():
+                continue
             results = OrderedDict()
             for questionnaire, contributor, label, data, section_warning in calculate_results(course):
                 results.setdefault(questionnaire.id, []).extend(data)
@@ -164,7 +166,7 @@ def export(self, response, ignore_not_enough_answers=False):
 
         writen(self, _("Total Voters/Total Participants"), "bold")
         for course, results in courses_with_results:
-            percent_participants = float(course.num_voters)/float(course.num_participants)
+            percent_participants = float(course.num_voters)/float(course.num_participants) if course.num_participants > 0 else 0
             writec(self, "{}/{} ({:.0%})".format(course.num_voters, course.num_participants, percent_participants), "total_voters", cols=2)
 
         self.workbook.save(response)


Test patch:
Repository: e-valuation/EvaP

Issue:
Exporter only uses first contributor per type
The exporter only uses the results of the first contributor per type.
It should instead compute the average of all contributors per type.



Discussion:

Resolving patch:
diff --git a/evap/results/exporters.py b/evap/results/exporters.py
--- a/evap/results/exporters.py
+++ b/evap/results/exporters.py
@@ -132,7 +132,6 @@ def export(self, response, ignore_not_enough_answers=False):
                                 if grade_result.average:
                                     values.append(grade_result.average)
                                     deviations.append(grade_result.deviation)
-                                break
                         enough_answers = course.can_publish_grades
                         if values and (enough_answers or ignore_not_enough_answers):
                             avg = sum(values) / len(values)


Test patch:
Repository: e-valuation/EvaP

Issue:
Option for staff to get list of all participants' email addresses



Discussion:
In addition to the existing functionality to send emails to all participants of a course via the platform, it should also be possible to extract the list of email addresses for usage outside of EvaP.


Resolving patch:
diff --git a/evap/staff/forms.py b/evap/staff/forms.py
--- a/evap/staff/forms.py
+++ b/evap/staff/forms.py
@@ -202,8 +202,11 @@ class CourseEmailForm(forms.Form, BootstrapMixin):
 
     def __init__(self, *args, **kwargs):
         self.instance = kwargs.pop('instance')
+        self.export = kwargs.pop('export', False)
         self.template = EmailTemplate()
         super().__init__(*args, **kwargs)
+        self.fields['subject'].required = not self.export
+        self.fields['body'].required = not self.export
 
     def clean(self):
         self.recipient_groups = self.cleaned_data.get('recipients')
@@ -213,11 +216,17 @@ def clean(self):
 
         return self.cleaned_data
 
-    # returns the number of recepients without an email address
+    # returns the number of recipients without an email address
     def missing_email_addresses(self):
         recipients = self.template.recipient_list_for_course(self.instance, self.recipient_groups)
         return len([user for user in recipients if not user.email])
 
+    def email_addresses(self):
+        if self.recipient_groups is None:
+            return []
+        recipients = self.template.recipient_list_for_course(self.instance, self.recipient_groups)
+        return set(user.email for user in recipients if user.email)
+
     def send(self):
         self.template.subject = self.cleaned_data.get('subject')
         self.template.body = self.cleaned_data.get('body')
diff --git a/evap/staff/views.py b/evap/staff/views.py
--- a/evap/staff/views.py
+++ b/evap/staff/views.py
@@ -535,9 +535,13 @@ def course_delete(request, semester_id, course_id):
 def course_email(request, semester_id, course_id):
     semester = get_object_or_404(Semester, id=semester_id)
     course = get_object_or_404(Course, id=course_id)
-    form = CourseEmailForm(request.POST or None, instance=course)
+    form = CourseEmailForm(request.POST or None, instance=course, export='export' in request.POST)
 
     if form.is_valid():
+        if form.export:
+            email_addresses = '; '.join(form.email_addresses())
+            messages.info(request, _('Recipients: ') + '\n' + email_addresses)
+            return render(request, "staff_course_email.html", dict(semester=semester, course=course, form=form))
         form.send()
 
         missing_email_addresses = form.missing_email_addresses()


Test patch:
Repository: e-valuation/EvaP

Issue:
Staff field on user page is missing
The user edit page does not have a staff field anymore.
Superusers should be able to add or remove the group there.



Discussion:
superusers can use the admin pages to change group memberships, so this is really not important.

Same goes for Grade Users.


Resolving patch:
diff --git a/evap/staff/forms.py b/evap/staff/forms.py
--- a/evap/staff/forms.py
+++ b/evap/staff/forms.py
@@ -4,6 +4,7 @@
 from django.utils.translation import ugettext_lazy as _
 from django.utils.text import normalize_newlines
 from django.core.exceptions import ValidationError
+from django.contrib.auth.models import Group
 
 from evap.evaluation.forms import BootstrapMixin, QuestionnaireMultipleChoiceField
 from evap.evaluation.models import Contribution, Course, Question, Questionnaire, \
@@ -318,6 +319,8 @@ def __init__(self, *args, **kwargs):
 
 
 class UserForm(forms.ModelForm, BootstrapMixin):
+    is_staff = forms.BooleanField(required=False, label=_("Staff user"))
+    is_grade_user = forms.BooleanField(required=False, label=_("Grade user"))
     courses_participating_in = forms.ModelMultipleChoiceField(None)
 
     class Meta:
@@ -333,6 +336,8 @@ def __init__(self, *args, **kwargs):
         self.fields['courses_participating_in'].initial = courses_of_current_semester.filter(participants=self.instance) if self.instance.pk else ()
         self.fields['courses_participating_in'].label = _("Courses participating in (active semester)")
         self.fields['courses_participating_in'].required = False
+        self.fields['is_staff'].initial = self.instance.is_staff
+        self.fields['is_grade_user'].initial = self.instance.is_grade_publisher
 
     def clean_username(self):
         username = self.cleaned_data.get('username')
@@ -361,6 +366,18 @@ def clean_email(self):
     def save(self, *args, **kw):
         super().save(*args, **kw)
         self.instance.course_set = list(self.instance.course_set.exclude(semester=Semester.active_semester())) + list(self.cleaned_data.get('courses_participating_in'))
+        
+        staff_group = Group.objects.get(name="Staff")
+        grade_user_group = Group.objects.get(name="Grade publisher")
+        if self.cleaned_data.get('is_staff'):
+            self.instance.groups.add(staff_group)
+        else:
+            self.instance.groups.remove(staff_group)
+
+        if self.cleaned_data.get('is_grade_user'):
+            self.instance.groups.add(grade_user_group)
+        else:
+            self.instance.groups.remove(grade_user_group)
 
 
 class LotteryForm(forms.Form, BootstrapMixin):


Test patch:
Repository: e-valuation/EvaP

Issue:
Only internal redirects
The platform should only redirect to internal pages after logging in.

(handled in `evaluation/views.py index`)



Discussion:
assign me


Resolving patch:
diff --git a/evap/evaluation/views.py b/evap/evaluation/views.py
--- a/evap/evaluation/views.py
+++ b/evap/evaluation/views.py
@@ -2,13 +2,14 @@
 from django.contrib.auth import login as auth_login
 from django.shortcuts import redirect, render
 from django.utils.translation import ugettext as _
+from django.core.urlresolvers import resolve, Resolver404
 
 from evap.evaluation.forms import NewKeyForm, LoginKeyForm, LoginUsernameForm
 from evap.evaluation.models import UserProfile, FaqSection, EmailTemplate, Semester
 
 
 def index(request):
-    """Main entry page into EvaP providing all the login options available. THe username/password
+    """Main entry page into EvaP providing all the login options available. The username/password
        login is thought to be used for internal users, e.g. by connecting to a LDAP directory.
        The login key mechanism is meant to be used to include external participants, e.g. visiting
        students or visiting contributors.
@@ -68,7 +69,12 @@ def index(request):
                 if user.is_participant:
                     return redirect(redirect_to)
             else:
-                return redirect(redirect_to)
+                try:
+                    resolve(redirect_to)
+                except Resolver404:
+                    pass
+                else:
+                    return redirect(redirect_to)
 
         # redirect user to appropriate start page
         if request.user.is_staff:


Test patch:
Repository: e-valuation/EvaP

Issue:
Warning in courses with small number of participants
In courses with 5 or less participants a warning should be shown above the course's questionnaire:

_This course has only a small number of participants. Please remember that your comments will be visible for the responsible person and the contributors you're evaluating. If two or more people evaluate the course, the results of all voting questions will also be published._



Discussion:

Resolving patch:
diff --git a/evap/student/views.py b/evap/student/views.py
--- a/evap/student/views.py
+++ b/evap/student/views.py
@@ -76,6 +76,7 @@ def vote(request, course_id):
                 course_form_group=course_form_group,
                 contributor_form_groups=contributor_form_groups,
                 course=course,
+                participants_warning=course.num_participants <= 5,
                 preview=False)
         return render(request, "student_vote.html", template_data)
 


Test patch:
Repository: e-valuation/EvaP

Issue:
Update navbar cache
When adding or deleting semesters the cache must be refreshed so that the navbar shows the existing semesters.

Currently changes are not immediately visible in the navbar because cached entries are used for rendering.



Discussion:

Resolving patch:
diff --git a/evap/staff/tools.py b/evap/staff/tools.py
--- a/evap/staff/tools.py
+++ b/evap/staff/tools.py
@@ -1,5 +1,9 @@
 from django.core.urlresolvers import reverse
 from django.http import HttpResponseRedirect
+from django.core.cache import cache
+from django.core.cache.utils import make_template_fragment_key
+
+from evap.evaluation.models import UserProfile
 
 import urllib.parse
 
@@ -8,3 +12,11 @@ def custom_redirect(url_name, *args, **kwargs):
     url = reverse(url_name, args=args)
     params = urllib.parse.urlencode(kwargs)
     return HttpResponseRedirect(url + "?%s" % params)
+
+def delete_navbar_cache():
+    # delete navbar cache from base.html
+    for user in UserProfile.objects.all():
+        key = make_template_fragment_key('navbar', [user.username, 'de'])
+        cache.delete(key)
+        key = make_template_fragment_key('navbar', [user.username, 'en'])
+        cache.delete(key)
diff --git a/evap/staff/views.py b/evap/staff/views.py
--- a/evap/staff/views.py
+++ b/evap/staff/views.py
@@ -22,7 +22,7 @@
                              FaqQuestionForm, UserImportForm, TextAnswerForm, DegreeForm, SingleResultForm, \
                              ExportSheetForm
 from evap.staff.importers import EnrollmentImporter, UserImporter
-from evap.staff.tools import custom_redirect
+from evap.staff.tools import custom_redirect, delete_navbar_cache
 from evap.student.views import vote_preview
 from evap.student.forms import QuestionsForm
 
@@ -234,6 +234,7 @@ def semester_create(request):
 
     if form.is_valid():
         semester = form.save()
+        delete_navbar_cache()
 
         messages.success(request, _("Successfully created semester."))
         return redirect('staff:semester_view', semester.id)
@@ -262,6 +263,7 @@ def semester_delete(request, semester_id):
     if semester.can_staff_delete:
         if request.method == 'POST':
             semester.delete()
+            delete_navbar_cache()
             messages.success(request, _("Successfully deleted semester."))
             return redirect('staff:index')
         else:


Test patch:
Repository: e-valuation/EvaP

Issue:
Test management commands
Because in three years, run_tasks will silently fail on the production system and nobody will notice.
- [x] **run_tasks** - shouldn't be too hard and is rather important
- [x] **anonymize** - might be a bit of work to cover it properly, but should be straightforward.
- [x] **refresh_results_cache** - should be easy
- [x] **dump_testdata** - don't know how not to overwrite the file during testing, but should be possible

the other commands are already tested or rather unsuitable for testing
- [x] **merge_users** - already has a test (#703) and is shown to be pretty broken.
- [x] **run** - don't know how to test this and there isn't really anything that could break. still, somehow running it to check that it doesn't crash right away on e.g. imports would be cool
- [x] **reload_testdata** - don't know whether it's possible at all to test that, i mean it drops the whole database...
- [ ] **import_ad** - we never used it and i don't know whether it's feasible to mock ldap

use `self.stdout.write` instead of `print` and `call_command("command_name", stdout=StringIO())` to avoid console output during tests. don't know what to do about calls to `input`.



Discussion:
calls to input can be mocked as usual:

```
from mock import patch

with patch('builtins.input') as mock_input:
    # do stuff
```


Resolving patch:
diff --git a/evap/evaluation/management/commands/import_ad.py b/evap/evaluation/management/commands/import_ad.py
deleted file mode 100644
--- a/evap/evaluation/management/commands/import_ad.py
+++ /dev/null
@@ -1,42 +0,0 @@
-import getpass
-import ldap
-import sys
-
-from django.core.management.base import BaseCommand
-
-from evap.evaluation.models import UserProfile
-
-
-class Command(BaseCommand):
-    args = '<ldap server> <username>'
-    help = 'Imports user data from Active Directory. The username should be specified with realm.'
-
-    def handle(self, *args, **options):
-        try:
-            # connect
-            l = ldap.initialize(args[0])
-
-            # bind
-            l.bind_s(args[1], getpass.getpass("AD Password: "))
-
-            # find all users
-            result = l.search_s("OU=INSTITUT,DC=hpi,DC=uni-potsdam,DC=de", ldap.SCOPE_SUBTREE, filterstr="(&(&(objectClass=user)(!(objectClass=computer)))(givenName=*)(sn=*)(mail=*))")
-            for _, attrs in result:
-                try:
-                    user = UserProfile.objects.get(username__iexact=attrs['sAMAccountName'][0])
-                    user.first_name = attrs['givenName'][0]
-                    user.last_name = attrs['sn'][0]
-                    user.email = attrs['mail'][0]
-                    user.save()
-
-                    print("Successfully updated: '{0}'".format(user.username))
-                except UserProfile.DoesNotExist:
-                    pass
-                except Exception as e:
-                    print(e)
-
-            l.unbind_s()
-
-        except KeyboardInterrupt:
-            sys.stderr.write("\nOperation cancelled.\n")
-            sys.exit(1)


Test patch:
Repository: e-valuation/EvaP

Issue:
single results not sortable by result
On the results site of a semester are the single results not sortable by the result. When clicking on the results table header the results get sorted by something, but not the result.



Discussion:
What exactly is meant by "sortable by the result"? I see no results table header on the semester results site.

![screen shot 2016-02-29 at 7 24 43 pm](https://cloud.githubusercontent.com/assets/5385472/13404511/329aa7aa-df1a-11e5-9662-d29ccc029b3a.png)

your screenshot does not show the single results, but the normal course results


Resolving patch:
diff --git a/evap/staff/forms.py b/evap/staff/forms.py
--- a/evap/staff/forms.py
+++ b/evap/staff/forms.py
@@ -151,8 +151,6 @@ class Meta:
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
 
-        self.fields['type'].widget = forms.Select(choices=[(a, a) for a in Course.objects.values_list('type', flat=True).order_by().distinct()])
-
         self.fields['last_modified_time_2'].initial = self.instance.last_modified_time
         if self.instance.last_modified_user:
             self.fields['last_modified_user_2'].initial = self.instance.last_modified_user.full_name


Test patch: