コード例 #1
0
ファイル: tools.py プロジェクト: jb3rndt/EvaP
def _get_results_impl(evaluation: Evaluation,
                      *,
                      refetch_related_objects: bool = True):
    if refetch_related_objects:
        discard_cached_related_objects(evaluation)

    prefetch_related_objects([evaluation], *GET_RESULTS_PREFETCH_LOOKUPS)

    tas_per_contribution_question: Dict[Tuple[
        int, int], List[TextAnswer]] = unordered_groupby(
            ((textanswer.contribution_id, textanswer.question_id), textanswer)
            for contribution in evaluation.contributions.all()
            for textanswer in contribution.textanswer_set.all()
            if textanswer.state in
            [TextAnswer.State.PRIVATE, TextAnswer.State.PUBLISHED])

    racs_per_contribution_question: Dict[Tuple[
        int, int], List[RatingAnswerCounter]] = unordered_groupby(
            ((counter.contribution_id, counter.question_id), counter)
            for contribution in evaluation.contributions.all()
            for counter in contribution.ratinganswercounter_set.all())

    contributor_contribution_results = []
    for contribution in evaluation.contributions.all():
        questionnaire_results = []
        for questionnaire in contribution.questionnaires.all():
            results: List[Union[HeadingResult, TextResult, RatingResult]] = []
            for question in questionnaire.questions.all():
                if question.is_heading_question:
                    results.append(HeadingResult(question=question))
                    continue
                text_result = None
                if question.can_have_textanswers and evaluation.can_publish_text_results:
                    answers = tas_per_contribution_question.get(
                        (contribution.id, question.id), [])
                    text_result = TextResult(
                        question=question,
                        answers=answers,
                        answers_visible_to=textanswers_visible_to(
                            contribution))
                if question.is_rating_question:
                    if evaluation.can_publish_rating_results:
                        answer_counters = racs_per_contribution_question.get(
                            (contribution.id, question.id), [])
                    else:
                        answer_counters = None
                    results.append(
                        RatingResult(question,
                                     answer_counters,
                                     additional_text_result=text_result))
                elif question.is_text_question and evaluation.can_publish_text_results:
                    assert text_result is not None
                    results.append(text_result)

            questionnaire_results.append(
                QuestionnaireResult(questionnaire, results))
        contributor_contribution_results.append(
            ContributionResult(contribution.contributor, contribution.label,
                               questionnaire_results))
    return EvaluationResult(contributor_contribution_results)
コード例 #2
0
    def check_enrollment_data_sanity(self):
        enrollments_per_user = unordered_groupby(
            (enrollment[1].email, enrollment)
            for enrollment in self.enrollments)

        for email, enrollments in enrollments_per_user.items():
            if len(enrollments) > settings.IMPORTER_MAX_ENROLLMENTS:
                self.warnings[ImporterWarning.MANY].append(
                    _("Warning: User {} has {} enrollments, which is a lot.").
                    format(email, len(enrollments)))
コード例 #3
0
ファイル: views.py プロジェクト: jb3rndt/EvaP
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)
コード例 #4
0
ファイル: anonymize.py プロジェクト: jb3rndt/EvaP
    def anonymize_answers(self, lorem_ipsum):
        # This method is very mathematical and has a lot of "one new variable per line" code, but we think it's okay.
        # pylint: disable=too-many-locals
        self.stdout.write("Replacing text answers with fake ones...")
        for text_answer in TextAnswer.objects.all():
            text_answer.answer = self.lorem(text_answer.answer, lorem_ipsum)
            if text_answer.original_answer:
                text_answer.original_answer = self.lorem(
                    text_answer.original_answer, lorem_ipsum)
            text_answer.save()

        self.stdout.write("Shuffling rating answer counter counts...")

        contributions = Contribution.objects.all().prefetch_related(
            "ratinganswercounter_set__question")
        try:
            self.stdout.ending = ""
            progress_bar = ProgressBar(self.stdout, contributions.count())
            for contribution_counter, contribution in enumerate(contributions):
                progress_bar.update(contribution_counter + 1)

                counters_per_question = unordered_groupby(
                    (counter.question, counter)
                    for counter in contribution.ratinganswercounter_set.all())

                for question, counters in counters_per_question.items():
                    original_sum = sum(counter.count for counter in counters)

                    missing_values = set(
                        CHOICES[question.type].values).difference(
                            set(c.answer for c in counters))
                    missing_values.discard(
                        NO_ANSWER
                    )  # don't add NO_ANSWER counter if it didn't exist before
                    for value in missing_values:
                        counters.append(
                            RatingAnswerCounter(question=question,
                                                contribution=contribution,
                                                answer=value,
                                                count=0))

                    generated_counts = [random.random()
                                        for c in counters]  # nosec
                    generated_sum = sum(generated_counts)
                    generated_counts = [
                        floor(count / generated_sum * original_sum)
                        for count in generated_counts
                    ]

                    to_add = original_sum - sum(generated_counts)
                    index = random.randint(0,
                                           len(generated_counts) - 1)  # nosec
                    generated_counts[index] += to_add

                    for counter, generated_count in zip(
                            counters, generated_counts):
                        assert generated_count >= 0
                        counter.count = generated_count

                        if counter.count:
                            counter.save()
                        elif counter.id:
                            counter.delete()

                    assert original_sum == sum(counter.count
                                               for counter in counters)
        finally:
            self.stdout.ending = "\n"