Esempio n. 1
0
def assignments():
    with DbCursor() as c:
        student = _get_student(c)
        user_id, _, _, login, _, _ = student
        super_value = get_super(c, user_id)
        dropped = super_value is not None and super_value < 0
        c.execute(
            "SELECT assignment, score, slipunits, updated FROM grades WHERE user = ?",
            [user_id])
        grade_info = {
            assignment: (score, slipunits, updated)
            for assignment, score, slipunits, updated in c.fetchall()
        }
        template_common = _template_common(c)
    assignments_info = []
    if not dropped:
        for assignment in config.assignments:
            a = assignment.student_view(login)
            if now_compare(a.not_visible_before) >= 0:
                assignments_info.append(
                    (a.name, a.full_score, a.weight, a.due_date) +
                    grade_info.get(a.name, (None, None, None)))
    return render_template("dashboard/assignments.html",
                           assignments_info=assignments_info,
                           **template_common)
Esempio n. 2
0
def students_one(identifier, type_):
    with DbCursor() as c:
        student = None
        if type_ in ("id", "user_id"):
            student = get_user_by_id(c, identifier)
        elif type_ in ("github", "_github_explicit"):
            student = get_user_by_github(c, identifier)
        elif type_ == "login":
            student = get_user_by_login(c, identifier)
        elif type_ in ("sid", "student_id"):
            student = get_user_by_student_id(c, identifier)
        if student is None:
            abort(404)
        user_id, _, _, _, _, _ = student
        super_ = get_super(c, user_id)
        photo = None
        if student_photos_enabled:
            photo = get_photo(c, user_id)
        c.execute(
            '''SELECT users.id, users.name, users.github, groupsusers.`group`
                     FROM groupsusers LEFT JOIN users ON groupsusers.user = users.id
                     WHERE groupsusers.`group` IN
                         (SELECT `group` FROM groupsusers WHERE user = ?)''',
            [user_id])
        groups = OrderedDict()
        for g_user_id, g_name, g_github, g_group in c.fetchall():
            groups.setdefault(g_group, []).append(
                (g_user_id, g_name, g_github))
        grouplimit = get_grouplimit(c, user_id)
        c.execute(
            '''SELECT transaction_name, source, assignment, score, slipunits, updated,
                     description FROM gradeslog WHERE user = ? ORDER BY updated DESC''',
            [user_id])
        entries = c.fetchall()
        full_scores = {
            assignment.name: assignment.full_score
            for assignment in config.assignments
        }
        events = [entry + (full_scores.get(entry[2]), ) for entry in entries]
        c.execute(
            "SELECT assignment, score, slipunits, updated FROM grades WHERE user = ?",
            [user_id])
        grade_info = {
            assignment: (score, slipunits, updated)
            for assignment, score, slipunits, updated in c.fetchall()
        }
        assignments_info = [(a.name, a.full_score, a.weight, a.due_date) +
                            grade_info.get(a.name, (None, None, None))
                            for a in config.assignments]
    return render_template("ta/students_one.html",
                           student=student,
                           super_=super_,
                           photo=photo,
                           groups=groups.items(),
                           grouplimit=grouplimit,
                           events=events,
                           assignments_info=assignments_info,
                           **_template_common())
Esempio n. 3
0
def students_one(identifier, type_):
    with DbCursor() as c:
        student = None
        if type_ in ("id", "user_id"):
            student = get_user_by_id(c, identifier)
        elif type_ in ("github", "_github_explicit"):
            student = get_user_by_github(c, identifier)
        elif type_ == "login":
            student = get_user_by_login(c, identifier)
        elif type_ in ("sid", "student_id"):
            student = get_user_by_student_id(c, identifier)
        if student is None:
            abort(404)
        user_id, _, _, _, _, _ = student
        super_ = get_super(c, user_id)
        photo = None
        if student_photos_enabled:
            photo = get_photo(c, user_id)
        c.execute(
            """SELECT users.id, users.name, users.github, groupsusers.`group`
                     FROM groupsusers LEFT JOIN users ON groupsusers.user = users.id
                     WHERE groupsusers.`group` IN
                         (SELECT `group` FROM groupsusers WHERE user = ?)""",
            [user_id],
        )
        groups = OrderedDict()
        for g_user_id, g_name, g_github, g_group in c.fetchall():
            groups.setdefault(g_group, []).append((g_user_id, g_name, g_github))
        grouplimit = get_grouplimit(c, user_id)
        c.execute(
            """SELECT transaction_name, source, assignment, score, slipunits, updated,
                     description FROM gradeslog WHERE user = ? ORDER BY updated DESC""",
            [user_id],
        )
        entries = c.fetchall()
        full_scores = {assignment.name: assignment.full_score for assignment in config.assignments}
        events = [entry + (full_scores.get(entry[2]),) for entry in entries]
        c.execute("SELECT assignment, score, slipunits, updated FROM grades WHERE user = ?", [user_id])
        grade_info = {assignment: (score, slipunits, updated) for assignment, score, slipunits, updated in c.fetchall()}
        assignments_info = [
            (a.name, a.full_score, a.weight, a.due_date) + grade_info.get(a.name, (None, None, None))
            for a in config.assignments
        ]
    return render_template(
        "ta/students_one.html",
        student=student,
        super_=super_,
        photo=photo,
        groups=groups.items(),
        grouplimit=grouplimit,
        events=events,
        assignments_info=assignments_info,
        **_template_common()
    )
Esempio n. 4
0
def build_now():
    job_name = request.form.get("f_job_name")
    repo = request.form.get("f_repo")
    assignment = get_assignment_by_name(job_name)
    if not assignment:
        abort(400)
    assignment = assignment.student_view(repo)
    if assignment.manual_grading:
        abort(400)

    with DbCursor() as c:
        student = _get_student(c)
        user_id, _, _, login, _, _ = student
        super_value = get_super(c, user_id)
        dropped = super_value is not None and super_value < 0
        if assignment.is_group:
            repos = get_groups(c, user_id)
        else:
            repos = [login]

        if repo not in repos:
            abort(403)

    if now_compare(assignment.not_visible_before,
                   add_grace_period(
                       assignment.cannot_build_after)) != 0 or dropped:
        abort(400)

    branch_hash = get_branch_hash(repo, "master")
    message = None
    if branch_hash:
        message = get_commit_message(repo, branch_hash)

    # This section doesn't absolutely NEED to be consistent with the previous transaction,
    # since we have not specified any actual data constraints. The only possible logical error
    # would be to fulfill a request when the current user's permissions have been revoked
    # between these two transactions.
    with DbCursor() as c:
        build_name = create_build(c, job_name, repo, branch_hash, message)

    if should_limit_source(repo, job_name):
        rate_limit_fail_build(build_name)
    else:
        job = Job(build_name, repo, "Web interface")
        dockergrader_queue.enqueue(job)

    return redirect(url_for("dashboard.builds_one", name=build_name))
Esempio n. 5
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

            super_value = get_super(c, inviter_user_id)
            dropped = super_value is not None and super_value < 0
            if dropped:
                fail_validation(
                    "You are not enrolled in the class; contact a TA if you believe this is a mistake"
                )

            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:
                if config.group_min_size == config.group_max_size:
                    fail_validation(
                        "You need exactly %d people in your group" %
                        config.group_min_size)
                else:
                    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)
Esempio n. 6
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

            super_value = get_super(c, user_id)
            dropped = super_value is not None and super_value < 0
            if dropped:
                fail_validation(
                    "You are not enrolled in the class; contact a TA if you believe this is a mistake"
                )

            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)
Esempio n. 7
0
def assignments_one(name):
    with DbCursor() as c:
        student = _get_student(c)
        user_id, _, _, login, _, _ = student
        assignment = get_assignment_by_name(name)
        super_value = get_super(c, user_id)
        dropped = super_value is not None and super_value < 0

        if not assignment:
            abort(404)

        assignment = assignment.student_view(login)

        slipunits_now = slip_units_now(assignment.due_date)
        is_visible = now_compare(
            assignment.not_visible_before) >= 0 and not dropped
        if assignment.manual_grading:
            can_build = False
        else:
            can_build = now_compare(assignment.cannot_build_after) <= 0

        if not is_visible:
            abort(404)

        c.execute(
            "SELECT score, slipunits, updated FROM grades WHERE user = ? AND assignment = ?",
            [user_id, name])
        grade = c.fetchone()
        if not grade:
            grade = (None, None, None)
        if assignment.is_group:
            repos = get_groups(c, user_id)
        else:
            repos = [login]
        c.execute(
            '''SELECT build_name, source, status, score, `commit`, message, started
                     FROM builds WHERE job = ? AND source IN (%s)
                     ORDER BY started DESC''' % (",".join(["?"] * len(repos))),
            [name] + repos)
        builds = c.fetchall()
        if builds:
            most_recent_repo = builds[0][1]
        else:
            most_recent_repo = None
        if grade[0] is not None:
            c.execute(
                '''SELECT COUNT(*) + 1 FROM grades WHERE assignment = ? AND score > ?''',
                [name, grade[0]])
            rank, = c.fetchone()
        else:
            rank = None
        c.execute(
            '''SELECT COUNT(*), AVG(score) FROM grades
                     WHERE assignment = ? AND score IS NOT NULL''', [name])
        stats = c.fetchone()
        if stats[0] == 0:
            variance = None
            stddev = None
        else:
            c.execute(
                "SELECT AVG((score - ?) * (score - ?)) FROM grades WHERE assignment = ?",
                [stats[1], stats[1], name])
            variance, = c.fetchone()
            stddev = sqrt(variance)

        assignment_info = (
            (assignment.name, assignment.full_score, assignment.weight,
             assignment.due_date, assignment.category, assignment.is_group,
             assignment.manual_grading) + grade + (rank, ) + stats +
            (stddev, ))
        template_common = _template_common(c)
    return render_template("dashboard/assignments_one.html",
                           assignment_info=assignment_info,
                           builds=builds,
                           repos=repos,
                           most_recent_repo=most_recent_repo,
                           slipunits_now=slipunits_now,
                           can_build=can_build,
                           **template_common)