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

Issue:
there is duplicated code in EvaP
while browsing the code, i ran across a lot of structurally very similar blocks of code. 

this is a reminder for me to search for these code parts, collect a few, and find the cause and solutions for them.

examples: 
- [x] https://github.com/fsr-itse/EvaP/commit/ca4b28a6054944859ec4447fff95fc36095a2ffb.
- [x] the contributor course view/template vs the fsr course view/template.
- [x] student_index and contributor_index (html and view)
- [ ] fsr_import and user_import
- [x] the multiselect initialization inside the script blocks exists multiple times in different files. one can find it by searching for select[multiple='multiple']
- [x] https://github.com/janno42/EvaP/blob/reward_points/evap/fsr/templates/fsr_reward_point_redemption_event_delete.html
- [x] search for $(".twipsify") and $("input[data-datepicker='datepicker']:not([readonly='True'])")
- [x] sortable and apply_ordering functions
- [x] if ($.fn.button.noConflict != undefined)
- [x] $('#id_degree').combobox() and similar
- [x] fsr_course_preview.html, fsr_questionnaire_view.html, contributor_course_preview.html
- [x] javascript-code of the sortable forms: [contributor/staff]_course_form.html (or rather, evap_course_edit_js.html), staff_faq_index.html and staff_faq_section.html
- [x] all the leave.js occurrences



Discussion:

Resolving patch:
diff --git a/evap/evaluation/management/commands/merge_users.py b/evap/evaluation/management/commands/merge_users.py
--- a/evap/evaluation/management/commands/merge_users.py
+++ b/evap/evaluation/management/commands/merge_users.py
@@ -5,8 +5,8 @@
 
 
 class Command(BaseCommand):
-    args = '<user ID 1> <user ID 2>'
-    help = 'Merge two users'
+    args = '<primary user ID> <duplicate user ID>'
+    help = 'Merges duplicate user into primary user'
 
     def handle(self, *args, **options):
         try:
diff --git a/evap/evaluation/templatetags/evaluation_templatetags.py b/evap/evaluation/templatetags/evaluation_templatetags.py
--- a/evap/evaluation/templatetags/evaluation_templatetags.py
+++ b/evap/evaluation/templatetags/evaluation_templatetags.py
@@ -7,3 +7,9 @@
 @register.inclusion_tag("user_list_with_links.html")
 def include_user_list_with_links(users):
     return dict(users=users)
+
+
+@register.inclusion_tag("sortable_form_js.html")
+def include_sortable_form_js():
+    return dict()
+
diff --git a/evap/staff/templatetags/staff_templatetags.py b/evap/staff/templatetags/staff_templatetags.py
--- a/evap/staff/templatetags/staff_templatetags.py
+++ b/evap/staff/templatetags/staff_templatetags.py
@@ -20,3 +20,7 @@ def include_staff_course_selection_list(course_forms, btn_label, empty_msg):
 @register.inclusion_tag('staff_user_labels.html')
 def include_staff_user_labels(user):
     return dict(user=user)
+
+@register.inclusion_tag("staff_questionnaire_index_list.html")
+def include_staff_questionnaire_index_list(questionnaires, headline):
+    return dict(questionnaires=questionnaires, headline=headline)


Test patch:
Repository: e-valuation/EvaP

Issue:
New course form has no "add another"
In the "new course" form the link to add another contributor is missing.



Discussion:

Resolving patch:
diff --git a/evap/staff/views.py b/evap/staff/views.py
--- a/evap/staff/views.py
+++ b/evap/staff/views.py
@@ -299,7 +299,7 @@ def course_create(request, semester_id):
         messages.success(request, _("Successfully created course."))
         return redirect('evap.staff.views.semester_view', semester_id)
     else:
-        return render(request, "staff_course_form.html", dict(semester=semester, form=form, formset=formset))
+        return render(request, "staff_course_form.html", dict(semester=semester, form=form, formset=formset, staff=True))
 
 
 @staff_required


Test patch:
Repository: e-valuation/EvaP

Issue:
separate questionnaire types on FSR overview page
separate lists for course questionnaires and contributor questionnaires would be cool.



Discussion:

Resolving patch:
diff --git a/evap/staff/views.py b/evap/staff/views.py
--- a/evap/staff/views.py
+++ b/evap/staff/views.py
@@ -35,7 +35,8 @@ def get_tab(request):
 @staff_required
 def index(request):
     template_data = dict(semesters=Semester.objects.all(),
-                         questionnaires=Questionnaire.objects.filter(obsolete=False),
+                         questionnaires_courses=Questionnaire.objects.filter(obsolete=False,is_for_contributors=False),
+                         questionnaire_contributors=Questionnaire.objects.filter(obsolete=False,is_for_contributors=True),
                          templates=EmailTemplate.objects.all(),
                          sections=FaqSection.objects.all(),
                          disable_breadcrumb_staff=True)


Test patch:
Repository: e-valuation/EvaP

Issue:
Results page: Visual representation of the ratings
The participation ("Beteiligung") is currently represented visually. In contrast, the rating is not expressed in a similar way which leads to confusion as some interpreted the participation as the visual representation of the rating.

We need some visual encoding for the average rating. We need to find the a good way how this can be done.



Discussion:
The average and the median grade on the results page of a semester should get a rectangle behind them which is colored with respect to the grade.

please assign me and @Felerius 


Resolving patch:
diff --git a/evap/evaluation/templatetags/morefilters.py b/evap/evaluation/templatetags/morefilters.py
--- a/evap/evaluation/templatetags/morefilters.py
+++ b/evap/evaluation/templatetags/morefilters.py
@@ -1,12 +1,16 @@
 from django import template
 from django.conf import settings
 from django.template import Library
-from evap.evaluation.tools import LIKERT_NAMES, GRADE_NAMES, STATES_ORDERED, STUDENT_STATES_ORDERED
+from evap.evaluation.tools import LIKERT_NAMES, GRADE_NAMES, STATES_ORDERED, STUDENT_STATES_ORDERED, get_grade_color
 from evap.rewards.tools import can_user_use_reward_points
 
 register = Library()
 
 
+@register.filter(name='gradecolor')
+def gradecolor(grade):
+    return 'rgb({}, {}, {})'.format(*get_grade_color(grade))
+
 # from http://www.jongales.com/blog/2009/10/19/percentage-django-template-tag/
 @register.filter(name='percentage')
 def percentage(fraction, population):
diff --git a/evap/evaluation/tools.py b/evap/evaluation/tools.py
--- a/evap/evaluation/tools.py
+++ b/evap/evaluation/tools.py
@@ -6,6 +6,15 @@
 
 from collections import OrderedDict, defaultdict
 from collections import namedtuple
+from math import ceil
+
+GRADE_COLORS = {
+    1: (136, 191, 74),
+    2: (187, 209, 84),
+    3: (239, 226, 88),
+    4: (242, 158, 88),
+    5: (235,  89, 90),
+}
 
 LIKERT_NAMES = {
     1: _(u"Strongly agree"),
@@ -319,3 +328,17 @@ def user_publish_notifications(courses):
             user_notifications[course.responsible_contributor].add(course)
 
     return user_notifications
+
+def color_mix(color1, color2, fraction):
+    return tuple(
+        int(round(color1[i] * (1 - fraction) + color2[i] * fraction)) for i in range(3)
+    )
+
+def get_grade_color(grade):
+    # Can happen if no one leaves any grades. Return white because its least likely to cause problems.
+    if grade is None:
+        return (255, 255, 255)
+    grade = round(grade, 1)
+    next_lower = int(grade)
+    next_higher = int(ceil(grade))
+    return color_mix(GRADE_COLORS[next_lower], GRADE_COLORS[next_higher], grade - next_lower)


Test patch:
Repository: e-valuation/EvaP

Issue:
Editing questionnaires can destroy results
When editing a questionnaire after it was used in an evaluation, the results can be destroyed because answers are not necessarily linked to the same questions anymore.

Changes in questionnaires should not influence running and past evaluations.



Discussion:
Can you provide steps to reliably reproduce this, please? Simply editing a question title did not trigger it on my first try. ;-)

Yes, just editing doesn't destroy it. Try to remove an existing question and add a new one, then save.
Please speak to @kaifabian in case you want to work on this together with him, he planned to implement versioning for the questionnaires to resolve this problem.

@kaifabian  Did you work on this issue, do you want to continue or can I remove your assignment in preparation for the next Hackday?


Resolving patch:
diff --git a/evap/evaluation/models.py b/evap/evaluation/models.py
--- a/evap/evaluation/models.py
+++ b/evap/evaluation/models.py
@@ -101,8 +101,12 @@ def __unicode__(self):
         return self.name
 
     @property
-    def can_staff_delete(self):
+    def can_staff_edit(self):
         return not self.contributions.exists()
+    
+    @property
+    def can_staff_delete(self):
+        return self.can_staff_edit
 
 
 class Course(models.Model):
diff --git a/evap/staff/views.py b/evap/staff/views.py
--- a/evap/staff/views.py
+++ b/evap/staff/views.py
@@ -501,8 +501,8 @@ def questionnaire_edit(request, questionnaire_id):
     form = QuestionnaireForm(request.POST or None, instance=questionnaire)
     formset = QuestionFormset(request.POST or None, instance=questionnaire)
 
-    if questionnaire.obsolete:
-        messages.info(request, _("Obsolete questionnaires cannot be edited."))
+    if questionnaire.can_staff_edit:
+        messages.info(request, _("Questionnaires that are already used cannot be edited."))
         return redirect('evap.staff.views.questionnaire_index')
 
     if form.is_valid() and formset.is_valid():


Test patch:
Repository: e-valuation/EvaP

Issue:
Add a "per lecturer todo" view
Thomas Schulz created a table which looked like this
- Lecturer 1, Delegates: A, B
  - Lecture 1: status
  - Lecture 2: status
- Lecturer 2 and so on.

which obviously is quite helpful for knowing which lecturer needs a friendly reminder to approve his lectures.



Discussion:
show only prepared courses, but if a course of a lecture who still has prepared courses is already approved, this approved course should also be shown together with the delegate who approved this


Resolving patch:
diff --git a/evap/staff/urls.py b/evap/staff/urls.py
--- a/evap/staff/urls.py
+++ b/evap/staff/urls.py
@@ -17,6 +17,7 @@
     url(r"^semester/(\d+)/approve$", semester_approve),
     url(r"^semester/(\d+)/reset$", semester_revert_to_new),
     url(r"^semester/(\d+)/contributorready$", semester_contributor_ready),
+    url(r"^semester/(\d+)/todo", semester_todo),
     url(r"^semester/(\d+)/lottery$", semester_lottery),
     url(r"^semester/(\d+)/course/create$", course_create),
     url(r"^semester/(\d+)/course/(\d+)/edit$", course_edit),
diff --git a/evap/staff/views.py b/evap/staff/views.py
--- a/evap/staff/views.py
+++ b/evap/staff/views.py
@@ -275,6 +275,21 @@ def semester_lottery(request, semester_id):
     template_data =dict(semester=semester, form=form, eligible=eligible, winners=winners)
     return render(request, "staff_semester_lottery.html", template_data)
 
+@staff_required
+def semester_todo(request, semester_id):
+    semester = get_object_or_404(Semester, id=semester_id)
+
+    courses = semester.course_set.filter(state__in=['prepared', 'lecturerApproved']).all()
+
+    prepared_courses = semester.course_set.filter(state__in=['prepared']).all()
+    responsibles = (course.responsible_contributor for course in prepared_courses)
+    responsibles = list(set(responsibles))
+    responsibles.sort(key = lambda responsible: (responsible.last_name, responsible.first_name))
+
+    responsible_list = [(responsible, [course for course in courses if course.responsible_contributor.id == responsible.id], responsible.delegates.all()) for responsible in responsibles]
+
+    template_data = dict(semester=semester, responsible_list=responsible_list)
+    return render(request, "staff_semester_todo.html", template_data)
 
 @staff_required
 def course_create(request, semester_id):


Test patch:
Repository: e-valuation/EvaP

Issue:
calculate results upon publishing, cache indefinitely
currently, results are calculated when a user wants to view them, and they are cached for one day. that means a lot of people will need to wait ~10s for the results.



Discussion:
the result preview page should not use the cache.

if e.g. a comment slipped through review and we have to remove it after publishing, we'll have to clear the cache for the respective course. do we want to account for that in code?

maybe we could add an option "refresh cache" which would delete all cached results for a semester and recalculates everything?


Resolving patch:
diff --git a/evap/evaluation/tools.py b/evap/evaluation/tools.py
--- a/evap/evaluation/tools.py
+++ b/evap/evaluation/tools.py
@@ -133,18 +133,26 @@ def get_distribution(answers):
 
 
 def calculate_results(course):
+    if course.state == "published":
+        cache_key = str.format('evap.staff.results.tools.calculate_results-{:d}', course.id)
+        prior_results = cache.get(cache_key)
+        if prior_results:
+            return prior_results
+
+    results = _calculate_results_impl(course)
+
+    if course.state == "published":
+        cache.set(cache_key, results, None)
+    return results
+
+
+def _calculate_results_impl(course):
     """Calculates the result data for a single course. Returns a list of
     `ResultSection` tuples. Each of those tuples contains the questionnaire, the
     contributor (or None), a list of single result elements, the average and
     median grades for that section (or None). The result elements are either
     `RatingResult` or `TextResult` instances."""
 
-    # return cached results if available
-    cache_key = str.format('evap.staff.results.views.calculate_results-{:d}', course.id)
-    prior_results = cache.get(cache_key)
-    if prior_results:
-        return prior_results
-
     # there will be one section per relevant questionnaire--contributor pair
     sections = []
 
@@ -184,11 +192,6 @@ def calculate_results(course):
 
         sections.append(ResultSection(questionnaire, contribution.contributor, results, section_warning))
 
-    # store results into cache
-    # XXX: What would be a good timeout here? Once public, data is not going to
-    #      change anyway.
-    cache.set(cache_key, sections, 24 * 60 * 60)
-
     return sections
 
 
diff --git a/evap/settings.py b/evap/settings.py
--- a/evap/settings.py
+++ b/evap/settings.py
@@ -23,7 +23,7 @@
 TEMPLATE_DEBUG = DEBUG
 
 # Very helpful but eats a lot of performance on sql-heavy pages.
-# Works only with DEBUG = True.
+# Works only with DEBUG = True and Django's development server (so no apache).
 ENABLE_DEBUG_TOOLBAR = False
 
 
@@ -87,6 +87,15 @@
     }
 }
 
+CACHES = {
+    'default': {
+        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
+        'OPTIONS': {
+            'MAX_ENTRIES': 1000 # note that the results alone need one entry per course
+        }
+    }
+}
+
 # Config for feedback links
 FEEDBACK_EMAIL = "webmaster@localhost"
 TRACKER_URL = "https://github.com/fsr-itse/EvaP"


Test patch:
Repository: e-valuation/EvaP

Issue:
colorize average grades on course detail pages
the numbers in the lower right should be css'd like the ones in the upper left.

![2015 04 02 17_35_57-000017](https://cloud.githubusercontent.com/assets/1891915/6967309/c4bbfc5a-d95e-11e4-89c6-62640090b0c5.png)



Discussion:

Resolving patch:
diff --git a/evap/evaluation/templatetags/evaluation_templatetags.py b/evap/evaluation/templatetags/evaluation_templatetags.py
--- a/evap/evaluation/templatetags/evaluation_templatetags.py
+++ b/evap/evaluation/templatetags/evaluation_templatetags.py
@@ -15,3 +15,7 @@ def include_sortable_form_js():
 @register.inclusion_tag("progress_bar.html")
 def include_progress_bar(done, total, large=False):
     return dict(done=done, total=total, large=large)
+
+@register.inclusion_tag("result_bar.html")
+def include_result_bar(result, show_grades, questionnaire_warning=False):
+    return dict(result=result, show_grades=show_grades, questionnaire_warning=questionnaire_warning)


Test patch:
Repository: e-valuation/EvaP

Issue:
Search field for contributor selection
The current contributor selection is a simple dropdown list with all users. Therefore you can only search for people when starting to type their first name.
This should be changed so that the dropdown is replaced by an edit field that has a dropdown option which can be manually triggered and that opens automatically when starting to type and which then only holds names that contain the typed substring (like the multiselect input alread does).

Search field for contributor selection
The current contributor selection is a simple dropdown list with all users. Therefore you can only search for people when starting to type their first name.
This should be changed so that the dropdown is replaced by an edit field that has a dropdown option which can be manually triggered and that opens automatically when starting to type and which then only holds names that contain the typed substring (like the multiselect input alread does).



Discussion:
:+1: 

assign me

@lawrencebenson please accept github group invitation

:+1: 

assign me

@lawrencebenson please accept github group invitation


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,6 +151,7 @@ class Meta:
 
 class AtLeastOneFormSet(BaseInlineFormSet):
     def clean(self):
+        super().clean()
         count = 0
         for form in self.forms:
             if form.cleaned_data and not form.cleaned_data.get('DELETE', False):


Test patch:
diff --git a/evap/staff/tests.py b/evap/staff/tests.py
--- a/evap/staff/tests.py
+++ b/evap/staff/tests.py
@@ -26,7 +26,7 @@
 
 
 def lastform(page):
-    return page.forms[max(page.forms.keys())]
+    return page.forms[max(key for key in page.forms.keys() if isinstance(key, int))]
 
 
 # taken from http://lukeplant.me.uk/blog/posts/fuzzy-testing-with-assertnumqueries/
Repository: e-valuation/EvaP

Issue:
headline css is broken
our headlines don't use h1 h2 etc anymore and look completely broken on firefox mobile.



Discussion:

Resolving patch:
diff --git a/evap/staff/templatetags/staff_templatetags.py b/evap/staff/templatetags/staff_templatetags.py
--- a/evap/staff/templatetags/staff_templatetags.py
+++ b/evap/staff/templatetags/staff_templatetags.py
@@ -9,14 +9,6 @@
 def include_staff_semester_menu():
     return dict(semesters=Semester.objects.all()[:5])
 
-@register.inclusion_tag('staff_course_selection_list.html')
-def include_staff_course_selection_list(course_forms, btn_label, empty_msg):
-    return {
-        'course_forms': course_forms,
-        'btn_label':    btn_label,
-        'empty_msg':    empty_msg
-    }
-
 @register.inclusion_tag('staff_user_labels.html')
 def include_staff_user_labels(user):
     return dict(user=user)


Test patch:
Repository: e-valuation/EvaP

Issue:
Add "public view" on results pages for staff users
For staff users there should be an option on the results pages to switch between "public view" (without comments, like students would see the page) and "complete view" (the current view including all comments).



Discussion:

Resolving patch:
diff --git a/evap/results/views.py b/evap/results/views.py
--- a/evap/results/views.py
+++ b/evap/results/views.py
@@ -72,11 +72,14 @@ def course_detail(request, semester_id, course_id):
 
     sections = calculate_results(course)
 
+    public_view = request.GET.get('public_view', 'false') # default: show own view
+    public_view = {'true': True, 'false': False}.get(public_view.lower()) # convert parameter to boolean
+
     for section in sections:
         results = []
         for result in section.results:
             if isinstance(result, TextResult):
-                answers = [answer for answer in result.answers if user_can_see_text_answer(request.user, answer)]
+                answers = [answer for answer in result.answers if user_can_see_text_answer(request.user, answer, public_view)]
                 if answers:
                     results.append(TextResult(question=result.question, answers=answers))
             else:
@@ -113,10 +116,14 @@ def course_detail(request, semester_id, course_id):
             evaluation_warning=evaluation_warning,
             sufficient_votes_warning=sufficient_votes_warning,
             show_grades=show_grades,
-            staff=request.user.is_staff)
+            staff=request.user.is_staff,
+            contributor=course.is_user_contributor_or_delegate(request.user),
+            public_view=public_view)
     return render(request, "results_course_detail.html", template_data)
 
-def user_can_see_text_answer(user, text_answer):
+def user_can_see_text_answer(user, text_answer, public_view=False):
+    if public_view:
+        return False
     if user.is_staff:
         return True
     contributor = text_answer.contribution.contributor


Test patch:
Repository: e-valuation/EvaP

Issue:
Reminder emails should show number of days left for evaluation
Reminder emails informing students that the evaluation period of one of their courses ends should include the number of days that is left for evaluation for each course that is listed in the message.



Discussion:

Resolving patch:
diff --git a/evap/evaluation/models.py b/evap/evaluation/models.py
--- a/evap/evaluation/models.py
+++ b/evap/evaluation/models.py
@@ -985,10 +985,10 @@ def __send_to_user(cls, user, template, subject_params, body_params, cc):
 
 
     @classmethod
-    def send_reminder_to_user(cls, user, due_in_number_of_days, due_courses):
+    def send_reminder_to_user(cls, user, first_due_in_days, due_courses):
         template = cls.objects.get(name=cls.STUDENT_REMINDER)
-        subject_params = {'user': user, 'due_in_number_of_days': due_in_number_of_days}
-        body_params = {'user': user, 'due_in_number_of_days': due_in_number_of_days, 'due_courses': due_courses}
+        subject_params = {'user': user, 'first_due_in_days': first_due_in_days}
+        body_params = {'user': user, 'first_due_in_days': first_due_in_days, 'due_courses': due_courses}
 
         cls.__send_to_user(user, template, subject_params, body_params, cc=False)
 
diff --git a/evap/staff/management/commands/run_tasks.py b/evap/staff/management/commands/run_tasks.py
--- a/evap/staff/management/commands/run_tasks.py
+++ b/evap/staff/management/commands/run_tasks.py
@@ -1,4 +1,5 @@
 import datetime
+import operator
 
 from django.core.management.base import BaseCommand
 from django.conf import settings
@@ -24,10 +25,14 @@ def check_reminders(self):
             recipients.update(course.due_participants)
 
         for recipient in recipients:
-            due_courses = list(set(Course.objects.filter(participants=recipient, state='inEvaluation').exclude(voters=recipient)))
-            due_in_number_of_days = min((course.vote_end_date - datetime.date.today()).days for course in due_courses)
-
-            EmailTemplate.send_reminder_to_user(recipient, due_in_number_of_days=due_in_number_of_days, due_courses=due_courses)
+            due_courses = dict()
+            for course in Course.objects.filter(participants=recipient, state='inEvaluation').exclude(voters=recipient):
+                due_courses[course] = (course.vote_end_date - datetime.date.today()).days
+            first_due_in_days = min(due_courses.values())
+            # sort courses by number of days left for evaluation and bring them to following format: [(course, due_in_days), ...]
+            due_courses = sorted(due_courses.items(), key=operator.itemgetter(1))
+
+            EmailTemplate.send_reminder_to_user(recipient, first_due_in_days=first_due_in_days, due_courses=due_courses)
 
     def handle(self, *args, **options):
         if len(args) > 0 and args[0] == 'daily':


Test patch: