示例#1
0
def viewEurobook(cid, instr):
    '''
  Function Type: View Function
  Template: common/eurobook.html
  Purpose: Display all of the grades for this course. Allow for creation of
  arbitrary submission entries.

  Inputs:
    cid: The object ID of the course to display

  Template Parameters: TODO

  Forms Handled: TODO
  '''
    try:
        c = Course.objects.get(id=cid)
        if instr and not c in current_user.courseInstructor:
            abort(403)
        elif not instr and not c in current_user.gradingCourses():
            abort(403)

        #Get the users for this course
        s = User.objects.filter(courseStudent=c)

        s = list(s)
        s.sort(key=lambda x: x.username)
        uids = [str(u.id) for u in s]

        return render_template('common/eurobook.html', course=c, uids=uids,\
                          instructor=instr)
    except Course.DoesNotExist:
        abort(404)
def viewEurobook(cid, instr):
  '''
  Function Type: View Function
  Template: common/eurobook.html
  Purpose: Display all of the grades for this course. Allow for creation of
  arbitrary submission entries.

  Inputs:
    cid: The object ID of the course to display

  Template Parameters: TODO

  Forms Handled: TODO
  '''
  try:
    c = Course.objects.get(id=cid)
    if instr and not c in current_user.courseInstructor:
      abort(403)
    elif not instr and not c in current_user.gradingCourses():
      abort(403)

    #Get the users for this course
    s = User.objects.filter(courseStudent=c)

    s = list(s)
    s.sort(key=lambda x:x.username)
    uids = [str(u.id) for u in s]

    return render_template('common/eurobook.html', course=c, uids=uids,\
                      instructor=instr)
  except Course.DoesNotExist:
    abort(404)
示例#3
0
def editAuxillaryGrades(cid, instr, col):
  '''
  Function Type: View Function
  Template: instructor/editcolumn.html
  Purpose: Allows the grutor to edit one column of the gradebook manually

  Inputs:
    cid: The object ID of the course to authenticate the grader
    col: The object ID of the column to be edited

  Template Parameters: TODO
  '''
  try:
    course = Course.objects.get(id=cid)
    column = GBColumn.objects.get(id=col)

    if instr and not course in current_user.courseInstructor:
      abort(403)
    elif not instr and not course in current_user.gradingCourses():
      abort(403)

    users = User.objects.filter(courseStudent=course)

    for u in users:
      if not u.keyOfUsername() in column.scores:
        grade = GBGrade()
        grade.scores['score'] = 0
        grade.save()
        column.scores[u.keyOfUsername()] = grade

    column.save()

    return render_template("common/auxillaryGrades.html", course = course, col=column, users=users, instructor=instr)
  except (Course.DoesNotExist, GBColumn.DoesNotExist):
    abort(404)
示例#4
0
def grutorGradelistProblem(pid):
    '''
  Function Type: View Function
  Template: grutor/problems.html
  Purpose: Display all of the student submissions for the problem specified by
  <pid>.

  Inputs:
    pid: A problem object ID

  Template Parameters:
    course: The course which contains the problem specified by <pid>
    assignment: The assignment group containing the problem specified by <pid>
    problem: The problem specified by <pid>
    users: A list of the students who are enrolled in <course>

  Forms handled: None
  '''
    try:
        p = Problem.objects.get(id=pid)
        c, a = p.getParents()
        #For security purposes we send anyone who isnt in this class to the index
        if not (c in current_user.gradingCourses()):
            abort(403)

        #Get the students for this course
        students = User.objects.filter(courseStudent=c)

        return render_template("grutor/problems.html", \
                                course=c, problem=p, assignment=a, users=students)
    except Course.DoesNotExist as e:
        abort(404)
def grutorGradelistProblem(pid):
  '''
  Function Type: View Function
  Template: grutor/problems.html
  Purpose: Display all of the student submissions for the problem specified by
  <pid>.

  Inputs:
    pid: A problem object ID

  Template Parameters:
    course: The course which contains the problem specified by <pid>
    assignment: The assignment group containing the problem specified by <pid>
    problem: The problem specified by <pid>
    users: A list of the students who are enrolled in <course>

  Forms handled: None
  '''
  try:
    p = Problem.objects.get(id=pid)
    c,a = p.getParents()
    #For security purposes we send anyone who isnt in this class to the index
    if not ( c in current_user.gradingCourses()):
      abort(403)

    #Get the students for this course
    students = User.objects.filter(courseStudent=c)

    return render_template("grutor/problems.html", \
                            course=c, problem=p, assignment=a, users=students)
  except Course.DoesNotExist as e:
    abort(404)
示例#6
0
def studentGetFiles(pid, uid, subnum):
  try:
    problem = Problem.objects.get(id=pid)
    c, a = problem.getParents()
    if not (c in current_user.courseStudent or c in current_user.gradingCourses()):
      abort(403)

    u = User.objects.get(id=uid)
    s = problem.getSubmission(u, subnum)

    content = request.get_json()

    filepath = getSubmissionPath(c, a, problem, u, subnum)
    filepath = os.path.join(filepath, content['filename'])

    import magic

    fileType = magic.from_file(filepath, mime=True)
    fileType = fileType.split('/')

    if fileType[0] == 'text':
      try:
        f = codecs.open(filepath, encoding='utf-8', errors='ignore')
        content = f.read()
        return jsonify(majorType=fileType[0], minorType=fileType[1], content=content)
      except Exception as e:
        return jsonify(majorType=fileType[0], minorType=fileType[1], content=str(e))
        pass
      finally:
        f.close()
    else:
      return jsonify(majorType=fileType[0], minorType=fileType[1],\
       url=url_for('serveFiles', pid=pid, uid=uid, subnum=subnum, filename=content['filename']))
  except Problem.DoesNotExist:
    abort(404)
def editAuxillaryGrades(cid, instr, col):
  '''
  Function Type: View Function
  Template: instructor/editcolumn.html
  Purpose: Allows the grutor to edit one column of the gradebook manually

  Inputs:
    cid: The object ID of the course to authenticate the grader
    col: The object ID of the column to be edited

  Template Parameters: TODO
  '''
  try:
    course = Course.objects.get(id=cid)
    column = GBColumn.objects.get(id=col)

    if instr and not course in current_user.courseInstructor:
      abort(403)
    elif not instr and not course in current_user.gradingCourses():
      abort(403)

    users = User.objects.filter(courseStudent=course)

    for u in users:
      if not u.keyOfUsername() in column.scores:
        grade = GBGrade()
        grade.scores['score'] = 0
        grade.save()
        column.scores[u.keyOfUsername()] = grade

    column.save()

    return render_template("common/auxillaryGrades.html", course = course, col=column, users=users, instructor=instr)
  except (Course.DoesNotExist, GBColumn.DoesNotExist):
    abort(404)
示例#8
0
def serveFiles(pid, uid, subnum, filename):
  '''
  Function Type: Callback-Download
  Purpose: Downloads the file specified for the user.

  Inputs:
    pid: The object ID of the problem that the file belongs to
    uid: The object ID of the user the file belongs to
    subnum: The submission number that the file belongs to
    filename: The filename from the submission to download
  '''
  try:
    p = Problem.objects.get(id=pid)
    c,a = p.getParents()
    #For security purposes we send anyone who isnt in this class to the index
    if not ( c in current_user.courseStudent or c in current_user.gradingCourses()):
      abort(403)

    u = User.objects.get(id=uid)

    s = p.getSubmission(u, subnum)

    filepath = getSubmissionPath(c, a, p, u, subnum)

    return send_file(os.path.join(filepath, filename))
  except (Problem.DoesNotExist, Course.DoesNotExist, AssignmentGroup.DoesNotExist):
    #If either p can't be found or we can't get its parents then 404
    abort(404)
示例#9
0
def grutorSaveGrades(pid, uid, subnum):
    '''
  Function Type: Callback-AJAX Function
  Called By: grutor/gradesubmission.html:saveGrades()
  Purpose: Recieves a list of grades from the page and puts them into the grade
  for this submission.

  Inputs:
    pid: The problem that this grade is for
    uid: The user whose grade this is
    subnum: The submission number that is currently being graded

  POST Values: A dictionary mapping names of rubric sections to numbers.

  Outputs:
    res: The result. True if it succeeded, False if it failed, and a string
    if there was an exception.
  '''
    try:
        p = Problem.objects.get(id=pid)
        c, a = p.getParents()

        #For security purposes we send anyone who isnt in this class to the index
        if not (c in current_user.gradingCourses()):
            return jsonify(res=False)

        #Try to get the contents
        content = request.get_json()

        #make sure we got the contents
        if content == None:
            return jsonify(res=False)

        #Define function for applying scores to a submission
        def score(sub):
            for section in content:
                sub.grade.scores[section] = content[section]

            sub.grade.save()
            sub.save()

        #End definition

        #Before we change anything make sure all changes can go through
        checkMounted()

        user = User.objects.get(id=uid)
        sub = p.getSubmission(user, subnum)

        score(sub)
        grutorSubArchive(p, c, a, user, sub)
        if sub.partner != None:
            score(sub.partnerSubmission)
            grutorSubArchive(p, c, a, sub.partner, sub.partnerSubmission)

        return jsonify(res=True, type="grades")
    except Exception as e:
        return jsonify(res=False, error=str(e))
def grutorSaveGrades(pid, uid, subnum):
  '''
  Function Type: Callback-AJAX Function
  Called By: grutor/gradesubmission.html:saveGrades()
  Purpose: Recieves a list of grades from the page and puts them into the grade
  for this submission.

  Inputs:
    pid: The problem that this grade is for
    uid: The user whose grade this is
    subnum: The submission number that is currently being graded

  POST Values: A dictionary mapping names of rubric sections to numbers.

  Outputs:
    res: The result. True if it succeeded, False if it failed, and a string
    if there was an exception.
  '''
  try:
    p = Problem.objects.get(id=pid)
    c,a = p.getParents()

    #For security purposes we send anyone who isnt in this class to the index
    if not ( c in current_user.gradingCourses()):
      return jsonify(res=False)

    #Try to get the contents
    content = request.get_json()

    #make sure we got the contents
    if content == None:
      return jsonify(res=False)

    #Define function for applying scores to a submission
    def score(sub):
      for section in content:
        sub.grade.scores[section] = content[section]

      sub.grade.save()
      sub.save()
    #End definition

    #Before we change anything make sure all changes can go through
    checkMounted()

    user = User.objects.get(id=uid)
    sub = p.getSubmission(user, subnum)

    score(sub)
    grutorSubArchive(p, c, a, user, sub)
    if sub.partner != None:
      score(sub.partnerSubmission)
      grutorSubArchive(p, c, a, sub.partner, sub.partnerSubmission)

    return jsonify(res=True, type="grades")
  except Exception as e:
    return jsonify(res=False, error=str(e))
示例#11
0
def grutorGetStatus_Problems(pid):
  try:
    p = Problem.objects.get(id=pid)
    c,a = p.getParents()

    if not (c in current_user.gradingCourses()):
      abort(403)

    u, i, d = p.getStatusCount()
    return jsonify(u=u, i=i, d=d)
  except Problem.DoesNotExist:
    abort(404)
示例#12
0
def grutorGetStatus_Problems(pid):
    try:
        p = Problem.objects.get(id=pid)
        c, a = p.getParents()

        if not (c in current_user.gradingCourses()):
            abort(403)

        u, i, d = p.getStatusCount()
        return jsonify(u=u, i=i, d=d)
    except Problem.DoesNotExist:
        abort(404)
示例#13
0
def studentViewFiles(pid, uid, subnum):
  try:
    problem = Problem.objects.get(id=pid)
    c, a = problem.getParents()
    if not (c in current_user.courseStudent or c in current_user.gradingCourses()):
      abort(403)

    u = User.objects.get(id=uid)
    return render_template('student/reviewfiles.html', problem=problem, subnum=subnum,\
                           user=u, course=c, assignment=a)
  except Problem.DoesNotExist:
    abort(404)
示例#14
0
def grutorGetStatus_Assignments(pid):
  try:
    p = Problem.objects.get(id=pid)
    c,a = p.getParents()

    if not (c in current_user.gradingCourses()):
      abort(403)

    if c.name != "CS5G":
      u, i, d = p.getStatusCount()
      return jsonify(u=u, i=i, d=d)
    # Special case to avoid calculations for CS5G
    else:
      return jsonify(u=0, i=0, d=0)
  except Problem.DoesNotExist:
    abort(404)
示例#15
0
def grutorGetStatus_Assignments(pid):
    try:
        p = Problem.objects.get(id=pid)
        c, a = p.getParents()

        if not (c in current_user.gradingCourses()):
            abort(403)

        if c.name != "CS5G":
            u, i, d = p.getStatusCount()
            return jsonify(u=u, i=i, d=d)
        # Special case to avoid calculations for CS5G
        else:
            return jsonify(u=0, i=0, d=0)
    except Problem.DoesNotExist:
        abort(404)
示例#16
0
def commonRenderEuros(cid, instr):
    try:
        content = request.get_json()
        c = Course.objects.get(id=cid)
        u = User.objects.get(id=content['uid'])

        #If we are accessing the instructor version check that they are an instr
        if instr and not c in current_user.courseInstructor:
            abort(403)

        if not c in current_user.gradingCourses():
            abort(403)

        euroCount, lateAssignments = c.getEuroCountAndLateAssignmentsList(u)

        # Username
        outString = "<tr>"
        outString += "<td>"
        if instr:
            outString += u.username
            if c.anonymousGrading:
                outString += " (" + c.getIdentifier(u.keyOfUsername()) + ")"
        else:
            if c.anonymousGrading:
                outString += c.getIdentifier(u.keyOfUsername())
            else:
                outString += u.username
        outString += "</td>"

        # Total euros used
        outString += "<td>%d</td>" % (euroCount)

        # Summary by assignment
        for a in c.assignments:
            if a in lateAssignments:
                outString += "<td style='text-align:center' class='danger'><span class='octicon octicon-check'></span></td>"
            else:
                outString += "<td></td>"

        # Close the row
        outString += "</tr>"

        return jsonify(res=outString)

    except (Course.DoesNotExist, User.DoesNotExist):
        abort(404)
示例#17
0
def commonRenderEuros(cid, instr):
  try:
    content = request.get_json()
    c = Course.objects.get(id=cid)
    u = User.objects.get(id=content['uid'])

    #If we are accessing the instructor version check that they are an instr
    if instr and not c in current_user.courseInstructor:
      abort(403)

    if not c in current_user.gradingCourses():
      abort(403)

    euroCount, lateAssignments = c.getEuroCountAndLateAssignmentsList(u)

    # Username
    outString = "<tr>"
    outString += "<td>"
    if instr:
      outString += u.username
      if c.anonymousGrading:
        outString += " (" + c.getIdentifier(u.keyOfUsername()) + ")"
    else:
      if c.anonymousGrading:
        outString += c.getIdentifier(u.keyOfUsername())
      else:
        outString += u.username
    outString += "</td>"

    # Total euros used
    outString += "<td>%d</td>" % (euroCount)

    # Summary by assignment
    for a in c.assignments:
      if a in lateAssignments:
        outString += "<td style='text-align:center' class='danger'><span class='octicon octicon-check'></span></td>"
      else:
        outString += "<td></td>"

    # Close the row
    outString += "</tr>"

    return jsonify(res=outString)

  except (Course.DoesNotExist,User.DoesNotExist):
    abort(404)
示例#18
0
def grutorReleaseSubmission(pid, uid, subnum):
    '''
  Function Type: Callback-Redirect Function
  Purpose: Put the submission back so that it may be chosen by another
  grader.

  Inputs:
    pid: The object ID of the problem this submission belongs to
    uid: The object ID of the user this submission belongs to
    subnum: The submission number for this submission

  Forms Handled: None
  '''
    try:
        p = Problem.objects.get(id=pid)
        c, a = p.getParents()
        user = User.objects.get(id=uid)

        #For security purposes we send anyone who isnt in this class to the index
        if not (c in current_user.gradingCourses()):
            abort(403)

        #Define function for releasing submissions
        def release(sub):
            sub.status = SUBMISSION_TESTED
            sub.gradedBy = None
            sub.grade.save()
            sub.save()

        #End definition

        submission = p.getSubmission(user, subnum)
        #if not submission.status == 4:
        release(submission)

        if submission.partner != None:
            release(submission.partnerSubmission)

        p.save()

        return redirect(url_for('grutorGradelistProblem', pid=pid))
    except (Problem.DoesNotExist, Course.DoesNotExist,
            AssignmentGroup.DoesNotExist):
        #If either p can't be found or we can't get its parents then 404
        abort(404)
示例#19
0
def grutorFinishSubmission(pid, uid, subnum):
    '''
  Function Type: Callback-Redirect Function
  Purpose: Save all the changes to a given submission and return to the
  list of problems.

  Inputs:
    pid: The object ID of the problem this submission belongs to
    uid: The object ID of the user this submission belongs to
    subnum: The submission number for this submission

  Forms Handled: None
  '''
    try:
        p = Problem.objects.get(id=pid)
        c, a = p.getParents()
        user = User.objects.get(id=uid)

        #For security purposes we send anyone who isnt in this class to the index
        if not (c in current_user.gradingCourses()):
            abort(403)

        #Define a function for performing closing operations
        def finish(sub):
            sub.status = SUBMISSION_GRADED
            sub.gradedBy = User.objects.get(id=g.user.id)
            sub.save()

        #End definition

        submission = p.getSubmission(user, subnum)
        finish(submission)

        #Handle the partners submission as well
        if submission.partner != None:
            finish(submission.partnerSubmission)

        p.save()

        return redirect(url_for('grutorGradelistProblem', pid=pid))
    except (Problem.DoesNotExist, Course.DoesNotExist,
            AssignmentGroup.DoesNotExist):
        #If either p can't be found or we can't get its parents then 404
        abort(404)
示例#20
0
def viewGradebook(cid, instr):
  '''
  Function Type: View Function
  Template: instructor/gradebook.html
  Purpose: Display all of the grades for this course. Allow for creation of
  arbitrary submission entries.

  Inputs:
    cid: The object ID of the course to display

  Template Parameters: TODO

  Forms Handled: TODO
  '''
  try:
    c = Course.objects.get(id=cid)
    if instr and not c in current_user.courseInstructor:
      abort(403)
    elif not instr and not c in current_user.gradingCourses():
      abort(403)

    #Get the users for this course
    s = User.objects.filter(courseStudent=c)


    disableColForm = False
    colForm = CreateGradeColumnForm()
    colForm.group.choices = [(x.id,x.name) for x in c.gradeBook.auxillaryGrades]
    if len(colForm.group.choices) == 0:
      colForm.group.choices = [("N/A", "N/A")]
      disableColForm = True


    s = list(s)
    s.sort(key=lambda x:x.username)
    uids = [str(u.id) for u in s]

    return render_template('common/gradebook.html', course=c, uids=uids,\
                      groupForm=CreateGradebookGroupForm(),\
                      colForm=colForm, disableColForm=disableColForm,\
                      instructor=instr)
  except Course.DoesNotExist:
    abort(404)
def grutorReleaseSubmission(pid, uid, subnum):
  '''
  Function Type: Callback-Redirect Function
  Purpose: Put the submission back so that it may be chosen by another
  grader.

  Inputs:
    pid: The object ID of the problem this submission belongs to
    uid: The object ID of the user this submission belongs to
    subnum: The submission number for this submission

  Forms Handled: None
  '''
  try:
    p = Problem.objects.get(id=pid)
    c,a = p.getParents()
    user = User.objects.get(id=uid)

    #For security purposes we send anyone who isnt in this class to the index
    if not ( c in current_user.gradingCourses()):
      abort(403)

    #Define function for releasing submissions
    def release(sub):
      sub.status = SUBMISSION_TESTED
      sub.gradedBy = None
      sub.grade.save()
      sub.save()
    #End definition

    submission = p.getSubmission(user, subnum)
    #if not submission.status == 4:
    release(submission)

    if submission.partner != None:
      release(submission.partnerSubmission)

    p.save()

    return redirect(url_for('grutorGradelistProblem', pid=pid))
  except (Problem.DoesNotExist, Course.DoesNotExist, AssignmentGroup.DoesNotExist):
    #If either p can't be found or we can't get its parents then 404
    abort(404)
def viewGradebook(cid, instr):
  '''
  Function Type: View Function
  Template: instructor/gradebook.html
  Purpose: Display all of the grades for this course. Allow for creation of
  arbitrary submission entries.

  Inputs:
    cid: The object ID of the course to display

  Template Parameters: TODO

  Forms Handled: TODO
  '''
  try:
    c = Course.objects.get(id=cid)
    if instr and not c in current_user.courseInstructor:
      abort(403)
    elif not instr and not c in current_user.gradingCourses():
      abort(403)

    #Get the users for this course
    s = User.objects.filter(courseStudent=c)


    disableColForm = False
    colForm = CreateGradeColumnForm()
    colForm.group.choices = [(x.id,x.name) for x in c.gradeBook.auxillaryGrades]
    if len(colForm.group.choices) == 0:
      colForm.group.choices = [("N/A", "N/A")]
      disableColForm = True


    s = list(s)
    s.sort(key=lambda x:x.username)
    uids = [str(u.id) for u in s]

    return render_template('common/gradebook.html', course=c, uids=uids,\
                      groupForm=CreateGradebookGroupForm(),\
                      colForm=colForm, disableColForm=disableColForm,\
                      instructor=instr)
  except Course.DoesNotExist:
    abort(404)
示例#23
0
def grutorToggleLate(pid, uid, subnum):
    '''
  Function Type: Callback-Redirect Function
  Purpose: Toggle the isLate flag for an assignment

  Inputs:
    pid: The object ID of the problem this submission belongs to
    uid: The object ID of the user this submission belongs to
    subnum: The submission number for this submission

  Forms Handled: None
  '''
    try:
        p = Problem.objects.get(id=pid)
        c, a = p.getParents()
        user = User.objects.get(id=uid)

        #For security purposes we send anyone who isnt in this class to the index
        if not (c in current_user.gradingCourses()):
            return jsonify(res=False)

        #Define function for releasing submissions
        def toggle(sub):
            sub.isLate = not sub.isLate
            sub.save()

        #End definition

        submission = p.getSubmission(user, subnum)
        #if not submission.status == 4:
        toggle(submission)

        if submission.partner != None:
            toggle(submission.partnerSubmission)

        p.save()

        return jsonify(res=True)
    except (Problem.DoesNotExist, Course.DoesNotExist,
            AssignmentGroup.DoesNotExist):
        pass
    return jsonify(res=False)
def grutorFinishSubmission(pid, uid, subnum):
  '''
  Function Type: Callback-Redirect Function
  Purpose: Save all the changes to a given submission and return to the
  list of problems.

  Inputs:
    pid: The object ID of the problem this submission belongs to
    uid: The object ID of the user this submission belongs to
    subnum: The submission number for this submission

  Forms Handled: None
  '''
  try:
    p = Problem.objects.get(id=pid)
    c,a = p.getParents()
    user = User.objects.get(id=uid)

    #For security purposes we send anyone who isnt in this class to the index
    if not ( c in current_user.gradingCourses()):
      abort(403)

    #Define a function for performing closing operations
    def finish(sub):
      sub.status = SUBMISSION_GRADED
      sub.gradedBy = User.objects.get(id=g.user.id)
      sub.save()
    #End definition

    submission = p.getSubmission(user, subnum)
    finish(submission)

    #Handle the partners submission as well
    if submission.partner != None:
      finish(submission.partnerSubmission)

    p.save()

    return redirect(url_for('grutorGradelistProblem', pid=pid))
  except (Problem.DoesNotExist, Course.DoesNotExist, AssignmentGroup.DoesNotExist):
    #If either p can't be found or we can't get its parents then 404
    abort(404)
def grutorToggleLate(pid, uid, subnum):
  '''
  Function Type: Callback-Redirect Function
  Purpose: Toggle the isLate flag for an assignment

  Inputs:
    pid: The object ID of the problem this submission belongs to
    uid: The object ID of the user this submission belongs to
    subnum: The submission number for this submission

  Forms Handled: None
  '''
  try:
    p = Problem.objects.get(id=pid)
    c,a = p.getParents()
    user = User.objects.get(id=uid)

    #For security purposes we send anyone who isnt in this class to the index
    if not ( c in current_user.gradingCourses()):
      return jsonify(res=False)

    #Define function for releasing submissions
    def toggle(sub):
      sub.isLate = not sub.isLate
      sub.save()
    #End definition

    submission = p.getSubmission(user, subnum)
    #if not submission.status == 4:
    toggle(submission)

    if submission.partner != None:
      toggle(submission.partnerSubmission)

    p.save()

    return jsonify(res=True)
  except (Problem.DoesNotExist, Course.DoesNotExist, AssignmentGroup.DoesNotExist):
    pass
  return jsonify(res=False)
示例#26
0
def saveGradeColumn(cid,col):
  try:
    course = Course.objects.get(id=cid)
    column = GBColumn.objects.get(id=col)

    if not (course in current_user.gradingCourses() or current_user.isAdmin):
      return jsonify(res=False)

    content = request.get_json()

    column.maxScore = content['maxScore']

    for id in content['scores']:
      u = User.objects.get(id=id)
      column.scores[u.keyOfUsername()].scores['score'] = content['scores'][id]
      column.scores[u.keyOfUsername()].save()

    column.save()

    return jsonify(res=True)

  except Exception as e:
    return jsonify(res=False, exeption=str(e))
def saveGradeColumn(cid,col):
  try:
    course = Course.objects.get(id=cid)
    column = GBColumn.objects.get(id=col)

    if not (course in current_user.gradingCourses() or current_user.isAdmin):
      return jsonify(res=False)

    content = request.get_json()

    column.maxScore = content['maxScore']

    for id in content['scores']:
      u = User.objects.get(id=id)
      column.scores[u.keyOfUsername()].scores['score'] = content['scores'][id]
      column.scores[u.keyOfUsername()].save()

    column.save()

    return jsonify(res=True)

  except Exception as e:
    return jsonify(res=False, exeption=str(e))
示例#28
0
def grutorAssignments(cid):
  '''
  Function Type: View Function
  Template: grutor/assignments.html
  Purpose: Display all of the assignment groups and problems in those groups
  for the course specified by <cid>.

  Inputs:
    cid: A course object ID

  Template Parameters:
    course: The course object specified by <cid>

  Forms Handled: None
  '''
  try:
    c = Course.objects.get(id=cid)
    #For security purposes we send anyone who isnt grading this class to the index
    if not ( c in current_user.gradingCourses()):
      abort(403)

    return render_template("grutor/assignments.html", course=c)
  except Course.DoesNotExist as e:
    abort(404)
示例#29
0
def grutorSaveComment(pid, uid, subnum):
    '''
  Function Type: Callback-AJAX Function
  Called By: grutor/gradesubmission.html:saveComments()
  Purpose: Recieves a markdown formatted string and saves it as a grader
  comment for a specified submission

  Inputs:
    pid: The problem that this grade is for
    uid: The user whose grade this is
    subnum: The submission number that is currently being graded

  POST Values: A json object containing one field called "text" which contains
  the markdown formatted string

  Outputs:
    res: The result. True if it succeeded, False if it failed, and a string
    if there was an exception.
  '''
    try:
        p = Problem.objects.get(id=pid)
        c, a = p.getParents()

        #For security purposes we send anyone who isnt in this class to the index
        if not (c in current_user.gradingCourses()):
            return jsonify(res=False)

        #Try to get the contents
        content = request.get_json()

        #make sure we got the contents
        if content == None:
            return jsonify(res=False)

        #Define function for saving comments
        def comment(sub):
            sub.comments = content['text']
            sub.autoGraderComments = content['autotext']
            sub.save()

        user = User.objects.get(id=uid)
        sub = p.getSubmission(user, subnum)

        #Before we change anything make sure all changes can go through
        checkMounted()

        comment(sub)

        grutorSubArchive(p, c, a, user, sub)
        if sub.partner != None:
            comment(sub.partnerSubmission)
            grutorSubArchive(p, c, a, sub.partner, sub.partnerSubmission)

        #Save changes to the problem
        p.save(cascade=True)

        return jsonify(res=True, type="comments")
    except Exception as e:
        import traceback
        tb = traceback.format_exc()
        return jsonify(res=False, error=str(tb))
示例#30
0
def grutorGradeRandom(pid):
    '''
  Function Type: Callback-Redirect Function
  Purpose: Select an ungraded student submission and claim it for the current
  grader. If it selects a student without a submission one is created.

  Inputs:
    pid: The object ID of the problem that is being graded

  Forms Handled: None
  '''
    try:
        p = Problem.objects.get(id=pid)
        c, a = p.getParents()
        #For security we redirect anyone who shouldn't be here to the index
        if not (c in current_user.gradingCourses()):
            abort(403)

        #Shuffle the users in the course so we can get a random one
        courseUsers = list(User.objects.filter(courseStudent=c))
        random.shuffle(courseUsers)

        #For each user try to get a submission for them
        for key in p.studentSubmissions.keys():
            username = userFromKey(key)
            user = User.objects.get(username=username)

            #Get the pymongo collection for some atomic actions not provided by
            #the mongoengine wrapper
            subCol = Submission._get_collection()
            sub = p.getLatestSubmission(user)

            if sub == None:
                flash(
                    "Bad state for user %s. Please notify the administrator." %
                    (username), "error")
                continue

            if sub.partner == None:
                res = subCol.find_and_modify(query={'_id': sub.id, 'status':SUBMISSION_TESTED, 'isLatest':True}, \
                  update={'$set': {'status':SUBMISSION_GRADING, 'gradedBy': g.user.id}})
            else:
                otherSub = sub.partnerSubmission
                #We use total lock oerdering to prevent deadlock
                subList = sorted([sub, otherSub], key=lambda x: x.id)
                res = subCol.find_and_modify(query={'_id': subList[0].id, 'status':SUBMISSION_TESTED, 'isLatest':True}, \
                  update={'$set': {'status':SUBMISSION_GRADING, 'gradedBy': g.user.id}})
                #res = Submission.objects.exec_js(LOCK_QUERY, id=subList[0].id, uid=g.user.id)
                if res == None:
                    continue
                res = subCol.find_and_modify(query={'_id': subList[1].id, 'status':SUBMISSION_TESTED, 'isLatest':True}, \
                  update={'$set': {'status':SUBMISSION_GRADING, 'gradedBy': g.user.id}})
                #res = Submission.objects.exec_js(LOCK_QUERY, id=subList[1].id, uid=g.user.id)

            if not res == None:
                return redirect(
                    url_for("grutorGradeSubmission",
                            pid=pid,
                            uid=user.id,
                            subnum=p.getSubmissionNumber(user)))
        flash("All submissions have been claimed", "warning")
        flash(
            "Untested submissions or submissions that crashed the auto-grader are not considered by this button. Please look below for such submissions."
        )
        return redirect(url_for('grutorGradelistProblem', pid=pid))

    except (Problem.DoesNotExist, Course.DoesNotExist,
            AssignmentGroup.DoesNotExist):
        #If either p can't be found or we can't get its parents then 404
        abort(404)
    except User.DoesNotExist:
        #If the user doesn't exist we have a problem
        flash(
            """Successfully locked a submission but the user for that
    submission couldn't be found in the database. Please contact a system
    administrator to have them resolve this issue.""", "error")
        abort(404)
示例#31
0
def grutorMakeBlank(pid, uid):
    '''
  Function Type: Callback-Redirect Function
  Purpose: When a student does not have a submission for a given assignment this
  function is called. It creates a blank submission with no files and then
  redirects the grader to the grade submission page.

  Inputs:
    pid: The object ID for the problem that is being graded.
    uid: The object ID of the user who is being graded.

  Forms Handled: None
  '''
    try:
        p = Problem.objects.get(id=pid)
        c, a = p.getParents()
        user = User.objects.get(id=uid)

        #For security purposes we send anyone who isnt in this class to the index
        if not (c in current_user.gradingCourses()):
            abort(403)

        #Check that the user we are trying to create a submission for is in the class
        if not (c in user.courseStudent):
            flash(
                "The user you were trying to make a submission for is not in the course."
            )
            abort(404)

        #Create a blank submission
        #Create the grade
        grade = GBGrade()
        grade.save()
        p.gradeColumn.scores[user.keyOfUsername()] = grade

        p.studentSubmissions[user.keyOfUsername()] = StudentSubmissionList()

        #create a filepath
        filepath = getSubmissionPath(c, a, p, user, 1)

        sub = Submission()
        sub.problem = p
        #Initial fields for submission
        sub.filePath = filepath
        sub.grade = p.gradeColumn.scores[user.keyOfUsername()]
        sub.submissionTime = datetime.datetime.utcnow()
        sub.status = SUBMISSION_GRADING
        sub.gradedBy = User.objects.get(id=g.user.id)

        sub.save()
        p.studentSubmissions[user.keyOfUsername()].addSubmission(sub)

        #The grader is making this so it isn't late
        sub.isLate = False

        #Create the needed folders
        os.makedirs(filepath)

        p.save(cascade=True)
        return redirect(
            url_for('grutorGradeSubmission', uid=uid, pid=pid, subnum=1))
    except (Problem.DoesNotExist, Course.DoesNotExist,
            AssignmentGroup.DoesNotExist):
        #If either p can't be found or we can't get its parents then 404
        abort(404)
示例#32
0
def grutorGradeRandom(pid):
  '''
  Function Type: Callback-Redirect Function
  Purpose: Select an ungraded student submission and claim it for the current
  grader. If it selects a student without a submission one is created.

  Inputs:
    pid: The object ID of the problem that is being graded

  Forms Handled: None
  '''
  try:
    p = Problem.objects.get(id=pid)
    c,a = p.getParents()
    #For security we redirect anyone who shouldn't be here to the index
    if not (c in current_user.gradingCourses()):
      abort(403)

    #Shuffle the users in the course so we can get a random one
    courseUsers = list(User.objects.filter(courseStudent=c))
    random.shuffle(courseUsers)

    #For each user try to get a submission for them
    for key in p.studentSubmissions.keys():
      username = userFromKey(key)
      user = User.objects.get(username=username)

      #Get the pymongo collection for some atomic actions not provided by
      #the mongoengine wrapper
      subCol = Submission._get_collection()
      sub = p.getLatestSubmission(user)

      if sub == None:
        flash("Bad state for user %s. Please notify the administrator."%(username), "error")
        continue

      if sub.partner == None:
        res = subCol.find_and_modify(query={'_id': sub.id, 'status':SUBMISSION_TESTED, 'isLatest':True}, \
          update={'$set': {'status':SUBMISSION_GRADING, 'gradedBy': g.user.id}})
      else:
        otherSub = sub.partnerSubmission
        #We use total lock oerdering to prevent deadlock
        subList = sorted([sub, otherSub], key=lambda x: x.id)
        res = subCol.find_and_modify(query={'_id': subList[0].id, 'status':SUBMISSION_TESTED, 'isLatest':True}, \
          update={'$set': {'status':SUBMISSION_GRADING, 'gradedBy': g.user.id}})
        #res = Submission.objects.exec_js(LOCK_QUERY, id=subList[0].id, uid=g.user.id)
        if res == None:
          continue
        res = subCol.find_and_modify(query={'_id': subList[1].id, 'status':SUBMISSION_TESTED, 'isLatest':True}, \
          update={'$set': {'status':SUBMISSION_GRADING, 'gradedBy': g.user.id}})
        #res = Submission.objects.exec_js(LOCK_QUERY, id=subList[1].id, uid=g.user.id)

      if not res == None:
        return redirect(url_for("grutorGradeSubmission", pid=pid, uid=user.id, subnum=p.getSubmissionNumber(user)))
    flash("All submissions have been claimed", "warning")
    flash("Untested submissions or submissions that crashed the auto-grader are not considered by this button. Please look below for such submissions.")
    return redirect(url_for('grutorGradelistProblem', pid=pid))

  except (Problem.DoesNotExist, Course.DoesNotExist, AssignmentGroup.DoesNotExist):
    #If either p can't be found or we can't get its parents then 404
    abort(404)
  except User.DoesNotExist:
    #If the user doesn't exist we have a problem
    flash("""Successfully locked a submission but the user for that
    submission couldn't be found in the database. Please contact a system
    administrator to have them resolve this issue.""", "error")
    abort(404)
示例#33
0
def commonRenderGrade(cid, instr):
  try:
    content = request.get_json()
    c = Course.objects.get(id=cid)
    u = User.objects.get(id=content['uid'])

    #If we are accessing the instructor version check that they are an instr
    if instr and not c in current_user.courseInstructor:
      abort(403)

    if not c in current_user.gradingCourses():
      abort(403)

    assignmentScores = getStudentAssignmentScores(c, u)

    userCourseScore = 0

    outString = "<tr>"
    # <td>{{username/identifier}}</td>
    outString += "<td>"
    if instr:
      outString += u.username
      if c.anonymousGrading:
        outString += " (" + c.getIdentifier(u.keyOfUsername()) + ")"
    else:
      if c.anonymousGrading:
        outString += c.getIdentifier(u.keyOfUsername())
      else:
        outString += u.username
    outString += "</td>"
    # <td>{{link to problem grading}}</td>
    for assignment, a in zip(assignmentScores, c.assignments):
      #If this assignment doesn't have any problems we put a blank column in
      if len(assignment) == 0:
        outString += "<td class='active'></td>"
        continue

      for problem, p in zip(assignment, a.problems):
        if problem == None:
          #If there was no submission link to the make blank page
          outString += "<td class='active'><a href='"
          outString += "#'" #TODO Replace this with an actual link
          outString += ">0.00"
          outString += "</a></td>"
        else:
          highlight = createHighlight(problem)
          url = url_for('grutorGradeSubmission', pid=p.id, uid=u.id, subnum=p.getSubmissionNumber(u))
          if 'finalTotalScore' in problem:
            points =  problem['finalTotalScore']
            userCourseScore += problem['finalTotalScore']
          else:
            points = problem['rawTotalScore']
            userCourseScore += problem['rawTotalScore']

          maxPoints = p.gradeColumn.maxScore
          cellTemplate = "<td %s><a href='%s'>%.2f</a></td>" % (highlight, url, points)
          outString += cellTemplate

    for group in c.gradeBook.auxillaryGrades:
      if len(group.columns) == 0:
        outString += "<td class='active'></td>"
        continue

      for col in group.columns:
        score = col.scores.setdefault(u.keyOfUsername(), None)
        if score:
          outString += "<td>%.2f</td>" % (score.totalScore())
          userCourseScore += score.totalScore()
        else:
          outString += "<td>%.2f</td>" % (0)

    outString += "<td>%.2f</td></tr>" % (userCourseScore)
    return jsonify(res=outString)

  except (Course.DoesNotExist,User.DoesNotExist):
    abort(404)
def grutorSaveComment(pid, uid, subnum):
  '''
  Function Type: Callback-AJAX Function
  Called By: grutor/gradesubmission.html:saveComments()
  Purpose: Recieves a markdown formatted string and saves it as a grader
  comment for a specified submission

  Inputs:
    pid: The problem that this grade is for
    uid: The user whose grade this is
    subnum: The submission number that is currently being graded

  POST Values: A json object containing one field called "text" which contains
  the markdown formatted string

  Outputs:
    res: The result. True if it succeeded, False if it failed, and a string
    if there was an exception.
  '''
  try:
    p = Problem.objects.get(id=pid)
    c,a = p.getParents()

    #For security purposes we send anyone who isnt in this class to the index
    if not ( c in current_user.gradingCourses()):
      return jsonify(res=False)

    #Try to get the contents
    content = request.get_json()

    #make sure we got the contents
    if content == None:
      return jsonify(res=False)

    #Define function for saving comments
    def comment(sub):
      sub.comments = content['text']
      sub.autoGraderComments = content['autotext']
      sub.save()

    user = User.objects.get(id=uid)
    sub = p.getSubmission(user, subnum)


    #Before we change anything make sure all changes can go through
    checkMounted()

    comment(sub)

    grutorSubArchive(p, c, a, user, sub)
    if sub.partner != None:
      comment(sub.partnerSubmission)
      grutorSubArchive(p, c, a, sub.partner, sub.partnerSubmission)

    #Save changes to the problem
    p.save(cascade=True)

    return jsonify(res=True, type="comments")
  except Exception as e:
    import traceback
    tb = traceback.format_exc()
    return jsonify(res=False, error=str(tb))
def commonRenderGrade(cid, instr):
  try:
    content = request.get_json()
    c = Course.objects.get(id=cid)
    u = User.objects.get(id=content['uid'])

    #If we are accessing the instructor version check that they are an instr
    if instr and not c in current_user.courseInstructor:
      abort(403)

    if not c in current_user.gradingCourses():
      abort(403)

    assignmentScores = getStudentAssignmentScores(c, u)

    userCourseScore = 0

    outString = "<tr>"
    # <td>{{username/identifier}}</td>
    outString += "<td>"
    if instr:
      outString += u.username
      if c.anonymousGrading:
        outString += " (" + c.getIdentifier(u.keyOfUsername()) + ")"
    else:
      if c.anonymousGrading:
        outString += c.getIdentifier(u.keyOfUsername())
      else:
        outString += u.username
    outString += "</td>"
    # <td>{{link to problem grading}}</td>
    for assignment, a in zip(assignmentScores, c.assignments):
      #If this assignment doesn't have any problems we put a blank column in
      if len(assignment) == 0:
        outString += "<td class='active'></td>"
        continue

      for problem, p in zip(assignment, a.problems):
        if problem == None:
          #If there was no submission link to the make blank page
          outString += "<td class='active'><a href='"
          outString += "#'" #TODO Replace this with an actual link
          outString += ">0.00"
          outString += "</a></td>"
        else:
          highlight = createHighlight(problem)
          url = url_for('grutorGradeSubmission', pid=p.id, uid=u.id, subnum=p.getSubmissionNumber(u))
          if 'finalTotalScore' in problem:
            points =  problem['finalTotalScore']
            userCourseScore += problem['finalTotalScore']
          else:
            points = problem['rawTotalScore']
            userCourseScore += problem['rawTotalScore']

          maxPoints = p.gradeColumn.maxScore
          cellTemplate = "<td %s><a href='%s'>%.2f</a></td>" % (highlight, url, points)
          outString += cellTemplate

    for group in c.gradeBook.auxillaryGrades:
      if len(group.columns) == 0:
        outString += "<td class='active'></td>"
        continue

      for col in group.columns:
        score = col.scores.setdefault(u.keyOfUsername(), None)
        if score:
          outString += "<td>%.2f</td>" % (score.totalScore())
          userCourseScore += score.totalScore()
        else:
          outString += "<td>%.2f</td>" % (0)

    outString += "<td>%.2f</td></tr>" % (userCourseScore)
    return jsonify(res=outString)

  except (Course.DoesNotExist,User.DoesNotExist):
    abort(404)
示例#36
0
def grutorGradeSubmission(pid, uid, subnum):
    '''
  Function Type: View Function
  Template: grutor/gradesubmission.html
  Purpose: Display to the grader forms that will allow the grader to assign
  grades and give comments on a submission. Additionally allows the grader to
  download the files for the submission.

  Inputs:
    pid: The object ID of the problem being graded
    uid: The object ID of the user whose submission is being graded
    subnum: Which submission of the user is being graded

  Template Parameters:
    course: The course this problem is contained in
    assignment: The assignment group this problem is contained in
    problem: The problem with ID <pid>
    subnum: The submission number that is being graded
    user: The user object specified by <uid>
    submission: The submission object specified by the user, problem, and
    subnum

  Forms Handled: None
  '''
    try:
        p = Problem.objects.get(id=pid)
        c, a = p.getParents()
        user = User.objects.get(id=uid)

        #For security purposes we send anyone who isnt in this class to the index
        if not (c in current_user.gradingCourses()):
            abort(403)

        #p = Problem.objects.get(id=pid)
        #a = AssignmentGroup.objects.get(id=aid)

        submission = p.getSubmission(user, subnum)

        u = User.objects.get(id=g.user.id)

        #If this is not in progress by anyone try to claim it atomically
        if submission.status < SUBMISSION_GRADING:
            subCol = Submission._get_collection()
            if submission.partner == None:
                res = subCol.find_and_modify(query={
                    '_id': submission.id,
                    'status': {
                        "$lt": SUBMISSION_GRADING
                    }
                },
                                             update={
                                                 "$set": {
                                                     "status":
                                                     SUBMISSION_GRADING,
                                                     "gradedBy": g.user.id
                                                 }
                                             })
                submission.reload()
            else:
                otherSub = submission.partnerSubmission
                subList = sorted([submission, otherSub], key=lambda x: x.id)
                res = subCol.find_and_modify(query={'_id': subList[0].id, 'status':{"$lt": SUBMISSION_GRADING}}, \
                  update={'$set': {'status':SUBMISSION_GRADING, 'gradedBy': g.user.id}})
                #res = Submission.objects.exec_js(LOCK_QUERY, id=subList[0].id, uid=g.user.id)
                if res != None:
                    res = subCol.find_and_modify(query={'_id': subList[1].id, 'status':{"$lt": SUBMISSION_GRADING}}, \
                      update={'$set': {'status':SUBMISSION_GRADING, 'gradedBy': g.user.id}})
            if res == None:
                flash(
                    "It appears another grader has already claimed this assignment are you sure you want to grade it?",
                    "warning")
        elif submission.gradedBy != u and not submission.status == 4:
            flash(
                "It appears another grader has already claimed this assignment are you sure you want to grade it?",
                "warning")

        submission.reload()
        submission.save()

        p.save()

        return render_template("grutor/gradesubmission.html", \
                                course=c, problem=p, assignment=a, subnum=subnum,
                                user=user, submission=submission)
    except Course.DoesNotExist as e:
        abort(404)
def grutorGradeSubmission(pid, uid, subnum):
  '''
  Function Type: View Function
  Template: grutor/gradesubmission.html
  Purpose: Display to the grader forms that will allow the grader to assign
  grades and give comments on a submission. Additionally allows the grader to
  download the files for the submission.

  Inputs:
    pid: The object ID of the problem being graded
    uid: The object ID of the user whose submission is being graded
    subnum: Which submission of the user is being graded

  Template Parameters:
    course: The course this problem is contained in
    assignment: The assignment group this problem is contained in
    problem: The problem with ID <pid>
    subnum: The submission number that is being graded
    user: The user object specified by <uid>
    submission: The submission object specified by the user, problem, and
    subnum

  Forms Handled: None
  '''
  try:
    p = Problem.objects.get(id=pid)
    c,a = p.getParents()
    user = User.objects.get(id=uid)

    #For security purposes we send anyone who isnt in this class to the index
    if not ( c in current_user.gradingCourses()):
      abort(403)

    #p = Problem.objects.get(id=pid)
    #a = AssignmentGroup.objects.get(id=aid)

    submission = p.getSubmission(user, subnum)

    u = User.objects.get(id=g.user.id)

    #If this is not in progress by anyone try to claim it atomically
    if submission.status < SUBMISSION_GRADING:
      subCol = Submission._get_collection()
      if submission.partner == None:
        res = subCol.find_and_modify(query={'_id':submission.id, 'status': {"$lt": SUBMISSION_GRADING}}, update={"$set": {"status":SUBMISSION_GRADING, "gradedBy": g.user.id}})
        submission.reload()
      else:
        otherSub = submission.partnerSubmission
        subList = sorted([submission, otherSub], key=lambda x: x.id)
        res = subCol.find_and_modify(query={'_id': subList[0].id, 'status':{"$lt": SUBMISSION_GRADING}}, \
          update={'$set': {'status':SUBMISSION_GRADING, 'gradedBy': g.user.id}})
        #res = Submission.objects.exec_js(LOCK_QUERY, id=subList[0].id, uid=g.user.id)
        if res != None:
          res = subCol.find_and_modify(query={'_id': subList[1].id, 'status':{"$lt": SUBMISSION_GRADING}}, \
            update={'$set': {'status':SUBMISSION_GRADING, 'gradedBy': g.user.id}})
      if res == None:
        flash("It appears another grader has already claimed this assignment are you sure you want to grade it?", "warning")
    elif submission.gradedBy != u and not submission.status == 4:
      flash("It appears another grader has already claimed this assignment are you sure you want to grade it?", "warning")

    submission.reload()
    submission.save()

    p.save()

    return render_template("grutor/gradesubmission.html", \
                            course=c, problem=p, assignment=a, subnum=subnum,
                            user=user, submission=submission)
  except Course.DoesNotExist as e:
    abort(404)
示例#38
0
def grutorMakeBlank(pid, uid):
  '''
  Function Type: Callback-Redirect Function
  Purpose: When a student does not have a submission for a given assignment this
  function is called. It creates a blank submission with no files and then
  redirects the grader to the grade submission page.

  Inputs:
    pid: The object ID for the problem that is being graded.
    uid: The object ID of the user who is being graded.

  Forms Handled: None
  '''
  try:
    p = Problem.objects.get(id=pid)
    c,a = p.getParents()
    user = User.objects.get(id=uid)

    #For security purposes we send anyone who isnt in this class to the index
    if not (c in current_user.gradingCourses()):
      abort(403)

    #Check that the user we are trying to create a submission for is in the class
    if not (c in user.courseStudent):
      flash("The user you were trying to make a submission for is not in the course.")
      abort(404)

    #Create a blank submission
    #Create the grade
    grade = GBGrade()
    grade.save()
    p.gradeColumn.scores[user.keyOfUsername()] = grade


    p.studentSubmissions[user.keyOfUsername()] = StudentSubmissionList()

    #create a filepath
    filepath = getSubmissionPath(c, a, p, user, 1)

    sub = Submission()
    sub.problem = p
    #Initial fields for submission
    sub.filePath = filepath
    sub.grade = p.gradeColumn.scores[user.keyOfUsername()]
    sub.submissionTime = datetime.datetime.utcnow()
    sub.status = SUBMISSION_GRADING
    sub.gradedBy = User.objects.get(id=g.user.id)

    sub.save()
    p.studentSubmissions[user.keyOfUsername()].addSubmission(sub)

    #The grader is making this so it isn't late
    sub.isLate = False

    #Create the needed folders
    os.makedirs(filepath)

    p.save(cascade=True)
    return redirect(url_for('grutorGradeSubmission', uid=uid, pid=pid, subnum=1))
  except (Problem.DoesNotExist, Course.DoesNotExist, AssignmentGroup.DoesNotExist):
    #If either p can't be found or we can't get its parents then 404
    abort(404)