Ejemplo n.º 1
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)
 def get_transaction_id(self, c):
     option_key = "%s_next_transaction_id" % self.queue_name
     transaction_id = get_next_autoincrementing_value(c, option_key)
     return transaction_id
Ejemplo n.º 3
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)