def get(self, request, exam_id=None, course_id=None, content_id=None):  # pylint: disable=unused-argument
        """
        HTTP GET handler.
            Scenarios:
                by exam_id: calls get_exam_by_id()
                by course_id, content_id: get_exam_by_content_id()

        """
        if exam_id:
            data = get_exam_by_id(exam_id)
        elif course_id is not None:
            if content_id is not None:
                # get by course_id & content_id
                data = get_exam_by_content_id(course_id, content_id)
            else:
                data = get_all_exams_for_course(course_id=course_id,
                                                active_only=True)
        return Response(data)
Beispiel #2
0
    def get(self, request, exam_id=None, course_id=None, content_id=None):  # pylint: disable=unused-argument
        """
        HTTP GET handler.
            Scenarios:
                by exam_id: calls get_exam_by_id()
                by course_id, content_id: get_exam_by_content_id()

        """
        if exam_id:
            data = get_exam_by_id(exam_id)
        elif course_id is not None:
            if content_id is not None:
                # get by course_id & content_id
                data = get_exam_by_content_id(course_id, content_id)
            else:
                data = get_all_exams_for_course(
                    course_id=course_id,
                    active_only=True
                )
        return Response(data)
Beispiel #3
0
        """

        if exam_id:
            try:
                return Response(data=get_exam_by_id(exam_id),
                                status=status.HTTP_200_OK)
            except ProctoredExamNotFoundException, ex:
                LOG.exception(ex)
                return Response(status=status.HTTP_400_BAD_REQUEST,
                                data={"detail": "The exam_id does not exist."})
        else:
            if course_id is not None:
                if content_id is not None:
                    # get by course_id & content_id
                    try:
                        return Response(data=get_exam_by_content_id(
                            course_id, content_id),
                                        status=status.HTTP_200_OK)
                    except ProctoredExamNotFoundException, ex:
                        LOG.exception(ex)
                        return Response(
                            status=status.HTTP_400_BAD_REQUEST,
                            data={
                                "detail":
                                "The exam with course_id, content_id does not exist."
                            })
                else:
                    timed_exams_only = not request.user.is_staff
                    result_set = get_all_exams_for_course(
                        course_id=course_id,
                        timed_exams_only=timed_exams_only,
                        active_only=True)
Beispiel #4
0
def register_special_exams(course_key):
    """
    This is typically called on a course published signal. The course is examined for sequences
    that are marked as timed exams. Then these are registered with the edx-proctoring
    subsystem. Likewise, if formerly registered exams are unmarked, then those
    registered exams are marked as inactive
    """

    if not settings.FEATURES.get('ENABLE_SPECIAL_EXAMS'):
        # if feature is not enabled then do a quick exit
        return

    course = modulestore().get_course(course_key)
    if not course.enable_proctored_exams and not course.enable_timed_exams:
        # likewise if course does not have these features turned on
        # then quickly exit
        return

    # get all sequences, since they can be marked as timed/proctored exams
    _timed_exams = modulestore().get_items(course_key,
                                           qualifiers={
                                               'category': 'sequential',
                                           },
                                           settings={
                                               'is_time_limited': True,
                                           })

    # filter out any potential dangling sequences
    timed_exams = [
        timed_exam for timed_exam in _timed_exams
        if is_item_in_course_tree(timed_exam)
    ]

    # enumerate over list of sequences which are time-limited and
    # add/update any exam entries in edx-proctoring
    for timed_exam in timed_exams:
        msg = (
            'Found {location} as a timed-exam in course structure. Inspecting...'
            .format(location=unicode(timed_exam.location)))
        log.info(msg)

        try:
            exam = get_exam_by_content_id(unicode(course_key),
                                          unicode(timed_exam.location))
            # update case, make sure everything is synced
            exam_id = update_exam(
                exam_id=exam['id'],
                exam_name=timed_exam.display_name,
                time_limit_mins=timed_exam.default_time_limit_minutes,
                due_date=timed_exam.due,
                is_proctored=timed_exam.is_proctored_exam,
                is_practice_exam=timed_exam.is_practice_exam,
                is_active=True,
                hide_after_due=timed_exam.hide_after_due,
            )
            msg = 'Updated timed exam {exam_id}'.format(exam_id=exam['id'])
            log.info(msg)

        except ProctoredExamNotFoundException:
            exam_id = create_exam(
                course_id=unicode(course_key),
                content_id=unicode(timed_exam.location),
                exam_name=timed_exam.display_name,
                time_limit_mins=timed_exam.default_time_limit_minutes,
                due_date=timed_exam.due,
                is_proctored=timed_exam.is_proctored_exam,
                is_practice_exam=timed_exam.is_practice_exam,
                is_active=True,
                hide_after_due=timed_exam.hide_after_due,
            )
            msg = 'Created new timed exam {exam_id}'.format(exam_id=exam_id)
            log.info(msg)

        # only create/update exam policy for the proctored exams
        if timed_exam.is_proctored_exam and not timed_exam.is_practice_exam:
            try:
                update_review_policy(
                    exam_id=exam_id,
                    set_by_user_id=timed_exam.edited_by,
                    review_policy=timed_exam.exam_review_rules)
            except ProctoredExamReviewPolicyNotFoundException:
                if timed_exam.exam_review_rules:  # won't save an empty rule.
                    create_exam_review_policy(
                        exam_id=exam_id,
                        set_by_user_id=timed_exam.edited_by,
                        review_policy=timed_exam.exam_review_rules)
                    msg = 'Created new exam review policy with exam_id {exam_id}'.format(
                        exam_id=exam_id)
                    log.info(msg)
        else:
            try:
                # remove any associated review policy
                remove_review_policy(exam_id=exam_id)
            except ProctoredExamReviewPolicyNotFoundException:
                pass

    # then see which exams we have in edx-proctoring that are not in
    # our current list. That means the the user has disabled it
    exams = get_all_exams_for_course(course_key)

    for exam in exams:
        if exam['is_active']:
            # try to look up the content_id in the sequences location

            search = [
                timed_exam for timed_exam in timed_exams
                if unicode(timed_exam.location) == exam['content_id']
            ]
            if not search:
                # This means it was turned off in Studio, we need to mark
                # the exam as inactive (we don't delete!)
                msg = 'Disabling timed exam {exam_id}'.format(
                    exam_id=exam['id'])
                log.info(msg)
                update_exam(
                    exam_id=exam['id'],
                    is_proctored=False,
                    is_active=False,
                )
Beispiel #5
0
def register_special_exams(course_key):
    """
    This is typically called on a course published signal. The course is examined for sequences
    that are marked as timed exams. Then these are registered with the edx-proctoring
    subsystem. Likewise, if formerly registered exams are unmarked, then those
    registered exams are marked as inactive
    """
    if not settings.FEATURES.get('ENABLE_SPECIAL_EXAMS'):
        # if feature is not enabled then do a quick exit
        return

    course = modulestore().get_course(course_key)
    if course is None:
        raise ItemNotFoundError(u"Course {} does not exist", unicode(course_key))

    if not course.enable_proctored_exams and not course.enable_timed_exams:
        # likewise if course does not have these features turned on
        # then quickly exit
        return

    # get all sequences, since they can be marked as timed/proctored exams
    _timed_exams = modulestore().get_items(
        course_key,
        qualifiers={
            'category': 'sequential',
        },
        settings={
            'is_time_limited': True,
        }
    )

    # filter out any potential dangling sequences
    timed_exams = [
        timed_exam
        for timed_exam in _timed_exams
        if is_item_in_course_tree(timed_exam)
    ]

    # enumerate over list of sequences which are time-limited and
    # add/update any exam entries in edx-proctoring
    for timed_exam in timed_exams:
        msg = (
            u'Found {location} as a timed-exam in course structure. Inspecting...'.format(
                location=unicode(timed_exam.location)
            )
        )
        log.info(msg)

        exam_metadata = {
            'exam_name': timed_exam.display_name,
            'time_limit_mins': timed_exam.default_time_limit_minutes,
            'due_date': timed_exam.due,
            'is_proctored': timed_exam.is_proctored_exam,
            # backends that support onboarding exams will treat onboarding exams as practice
            'is_practice_exam': timed_exam.is_practice_exam or timed_exam.is_onboarding_exam,
            'is_active': True,
            'hide_after_due': timed_exam.hide_after_due,
            'backend': course.proctoring_provider,
        }

        try:
            exam = get_exam_by_content_id(unicode(course_key), unicode(timed_exam.location))
            # update case, make sure everything is synced
            exam_metadata['exam_id'] = exam['id']

            exam_id = update_exam(**exam_metadata)
            msg = u'Updated timed exam {exam_id}'.format(exam_id=exam['id'])
            log.info(msg)

        except ProctoredExamNotFoundException:
            exam_metadata['course_id'] = unicode(course_key)
            exam_metadata['content_id'] = unicode(timed_exam.location)

            exam_id = create_exam(**exam_metadata)
            msg = u'Created new timed exam {exam_id}'.format(exam_id=exam_id)
            log.info(msg)

        exam_review_policy_metadata = {
            'exam_id': exam_id,
            'set_by_user_id': timed_exam.edited_by,
            'review_policy': timed_exam.exam_review_rules,
        }

        # only create/update exam policy for the proctored exams
        if timed_exam.is_proctored_exam and not timed_exam.is_practice_exam and not timed_exam.is_onboarding_exam:
            try:
                update_review_policy(**exam_review_policy_metadata)
            except ProctoredExamReviewPolicyNotFoundException:
                if timed_exam.exam_review_rules:  # won't save an empty rule.
                    create_exam_review_policy(**exam_review_policy_metadata)
                    msg = u'Created new exam review policy with exam_id {exam_id}'.format(exam_id=exam_id)
                    log.info(msg)
        else:
            try:
                # remove any associated review policy
                remove_review_policy(exam_id=exam_id)
            except ProctoredExamReviewPolicyNotFoundException:
                pass

    # then see which exams we have in edx-proctoring that are not in
    # our current list. That means the the user has disabled it
    exams = get_all_exams_for_course(course_key)

    for exam in exams:
        if exam['is_active']:
            # try to look up the content_id in the sequences location

            search = [
                timed_exam for timed_exam in timed_exams if
                unicode(timed_exam.location) == exam['content_id']
            ]
            if not search:
                # This means it was turned off in Studio, we need to mark
                # the exam as inactive (we don't delete!)
                msg = u'Disabling timed exam {exam_id}'.format(exam_id=exam['id'])
                log.info(msg)
                update_exam(
                    exam_id=exam['id'],
                    is_proctored=False,
                    is_active=False,
                )
Beispiel #6
0
                    data=get_exam_by_id(exam_id),
                    status=status.HTTP_200_OK
                )
            except ProctoredExamNotFoundException, ex:
                LOG.exception(ex)
                return Response(
                    status=status.HTTP_400_BAD_REQUEST,
                    data={"detail": "The exam_id does not exist."}
                )
        else:
            if course_id is not None:
                if content_id is not None:
                    # get by course_id & content_id
                    try:
                        return Response(
                            data=get_exam_by_content_id(course_id, content_id),
                            status=status.HTTP_200_OK
                        )
                    except ProctoredExamNotFoundException, ex:
                        LOG.exception(ex)
                        return Response(
                            status=status.HTTP_400_BAD_REQUEST,
                            data={"detail": "The exam with course_id, content_id does not exist."}
                        )
                else:
                    result_set = get_all_exams_for_course(
                        course_id=course_id
                    )
                    return Response(result_set)

Beispiel #7
0
                by course_id, content_id: get_exam_by_content_id()

        """

        if exam_id:
            try:
                return Response(data=get_exam_by_id(exam_id), status=status.HTTP_200_OK)
            except ProctoredExamNotFoundException, ex:
                LOG.exception(ex)
                return Response(status=status.HTTP_400_BAD_REQUEST, data={"detail": "The exam_id does not exist."})
        else:
            if course_id is not None:
                if content_id is not None:
                    # get by course_id & content_id
                    try:
                        return Response(data=get_exam_by_content_id(course_id, content_id), status=status.HTTP_200_OK)
                    except ProctoredExamNotFoundException, ex:
                        LOG.exception(ex)
                        return Response(
                            status=status.HTTP_400_BAD_REQUEST,
                            data={"detail": "The exam with course_id, content_id does not exist."},
                        )
                else:
                    timed_exams_only = not request.user.is_staff
                    result_set = get_all_exams_for_course(
                        course_id=course_id, timed_exams_only=timed_exams_only, active_only=True
                    )
                    return Response(result_set)


class StudentProctoredExamAttempt(AuthenticatedAPIView):
Beispiel #8
0
             data=get_exam_by_id(exam_id),
             status=status.HTTP_200_OK
         )
     except ProctoredExamNotFoundException, ex:
         LOG.exception(ex)
         return Response(
             status=status.HTTP_400_BAD_REQUEST,
             data={"detail": "The exam_id does not exist."}
         )
 else:
     if course_id is not None:
         if content_id is not None:
             # get by course_id & content_id
             try:
                 return Response(
                     data=get_exam_by_content_id(course_id, content_id),
                     status=status.HTTP_200_OK
                 )
             except ProctoredExamNotFoundException, ex:
                 LOG.exception(ex)
                 return Response(
                     status=status.HTTP_400_BAD_REQUEST,
                     data={"detail": "The exam with course_id, content_id does not exist."}
                 )
         else:
             timed_exams_only = not request.user.is_staff
             result_set = get_all_exams_for_course(
                 course_id=course_id,
                 timed_exams_only=timed_exams_only,
                 active_only=True
             )
Beispiel #9
0
def register_special_exams(course_key):
    """
    This is typically called on a course published signal. The course is examined for sequences
    that are marked as timed exams. Then these are registered with the edx-proctoring
    subsystem. Likewise, if formerly registered exams are unmarked, then those
    registered exams are marked as inactive
    """
    if not settings.FEATURES.get('ENABLE_SPECIAL_EXAMS'):
        # if feature is not enabled then do a quick exit
        return

    course = modulestore().get_course(course_key)
    if course is None:
        raise ItemNotFoundError(u"Course {} does not exist",
                                six.text_type(course_key))  # lint-amnesty, pylint: disable=raising-format-tuple

    if not course.enable_proctored_exams and not course.enable_timed_exams:
        # likewise if course does not have these features turned on
        # then quickly exit
        return

    # get all sequences, since they can be marked as timed/proctored exams
    _timed_exams = modulestore().get_items(course_key,
                                           qualifiers={
                                               'category': 'sequential',
                                           },
                                           settings={
                                               'is_time_limited': True,
                                           })

    # filter out any potential dangling sequences
    timed_exams = [
        timed_exam for timed_exam in _timed_exams
        if is_item_in_course_tree(timed_exam)
    ]

    # enumerate over list of sequences which are time-limited and
    # add/update any exam entries in edx-proctoring
    for timed_exam in timed_exams:
        msg = (
            u'Found {location} as a timed-exam in course structure. Inspecting...'
            .format(location=six.text_type(timed_exam.location)))
        log.info(msg)

        exam_metadata = {
            'exam_name': timed_exam.display_name,
            'time_limit_mins': timed_exam.default_time_limit_minutes,
            'due_date': timed_exam.due if not course.self_paced else None,
            'is_proctored': timed_exam.is_proctored_exam,
            # backends that support onboarding exams will treat onboarding exams as practice
            'is_practice_exam': timed_exam.is_practice_exam
            or timed_exam.is_onboarding_exam,
            'is_active': True,
            'hide_after_due': timed_exam.hide_after_due,
            'backend': course.proctoring_provider,
        }

        try:
            exam = get_exam_by_content_id(six.text_type(course_key),
                                          six.text_type(timed_exam.location))
            # update case, make sure everything is synced
            exam_metadata['exam_id'] = exam['id']

            exam_id = update_exam(**exam_metadata)
            msg = u'Updated timed exam {exam_id}'.format(exam_id=exam['id'])
            log.info(msg)

        except ProctoredExamNotFoundException:
            exam_metadata['course_id'] = six.text_type(course_key)
            exam_metadata['content_id'] = six.text_type(timed_exam.location)

            exam_id = create_exam(**exam_metadata)
            msg = u'Created new timed exam {exam_id}'.format(exam_id=exam_id)
            log.info(msg)

        exam_review_policy_metadata = {
            'exam_id': exam_id,
            'set_by_user_id': timed_exam.edited_by,
            'review_policy': timed_exam.exam_review_rules,
        }

        # only create/update exam policy for the proctored exams
        if timed_exam.is_proctored_exam and not timed_exam.is_practice_exam and not timed_exam.is_onboarding_exam:
            try:
                update_review_policy(**exam_review_policy_metadata)
            except ProctoredExamReviewPolicyNotFoundException:
                if timed_exam.exam_review_rules:  # won't save an empty rule.
                    create_exam_review_policy(**exam_review_policy_metadata)
                    msg = u'Created new exam review policy with exam_id {exam_id}'.format(
                        exam_id=exam_id)
                    log.info(msg)
        else:
            try:
                # remove any associated review policy
                remove_review_policy(exam_id=exam_id)
            except ProctoredExamReviewPolicyNotFoundException:
                pass

    # then see which exams we have in edx-proctoring that are not in
    # our current list. That means the the user has disabled it
    exams = get_all_exams_for_course(course_key)

    for exam in exams:
        if exam['is_active']:
            # try to look up the content_id in the sequences location

            search = [
                timed_exam for timed_exam in timed_exams
                if six.text_type(timed_exam.location) == exam['content_id']
            ]
            if not search:
                # This means it was turned off in Studio, we need to mark
                # the exam as inactive (we don't delete!)
                msg = u'Disabling timed exam {exam_id}'.format(
                    exam_id=exam['id'])
                log.info(msg)
                update_exam(
                    exam_id=exam['id'],
                    is_proctored=False,
                    is_active=False,
                )
Beispiel #10
0
def register_special_exams(course_key):
    """
    This is typically called on a course published signal. The course is examined for sequences
    that are marked as timed exams. Then these are registered with the edx-proctoring
    subsystem. Likewise, if formerly registered exams are unmarked, then those
    registered exams are marked as inactive
    """

    if not settings.FEATURES.get("ENABLE_SPECIAL_EXAMS"):
        # if feature is not enabled then do a quick exit
        return

    course = modulestore().get_course(course_key)
    if not course.enable_proctored_exams and not course.enable_timed_exams:
        # likewise if course does not have these features turned on
        # then quickly exit
        return

    # get all sequences, since they can be marked as timed/proctored exams
    _timed_exams = modulestore().get_items(
        course_key, qualifiers={"category": "sequential"}, settings={"is_time_limited": True}
    )

    # filter out any potential dangling sequences
    timed_exams = [timed_exam for timed_exam in _timed_exams if is_item_in_course_tree(timed_exam)]

    # enumerate over list of sequences which are time-limited and
    # add/update any exam entries in edx-proctoring
    for timed_exam in timed_exams:
        msg = "Found {location} as a timed-exam in course structure. Inspecting...".format(
            location=unicode(timed_exam.location)
        )
        log.info(msg)

        try:
            exam = get_exam_by_content_id(unicode(course_key), unicode(timed_exam.location))
            # update case, make sure everything is synced
            update_exam(
                exam_id=exam["id"],
                exam_name=timed_exam.display_name,
                time_limit_mins=timed_exam.default_time_limit_minutes,
                due_date=timed_exam.due,
                is_proctored=timed_exam.is_proctored_exam,
                is_practice_exam=timed_exam.is_practice_exam,
                is_active=True,
            )
            msg = "Updated timed exam {exam_id}".format(exam_id=exam["id"])
            log.info(msg)
        except ProctoredExamNotFoundException:
            exam_id = create_exam(
                course_id=unicode(course_key),
                content_id=unicode(timed_exam.location),
                exam_name=timed_exam.display_name,
                time_limit_mins=timed_exam.default_time_limit_minutes,
                due_date=timed_exam.due,
                is_proctored=timed_exam.is_proctored_exam,
                is_practice_exam=timed_exam.is_practice_exam,
                is_active=True,
            )
            msg = "Created new timed exam {exam_id}".format(exam_id=exam_id)
            log.info(msg)

    # then see which exams we have in edx-proctoring that are not in
    # our current list. That means the the user has disabled it
    exams = get_all_exams_for_course(course_key)

    for exam in exams:
        if exam["is_active"]:
            # try to look up the content_id in the sequences location

            search = [timed_exam for timed_exam in timed_exams if unicode(timed_exam.location) == exam["content_id"]]
            if not search:
                # This means it was turned off in Studio, we need to mark
                # the exam as inactive (we don't delete!)
                msg = "Disabling timed exam {exam_id}".format(exam_id=exam["id"])
                log.info(msg)
                update_exam(exam_id=exam["id"], is_proctored=False, is_active=False)