Ejemplo n.º 1
0
    def test_update_answer_scores(self):

        comparison_results = calculate_score(comparison_pairs=[
            ComparisonPair(key1=1, key2=2, winner=ComparisonWinner.key1)
        ])
        scores = update_answer_scores([], 1, comparison_results)
        self.assertEqual(len(scores), 2)
        for score in scores:
            self.assertIsNone(score.id)

        score = AnswerScore(answer_id=1, id=2)
        scores = update_answer_scores([score], 1, comparison_results)
        self.assertEqual(len(scores), 2)
        self.assertEqual(scores[0].id, 2)
        self.assertIsNone(scores[1].id)

        comparison_results = calculate_score(comparison_pairs=[
            ComparisonPair(key1=1, key2=2, winner=ComparisonWinner.key1),
            ComparisonPair(key1=3, key2=4, winner=ComparisonWinner.key1)
        ])
        score = AnswerScore(answer_id=1, id=2)
        scores = update_answer_scores([score], 1, comparison_results)
        self.assertEqual(len(scores), 4)
Ejemplo n.º 2
0
    def get(self, course_uuid, assignment_uuid):
        """
        Return a list of answers for a assignment based on search criteria. The
        list of the answers are paginated. If there is any answers from instructor
        or TA, their answers will be on top of the list (unless they are comparable).

        :param course_uuid: course uuid
        :param assignment_uuid: assignment uuid
        :return: list of answers
        """
        course = Course.get_active_by_uuid_or_404(course_uuid)
        assignment = Assignment.get_active_by_uuid_or_404(assignment_uuid)

        require(
            READ,
            assignment,
            title="Answers Unavailable",
            message=
            "Answers are visible only to those enrolled in the course. Please double-check your enrollment in this course."
        )
        restrict_user = not allow(MANAGE, assignment)

        params = answer_list_parser.parse_args()

        # if assingment has no rank display limit set, restricted users can't force to retreive by rank
        if params[
                'orderBy'] == 'score' and restrict_user and not assignment.rank_display_limit:
            abort(
                400,
                title="Answers Unavailable",
                message=
                "Sorry, you cannot cannot see answers by rank for this assignment."
            )

        if restrict_user and not assignment.after_comparing:
            # only the answer from student himself/herself should be returned
            params['author'] = current_user.uuid

        # this query could be further optimized by reduction the selected columns
        query = Answer.query \
            .options(joinedload('file')) \
            .options(joinedload('user')) \
            .options(joinedload('group')) \
            .options(joinedload('score')) \
            .options(undefer_group('counts')) \
            .outerjoin(UserCourse, and_(
                Answer.user_id == UserCourse.user_id,
                UserCourse.course_id == course.id
            )) \
            .add_columns(
                and_(
                    UserCourse != None,
                    UserCourse.course_role.__eq__(CourseRole.instructor),
                    not Answer.comparable
                ).label("instructor_role"),
                and_(
                    UserCourse != None,
                    UserCourse.course_role.__eq__(CourseRole.teaching_assistant),
                    not Answer.comparable
                ).label("ta_role")
            ) \
            .filter(and_(
                Answer.assignment_id == assignment.id,
                Answer.active == True,
                Answer.practice == False,
                Answer.draft == False,
                or_(
                    and_(UserCourse.course_role != CourseRole.dropped, Answer.user_id != None),
                    Answer.group_id != None
                )
            )) \
            .order_by(desc('instructor_role'), desc('ta_role'))

        if params['author']:
            user = User.get_by_uuid_or_404(params['author'])
            group = user.get_course_group(course.id)
            if group:
                query = query.filter(
                    or_(Answer.user_id == user.id,
                        Answer.group_id == group.id))
            else:
                query = query.filter(Answer.user_id == user.id)
        elif params['group']:
            group = Group.get_active_by_uuid_or_404(params['group'])
            query = query.filter(
                or_(UserCourse.group_id == group.id,
                    Answer.group_id == group.id))

        if params['ids']:
            query = query.filter(Answer.uuid.in_(params['ids'].split(',')))

        if params['top']:
            query = query.filter(Answer.top_answer == True)

        if params['orderBy'] == 'score':
            # use outer join to include comparable answers that are not yet compared (for non-restricted users)
            query = query.outerjoin(AnswerScore) \
                .filter(Answer.comparable == True) \
                .order_by(AnswerScore.score.desc(), Answer.submission_date.desc(), Answer.created.desc())

            if restrict_user:
                # when orderd by rank, students won't see answers that are not compared (i.e. no score/rank)
                query = query.filter(AnswerScore.score.isnot(None))

            # limit answers up to rank if rank_display_limit is set and current_user is restricted (student)
            if assignment.rank_display_limit and restrict_user:
                score_for_rank = AnswerScore.get_score_for_rank(
                    assignment.id, assignment.rank_display_limit)

                # display answers with score >= score_for_rank
                if score_for_rank != None:
                    # will get all answers with a score greater than or equal to the score for a given rank
                    # the '- 0.00001' fixes floating point precision problems
                    query = query.filter(
                        AnswerScore.score >= score_for_rank - 0.00001)

        else:
            # when ordered by date, non-comparable answers should be on top of the list
            query = query.order_by(Answer.comparable,
                                   Answer.submission_date.desc(),
                                   Answer.created.desc())

        page = query.paginate(params['page'],
                              params['perPage'],
                              error_out=False)
        # remove label entities from results
        page.items = [
            answer for (answer, instructor_role, ta_role) in page.items
        ]

        on_answer_list_get.send(self,
                                event_name=on_answer_list_get.name,
                                user=current_user,
                                course_id=course.id,
                                data={'assignment_id': assignment.id})

        # only include score/rank info if:
        # - requesters are non-restricted users (i.e. instructors / TAs); or,
        # - retrieving answers ordered by score/rank
        include_score = (not restrict_user) or \
            (params['orderBy'] == 'score' and assignment.rank_display_limit)

        return {
            "objects":
            marshal(
                page.items,
                dataformat.get_answer(restrict_user,
                                      include_score=include_score)),
            "page":
            page.page,
            "pages":
            page.pages,
            "total":
            page.total,
            "per_page":
            page.per_page
        }
Ejemplo n.º 3
0
    def get(self, course_uuid, assignment_uuid):
        """
        Return a list of answers for a assignment based on search criteria. The
        list of the answers are paginated. If there is any answers from instructor
        or TA, their answers will be on top of the list (unless they are comparable).

        :param course_uuid: course uuid
        :param assignment_uuid: assignment uuid
        :return: list of answers
        """
        course = Course.get_active_by_uuid_or_404(course_uuid)
        assignment = Assignment.get_active_by_uuid_or_404(assignment_uuid)

        require(READ, assignment,
            title="Answers Unavailable",
            message="Answers are visible only to those enrolled in the course. Please double-check your enrollment in this course.")
        restrict_user = not allow(MANAGE, assignment)

        params = answer_list_parser.parse_args()

        # if assingment has no rank display limit set, restricted users can't force to retreive by rank
        if params['orderBy'] == 'score' and restrict_user and not assignment.rank_display_limit:
            abort(400, title="Answers Unavailable", message="Sorry, you cannot cannot see answers by rank for this assignment.")

        if restrict_user and not assignment.after_comparing:
            # only the answer from student himself/herself should be returned
            params['author'] = current_user.uuid

        # this query could be further optimized by reduction the selected columns
        query = Answer.query \
            .options(joinedload('file')) \
            .options(joinedload('user')) \
            .options(joinedload('group')) \
            .options(joinedload('score')) \
            .options(undefer_group('counts')) \
            .outerjoin(UserCourse, and_(
                Answer.user_id == UserCourse.user_id,
                UserCourse.course_id == course.id
            )) \
            .add_columns(
                and_(
                    UserCourse != None,
                    UserCourse.course_role.__eq__(CourseRole.instructor),
                    not Answer.comparable
                ).label("instructor_role"),
                and_(
                    UserCourse != None,
                    UserCourse.course_role.__eq__(CourseRole.teaching_assistant),
                    not Answer.comparable
                ).label("ta_role")
            ) \
            .filter(and_(
                Answer.assignment_id == assignment.id,
                Answer.active == True,
                Answer.practice == False,
                Answer.draft == False,
                or_(
                    and_(UserCourse.course_role != CourseRole.dropped, Answer.user_id != None),
                    Answer.group_id != None
                )
            )) \
            .order_by(desc('instructor_role'), desc('ta_role'))

        if params['author']:
            user = User.get_by_uuid_or_404(params['author'])
            group = user.get_course_group(course.id)
            if group:
                query = query.filter(or_(
                    Answer.user_id == user.id,
                    Answer.group_id == group.id
                ))
            else:
                query = query.filter(Answer.user_id == user.id)
        elif params['group']:
            group = Group.get_active_by_uuid_or_404(params['group'])
            query = query.filter(or_(
                UserCourse.group_id == group.id,
                Answer.group_id == group.id
            ))

        if params['ids']:
            query = query.filter(Answer.uuid.in_(params['ids'].split(',')))

        if params['top']:
            query = query.filter(Answer.top_answer == True)

        if params['orderBy'] == 'score':
            # use outer join to include comparable answers that are not yet compared (for non-restricted users)
            query = query.outerjoin(AnswerScore) \
                .filter(Answer.comparable == True) \
                .order_by(AnswerScore.score.desc(), Answer.submission_date.desc(), Answer.created.desc())

            if restrict_user:
                # when orderd by rank, students won't see answers that are not compared (i.e. no score/rank)
                query = query.filter(AnswerScore.score.isnot(None))

            # limit answers up to rank if rank_display_limit is set and current_user is restricted (student)
            if assignment.rank_display_limit and restrict_user:
                score_for_rank = AnswerScore.get_score_for_rank(assignment.id, assignment.rank_display_limit)

                # display answers with score >= score_for_rank
                if score_for_rank != None:
                    # will get all answers with a score greater than or equal to the score for a given rank
                    # the '- 0.00001' fixes floating point precision problems
                    query = query.filter(AnswerScore.score >= score_for_rank - 0.00001)

        else:
            # when ordered by date, non-comparable answers should be on top of the list
            query = query.order_by(Answer.comparable, Answer.submission_date.desc(), Answer.created.desc())

        page = query.paginate(params['page'], params['perPage'], error_out=False)
        # remove label entities from results
        page.items = [answer for (answer, instructor_role, ta_role) in page.items]

        on_answer_list_get.send(
            self,
            event_name=on_answer_list_get.name,
            user=current_user,
            course_id=course.id,
            data={'assignment_id': assignment.id})

        # only include score/rank info if:
        # - requesters are non-restricted users (i.e. instructors / TAs); or,
        # - retrieving answers ordered by score/rank
        include_score = (not restrict_user) or \
            (params['orderBy'] == 'score' and assignment.rank_display_limit)

        return {"objects": marshal(page.items, dataformat.get_answer(restrict_user, include_score=include_score)),
                "page": page.page, "pages": page.pages,
                "total": page.total, "per_page": page.per_page}
Ejemplo n.º 4
0
    def get(self, course_uuid, assignment_uuid):
        """
        Return a list of answers for a assignment based on search criteria. The
        list of the answers are paginated. If there is any answers from instructor
        or TA, their answers will be on top of the list.

        :param course_uuid: course uuid
        :param assignment_uuid: assignment uuid
        :return: list of answers
        """
        course = Course.get_active_by_uuid_or_404(course_uuid)
        assignment = Assignment.get_active_by_uuid_or_404(assignment_uuid)

        require(READ, assignment,
            title="Answers Unavailable",
            message="Answers are visible only to those enrolled in the course. Please double-check your enrollment in this course.")
        restrict_user = not allow(MANAGE, assignment)

        params = answer_list_parser.parse_args()

        if restrict_user and not assignment.after_comparing:
            # only the answer from student himself/herself should be returned
            params['author'] = current_user.uuid

        # this query could be further optimized by reduction the selected columns
        query = Answer.query \
            .options(joinedload('file')) \
            .options(joinedload('user')) \
            .options(joinedload('score')) \
            .options(undefer_group('counts')) \
            .join(UserCourse, and_(
                Answer.user_id == UserCourse.user_id,
                UserCourse.course_id == course.id
            )) \
            .add_columns(
                UserCourse.course_role.__eq__(CourseRole.instructor).label("instructor_role"),
                UserCourse.course_role.__eq__(CourseRole.teaching_assistant).label("ta_role")
            ) \
            .filter(and_(
                Answer.assignment_id == assignment.id,
                Answer.active == True,
                Answer.practice == False,
                Answer.draft == False,
                UserCourse.course_role != CourseRole.dropped
            )) \
            .order_by(desc('instructor_role'), desc('ta_role'))

        if params['author']:
            user = User.get_by_uuid_or_404(params['author'])
            query = query.filter(Answer.user_id == user.id)
        elif params['group']:
            query = query.filter(UserCourse.group_name == params['group'])

        if params['ids']:
            query = query.filter(Answer.uuid.in_(params['ids'].split(',')))

        if params['top']:
            query = query.filter(Answer.top_answer == True)

        if params['orderBy'] == 'score':
            query = query.join(AnswerScore) \
                .order_by(AnswerScore.score.desc(), Answer.created.desc())

            # limit answers up to rank if rank_display_limit is set and current_user is restricted (student)
            if assignment.rank_display_limit and restrict_user:
                score_for_rank = AnswerScore.get_score_for_rank(assignment.id, assignment.rank_display_limit)

                # display answers with score >= score_for_rank
                if score_for_rank != None:
                    # will get all answer with a score greater than or equal to the score for a given rank
                    # the '- 0.00001' fixes floating point precision problems
                    query = query.filter(AnswerScore.score >= score_for_rank - 0.00001)

        else:
            query = query.order_by(Answer.created.desc())

        page = query.paginate(params['page'], params['perPage'], error_out=False)
        # remove label entities from results
        page.items = [answer for (answer, instructor_role, ta_role) in page.items]

        on_answer_list_get.send(
            self,
            event_name=on_answer_list_get.name,
            user=current_user,
            course_id=course.id,
            data={'assignment_id': assignment.id})

        return {"objects": marshal(page.items, dataformat.get_answer(restrict_user)),
                "page": page.page, "pages": page.pages,
                "total": page.total, "per_page": page.per_page}