Commit c5c4305f by Victor Shnayder

Merge pull request #1110 from MITx/diana/instructor-grading-styling

Updates to the instructor grading pages
parents faae6a36 85b5190c
......@@ -29,16 +29,21 @@ class MockStaffGradingService(object):
def __init__(self):
self.cnt = 0
def get_next(self, course_id, grader_id):
def get_next(self,course_id, location, grader_id):
self.cnt += 1
return json.dumps({'success': True,
'submission_id': self.cnt,
'submission': 'Test submission {cnt}'.format(cnt=self.cnt),
'num_graded': 3,
'min_for_ml': 5,
'num_pending': 4,
'prompt': 'This is a fake prompt',
'ml_error_info': 'ML info',
'max_score': 2 + self.cnt % 3,
'rubric': 'A rubric'})
def save_grade(self, course_id, grader_id, submission_id, score, feedback):
return self.get_next(course_id, grader_id)
return self.get_next(course_id, 'fake location', grader_id)
class StaffGradingService(object):
......@@ -53,6 +58,7 @@ class StaffGradingService(object):
self.login_url = self.url + '/login/'
self.get_next_url = self.url + '/get_next_submission/'
self.save_grade_url = self.url + '/save_grade/'
self.get_problem_list_url = self.url + '/get_problem_list/'
self.session = requests.session()
......@@ -96,13 +102,43 @@ class StaffGradingService(object):
return response
def get_problem_list(self, course_id, grader_id):
"""
Get the list of problems for a given course.
Args:
course_id: course id that we want the problems of
grader_id: who is grading this? The anonymous user_id of the grader.
Returns:
json string with the response from the service. (Deliberately not
writing out the fields here--see the docs on the staff_grading view
in the grading_controller repo)
Raises:
GradingServiceError: something went wrong with the connection.
"""
op = lambda: self.session.get(self.get_problem_list_url,
allow_redirects = False,
params={'course_id': course_id,
'grader_id': grader_id})
try:
r = self._try_with_login(op)
except (RequestException, ConnectionError, HTTPError) as err:
# reraise as promised GradingServiceError, but preserve stacktrace.
raise GradingServiceError, str(err), sys.exc_info()[2]
return r.text
def get_next(self, course_id, grader_id):
def get_next(self, course_id, location, grader_id):
"""
Get the next thing to grade.
Args:
course_id: course id to get submission for
course_id: the course that this problem belongs to
location: location of the problem that we are grading and would like the
next submission for
grader_id: who is grading this? The anonymous user_id of the grader.
Returns:
......@@ -115,7 +151,7 @@ class StaffGradingService(object):
"""
op = lambda: self.session.get(self.get_next_url,
allow_redirects=False,
params={'course_id': course_id,
params={'location': location,
'grader_id': grader_id})
try:
r = self._try_with_login(op)
......@@ -198,7 +234,8 @@ def _check_access(user, course_id):
def get_next(request, course_id):
"""
Get the next thing to grade for course_id.
Get the next thing to grade for course_id and with the location specified
in the .
Returns a json dict with the following keys:
......@@ -218,17 +255,45 @@ def get_next(request, course_id):
"""
_check_access(request.user, course_id)
return HttpResponse(_get_next(course_id, request.user.id),
required = set(['location'])
if request.method != 'POST':
raise Http404
actual = set(request.POST.keys())
missing = required - actual
if len(missing) > 0:
return _err_response('Missing required keys {0}'.format(
', '.join(missing)))
grader_id = request.user.id
p = request.POST
location = p['location']
return HttpResponse(_get_next(course_id, request.user.id, location),
mimetype="application/json")
def _get_next(course_id, grader_id):
def get_problem_list(request, course_id):
"""
Implementation of get_next (also called from save_grade) -- returns a json string
Get all the problems for the given course id
TODO: fill in all of this stuff
"""
_check_access(request.user, course_id)
try:
response = grading_service().get_problem_list(course_id, request.user.id)
return HttpResponse(response,
mimetype="application/json")
except GradingServiceError:
log.exception("Error from grading service. server url: {0}"
.format(grading_service().url))
return HttpResponse(json.dumps({'success': False,
'error': 'Could not connect to grading service'}))
def _get_next(course_id, grader_id, location):
"""
Implementation of get_next (also called from save_grade) -- returns a json string
"""
try:
return grading_service().get_next(course_id, grader_id)
return grading_service().get_next(course_id, location, grader_id)
except GradingServiceError:
log.exception("Error from grading service. server url: {0}"
.format(grading_service().url))
......@@ -255,15 +320,17 @@ def save_grade(request, course_id):
if request.method != 'POST':
raise Http404
required = set('score', 'feedback', 'submission_id')
required = set(['score', 'feedback', 'submission_id', 'location'])
actual = set(request.POST.keys())
log.debug(actual)
missing = required - actual
if len(missing) != 0:
if len(missing) > 0:
return _err_response('Missing required keys {0}'.format(
', '.join(missing)))
grader_id = request.user.id
p = request.POST
location = p['location']
try:
result_json = grading_service().save_grade(course_id,
......@@ -286,6 +353,6 @@ def save_grade(request, course_id):
return _err_response('Grading service failed')
# Ok, save_grade seemed to work. Get the next submission to grade.
return HttpResponse(_get_next(course_id, grader_id),
return HttpResponse(_get_next(course_id, grader_id, location),
mimetype="application/json")
......@@ -236,6 +236,7 @@ class TestStaffGradingService(ct.PageLoader):
self.student = 'view@test.com'
self.instructor = 'view2@test.com'
self.password = 'foo'
self.location = 'TestLocation'
self.create_account('u1', self.student, self.password)
self.create_account('u2', self.instructor, self.password)
self.activate_user(self.student)
......@@ -271,8 +272,9 @@ class TestStaffGradingService(ct.PageLoader):
self.login(self.instructor, self.password)
url = reverse('staff_grading_get_next', kwargs={'course_id': self.course_id})
data = {'location': self.location}
r = self.check_for_get_code(200, url)
r = self.check_for_post_code(200, url, data)
d = json.loads(r.content)
self.assertTrue(d['success'])
self.assertEquals(d['submission_id'], self.mock_service.cnt)
......@@ -285,7 +287,8 @@ class TestStaffGradingService(ct.PageLoader):
data = {'score': '12',
'feedback': 'great!',
'submission_id': '123'}
'submission_id': '123',
'location': self.location}
r = self.check_for_post_code(200, url, data)
d = json.loads(r.content)
self.assertTrue(d['success'], str(d))
......
div.staff-grading {
textarea.feedback-area {
height: 100px;
height: 75px;
margin: 20px;
}
......@@ -26,4 +26,61 @@ div.staff-grading {
input[name='score-selection'] {
display: none;
}
ul
{
li
{
margin: 16px 0px;
}
}
.prompt-information-container,
.submission-wrapper,
.rubric-wrapper,
.grading-container
{
border: 1px solid gray;
padding: 15px;
}
.error-container
{
background-color: #FFCCCC;
padding: 15px;
margin-left: 0px;
}
.meta-info-wrapper
{
background-color: #eee;
padding:15px;
h3
{
font-size:1em;
}
ul
{
list-style-type: none;
font-size: .85em;
li
{
margin: 5px 0px;
}
}
}
.message-container
{
background-color: $yellow;
padding: 10px;
margin-left:0px;
}
.breadcrumbs
{
margin-top:20px;
margin-left:0px;
margin-bottom:5px;
font-size: .8em;
}
padding: 40px;
}
......@@ -18,42 +18,66 @@
<div class="staff-grading" data-ajax_url="${ajax_url}">
<h1>Staff grading</h1>
<div class="breadcrumbs">
</div>
<div class="error-container">
</div>
<div class="message-container">
</div>
<div class="ml-error-info-container">
<section class="problem-list-container">
<h2>Instructions</h2>
<div class="instructions">
<p>This is the list of problems that current need to be graded in order to train the machine learning models. Each problem needs to be trained separately, and we have indicated the number of student submissions that need to be graded in order for a model to be generated. You can grade more than the minimum required number of submissions--this will improve the accuracy of machine learning, though with diminishing returns. You can see the current accuracy of machine learning while grading.</p>
</div>
<h2>Problem List</h2>
<ul class="problem-list">
</ul>
</section>
<section class="prompt-wrapper">
<h3>Question prompt</h3>
<h2 class="prompt-name"></h2>
<div class="meta-info-wrapper">
<h3>Problem Information</h3>
<div class="problem-meta-info-container">
</div>
<h3>Maching Learning Information</h3>
<div class="ml-error-info-container">
</div>
</div>
<div class="prompt-information-container">
<h3>Question</h3>
<div class="prompt-container">
</div>
</section>
<section class="submission-wrapper">
<h3>Submission</h3>
</div>
<div class="rubric-wrapper">
<h3>Grading Rubric</h3>
<div class="rubric-container">
</div>
</div>
<div class="submission-wrapper">
<h3>Student Submission</h3>
<div class="submission-container">
</div>
</div>
</section>
<section class="rubric-wrapper">
<h3>Rubric</h3>
<div class="rubric-container">
<div class="action-button">
<input type=button value="Submit" class="action-button" name="show" />
</div>
<section class="grading-wrapper">
<h2>Grading</h2>
<div class="grading-container">
<div class="evaluation">
<textarea name="feedback" placeholder="Feedback for student..."
class="feedback-area" cols="70" rows="10"></textarea>
<p class="score-selection-container">
</p>
<textarea name="feedback" placeholder="Feedback for student (optional)"
class="feedback-area" cols="70" ></textarea>
</div>
</section>
<div class="submission">
<input type="button" value="Submit" class="submit-button" name="show"/>
......@@ -61,4 +85,5 @@
</div>
</div>
</section>
......@@ -243,6 +243,10 @@ if settings.COURSEWARE_ENABLED:
'instructor.staff_grading_service.get_next', name='staff_grading_get_next'),
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/staff_grading/save_grade$',
'instructor.staff_grading_service.save_grade', name='staff_grading_save_grade'),
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/staff_grading/save_grade$',
'instructor.staff_grading_service.save_grade', name='staff_grading_save_grade'),
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/staff_grading/get_problem_list$',
'instructor.staff_grading_service.get_problem_list', name='staff_grading_get_problem_list'),
)
# discussion forums live within courseware, so courseware must be enabled first
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment