예제 #1
0
def createForm(request, course, exercise, post_url):
    '''
    Creates form by configuration and grades answers.
    '''
    if "max_points" not in exercise:
        raise ConfigError("Missing required \"max_points\" in exercise configuration")
    try:
        acceptNonce(request)
    except PermissionDenied:
        return render_template(request, course, exercise, post_url,
            'access/exercise_frame.html', { "error":True, "nonce_used":True })

    form = GradedForm(request.POST or None, exercise=exercise)
    result = { "form": form }

    # Grade valid form posts.
    if form.is_valid():
        (points, error_groups, error_fields) = form.grade()
        points = pointsInRange(points, exercise["max_points"])

        # If points are not granted by form fields.
        if points == 0 and not error_fields:
            points = exercise["max_points"]

        result = { "form": form, "accepted": True, "points": points,
            "error_groups": error_groups, "error_fields": error_fields }

    return render_configured_template(request, course, exercise, post_url,
        'access/create_form_default.html', result)
예제 #2
0
def acceptGeneralForm(request, course, exercise, post_url):
    '''
    Presents a template and accepts form containing any input types 
    (text, file, etc) for grading queue.
    '''
    if not_modified_since(request, exercise):
        return not_modified_response(request, exercise)

    fields = copy.deepcopy(exercise.get("fields", []))
    result = None
    miss = False
    
    if request.method == "POST":
        # Parse submitted values.
        for entry in fields:        
            entry["value"] = request.POST.get(entry["name"], "").strip()
            if "required" in entry and entry["required"] and not entry["value"]:
                entry["missing"] = True
                miss = True
        
        files_submitted = [] 
        if "files" in exercise:
            # Confirm that all required files were submitted.
            #files_submitted = [] # exercise["files"] entries for the files that were really submitted
            for entry in exercise["files"]:
                # by default, all fields are required
                required = ("required" not in entry or entry["required"])
                if entry["field"] not in request.FILES:
                    if required:
                        result = { "rejected": True, "missing_files": True }
                        break
                else:
                    files_submitted.append(entry)
                   
        if miss:
            result = { "fields": fields, "rejected": True }
        elif result is None:
            # Store submitted values.
            sdir = create_submission_dir(course, exercise)
            for entry in fields:
                write_submission_file(sdir, entry["name"], entry["value"])
                               
            if "files" in exercise:
                if "required_number_of_files" in exercise and \
                        exercise["required_number_of_files"] > len(files_submitted):
                    result = { "rejected": True, "missing_files": True }
                else:
                    # Store submitted files.
                    for entry in files_submitted:
                        save_submitted_file(sdir, entry["name"], request.FILES[entry["field"]])             
            return _acceptSubmission(request, course, exercise, post_url, sdir)
    
    return cache_headers(
        render_configured_template(
            request, course, exercise, post_url,
            "access/accept_general_default.html", result
        ),
        request,
        exercise
    )    
예제 #3
0
def acceptGitUser(request, course, exercise, post_url):
    '''
    Presents a template and expects a user id to create Git URL for grading.
    '''
    auth_secret = "*AYVhD'b5,hKzf/6"

    _requireActions(exercise)
    if not "git_address" in exercise:
        raise  ConfigError("Missing \"git_address\" in exercise configuration.")

    user = detect_user(request)
    if request.method == "POST":
        if user is None and "user" in request.POST and "hash" in request.POST:
            user = request.POST["user"]
            if make_hash(auth_secret, user) != request.POST["hash"]:
                raise PermissionDenied()
        source = exercise["git_address"].replace("$USER", user)
        sdir = create_submission_dir(course, exercise)
        write_submission_file(sdir, "gitsource", source)
        return _acceptSubmission(request, course, exercise, post_url, sdir)

    return render_configured_template(request, course, exercise, post_url,
        "access/accept_git_user.html", {
            "user": user,
            "hash": make_hash(auth_secret, user)
        })
예제 #4
0
def acceptPost(request, course, exercise, post_url):
    '''
    Presents a template and accepts post value for grading queue.
    '''
    _requireActions(exercise)
    if not_modified_since(request, exercise):
        return not_modified_response(request, exercise)

    fields = copy.deepcopy(exercise.get("fields", []))
    if request.method == "POST":

        # Parse submitted values.
        miss = False
        for entry in fields:
            entry["value"] = request.POST.get(entry["name"], "").strip()
            if "required" in entry and entry["required"] and not entry["value"]:
                entry["missing"] = True
                miss = True
        if miss:
            result = {"fields": fields, "rejected": True}
        else:

            # Store submitted values.
            sdir = create_submission_dir(course, exercise)
            for entry in fields:
                write_submission_file(sdir, entry["name"], entry["value"])
            return _acceptSubmission(request, course, exercise, post_url, sdir)
    else:
        result = {"fields": fields}

    return cache_headers(
        render_configured_template(request, course, exercise, post_url,
                                   'access/accept_post_default.html', result),
        request, exercise)
예제 #5
0
def acceptGitUser(request, course, exercise, post_url):
    '''
    Presents a template and expects a user id to create Git URL for grading.
    '''
    auth_secret = "*AYVhD'b5,hKzf/6"

    _requireActions(exercise)
    if not "git_address" in exercise:
        raise ConfigError("Missing \"git_address\" in exercise configuration.")

    user = get_uid(request)
    if request.method == "POST":
        if "user" in request.POST and "hash" in request.POST:
            user = request.POST["user"]
            if make_hash(auth_secret, user) != request.POST["hash"]:
                raise PermissionDenied()
        source = exercise["git_address"].replace("$USER", user)
        sdir = create_submission_dir(course, exercise)
        write_submission_file(sdir, "gitsource", source)
        return _acceptSubmission(request, course, exercise, post_url, sdir)

    return render_configured_template(request, course, exercise, post_url,
                                      "access/accept_git_user.html", {
                                          "user": user,
                                          "hash": make_hash(auth_secret, user)
                                      })
예제 #6
0
def md5Authentication(request, course, exercise, post_url):
    '''
    Creates an md5 hash for user authentication.
    '''
    user = get_uid(request)
    key = make_hash(exercise["auth_secret"], user)
    return render_configured_template(request, course, exercise, post_url,
        None, { "user": user, "hash": key })
예제 #7
0
def md5Authentication(request, course, exercise, post_url):
    '''
    Creates an md5 hash for user authentication.
    '''
    user = detect_user(request)
    key = make_hash(exercise["auth_secret"], user)
    return render_configured_template(request, course, exercise, post_url,
        None, { "user": user, "hash": key })
예제 #8
0
def acceptAttachedExercise(request, course, exercise, post_url):
    '''
    Accepts attached exercise rules and user files for queue.
    '''
    _requireActions(exercise)
    if not_modified_since(request, exercise):
        return not_modified_response(request, exercise)

    result = None

    # Receive post.
    if request.method == "POST":

        # Search for file contents.
        if "file[]" in request.FILES:
            file_list = request.FILES.getlist("file[]")
        else:
            file_list = []
            i = 0
            while "content_%d" % (i) in request.FILES:
                file_list.append(request.FILES["content_%d" % (i)])
                i += 1

        # Store submitted files.
        if not file_list:
            result = {"rejected": True, "missing_files": True}
        else:
            sdir = create_submission_dir(course, exercise)
            i = 0
            for content in file_list:
                if i > 0:
                    key = "file_%d" % (i)
                    if not key in request.POST or not request.POST[key]:
                        result = {"error": True, "missing_file_name": True}
                        clean_submission_dir(sdir)
                        break
                    save_submitted_file(sdir, request.POST[key], content)
                else:
                    save_submitted_file(sdir, "exercise_attachment", content)
                i += 1
            if result is None:
                return _acceptSubmission(request, course, exercise, post_url,
                                         sdir)

    # Add the attachment as a hint to the default view form.
    if result is None:
        import copy
        exercise = copy.deepcopy(exercise)
        exercise["files"] = [{
            "field": "content_0",
            "name": "exercise_attachment"
        }]

    return cache_headers(
        render_configured_template(request, course, exercise, post_url,
                                   "access/accept_files_default.html", result),
        request, exercise)
예제 #9
0
def noGrading(request, course, exercise, post_url):
    '''
    Presents a template and does no grading.
    '''
    if not_modified_since(request, exercise):
        return not_modified_response(request, exercise)
    return cache_headers(
        render_configured_template(request, course, exercise, post_url, None,
                                   None), request, exercise)
예제 #10
0
def acceptAttachedExercise(request, course, exercise, post_url):
    '''
    Accepts attached exercise rules and user files for queue.
    '''
    _requireActions(exercise)
    if not_modified_since(request, exercise):
        return not_modified_response(request, exercise)

    result = None

    # Receive post.
    if request.method == "POST":

        # Search for file contents.
        if "file[]" in request.FILES:
            file_list = request.FILES.getlist("file[]")
        else:
            file_list = []
            i = 0
            while "content_%d" % (i) in request.FILES:
                file_list.append(request.FILES["content_%d" % (i)])
                i += 1

        # Store submitted files.
        if not file_list:
            result = { "error":True, "missing_files":True }
        else:
            sdir = create_submission_dir(course, exercise)
            i = 0
            for content in file_list:
                if i > 0:
                    key = "file_%d" % (i)
                    if not key in request.POST or not request.POST[key]:
                        result = { "error": True, "missing_file_name": True }
                        clean_submission_dir(sdir)
                        break
                    save_submitted_file(sdir, request.POST[key], content)
                else:
                    save_submitted_file(sdir, "exercise_attachment", content)
                i += 1
            if result is None:
                return _acceptSubmission(request, course, exercise, post_url, sdir)

    # Add the attachment as a hint to the default view form.
    if result is None:
        import copy
        exercise = copy.deepcopy(exercise)
        exercise["files"] = [ { "field": "content_0", "name": "exercise_attachment" } ]

    return cache_headers(
        render_configured_template(
            request, course, exercise, post_url,
            "access/accept_files_default.html", result
        ),
        request,
        exercise
    )
예제 #11
0
def createForm(request, course, exercise, post_url):
    '''
    Creates form by configuration and grades answers.
    '''
    if "max_points" not in exercise:
        raise ConfigError("Missing required \"max_points\" in exercise configuration")
    try:
        acceptNonce(request)
    except PermissionDenied:
        return render_template(request, course, exercise, post_url,
            'access/exercise_frame.html', { "error":True, "nonce_used":True })

    last = False
    if request.method == 'POST':
        try:
            n = int(request.GET.get('ordinal_number', '0'))
            max_n = int(request.GET.get('max_submissions', '0'))
        except ValueError:
            pass
        last = max_n > 0 and n >= max_n

    form = GradedForm(request.POST or None, request.FILES or None,
        exercise=exercise, show_correct_once=last)

    # Support caching of non personalized forms.
    if not form.randomized and not_modified_since(request, exercise):
        return not_modified_response(request, exercise)

    result = { "form": form, "rejected": True }

    # Grade valid form posts.
    if form.is_valid():
        (points, error_groups, error_fields) = form.grade()
        points = pointsInRange(points, exercise["max_points"])

        # Allow passing to asynchronous grading.
        if "actions" in exercise or "container" in exercise:
            from .stdasync import _saveForm
            return _saveForm(request, course, exercise, post_url, form)

        # If points are not granted by form fields.
        if points == 0 and not error_fields:
            points = exercise["max_points"]

        result = { "form": form, "accepted": True, "points": points,
            "error_groups": error_groups, "error_fields": error_fields }

    return cache_headers(
        render_configured_template(
            request, course, exercise, post_url,
            'access/create_form_default.html', result
        ),
        request,
        exercise,
        form.randomized,
    )
예제 #12
0
def noGrading(request, course, exercise, post_url):
    '''
    Presents a template and does no grading.
    '''
    if not_modified_since(request, exercise):
        return not_modified_response(request, exercise)
    return cache_headers(
        render_configured_template(
            request, course, exercise, post_url, None, None
        ),
        request,
        exercise
    )
예제 #13
0
def comparePostValues(request, course, exercise, post_url):
    '''
    Presents a template and grades configured POST values.
    '''
    if "max_points" not in exercise:
        raise ConfigError(
            "Missing required \"max_points\" in exercise configuration")

    if not_modified_since(request, exercise):
        return not_modified_response(request, exercise)

    result = None
    if request.method == "POST":

        if "values" in exercise:
            received = {}
            points = 0
            failed = []

            # Check each POST value against the rule.
            for (name, rule) in exercise["values"].items():
                received[name] = request.POST.get(name, False)
                if "accept" in rule:
                    if (received[name] in rule["accept"]) or \
                        (True in rule["accept"] and received[name] is not False):
                        if "points" in rule and isinstance(
                                rule["points"], int):
                            points += rule["points"]
                    else:
                        failed.append(name)

            # If points are not granted by rules.
            if points == 0 and not failed:
                points = exercise["max_points"]

            points = pointsInRange(points, exercise["max_points"])
            result = {
                "accepted": True,
                "received": received,
                "points": points,
                "failed": failed
            }
        else:
            result = {"accepted": True, "points": 0}

    return cache_headers(
        render_configured_template(request, course, exercise, post_url, None,
                                   result), request, exercise)
예제 #14
0
def acceptGitAddress(request, course, exercise, post_url):
    '''
    Presents a template and accepts Git URL for grading.
    '''
    _requireActions(exercise)
    if not_modified_since(request, exercise):
        return not_modified_response(request, exercise)

    result = None

    # Receive post.
    if request.method == "POST" and "git" in request.POST and request.POST["git"].strip():
        source = request.POST["git"]

        # Safe gitlab addresses.
        if "require_gitlab" in exercise:
            if not source.startswith("git@%s:" % (exercise["require_gitlab"])):
                url_start = "https://%s/" % (exercise["require_gitlab"])
                if source.startswith(url_start):
                    url_start_len = len(url_start)
                    url_parts = source[url_start_len:].split("/")
                    if len(url_parts) > 1:
                        source = "git@%s:%s/%s" % (exercise["require_gitlab"], url_parts[-2], url_parts[-1])
                        if not source.endswith(".git"):
                            source += ".git"
                    else:
                        result = { "error": True, "invalid_address": True }
                else:
                    result = { "error": True, "invalid_address": True }

        # Try to prevent shell injections.
        elif "\"" in source or ";" in source:
            result = { "error": True, "invalid_address": True }

        if result is None:
            sdir = create_submission_dir(course, exercise)
            write_submission_file(sdir, "gitsource", source)
            return _acceptSubmission(request, course, exercise, post_url, sdir)

    return cache_headers(
        render_configured_template(
            request, course, exercise, post_url,
            "access/accept_git_default.html", result
        ),
        request,
        exercise
    )
예제 #15
0
def acceptGitAddress(request, course, exercise, post_url):
    '''
    Presents a template and accepts Git URL for grading.
    '''
    _requireActions(exercise)
    if not_modified_since(request, exercise):
        return not_modified_response(request, exercise)

    result = None

    # Receive post.
    if request.method == "POST" and "git" in request.POST and request.POST["git"].strip():
        source = request.POST["git"]

        # Safe gitlab addresses.
        if "require_gitlab" in exercise:
            if not source.startswith("git@%s:" % (exercise["require_gitlab"])):
                url_start = "https://%s/" % (exercise["require_gitlab"])
                if source.startswith(url_start):
                    url_start_len = len(url_start)
                    url_parts = source[url_start_len:].split("/")
                    if len(url_parts) > 1:
                        source = "git@%s:%s/%s" % (exercise["require_gitlab"], url_parts[0], url_parts[1])
                        if not source.endswith(".git"):
                            source += ".git"
                    else:
                        result = { "error": True, "invalid_address": True }
                else:
                    result = { "error": True, "invalid_address": True }

        # Try to prevent shell injections.
        elif "\"" in source or ";" in source:
            result = { "error": True, "invalid_address": True }

        if result is None:
            sdir = create_submission_dir(course, exercise)
            write_submission_file(sdir, "gitsource", source)
            return _acceptSubmission(request, course, exercise, post_url, sdir)

    return cache_headers(
        render_configured_template(
            request, course, exercise, post_url,
            "access/accept_git_default.html", result
        ),
        request,
        exercise
    )
예제 #16
0
def comparePostValues(request, course, exercise, post_url):
    '''
    Presents a template and grades configured POST values.
    '''
    if "max_points" not in exercise:
        raise ConfigError("Missing required \"max_points\" in exercise configuration")

    if not_modified_since(request, exercise):
        return not_modified_response(request, exercise)

    result = None
    if request.method == "POST":

        if "values" in exercise:
            received = {}
            points = 0
            failed = []

            # Check each POST value against the rule.
            for (name, rule) in exercise["values"].items():
                received[name] = request.POST.get(name, False)
                if "accept" in rule:
                    if (received[name] in rule["accept"]) or \
                        (True in rule["accept"] and received[name] is not False):
                        if "points" in rule and isinstance(rule["points"], int):
                            points += rule["points"]
                    else:
                        failed.append(name)

            # If points are not granted by rules.
            if points == 0 and not failed:
                points = exercise["max_points"]

            points = pointsInRange(points, exercise["max_points"])
            result = { "accepted": True, "received": received,
                "points": points, "failed": failed }
        else:
            result = { "accepted": True, "points": 0 }

    return cache_headers(
        render_configured_template(
            request, course, exercise, post_url, None, result
        ),
        request,
        exercise
    )
예제 #17
0
def acceptFiles(request, course, exercise, post_url):
    '''
    Presents a template and accepts files for grading queue.
    '''
    _requireActions(exercise)
    if not_modified_since(request, exercise):
        return not_modified_response(request, exercise)

    result = None

    # Receive post.
    if request.method == "POST" and "files" in exercise:

        # Confirm that all required files were submitted.
        files_submitted = [] # exercise["files"] entries for the files that were really submitted
        for entry in exercise["files"]:
            # by default, all fields are required
            required = ("required" not in entry or entry["required"])
            if entry["field"] not in request.FILES:
                if required:
                    result = { "error": True, "missing_files": True }
                    break
            else:
                files_submitted.append(entry)

        if result is None:
            if "required_number_of_files" in exercise and \
                    exercise["required_number_of_files"] > len(files_submitted):
                result = { "error": True, "missing_files": True }
            else:
                # Store submitted files.
                sdir = create_submission_dir(course, exercise)
                for entry in files_submitted:
                    save_submitted_file(sdir, entry["name"], request.FILES[entry["field"]])
                return _acceptSubmission(request, course, exercise, post_url, sdir)

    return cache_headers(
        render_configured_template(
            request, course, exercise, post_url,
            "access/accept_files_default.html", result
        ),
        request,
        exercise
    )
예제 #18
0
def acceptFiles(request, course, exercise, post_url):
    '''
    Presents a template and accepts files for grading queue.
    '''
    _requireActions(exercise)
    if not_modified_since(request, exercise):
        return not_modified_response(request, exercise)

    result = None

    # Receive post.
    if request.method == "POST" and "files" in exercise:

        # Confirm that all required files were submitted.
        files_submitted = [] # exercise["files"] entries for the files that were really submitted
        for entry in exercise["files"]:
            # by default, all fields are required
            required = ("required" not in entry or entry["required"])
            if entry["field"] not in request.FILES:
                if required:
                    result = { "rejected": True, "missing_files": True }
                    break
            else:
                files_submitted.append(entry)

        if result is None:
            if "required_number_of_files" in exercise and \
                    exercise["required_number_of_files"] > len(files_submitted):
                result = { "rejected": True, "missing_files": True }
            else:
                # Store submitted files.
                sdir = create_submission_dir(course, exercise)
                for entry in files_submitted:
                    save_submitted_file(sdir, entry["name"], request.FILES[entry["field"]])
                return _acceptSubmission(request, course, exercise, post_url, sdir)

    return cache_headers(
        render_configured_template(
            request, course, exercise, post_url,
            "access/accept_files_default.html", result
        ),
        request,
        exercise
    )
예제 #19
0
def view(request, course, exercise, post_url):
    '''
    Renders an iframe to hold javascript based exercise from static files.
    '''
    url = '/static/' + course['key'] + exercise['iframe_src']
    result = {
        'src':
        update_url_params(
            url, {
                'submission_url':
                request.GET.get('submission_url'),
                'submit_url':
                request.build_absolute_uri(
                    reverse('access.views.exercise_ajax',
                            args=[course['key'], exercise['key']])),
            }),
    }
    return render_configured_template(request, course, exercise, post_url,
                                      './iframe.html', result)
예제 #20
0
def acceptPost(request, course, exercise, post_url):
    '''
    Presents a template and accepts post value for grading queue.
    '''
    _requireActions(exercise)
    if not_modified_since(request, exercise):
        return not_modified_response(request, exercise)

    fields = copy.deepcopy(exercise.get("fields", []))
    if request.method == "POST":

        # Parse submitted values.
        miss = False
        for entry in fields:
            entry["value"] = request.POST.get(entry["name"], "").strip()
            if "required" in entry and entry["required"] and not entry["value"]:
                entry["missing"] = True
                miss = True
        if miss:
            result = { "fields": fields, "error": True }
        else:

            # Store submitted values.
            sdir = create_submission_dir(course, exercise)
            for entry in fields:
                write_submission_file(sdir, entry["name"], entry["value"])
            return _acceptSubmission(request, course, exercise, post_url, sdir)
    else:
        result = { "fields": fields }

    return cache_headers(
        render_configured_template(
            request, course, exercise, post_url,
            'access/accept_post_default.html', result
        ),
        request,
        exercise
    )
예제 #21
0
def noGrading(request, course, exercise, post_url):
    '''
    Presents a template and does no grading.
    '''
    return render_configured_template(request, course, exercise, post_url, None, None);
예제 #22
0
def createForm(request, course, exercise, post_url):
    '''
    Creates form by configuration and grades answers.
    '''
    if "max_points" not in exercise:
        raise ConfigError(
            "Missing required \"max_points\" in exercise configuration")
    try:
        acceptNonce(request)
    except PermissionDenied:
        return render_template(request, course, exercise, post_url,
                               'access/exercise_frame.html', {
                                   "error": True,
                                   "nonce_used": True
                               })

    last = False
    if request.method == 'POST':
        try:
            n = int(request.GET.get('ordinal_number', '0'))
            max_n = int(request.GET.get('max_submissions', '0'))
        except ValueError:
            pass
        last = max_n > 0 and n >= max_n

    form = GradedForm(request.POST or None,
                      request.FILES or None,
                      exercise=exercise,
                      show_correct_once=last)

    # Support caching of non personalized forms.
    if not form.randomized and not_modified_since(request, exercise):
        return not_modified_response(request, exercise)

    result = {"form": form, "rejected": True}

    # Grade valid form posts.
    if form.is_valid():
        (points, error_groups, error_fields) = form.grade()
        points = pointsInRange(points, exercise["max_points"])

        # Allow passing to asynchronous grading.
        if "actions" in exercise or "container" in exercise:
            from .stdasync import _saveForm
            return _saveForm(request, course, exercise, post_url, form)

        # If points are not granted by form fields.
        if points == 0 and not error_fields:
            points = exercise["max_points"]

        result = {
            "form": form,
            "accepted": True,
            "points": points,
            "error_groups": error_groups,
            "error_fields": error_fields
        }

    return cache_headers(
        render_configured_template(request, course, exercise, post_url,
                                   'access/create_form_default.html', result),
        request,
        exercise,
        form.randomized,
    )
예제 #23
0
def acceptGeneralForm(request, course, exercise, post_url):
    '''
    Presents a template and accepts form containing any input types 
    (text, file, etc) for grading queue.
    '''

    _requireActions(exercise)
    if not_modified_since(request, exercise):
        return not_modified_response(request, exercise)

    fields = copy.deepcopy(exercise.get("fields", []))
    result = None
    miss = False
    
    if request.method == "POST":
        # Parse submitted values.
        for entry in fields:        
            entry["value"] = request.POST.get(entry["name"], "").strip()
            if "required" in entry and entry["required"] and not entry["value"]:
                entry["missing"] = True
                miss = True
        
        files_submitted = [] 
        if "files" in exercise:
            # Confirm that all required files were submitted.
            #files_submitted = [] # exercise["files"] entries for the files that were really submitted
            for entry in exercise["files"]:
                # by default, all fields are required
                required = ("required" not in entry or entry["required"])
                if entry["field"] not in request.FILES:
                    if required:
                        result = { "rejected": True, "missing_files": True }
                        break
                else:
                    files_submitted.append(entry)
                   
        if miss:
            result = { "fields": fields, "rejected": True }
        elif result is None:
            # Store submitted values.
            sdir = create_submission_dir(course, exercise)
            for entry in fields:
                write_submission_file(sdir, entry["name"], entry["value"])
                               
            if "files" in exercise:
                if "required_number_of_files" in exercise and \
                        exercise["required_number_of_files"] > len(files_submitted):
                    result = { "rejected": True, "missing_files": True }
                else:
                    # Store submitted files.
                    for entry in files_submitted:
                        save_submitted_file(sdir, entry["name"], request.FILES[entry["field"]])             
            return _acceptSubmission(request, course, exercise, post_url, sdir)
    
    return cache_headers(
        render_configured_template(
            request, course, exercise, post_url,
            "access/accept_general_default.html", result
        ),
        request,
        exercise
    )    
예제 #24
0
def createForm(request, course, exercise, post_url):
    '''
    Creates form by configuration and grades answers.
    '''
    if "max_points" not in exercise:
        raise ConfigError("Missing required \"max_points\" in exercise configuration")

    last = False
    if request.method == 'POST':
        try:
            n = int(request.GET.get('ordinal_number', '0'))
            max_n = int(request.GET.get('max_submissions', '0'))
        except ValueError:
            pass
        last = max_n > 0 and n >= max_n

    try:
        form = GradedForm(request.POST or None, request.FILES or None,
            exercise=exercise, reveal_correct=last, request=request)
    except PermissionDenied:
        # Randomized forms raise PermissionDenied when the POST data contains
        # forged checksums or samples. It could be cleaner to check those
        # in the form validation, but the old code raises an exception like this.
        return render_template(request, course, exercise, post_url,
            'access/exercise_frame.html', { "rejected": True, "invalid_checksum": True })

    # Support caching of non personalized forms.
    if not form.randomized and not_modified_since(request, exercise):
        return not_modified_response(request, exercise)

    result = { "form": form, "rejected": True }

    # Grade valid form posts.
    if form.is_valid():
        (points, error_groups, error_fields) = form.grade()
        points = pointsInRange(points, exercise["max_points"])

        # Allow passing to asynchronous grading.
        if "container" in exercise:
            from .stdasync import _saveForm
            return _saveForm(request, course, exercise, post_url, form)

        # If points are not granted by form fields.
        if points == 0 and not error_fields:
            points = exercise["max_points"]

        result = { "form": form, "accepted": True, "points": points,
            "error_groups": error_groups, "error_fields": error_fields }
    else:
        # Don't reveal the correct answers if the form was rejected, and a
        # submission was not consumed.
        form.reveal_correct = False

    return cache_headers(
        render_configured_template(
            request, course, exercise, post_url,
            'access/create_form_default.html', result
        ),
        request,
        exercise,
        form.randomized,
    )