Exemplo n.º 1
0
def warm_up_template_cache(evaluations):
    evaluations = get_evaluations_with_course_result_attributes(get_evaluations_with_prefetched_data(evaluations))
    current_language = translation.get_language()
    courses_to_render = {evaluation.course for evaluation in evaluations if evaluation.course.evaluation_count > 1}
    try:
        for course in courses_to_render:
            translation.activate("en")
            get_template("results_index_course.html").render(dict(course=course))
            translation.activate("de")
            get_template("results_index_course.html").render(dict(course=course))
            assert get_course_result_template_fragment_cache_key(course.id, "en") in caches["results"]
            assert get_course_result_template_fragment_cache_key(course.id, "de") in caches["results"]
        for evaluation in evaluations:
            assert evaluation.state in STATES_WITH_RESULT_TEMPLATE_CACHING
            is_subentry = evaluation.course.evaluation_count > 1
            translation.activate("en")
            get_template("results_index_evaluation.html").render(
                dict(evaluation=evaluation, links_to_results_page=True, is_subentry=is_subentry)
            )
            get_template("results_index_evaluation.html").render(
                dict(evaluation=evaluation, links_to_results_page=False, is_subentry=is_subentry)
            )
            translation.activate("de")
            get_template("results_index_evaluation.html").render(
                dict(evaluation=evaluation, links_to_results_page=True, is_subentry=is_subentry)
            )
            get_template("results_index_evaluation.html").render(
                dict(evaluation=evaluation, links_to_results_page=False, is_subentry=is_subentry)
            )
            assert get_evaluation_result_template_fragment_cache_key(evaluation.id, "en", True) in caches["results"]
            assert get_evaluation_result_template_fragment_cache_key(evaluation.id, "en", False) in caches["results"]
            assert get_evaluation_result_template_fragment_cache_key(evaluation.id, "de", True) in caches["results"]
            assert get_evaluation_result_template_fragment_cache_key(evaluation.id, "de", False) in caches["results"]
    finally:
        translation.activate(current_language)  # reset to previously set language to prevent unwanted side effects
Exemplo n.º 2
0
def index(request):
    semesters = Semester.get_all_with_published_unarchived_results()
    evaluations = Evaluation.objects.filter(course__semester__in=semesters,
                                            state='published')
    evaluations = [
        evaluation for evaluation in evaluations
        if evaluation.can_user_see_evaluation(request.user)
    ]

    if request.user.is_reviewer:
        additional_evaluations = get_evaluations_with_prefetched_data(
            Evaluation.objects.filter(
                course__semester__in=semesters,
                state__in=['in_evaluation', 'evaluated', 'reviewed']))
        additional_evaluations = get_evaluations_with_course_result_attributes(
            additional_evaluations)
        evaluations += additional_evaluations

    evaluations.sort(
        key=lambda evaluation:
        (evaluation.course.semester.pk, evaluation.full_name
         ))  # evaluations must be sorted for regrouping them in the template

    evaluation_pks = [evaluation.pk for evaluation in evaluations]
    degrees = Degree.objects.filter(
        courses__evaluations__pk__in=evaluation_pks).distinct()
    course_types = CourseType.objects.filter(
        courses__evaluations__pk__in=evaluation_pks).distinct()
    template_data = dict(
        evaluations=evaluations,
        degrees=degrees,
        course_types=course_types,
        semesters=semesters,
    )
    return render(request, "results_index.html", template_data)
Exemplo n.º 3
0
def get_evaluations_of_course(course, request):
    course_evaluations = []

    if course.evaluations.count() > 1:
        course_evaluations = [
            evaluation
            for evaluation in course.evaluations.filter(state="published")
            if evaluation.can_be_seen_by(request.user)
        ]
        if request.user.is_reviewer:
            course_evaluations += course.evaluations.filter(
                state__in=['in_evaluation', 'evaluated', 'reviewed'])

        course_evaluations = get_evaluations_with_course_result_attributes(
            course_evaluations)

        for course_evaluation in course_evaluations:
            if course_evaluation.is_single_result:
                course_evaluation.single_result_rating_result = get_single_result_rating_result(
                    course_evaluation)
            else:
                course_evaluation.distribution = calculate_average_distribution(
                    course_evaluation)
                course_evaluation.avg_grade = distribution_to_grade(
                    course_evaluation.distribution)

    return course_evaluations
Exemplo n.º 4
0
def warm_up_template_cache(evaluations):
    evaluations = get_evaluations_with_course_result_attributes(get_evaluations_with_prefetched_data(evaluations))
    current_language = translation.get_language()
    courses_to_render = set([evaluation.course for evaluation in evaluations if evaluation.course.evaluation_count > 1])
    try:
        for course in courses_to_render:
            translation.activate('en')
            get_template('results_index_course.html').render(dict(course=course))
            translation.activate('de')
            get_template('results_index_course.html').render(dict(course=course))
            assert get_course_result_template_fragment_cache_key(course.id, 'en') in caches['results']
            assert get_course_result_template_fragment_cache_key(course.id, 'de') in caches['results']
        for evaluation in evaluations:
            assert evaluation.state == 'published'
            is_subentry = evaluation.course.evaluation_count > 1
            translation.activate('en')
            get_template('results_index_evaluation.html').render(dict(evaluation=evaluation, can_user_see_results_page=True, is_subentry=is_subentry))
            get_template('results_index_evaluation.html').render(dict(evaluation=evaluation, can_user_see_results_page=False, is_subentry=is_subentry))
            translation.activate('de')
            get_template('results_index_evaluation.html').render(dict(evaluation=evaluation, can_user_see_results_page=True, is_subentry=is_subentry))
            get_template('results_index_evaluation.html').render(dict(evaluation=evaluation, can_user_see_results_page=False, is_subentry=is_subentry))
            assert get_evaluation_result_template_fragment_cache_key(evaluation.id, 'en', True) in caches['results']
            assert get_evaluation_result_template_fragment_cache_key(evaluation.id, 'en', False) in caches['results']
            assert get_evaluation_result_template_fragment_cache_key(evaluation.id, 'de', True) in caches['results']
            assert get_evaluation_result_template_fragment_cache_key(evaluation.id, 'de', False) in caches['results']
    finally:
        translation.activate(current_language)  # reset to previously set language to prevent unwanted side effects
Exemplo n.º 5
0
def index(request):
    semesters = Semester.get_all_with_published_unarchived_results()
    evaluations = Evaluation.objects.filter(course__semester__in=semesters, state='published')
    evaluations = [evaluation for evaluation in evaluations if evaluation.can_be_seen_by(request.user)]

    if request.user.is_reviewer:
        additional_evaluations = get_evaluations_with_prefetched_data(
            Evaluation.objects.filter(
                course__semester__in=semesters,
                state__in=['in_evaluation', 'evaluated', 'reviewed']
            )
        )
        additional_evaluations = get_evaluations_with_course_result_attributes(additional_evaluations)
        evaluations += additional_evaluations

    evaluations.sort(key=lambda evaluation: (evaluation.course.semester.pk, evaluation.full_name))  # evaluations must be sorted for regrouping them in the template

    evaluation_pks = [evaluation.pk for evaluation in evaluations]
    degrees = Degree.objects.filter(courses__evaluations__pk__in=evaluation_pks).distinct()
    course_types = CourseType.objects.filter(courses__evaluations__pk__in=evaluation_pks).distinct()
    template_data = dict(
        evaluations=evaluations,
        degrees=degrees,
        course_types=course_types,
        semesters=semesters,
    )
    return render(request, "results_index.html", template_data)
Exemplo n.º 6
0
def index(request):
    # retrieve all courses which have evaluations that are not in state "new" and in which the user participates
    courses = Course.objects.filter(
        evaluations__participants=request.user,
        evaluations__state__in=['prepared', 'editor_approved', 'approved', 'in_evaluation', 'evaluated', 'reviewed', 'published']
    ).distinct()
    # retrieve all evaluations which the user can see that are not new
    evaluations = [evaluation for course in courses for evaluation in course.evaluations.all() if evaluation.can_be_seen_by(request.user)]
    for evaluation in evaluations:
        if evaluation.state == "published":
            if not evaluation.is_single_result:
                evaluation.distribution = calculate_average_distribution(evaluation)
                evaluation.avg_grade = distribution_to_grade(evaluation.distribution)
            else:
                evaluation.single_result_rating_result = get_single_result_rating_result(evaluation)
        evaluation.participates_in = request.user in evaluation.participants.all()
        evaluation.voted_for = request.user in evaluation.voters.all()
    evaluations = get_evaluations_with_course_result_attributes(evaluations)
    evaluations.sort(key=lambda evaluation: evaluation.full_name)  # evaluations must be sorted for regrouping them in the template

    semesters = Semester.objects.all()
    semester_list = [dict(
        semester_name=semester.name,
        id=semester.id,
        is_active_semester=semester.is_active_semester,
        results_are_archived=semester.results_are_archived,
        grade_documents_are_deleted=semester.grade_documents_are_deleted,
        evaluations=[evaluation for evaluation in evaluations if evaluation.course.semester_id == semester.id]
    ) for semester in semesters]

    template_data = dict(
        semester_list=semester_list,
        can_download_grades=request.user.can_download_grades,
    )
    return render(request, "student_index.html", template_data)
Exemplo n.º 7
0
def index(request):
    user = request.user
    show_delegated = get_parameter_from_url_or_session(request, "show_delegated", True)

    contributor_visible_states = ['prepared', 'editor_approved', 'approved', 'in_evaluation', 'evaluated', 'reviewed', 'published']
    own_courses = Course.objects.filter(
        Q(evaluations__state__in=contributor_visible_states) & (
            Q(responsibles=user) |
            Q(evaluations__contributions__contributor=user)
        )
    )
    own_evaluations = [evaluation for course in own_courses for evaluation in course.evaluations.all() if evaluation.can_be_seen_by(user)]
    for evaluation in own_evaluations:
        evaluation.contributes_to = evaluation.contributions.filter(contributor=user).exists()

    displayed_evaluations = set(own_evaluations)
    if show_delegated:
        represented_users = user.represented_users.all()
        delegated_courses = Course.objects.filter(
            Q(evaluations__state__in=contributor_visible_states) & (
                Q(responsibles__in=represented_users) |
                Q(
                    evaluations__contributions__role=Contribution.Role.EDITOR,
                    evaluations__contributions__contributor__in=represented_users,
                )
            )
        )
        delegated_evaluations = set(evaluation for course in delegated_courses for evaluation in course.evaluations.all() if evaluation.can_be_seen_by(user))
        for evaluation in delegated_evaluations:
            evaluation.delegated_evaluation = True
        displayed_evaluations |= delegated_evaluations - displayed_evaluations
    displayed_evaluations = list(displayed_evaluations)
    displayed_evaluations.sort(key=lambda evaluation: (evaluation.course.name, evaluation.name))  # evaluations must be sorted for regrouping them in the template

    for evaluation in displayed_evaluations:
        if evaluation.state == "published":
            if not evaluation.is_single_result:
                evaluation.distribution = calculate_average_distribution(evaluation)
            else:
                evaluation.single_result_rating_result = get_single_result_rating_result(evaluation)
                evaluation.distribution = normalized_distribution(evaluation.single_result_rating_result.counts)
            evaluation.avg_grade = distribution_to_grade(evaluation.distribution)
    displayed_evaluations = get_evaluations_with_course_result_attributes(displayed_evaluations)

    semesters = Semester.objects.all()
    semester_list = [dict(
        semester_name=semester.name,
        id=semester.id,
        is_active=semester.is_active,
        evaluations=[evaluation for evaluation in displayed_evaluations if evaluation.course.semester_id == semester.id]
    ) for semester in semesters]

    template_data = dict(
        semester_list=semester_list,
        show_delegated=show_delegated,
        delegate_selection_form=DelegateSelectionForm(),
    )
    return render(request, "contributor_index.html", template_data)
Exemplo n.º 8
0
def evaluation_detail(request, semester_id, evaluation_id):
    # pylint: disable=too-many-locals
    semester = get_object_or_404(Semester, id=semester_id)
    evaluation = get_object_or_404(semester.evaluations, id=evaluation_id, course__semester=semester)

    view, view_as_user, represented_users, contributor_id = evaluation_detail_parse_get_parameters(request, evaluation)

    evaluation_result = get_results(evaluation)
    remove_textanswers_that_the_user_must_not_see(evaluation_result, view_as_user, represented_users, view)
    exclude_empty_headings(evaluation_result)
    remove_empty_questionnaire_and_contribution_results(evaluation_result)
    add_warnings(evaluation, evaluation_result)

    top_results, bottom_results, contributor_results = split_evaluation_result_into_top_bottom_and_contributor(
        evaluation_result, view_as_user, view
    )

    course_evaluations = get_evaluations_of_course(evaluation.course, request)
    course_evaluations.sort(key=lambda evaluation: evaluation.name)

    contributors_with_omitted_results = []
    if view == "export":
        contributors_with_omitted_results = [
            contribution_result.contributor
            for contribution_result in evaluation_result.contribution_results
            if contribution_result.contributor not in [None, view_as_user]
        ]

    # if the results are not cached, we need to attach distribution
    # information for rendering the distribution bar
    if evaluation.state not in STATES_WITH_RESULT_TEMPLATE_CACHING:
        prefetched = get_evaluations_with_prefetched_data([evaluation])
        evaluation = get_evaluations_with_course_result_attributes(prefetched)[0]

    is_responsible_or_contributor_or_delegate = evaluation.is_user_responsible_or_contributor_or_delegate(view_as_user)

    template_data = dict(
        evaluation=evaluation,
        course=evaluation.course,
        course_evaluations=course_evaluations,
        general_questionnaire_results_top=top_results,
        general_questionnaire_results_bottom=bottom_results,
        contributor_contribution_results=contributor_results,
        is_reviewer=view_as_user.is_reviewer,
        is_contributor=evaluation.is_user_contributor(view_as_user),
        is_responsible_or_contributor_or_delegate=is_responsible_or_contributor_or_delegate,
        can_download_grades=view_as_user.can_download_grades,
        can_export_text_answers=(
            view in ("export", "full") and (view_as_user.is_reviewer or is_responsible_or_contributor_or_delegate)
        ),
        view=view,
        view_as_user=view_as_user,
        contributors_with_omitted_results=contributors_with_omitted_results,
        contributor_id=contributor_id,
    )
    return render(request, "results_evaluation_detail.html", template_data)
Exemplo n.º 9
0
def index(request):
    # retrieve all courses which have evaluations that are not in state "new" and in which the user participates
    courses = Course.objects.filter(
        evaluations__participants=request.user,
        evaluations__state__in=[
            'prepared', 'editor_approved', 'approved', 'in_evaluation',
            'evaluated', 'reviewed', 'published'
        ]).distinct().prefetch_related('semester', 'grade_documents', 'type',
                                       'evaluations',
                                       'evaluations__participants',
                                       'evaluations__voters')
    # retrieve all evaluations which the user can see that are not new
    evaluations = [
        evaluation for course in courses
        for evaluation in course.evaluations.all()
        if evaluation.can_be_seen_by(request.user)
    ]
    for evaluation in evaluations:
        if evaluation.state == "published":
            if not evaluation.is_single_result:
                evaluation.distribution = calculate_average_distribution(
                    evaluation)
            else:
                evaluation.single_result_rating_result = get_single_result_rating_result(
                    evaluation)
                evaluation.distribution = normalized_distribution(
                    evaluation.single_result_rating_result.counts)
            evaluation.avg_grade = distribution_to_grade(
                evaluation.distribution)
        evaluation.participates_in = request.user in evaluation.participants.all(
        )
        evaluation.voted_for = request.user in evaluation.voters.all()
    evaluations = get_evaluations_with_course_result_attributes(evaluations)
    evaluations.sort(
        key=lambda evaluation: (evaluation.course.name, evaluation.name)
    )  # evaluations must be sorted for regrouping them in the template

    semesters = Semester.objects.all()
    semester_list = [
        dict(semester_name=semester.name,
             id=semester.id,
             is_active=semester.is_active,
             results_are_archived=semester.results_are_archived,
             grade_documents_are_deleted=semester.grade_documents_are_deleted,
             evaluations=[
                 evaluation for evaluation in evaluations
                 if evaluation.course.semester_id == semester.id
             ]) for semester in semesters
    ]

    template_data = dict(
        semester_list=semester_list,
        can_download_grades=request.user.can_download_grades,
    )

    return render(request, "student_index.html", template_data)
Exemplo n.º 10
0
def index(request):
    user = request.user
    show_delegated = get_parameter_from_url_or_session(request, "show_delegated", True)

    contributor_visible_states = ['prepared', 'editor_approved', 'approved', 'in_evaluation', 'evaluated', 'reviewed', 'published']
    own_courses = Course.objects.filter(
        Q(evaluations__state__in=contributor_visible_states) & (
            Q(responsibles=user) |
            Q(evaluations__contributions__contributor=user)
        )
    )
    own_evaluations = [evaluation for course in own_courses for evaluation in course.evaluations.all() if evaluation.can_be_seen_by(user)]
    for evaluation in own_evaluations:
        evaluation.contributes_to = evaluation.contributions.filter(contributor=user).exists()

    displayed_evaluations = set(own_evaluations)
    if show_delegated:
        represented_users = user.represented_users.all()
        delegated_courses = Course.objects.filter(
            Q(evaluations__state__in=contributor_visible_states) & (
                Q(responsibles__in=represented_users) |
                Q(evaluations__contributions__can_edit=True, evaluations__contributions__contributor__in=represented_users)
            )
        )
        delegated_evaluations = set(evaluation for course in delegated_courses for evaluation in course.evaluations.all() if evaluation.can_be_seen_by(user))
        for evaluation in delegated_evaluations:
            evaluation.delegated_evaluation = True
        displayed_evaluations |= delegated_evaluations - displayed_evaluations
    displayed_evaluations = list(displayed_evaluations)
    displayed_evaluations.sort(key=lambda evaluation: evaluation.full_name)  # evaluations must be sorted for regrouping them in the template

    for evaluation in displayed_evaluations:
        if evaluation.state == "published":
            if not evaluation.is_single_result:
                evaluation.distribution = calculate_average_distribution(evaluation)
                evaluation.avg_grade = distribution_to_grade(evaluation.distribution)
            else:
                evaluation.single_result_rating_result = get_single_result_rating_result(evaluation)
    displayed_evaluations = get_evaluations_with_course_result_attributes(displayed_evaluations)

    semesters = Semester.objects.all()
    semester_list = [dict(
        semester_name=semester.name,
        id=semester.id,
        is_active_semester=semester.is_active_semester,
        evaluations=[evaluation for evaluation in displayed_evaluations if evaluation.course.semester_id == semester.id]
    ) for semester in semesters]

    template_data = dict(
        semester_list=semester_list,
        show_delegated=show_delegated,
        delegate_selection_form=DelegateSelectionForm(),
    )
    return render(request, "contributor_index.html", template_data)
Exemplo n.º 11
0
def warm_up_template_cache(evaluations):
    evaluations = get_evaluations_with_course_result_attributes(
        get_evaluations_with_prefetched_data(evaluations))
    current_language = translation.get_language()
    courses_to_render = set([
        evaluation.course for evaluation in evaluations
        if evaluation.course.evaluation_count > 1
    ])
    try:
        for course in courses_to_render:
            translation.activate('en')
            get_template('results_index_course.html').render(
                dict(course=course))
            translation.activate('de')
            get_template('results_index_course.html').render(
                dict(course=course))
            assert get_course_result_template_fragment_cache_key(
                course.id, 'en') in caches['results']
            assert get_course_result_template_fragment_cache_key(
                course.id, 'de') in caches['results']
        for evaluation in evaluations:
            assert evaluation.state == 'published'
            is_subentry = evaluation.course.evaluation_count > 1
            translation.activate('en')
            get_template('results_index_evaluation.html').render(
                dict(evaluation=evaluation,
                     can_user_see_results_page=True,
                     is_subentry=is_subentry))
            get_template('results_index_evaluation.html').render(
                dict(evaluation=evaluation,
                     can_user_see_results_page=False,
                     is_subentry=is_subentry))
            translation.activate('de')
            get_template('results_index_evaluation.html').render(
                dict(evaluation=evaluation,
                     can_user_see_results_page=True,
                     is_subentry=is_subentry))
            get_template('results_index_evaluation.html').render(
                dict(evaluation=evaluation,
                     can_user_see_results_page=False,
                     is_subentry=is_subentry))
            assert get_evaluation_result_template_fragment_cache_key(
                evaluation.id, 'en', True) in caches['results']
            assert get_evaluation_result_template_fragment_cache_key(
                evaluation.id, 'en', False) in caches['results']
            assert get_evaluation_result_template_fragment_cache_key(
                evaluation.id, 'de', True) in caches['results']
            assert get_evaluation_result_template_fragment_cache_key(
                evaluation.id, 'de', False) in caches['results']
    finally:
        translation.activate(
            current_language
        )  # reset to previously set language to prevent unwanted side effects
Exemplo n.º 12
0
def index(request):
    semesters = Semester.get_all_with_published_unarchived_results()
    evaluations = Evaluation.objects.filter(course__semester__in=semesters,
                                            state=Evaluation.State.PUBLISHED)
    evaluations = evaluations.select_related("course", "course__semester")
    evaluations = [
        evaluation for evaluation in evaluations
        if evaluation.can_be_seen_by(request.user)
    ]

    if request.user.is_reviewer:
        additional_evaluations = get_evaluations_with_prefetched_data(
            Evaluation.objects.filter(
                course__semester__in=semesters,
                state__in=[
                    Evaluation.State.IN_EVALUATION, Evaluation.State.EVALUATED,
                    Evaluation.State.REVIEWED
                ],
            ))
        additional_evaluations = get_evaluations_with_course_result_attributes(
            additional_evaluations)
        evaluations += additional_evaluations

    # put evaluations into a dict that maps from course to a list of evaluations.
    # this dict is sorted by course.pk (important for the zip below)
    # (this relies on python 3.7's guarantee that the insertion order of the dict is preserved)
    evaluations.sort(key=lambda evaluation: evaluation.course.pk)
    courses_and_evaluations = unordered_groupby(
        (evaluation.course, evaluation) for evaluation in evaluations)

    course_pks = [course.pk for course in courses_and_evaluations.keys()]

    # annotate each course in courses with num_evaluations
    annotated_courses = (Course.objects.filter(pk__in=course_pks).annotate(
        num_evaluations=Count("evaluations")).order_by("pk").defer())
    for course, annotated_course in zip(courses_and_evaluations.keys(),
                                        annotated_courses):
        course.num_evaluations = annotated_course.num_evaluations

    degrees = Degree.objects.filter(courses__pk__in=course_pks).distinct()
    course_types = CourseType.objects.filter(
        courses__pk__in=course_pks).distinct()
    template_data = dict(
        courses_and_evaluations=courses_and_evaluations.items(),
        degrees=degrees,
        course_types=course_types,
        semesters=semesters,
    )
    return render(request, "results_index.html", template_data)
Exemplo n.º 13
0
def index(request):
    semesters = Semester.get_all_with_published_unarchived_results()
    evaluations = Evaluation.objects.filter(course__semester__in=semesters,
                                            state='published')
    evaluations = evaluations.select_related('course', 'course__semester')
    evaluations = [
        evaluation for evaluation in evaluations
        if evaluation.can_be_seen_by(request.user)
    ]

    if request.user.is_reviewer:
        additional_evaluations = get_evaluations_with_prefetched_data(
            Evaluation.objects.filter(
                course__semester__in=semesters,
                state__in=['in_evaluation', 'evaluated', 'reviewed']))
        additional_evaluations = get_evaluations_with_course_result_attributes(
            additional_evaluations)
        evaluations += additional_evaluations

    # put evaluations into a dict that maps from course to a list of evaluations.
    # this dict is sorted by course.pk (important for the zip below)
    # (this relies on python 3.7's guarantee that the insertion order of the dict is preserved)
    evaluations.sort(key=lambda evaluation: evaluation.course.pk)

    courses_and_evaluations = defaultdict(list)
    for evaluation in evaluations:
        courses_and_evaluations[evaluation.course].append(evaluation)

    course_pks = list([course.pk for course in courses_and_evaluations.keys()])

    # annotate each course in courses with num_evaluations
    annotated_courses = Course.objects.filter(pk__in=course_pks).annotate(
        num_evaluations=Count('evaluations')).order_by('pk').defer()
    for course, annotated_course in zip(courses_and_evaluations.keys(),
                                        annotated_courses):
        course.num_evaluations = annotated_course.num_evaluations

    degrees = Degree.objects.filter(courses__pk__in=course_pks).distinct()
    course_types = CourseType.objects.filter(
        courses__pk__in=course_pks).distinct()
    template_data = dict(
        courses_and_evaluations=courses_and_evaluations.items(),
        degrees=degrees,
        course_types=course_types,
        semesters=semesters,
    )
    return render(request, "results_index.html", template_data)
Exemplo n.º 14
0
def get_evaluations_of_course(course, request):
    course_evaluations = []

    if course.evaluations.count() > 1:
        course_evaluations = [
            evaluation for evaluation in course.evaluations.filter(
                state=Evaluation.State.PUBLISHED)
            if evaluation.can_be_seen_by(request.user)
        ]
        if request.user.is_reviewer:
            course_evaluations += course.evaluations.filter(state__in=[
                Evaluation.State.IN_EVALUATION, Evaluation.State.EVALUATED,
                Evaluation.State.REVIEWED
            ])
        annotate_distributions_and_grades(course_evaluations)
        course_evaluations = get_evaluations_with_course_result_attributes(
            course_evaluations)

    return course_evaluations
Exemplo n.º 15
0
def get_evaluations_of_course(course, request):
    course_evaluations = []

    if course.evaluations.count() > 1:
        course_evaluations = [
            evaluation
            for evaluation in course.evaluations.filter(state=Evaluation.State.PUBLISHED)
            if evaluation.can_be_seen_by(request.user)
        ]
        if request.user.is_reviewer:
            course_evaluations += course.evaluations.filter(
                state__in=[Evaluation.State.IN_EVALUATION, Evaluation.State.EVALUATED, Evaluation.State.REVIEWED]
            )

        course_evaluations = get_evaluations_with_course_result_attributes(course_evaluations)

        for course_evaluation in course_evaluations:
            if course_evaluation.is_single_result:
                course_evaluation.single_result_rating_result = get_single_result_rating_result(course_evaluation)
            else:
                course_evaluation.distribution = calculate_average_distribution(course_evaluation)
                course_evaluation.avg_grade = distribution_to_grade(course_evaluation.distribution)

    return course_evaluations
Exemplo n.º 16
0
def index(request):
    query = (Evaluation.objects.annotate(participates_in=Exists(
        Evaluation.objects.filter(id=OuterRef("id"), participants=request.user)
    )).annotate(voted_for=Exists(
        Evaluation.objects.filter(id=OuterRef(
            "id"), voters=request.user))).filter(
                ~Q(state=Evaluation.State.NEW),
                course__evaluations__participants=request.user).exclude(
                    state=Evaluation.State.NEW).prefetch_related(
                        "course",
                        "course__semester",
                        "course__grade_documents",
                        "course__type",
                        "course__evaluations",
                        "course__responsibles",
                        "course__degrees",
                    ).distinct())
    query = Evaluation.annotate_with_participant_and_voter_counts(query)
    evaluations = [
        evaluation for evaluation in query
        if evaluation.can_be_seen_by(request.user)
    ]

    inner_evaluation_ids = [
        inner_evaluation.id for evaluation in evaluations
        for inner_evaluation in evaluation.course.evaluations.all()
    ]
    inner_evaluation_query = Evaluation.objects.filter(
        pk__in=inner_evaluation_ids)
    inner_evaluation_query = Evaluation.annotate_with_participant_and_voter_counts(
        inner_evaluation_query)

    evaluations_by_id = {
        evaluation["id"]: evaluation
        for evaluation in inner_evaluation_query.values()
    }

    for evaluation in evaluations:
        for inner_evaluation in evaluation.course.evaluations.all():
            inner_evaluation.num_voters = evaluations_by_id[
                inner_evaluation.id]["num_voters"]
            inner_evaluation.num_participants = evaluations_by_id[
                inner_evaluation.id]["num_participants"]

    annotate_distributions_and_grades(e for e in evaluations
                                      if e.state == Evaluation.State.PUBLISHED)
    evaluations = get_evaluations_with_course_result_attributes(evaluations)

    # evaluations must be sorted for regrouping them in the template
    evaluations.sort(
        key=lambda evaluation: (evaluation.course.name, evaluation.name))

    semesters = Semester.objects.all()
    semester_list = [
        dict(
            semester_name=semester.name,
            id=semester.id,
            results_are_archived=semester.results_are_archived,
            grade_documents_are_deleted=semester.grade_documents_are_deleted,
            evaluations=[
                evaluation for evaluation in evaluations
                if evaluation.course.semester_id == semester.id
            ],
        ) for semester in semesters
    ]

    unfinished_evaluations_query = (Evaluation.objects.filter(
        participants=request.user,
        state__in=[
            Evaluation.State.PREPARED,
            Evaluation.State.EDITOR_APPROVED,
            Evaluation.State.APPROVED,
            Evaluation.State.IN_EVALUATION,
        ],
    ).exclude(voters=request.user).prefetch_related("course__responsibles",
                                                    "course__type",
                                                    "course__semester"))

    unfinished_evaluations_query = Evaluation.annotate_with_participant_and_voter_counts(
        unfinished_evaluations_query)
    unfinished_evaluations = list(unfinished_evaluations_query)

    # available evaluations come first, ordered by time left for evaluation and the name
    # evaluations in other (visible) states follow by name
    def sorter(evaluation):
        return (
            evaluation.state != Evaluation.State.IN_EVALUATION,
            evaluation.vote_end_date
            if evaluation.state == Evaluation.State.IN_EVALUATION else None,
            evaluation.full_name,
        )

    unfinished_evaluations.sort(key=sorter)

    template_data = dict(
        semester_list=semester_list,
        can_download_grades=request.user.can_download_grades,
        unfinished_evaluations=unfinished_evaluations,
        evaluation_end_warning_period=settings.EVALUATION_END_WARNING_PERIOD,
    )

    return render(request, "student_index.html", template_data)
Exemplo n.º 17
0
def evaluation_detail(request, semester_id, evaluation_id):
    semester = get_object_or_404(Semester, id=semester_id)
    evaluation = get_object_or_404(semester.evaluations,
                                   id=evaluation_id,
                                   course__semester=semester)

    if not evaluation.can_user_see_results_page(request.user):
        raise PermissionDenied

    evaluation_result = collect_results(evaluation)

    if request.user.is_reviewer:
        view = request.GET.get(
            'view', 'public')  # if parameter is not given, show public view.
    else:
        view = request.GET.get(
            'view', 'full')  # if parameter is not given, show own view.
    if view not in ['public', 'full', 'export']:
        view = 'public'

    view_as_user = request.user
    if view == 'export' and request.user.is_staff:
        view_as_user = UserProfile.objects.get(
            id=int(request.GET.get('contributor_id', request.user.id)))

    represented_users = [view_as_user]
    if view != 'export':
        represented_users += list(view_as_user.represented_users.all())
    # redirect to non-public view if there is none because the results have not been published
    if not evaluation.can_publish_rating_results and view == 'public':
        view = 'full'

    # remove text answers if the user may not see them
    for questionnaire_result in evaluation_result.questionnaire_results:
        for question_result in questionnaire_result.question_results:
            if isinstance(question_result, TextResult):
                question_result.answers = [
                    answer for answer in question_result.answers
                    if user_can_see_textanswer(view_as_user, represented_users,
                                               answer, view)
                ]
        # remove empty TextResults
        questionnaire_result.question_results = [
            result for result in questionnaire_result.question_results
            if not isinstance(result, TextResult) or len(result.answers) > 0
        ]

    # filter empty headings
    for questionnaire_result in evaluation_result.questionnaire_results:
        filtered_question_results = []
        for index, question_result in enumerate(
                questionnaire_result.question_results):
            # filter out if there are no more questions or the next question is also a heading question
            if isinstance(question_result, HeadingResult):
                if index == len(questionnaire_result.question_results
                                ) - 1 or isinstance(
                                    questionnaire_result.question_results[index
                                                                          + 1],
                                    HeadingResult):
                    continue
            filtered_question_results.append(question_result)
        questionnaire_result.question_results = filtered_question_results

    # remove empty questionnaire_results and contribution_results
    for contribution_result in evaluation_result.contribution_results:
        contribution_result.questionnaire_results = [
            questionnaire_result for questionnaire_result in
            contribution_result.questionnaire_results
            if questionnaire_result.question_results
        ]
    evaluation_result.contribution_results = [
        contribution_result
        for contribution_result in evaluation_result.contribution_results
        if contribution_result.questionnaire_results
    ]

    add_warnings(evaluation, evaluation_result)

    # split evaluation_result into different lists
    general_questionnaire_results_top = []
    general_questionnaire_results_bottom = []
    contributor_contribution_results = []
    for contribution_result in evaluation_result.contribution_results:
        if contribution_result.contributor is None:
            for questionnaire_result in contribution_result.questionnaire_results:
                if questionnaire_result.questionnaire.is_below_contributors:
                    general_questionnaire_results_bottom.append(
                        questionnaire_result)
                else:
                    general_questionnaire_results_top.append(
                        questionnaire_result)
        elif view != 'export' or view_as_user.id == contribution_result.contributor.id:
            contributor_contribution_results.append(contribution_result)

    if not contributor_contribution_results:
        general_questionnaire_results_top += general_questionnaire_results_bottom
        general_questionnaire_results_bottom = []

    course_evaluations = []
    if evaluation.course.evaluations.count() > 1:
        course_evaluations = [
            evaluation for evaluation in evaluation.course.evaluations.filter(
                state="published")
            if evaluation.can_user_see_evaluation(request.user)
        ]
        if request.user.is_reviewer:
            course_evaluations += evaluation.course.evaluations.filter(
                state__in=['in_evaluation', 'evaluated', 'reviewed'])
        course_evaluations = get_evaluations_with_course_result_attributes(
            course_evaluations)
        for course_evaluation in course_evaluations:
            if course_evaluation.is_single_result:
                course_evaluation.single_result_rating_result = get_single_result_rating_result(
                    course_evaluation)
            else:
                course_evaluation.distribution = calculate_average_distribution(
                    course_evaluation)
                course_evaluation.avg_grade = distribution_to_grade(
                    course_evaluation.distribution)

    other_contributors = []
    if view == 'export':
        other_contributors = [
            contribution_result.contributor
            for contribution_result in evaluation_result.contribution_results
            if contribution_result.contributor not in [None, view_as_user]
        ]

    # if the evaluation is not published, the rendered results are not cached, so we need to attach distribution
    # information for rendering the distribution bar
    if evaluation.state != 'published':
        evaluation = get_evaluations_with_prefetched_data([evaluation])[0]

    template_data = dict(
        evaluation=evaluation,
        course=evaluation.course,
        course_evaluations=course_evaluations,
        general_questionnaire_results_top=general_questionnaire_results_top,
        general_questionnaire_results_bottom=
        general_questionnaire_results_bottom,
        contributor_contribution_results=contributor_contribution_results,
        is_reviewer=view_as_user.is_reviewer,
        is_contributor=evaluation.is_user_contributor(view_as_user),
        is_responsible_or_contributor_or_delegate=evaluation.
        is_user_responsible_or_contributor_or_delegate(view_as_user),
        can_download_grades=view_as_user.can_download_grades,
        view=view,
        view_as_user=view_as_user,
        other_contributors=other_contributors,
    )
    return render(request, "results_evaluation_detail.html", template_data)
Exemplo n.º 18
0
def evaluation_detail(request, semester_id, evaluation_id):
    semester = get_object_or_404(Semester, id=semester_id)
    evaluation = get_object_or_404(semester.evaluations, id=evaluation_id, course__semester=semester)

    if not evaluation.can_results_page_be_seen_by(request.user):
        raise PermissionDenied

    evaluation_result = collect_results(evaluation)

    if request.user.is_reviewer:
        view = request.GET.get('view', 'public')  # if parameter is not given, show public view.
    else:
        view = request.GET.get('view', 'full')  # if parameter is not given, show own view.
    if view not in ['public', 'full', 'export']:
        view = 'public'

    view_as_user = request.user
    if view == 'export' and request.user.is_staff:
        view_as_user = UserProfile.objects.get(id=int(request.GET.get('contributor_id', request.user.id)))

    represented_users = [view_as_user]
    if view != 'export':
        represented_users += list(view_as_user.represented_users.all())
    # redirect to non-public view if there is none because the results have not been published
    if not evaluation.can_publish_rating_results and view == 'public':
        view = 'full'

    # remove text answers if the user may not see them
    for questionnaire_result in evaluation_result.questionnaire_results:
        for question_result in questionnaire_result.question_results:
            if isinstance(question_result, TextResult):
                question_result.answers = [answer for answer in question_result.answers if can_textanswer_be_seen_by(view_as_user, represented_users, answer, view)]
        # remove empty TextResults
        questionnaire_result.question_results = [result for result in questionnaire_result.question_results if not isinstance(result, TextResult) or len(result.answers) > 0]

    # filter empty headings
    for questionnaire_result in evaluation_result.questionnaire_results:
        filtered_question_results = []
        for index, question_result in enumerate(questionnaire_result.question_results):
            # filter out if there are no more questions or the next question is also a heading question
            if isinstance(question_result, HeadingResult):
                if index == len(questionnaire_result.question_results) - 1 or isinstance(questionnaire_result.question_results[index + 1], HeadingResult):
                    continue
            filtered_question_results.append(question_result)
        questionnaire_result.question_results = filtered_question_results

    # remove empty questionnaire_results and contribution_results
    for contribution_result in evaluation_result.contribution_results:
        contribution_result.questionnaire_results = [questionnaire_result for questionnaire_result in contribution_result.questionnaire_results if questionnaire_result.question_results]
    evaluation_result.contribution_results = [contribution_result for contribution_result in evaluation_result.contribution_results if contribution_result.questionnaire_results]

    add_warnings(evaluation, evaluation_result)

    # split evaluation_result into different lists
    general_questionnaire_results_top = []
    general_questionnaire_results_bottom = []
    contributor_contribution_results = []
    for contribution_result in evaluation_result.contribution_results:
        if contribution_result.contributor is None:
            for questionnaire_result in contribution_result.questionnaire_results:
                if questionnaire_result.questionnaire.is_below_contributors:
                    general_questionnaire_results_bottom.append(questionnaire_result)
                else:
                    general_questionnaire_results_top.append(questionnaire_result)
        elif view != 'export' or view_as_user.id == contribution_result.contributor.id:
            contributor_contribution_results.append(contribution_result)

    if not contributor_contribution_results:
        general_questionnaire_results_top += general_questionnaire_results_bottom
        general_questionnaire_results_bottom = []

    course_evaluations = []
    if evaluation.course.evaluations.count() > 1:
        course_evaluations = [evaluation for evaluation in evaluation.course.evaluations.filter(state="published") if evaluation.can_be_seen_by(request.user)]
        if request.user.is_reviewer:
            course_evaluations += evaluation.course.evaluations.filter(state__in=['in_evaluation', 'evaluated', 'reviewed'])
        course_evaluations = get_evaluations_with_course_result_attributes(course_evaluations)
        for course_evaluation in course_evaluations:
            if course_evaluation.is_single_result:
                course_evaluation.single_result_rating_result = get_single_result_rating_result(course_evaluation)
            else:
                course_evaluation.distribution = calculate_average_distribution(course_evaluation)
                course_evaluation.avg_grade = distribution_to_grade(course_evaluation.distribution)

    other_contributors = []
    if view == 'export':
        other_contributors = [contribution_result.contributor for contribution_result in evaluation_result.contribution_results if contribution_result.contributor not in [None, view_as_user]]

    # if the evaluation is not published, the rendered results are not cached, so we need to attach distribution
    # information for rendering the distribution bar
    if evaluation.state != 'published':
        evaluation = get_evaluations_with_prefetched_data([evaluation])[0]

    template_data = dict(
        evaluation=evaluation,
        course=evaluation.course,
        course_evaluations=course_evaluations,
        general_questionnaire_results_top=general_questionnaire_results_top,
        general_questionnaire_results_bottom=general_questionnaire_results_bottom,
        contributor_contribution_results=contributor_contribution_results,
        is_reviewer=view_as_user.is_reviewer,
        is_contributor=evaluation.is_user_contributor(view_as_user),
        is_responsible_or_contributor_or_delegate=evaluation.is_user_responsible_or_contributor_or_delegate(view_as_user),
        can_download_grades=view_as_user.can_download_grades,
        view=view,
        view_as_user=view_as_user,
        other_contributors=other_contributors,
    )
    return render(request, "results_evaluation_detail.html", template_data)
Exemplo n.º 19
0
def index(request):
    user = request.user
    show_delegated = get_parameter_from_url_or_session(request,
                                                       "show_delegated", True)

    represented_proxy_users = user.represented_users.filter(is_proxy_user=True)
    contributor_visible_states = [
        Evaluation.State.PREPARED,
        Evaluation.State.EDITOR_APPROVED,
        Evaluation.State.APPROVED,
        Evaluation.State.IN_EVALUATION,
        Evaluation.State.EVALUATED,
        Evaluation.State.REVIEWED,
        Evaluation.State.PUBLISHED,
    ]
    own_courses = Course.objects.filter(
        Q(evaluations__state__in=contributor_visible_states)
        &
        (Q(responsibles=user)
         | Q(evaluations__contributions__contributor=user)
         |
         Q(evaluations__contributions__contributor__in=represented_proxy_users)
         | Q(responsibles__in=represented_proxy_users)))

    own_evaluations = (Evaluation.objects.filter(
        course__in=own_courses).annotate(contributes_to=Exists(
            Evaluation.objects.filter(
                id=OuterRef(
                    "id"), contributions__contributor=user))).prefetch_related(
                        "course", "course__evaluations", "course__degrees",
                        "course__type", "course__semester"))
    own_evaluations = [
        evaluation for evaluation in own_evaluations
        if evaluation.can_be_seen_by(user)
    ]

    displayed_evaluations = own_evaluations
    if show_delegated:
        represented_users = user.represented_users.exclude(is_proxy_user=True)
        delegated_courses = Course.objects.filter(
            Q(evaluations__state__in=contributor_visible_states)
            &
            (Q(responsibles__in=represented_users)
             | Q(
                 evaluations__contributions__role=Contribution.Role.EDITOR,
                 evaluations__contributions__contributor__in=represented_users,
             )))
        delegated_evaluations = Evaluation.objects.filter(
            course__in=delegated_courses).prefetch_related(
                "course", "course__evaluations", "course__degrees",
                "course__type", "course__semester")
        delegated_evaluations = [
            evaluation for evaluation in delegated_evaluations
            if evaluation.can_be_seen_by(user)
        ]
        for evaluation in delegated_evaluations:
            evaluation.delegated_evaluation = True
        displayed_evaluations += set(delegated_evaluations) - set(
            displayed_evaluations)

    displayed_evaluations.sort(
        key=lambda evaluation: (evaluation.course.name, evaluation.name)
    )  # evaluations must be sorted for regrouping them in the template

    annotate_distributions_and_grades(e for e in displayed_evaluations
                                      if e.state == Evaluation.State.PUBLISHED)
    displayed_evaluations = get_evaluations_with_course_result_attributes(
        displayed_evaluations)

    semesters = Semester.objects.all()
    semester_list = [
        dict(
            semester_name=semester.name,
            id=semester.id,
            is_active=semester.is_active,
            evaluations=[
                evaluation for evaluation in displayed_evaluations
                if evaluation.course.semester_id == semester.id
            ],
        ) for semester in semesters
    ]

    template_data = dict(
        semester_list=semester_list,
        show_delegated=show_delegated,
        delegate_selection_form=DelegateSelectionForm(),
    )
    return render(request, "contributor_index.html", template_data)
Exemplo n.º 20
0
def evaluation_detail(request, semester_id, evaluation_id):
    semester = get_object_or_404(Semester, id=semester_id)
    evaluation = get_object_or_404(semester.evaluations,
                                   id=evaluation_id,
                                   course__semester=semester)

    if not evaluation.can_results_page_be_seen_by(request.user):
        raise PermissionDenied

    if request.user.is_reviewer:
        view = request.GET.get(
            'view', 'public')  # if parameter is not given, show public view.
    else:
        view = request.GET.get(
            'view', 'full')  # if parameter is not given, show own view.
    if view not in ['public', 'full', 'export']:
        view = 'public'

    view_as_user = request.user
    if view == 'export' and request.user.is_staff:
        view_as_user = UserProfile.objects.get(
            id=int(request.GET.get('contributor_id', request.user.id)))

    represented_users = [view_as_user]
    if view != 'export':
        represented_users += list(view_as_user.represented_users.all())
    # redirect to non-public view if there is none because the results have not been published
    if not evaluation.can_publish_rating_results and view == 'public':
        view = 'full'

    evaluation_result = collect_results(evaluation)
    remove_textanswers_that_the_user_must_not_see(evaluation_result,
                                                  view_as_user,
                                                  represented_users, view)
    filter_empty_headings(evaluation_result)
    remove_empty_questionnaire_and_contribution_results(evaluation_result)
    add_warnings(evaluation, evaluation_result)

    top_results, bottom_results, contributor_results = split_evaluation_result_into_top_bottom_and_contributor(
        evaluation_result, view_as_user, view)

    course_evaluations = get_evaluations_of_course(evaluation.course, request)
    course_evaluations.sort(key=lambda evaluation: evaluation.name)

    contributors_with_omitted_results = []
    if view == 'export':
        contributors_with_omitted_results = [
            contribution_result.contributor
            for contribution_result in evaluation_result.contribution_results
            if contribution_result.contributor not in [None, view_as_user]
        ]

    # if the evaluation is not published, the rendered results are not cached, so we need to attach distribution
    # information for rendering the distribution bar
    if evaluation.state != 'published':
        evaluation = get_evaluations_with_course_result_attributes(
            get_evaluations_with_prefetched_data([evaluation]))[0]

    template_data = dict(
        evaluation=evaluation,
        course=evaluation.course,
        course_evaluations=course_evaluations,
        general_questionnaire_results_top=top_results,
        general_questionnaire_results_bottom=bottom_results,
        contributor_contribution_results=contributor_results,
        is_reviewer=view_as_user.is_reviewer,
        is_contributor=evaluation.is_user_contributor(view_as_user),
        is_responsible_or_contributor_or_delegate=evaluation.
        is_user_responsible_or_contributor_or_delegate(view_as_user),
        can_download_grades=view_as_user.can_download_grades,
        view=view,
        view_as_user=view_as_user,
        contributors_with_omitted_results=contributors_with_omitted_results,
    )
    return render(request, "results_evaluation_detail.html", template_data)
Exemplo n.º 21
0
def index(request):
    query = (Evaluation.objects
        .annotate(participates_in=Exists(Evaluation.objects.filter(id=OuterRef('id'), participants=request.user)))
        .annotate(voted_for=Exists(Evaluation.objects.filter(id=OuterRef('id'), voters=request.user)))

        .filter(~Q(state="new"), course__evaluations__participants=request.user)
        .exclude(state="new")
        .prefetch_related(
            'course', 'course__semester', 'course__grade_documents', 'course__type',
            'course__evaluations', 'course__responsibles', 'course__degrees',
        )
        .distinct()
    )
    query = Evaluation.annotate_with_participant_and_voter_counts(query)
    evaluations = [evaluation for evaluation in query if evaluation.can_be_seen_by(request.user)]

    inner_evaluation_ids = [inner_evaluation.id for evaluation in evaluations for inner_evaluation in evaluation.course.evaluations.all()]
    inner_evaluation_query = Evaluation.objects.filter(pk__in=inner_evaluation_ids)
    inner_evaluation_query = Evaluation.annotate_with_participant_and_voter_counts(inner_evaluation_query)

    evaluations_by_id = {evaluation['id']: evaluation for evaluation in inner_evaluation_query.values()}

    for evaluation in evaluations:
        for inner_evaluation in evaluation.course.evaluations.all():
            inner_evaluation.num_voters = evaluations_by_id[inner_evaluation.id]['num_voters']
            inner_evaluation.num_participants = evaluations_by_id[inner_evaluation.id]['num_participants']

    for evaluation in evaluations:
        if evaluation.state == "published":
            if not evaluation.is_single_result:
                evaluation.distribution = calculate_average_distribution(evaluation)
            else:
                evaluation.single_result_rating_result = get_single_result_rating_result(evaluation)
                evaluation.distribution = normalized_distribution(evaluation.single_result_rating_result.counts)
            evaluation.avg_grade = distribution_to_grade(evaluation.distribution)
    evaluations = get_evaluations_with_course_result_attributes(evaluations)

    # evaluations must be sorted for regrouping them in the template
    evaluations.sort(key=lambda evaluation: (evaluation.course.name, evaluation.name))

    semesters = Semester.objects.all()
    semester_list = [dict(
        semester_name=semester.name,
        id=semester.id,
        results_are_archived=semester.results_are_archived,
        grade_documents_are_deleted=semester.grade_documents_are_deleted,
        evaluations=[evaluation for evaluation in evaluations if evaluation.course.semester_id == semester.id]
    ) for semester in semesters]

    unfinished_evaluations_query = (
        Evaluation.objects
        .filter(participants=request.user, state__in=['prepared', 'editor_approved', 'approved', 'in_evaluation'])
        .exclude(voters=request.user)
        .prefetch_related('course__responsibles', 'course__type', 'course__semester')
    )

    unfinished_evaluations_query = Evaluation.annotate_with_participant_and_voter_counts(unfinished_evaluations_query)
    unfinished_evaluations = list(unfinished_evaluations_query)

    # available evaluations come first, ordered by time left for evaluation and the name
    # evaluations in other (visible) states follow by name
    def sorter(evaluation):
        return (
            evaluation.state != 'in_evaluation',
            evaluation.vote_end_date if evaluation.state == 'in_evaluation' else None,
            evaluation.full_name
        )
    unfinished_evaluations.sort(key=sorter)

    template_data = dict(
        semester_list=semester_list,
        can_download_grades=request.user.can_download_grades,
        unfinished_evaluations=unfinished_evaluations,
        evaluation_end_warning_period=settings.EVALUATION_END_WARNING_PERIOD,
    )

    return render(request, "student_index.html", template_data)