示例#1
0
文件: __init__.py 项目: aykamko/ob2
def _get_next_step(current_step):
    # I know this kind of logic requires O(2^N) different cases, but right now there's only 1 config
    # option that affects this list (it's the student photos enable/disable), so it's simplest to
    # express the 2 alternatives this way.
    #
    # When we add more features to the onboarding process, you can come up with a better,
    # generalized way of determining the onboarding steps.
    if config.student_photos_enabled:
        steps = ["onboarding.student_id", "onboarding.photo"]
    else:
        steps = ["onboarding.student_id"]

    if current_step is None:
        return steps[0]
    step_i = steps.index(current_step)
    if step_i == len(steps) - 1:
        # This is the final step of onboarding.
        # Authenticate the user and redirect them to the dashboard.
        with DbCursor() as c:
            user = get_user_by_github(c, github_username())
        assert user
        user_id_, _, _, _, _, _ = user
        authenticate_as_user(user_id_)
        return "onboarding.welcome"
    else:
        return steps[step_i + 1]
示例#2
0
def _get_next_step(current_step):
    # I know this kind of logic requires O(2^N) different cases, but right now there's only 1 config
    # option that affects this list (it's the student photos enable/disable), so it's simplest to
    # express the 2 alternatives this way.
    #
    # When we add more features to the onboarding process, you can come up with a better,
    # generalized way of determining the onboarding steps.
    if config.student_photos_enabled:
        steps = ["onboarding.student_id", "onboarding.photo"]
    else:
        steps = ["onboarding.student_id"]

    if current_step is None:
        return steps[0]
    step_i = steps.index(current_step)
    if step_i == len(steps) - 1:
        # This is the final step of onboarding.
        # Authenticate the user and redirect them to the dashboard.
        with DbCursor() as c:
            user = get_user_by_github(c, github_username())
        assert user
        user_id_, _, _, _, _, _ = user
        authenticate_as_user(user_id_)
        return "onboarding.welcome"
    else:
        return steps[step_i + 1]
示例#3
0
 def photo():
     github = github_username()
     if request.method == "GET":
         return render_template("onboarding/photo.html", github=github)
     try:
         with DbCursor() as c:
             user = get_user_by_github(c, github)
             user_id, _, _, _, _, _ = user
             photo_base64 = request.form.get("f_photo_cropped")
             photo_prefix = "data:image/jpeg;base64,"
             if not photo_base64:
                 fail_validation(
                     "No photo submitted. Please choose a photo.")
             if not photo_base64.startswith(photo_prefix):
                 fail_validation(
                     "Unrecognized photo format. (Potential autograder bug?)"
                 )
             photo_binary = buffer(
                 binascii.a2b_base64(photo_base64[len(photo_prefix):]))
             if len(photo_binary) > 2**21:
                 fail_validation(
                     "Photo exceeds maximum allowed size (2MiB).")
             c.execute("UPDATE users SET photo = ? WHERE id = ?",
                       [photo_binary, user_id])
         return redirect(url_for(_get_next_step("onboarding.photo")))
     except ValidationError as e:
         return redirect_with_error(url_for("onboarding.photo"), e)
示例#4
0
def student_id():
    github = github_username()
    if request.method == "GET":
        return render_template("onboarding/student_id.html", github=github)
    try:
        mailer_job = None
        github_job = None
        with DbCursor() as c:
            user = get_user_by_github(c, github)
            if user:
                return redirect(url_for("dashboard.index"))
            student_id = request.form.get("f_student_id")
            if not student_id:
                fail_validation("Student ID is required")
            user = get_user_by_student_id(c, student_id)
            if not user:
                fail_validation("Student not found with that student ID")
            user_id, name, _, login, old_github, email = user
            if old_github:
                fail_validation(
                    "Another GitHub account has been associated with that student "
                    "ID already.")
            if not name:
                fail_validation(
                    "There is no name associated with this account. (Contact your TA?)"
                )
            if not login:
                fail_validation(
                    "There is no login associated with this account. (Contact your "
                    "TA?)")
            if not email:
                fail_validation(
                    "There is no email associated with this account. (Contact your "
                    "TA?)")
            c.execute('''UPDATE users SET github = ? WHERE sid = ?''',
                      [github, student_id])
            if not config.github_read_only_mode:
                github_job = repomanager_queue.create(c, "assign_repo",
                                                      (login, [github]))
            if config.mailer_enabled:
                if config.inst_account_enabled:
                    attachments = [("pdf", get_inst_account_form_path(login))]
                else:
                    attachments = []
                email_payload = create_email(
                    "onboarding_confirm",
                    email,
                    "%s Autograder Registration" % config.course_number,
                    _attachments=attachments,
                    name=name,
                    login=login,
                    inst_account_enabled=config.inst_account_enabled)
                mailer_job = mailer_queue.create(c, "send", email_payload)
        if config.mailer_enabled and mailer_job:
            mailer_queue.enqueue(mailer_job)
        if not config.github_read_only_mode and github_job:
            repomanager_queue.enqueue(github_job)
        return redirect(url_for(_get_next_step("onboarding.student_id")))
    except ValidationError as e:
        return redirect_with_error(url_for("onboarding.student_id"), e)
示例#5
0
文件: __init__.py 项目: aykamko/ob2
def welcome():
    github = github_username()
    with DbCursor() as c:
        user = get_user_by_id(c, user_id())
    return render_template("onboarding/welcome.html",
                           github=github,
                           user=user,
                           inst_account_enabled=config.inst_account_enabled)
示例#6
0
def welcome():
    github = github_username()
    with DbCursor() as c:
        user = get_user_by_id(c, user_id())
    return render_template("onboarding/welcome.html",
                           github=github,
                           user=user,
                           inst_account_enabled=config.inst_account_enabled)
示例#7
0
文件: __init__.py 项目: aykamko/ob2
def log_out():
    if request.method == "POST":
        authenticate_as_user(None)
        authenticate_as_github_username(None)
        return redirect(url_for("onboarding.log_in"))
    elif github_username() or user_id():
        return render_template("onboarding/log_out.html")
    else:
        return redirect(url_for("onboarding.log_in"))
示例#8
0
def log_out():
    if request.method == "POST":
        authenticate_as_user(None)
        authenticate_as_github_username(None)
        return redirect(url_for("onboarding.log_in"))
    elif github_username() or user_id():
        return render_template("onboarding/log_out.html")
    else:
        return redirect(url_for("onboarding.log_in"))
示例#9
0
文件: __init__.py 项目: aykamko/ob2
def student_id():
    github = github_username()
    if request.method == "GET":
        return render_template("onboarding/student_id.html",
                               github=github)
    try:
        mailer_job = None
        github_job = None
        with DbCursor() as c:
            user = get_user_by_github(c, github)
            if user:
                return redirect(url_for("dashboard.index"))
            student_id = request.form.get("f_student_id")
            if not student_id:
                fail_validation("Student ID is required")
            user = get_user_by_student_id(c, student_id)
            if not user:
                fail_validation("Student not found with that student ID")
            user_id, name, _, login, old_github, email = user
            if old_github:
                fail_validation("Another GitHub account has been associated with that student "
                                "ID already.")
            if not name:
                fail_validation("There is no name associated with this account. (Contact your TA?)")
            if not login:
                fail_validation("There is no login associated with this account. (Contact your "
                                "TA?)")
            if not email:
                fail_validation("There is no email associated with this account. (Contact your "
                                "TA?)")
            c.execute('''UPDATE users SET github = ? WHERE sid = ?''',
                      [github, student_id])
            if not config.github_read_only_mode:
                github_job = repomanager_queue.create(c, "assign_repo", (login, [github]))
            if config.mailer_enabled:
                if config.inst_account_enabled:
                    attachments = [("pdf", get_inst_account_form_path(login))]
                else:
                    attachments = []
                email_payload = create_email("onboarding_confirm", email,
                                             "%s Autograder Registration" % config.course_number,
                                             _attachments=attachments, name=name, login=login,
                                             inst_account_enabled=config.inst_account_enabled)
                mailer_job = mailer_queue.create(c, "send", email_payload)
        if config.mailer_enabled and mailer_job:
            mailer_queue.enqueue(mailer_job)
        if not config.github_read_only_mode and github_job:
            repomanager_queue.enqueue(github_job)
        return redirect(url_for(_get_next_step("onboarding.student_id")))
    except ValidationError as e:
        return redirect_with_error(url_for("onboarding.student_id"), e)
示例#10
0
文件: __init__.py 项目: aykamko/ob2
def _get_current_step():
    if is_ta():
        return "ta.index"
    if user_id():
        return "dashboard.index"
    github = github_username()
    if not github:
        return "onboarding.log_in"
    with DbCursor() as c:
        user = get_user_by_github(c, github)
        if not user:
            return "onboarding.student_id"
        user_id_, _, _, _, _, _ = user
        if config.student_photos_enabled:
            photo = get_photo(c, user_id_)
            if not photo:
                return "onboarding.photo"
        authenticate_as_user(user_id_)
        return "dashboard.index"
示例#11
0
def _get_current_step():
    if is_ta():
        return "ta.index"
    if user_id():
        return "dashboard.index"
    github = github_username()
    if not github:
        return "onboarding.log_in"
    with DbCursor() as c:
        user = get_user_by_github(c, github)
        if not user:
            return "onboarding.student_id"
        user_id_, _, _, _, _, _ = user
        if config.student_photos_enabled:
            photo = get_photo(c, user_id_)
            if not photo:
                return "onboarding.photo"
        authenticate_as_user(user_id_)
        return "dashboard.index"
示例#12
0
文件: __init__.py 项目: aykamko/ob2
 def photo():
     github = github_username()
     if request.method == "GET":
         return render_template("onboarding/photo.html",
                                github=github)
     try:
         with DbCursor() as c:
             user = get_user_by_github(c, github)
             user_id, _, _, _, _, _ = user
             photo_base64 = request.form.get("f_photo_cropped")
             photo_prefix = "data:image/jpeg;base64,"
             if not photo_base64:
                 fail_validation("No photo submitted. Please choose a photo.")
             if not photo_base64.startswith(photo_prefix):
                 fail_validation("Unrecognized photo format. (Potential autograder bug?)")
             photo_binary = buffer(binascii.a2b_base64(photo_base64[len(photo_prefix):]))
             if len(photo_binary) > 2**21:
                 fail_validation("Photo exceeds maximum allowed size (2MiB).")
             c.execute("UPDATE users SET photo = ? WHERE id = ?", [photo_binary, user_id])
         return redirect(url_for(_get_next_step("onboarding.photo")))
     except ValidationError as e:
         return redirect_with_error(url_for("onboarding.photo"), e)
示例#13
0
def _template_common():
    return {
        "github_username": github_username(),
        "groups_enabled": config.groups_enabled
    }
示例#14
0
def enter_grades_confirm():
    try:
        f_step = request.form.get("f_step")
        if f_step not in ("1", "2"):
            fail_validation("Enum out of range (probably a programming error)")
        step = int(f_step)
        assignment_name = request.form.get("f_assignment")
        if not assignment_name:
            fail_validation("Assignment name is required")
        assignment = get_assignment_by_name(assignment_name)
        if assignment is None:
            fail_validation("Assignment not found: %s" % assignment_name)
        min_score, max_score = assignment.min_score, assignment.max_score

        description = request.form.get("f_description")
        if not description:
            fail_validation("Transaction description is required")

        transaction_source = github_username()

        entries = []
        user_id_set = set()

        with DbCursor() as c:
            valid_identifiers, ambiguous_identifiers = get_valid_ambiguous_identifiers(
                c)

            def try_add(f_student, f_score, f_slipunits):
                if not any((f_student, f_score, f_slipunits)):
                    return
                elif not f_student and (f_score or f_slipunits):
                    fail_validation(
                        "Expected student SID, login, or name, but none provided"
                    )
                elif f_student in ambiguous_identifiers:
                    fail_validation(
                        "The identifier '%s' is ambiguous. Please use another."
                        % f_student)
                else:
                    if step == 1:
                        students = get_users_by_identifier(c, f_student)
                    elif step == 2:
                        student = get_user_by_id(c, f_student)
                        # Let the usual error handling take care of this case
                        students = [student] if student else []
                    if not students:
                        fail_validation("Student or group not found: %s" %
                                        f_student)
                    for student in students:
                        user_id, student_name, _, _, _, _ = student
                        if user_id in user_id_set:
                            fail_validation(
                                "Student was listed more than once: %s" %
                                student_name)
                        try:
                            score = float_or_none(f_score)
                        except ValueError:
                            fail_validation("Not a valid score: %s" % f_score)
                        try:
                            slipunits = int_or_none(f_slipunits)
                        except ValueError:
                            fail_validation(
                                "Slip %s amount not valid: %s" %
                                (slip_unit_name_plural, f_slipunits))
                        if slipunits is not None and slipunits < 0:
                            fail_validation("Slip %s cannot be negative" %
                                            slip_unit_name_plural)
                        if score is not None and not min_score <= score <= max_score:
                            fail_validation(
                                "Score is out of allowed range: %s (Range: %s to %s)"
                                % (f_score, str(min_score), str(max_score)))
                        entries.append([user_id, score, slipunits])
                        user_id_set.add(user_id)

            if step == 1:
                f_students = request.form.getlist("f_student")
                f_scores = request.form.getlist("f_score")
                f_slipunitss = request.form.getlist("f_slipunits")
                if not same_length(f_students, f_scores, f_slipunitss):
                    fail_validation(
                        "Different numbers of students, scores, and slip %s " +
                        "reported. Browser bug?" % slip_unit_name_plural)
                for f_student, f_score, f_slipunits in zip(
                        f_students, f_scores, f_slipunitss):
                    try_add(f_student, f_score, f_slipunits)

            f_csv = request.form.get("f_csv", "")
            for row in csv.reader(StringIO.StringIO(f_csv),
                                  delimiter=",",
                                  quotechar='"'):
                if len(row) != 3:
                    fail_validation("CSV rows must contain 3 entries")
                try_add(*row)

            if not entries:
                fail_validation("No grade or slip %s changes entered" %
                                slip_unit_name_plural)

            if step == 1:
                c.execute(
                    '''SELECT id, name, sid, login, github FROM users
                             WHERE id IN (%s)''' %
                    (",".join(["?"] * len(entries))),
                    [user_id for user_id, _, _ in entries])
                students = c.fetchall()
                details_user = {}
                for user_id, name, sid, login, github in students:
                    details_user[user_id] = [name, sid, login, github]
                c.execute(
                    '''SELECT user, score, slipunits, updated FROM grades
                             WHERE assignment = ? AND user IN (%s)''' %
                    (",".join(["?"] * len(entries))),
                    [assignment.name] + [user_id for user_id, _, _ in entries])
                grades = c.fetchall()
                details_grade = {}
                for user_id, score, slipunits, updated in grades:
                    details_grade[user_id] = [score, slipunits, updated]
                entries_details = []
                for entry in entries:
                    user_id = entry[0]
                    entry_details = (entry +
                                     details_user.get(user_id, [None] * 4) +
                                     details_grade.get(user_id, [None] * 3))
                    entries_details.append(entry_details)
            elif step == 2:
                transaction_number = get_next_autoincrementing_value(
                    c, "enter_grades_last_transaction_number")
                transaction_name = "enter-grades-%s" % transaction_number
                for user_id, score, slipunits in entries:
                    assign_grade_batch(c, [user_id],
                                       assignment.name,
                                       score,
                                       slipunits,
                                       transaction_name,
                                       description,
                                       transaction_source,
                                       manual=True,
                                       dont_lower=False)
        if step == 1:
            entries_csv = StringIO.StringIO()
            entries_csv_writer = csv.writer(entries_csv,
                                            delimiter=",",
                                            quotechar='"')
            for entry in entries:
                entries_csv_writer.writerow(entry)
            return render_template("ta/enter_grades_confirm.html",
                                   entries_details=entries_details,
                                   entries_csv=entries_csv.getvalue(),
                                   assignment_name=assignment.name,
                                   description=description,
                                   full_score=assignment.full_score,
                                   **_template_common())
        elif step == 2:
            if len(entries) == 1:
                flash("1 grade committed", "success")
            else:
                flash("%d grades committed" % len(entries), "success")
            return redirect(url_for("ta.enter_grades"))
    except ValidationError as e:
        return redirect_with_error(url_for("ta.enter_grades"), e)
示例#15
0
def _template_common():
    return {"github_username": github_username(),
            "groups_enabled": config.groups_enabled}
示例#16
0
def enter_grades_confirm():
    try:
        f_step = request.form.get("f_step")
        if f_step not in ("1", "2"):
            fail_validation("Enum out of range (probably a programming error)")
        step = int(f_step)
        assignment_name = request.form.get("f_assignment")
        if not assignment_name:
            fail_validation("Assignment name is required")
        assignment = get_assignment_by_name(assignment_name)
        if assignment is None:
            fail_validation("Assignment not found: %s" % assignment_name)
        min_score, max_score = assignment.min_score, assignment.max_score

        description = request.form.get("f_description")
        if not description:
            fail_validation("Transaction description is required")

        transaction_source = github_username()

        entries = []
        user_id_set = set()

        with DbCursor() as c:
            valid_identifiers, ambiguous_identifiers = get_valid_ambiguous_identifiers(c)

            def try_add(f_student, f_score, f_slipunits):
                if not any((f_student, f_score, f_slipunits)):
                    return
                elif not f_student and (f_score or f_slipunits):
                    fail_validation("Expected student SID, login, or name, but none provided")
                elif f_student in ambiguous_identifiers:
                    fail_validation("The identifier '%s' is ambiguous. Please use another." %
                                    f_student)
                else:
                    if step == 1:
                        students = get_users_by_identifier(c, f_student)
                    elif step == 2:
                        student = get_user_by_id(c, f_student)
                        # Let the usual error handling take care of this case
                        students = [student] if student else []
                    if not students:
                        fail_validation("Student or group not found: %s" % f_student)
                    for student in students:
                        user_id, student_name, _, _, _, _ = student
                        if user_id in user_id_set:
                            fail_validation("Student was listed more than once: %s" % student_name)
                        try:
                            score = float_or_none(f_score)
                        except ValueError:
                            fail_validation("Not a valid score: %s" % f_score)
                        try:
                            slipunits = int_or_none(f_slipunits)
                        except ValueError:
                            fail_validation("Slip %s amount not valid: %s" % (slip_unit_name_plural,
                                                                              f_slipunits))
                        if slipunits is not None and slipunits < 0:
                            fail_validation("Slip %s cannot be negative" % slip_unit_name_plural)
                        if score is not None and not min_score <= score <= max_score:
                            fail_validation("Score is out of allowed range: %s (Range: %s to %s)" %
                                            (f_score, str(min_score), str(max_score)))
                        entries.append([user_id, score, slipunits])
                        user_id_set.add(user_id)

            if step == 1:
                f_students = request.form.getlist("f_student")
                f_scores = request.form.getlist("f_score")
                f_slipunitss = request.form.getlist("f_slipunits")
                if not same_length(f_students, f_scores, f_slipunitss):
                    fail_validation("Different numbers of students, scores, and slip %s " +
                                    "reported. Browser bug?" % slip_unit_name_plural)
                for f_student, f_score, f_slipunits in zip(f_students, f_scores, f_slipunitss):
                    try_add(f_student, f_score, f_slipunits)

            f_csv = request.form.get("f_csv", "")
            for row in csv.reader(StringIO.StringIO(f_csv), delimiter=",", quotechar='"'):
                if len(row) != 3:
                    fail_validation("CSV rows must contain 3 entries")
                try_add(*row)

            if not entries:
                fail_validation("No grade or slip %s changes entered" % slip_unit_name_plural)

            if step == 1:
                c.execute('''SELECT id, name, sid, login, github FROM users
                             WHERE id IN (%s)''' % (",".join(["?"] * len(entries))),
                          [user_id for user_id, _, _ in entries])
                students = c.fetchall()
                details_user = {}
                for user_id, name, sid, login, github in students:
                    details_user[user_id] = [name, sid, login, github]
                c.execute('''SELECT user, score, slipunits, updated FROM grades
                             WHERE assignment = ? AND user IN (%s)''' %
                          (",".join(["?"] * len(entries))),
                          [assignment.name] + [user_id for user_id, _, _ in entries])
                grades = c.fetchall()
                details_grade = {}
                for user_id, score, slipunits, updated in grades:
                    details_grade[user_id] = [score, slipunits, updated]
                entries_details = []
                for entry in entries:
                    user_id = entry[0]
                    entry_details = (entry + details_user.get(user_id, [None] * 4)
                                           + details_grade.get(user_id, [None] * 3))
                    entries_details.append(entry_details)
            elif step == 2:
                transaction_number = get_next_autoincrementing_value(
                    c, "enter_grades_last_transaction_number")
                transaction_name = "enter-grades-%s" % transaction_number
                for user_id, score, slipunits in entries:
                    assign_grade_batch(c, [user_id], assignment.name, score, slipunits,
                                       transaction_name, description, transaction_source,
                                       manual=True, dont_lower=False)
        if step == 1:
            entries_csv = StringIO.StringIO()
            entries_csv_writer = csv.writer(entries_csv, delimiter=",", quotechar='"')
            for entry in entries:
                entries_csv_writer.writerow(entry)
            return render_template("ta/enter_grades_confirm.html",
                                   entries_details=entries_details,
                                   entries_csv=entries_csv.getvalue(),
                                   assignment_name=assignment.name,
                                   description=description,
                                   full_score=assignment.full_score,
                                   **_template_common())
        elif step == 2:
            if len(entries) == 1:
                flash("1 grade committed", "success")
            else:
                flash("%d grades committed" % len(entries), "success")
            return redirect(url_for("ta.enter_grades"))
    except ValidationError as e:
        return redirect_with_error(url_for("ta.enter_grades"), e)