Esempio n. 1
0
    def post(self, request, *args, **kwargs):

        # Use form to parse and validate the request.
        form = SubmissionCreateAndReviewForm(
            request.POST,
            exercise=self.exercise,
            students_choices=self.instance.get_student_profiles())
        if not form.is_valid():
            messages.error(
                request,
                _("Invalid POST data:\n{error}").format(
                    error="\n".join(extract_form_errors(form))))
            return self.redirect(self.exercise.get_submission_list_url())

        sub = Submission.objects.create(exercise=self.exercise)
        sub.submitters.set(form.cleaned_students)
        sub.feedback = form.cleaned_data.get("feedback")
        sub.set_points(form.cleaned_data.get("points"),
                       self.exercise.max_points,
                       no_penalties=True)
        sub.submission_time = form.cleaned_data.get("submission_time")
        sub.grader = self.profile
        sub.grading_time = timezone.now()
        sub.set_ready()
        sub.save()

        messages.success(request, _("New submission stored."))
        return self.redirect(sub.get_absolute_url())
Esempio n. 2
0
def create_submissions(instance, admin_profile, json_text):
    """
    Batch creates submissions and feedback from formatted JSON.
    """
    try:
        submissions_json = json.loads(json_text)
    except Exception as e:
        return [_("Failed to parse the JSON: {}").format(str(e))]
    if not "objects" in submissions_json:
        return [_('Missing JSON field: objects')]

    errors = []
    validated_forms = []
    count = 0
    for submission_json in submissions_json["objects"]:
        count += 1
        if not "exercise_id" in submission_json:
            errors.append(
                _('Missing field "exercise_id" in object {count:d}.')\
                    .format(count=count))
            continue

        exercise = BaseExercise.objects.filter(
            id=submission_json["exercise_id"],
            course_module__course_instance=instance).first()
        if not exercise:
            errors.append(
                _('Unknown exercise_id {id:d} in object {count:d}.')\
                    .format(id=submission_json["exercise_id"], count=count))
            continue

        # Use form to parse and validate object data.
        form = BatchSubmissionCreateAndReviewForm(submission_json,
                                                  exercise=exercise)
        if form.is_valid():
            validated_forms.append(form)
        else:
            errors.append(
                _('Invalid fields in object {count:d}: {error}')\
                    .format(count=count,
                        error="\n".join(extract_form_errors(form))))

    if not errors:
        for form in validated_forms:
            sub = Submission.objects.create(exercise=form.exercise)
            sub.submitters = form.cleaned_data.get("students") \
                or (form.cleaned_data.get("students_by_student_id")
                    or form.cleaned_data.get("students_by_email"))
            sub.feedback = form.cleaned_data.get("feedback")
            sub.set_points(form.cleaned_data.get("points"),
                           sub.exercise.max_points,
                           no_penalties=True)
            sub.submission_time = form.cleaned_data.get("submission_time")
            sub.grading_time = timezone.now()
            sub.grader = form.cleaned_data.get("grader") or admin_profile
            sub.set_ready()
            sub.save()

    return errors
Esempio n. 3
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)]}
Esempio n. 4
0
def create_submissions(instance, admin_profile, json_text):
    """
    Batch creates submissions and feedback from formatted JSON.
    """
    try:
        submissions_json = json.loads(json_text)
    except Exception as e:
        return [_("Failed to parse the JSON: {}").format(str(e))]
    if not "objects" in submissions_json:
        return [_('Missing JSON field: objects')]

    errors = []
    validated_forms = []
    count = 0
    for submission_json in submissions_json["objects"]:
        count += 1
        if not "exercise_id" in submission_json:
            errors.append(
                _('Missing field "exercise_id" in object {count:d}.')\
                    .format(count=count))
            continue

        exercise = BaseExercise.objects.filter(
            id=submission_json["exercise_id"],
            course_module__course_instance=instance).first()
        if not exercise:
            errors.append(
                _('Unknown exercise_id {id:d} in object {count:d}.')\
                    .format(id=submission_json["exercise_id"], count=count))
            continue

        # Use form to parse and validate object data.
        form = BatchSubmissionCreateAndReviewForm(submission_json,
            exercise=exercise)
        if form.is_valid():
            validated_forms.append(form)
        else:
            errors.append(
                _('Invalid fields in object {count:d}: {error}')\
                    .format(count=count,
                        error="\n".join(extract_form_errors(form))))

    if not errors:
        for form in validated_forms:
            sub = Submission.objects.create(exercise=form.exercise)
            sub.submitters = form.cleaned_data.get("students") \
                or (form.cleaned_data.get("students_by_student_id")
                    or form.cleaned_data.get("students_by_email"))
            sub.feedback = form.cleaned_data.get("feedback")
            sub.set_points(form.cleaned_data.get("points"),
                sub.exercise.max_points, no_penalties=True)
            sub.submission_time = form.cleaned_data.get("submission_time")
            sub.grading_time = timezone.now()
            sub.grader = form.cleaned_data.get("grader") or admin_profile
            sub.set_ready()
            sub.save()

    return errors
Esempio n. 5
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)]}
Esempio n. 6
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)]
        }
Esempio n. 7
0
def create_submissions(instance, admin_profile, json_text):
    """
    Batch creates submissions and feedback from formatted JSON.
    """
    try:
        submissions_json = json.loads(json_text)
    except Exception as e:
        return [
            _("Parsing the submission JSON raised an error '{error!s}'.").
            format(error=e)
        ]

    if isinstance(submissions_json, dict):
        if not "objects" in submissions_json:
            return [_('Missing JSON field: objects.')]
        submissions_json = submissions_json["objects"]
    if not isinstance(submissions_json, list):
        return [_("Invalid JSON. Expected list or list in objects field")]

    errors = []
    validated_forms = []
    count = 0
    for submission_json in submissions_json:
        count += 1
        if not "exercise_id" in submission_json:
            errors.append(
                _('Missing field "exercise_id" in object {count:d}.').format(
                    count=count))
            continue

        exercise = BaseExercise.objects.filter(
            id=submission_json["exercise_id"],
            course_module__course_instance=instance).first()
        if not exercise:
            errors.append(
                _('Unknown exercise_id {id:d} in object {count:d}.').format(
                    id=submission_json["exercise_id"], count=count))
            continue

        # Use form to parse and validate object data.
        form = BatchSubmissionCreateAndReviewForm(submission_json,
                                                  exercise=exercise)
        if form.is_valid():
            validated_forms.append(form)
        else:
            errors.append(
                _("Object number {ordinal:d} has invalid fields:\n {errors}").
                format(ordinal=count,
                       errors='\n '.join(extract_form_errors(form))))

    if not errors:
        for form in validated_forms:
            sub = Submission.objects.create(exercise=form.exercise)
            sub.submitters = form.cleaned_students
            sub.feedback = form.cleaned_data.get("feedback")
            sub.set_points(form.cleaned_data.get("points"),
                           sub.exercise.max_points,
                           no_penalties=True)
            sub.submission_time = form.cleaned_data.get("submission_time")
            sub.grading_time = timezone.now()
            sub.grader = form.cleaned_data.get("grader") or admin_profile
            sub.set_ready()
            sub.save()

    return errors
Esempio n. 8
0
def create_submissions(instance, admin_profile, json_text):
    """
    Batch creates submissions and feedback from formatted JSON.
    """
    try:
        submissions_json = json.loads(json_text)
    except Exception as e:
        return [format_lazy(
            _('EXCEPTION_PARSING_SUBMISSION_JSON -- {error!s}'),
            error=e,
        )]

    if isinstance(submissions_json, dict):
        if not "objects" in submissions_json:
            return [_('JSON_FIELD_MISSING_OBJECTS')]
        submissions_json = submissions_json["objects"]
    if not isinstance(submissions_json, list):
        return [_('JSON_INVALID_EXPECTED_LIST')]

    errors = []
    validated_forms = []
    count = 0
    for submission_json in submissions_json:
        count += 1
        if not "exercise_id" in submission_json:
            errors.append(
                format_lazy(
                    _('JSON_ERROR_MISSING_FIELD_EXERCISE_ID -- {count:d}'),
                    count=count,
                )
            )
            continue

        exercise = BaseExercise.objects.filter(
            id=submission_json["exercise_id"],
            course_module__course_instance=instance).first()
        if not exercise:
            errors.append(
                format_lazy(
                    _('JSON_ERROR_UNKNOWN_EXERCISE_ID -- {id:d}, {count:d}'),
                    id=submission_json["exercise_id"],
                    count=count,
                )
            )
            continue

        # Use form to parse and validate object data.
        form = BatchSubmissionCreateAndReviewForm(submission_json,
            exercise=exercise)
        if form.is_valid():
            validated_forms.append(form)
        else:
            errors.append(
                format_lazy(
                    _('JSON_ERROR_OBJECT_INVALID_FIELDS -- {ordinal:d}, {errors}'),
                    ordinal=count,
                    errors='\n '.join(extract_form_errors(form))
                )
            )

    if not errors:
        for form in validated_forms:
            sub = Submission.objects.create(exercise=form.exercise)
            sub.submitters.set(form.cleaned_students)
            sub.feedback = form.cleaned_data.get("feedback")
            sub.set_points(form.cleaned_data.get("points"),
                sub.exercise.max_points, no_penalties=True)
            sub.submission_time = form.cleaned_data.get("submission_time")
            sub.grading_time = timezone.now()
            sub.grader = form.cleaned_data.get("grader") or admin_profile
            sub.set_ready()
            sub.save()

    return errors
Esempio n. 9
0
    def post(self, request, *args, **kwargs):
        self.handle()
        self.error = False
        try:
            submissions_json = json.loads(
                request.POST.get("submissions_json", "{}"))
        except Exception as e:
            logger.exception(
                "Failed to parse submission batch JSON from user: %s",
                request.user.username)
            self.set_error(
                _("Failed to parse the JSON: {error}"),
                error=str(e))
        if not self.error and not "objects" in submissions_json:
            self.set_error(_('Missing JSON field: objects'))

        validated_forms = []
        if not self.error:
            count = 0
            for submission_json in submissions_json["objects"]:
                count += 1
                if not "exercise_id" in submission_json:
                    self.set_error(
                        _('Missing field "exercise_id" in object {count:d}.'),
                        count=count)
                    continue

                exercise = BaseExercise.objects.filter(
                    id=submission_json["exercise_id"],
                    course_module__course_instance=self.instance).first()
                if not exercise:
                    self.set_error(
                        _('Unknown exercise_id {id} in object {count:d}.'),
                        count=count,
                        id=submission_json["exercise_id"])
                    continue

                # Use form to parse and validate object data.
                form = BatchSubmissionCreateAndReviewForm(submission_json,
                    exercise=exercise)
                if form.is_valid():
                    validated_forms.append(form)
                else:
                    self.set_error(
                        _('Invalid fields in object {count:d}: {error}'),
                        count=count,
                        error="\n".join(extract_form_errors(form)))

        if not self.error:
            for form in validated_forms:
                sub = Submission.objects.create(exercise=form.exercise)
                sub.submitters = form.cleaned_data.get("students") \
                    or form.cleaned_data.get("students_by_student_id")
                sub.feedback = form.cleaned_data.get("feedback")
                sub.set_points(form.cleaned_data.get("points"),
                    sub.exercise.max_points, no_penalties=True)
                sub.submission_time = form.cleaned_data.get("submission_time")
                sub.grading_time = timezone.now()
                sub.grader = form.cleaned_data.get("grader") or self.profile
                sub.set_ready()
                sub.save()
            messages.success(request, _("New submissions stored."))

        return self.response()
Esempio n. 10
0
def create_submissions(instance, admin_profile, json_text):
    """
    Batch creates submissions and feedback from formatted JSON.
    """
    try:
        submissions_json = json.loads(json_text)
    except Exception as e:
        return [_("Parsing the submission JSON raised an error '{error!s}'.")
                    .format(error=e)]

    if isinstance(submissions_json, dict):
        if not "objects" in submissions_json:
            return [_('Missing JSON field: objects.')]
        submissions_json = submissions_json["objects"]
    if not isinstance(submissions_json, list):
        return [_("Invalid JSON. Expected list or list in objects field")]

    errors = []
    validated_forms = []
    count = 0
    for submission_json in submissions_json:
        count += 1
        if not "exercise_id" in submission_json:
            errors.append(
                _('Missing field "exercise_id" in object {count:d}.')
                    .format(count=count))
            continue

        exercise = BaseExercise.objects.filter(
            id=submission_json["exercise_id"],
            course_module__course_instance=instance).first()
        if not exercise:
            errors.append(
                _('Unknown exercise_id {id:d} in object {count:d}.')
                    .format(id=submission_json["exercise_id"],
                            count=count))
            continue

        # Use form to parse and validate object data.
        form = BatchSubmissionCreateAndReviewForm(submission_json,
            exercise=exercise)
        if form.is_valid():
            validated_forms.append(form)
        else:
            errors.append(
                _("Object number {ordinal:d} has invalid fields:\n {errors}")
                    .format(ordinal=count,
                            errors='\n '.join(extract_form_errors(form))))

    if not errors:
        for form in validated_forms:
            sub = Submission.objects.create(exercise=form.exercise)
            sub.submitters = form.cleaned_students
            sub.feedback = form.cleaned_data.get("feedback")
            sub.set_points(form.cleaned_data.get("points"),
                sub.exercise.max_points, no_penalties=True)
            sub.submission_time = form.cleaned_data.get("submission_time")
            sub.grading_time = timezone.now()
            sub.grader = form.cleaned_data.get("grader") or admin_profile
            sub.set_ready()
            sub.save()

    return errors