Example #1
0
    def test_archiving_does_not_change_results(self):
        results = calculate_average_grades_and_deviation(self.course)

        self.semester.archive()
        self.refresh_course()
        cache.clear()

        self.assertEqual(calculate_average_grades_and_deviation(self.course), results)
Example #2
0
    def test_archiving_does_not_change_results(self):
        results = calculate_average_grades_and_deviation(self.course)

        self.semester.archive()
        self.refresh_course()
        cache.clear()

        self.assertEqual(calculate_average_grades_and_deviation(self.course), results)
Example #3
0
def semester_detail(request, semester_id):
    semester = get_object_or_404(Semester, id=semester_id)
    courses = list(semester.course_set.filter(state="published").prefetch_related("degrees"))

    # Annotate each course object with its grades.
    for course in courses:
        course.avg_grade, course.avg_deviation = calculate_average_grades_and_deviation(course)

    CourseTuple = namedtuple('CourseTuple', ('courses', 'single_results'))

    courses_by_degree = OrderedDict()
    for degree in Degree.objects.all():
        courses_by_degree[degree] = CourseTuple([], [])
    for course in courses:
        if course.is_single_result:
            for degree in course.degrees.all():
                section = calculate_results(course)[0]
                result = section.results[0]
                courses_by_degree[degree].single_results.append((course, result))
        else:
            for degree in course.degrees.all():
                courses_by_degree[degree].courses.append(course)

    template_data = dict(semester=semester, courses_by_degree=courses_by_degree, staff=request.user.is_staff)
    return render(request, "results_semester_detail.html", template_data)
Example #4
0
def semester_detail(request, semester_id):
    semester = get_object_or_404(Semester, id=semester_id)
    courses = list(semester.course_set.filter(state="published").prefetch_related("degrees"))

    # annotate each course object with its grades
    for course in courses:
        course.avg_grade, course.avg_deviation = calculate_average_grades_and_deviation(course)

    CourseTuple = namedtuple('CourseTuple', ('courses', 'single_results'))

    courses_by_degree = OrderedDict()
    for degree in Degree.objects.all():
        courses_by_degree[degree] = CourseTuple([], [])
    for course in courses:
        if course.is_single_result():
            for degree in course.degrees.all():
                section = calculate_results(course)[0]
                result = section.results[0]
                courses_by_degree[degree].single_results.append((course, result))
        else:
            for degree in course.degrees.all():
                courses_by_degree[degree].courses.append(course)

    template_data = dict(semester=semester, courses_by_degree=courses_by_degree, staff=request.user.is_staff)
    return render(request, "results_semester_detail.html", template_data)
Example #5
0
    def test_average_grades(self):
        contributor1 = mommy.make(UserProfile)
        contributor2 = mommy.make(UserProfile)

        course = mommy.make(Course)
        questionnaire = mommy.make(Questionnaire)
        question_grade = mommy.make(Question, questionnaire=questionnaire, type="G")
        question_likert = mommy.make(Question, questionnaire=questionnaire, type="L")
        general_contribution = mommy.make(Contribution, contributor=None, course=course, questionnaires=[questionnaire])
        contribution1 = mommy.make(Contribution, contributor=contributor1, course=course, questionnaires=[questionnaire])
        contribution2 = mommy.make(Contribution, contributor=contributor2, course=course, questionnaires=[questionnaire])

        mommy.make(RatingAnswerCounter, question=question_grade, contribution=contribution1, answer=1, count=1)
        mommy.make(RatingAnswerCounter, question=question_grade, contribution=contribution2, answer=4, count=2)
        mommy.make(RatingAnswerCounter, question=question_likert, contribution=contribution1, answer=3, count=4)
        mommy.make(RatingAnswerCounter, question=question_likert, contribution=general_contribution, answer=5, count=3)

        total_likert = settings.CONTRIBUTION_PERCENTAGE * 3 + (1 - settings.CONTRIBUTION_PERCENTAGE) * 5
        total_grade = 2.5
        total = settings.GRADE_PERCENTAGE * total_grade + (1 - settings.GRADE_PERCENTAGE) * total_likert

        average, deviation = calculate_average_grades_and_deviation(course)

        self.assertAlmostEqual(average, total)
        self.assertAlmostEqual(deviation, 0)
Example #6
0
def course_detail(request, semester_id, course_id):
    semester = get_object_or_404(Semester, id=semester_id)
    course = get_object_or_404(semester.course_set, id=course_id)

    if not course.can_user_see_results(request.user):
        raise PermissionDenied

    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, public_view)]
                if answers:
                    results.append(TextResult(question=result.question, answers=answers))
            else:
                results.append(result)
        section.results[:] = results

    # filter empty sections and group by contributor
    course_sections = []
    contributor_sections = OrderedDict()
    for section in sections:
        if not section.results:
            continue
        if section.contributor is None:
            course_sections.append(section)
        else:
            contributor_sections.setdefault(section.contributor, []).append(section)

    # show a warning if course is still in evaluation (for staff preview)
    evaluation_warning = course.state != 'published'

    # results for a course might not be visible because there are not enough answers
    # but it can still be "published" e.g. to show the comment results to contributors.
    # users who can open the results page see a warning message in this case
    sufficient_votes_warning = not course.can_publish_grades

    show_grades = request.user.is_staff or course.can_publish_grades

    course.avg_grade, course.avg_deviation = calculate_average_grades_and_deviation(course)

    template_data = dict(
            course=course,
            course_sections=course_sections,
            contributor_sections=contributor_sections,
            evaluation_warning=evaluation_warning,
            sufficient_votes_warning=sufficient_votes_warning,
            show_grades=show_grades,
            staff=request.user.is_staff,
            contributor=course.is_user_contributor_or_delegate(request.user),
            can_download_grades=request.user.can_download_grades,
            public_view=public_view)
    return render(request, "results_course_detail.html", template_data)
Example #7
0
def semester_raw_export(request, semester_id):
    semester = get_object_or_404(Semester, id=semester_id)

    filename = "Evaluation-{}-{}_raw.csv".format(semester.name, get_language())
    response = HttpResponse(content_type="text/csv")
    response["Content-Disposition"] = "attachment; filename=\"{}\"".format(filename)

    writer = csv.writer(response, delimiter=";")
    writer.writerow([_('Name'), _('Degrees'), _('Type'), _('Single result'), _('State'), _('#Voters'),
        _('#Participants'), _('#Comments'), _('Average grade')])
    for course in semester.course_set.all():
        degrees = ", ".join([degree.name for degree in course.degrees.all()])
        course.avg_grade, course.avg_deviation = calculate_average_grades_and_deviation(course)
        if course.state in ['evaluated', 'reviewed', 'published'] and course.avg_grade is not None:
            avg_grade = "{:.1f}".format(course.avg_grade)
        else:
            avg_grade = ""
        writer.writerow([course.name, degrees, course.type.name, course.is_single_result, course.state,
            course.num_voters, course.num_participants, course.textanswer_set.count(), avg_grade])

    return response
Example #8
0
    def export(self, response, ignore_not_enough_answers=False):
        courses_with_results = list()
        for course in self.semester.course_set.filter(state="published").all():
            results = OrderedDict()
            for questionnaire, contributor, label, data, section_warning in calculate_results(course):
                results.setdefault(questionnaire.id, []).extend(data)
            courses_with_results.append((course, results))

        courses_with_results.sort(key=lambda cr: cr[0].type)

        qn_frequencies = defaultdict(int)
        for course, results in courses_with_results:
            for questionnaire, results in results.items():
                qn_frequencies[questionnaire] += 1

        qn_relevant = list(qn_frequencies.items())
        qn_relevant.sort(key=lambda t: -t[1])

        questionnaires = [Questionnaire.objects.get(id=t[0]) for t in qn_relevant]

        self.workbook = xlwt.Workbook()
        self.sheet = self.workbook.add_sheet(_("Results"))
        self.row = 0
        self.col = 0


        self.init_styles(self.workbook)

        writec(self, _("Evaluation {0} - created on {1}").format(self.semester.name, datetime.date.today()), "headline")
        for course, results in courses_with_results:
            if course.state == "published":
                writec(self, course.name, "course", cols=2)
            else:
                writec(self, course.name, "course_unfinished", cols=2)

        writen(self)
        for course, results in courses_with_results:
            writec(self, "Average", "avg")
            writec(self, "Deviation", "border_top_bottom_right")

        for questionnaire in questionnaires:
            writen(self, questionnaire.name, "bold")
            for course, results in courses_with_results:
                self.write_two_empty_cells_with_borders()

            for question in questionnaire.question_set.all():
                if question.is_text_question:
                    continue

                writen(self, question.text)

                for course, results in courses_with_results:
                    qn_results = results.get(questionnaire.id, None)
                    if qn_results:
                        values = []
                        deviations = []
                        for grade_result in qn_results:
                            if grade_result.question.id == question.id:
                                if grade_result.average:
                                    values.append(grade_result.average)
                                    deviations.append(grade_result.deviation)
                                break
                        enough_answers = course.can_publish_grades
                        if values and (enough_answers or ignore_not_enough_answers):
                            avg = sum(values) / len(values)
                            writec(self, avg, self.grade_to_style(avg))

                            dev = sum(deviations) / len(deviations)
                            writec(self, dev, self.deviation_to_style(dev))
                        else:
                            self.write_two_empty_cells_with_borders()
                    else:
                        self.write_two_empty_cells_with_borders()
            writen(self, None)
            for course, results in courses_with_results:
                self.write_two_empty_cells_with_borders()

        writen(self, _("Overall Average Grade"), "bold")
        for course, results in courses_with_results:
            avg, dev = calculate_average_grades_and_deviation(course)
            if avg:
                writec(self, avg, self.grade_to_style(avg), cols=2)
            else:
                self.write_two_empty_cells_with_borders()

        writen(self, _("Overall Average Standard Deviation"), "bold")
        for course, results in courses_with_results:
            avg, dev = calculate_average_grades_and_deviation(course)
            if dev is not None:
                writec(self, dev, self.deviation_to_style(dev), cols=2)
            else:
                self.write_two_empty_cells_with_borders()

        writen(self, _("Total Voters/Total Participants"), "bold")
        for course, results in courses_with_results:
            percent_participants = float(course.num_voters)/float(course.num_participants)
            writec(self, "{}/{} ({:.0%})".format(course.num_voters, course.num_participants, percent_participants), "total_voters", cols=2)

        self.workbook.save(response)
Example #9
0
def course_detail(request, semester_id, course_id):
    semester = get_object_or_404(Semester, id=semester_id)
    course = get_object_or_404(semester.course_set, id=course_id, semester=semester)

    if not course.can_user_see_results(request.user):
        raise PermissionDenied

    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.

    represented_users = list(request.user.represented_users.all())
    represented_users.append(request.user)

    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, represented_users, answer, public_view)]
                if answers:
                    results.append(TextResult(question=result.question, answers=answers))
            else:
                results.append(result)
        section.results[:] = results

    # Filter empty sections and group by contributor.
    course_sections = []
    contributor_sections = OrderedDict()
    for section in sections:
        if not section.results:
            continue
        if section.contributor is None:
            course_sections.append(section)
        else:
            contributor_sections.setdefault(section.contributor,
                                            {'total_votes': 0, 'sections': []})['sections'].append(section)

            # Sum up all Sections for this contributor.
            # If section is not a RatingResult:
            # Add 1 as we assume it is a TextResult or something similar that should be displayed.
            contributor_sections[section.contributor]['total_votes'] +=\
                sum([s.total_count if isinstance(s, RatingResult) else 1 for s in section.results])

    # Show a warning if course is still in evaluation (for staff preview).
    evaluation_warning = course.state != 'published'

    # Results for a course might not be visible because there are not enough answers
    # but it can still be "published" e.g. to show the comment results to contributors.
    # Users who can open the results page see a warning message in this case.
    sufficient_votes_warning = not course.can_publish_grades

    show_grades = request.user.is_staff or course.can_publish_grades

    course.avg_grade, course.avg_deviation = calculate_average_grades_and_deviation(course)

    template_data = dict(
            course=course,
            course_sections=course_sections,
            contributor_sections=contributor_sections,
            evaluation_warning=evaluation_warning,
            sufficient_votes_warning=sufficient_votes_warning,
            show_grades=show_grades,
            staff=request.user.is_staff,
            contributor=course.is_user_contributor_or_delegate(request.user),
            can_download_grades=request.user.can_download_grades,
            public_view=public_view)
    return render(request, "results_course_detail.html", template_data)
Example #10
0
    def export(self, response, course_types_list, ignore_not_enough_answers=False, include_unpublished=False):
        self.workbook = xlwt.Workbook()
        self.init_styles(self.workbook)
        counter = 1

        for course_types in course_types_list:
            self.sheet = self.workbook.add_sheet("Sheet " + str(counter))
            counter += 1
            self.row = 0
            self.col = 0

            courses_with_results = list()
            course_states = ['published']
            if include_unpublished:
                course_states.extend(['evaluated', 'reviewed'])

            used_questionnaires = set()
            for course in self.semester.course_set.filter(state__in=course_states, type__in=course_types).all():
                if course.is_single_result():
                    continue
                results = OrderedDict()
                for questionnaire, contributor, label, data, section_warning in calculate_results(course):
                    if has_no_rating_answers(course, contributor, questionnaire):
                        continue
                    results.setdefault(questionnaire.id, []).extend(data)
                    used_questionnaires.add(questionnaire)
                courses_with_results.append((course, results))

            courses_with_results.sort(key=lambda cr: cr[0].type)
            used_questionnaires = sorted(used_questionnaires)

            writec(self, _("Evaluation {0}\n\n{1}").format(self.semester.name, ", ".join(course_types)), "headline")

            for course, results in courses_with_results:
                writec(self, course.name, "course", cols=2)

            writen(self)
            for course, results in courses_with_results:
                writec(self, "Average", "avg")
                writec(self, "Deviation", "border_top_bottom_right")

            for questionnaire in used_questionnaires:
                writen(self, questionnaire.name, "bold")
                for course, results in courses_with_results:
                    self.write_two_empty_cells_with_borders()

                for question in questionnaire.question_set.all():
                    if question.is_text_question:
                        continue

                    writen(self, question.text)

                    for course, results in courses_with_results:
                        if questionnaire.id not in results:
                            self.write_two_empty_cells_with_borders()
                            continue
                        qn_results = results[questionnaire.id]
                        values = []
                        deviations = []
                        total_count = 0

                        for grade_result in qn_results:
                            if grade_result.question.id == question.id:
                                if grade_result.average:
                                    values.append(grade_result.average * grade_result.total_count)
                                    deviations.append(grade_result.deviation * grade_result.total_count)
                                    total_count += grade_result.total_count
                        enough_answers = course.can_publish_grades
                        if values and (enough_answers or ignore_not_enough_answers):
                            avg = sum(values) / total_count
                            writec(self, avg, self.grade_to_style(avg))

                            dev = sum(deviations) / total_count
                            writec(self, dev, self.deviation_to_style(dev))
                        else:
                            self.write_two_empty_cells_with_borders()
                writen(self, None)
                for course, results in courses_with_results:
                    self.write_two_empty_cells_with_borders()

            writen(self, _("Overall Average Grade"), "bold")
            for course, results in courses_with_results:
                avg, dev = calculate_average_grades_and_deviation(course)
                if avg:
                    writec(self, avg, self.grade_to_style(avg, total=True), cols=2)
                else:
                    self.write_two_empty_cells_with_borders()

            writen(self, _("Overall Average Standard Deviation"), "bold")
            for course, results in courses_with_results:
                avg, dev = calculate_average_grades_and_deviation(course)
                if dev is not None:
                    writec(self, dev, self.deviation_to_style(dev, total=True), cols=2)
                else:
                    self.write_two_empty_cells_with_borders()

            writen(self, _("Total Voters/Total Participants"), "bold")
            for course, results in courses_with_results:
                percent_participants = float(course.num_voters)/float(course.num_participants) if course.num_participants > 0 else 0
                writec(self, "{}/{} ({:.0%})".format(course.num_voters, course.num_participants, percent_participants), "total_voters", cols=2)

        self.workbook.save(response)
Example #11
0
def course_detail(request, semester_id, course_id):
    semester = get_object_or_404(Semester, id=semester_id)
    course = get_object_or_404(semester.course_set,
                               id=course_id,
                               semester=semester)

    if not course.can_user_see_results(request.user):
        raise PermissionDenied

    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.

    represented_users = list(request.user.represented_users.all())
    represented_users.append(request.user)

    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, represented_users, answer, public_view)
                ]
                if answers:
                    results.append(
                        TextResult(question=result.question, answers=answers))
            else:
                results.append(result)
        section.results[:] = results

    # Filter empty sections and group by contributor.
    course_sections = []
    contributor_sections = OrderedDict()
    for section in sections:
        if not section.results:
            continue
        if section.contributor is None:
            course_sections.append(section)
        else:
            contributor_sections.setdefault(section.contributor, {
                'total_votes': 0,
                'sections': []
            })['sections'].append(section)

            # Sum up all Sections for this contributor.
            # If section is not a RatingResult:
            # Add 1 as we assume it is a TextResult or something similar that should be displayed.
            contributor_sections[section.contributor]['total_votes'] +=\
                sum([s.total_count if isinstance(s, RatingResult) else 1 for s in section.results])

    # Show a warning if course is still in evaluation (for staff preview).
    evaluation_warning = course.state != 'published'

    # Results for a course might not be visible because there are not enough answers
    # but it can still be "published" e.g. to show the comment results to contributors.
    # Users who can open the results page see a warning message in this case.
    sufficient_votes_warning = not course.can_publish_grades

    show_grades = request.user.is_staff or course.can_publish_grades

    course.avg_grade, course.avg_deviation = calculate_average_grades_and_deviation(
        course)

    template_data = dict(course=course,
                         course_sections=course_sections,
                         contributor_sections=contributor_sections,
                         evaluation_warning=evaluation_warning,
                         sufficient_votes_warning=sufficient_votes_warning,
                         show_grades=show_grades,
                         staff=request.user.is_staff,
                         contributor=course.is_user_contributor_or_delegate(
                             request.user),
                         can_download_grades=request.user.can_download_grades,
                         public_view=public_view)
    return render(request, "results_course_detail.html", template_data)