Exemplo n.º 1
0
def flag(name, bid):
    assign = get_assignment(name)
    user_ids = assign.active_user_ids(current_user.id)
    flag = 'flag' in request.form
    next_url = request.form['next']

    backup = models.Backup.query.get(bid)
    if not Backup.can(backup, current_user, "view"):
        abort(404)

    if not assign.active:
        flash('It is too late to change what submission is graded.', 'warning')
    elif flag:
        result = assign.flag(bid, user_ids)
        flash('Flagged submission {}. '.format(result.hashid) +
              'This submission will be used for grading', 'success')
    else:
        result = assign.unflag(bid, user_ids)
        flash('Removed flag from {}. '.format(result.hashid) +
              'The most recent submission will be used for grading.', 'success')

    if is_safe_redirect_url(request, next_url):
        return redirect(next_url)
    else:
        flash("Not a valid redirect", "danger")
        abort(400)
Exemplo n.º 2
0
Arquivo: student.py Projeto: kvakil/ok
def code(name, submit, bid):
    assign = get_assignment(name)
    backup = Backup.query.get(bid)

    if not (backup and Backup.can(backup, current_user, "view")):
        abort(404)
    if backup.submit != submit:
        return redirect(url_for('.code', name=name, submit=backup.submit, bid=bid))

    diff_type = request.args.get('diff')
    if diff_type not in (None, 'short', 'full'):
        return redirect(url_for('.code', name=name, submit=submit, bid=bid))
    if not assign.files and diff_type:
        return abort(404)

    # sort comments by (filename, line)
    comments = collections.defaultdict(list)
    for comment in backup.comments:
        comments[(comment.filename, comment.line)].append(comment)
    # highlight files and add comments
    files = highlight.diff_files(assign.files, backup.files(), diff_type)
    for filename, source_file in files.items():
        for line in source_file.lines:
            line.comments = comments[(filename, line.line_after)]
    return render_template('student/assignment/code.html',
        course=assign.course, assignment=assign, backup=backup,
        files=files, diff_type=diff_type)
Exemplo n.º 3
0
def flag(name, bid):
    assign = get_assignment(name)
    user_ids = assign.active_user_ids(current_user.id)
    flag = 'flag' in request.form
    next_url = request.form['next']

    backup = models.Backup.query.get(bid)
    if not Backup.can(backup, current_user, "view"):
        abort(404)

    if not assign.active:
        flash('It is too late to change what submission is graded.', 'warning')
    elif flag:
        result = assign.flag(bid, user_ids)
        flash('Flagged submission {}. '.format(result.hashid) +
              'This submission will be used for grading', 'success')
    else:
        result = assign.unflag(bid, user_ids)
        flash('Removed flag from {}. '.format(result.hashid) +
              'The most recent submission will be used for grading.', 'success')

    if is_safe_redirect_url(request, next_url):
        return redirect(next_url)
    else:
        flash("Not a valid redirect", "danger")
        abort(400)
Exemplo n.º 4
0
def download(name, submit, bid, file):
    backup = Backup.query.get(bid)
    if not (backup and Backup.can(backup, current_user, "view")):
        abort(404)
    if backup.submit != submit:
        return redirect(url_for('.download', name=name, submit=backup.submit,
                                bid=bid, file=file))
    try:
        contents = backup.files()[file]
    except KeyError:
        abort(404)
    response = make_response(contents)

    inline = 'raw' in request.args

    content_disposition = "inline" if inline else "attachment"
    response.headers["Content-Disposition"] = ("{0}; filename={1!s}"
                                               .format(content_disposition, file))
    response.headers["Content-Security-Policy"] = "default-src 'none';"
    response.headers["X-Content-Type-Options"] = "nosniff"
    if file.endswith('.ipynb') and not inline:
        # Prevent safari from adding a .txt extension to files
        response.headers["Content-Type"] = "application/octet-stream; charset=UTF-8"
    else:
        response.headers["Content-Type"] = "text/plain; charset=UTF-8"

    return response
Exemplo n.º 5
0
def edit_backup(bid):
    courses, current_course = get_courses()
    backup = Backup.query.options(db.joinedload('assignment')).get(bid)
    if not backup:
        abort(404)
    if not Backup.can(backup, current_user, 'grade'):
        flash("You do not have permission to score this assignment.",
              "warning")
        abort(401)
    form = forms.SubmissionTimeForm()
    if form.validate_on_submit():
        backup.custom_submission_time = form.get_submission_time(
            backup.assignment)
        db.session.commit()
        flash('Submission time saved', 'success')
        return redirect(url_for('.edit_backup', bid=bid))
    else:
        form.set_submission_time(backup)
    return render_template(
        'staff/grading/edit.html',
        courses=courses,
        current_course=current_course,
        backup=backup,
        student=backup.submitter,
        form=form,
    )
Exemplo n.º 6
0
def download(name, submit, bid, file):
    backup = Backup.query.get(bid)
    if not (backup and Backup.can(backup, current_user, "view")):
        abort(404)
    if backup.submit != submit:
        return redirect(
            url_for('.download',
                    name=name,
                    submit=backup.submit,
                    bid=bid,
                    file=file))
    try:
        contents = backup.files()[file]
    except KeyError:
        abort(404)
    response = make_response(contents)

    content_disposition = "inline" if 'raw' in request.args else "attachment"
    response.headers["Content-Disposition"] = ("{0}; filename={1!s}".format(
        content_disposition, file))
    response.headers["Content-Security-Policy"] = "default-src 'none';"
    response.headers["X-Content-Type-Options"] = "nosniff"
    response.headers["Content-Type"] = "text/plain; charset=UTF-8"

    return response
Exemplo n.º 7
0
def composition(bid):
    backup = Backup.query.get(bid)
    if not (backup and Backup.can(backup, current_user, "grade")):
        abort(404)
    form = forms.CompositionScoreForm()
    existing = Score.query.filter_by(backup=backup, kind="composition").first()
    if existing:
        form.kind.data = "composition"
        form.message.data = existing.message
        form.score.data = existing.score
    return grading_view(backup, form=form)
Exemplo n.º 8
0
Arquivo: admin.py Projeto: gratimax/ok
def composition(bid):
    backup = Backup.query.get(bid)
    if not (backup and Backup.can(backup, current_user, "grade")):
        abort(404)
    form = forms.CompositionScoreForm()
    existing = Score.query.filter_by(backup=backup, kind="composition").first()
    if existing:
        form.kind.data = "composition"
        form.message.data = existing.message
        form.score.data = existing.score
    return grading_view(backup, form=form)
Exemplo n.º 9
0
def download(name, submit, bid, file):
    backup = Backup.query.get(bid)
    if not (backup and Backup.can(backup, current_user, "view")):
        abort(404)
    if backup.submit != submit:
        return redirect(url_for('.download', name=name, submit=backup.submit,
                                bid=bid, file=file))
    try:
        contents = backup.files()[file]
    except KeyError:
        abort(404)
    response = make_response(contents)
    response.headers["Content-Disposition"] = "attachment; filename={0!s}".format(file)
    return response
Exemplo n.º 10
0
Arquivo: admin.py Projeto: gratimax/ok
def grading(bid):
    backup = Backup.query.get(bid)
    if not (backup and Backup.can(backup, current_user, "grade")):
        abort(404)

    form = forms.GradeForm()
    existing = Score.query.filter_by(backup=backup).first()

    if existing and existing.kind in GRADE_TAGS:
        form = forms.GradeForm(kind=existing.kind)
        form.kind.data = existing.kind
        form.message.data = existing.message
        form.score.data = existing.score

    return grading_view(backup, form=form)
Exemplo n.º 11
0
def grading(bid):
    backup = Backup.query.get(bid)
    if not (backup and Backup.can(backup, current_user, "grade")):
        abort(404)

    form = forms.GradeForm()
    existing = [s for s in backup.scores if not s.archived]
    first_score = existing[0] if existing else None

    if first_score and first_score.kind in GRADE_TAGS:
        form = forms.GradeForm(kind=first_score.kind)
        form.kind.data = first_score.kind
        form.message.data = first_score.message
        form.score.data = first_score.score

    return grading_view(backup, form=form)
Exemplo n.º 12
0
def autograde_backup(bid):
    backup = Backup.query.options(db.joinedload('assignment')).get(bid)
    if not backup:
        abort(404)
    if not Backup.can(backup, current_user, 'grade'):
        flash("You do not have permission to score this assignment.", "warning")
        abort(401)

    form = forms.CSRFForm()
    if form.validate_on_submit():
        try:
            autograder.autograde_backup(backup)
            flash('Submitted to the autograder', 'success')
        except ValueError as e:
            flash(str(e), 'error')
    return redirect(url_for('.grading', bid=bid))
Exemplo n.º 13
0
def download(name, submit, bid, file):
    backup = Backup.query.get(bid)
    if not (backup and Backup.can(backup, current_user, "view")):
        abort(404)
    if backup.submit != submit:
        return redirect(
            url_for('.download',
                    name=name,
                    submit=backup.submit,
                    bid=bid,
                    file=file))
    try:
        contents = backup.files()[file]
    except KeyError:
        abort(404)
    response = make_response(contents)
    response.headers[
        "Content-Disposition"] = "attachment; filename={0!s}".format(file)
    return response
Exemplo n.º 14
0
def download(name, submit, bid, file):
    backup = Backup.query.get(bid)
    if not (backup and Backup.can(backup, current_user, "view")):
        abort(404)
    if backup.submit != submit:
        return redirect(url_for('.download', name=name, submit=backup.submit,
                                bid=bid, file=file))
    try:
        contents = backup.files()[file]
    except KeyError:
        abort(404)
    response = make_response(contents)

    content_disposition = "inline" if 'raw' in request.args else "attachment"
    response.headers["Content-Disposition"] = ("{0}; filename={1!s}"
                                               .format(content_disposition, file))
    response.headers["Content-Security-Policy"] = "default-src 'none';"
    response.headers["X-Content-Type-Options"] = "nosniff"
    response.headers["Content-Type"] = "text/plain; charset=UTF-8"

    return response
Exemplo n.º 15
0
def grade(bid):
    """ Used as a form submission endpoint. """
    backup = Backup.query.options(db.joinedload('assignment')).get(bid)
    if not backup:
        abort(404)
    if not Backup.can(backup, current_user, 'grade'):
        flash("You do not have permission to score this assignment.", "warning")
        abort(401)

    form = forms.GradeForm()
    score_kind = form.kind.data.strip().lower()
    is_composition = (score_kind == "composition")
    # TODO: Form should include redirect url instead of guessing based off tag

    if is_composition:
        form = forms.CompositionScoreForm()

    if not form.validate_on_submit():
        return grading_view(backup, form=form)

    score = Score(backup=backup, grader=current_user,
                  assignment_id=backup.assignment_id)
    form.populate_obj(score)
    db.session.add(score)
    db.session.commit()

    # Archive old scores of the same kind
    score.archive_duplicates()

    next_page = None
    flash_msg = "Added a {0} {1} score.".format(score.score, score_kind)

    # Find GradingTasks applicable to this score
    tasks = backup.grading_tasks
    for task in tasks:
        task.score = score
        cache.delete_memoized(User.num_grading_tasks, task.grader)

    db.session.commit()

    if len(tasks) == 1:
        # Go to next task for the current task queue if possible.
        task = tasks[0]
        next_task = task.get_next_task()
        next_route = '.composition' if is_composition else '.grading'
        # Handle case when the task is on the users queue
        if next_task:
            flash_msg += (" There are {0} tasks left. Here's the next submission:"
                          .format(task.remaining))
            next_page = url_for(next_route, bid=next_task.backup_id)
        else:
            flash_msg += " All done with grading for {}".format(backup.assignment.name)
            next_page = url_for('.grading_tasks')
    else:
        # TODO: Send task id or redirect_url in the grading form
        # For now, default to grading tasks
        next_page = url_for('.grading_tasks')

    flash(flash_msg, 'success')

    if not next_page:
        next_page = url_for('.assignment_queues', aid=backup.assignment_id,
                            cid=backup.assignment.course_id)
    return redirect(next_page)
Exemplo n.º 16
0
Arquivo: admin.py Projeto: gratimax/ok
def grade(bid):
    """ Used as a form submission endpoint. """
    backup = Backup.query.options(db.joinedload('assignment')).get(bid)
    if not backup:
        abort(404)
    if not Backup.can(backup, current_user, 'grade'):
        flash("You do not have permission to score this assignment.", "warning")
        abort(401)

    form = forms.GradeForm()
    score_kind = form.kind.data.strip().lower()
    is_composition = (score_kind == "composition")
    # TODO: Form should include redirect url instead of guessing based off tag

    if is_composition:
        form = forms.CompositionScoreForm()

    if not form.validate_on_submit():
        return grading_view(backup, form=form)

    score = Score(backup=backup, grader=current_user,
                  assignment_id=backup.assignment_id)
    form.populate_obj(score)
    db.session.add(score)
    db.session.commit()

    # Archive old scores of the same kind
    score.archive_duplicates()

    next_page = None
    flash_msg = "Added a {0} {1} score.".format(score.score, score_kind)

    # Find GradingTasks applicable to this score
    tasks = backup.grading_tasks
    for task in tasks:
        task.score = score
        cache.delete_memoized(User.num_grading_tasks, task.grader)

    db.session.commit()

    if len(tasks) == 1:
        # Go to next task for the current task queue if possible.
        task = tasks[0]
        next_task = task.get_next_task()
        next_route = '.composition' if is_composition else '.grading'
        # Handle case when the task is on the users queue
        if next_task:
            flash_msg += (" There are {0} tasks left. Here's the next submission:"
                          .format(task.remaining))
            next_page = url_for(next_route, bid=next_task.backup_id)
        else:
            flash_msg += " All done with grading for {}".format(backup.assignment.name)
            next_page = url_for('.grading_tasks')
    else:
        # TODO: Send task id or redirect_url in the grading form
        # For now, default to grading tasks
        next_page = url_for('.grading_tasks')

    flash(flash_msg, 'success')

    if not next_page:
        next_page = url_for('.assignment_queues', aid=backup.assignment_id,
                            cid=backup.assignment.course_id)
    return redirect(next_page)