Beispiel #1
0
def fetch(args, metadata):
    course = canvas.Course()
    what = args[0].rstrip(os.sep)
    args = args[1:]
    if os.sep in what:
        partition = os.path.split(what)
        what = partition[0]
        args.insert(0, partition[1])
    args = list(map(lambda s: s.rstrip(os.sep), args))
    if what == "students":
        fetch_students(course)
    elif what == "groups":
        fetch_groups(course)
    elif what == "group":
        fetch_group(course, " ".join(args))
    elif what == "subs":
        if len(args) == 0:
            fetch_all_subs(course)
        else:
            fetch_subs(course,
                       " ".join(args),
                       deep=True,
                       metadata=metadata == True)
    else:
        raise Exception("Don't yet know how to fetch {}.".format(str(args)))
Beispiel #2
0
def add_students_to_sections_random(section_names):
    course = canvas.Course()
    can = canvas.Canvas()

    section_ids = {
        section_name: find_section_id(section_name)
        for section_name in section_names
    }

    users_all = can.list_students(course.id)

    random.shuffle(users_all)
    users_slice_start = 0
    for section_name, n_sections_remaining in zip(
            section_names, range(len(section_ids), 0, -1)):
        n_users_remaining = len(users_all) - users_slice_start
        section_size = n_users_remaining // n_sections_remaining
        section_id = section_ids[section_name]
        section_users = users_all[users_slice_start:users_slice_start +
                                  section_size]
        print('Section {} (id: {}) gets {} students: {}'.format(
            repr(section_name), section_id, section_size,
            ', '.join(u['name'] for u in section_users)))
        for user in section_users:
            can.add_section_member(section_id, user['id'])
        users_slice_start += section_size
Beispiel #3
0
def grade(args):
    args, _ = grade_args_parser().parse_known_args(args)

    _check_grade(args.grade)
    _check_filepaths(args.attachments)

    if args.comment:
        comment = args.comment
    elif args.comment_file:
        _check_filepaths([args.comment_file])
        with open(args.comment_file) as f:
            comment = f.read()
    elif args.attachments:
        comment = "See attached file{}.".format(
            "" if len(args.attachments) == 1 else "s")
    else:
        comment = None

    course = canvas.Course()
    assignment = canvas.Assignment(course)
    submission = canvas.Submission()
    student_ids = submission.student_ids
    if args.one:
        student_ids = student_ids[:1]
    for sub in assignment.submissions():
        if sub['user_id'] in student_ids:
            current_grade = sub['grade']
            if current_grade == grade:
                print('Already graded.')
                course.canvas.show_verification_urls(
                    course.id, assignment.id, sub['user_id'])
                return
    for student_id in student_ids:
        assignment.give_feedback(student_id, args.grade, comment, args.attachments, use_post=True)
Beispiel #4
0
def find_user(user_name):
    course = canvas.Course()
    can = canvas.Canvas()
    users = can.list_students(course.id)

    # Hack to remove duplicates.
    users_found = list(filter(lambda user: user_name == user['name'] or user_name == user['login_id'][:6], users))
    users_found = list(set(tuple(x.items()) for x in users_found))
    users_found = [{k: v for k, v in x} for x in users_found]
    if len(users_found) == 1:
        print('Found; id: {}, sis_user_id: {}, sis_login_id: {}, name: {}'.format(
            users_found[0]['id'], users_found[0]['sis_user_id'],
            users_found[0]['sis_login_id'], users_found[0]['name']))
    elif len(users_found) > 1:
        print('{} users found:'.format(len(users_found)))
        for user in users_found:
            print(user)
        sys.exit(1)
    else:
        print('No users found.  Guesses:')
        users.sort(key=lambda user: levenshtein.ratio(user_name, user['name']),
                   reverse=True)
        for user in users[:10]:
            print('{:.2%} match; id: {}, sis_user_id: {}, sis_login_id: {}, name: {}'.format(
                levenshtein.ratio(user_name, user['name']),
                user['id'], user['sis_user_id'],
                user['sis_login_id'], user['name']))

        sys.exit(1)
Beispiel #5
0
def set_group_members(group_name, user_names):
    course = canvas.Course()

    can = canvas.Canvas()
    groups_all = can.groups_in_course(course.id)
    groups = list(filter(lambda x: x['name'] == group_name,
                         groups_all))
    if len(groups) < 1:
        raise Exception('no group of that name')
    else:
        group_id = groups[0]['id']

    users_all = can.list_students(course.id)
    user_ids = []
    for user_name in user_names:
        users = list(filter(lambda x: x['name'] == user_name,
                            users_all))
        if len(users) < 1:
            raise Exception('no user of that name')
        else:
            user_id = users[0]['id']
        user_ids.append(user_id)
    can.add_group_members(group_id, user_ids)

    fetch_groups(course) # a bit silly, and very slow
Beispiel #6
0
def grade(args):
    args, more_attachments = grade_args_parser().parse_known_args(args)
    args.attachments += more_attachments

    _check_grade(args.grade)
    _check_filepaths(args.attachments)

    if args.comment:
        comment = args.comment
    elif args.comment_file:
        _check_filepaths([args.comment_file])
        with open(args.comment_file) as f:
            comment = f.read()
    elif args.attachments:
        comment = "See attached file{}.".format("" if len(args.attachments) ==
                                                1 else "s")
    else:
        comment = None

    course = canvas.Course()
    assignment = canvas.Assignment(course)
    submission = canvas.Submission()
    student_ids = submission.student_ids
    if args.one:
        student_ids = student_ids[:1]
    elif args.kuid is not None:
        users_found = _find_user(args.kuid)
        if len(users_found) == 1:
            user_id = users_found[0]['id']
            student_ids = [user_id]
        elif len(users_found) > 1:
            print(
                "Kuid is too ambiguous! Found multiple users with the kuid {}:."
                .format(args.kuid))
            for user in users_found:
                print('- id: {}, login_id: {}, kuid: {}, name: {}'.format(
                    user['id'], user['login_id'], user['kuid'], user['name']))
            sys.exit(1)
        else:
            print("Found no users with the kuid {}!".format(args.kuid))
            sys.exit(1)

    for sub in assignment.submissions():
        if sub['user_id'] in student_ids:
            current_grade = sub['grade']
            if current_grade == grade:
                print('Already graded.')
                course.canvas.show_verification_urls(course.id, assignment.id,
                                                     sub['user_id'])
                return
    for student_id in student_ids:
        assignment.give_feedback(student_id,
                                 args.grade,
                                 comment,
                                 args.attachments,
                                 use_post=True)
Beispiel #7
0
def create(subs_path, category_name, groups_file):
    canvas = canvaslib.Canvas()
    course = canvaslib.Course()

    # Get mapping from abc123 to Canvas User ID.
    user_ids = get_user_id_mapping(canvas, course)

    # Extract groups.
    with open(groups_file) as f:
        contents = f.read().strip()
    groups = [line.split(' ') for line in contents.split('\n')]

    # Update Canvas.
    create_groups_on_canvas(canvas, course, category_name, user_ids, groups)

    # Update locally.
    groupsubs_path = subs_path.replace('subs/', 'groupsubs/')
    os.makedirs(groupsubs_path, exist_ok=True)
    for group_members, group_number in zip(groups, range(len(groups))):
        groupsub_path = os.path.join(groupsubs_path,
                                     '{:03d}'.format(group_number))
        group_members_submitted = []
        total_count = 0
        for abc123 in group_members:
            pattern = os.path.join(subs_path, abc123) + '_*'
            subpaths = glob.glob(pattern)

            # There should be 0 or 1 directories that match.
            # 0 if, for some reason, a KU ID specified in a group.txt doesn't
            #   have a submission. (This can be for other reasons than that it
            #   is an invalid KU ID, or that that KU ID isn't subscribed to the
            #   course. Example: cbh239 is on Advanced Programming 2017 and was
            #   mentioned in a group.txt, they didn't submit anything
            #   themselves for assignment 1, but they don't have an empty
            #   directory like other students.
            if len(subpaths) > 1:
                raise Exception('Wait! Two submissions match {}: {}'.format(
                    abc123, ", ".join(subpaths)))

            elif len(subpaths) == 1:
                subpath = subpaths[0]
                ignore_files = [".staffeli.yml", "group.txt"]
                files = [
                    f for f in os.listdir(subpath) if f not in ignore_files
                ]
                if len(files) > 0:
                    group_members_submitted.append(subpath)

        if len(group_members_submitted) != 1:
            raise Exception('Wait! Multiple submissions from {}: {}'.format(
                ", ".join(group_members), ", ".join(group_members_submitted)))

        submitter_path = group_members_submitted[0]
        os.symlink(os.path.join('..', '..', submitter_path), groupsub_path)

    return 0
Beispiel #8
0
def find_section_id(section_name):
    course = canvas.Course()
    can = canvas.Canvas()

    sections_all = can.course_sections(course.id)
    sections = list(filter(lambda x: x['name'] == section_name, sections_all))
    if len(sections) < 1:
        raise Exception('no section of that name')
    else:
        section_id = sections[0]['id']
    return section_id
Beispiel #9
0
def _find_user(user_name):
    course = canvas.Course()
    users = course.list_students().json

    # Hack to remove duplicates.
    users_found = list(
        filter(
            lambda user: user_name == user['name'] or user_name == user[
                'login_id'][:6], users))
    users_found = list(set(tuple(x.items()) for x in users_found))
    users_found = [{k: v for k, v in x} for x in users_found]
    return users_found
Beispiel #10
0
def delete_all_groups(group_category_name):
    course = canvas.Course()
    can = canvas.Canvas()

    categories_all = can.group_categories(course.id)
    categories = list(
        filter(lambda x: x['name'] == group_category_name, categories_all))
    if len(categories) < 1:
        raise Exception('no category of that name')
    else:
        group_category_id = categories[0]['id']

    can.delete_all_groups(group_category_id)

    fetch_groups(course)  # a bit silly, and very slow
Beispiel #11
0
def add_member_to_section(section_name, user_name):
    course = canvas.Course()
    can = canvas.Canvas()

    section_id = find_section_id(section_name)

    users_all = can.list_students(course.id)
    users = list(filter(lambda x: (x['name'] == user_name or
                                   x['login_id'][:6] == user_name),
                        users_all))
    if len(users) < 1:
        raise Exception('no user of that name')
    else:
        user_id = users[0]['id']
    can.add_section_member(section_id, user_id)
Beispiel #12
0
def grade(args):
    args, remargs = grade_args_parser().parse_known_args(args)
    grade = _check_grade(args.grade)
    filepaths = _check_filepaths(remargs)
    message = args.message

    course = canvas.Course()
    assignment = canvas.Assignment(course)
    submission = canvas.Submission()
    for student_id in submission.student_ids:
        assignment.give_feedback(student_id,
                                 grade,
                                 message,
                                 filepaths,
                                 use_post=True)
Beispiel #13
0
def fetch(args, metadata):
    course = canvas.Course()
    what = args[0]
    args = args[1:]
    if '/' in what:
        partition = what.partition('/')
        what = partition[0]
        args.insert(0, partition[2])
    if what == "students":
        fetch_students(course)
    elif what == "groups":
        fetch_groups(course)
    elif what == "group":
        fetch_group(course, " ".join(args))
    elif what == "subs":
        if len(args) == 0:
            fetch_all_subs(course)
        else:
            fetch_subs(course,
                       " ".join(args).strip('/'),
                       deep=True,
                       metadata=metadata == True)
    else:
        raise Exception("Don't yet know how to fetch {}.".format(str(args)))
Beispiel #14
0
def groupsplit(args):
    split_according_to_groups(canvas.Course(), args[0], args[1])
Beispiel #15
0
#!/usr/bin/env python3
#
# Split into sections.

import sys
import re
import os

import staffeli.canvas as canvas


course = canvas.Course()
can = canvas.Canvas()

def create(groupsubs_path, groups_file, *section_names):
    sections_path = groupsubs_path.replace('groupsubs/', 'sections/')

    with open(groups_file) as f:
        contents = f.read().strip()
    groups = [line.split(' ') for line in contents.split('\n')]

    groups_distributed = []

    all_sections = can.list_sections(course.id)
    for name in section_names:
        section = next(filter(lambda sec: sec['name'] == name,
                              all_sections))

        m = re.match(r'Class (.+)', name)
        if m is not None:
            name = m.group(1).lower()
Beispiel #16
0
def sectsplit(name, subs=None, splits=None):
    """Split submissions according to sections."""
    subs = subs if subs else "subs"
    splits = splits if splits else "splits"
    split_by_section(canvas.Course(), name, subs, splits)