def submissions_user(course_id, owner_id): ''' List all the users in the course ''' course_id = int(course_id) course = Course.by_id(course_id) check_resource_exists(course, "Course", course_id) user, user_id = get_user() if course_id is not None: is_grader = user.is_grader(course_id) else: is_grader = False is_owner = user_id == maybe_int(owner_id) if not is_grader and not is_owner: return "You are not an instructor or the owner of the assignment!" owner = User.by_id(maybe_int(owner_id)) assignments = natsorted(course.get_submitted_assignments(), key=lambda r: r.name) all_subs = Submission.by_student(owner_id, course_id) all_subs = {s[0].assignment_id: s for s in all_subs} submissions = [all_subs.get(assignment.id, (None, None, assignment)) for assignment in assignments] return render_template('courses/submissions_user.html', course_id=course_id, assignments=assignments, submissions=submissions, owner=owner, is_instructor=is_grader)
def submissions_filter(course_id): ''' List all the users in the course ''' is_grader = g.user.is_grader(int(course_id)) if not is_grader: return "You are not an instructor or TA in this course!" course_id = int(course_id) course = Course.by_id(course_id) students = natsorted(course.get_students(), key=lambda r: r.name()) assignments = natsorted(course.get_submitted_assignments(), key=lambda r: r.name) criteria = request.values.get("criteria", "none") search_key = int(request.values.get("search_key", "-1")) submissions = [] if criteria == "student": all_subs = Submission.by_student(search_key, course_id) all_subs = {s[0].assignment_id: s for s in all_subs} submissions = [ all_subs.get(assignment.id, (None, None, assignment)) for assignment in assignments ] elif criteria == "assignment": all_subs = Submission.by_assignment(search_key, course_id) all_subs = {s[0].user_id: s for s in all_subs} submissions = [ all_subs.get(student.id, (None, student, None)) for student in students ] return render_template('courses/submissions_filter.html', course_id=course_id, assignments=assignments, students=students, submissions=submissions, criteria=criteria, search_key=search_key, is_instructor=is_grader)
def dashboard(lti=lti, lti_exception=None): """ :type lti: controllers.pylti.flask.lTI """ force_default_assignment = maybe_bool(request.values.get('force_default_assignment', "false")) if 'user' not in g and not g.user: return "You are not logged in." course_id = get_course_id() user, user_id = get_user() if course_id is None: return "You are not in a course context." is_grader = user.is_grader(course_id) if is_grader and not force_default_assignment: return grader_dashboard(user, course_id) course = Course.by_id(course_id) assignment = course.get_default_assignment() if assignment is not None: return redirect(url_for("blockpy.load", assignment_id=assignment.id, course_id=course_id, user_id=user_id, force_download=False, embed=True)) else: # No default assignment! assignments = natsorted(course.get_submitted_assignments(), key=lambda r: r.name) all_subs = Submission.by_student(user_id, course_id) all_subs = {s[0].assignment_id: s for s in all_subs} submissions = [all_subs.get(assignment.id, (None, None, assignment)) for assignment in assignments] return render_template('courses/dashboard.html', embed=True, course_id=course_id, user=user, is_grader=is_grader, submissions=submissions, criteria='student')
def get_assignments(): assignment_ids = request.values.get('assignment_ids', "") course_id = get_course_id() user, user_id = get_user() # TODO: verify that they have the permissions to see these assignments assignments, groups = [], [] errors = [] if not assignment_ids: course: Course = Course.by_id(course_id) check_resource_exists(course, "Course", course_id) grouped_assignments = natsorted( course.get_submitted_assignments_grouped(), key=lambda r: (r.AssignmentGroup.name if r.AssignmentGroup is not None else None, r.Assignment.name)) assignments = [a.Assignment.encode_json() for a in grouped_assignments] groups = [ a.AssignmentGroup.encode_json() if a.AssignmentGroup is not None else None for a in grouped_assignments ] else: for assignment_id in assignment_ids.split(","): if not assignment_id.isdigit(): errors.append(f"Unknown Assignment ID: {assignment_id!r}") assignment_id = int(assignment_id) # With Course Role Information assignment = Assignment.by_id(assignment_id) check_resource_exists(assignment, "Assignment", assignment_id) assignments.append(assignment.encode_json()) return ajax_success( dict(assignments=assignments, errors=errors, groups=groups))
def dashboard(lti=lti): """ :type lti: controllers.pylti.flask.lTI """ if 'user' not in g and not g.user: return "You are not logged in." course_id = get_course_id() user, user_id = get_user() if course_id is None: return "You are not in a course context." is_grader = user.is_grader(course_id) if is_grader: return grader_dashboard(user, course_id) course = Course.by_id(course_id) assignments = natsorted(course.get_submitted_assignments(), key=lambda r: r.name) all_subs = Submission.by_student(user_id, course_id) all_subs = {s[0].assignment_id: s for s in all_subs} submissions = [ all_subs.get(assignment.id, (None, None, assignment)) for assignment in assignments ] return render_template('courses/dashboard.html', embed=True, course_id=course_id, user=user, is_grader=is_grader, submissions=submissions, criteria='student')
def import_bundle(bundle, owner_id, course_id=None, update=True): if 'course' in bundle: course = Course.decode_json(bundle['course'], owner_id=owner_id) db.session.add(course) db.session.commit() else: course = Course.by_id(course_id) assignment_remap = {} assignments = bundle.get('assignments', []) for assignment_data in natsorted(assignments, key=lambda a: a['name']): assignment = Assignment.decode_json(assignment_data, course_id=course.id, owner_id=owner_id) assignment_remap[assignment_data['url']] = assignment.id group_remap = {} groups = bundle.get('groups', []) for group_data in natsorted(groups, key=lambda g: g['name']): group = AssignmentGroup.decode_json(group_data, course_id=course.id, owner_id=owner_id) group_remap[group_data['url']] = group.id memberships = bundle.get('memberships', []) for member_data in sorted(memberships, key=sorter): assignment_id = assignment_remap[member_data['assignment_url']] group_id = group_remap[member_data['assignment_group_url']] member = AssignmentGroupMembership.decode_json( member_data, assignment_id=assignment_id, assignment_group_id=group_id) return True
def fix_course_outcome_url(): new_url = request.values.get("new_url") course_id = get_course_id() user, user_id = get_user() require_course_instructor(user, course_id) course = Course.by_id(course_id) course.update_endpoint(new_url) return ajax_success({"success": "True"})
def view_assignments(course_id): if not g.user.in_course(course_id): return redirect(url_for('courses.index')) course = Course.by_id(course_id) assignments = Assignment.by_course(course_id) groups = AssignmentGroup.by_course(course_id) return render_template('courses/view_assignments.html', assignments=assignments, groups=groups, course=course, course_id=course_id)
def manage_users(course_id): ''' List all the users in the course ''' if not g.user.in_course(course_id): return redirect(url_for('courses.index')) is_instructor = g.user.is_instructor(int(course_id)) students = Course.by_id(int(course_id)).get_users() return render_template('courses/manage_users.html', students=students, course_id=course_id, is_instructor=is_instructor)
def lti_post_grade(lti, submission, lis_result_sourcedid, assignment_group_id, user_id, course_id): total_score, view_url = get_outcomes(submission, assignment_group_id, user_id, course_id) lis_result_sourcedid = submission.endpoint if lis_result_sourcedid is None else lis_result_sourcedid if 'lis_outcome_service_url' not in session: course = Course.by_id(course_id) session['lis_outcome_service_url'] = course.endpoint session['lis_result_sourcedid'] = lis_result_sourcedid if lis_result_sourcedid and lti: lti.post_grade(total_score, view_url, endpoint=lis_result_sourcedid, url=True) return True, total_score return False, total_score
def rename_course(): course_id = int(request.values.get('course_id')) course = Course.by_id(course_id) # Verify exists check_resource_exists(course, "Course", course_id) # Verify permissions require_course_instructor(g.user, course_id) # Perform action new_name = request.values.get('name') Course.rename(course_id, new_name) return jsonify(success=True)
def remove_course(course_id): course_id = int(request.values.get('course_id')) course = Course.by_id(course_id) # Verify exists check_resource_exists(course, "Course", course_id) # Verify permissions require_course_instructor(g.user, course_id) # Perform action Course.remove(course_id) flash('Course removed') return redirect(url_for('courses.index'))
def export(): user = load_api_user() assignment_url = request.json.get("assignment_url") assignment_id = request.json.get("assignment_id") if assignment_id or assignment_url: if assignment_url: assignment = Assignment.by_url(assignment_url) else: assignment = Assignment.by_id(assignment_id) check_resource_exists(assignment, "Assignment", assignment_id or assignment_url) if not user.is_instructor(assignment.course_id): return abort(400, "Not an instructor in this assignments' course.") return json.dumps(export_bundle(assignments=[assignment])) group_id = request.json.get("assignment_group_id") if group_id: assignment_group = AssignmentGroup.by_id(group_id) assignments = assignment_group.get_assignments() memberships = assignment_group.get_memberships() if not user.is_instructor(assignment_group.course_id): return abort( 400, "Not an instructor in this assignment group's course.") for assignment in assignments: if not user.is_instructor(assignment.course_id): return abort(400, "Not an instructor in this assignments' course.") bundle = export_bundle(groups=[assignment_group], assignments=assignments, memberships=memberships) return json.dumps(bundle) course_id = request.json.get("course_id") if course_id: if not user.is_instructor(course_id): return abort(400, "Not an instructor in this course.") course = Course.by_id(course_id) groups = course.get_assignment_groups() assignment_and_memberships = course.get_assignments() assignments = [a for a, m in assignment_and_memberships] memberships = [m for a, m in assignment_and_memberships] bundle = export_bundle(groups=groups, assignments=assignments, memberships=memberships) return json.dumps(bundle) abort(400, "No assignment_id or assignment_group_id given")
def generate_link_subjects(zip_file, course_id): with io.StringIO() as linktable_file: writer = csv.writer(linktable_file, **PROGSNAP_CSV_WRITER_OPTIONS) writer.writerow([ "SubjectID", "X-IsStaff", "X-Roles", "X-Name.Last", "X-Name.First", "X-Email" ]) # Get any users explicitly in this course users_with_roles = Course.by_id(course_id).get_users() users, user_roles = {}, {} for role, user in users_with_roles: if user.id not in users: users[user.id] = user user_roles[user.id] = set() user_roles[user.id].add(role.name) # Get any additional users found in the logs log_users = Log.get_users_for_course(course_id) for log_user in log_users: if log_user.id not in users: users[log_user.id] = log_user user_roles[log_user.id] = { role.name for role in log_user.get_course_roles(course_id) } # Report their information for user_id, user in natsorted( users.items(), lambda u: (u[1].last_name, u[1].first_name)): roles = user_roles[user_id] display_roles = ", ".join(sorted(roles)) writer.writerow([ user.id, # SubjectId bool(User.is_lti_instructor(roles)), # X-IsStaff display_roles, # X-Roles user.last_name, # X-Name.Last user.first_name, # X-Name.First user.email, # X-Email ]) zip_file.writestr("LinkTables/Subject.csv", linktable_file.getvalue()) return "LinkTables/Subject.csv"
def browse_history(): # Get parameters course_id = maybe_int(request.values.get('course_id')) assignment_id = maybe_int(request.values.get('assignment_id')) student_id = maybe_int(request.values.get('user_id')) page_offset = maybe_int(request.values.get('page_offset', 0)) embed = maybe_bool(request.values.get('embed')) user, user_id = get_user() # Get resources assignment = Assignment.by_id(assignment_id) student = User.by_id(student_id) course = Course.by_id(course_id) # Verify user can see the submission if user_id != student_id and not user.is_grader(course_id): return ajax_failure("Only graders can see logs for other people.") history = Log.get_history(course_id, assignment_id, student_id, page_offset, HISTORY_PAGE_LIMIT) return render_template('blockpy/browse_history.html', assignment=assignment, student=student, course=course, history=history, embed=embed)
def course(course_id): user, user_id = get_user() if course_id.isdigit(): course_id = int(course_id) course: Course = Course.by_id(course_id) else: course: Course = Course.by_url(course_id) check_resource_exists(course, "Course", course_id) if not user.in_course(course_id) and course.visibility != "public": flash("You are not a user in this course and/or it is not public.") return redirect(url_for('courses.index')) is_instructor = user.is_instructor(course_id) is_grader = user.is_grader(course_id) if is_grader: return render_template('courses/course.html', course=course, course_id=course_id, is_grader=is_grader, is_instructor=is_instructor) return view_assignments(course_id)
def users(): user_ids = request.values.get('user_ids', "") course_id = get_course_id() user, user_id = get_user() if course_id is None: return ajax_failure("You are not in a course context.") is_grader = user.is_grader(course_id) if not is_grader and user_ids != str(user_id): return ajax_failure("You do not have permissions to see those users.") users = [] errors = [] # If blank, then get all the available users if not user_ids: course = Course.by_id(course_id) check_resource_exists(course, "Course", course_id) user_roles = course.get_users() user_data = {} for role, user in user_roles: if user not in user_data: user_data[user] = user.encode_json() user_data[user]['roles'] = [] user_data[user]['roles'].append(role.encode_json()) users.extend(user_data.values()) # Otherwise, get the subset suggested else: for user_id in user_ids.split(","): if not user_id.isdigit(): errors.append(f"Unknown User ID: {user_id!r}") continue user_id = int(user_id) # With Course Role Information user = User.by_id(user_id) check_resource_exists(user, "User", user_id) user_data = user.encode_json() user_data['roles'] = [ r.encode_json() for r in user.get_course_roles(course_id) ] users.append(user_data) return ajax_success(dict(users=users, errors=errors))
def submissions_grid(course_id): ''' List all the users in the course ''' # TODO: Fix this course_id = int(course_id) is_instructor = g.user.is_instructor(course_id) if not is_instructor: return "You are not an instructor!" course = Course.by_id(course_id) students = course.get_students() assignments = natsorted(course.get_submitted_assignments(), key=lambda r: r[0].name) grouped_assignments = defaultdict(list) #for assignment in assignments: # grouped_assignments[membership.assignment_group_id].append(assignment) assignment_groups = course.get_assignment_groups() submissions = {(s.assignment_id, s.user_id): s for s in course.get_submissions()} return render_template('courses/submissions_grid.html', course_id=course_id, students=students, submissions=submissions, assignment_groups=assignment_groups, grouped_assignments=grouped_assignments, is_instructor=is_instructor)