예제 #1
0
    def test_caches_published_course(self):
        course = mommy.make(Course, state='published')

        self.assertIsNone(cache.get('evap.staff.results.tools.calculate_results-{:d}'.format(course.id)))

        calculate_results(course)

        self.assertIsNotNone(cache.get('evap.staff.results.tools.calculate_results-{:d}'.format(course.id)))
예제 #2
0
파일: test_tools.py 프로젝트: phSch08/EvaP
    def test_caches_published_course(self):
        course = mommy.make(Course, state='published')

        self.assertIsNone(cache.get(get_results_cache_key(course)))

        calculate_results(course)

        self.assertIsNotNone(cache.get(get_results_cache_key(course)))
예제 #3
0
    def handle(self, *args, **options):
        self.stdout.write("Clearing cache...")
        cache.clear()
        total_count = Course.objects.count()

        self.stdout.write("Calculating results for all courses...")

        self.stdout.ending = None
        progress_bar = ProgressBar(self.stdout, total_count)

        for counter, course in enumerate(Course.objects.all()):
            progress_bar.update(counter + 1)
            calculate_results(course)

        self.stdout.write("Results cache has been refreshed.\n")
예제 #4
0
파일: views.py 프로젝트: Benedikt1992/EvaP
def semester_detail(request, semester_id):
    semester = get_object_or_404(Semester, id=semester_id)
    if request.user.is_reviewer:
        courses = list(semester.course_set.filter(state__in=["in_evaluation", "evaluated", "reviewed", "published"]).prefetch_related("degrees"))
    else:
        courses = list(semester.course_set.filter(state="published").prefetch_related("degrees"))

    courses = [course for course in courses if course.can_user_see_course(request.user)]

    # 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)
    return render(request, "results_semester_detail.html", template_data)
예제 #5
0
    def test_calculate_results_after_user_merge(self):
        """ Asserts that merge_users leaves the results cache in a consistent state. Regression test for #907 """
        contributor = mommy.make(UserProfile)
        main_user = mommy.make(UserProfile)
        student = mommy.make(UserProfile)

        course = mommy.make(Course, state='published', participants=[student])
        questionnaire = mommy.make(Questionnaire)
        mommy.make(Question, questionnaire=questionnaire, type="G")
        mommy.make(Contribution, contributor=contributor, course=course, questionnaires=[questionnaire])

        calculate_results(course)

        merge_users(main_user, contributor)

        results = calculate_results(course)

        for section in results:
            self.assertTrue(Contribution.objects.filter(course=course, contributor=section.contributor).exists())
예제 #6
0
파일: test_tools.py 프로젝트: phSch08/EvaP
    def test_calculation_results(self):
        contributor1 = mommy.make(UserProfile)
        student = mommy.make(UserProfile)

        course = mommy.make(Course,
                            state='published',
                            participants=[student, contributor1])
        questionnaire = mommy.make(Questionnaire)
        question = mommy.make(Question, questionnaire=questionnaire, type="G")
        contribution1 = mommy.make(Contribution,
                                   contributor=contributor1,
                                   course=course,
                                   questionnaires=[questionnaire])

        mommy.make(RatingAnswerCounter,
                   question=question,
                   contribution=contribution1,
                   answer=1,
                   count=5)
        mommy.make(RatingAnswerCounter,
                   question=question,
                   contribution=contribution1,
                   answer=2,
                   count=15)
        mommy.make(RatingAnswerCounter,
                   question=question,
                   contribution=contribution1,
                   answer=3,
                   count=40)
        mommy.make(RatingAnswerCounter,
                   question=question,
                   contribution=contribution1,
                   answer=4,
                   count=60)
        mommy.make(RatingAnswerCounter,
                   question=question,
                   contribution=contribution1,
                   answer=5,
                   count=30)

        results = calculate_results(course)

        self.assertEqual(len(results), 1)
        self.assertEqual(len(results[0].results), 1)
        result = results[0].results[0]

        self.assertEqual(result.total_count, 150)
        self.assertAlmostEqual(result.average, float(109) / 30)
        self.assertAlmostEqual(result.deviation, 1.015983376941878)
예제 #7
0
def semester_detail(request, semester_id):
    semester = get_object_or_404(Semester, id=semester_id)

    visible_states = ['published']
    if request.user.is_reviewer:
        visible_states += ['in_evaluation', 'evaluated', 'reviewed']

    courses = semester.course_set.filter(
        state__in=visible_states).prefetch_related("degrees")

    courses = [
        course for course in courses
        if course.can_user_see_course(request.user)
    ]

    for course in courses:
        course.distribution = calculate_average_distribution(
            course) if course.can_user_see_grades(request.user) else None
        course.avg_grade = distribution_to_grade(course.distribution)

    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)
    return render(request, "results_semester_detail.html", template_data)
예제 #8
0
    def test_calculation_results(self):
        contributor1 = mommy.make(UserProfile)
        student = mommy.make(UserProfile)

        course = mommy.make(Course, state='published', participants=[student, contributor1])
        questionnaire = mommy.make(Questionnaire)
        question = mommy.make(Question, questionnaire=questionnaire, type="G")
        contribution1 = mommy.make(Contribution, contributor=contributor1, course=course, questionnaires=[questionnaire])

        mommy.make(RatingAnswerCounter, question=question, contribution=contribution1, answer=1, count=5)
        mommy.make(RatingAnswerCounter, question=question, contribution=contribution1, answer=2, count=15)
        mommy.make(RatingAnswerCounter, question=question, contribution=contribution1, answer=3, count=40)
        mommy.make(RatingAnswerCounter, question=question, contribution=contribution1, answer=4, count=60)
        mommy.make(RatingAnswerCounter, question=question, contribution=contribution1, answer=5, count=30)

        results = calculate_results(course)

        self.assertEqual(len(results), 1)
        self.assertEqual(len(results[0].results), 1)
        result = results[0].results[0]

        self.assertEqual(result.total_count, 150)
        self.assertAlmostEqual(result.average, float(109) / 30)
        self.assertAlmostEqual(result.deviation, 1.015983376941878)
예제 #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)

    if request.user.is_reviewer:
        public_view = request.GET.get(
            'public_view'
        ) != 'false'  # if parameter is not given, show public view.
    else:
        public_view = request.GET.get(
            'public_view'
        ) == 'true'  # if parameter is not given, show own view.

    # If grades are not published, there is no public view
    if not course.can_publish_grades:
        public_view = False

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

    show_grades = request.user.is_reviewer or course.can_publish_grades

    # filter text answers
    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 headings
    for section in sections:
        filtered_results = []
        for index in range(len(section.results)):
            result = section.results[index]
            # filter out if there are no more questions or the next question is also a heading question
            if isinstance(result, HeadingResult):
                if index == len(section.results) - 1 or isinstance(
                        section.results[index + 1], HeadingResult):
                    continue
            filtered_results.append(result)
        section.results[:] = filtered_results

    # remove empty sections
    sections = [section for section in sections if section.results]

    # group by contributor
    course_sections_top = []
    course_sections_bottom = []
    contributor_sections = OrderedDict()
    for section in sections:
        if section.contributor is None:
            if section.questionnaire.is_below_contributors:
                course_sections_bottom.append(section)
            else:
                course_sections_top.append(section)
        else:
            contributor_sections.setdefault(section.contributor, {
                'total_votes': 0,
                'sections': []
            })['sections'].append(section)

            for result in section.results:
                if isinstance(result, TextResult):
                    contributor_sections[
                        section.contributor]['total_votes'] += 1
                elif isinstance(result, RatingResult) or isinstance(
                        result, YesNoResult):
                    # Only count rating results if we show the grades.
                    if show_grades:
                        contributor_sections[section.contributor][
                            'total_votes'] += result.total_count

    # Show a warning if course is still in evaluation (for reviewer 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

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

    template_data = dict(course=course,
                         course_sections_top=course_sections_top,
                         course_sections_bottom=course_sections_bottom,
                         contributor_sections=contributor_sections,
                         evaluation_warning=evaluation_warning,
                         sufficient_votes_warning=sufficient_votes_warning,
                         show_grades=show_grades,
                         reviewer=request.user.is_reviewer,
                         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)
예제 #10
0
파일: exporters.py 프로젝트: phoeinx/EvaP
    def export(self,
               response,
               course_types_list,
               include_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
                if not course.can_publish_grades and not include_not_enough_answers:
                    continue
                results = OrderedDict()
                for questionnaire, contributor, __, data, __ 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, cr[0].name))
            used_questionnaires = sorted(used_questionnaires)

            course_type_names = [
                ct.name
                for ct in CourseType.objects.filter(pk__in=course_types)
            ]
            writec(
                self,
                _("Evaluation {0}\n\n{1}").format(
                    self.semester.name, ", ".join(course_type_names)),
                "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, _("Avg."), "avg")
                writec(self, _("Std. dev."), "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()

                filtered_questions = self.filter_text_and_heading_questions(
                    questionnaire.question_set.all())

                for question in filtered_questions:
                    if question.is_heading_question:
                        writen(self, question.text, "italic")
                    else:
                        writen(self, question.text)

                    for course, results in courses_with_results:
                        if questionnaire.id not in results or question.is_heading_question:
                            self.write_two_empty_cells_with_borders()
                            continue
                        qn_results = results[questionnaire.id]
                        values = []
                        deviations = []
                        total_count = 0
                        approval_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
                                if grade_result.question.is_yes_no_question:
                                    approval_count += grade_result.approval_count
                        enough_answers = course.can_publish_grades
                        if values and enough_answers:
                            avg = sum(values) / total_count
                            dev = sum(deviations) / total_count

                            if question.is_yes_no_question:
                                percent_approval = float(
                                    approval_count) / float(
                                        total_count) if total_count > 0 else 0
                                writec(self, "{:.0%}".format(percent_approval),
                                       self.grade_to_style(avg))
                                writec(self, None, "border_right")
                            else:
                                writec(self, avg, self.grade_to_style(avg))
                                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)
예제 #11
0
def merge_users(main_user, other_user, preview=False):
    """Merges other_user into main_user"""

    merged_user = dict()
    merged_user['username'] = main_user.username
    merged_user[
        'title'] = main_user.title if main_user.title else other_user.title or ""
    merged_user[
        'first_name'] = main_user.first_name if main_user.first_name else other_user.first_name or ""
    merged_user[
        'last_name'] = main_user.last_name if main_user.last_name else other_user.last_name or ""
    merged_user[
        'email'] = main_user.email if main_user.email else other_user.email or None

    merged_user['groups'] = Group.objects.filter(
        user__in=[main_user, other_user]).distinct()
    merged_user[
        'is_superuser'] = main_user.is_superuser or other_user.is_superuser
    merged_user['delegates'] = UserProfile.objects.filter(
        represented_users__in=[main_user, other_user]).distinct()
    merged_user['represented_users'] = UserProfile.objects.filter(
        delegates__in=[main_user, other_user]).distinct()
    merged_user['cc_users'] = UserProfile.objects.filter(
        ccing_users__in=[main_user, other_user]).distinct()
    merged_user['ccing_users'] = UserProfile.objects.filter(
        cc_users__in=[main_user, other_user]).distinct()

    errors = []
    warnings = []
    if any(contribution.course in [
            contribution.course
            for contribution in main_user.get_sorted_contributions()
    ] for contribution in other_user.get_sorted_contributions()):
        errors.append('contributions')
    if any(course in main_user.get_sorted_courses_participating_in()
           for course in other_user.get_sorted_courses_participating_in()):
        errors.append('courses_participating_in')
    if any(course in main_user.get_sorted_courses_voted_for()
           for course in other_user.get_sorted_courses_voted_for()):
        errors.append('courses_voted_for')

    if main_user.reward_point_grantings.all().exists(
    ) and other_user.reward_point_grantings.all().exists():
        warnings.append('rewards')

    merged_user['contributions'] = Contribution.objects.filter(
        contributor__in=[main_user, other_user]).order_by(
            'course__semester__created_at', 'course__name_de')
    merged_user['courses_participating_in'] = Course.objects.filter(
        participants__in=[main_user, other_user]).order_by(
            'semester__created_at', 'name_de')
    merged_user['courses_voted_for'] = Course.objects.filter(
        voters__in=[main_user, other_user]).order_by('semester__created_at',
                                                     'name_de')

    merged_user[
        'reward_point_grantings'] = main_user.reward_point_grantings.all(
        ) if main_user.reward_point_grantings.all().exists(
        ) else other_user.reward_point_grantings.all()
    merged_user[
        'reward_point_redemptions'] = main_user.reward_point_redemptions.all(
        ) if main_user.reward_point_redemptions.all().exists(
        ) else other_user.reward_point_redemptions.all()

    if preview or errors:
        return merged_user, errors, warnings

    # update last_modified_user for courses and grade documents
    Course.objects.filter(last_modified_user=other_user).update(
        last_modified_user=main_user)
    GradeDocument.objects.filter(last_modified_user=other_user).update(
        last_modified_user=main_user)

    # email must not exist twice. other_user can't be deleted before contributions have been changed
    other_user.email = ""
    other_user.save()

    # update values for main user
    for key, value in merged_user.items():
        attr = getattr(main_user, key)
        if hasattr(attr, "set"):
            attr.set(
                value)  # use the 'set' method for e.g. many-to-many relations
        else:
            setattr(main_user, key,
                    value)  # use direct assignment for everything else
    main_user.save()

    # delete rewards
    other_user.reward_point_grantings.all().delete()
    other_user.reward_point_redemptions.all().delete()

    # refresh results cache
    for course in Course.objects.filter(
            contributions__contributor=main_user).distinct():
        calculate_results(course, force_recalculation=True)

    # delete other_user
    other_user.delete()

    return merged_user, errors, warnings
예제 #12
0
파일: views.py 프로젝트: Benedikt1992/EvaP
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') == 'true'  # if parameter is not given, show own view.

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

    # filter text answers
    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

    # remove empty sections
    sections = [section for section in sections if section.results]

    # 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 reviewer 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_reviewer 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,
            reviewer=request.user.is_reviewer,
            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)
예제 #13
0
    def export(self, response, course_types_list, include_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
                if not course.can_publish_grades and not include_not_enough_answers:
                    continue
                results = OrderedDict()
                for questionnaire, contributor, __, data, __ 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, cr[0].name))
            used_questionnaires = sorted(used_questionnaires)

            course_type_names = [ct.name for ct in CourseType.objects.filter(pk__in=course_types)]
            writec(self, _("Evaluation {0}\n\n{1}").format(self.semester.name, ", ".join(course_type_names)), "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, _("Avg."), "avg")
                writec(self, _("Std. dev."), "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
                        approval_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
                                if grade_result.question.is_yes_no_question:
                                    approval_count += grade_result.approval_count
                        enough_answers = course.can_publish_grades
                        if values and enough_answers:
                            avg = sum(values) / total_count
                            dev = sum(deviations) / total_count

                            if question.is_yes_no_question:
                                percent_approval = float(approval_count) / float(total_count) if total_count > 0 else 0
                                writec(self, "{:.0%}".format(percent_approval), self.grade_to_style(avg))
                                writec(self, None, "border_right")
                            else:
                                writec(self, avg, self.grade_to_style(avg))
                                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)
예제 #14
0
파일: tools.py 프로젝트: JenniferStamm/EvaP
def merge_users(main_user, other_user, preview=False):
    """Merges other_user into main_user"""

    merged_user = dict()
    merged_user['username'] = main_user.username
    merged_user['is_active'] = main_user.is_active or other_user.is_active
    merged_user['title'] = main_user.title if main_user.title else other_user.title or ""
    merged_user['first_name'] = main_user.first_name if main_user.first_name else other_user.first_name or ""
    merged_user['last_name'] = main_user.last_name if main_user.last_name else other_user.last_name or ""
    merged_user['email'] = main_user.email if main_user.email else other_user.email or None

    merged_user['groups'] = Group.objects.filter(user__in=[main_user, other_user]).distinct()
    merged_user['is_superuser'] = main_user.is_superuser or other_user.is_superuser
    merged_user['delegates'] = UserProfile.objects.filter(represented_users__in=[main_user, other_user]).distinct()
    merged_user['represented_users'] = UserProfile.objects.filter(delegates__in=[main_user, other_user]).distinct()
    merged_user['cc_users'] = UserProfile.objects.filter(ccing_users__in=[main_user, other_user]).distinct()
    merged_user['ccing_users'] = UserProfile.objects.filter(cc_users__in=[main_user, other_user]).distinct()

    errors = []
    warnings = []
    if any(contribution.course in [contribution.course for contribution in main_user.get_sorted_contributions()] for contribution in other_user.get_sorted_contributions()):
        errors.append('contributions')
    if any(course in main_user.get_sorted_courses_participating_in() for course in other_user.get_sorted_courses_participating_in()):
        errors.append('courses_participating_in')
    if any(course in main_user.get_sorted_courses_voted_for() for course in other_user.get_sorted_courses_voted_for()):
        errors.append('courses_voted_for')

    if main_user.reward_point_grantings.all().exists() and other_user.reward_point_grantings.all().exists():
        warnings.append('rewards')

    merged_user['contributions'] = Contribution.objects.filter(contributor__in=[main_user, other_user]).order_by('course__semester__created_at', 'course__name_de')
    merged_user['courses_participating_in'] = Course.objects.filter(participants__in=[main_user, other_user]).order_by('semester__created_at', 'name_de')
    merged_user['courses_voted_for'] = Course.objects.filter(voters__in=[main_user, other_user]).order_by('semester__created_at', 'name_de')

    merged_user['reward_point_grantings'] = main_user.reward_point_grantings.all() if main_user.reward_point_grantings.all().exists() else other_user.reward_point_grantings.all()
    merged_user['reward_point_redemptions'] = main_user.reward_point_redemptions.all() if main_user.reward_point_redemptions.all().exists() else other_user.reward_point_redemptions.all()

    if preview or errors:
        return merged_user, errors, warnings

    # update last_modified_user for courses and grade documents
    Course.objects.filter(last_modified_user=other_user).update(last_modified_user=main_user)
    GradeDocument.objects.filter(last_modified_user=other_user).update(last_modified_user=main_user)

    # email must not exist twice. other_user can't be deleted before contributions have been changed
    other_user.email = ""
    other_user.save()

    # update values for main user
    for key, value in merged_user.items():
        attr = getattr(main_user, key)
        if hasattr(attr, "set"):
            attr.set(value)  # use the 'set' method for e.g. many-to-many relations
        else:
            setattr(main_user, key, value)  # use direct assignment for everything else
    main_user.save()

    # delete rewards
    other_user.reward_point_grantings.all().delete()
    other_user.reward_point_redemptions.all().delete()

    # refresh results cache
    for course in Course.objects.filter(contributions__contributor=main_user).distinct():
        calculate_results(course, force_recalculation=True)

    # delete other_user
    other_user.delete()

    return merged_user, errors, warnings
예제 #15
0
파일: test_tools.py 프로젝트: phoeinx/EvaP
    def test_cache_unpublished_course(self):
        course = mommy.make(Course, state='published')
        calculate_results(course)
        course.unpublish()

        self.assertIsNone(caches['results'].get(get_results_cache_key(course)))
예제 #16
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_page(request.user):
        raise PermissionDenied

    sections = calculate_results(course)

    if request.user.is_reviewer:
        public_view = request.GET.get(
            'public_view'
        ) != 'false'  # if parameter is not given, show public view.
    else:
        public_view = request.GET.get(
            'public_view'
        ) == 'true'  # if parameter is not given, show own view.

    # If grades are not published, there is no public view
    if not course.has_enough_voters_to_publish_grades:
        public_view = False

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

    show_grades = course.can_user_see_grades(request.user)

    # remove text answers and grades if the user may not see them
    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))
            elif isinstance(result, RatingResult) and not show_grades:
                results.append(
                    RatingResult(question=result.question,
                                 total_count=result.total_count,
                                 average=None,
                                 counts=None,
                                 warning=result.warning))
            elif isinstance(result, YesNoResult) and not show_grades:
                results.append(
                    YesNoResult(question=result.question,
                                total_count=result.total_count,
                                average=None,
                                counts=None,
                                warning=result.warning,
                                approval_count=None))
            else:
                results.append(result)

        section.results[:] = results

    # filter empty headings
    for section in sections:
        filtered_results = []
        for index in range(len(section.results)):
            result = section.results[index]
            # filter out if there are no more questions or the next question is also a heading question
            if isinstance(result, HeadingResult):
                if index == len(section.results) - 1 or isinstance(
                        section.results[index + 1], HeadingResult):
                    continue
            filtered_results.append(result)
        section.results[:] = filtered_results

    # remove empty sections
    sections = [section for section in sections if section.results]

    # group by contributor
    course_sections_top = []
    course_sections_bottom = []
    contributor_sections = OrderedDict()
    for section in sections:
        if section.contributor is None:
            if section.questionnaire.is_below_contributors:
                course_sections_bottom.append(section)
            else:
                course_sections_top.append(section)
        else:
            contributor_sections.setdefault(section.contributor, {
                'total_votes': 0,
                'sections': []
            })['sections'].append(section)

            for result in section.results:
                if isinstance(result, TextResult):
                    contributor_sections[
                        section.contributor]['total_votes'] += 1
                elif isinstance(result, RatingResult) or isinstance(
                        result, YesNoResult):
                    # Only count rating results if we show the grades.
                    if show_grades:
                        contributor_sections[section.contributor][
                            'total_votes'] += result.total_count

    course.distribution = calculate_average_distribution(
        course) if show_grades else None
    course.avg_grade = distribution_to_grade(course.distribution)

    template_data = dict(course=course,
                         course_sections_top=course_sections_top,
                         course_sections_bottom=course_sections_bottom,
                         contributor_sections=contributor_sections,
                         reviewer=request.user.is_reviewer,
                         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)