Пример #1
0
def export_submissions():
    assignment_id = int(request.values.get('assignment_id'))
    assignment = Assignment.by_id(assignment_id)
    course_id = get_course_id(True)
    user, user_id = get_user()
    # Verify exists
    check_resource_exists(assignment, "Assignment", assignment_id)
    # Verify permissions
    assignment = Assignment.by_id(int(assignment_id))
    if course_id is None or not user.is_instructor(int(course_id)):
        return "You are not an instructor or the owner of the assignment!"
    # Get data
    suas = Submission.by_assignment(assignment_id, course_id)
    submissions = [sua[0] for sua in suas]
    users = [sua[1] for sua in suas]
    bundle = export_zip(assignments=[assignment],
                        submissions=submissions,
                        users=users)
    filename = assignment.get_filename(extension='.zip')
    return Response(bundle,
                    mimetype='application/zip',
                    headers={
                        'Content-Disposition':
                        'attachment;filename={}'.format(filename)
                    })
Пример #2
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))
Пример #3
0
def dump_logs():
    assignment_id = int(request.values.get('assignment_id'))
    course_id = int(request.values.get('course_id'))
    assignment = Assignment.by_id(assignment_id)
    user, user_id = get_user()
    # Verify exists
    check_resource_exists(assignment, "Assignment", assignment_id)
    # Verify permissions
    if not user.is_grader(course_id):
        return "You are not a grader in this course."
    # Get data
    suas = Submission.by_assignment(assignment_id, course_id)
    data = {
        'assignment':
        assignment.encode_json(),
        'submissions': [{
            'user':
            u.encode_json(),
            'submission':
            sub.encode_json(),
            'history':
            Log.get_history(course_id, assignment_id, u.id),
            'reviews':
            sub.get_reviews()
        } for (sub, u, assign) in suas]
    }
    filename = assignment.get_filename() + '_submissions.json'
    return Response(json.dumps(data),
                    mimetype='application/json',
                    headers={
                        'Content-Disposition':
                        'attachment;filename={}'.format(filename)
                    })
Пример #4
0
def get_assignment(lti=lti):
    assignment_id = int(request.values.get('assignment_id'))
    assignment = Assignment.by_id(assignment_id)
    is_embedded = ('embed' == request.values.get('menu', "select"))
    # Verify exists
    check_resource_exists(assignment, "Assignment", assignment_id)
    # Perform action
    select_url = get_select_menu_link(assignment.id, assignment.title(),
                                      is_embedded, False)
    return jsonify(success=True,
                   redirect=url_for('assignments.load',
                                    assignment_id=assignment.id),
                   id=assignment.id,
                   name=assignment.name,
                   type=assignment.type,
                   instructions=strip_tags(assignment.instructions)[:255],
                   title=assignment.title(),
                   view=url_for('assignments.load',
                                assignment_id=assignment.id,
                                embed=is_embedded),
                   select=select_url,
                   edit=url_for('assignments.load',
                                assignment_id=assignment.id,
                                course_id=assignment.course_id),
                   date_modified=assignment.pretty_date_modified())
Пример #5
0
def load_assignment(lti=lti):
    # Get arguments
    assignment_id = int(request.values.get('assignment_id'))
    assignment = Assignment.by_id(assignment_id)
    course_id = get_course_id(True)
    user, user_id = get_user()
    # Verify exists
    check_resource_exists(assignment, "Assignment", assignment_id)
    # Verify permissions
    if course_id is None:
        editor_information = assignment.for_read_only_editor(user_id)
    else:
        editor_information = assignment.for_editor(user_id, course_id)
        browser_info = repr({
            'platform': request.user_agent.platform,
            'browser': request.user_agent.browser,
            'version': request.user_agent.version,
            'language': request.user_agent.language,
            'user_agent': request.user_agent.string
        })
        # Log the event
        if user is not None:
            make_log_entry(assignment_id,
                           assignment.version,
                           course_id,
                           user_id,
                           'Session.Start',
                           message=browser_info)
    # Verify passcode, if necessary
    if assignment.passcode_fails(request.values.get('passcode')):
        return ajax_failure("Passcode {!r} rejected".format(
            request.values.get("passcode")))
    return ajax_success(editor_information)
Пример #6
0
def watch():
    assignment_list = request.values.get('assignments', '')
    assignments = [int(aid) for aid in assignment_list.split(',') if len(aid) > 0]
    course_id = request.values.get('course_id', g.course.id if 'course' in g else None)
    if course_id == None or course_id == "":
        return ajax_failure("No Course ID given!")
    if g.user is None or not g.user.is_instructor(int(course_id)):
        return ajax_failure("You are not an instructor in this assignments' course.")
    update = request.values.get('update', 'false') == "true"
    if update:
        data = []
        for aid in assignments:
            submissions = Submission.by_assignment(aid, int(course_id))
            completions = sum([int(sua[0].correct) for sua in submissions])
            workings = Submission.get_latest(aid, int(course_id))
            histories = [process_history([h['time'] for h in sua[0].get_history()])
                         for sua in submissions]
            touches = [int(sua[0].version) for sua in submissions]
            feedbacks = [l[0] for l in Log.calculate_feedbacks(aid, course_id)]
            data.append({'id': aid,
                         'Completions': completions,
                         'Workings': workings,
                         'Time': histories,
                         'Touches': touches,
                         'Feedbacks': feedbacks})
        return jsonify(success=True, data=data)
    else:
        assignments = [Assignment.by_id(aid) for aid in assignments]
        return render_template('blockpy/watch.html', course_id=course_id, assignments=assignments,
                               assignment_list=assignment_list)
Пример #7
0
def load_assignment(lti=lti):
    # Get arguments
    assignment_id = int(request.values.get('assignment_id'))
    assignment = Assignment.by_id(assignment_id)
    student_id = maybe_int(request.values.get('user_id'))
    course_id = get_course_id(True)
    user, user_id = get_user()
    force_download = maybe_bool(request.values.get('force_download', "false"))
    # Verify exists
    check_resource_exists(assignment, "Assignment", assignment_id)
    # Verify permissions
    if user_id != student_id and not user.is_grader(course_id):
        return ajax_failure(
            "Only graders can see submissions for other people.")
    if course_id is None:
        editor_information = assignment.for_read_only_editor(student_id)
    else:
        editor_information = assignment.for_editor(student_id, course_id)
        browser_info = json.dumps({
            'platform': request.user_agent.platform,
            'browser': request.user_agent.browser,
            'version': request.user_agent.version,
            'language': request.user_agent.language,
            'user_agent': request.user_agent.string
        })
        # Log the event
        if user is not None:
            if user_id != student_id:
                make_log_entry(assignment_id,
                               assignment.version,
                               course_id,
                               user_id,
                               'X-Submission.Get',
                               message=str(student_id))
            else:
                make_log_entry(assignment_id,
                               assignment.version,
                               course_id,
                               user_id,
                               'Session.Start',
                               message=browser_info)
    # Verify passcode, if necessary
    if assignment.passcode_fails(request.values.get('passcode')):
        return ajax_failure("Passcode {!r} rejected".format(
            request.values.get("passcode")))
    if force_download:
        student_filename = User.by_id(student_id).get_filename("")
        filename = assignment.get_filename(
            "") + "_" + student_filename + '_submission.json'
        return Response(json.dumps(editor_information),
                        mimetype='application/json',
                        headers={
                            'Content-Disposition':
                            'attachment;filename={}'.format(filename)
                        })
    else:
        return ajax_success(editor_information)
Пример #8
0
def remove_assignment(lti=None):
    assignment_id = int(request.values.get('assignment_id'))
    assignment = Assignment.by_id(assignment_id)
    # Verify exists
    check_resource_exists(assignment, "Assignment", assignment_id)
    # Verify permissions
    require_course_instructor(g.user, assignment.course_id)
    Assignment.remove(assignment.id)
    return jsonify(success=True)
Пример #9
0
def move_course(lti=None):
    assignment_id = int(request.values.get('assignment_id'))
    new_course_id = int(request.values.get('new_course_id'))
    assignment = Assignment.by_id(int(assignment_id))
    # Verify exists
    check_resource_exists(assignment, "Assignment", assignment_id)
    # Verify permissions
    require_course_instructor(g.user, assignment.course_id)
    require_course_instructor(g.user, new_course_id)
    # Perform action
    assignment.move_course(new_course_id)
    return jsonify(success=True)
Пример #10
0
def load_assignment_give_feedback():
    '''
    Very random function necessary for syncing with JN - we need to expose the 'on_run'
    field from assignments in public courses.

    TODO: Do this for public courses only, not just private ones

    :return:
    '''
    assignment_id = request.values.get('assignment_id', None)
    if assignment_id is None:
        return ajax_failure("No Assignment ID given!")
    assignment = Assignment.by_id(assignment_id)
    return jsonify(success=True, give_feedback=assignment.on_run)
Пример #11
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 this file
    assignments = []
    for assignment_id in assignment_ids.split(","):
        if not assignment_id.isdigit():
            return ajax_failure(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))
Пример #12
0
 def update_submission(self, score, correct):
     was_changed = self.score != score or self.correct != correct
     self.score = int(round(100 * score))
     self.correct = correct
     assignment = Assignment.by_id(self.assignment_id)
     if assignment.reviewed:
         self.submission_status = SubmissionStatuses.IN_PROGRESS
         self.grading_status = GradingStatuses.NOT_READY
     elif self.correct:
         self.submission_status = SubmissionStatuses.COMPLETED
         self.grading_status = GradingStatuses.FULLY_GRADED
     else:
         self.submission_status = SubmissionStatuses.SUBMITTED
         self.grading_status = GradingStatuses.PENDING
     db.session.commit()
     return was_changed
 def encode_json(self):
     group = AssignmentGroup.by_id(self.assignment_group_id)
     group_url = group.url if group else None
     assignment = Assignment.by_id(self.assignment_id)
     assignment_url = assignment.url if assignment else None
     return {
         '_schema_version': 1,
         'assignment_group_id': self.assignment_group_id,
         'assignment_group_url': group_url,
         'assignment_id': self.assignment_id,
         'assignment_url': assignment_url,
         'position': self.position,
         'id': self.id,
         'date_modified': datetime_to_string(self.date_modified),
         'date_created': datetime_to_string(self.date_created)
     }
Пример #14
0
def export():
    assignment_id = int(request.values.get('assignment_id'))
    assignment = Assignment.by_id(assignment_id)
    course_id = get_course_id(True)
    user, user_id = get_user()
    # Verify exists
    check_resource_exists(assignment, "Assignment", assignment_id)
    # Verify permissions
    bundle = export_bundle(assignments=[assignment])
    filename = assignment.get_filename()
    return Response(json.dumps(bundle),
                    mimetype='application/json',
                    headers={
                        'Content-Disposition':
                        'attachment;filename={}'.format(filename)
                    })
Пример #15
0
def load_editor(lti, editor_information):
    assignment = Assignment.by_id(editor_information['current_assignment_id'])
    position = editor_information['assignments'].index(assignment)
    if position is None:
        return "No assignment found for this user/course/assignment (maze game):" + repr(
            editor_information)
    if not editor_information['submissions']:
        return "No submission found for this user/course/assignment (maze game):" + repr(
            editor_information)

    return render_template(
        'maze/maze.html',
        ip=request.remote_addr,
        level=assignment.name,
        submission=editor_information['submissions'][position],
        assignment=assignment,
        **editor_information)
Пример #16
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")
Пример #17
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)
Пример #18
0
def move_membership(lti=None):
    # Get arguments
    assignment_id = int(request.values.get('assignment_id'))
    old_group_id = int(request.values.get('old_group_id'))
    new_group_id = int(request.values.get('new_group_id'))
    assignment = Assignment.by_id(assignment_id)
    # Verify exists
    check_resource_exists(assignment, "Assignment", assignment_id)
    # Verify permissions
    require_course_instructor(g.user, assignment.course_id)

    # Verify permissions
    if new_group_id != -1:
        new_assignment_group = AssignmentGroup.by_id(new_group_id)
        require_course_instructor(g.user, new_assignment_group.course_id)
    if old_group_id != -1:
        old_assignment_group = AssignmentGroup.by_id(old_group_id)
        require_course_instructor(g.user, old_assignment_group.course_id)
    # Perform action
    AssignmentGroupMembership.move_assignment(assignment_id, new_group_id)
    # Result
    return jsonify(success=True)
Пример #19
0
def parse_assignment_load():
    # Lookup Code
    assignment_group_id = parse_lookup_code()
    # Assignment Group ID
    if assignment_group_id is None:
        assignment_group_id = maybe_int(
            request.args.get('assignment_group_id'))
    # Exact "url" code for group
    if assignment_group_id is None:
        assignment_group_id = AssignmentGroup.id_by_url(
            request.args.get('assignment_group_url'))
    # Assignment ID
    current_assignment_id = maybe_int(request.args.get('assignment_id'))
    # Exact "url" code for assignment
    if current_assignment_id is None:
        current_assignment_id = Assignment.id_by_url(
            request.args.get('assignment_url'))
    # User
    user = g.get('user', None)
    user_id = user.id if user else None
    # Course ID of the user
    course_id = maybe_int(request.args.get('course_id', None))
    if course_id is None:
        course_id = int(g.course.id) if 'course' in g and g.course else None
    # LTI submission URL
    new_submission_url = request.form.get('lis_result_sourcedid', None)
    # Embedded?
    embed = request.values.get('embed', 'false').lower() == 'true'
    # Get group
    assignment_group = AssignmentGroup.by_id(assignment_group_id)
    # Get assignments
    if assignment_group is None:
        assignment = Assignment.by_id(current_assignment_id)
        if assignment:
            assignments = [assignment]
        else:
            assignments = []
    else:
        assignments = assignment_group.get_assignments()
    # Potentially adjust assignment_id
    if current_assignment_id is None and assignments:
        current_assignment_id = assignments[0].id
    # Get submissions
    if user_id is None or course_id is None:
        submissions = []
    else:
        submissions = [
            assignment.load_or_new_submission(user_id, course_id,
                                              new_submission_url,
                                              assignment_group_id)
            for assignment in assignments
        ]
    # Determine the users' role in relation to this information
    role = user.determine_role(assignments,
                               submissions) if user else "anonymous"
    if role in ("student", "anonymous"):
        # Check for any IP locked assignments
        for assignment in assignments:
            if not assignment.is_allowed(request.remote_addr):
                return abort(
                    403,
                    "You cannot access this assignment from your current location: "
                    + request.remote_addr)
    # Check passcode
    passcode_protected = False
    for assignment in assignments:
        if assignment.has_passcode() and not passcode_protected:
            passcode_protected = True
    # Combine the submissions and assignments
    group = list(zip(assignments, submissions))
    # Okay we've got everything
    return dict(group=group,
                assignment_group=assignment_group,
                assignments=assignments,
                submissions=submissions,
                assignment_group_id=assignment_group_id,
                current_assignment_id=current_assignment_id,
                user=user,
                user_id=user_id,
                role=role,
                course_id=course_id,
                embed=embed,
                passcode_protected=passcode_protected)