prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <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).
  
  
  </issue>
  <code>
  [start of evap/results/views.py]
  1 from django.http import HttpResponse
  2 from django.core.exceptions import PermissionDenied
  3 from django.shortcuts import get_object_or_404, render
  4 from django.utils.translation import get_language
  5 from django.contrib.auth.decorators import login_required
  6 
  7 from evap.evaluation.auth import staff_required
  8 from evap.evaluation.models import Semester, Degree
  9 from evap.evaluation.tools import calculate_results, calculate_average_grades_and_deviation, TextResult
  10 
  11 from evap.results.exporters import ExcelExporter
  12 
  13 from collections import OrderedDict, namedtuple
  14 
  15 
  16 @login_required
  17 def index(request):
  18     semesters = Semester.get_all_with_published_courses()
  19 
  20     return render(request, "results_index.html", dict(semesters=semesters))
  21 
  22 
  23 @login_required
  24 def semester_detail(request, semester_id):
  25     semester = get_object_or_404(Semester, id=semester_id)
  26     courses = list(semester.course_set.filter(state="published").prefetch_related("degrees"))
  27 
  28     # annotate each course object with its grades
  29     for course in courses:
  30         course.avg_grade, course.avg_deviation = calculate_average_grades_and_deviation(course)
  31 
  32     CourseTuple = namedtuple('CourseTuple', ('courses', 'single_results'))
  33 
  34     courses_by_degree = OrderedDict()
  35     for degree in Degree.objects.all():
  36         courses_by_degree[degree] = CourseTuple([], [])
  37     for course in courses:
  38         if course.is_single_result():
  39             for degree in course.degrees.all():
  40                 section = calculate_results(course)[0]
  41                 result = section.results[0]
  42                 courses_by_degree[degree].single_results.append((course, result))
  43         else:
  44             for degree in course.degrees.all():
  45                 courses_by_degree[degree].courses.append(course)
  46 
  47     template_data = dict(semester=semester, courses_by_degree=courses_by_degree, staff=request.user.is_staff)
  48     return render(request, "results_semester_detail.html", template_data)
  49 
  50 
  51 @staff_required
  52 def semester_export(request, semester_id):
  53     semester = get_object_or_404(Semester, id=semester_id)
  54 
  55     filename = "Evaluation-%s-%s.xls" % (semester.name, get_language())
  56 
  57     response = HttpResponse(content_type="application/vnd.ms-excel")
  58     response["Content-Disposition"] = "attachment; filename=\"%s\"" % filename
  59 
  60     ExcelExporter(semester).export(response, 'all' in request.GET)
  61 
  62     return response
  63 
  64 
  65 @login_required
  66 def course_detail(request, semester_id, course_id):
  67     semester = get_object_or_404(Semester, id=semester_id)
  68     course = get_object_or_404(semester.course_set, id=course_id)
  69 
  70     if not course.can_user_see_results(request.user):
  71         raise PermissionDenied
  72 
  73     sections = calculate_results(course)
  74 
  75     for section in sections:
  76         results = []
  77         for result in section.results:
  78             if isinstance(result, TextResult):
  79                 answers = [answer for answer in result.answers if user_can_see_text_answer(request.user, answer)]
  80                 if answers:
  81                     results.append(TextResult(question=result.question, answers=answers))
  82             else:
  83                 results.append(result)
  84         section.results[:] = results
  85 
  86     # filter empty sections and group by contributor
  87     course_sections = []
  88     contributor_sections = OrderedDict()
  89     for section in sections:
  90         if not section.results:
  91             continue
  92         if section.contributor is None:
  93             course_sections.append(section)
  94         else:
  95             contributor_sections.setdefault(section.contributor, []).append(section)
  96 
  97     # show a warning if course is still in evaluation (for staff preview)
  98     evaluation_warning = course.state != 'published'
  99 
  100     # results for a course might not be visible because there are not enough answers
  101     # but it can still be "published" e.g. to show the comment results to contributors.
  102     # users who can open the results page see a warning message in this case
  103     sufficient_votes_warning = not course.can_publish_grades
  104 
  105     show_grades = request.user.is_staff or course.can_publish_grades
  106 
  107     course.avg_grade, course.avg_deviation = calculate_average_grades_and_deviation(course)
  108 
  109     template_data = dict(
  110             course=course,
  111             course_sections=course_sections,
  112             contributor_sections=contributor_sections,
  113             evaluation_warning=evaluation_warning,
  114             sufficient_votes_warning=sufficient_votes_warning,
  115             show_grades=show_grades,
  116             staff=request.user.is_staff)
  117     return render(request, "results_course_detail.html", template_data)
  118 
  119 def user_can_see_text_answer(user, text_answer):
  120     if user.is_staff:
  121         return True
  122     contributor = text_answer.contribution.contributor
  123     if text_answer.is_private:
  124         return contributor == user
  125     if text_answer.is_published:
  126         if contributor == user or contributor in user.represented_users.all():
  127             return True
  128         if text_answer.contribution.course.is_user_responsible_or_delegate(user):
  129             return True
  130 
  131     return False
  132
  [end of evap/results/views.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: 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 @@
   
       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 @@
               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
  
verification_info: {"golden_diff": "diff --git a/evap/results/views.py b/evap/results/views.py\n--- a/evap/results/views.py\n+++ b/evap/results/views.py\n@@ -72,11 +72,14 @@\n \n     sections = calculate_results(course)\n \n+    public_view = request.GET.get('public_view', 'false') # default: show own view\n+    public_view = {'true': True, 'false': False}.get(public_view.lower()) # convert parameter to boolean\n+\n     for section in sections:\n         results = []\n         for result in section.results:\n             if isinstance(result, TextResult):\n-                answers = [answer for answer in result.answers if user_can_see_text_answer(request.user, answer)]\n+                answers = [answer for answer in result.answers if user_can_see_text_answer(request.user, answer, public_view)]\n                 if answers:\n                     results.append(TextResult(question=result.question, answers=answers))\n             else:\n@@ -113,10 +116,14 @@\n             evaluation_warning=evaluation_warning,\n             sufficient_votes_warning=sufficient_votes_warning,\n             show_grades=show_grades,\n-            staff=request.user.is_staff)\n+            staff=request.user.is_staff,\n+            contributor=course.is_user_contributor_or_delegate(request.user),\n+            public_view=public_view)\n     return render(request, \"results_course_detail.html\", template_data)\n \n-def user_can_see_text_answer(user, text_answer):\n+def user_can_see_text_answer(user, text_answer, public_view=False):\n+    if public_view:\n+        return False\n     if user.is_staff:\n         return True\n     contributor = text_answer.contribution.contributor\n", "issue": "Add \"public view\" on results pages for staff users\nFor 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).\n\n", "before_files": [{"content": "from django.http import HttpResponse\nfrom django.core.exceptions import PermissionDenied\nfrom django.shortcuts import get_object_or_404, render\nfrom django.utils.translation import get_language\nfrom django.contrib.auth.decorators import login_required\n\nfrom evap.evaluation.auth import staff_required\nfrom evap.evaluation.models import Semester, Degree\nfrom evap.evaluation.tools import calculate_results, calculate_average_grades_and_deviation, TextResult\n\nfrom evap.results.exporters import ExcelExporter\n\nfrom collections import OrderedDict, namedtuple\n\n\n@login_required\ndef index(request):\n    semesters = Semester.get_all_with_published_courses()\n\n    return render(request, \"results_index.html\", dict(semesters=semesters))\n\n\n@login_required\ndef semester_detail(request, semester_id):\n    semester = get_object_or_404(Semester, id=semester_id)\n    courses = list(semester.course_set.filter(state=\"published\").prefetch_related(\"degrees\"))\n\n    # annotate each course object with its grades\n    for course in courses:\n        course.avg_grade, course.avg_deviation = calculate_average_grades_and_deviation(course)\n\n    CourseTuple = namedtuple('CourseTuple', ('courses', 'single_results'))\n\n    courses_by_degree = OrderedDict()\n    for degree in Degree.objects.all():\n        courses_by_degree[degree] = CourseTuple([], [])\n    for course in courses:\n        if course.is_single_result():\n            for degree in course.degrees.all():\n                section = calculate_results(course)[0]\n                result = section.results[0]\n                courses_by_degree[degree].single_results.append((course, result))\n        else:\n            for degree in course.degrees.all():\n                courses_by_degree[degree].courses.append(course)\n\n    template_data = dict(semester=semester, courses_by_degree=courses_by_degree, staff=request.user.is_staff)\n    return render(request, \"results_semester_detail.html\", template_data)\n\n\n@staff_required\ndef semester_export(request, semester_id):\n    semester = get_object_or_404(Semester, id=semester_id)\n\n    filename = \"Evaluation-%s-%s.xls\" % (semester.name, get_language())\n\n    response = HttpResponse(content_type=\"application/vnd.ms-excel\")\n    response[\"Content-Disposition\"] = \"attachment; filename=\\\"%s\\\"\" % filename\n\n    ExcelExporter(semester).export(response, 'all' in request.GET)\n\n    return response\n\n\n@login_required\ndef course_detail(request, semester_id, course_id):\n    semester = get_object_or_404(Semester, id=semester_id)\n    course = get_object_or_404(semester.course_set, id=course_id)\n\n    if not course.can_user_see_results(request.user):\n        raise PermissionDenied\n\n    sections = calculate_results(course)\n\n    for section in sections:\n        results = []\n        for result in section.results:\n            if isinstance(result, TextResult):\n                answers = [answer for answer in result.answers if user_can_see_text_answer(request.user, answer)]\n                if answers:\n                    results.append(TextResult(question=result.question, answers=answers))\n            else:\n                results.append(result)\n        section.results[:] = results\n\n    # filter empty sections and group by contributor\n    course_sections = []\n    contributor_sections = OrderedDict()\n    for section in sections:\n        if not section.results:\n            continue\n        if section.contributor is None:\n            course_sections.append(section)\n        else:\n            contributor_sections.setdefault(section.contributor, []).append(section)\n\n    # show a warning if course is still in evaluation (for staff preview)\n    evaluation_warning = course.state != 'published'\n\n    # results for a course might not be visible because there are not enough answers\n    # but it can still be \"published\" e.g. to show the comment results to contributors.\n    # users who can open the results page see a warning message in this case\n    sufficient_votes_warning = not course.can_publish_grades\n\n    show_grades = request.user.is_staff or course.can_publish_grades\n\n    course.avg_grade, course.avg_deviation = calculate_average_grades_and_deviation(course)\n\n    template_data = dict(\n            course=course,\n            course_sections=course_sections,\n            contributor_sections=contributor_sections,\n            evaluation_warning=evaluation_warning,\n            sufficient_votes_warning=sufficient_votes_warning,\n            show_grades=show_grades,\n            staff=request.user.is_staff)\n    return render(request, \"results_course_detail.html\", template_data)\n\ndef user_can_see_text_answer(user, text_answer):\n    if user.is_staff:\n        return True\n    contributor = text_answer.contribution.contributor\n    if text_answer.is_private:\n        return contributor == user\n    if text_answer.is_published:\n        if contributor == user or contributor in user.represented_users.all():\n            return True\n        if text_answer.contribution.course.is_user_responsible_or_delegate(user):\n            return True\n\n    return False\n", "path": "evap/results/views.py"}]}