Пример #1
0
def _post_async_submission(request, exercise, submission, errors=None):
    """
    Creates or grades a submission.

    Required parameters in the request are points, max_points and feedback. If
    errors occur or submissions are no longer accepted, a dictionary with
    "success" is False and "errors" list will be returned.
    """
    if not errors:
        errors = []

    # The feedback field may contain null characters, which would invalidate
    # the form before its clean method is executed. So replace them beforehand.
    post_data = request.POST.copy()
    feedback = post_data.get('feedback')
    if feedback:
        post_data['feedback'] = feedback.replace('\x00', '\\x00')

    # Use form to parse and validate the request.
    form = SubmissionCallbackForm(post_data)
    errors.extend(extract_form_errors(form))
    if not form.is_valid():
        submission.feedback = _(
            "ERROR_ALERT_EXERCISE_ASSESSMENT_SERVICE_MALFUNCTIONING")
        submission.set_error()
        submission.save()
        if exercise.course_instance.visible_to_students:
            msg = "Exercise service returned with invalid grade request: {}"\
                .format("\n".join(errors))
            logger.error(msg, extra={"request": request})
            email_course_error(request, exercise, msg, False)
        return {"success": False, "errors": errors}

    # Grade the submission.
    try:
        submission.set_points(form.cleaned_data["points"],
                              form.cleaned_data["max_points"])
        submission.feedback = form.cleaned_data["feedback"]
        submission.grading_data = post_data

        if form.cleaned_data["error"]:
            submission.set_error()
        else:
            submission.set_ready()
        submission.save()

        if form.cleaned_data["notify"]:
            Notification.send(None, submission)
        else:
            Notification.remove(submission)

        return {"success": True, "errors": []}

    # Produce error if something goes wrong during saving the points.
    except Exception as e:
        logger.exception("Unexpected error while saving grade"
                         " for {} and submission id {:d}".format(
                             str(exercise), submission.id))
        return {"success": False, "errors": [repr(e)]}
Пример #2
0
def _post_async_submission(request, exercise, submission, errors=None):
    """
    Creates or grades a submission.

    Required parameters in the request are points, max_points and feedback. If
    errors occur or submissions are no longer accepted, a dictionary with
    "success" is False and "errors" list will be returned.
    """
    if not errors:
        errors = []

    # Use form to parse and validate the request.
    form = SubmissionCallbackForm(request.POST)
    errors.extend(extract_form_errors(form))
    if not form.is_valid():
        submission.feedback = _(
            "<div class=\"alert alert-error\">\n"
            "<p>The exercise assessment service is malfunctioning. "
            "Staff has been notified.</p>\n"
            "<p>This submission is now marked as erroneous.</p>\n"
            "</div>")
        submission.set_error()
        submission.save()
        if exercise.course_instance.visible_to_students:
            msg = "Exercise service returned with invalid grade request: {}"\
                .format("\n".join(errors))
            logger.error(msg, extra={"request": request})
            email_course_error(request, exercise, msg, False)
        return {"success": False, "errors": errors}

    # Grade the submission.
    try:
        submission.set_points(form.cleaned_data["points"],
                              form.cleaned_data["max_points"])
        submission.feedback = form.cleaned_data["feedback"]
        submission.grading_data = request.POST

        if form.cleaned_data["error"]:
            submission.set_error()
        else:
            submission.set_ready()
        submission.save()

        if form.cleaned_data["notify"]:
            Notification.send(None, submission)
        else:
            Notification.remove(submission)

        return {"success": True, "errors": []}

    # Produce error if something goes wrong during saving the points.
    except Exception as e:
        logger.exception("Unexpected error while saving grade"
                         " for {} and submission id {:d}".format(
                             str(exercise), submission.id))
        return {"success": False, "errors": [repr(e)]}
Пример #3
0
def _post_async_submission(request, exercise, submission, students, errors):
    """
    Creates or grades a submission.

    Required parameters in the request are points, max_points and feedback. If
    errors occur or submissions are no longer accepted, a dictionary with
    "success" is False and "errors" list will be returned.
    """

    # Use form to parse and validate the request.
    form = SubmissionCallbackForm(request.POST)
    errors.extend(extract_form_errors(form))
    if not form.is_valid():
        submission.feedback = _(
            "<div class=\"alert alert-error\">\n"
            "<p>The exercise assessment service is malfunctioning. "
            "Staff has been notified.</p>\n"
            "<p>This submission is now marked as erroneous.</p>\n"
            "</div>")
        submission.set_error()
        submission.save()
        if exercise.course_instance.visible_to_students:
            msg = "Exercise service returned with invalid grade request: {}"\
                .format("\n".join(errors))
            logger.error(msg, extra={"request": request})
            email_course_error(request, exercise, msg, False)
        return {
            "success": False,
            "errors": errors
        }

    # Grade the submission.
    try:
        submission.set_points(form.cleaned_data["points"],
                              form.cleaned_data["max_points"])
        submission.feedback = form.cleaned_data["feedback"]
        submission.grading_data = request.POST

        if form.cleaned_data["error"]:
            submission.set_error()
        else:
            submission.set_ready()
        submission.save()
        return {
            "success": True,
            "errors": []
        }

    # Produce error if something goes wrong during saving the points.
    except Exception as e:
        logger.exception("Unexpected error while saving grade"
            " for {} and submission id {:d}".format(str(exercise), submission.id));
        return {
            "success": False,
            "errors": [repr(e)]
        }
Пример #4
0
def load_exercise_page(request, url, exercise):
    """
    Loads the exercise page from the remote URL.

    """
    page = ExercisePage(exercise)
    try:
        parse_page_content(page, RemotePage(url), exercise)
    except RemotePageException:
        messages.error(request,
            _("Connecting to the exercise service failed!"))
        if exercise.id and exercise.course_instance.visible_to_students:
            msg = "Failed to request {}".format(url)
            logger.exception(msg)
            email_course_error(request, exercise, msg)
    return page
Пример #5
0
def load_exercise_page(request, url, last_modified, exercise):
    """
    Loads the exercise page from the remote URL.

    """
    page = ExercisePage(exercise)
    try:
        parse_page_content(page, RemotePage(url, stamp=last_modified),
                           exercise)
    except RemotePageException:
        messages.error(request,
                       _("Connecting to the exercise service failed!"))
        if exercise.id:
            instance = exercise.course_instance
            msg = "Failed to request {}".format(url)
            if instance.visible_to_students and not instance.is_past():
                logger.exception(msg)
                email_course_error(request, exercise, msg)
            else:
                logger.warning(msg)
    return page
Пример #6
0
def load_exercise_page(request, url, last_modified, exercise):
    """
    Loads the exercise page from the remote URL.

    """
    page = ExercisePage(exercise)
    try:
        parse_page_content(
            page,
            RemotePage(url,
                       instance_id=exercise.course_instance.id,
                       stamp=last_modified), exercise)
    except RemotePageException:
        messages.error(request, _('EXERCISE_SERVICE_ERROR_CONNECTION_FAILED'))
        if exercise.id:
            instance = exercise.course_instance
            msg = "Failed to request {}".format(url)
            if instance.visible_to_students and not instance.is_past():
                logger.exception(msg)
                email_course_error(request, exercise, msg)
            else:
                logger.warning(msg)
    return page
Пример #7
0
def load_exercise_page(request, url, last_modified, exercise):
    """
    Loads the exercise page from the remote URL.

    """
    page = ExercisePage(exercise)
    try:
        parse_page_content(
            page,
            RemotePage(url, stamp=last_modified),
            exercise
        )
    except RemotePageException:
        messages.error(request,
            _("Connecting to the exercise service failed!"))
        if exercise.id:
            instance = exercise.course_instance
            msg = "Failed to request {}".format(url)
            if instance.visible_to_students and not instance.is_past():
                logger.exception(msg)
                email_course_error(request, exercise, msg)
            else:
                logger.warning(msg)
    return page
Пример #8
0
def load_feedback_page(request, url, exercise, submission, no_penalties=False):
    """
    Loads the feedback or accept page from the remote URL.
    """
    page = ExercisePage(exercise)
    try:
        data, files = submission.get_post_parameters(request, url)
        remote_page = RemotePage(url,
                                 post=True,
                                 data=data,
                                 files=files,
                                 instance_id=exercise.course_instance.id)
        submission.clean_post_parameters()
        parse_page_content(page, remote_page, exercise)
    except RemotePageException:
        page.errors.append(_('ASSESSMENT_SERVICE_ERROR_CONNECTION_FAILED'))
        if exercise.course_instance.visible_to_students:
            msg = "Failed to request {}".format(url)
            logger.exception(msg)
            email_course_error(request, exercise, msg)

    if page.is_loaded:
        submission.feedback = page.clean_content
        if page.is_accepted:
            submission.set_waiting()
            if page.is_graded:
                if page.is_sane():
                    submission.set_points(page.points, page.max_points,
                                          no_penalties)
                    submission.set_ready()
                    # Hide unnecessary system wide messages when grader works as expected.
                    # msg = _("The exercise was submitted and graded "
                    #     "successfully. Points: {points:d}/{max:d}").format(
                    #     points=submission.grade,
                    #     max=exercise.max_points
                    # )
                    # if submission.grade < exercise.max_points:
                    #     messages.info(request, msg)
                    # else:
                    #     messages.success(request, msg)
                else:
                    submission.set_error()
                    page.errors.append(
                        format_lazy(_(
                            'ASSESSMENT_SERVICE_ERROR_RESPONDED_INVALID_POINTS -- {points:d}, {max:d}, {exercise_max:d}'
                        ),
                                    points=page.points,
                                    max=page.max_points,
                                    exercise_max=exercise.max_points))
                    if exercise.course_instance.visible_to_students:
                        msg = "Graded with invalid points {:d}/{:d}"\
                            " (exercise max {:d}): {}".format(
                                page.points, page.max_points,
                                exercise.max_points, exercise.service_url)
                        logger.error(msg, extra={"request": request})
                        email_course_error(request, exercise, msg)
            else:
                pass
                # Hide unnecessary system wide messages when grader works as expected.
                # messages.success(request,
                #     _("The exercise was submitted successfully "
                #       "and is now waiting to be graded.")
                # )
        elif page.is_rejected:
            submission.set_rejected()
        else:
            submission.set_error()
            logger.info("No accept or points received: %s",
                        exercise.service_url)
            page.errors.append(_('ASSESSMENT_SERVICE_ERROR_RESPONDED_ERROR'))
        submission.save()

    return page
Пример #9
0
def load_feedback_page(request, url, exercise, submission, no_penalties=False):
    """
    Loads the feedback or accept page from the remote URL.

    """
    page = ExercisePage(exercise)
    try:
        data, files = submission.get_post_parameters(request, url)
        remote_page = RemotePage(url, post=True, data=data, files=files)
        submission.clean_post_parameters()
        parse_page_content(page, remote_page, exercise)
    except RemotePageException:
        messages.error(request,
            _("Connecting to the assessment service failed!"))
        if exercise.course_instance.visible_to_students:
            msg = "Failed to request {}".format(url)
            logger.exception(msg)
            email_course_error(request, exercise, msg)

    if page.is_loaded:
        submission.feedback = page.content
        if page.is_accepted:
            submission.set_waiting()
            if page.is_graded:
                if page.is_sane():
                    submission.set_points(
                        page.points, page.max_points, no_penalties)
                    submission.set_ready()
                    msg = _("The exercise was submitted and graded "
                        "successfully. Points: {points:d}/{max:d}").format(
                        points=submission.grade,
                        max=exercise.max_points
                    )
                    if submission.grade < exercise.max_points:
                        messages.info(request, msg)
                    else:
                        messages.success(request, msg)
                else:
                    submission.set_error()
                    messages.error(request,
                        _("Assessment service responded with invalid points. "
                          "Points: {points:d}/{max:d} "
                          "(exercise max {exercise_max:d})").format(
                            points=page.points,
                            max=page.max_points,
                            exercise_max=exercise.max_points
                        )
                    )
                    if exercise.course_instance.visible_to_students:
                        msg = "Graded with invalid points {:d}/{:d}"\
                            " (exercise max {:d}): {}".format(
                                page.points, page.max_points,
                                exercise.max_points, exercise.service_url)
                        logger.error(msg, extra={"request": request})
                        email_course_error(request, exercise, msg)
            else:
                messages.success(request,
                    _("The exercise was submitted successfully "
                      "and is now waiting to be graded.")
                )
        else:
            submission.set_error()
            logger.info("No accept or points received: %s",
                exercise.service_url)
            messages.error(request,
                _("Assessment service responded with error."))
        submission.save()

    return page