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
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)
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
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
def clone(args): dirname = " ".join(args) course = canvas.Canvas().course(name=dirname) mknewdir(dirname) course.cache(dirname) os.chdir(dirname) fetch_students(course) fetch_groups(course)
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
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
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)
def clone(remargs): if len(remargs) == 1: course_name = remargs[0] dirname = course_name elif len(remargs) == 2: course_name = remargs[0] dirname = remargs[1] else: print("Usage: staffeli clone 'COURSE NAME' [DIRECTORY], or see: staffeli help") sys.exit(1) course = canvas.Canvas().course(name = course_name) mknewdir(dirname) course.cache(dirname) print("Cloning '{}' into '{}'...".format(course.displayname, dirname)) os.chdir(dirname) fetch_students(course) fetch_groups(course)
#!/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()