Ejemplo n.º 1
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)
Ejemplo n.º 2
0
def group_create():
    if not config.groups_enabled:
        abort(404)
    try:
        githubs = request.form.getlist("f_github")
        mailer_jobs = []
        with DbCursor() as c:
            student = _get_student(c)
            inviter_user_id, inviter_name, _, _, inviter_github, _ = student
            grouplimit = get_grouplimit(c, inviter_user_id)
            if grouplimit < 1:
                fail_validation("You are in too many groups already")
            invitees = []
            invitation_user_ids = set()
            for github in githubs:
                if not github:
                    continue
                invitee = get_user_by_github(c, github)
                if invitee is None:
                    fail_validation("GitHub username not found: %s" % github)
                invitee_id, _, _, _, _, _ = invitee
                if invitee_id == inviter_user_id:
                    continue
                if invitee_id in invitation_user_ids:
                    continue
                invitation_user_ids.add(invitee_id)
                invitees.append(invitee)
            if not config.group_min_size <= len(invitation_user_ids) + 1 <= config.group_max_size:
                fail_validation("You need between %d and %d people in your group" % (
                    config.group_min_size, config.group_max_size))
            if config.mailer_enabled:
                for _, invitee_name, _, _, _, invitee_email in invitees:
                    email_payload = create_email("group_invite", invitee_email,
                                                 "%s has invited you to a group" % inviter_name,
                                                 inviter_name=inviter_name,
                                                 inviter_github=inviter_github,
                                                 invitee_name=invitee_name,
                                                 invitees=invitees)
                    mailer_job = mailer_queue.create(c, "send", email_payload)
                    mailer_jobs.append(mailer_job)
            invitation_id = get_next_autoincrementing_value(c, "group_next_invitation_id")
            for invitation_user_id in invitation_user_ids:
                c.execute("INSERT INTO invitations (invitation_id, user, status) VALUES (?, ?, ?)",
                          [invitation_id, invitation_user_id, INVITED])
            c.execute("INSERT INTO invitations (invitation_id, user, status) VALUES (?, ?, ?)",
                      [invitation_id, inviter_user_id, ACCEPTED])
            modify_grouplimit(c, inviter_user_id, -1)
            finalize_group_if_ready(c, invitation_id)
        if config.mailer_enabled:
            for mailer_job in mailer_jobs:
                mailer_queue.enqueue(mailer_job)
        return redirect(url_for("dashboard.group"))
    except ValidationError as e:
        return redirect_with_error(url_for("dashboard.group"), e)
Ejemplo n.º 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)
Ejemplo n.º 4
0
def group_respond():
    if not config.groups_enabled:
        abort(404)
    try:
        github_job = None
        mailer_jobs = []
        with DbCursor() as c:
            invitation_id = request.form.get("f_group")
            response = request.form.get("f_response")
            if not invitation_id:
                fail_validation("Expected an invitation identifier (probably a programming error)")
            if response not in ("accept", "reject"):
                fail_validation("Expected a response (probably a programming error)")
            student = _get_student(c)
            user_id, _, _, _, _, _ = student
            c.execute('''SELECT status FROM invitations WHERE invitation_id = ? AND user = ?''',
                      [invitation_id, user_id])
            statuses = c.fetchall()
            if len(statuses) != 1:
                fail_validation("Invitation has already been responded to")
            status = statuses[0][0]
            if response == "accept":
                if status != INVITED:
                    fail_validation("Invitation has already been responded to")
                grouplimit = get_grouplimit(c, user_id)
                if grouplimit < 1:
                    fail_validation("You have joined too many groups already")
                c.execute('''UPDATE invitations SET status = ?
                             WHERE invitation_id = ? AND user = ?''',
                          [ACCEPTED, invitation_id, user_id])
                modify_grouplimit(c, user_id, -1)
                group_name, group_members = finalize_group_if_ready(c, invitation_id)
                if group_name:
                    if not config.github_read_only_mode:
                        group_githubs = []
                        for _, _, _, github in group_members:
                            assert github, "GitHub handle is empty"
                            group_githubs.append(github)
                        github_job = repomanager_queue.create(c, "assign_repo",
                                                              (group_name, group_githubs))
                    if config.mailer_enabled:
                        for _, name, email, github in group_members:
                            email_payload = create_email("group_confirm", email,
                                                         "%s has been created" % group_name,
                                                         group_name=group_name,
                                                         name=name, group_members=group_members)
                            mailer_job = mailer_queue.create(c, "send", email_payload)
                            mailer_jobs.append(mailer_job)
            elif response == "reject":
                if status not in (ACCEPTED, INVITED):
                    fail_validation("Invitation has already been rejected")
                c.execute('''UPDATE invitations SET status = ?
                             WHERE invitation_id = ? AND user = ?''',
                          [REJECTED, invitation_id, user_id])
                if status == ACCEPTED:
                    # Give them back +1 to their group limit
                    modify_grouplimit(c, user_id, +1)
        if config.mailer_enabled:
            for mailer_job in mailer_jobs:
                mailer_queue.enqueue(mailer_job)
        if github_job and not config.github_read_only_mode:
            repomanager_queue.enqueue(github_job)
        return redirect(url_for("dashboard.group"))
    except ValidationError as e:
        return redirect_with_error(url_for("dashboard.group"), e)
Ejemplo n.º 5
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)
Ejemplo n.º 6
0
 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)
Ejemplo n.º 7
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)
Ejemplo n.º 8
0
def group_create():
    if not config.groups_enabled:
        abort(404)
    try:
        githubs = request.form.getlist("f_github")
        github_job = None
        mailer_jobs = []
        with DbCursor() as c:
            student = _get_student(c)
            inviter_user_id, inviter_name, _, _, inviter_github, _ = student
            grouplimit = get_grouplimit(c, inviter_user_id)
            if grouplimit < 1:
                fail_validation("You are in too many groups already")
            invitees = []
            invitation_user_ids = set()
            for github in githubs:
                if not github:
                    continue
                invitee = get_user_by_github(c, github)
                if invitee is None:
                    fail_validation("GitHub username not found: %s" % github)
                invitee_id, _, _, _, _, _ = invitee
                if invitee_id == inviter_user_id:
                    continue
                if invitee_id in invitation_user_ids:
                    continue
                invitation_user_ids.add(invitee_id)
                invitees.append(invitee)
            if not config.group_min_size <= len(
                    invitation_user_ids) + 1 <= config.group_max_size:
                fail_validation(
                    "You need between %d and %d people in your group" %
                    (config.group_min_size, config.group_max_size))
            if config.mailer_enabled:
                for _, invitee_name, _, _, _, invitee_email in invitees:
                    email_payload = create_email(
                        "group_invite",
                        invitee_email,
                        "%s has invited you to a group" % inviter_name,
                        inviter_name=inviter_name,
                        inviter_github=inviter_github,
                        invitee_name=invitee_name,
                        invitees=invitees)
                    mailer_job = mailer_queue.create(c, "send", email_payload)
                    mailer_jobs.append(mailer_job)
            invitation_id = get_next_autoincrementing_value(
                c, "group_next_invitation_id")
            for invitation_user_id in invitation_user_ids:
                c.execute(
                    "INSERT INTO invitations (invitation_id, user, status) VALUES (?, ?, ?)",
                    [invitation_id, invitation_user_id, INVITED])
            c.execute(
                "INSERT INTO invitations (invitation_id, user, status) VALUES (?, ?, ?)",
                [invitation_id, inviter_user_id, ACCEPTED])
            modify_grouplimit(c, inviter_user_id, -1)
            group_name, group_members = finalize_group_if_ready(
                c, invitation_id)
            if group_name:
                if not config.github_read_only_mode:
                    group_githubs = []
                    for _, _, _, github in group_members:
                        assert github, "GitHub handle is empty"
                        group_githubs.append(github)
                    github_job = repomanager_queue.create(
                        c, "assign_repo", (group_name, group_githubs))
                if config.mailer_enabled:
                    for _, name, email, github in group_members:
                        email_payload = create_email(
                            "group_confirm",
                            email,
                            "%s has been created" % group_name,
                            group_name=group_name,
                            name=name,
                            group_members=group_members)
                        mailer_job = mailer_queue.create(
                            c, "send", email_payload)
                        mailer_jobs.append(mailer_job)
        if config.mailer_enabled:
            for mailer_job in mailer_jobs:
                mailer_queue.enqueue(mailer_job)
        if github_job and not config.github_read_only_mode:
            repomanager_queue.enqueue(github_job)
        return redirect(url_for("dashboard.group"))
    except ValidationError as e:
        return redirect_with_error(url_for("dashboard.group"), e)
Ejemplo n.º 9
0
def group_respond():
    if not config.groups_enabled:
        abort(404)
    try:
        github_job = None
        mailer_jobs = []
        with DbCursor() as c:
            invitation_id = request.form.get("f_group")
            response = request.form.get("f_response")
            if not invitation_id:
                fail_validation(
                    "Expected an invitation identifier (probably a programming error)"
                )
            if response not in ("accept", "reject"):
                fail_validation(
                    "Expected a response (probably a programming error)")
            student = _get_student(c)
            user_id, _, _, _, _, _ = student
            c.execute(
                '''SELECT status FROM invitations WHERE invitation_id = ? AND user = ?''',
                [invitation_id, user_id])
            statuses = c.fetchall()
            if len(statuses) != 1:
                fail_validation("Invitation has already been responded to")
            status = statuses[0][0]
            if response == "accept":
                if status != INVITED:
                    fail_validation("Invitation has already been responded to")
                grouplimit = get_grouplimit(c, user_id)
                if grouplimit < 1:
                    fail_validation("You have joined too many groups already")
                c.execute(
                    '''UPDATE invitations SET status = ?
                             WHERE invitation_id = ? AND user = ?''',
                    [ACCEPTED, invitation_id, user_id])
                modify_grouplimit(c, user_id, -1)
                group_name, group_members = finalize_group_if_ready(
                    c, invitation_id)
                if group_name:
                    if not config.github_read_only_mode:
                        group_githubs = []
                        for _, _, _, github in group_members:
                            assert github, "GitHub handle is empty"
                            group_githubs.append(github)
                        github_job = repomanager_queue.create(
                            c, "assign_repo", (group_name, group_githubs))
                    if config.mailer_enabled:
                        for _, name, email, github in group_members:
                            email_payload = create_email(
                                "group_confirm",
                                email,
                                "%s has been created" % group_name,
                                group_name=group_name,
                                name=name,
                                group_members=group_members)
                            mailer_job = mailer_queue.create(
                                c, "send", email_payload)
                            mailer_jobs.append(mailer_job)
            elif response == "reject":
                if status not in (ACCEPTED, INVITED):
                    fail_validation("Invitation has already been rejected")
                c.execute(
                    '''UPDATE invitations SET status = ?
                             WHERE invitation_id = ? AND user = ?''',
                    [REJECTED, invitation_id, user_id])
                if status == ACCEPTED:
                    # Give them back +1 to their group limit
                    modify_grouplimit(c, user_id, +1)
        if config.mailer_enabled:
            for mailer_job in mailer_jobs:
                mailer_queue.enqueue(mailer_job)
        if github_job and not config.github_read_only_mode:
            repomanager_queue.enqueue(github_job)
        return redirect(url_for("dashboard.group"))
    except ValidationError as e:
        return redirect_with_error(url_for("dashboard.group"), e)
Ejemplo n.º 10
0
 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)
Ejemplo n.º 11
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)
Ejemplo n.º 12
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)