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())
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() )
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)
def group(): if not config.groups_enabled: abort(404) with DbCursor() as c: student = _get_student(c) user_id, _, _, login, _, _ = student grouplimit = get_grouplimit(c, user_id) can_add_groups = grouplimit > 0 # Fetch established groups c.execute('''SELECT users.name, users.email, users.github, groupsusers.`group` FROM groupsusers LEFT JOIN users ON groupsusers.user = users.id WHERE groupsusers.`group` IN (SELECT `group` from groupsusers WHERE user = ?) ORDER BY groupsusers.`group`, users.name ASC''', [user_id]) partners = c.fetchall() groups = OrderedDict() for name, email, github, group in partners: groups.setdefault(group, []).append((name, email, github)) # Fetch all my groups that are waiting on other people to accept c.execute('''SELECT users.name, invitations.status, invitations.invitation_id FROM invitations LEFT JOIN users ON invitations.user = users.id WHERE invitations.invitation_id IN (SELECT invitation_id FROM invitations WHERE user = ? AND status = ?) ORDER BY invitations.invitation_id, users.name''', [user_id, ACCEPTED]) invitees = c.fetchall() proposed_groups = OrderedDict() for name, status, invitation_id in invitees: proposed_groups.setdefault(invitation_id, []).append((name, status)) # Fetch all groups that want me c.execute('''SELECT users.name, invitations.status, invitations.invitation_id FROM invitations LEFT JOIN users ON invitations.user = users.id WHERE users.id != ? AND invitations.invitation_id IN (SELECT invitation_id FROM invitations WHERE user = ? AND status = ?) ORDER BY invitations.invitation_id, users.name''', [user_id, user_id, INVITED]) invitations = c.fetchall() proposing_groups = OrderedDict() for name, status, invitation_id in invitations: proposing_groups.setdefault(invitation_id, []).append((name, status)) template_common = _template_common(c) return render_template("dashboard/group.html", groups=groups.items(), proposed_groups=proposed_groups.items(), proposing_groups=proposing_groups.items(), can_add_groups=can_add_groups, min_size=config.group_min_size, max_size=config.group_max_size, **template_common)
def modify_grouplimit_now(): user_id = request.form.get("f_user_id") action = request.form.get("f_action") if not user_id: abort(400) if action not in ("add", "subtract"): abort(400) with DbCursor() as c: student = get_user_by_id(c, user_id) if not student: abort(400) _, _, _, _, github, _ = student modification = {"add": +1, "subtract": -1} modify_grouplimit(c, user_id, modification[action]) grouplimit = get_grouplimit(c, user_id) flash("grouplimit has been set to %d" % grouplimit, "success") if github: return redirect(url_for("ta.students_one", identifier=github, type_="github")) else: return redirect(url_for("ta.students_one", identifier=user_id, type_="user_id"))
def modify_grouplimit_now(): user_id = request.form.get("f_user_id") action = request.form.get("f_action") if not user_id: abort(400) if action not in ("add", "subtract"): abort(400) with DbCursor() as c: student = get_user_by_id(c, user_id) if not student: abort(400) _, _, _, _, github, _ = student modification = {"add": +1, "subtract": -1} modify_grouplimit(c, user_id, modification[action]) grouplimit = get_grouplimit(c, user_id) flash("grouplimit has been set to %d" % grouplimit, "success") if github: return redirect( url_for("ta.students_one", identifier=github, type_="github")) else: return redirect( url_for("ta.students_one", identifier=user_id, type_="user_id"))
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)
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)
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)
def group(): if not config.groups_enabled: abort(404) with DbCursor() as c: student = _get_student(c) user_id, _, _, login, _, _ = student grouplimit = get_grouplimit(c, user_id) can_add_groups = grouplimit > 0 # Fetch established groups c.execute( '''SELECT users.name, users.email, users.github, groupsusers.`group` FROM groupsusers LEFT JOIN users ON groupsusers.user = users.id WHERE groupsusers.`group` IN (SELECT `group` from groupsusers WHERE user = ?) ORDER BY groupsusers.`group`, users.name ASC''', [user_id]) partners = c.fetchall() groups = OrderedDict() for name, email, github, group in partners: groups.setdefault(group, []).append((name, email, github)) # Fetch all my groups that are waiting on other people to accept c.execute( '''SELECT users.name, invitations.status, invitations.invitation_id FROM invitations LEFT JOIN users ON invitations.user = users.id WHERE invitations.invitation_id IN (SELECT invitation_id FROM invitations WHERE user = ? AND status = ?) ORDER BY invitations.invitation_id, users.name''', [user_id, ACCEPTED]) invitees = c.fetchall() proposed_groups = OrderedDict() for name, status, invitation_id in invitees: proposed_groups.setdefault(invitation_id, []).append( (name, status)) # Fetch all groups that want me c.execute( '''SELECT users.name, invitations.status, invitations.invitation_id FROM invitations LEFT JOIN users ON invitations.user = users.id WHERE users.id != ? AND invitations.invitation_id IN (SELECT invitation_id FROM invitations WHERE user = ? AND status = ?) ORDER BY invitations.invitation_id, users.name''', [user_id, user_id, INVITED]) invitations = c.fetchall() proposing_groups = OrderedDict() for name, status, invitation_id in invitations: proposing_groups.setdefault(invitation_id, []).append( (name, status)) template_common = _template_common(c) return render_template("dashboard/group.html", groups=groups.items(), proposed_groups=proposed_groups.items(), proposing_groups=proposing_groups.items(), can_add_groups=can_add_groups, min_size=config.group_min_size, max_size=config.group_max_size, **template_common)