예제 #1
0
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)
예제 #2
0
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)
예제 #3
0
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')
예제 #4
0
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))
예제 #5
0
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')
예제 #6
0
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
예제 #7
0
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"})
예제 #8
0
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)
예제 #9
0
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)
예제 #10
0
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
예제 #11
0
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)
예제 #12
0
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'))
예제 #13
0
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")
예제 #14
0
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"
예제 #15
0
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)
예제 #16
0
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)
예제 #17
0
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))
예제 #18
0
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)