Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
e4ee1c6c
Commit
e4ee1c6c
authored
Jun 24, 2013
by
Carlos Andrés Rocha
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Rename arguments of modx_dispatch and handle_ajax related functions
Refactor a bit modx_dispatch
parent
2f02496c
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
254 additions
and
230 deletions
+254
-230
common/lib/capa/capa/capa_problem.py
+4
-4
common/lib/capa/capa/inputtypes.py
+11
-11
common/lib/capa/capa/tests/test_inputtypes.py
+4
-4
common/lib/xmodule/xmodule/capa_module.py
+38
-35
common/lib/xmodule/xmodule/combined_open_ended_module.py
+2
-3
common/lib/xmodule/xmodule/conditional_module.py
+1
-1
common/lib/xmodule/xmodule/open_ended_grading_classes/combined_open_ended_modulev1.py
+20
-20
common/lib/xmodule/xmodule/open_ended_grading_classes/open_ended_module.py
+21
-21
common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py
+20
-20
common/lib/xmodule/xmodule/open_ended_grading_classes/self_assessment_module.py
+17
-17
common/lib/xmodule/xmodule/peer_grading_module.py
+35
-38
common/lib/xmodule/xmodule/poll_module.py
+2
-2
common/lib/xmodule/xmodule/seq_module.py
+2
-2
common/lib/xmodule/xmodule/tests/test_logic.py
+2
-2
common/lib/xmodule/xmodule/timelimit_module.py
+1
-2
common/lib/xmodule/xmodule/video_module.py
+2
-2
common/lib/xmodule/xmodule/videoalpha_module.py
+2
-2
common/lib/xmodule/xmodule/word_cloud_module.py
+3
-3
common/lib/xmodule/xmodule/x_module.py
+2
-2
lms/djangoapps/courseware/module_render.py
+64
-36
lms/urls.py
+1
-3
No files found.
common/lib/capa/capa/capa_problem.py
View file @
e4ee1c6c
...
...
@@ -373,7 +373,7 @@ class LoncapaProblem(object):
html
=
contextualize_text
(
etree
.
tostring
(
self
.
_extract_html
(
self
.
tree
)),
self
.
context
)
return
html
def
handle_input_ajax
(
self
,
get
):
def
handle_input_ajax
(
self
,
data
):
'''
InputTypes can support specialized AJAX calls. Find the correct input and pass along the correct data
...
...
@@ -381,10 +381,10 @@ class LoncapaProblem(object):
'''
# pull out the id
input_id
=
get
[
'input_id'
]
input_id
=
data
[
'input_id'
]
if
self
.
inputs
[
input_id
]:
dispatch
=
get
[
'dispatch'
]
return
self
.
inputs
[
input_id
]
.
handle_ajax
(
dispatch
,
get
)
dispatch
=
data
[
'dispatch'
]
return
self
.
inputs
[
input_id
]
.
handle_ajax
(
dispatch
,
data
)
else
:
log
.
warning
(
"Could not find matching input for id:
%
s"
%
input_id
)
return
{}
...
...
common/lib/capa/capa/inputtypes.py
View file @
e4ee1c6c
...
...
@@ -223,13 +223,13 @@ class InputTypeBase(object):
"""
pass
def
handle_ajax
(
self
,
dispatch
,
get
):
def
handle_ajax
(
self
,
dispatch
,
data
):
"""
InputTypes that need to handle specialized AJAX should override this.
Input:
dispatch: a string that can be used to determine how to handle the data passed in
get
: a dictionary containing the data that was sent with the ajax call
data
: a dictionary containing the data that was sent with the ajax call
Output:
a dictionary object that can be serialized into JSON. This will be sent back to the Javascript.
...
...
@@ -677,20 +677,20 @@ class MatlabInput(CodeInput):
self
.
queue_len
=
1
self
.
msg
=
self
.
plot_submitted_msg
def
handle_ajax
(
self
,
dispatch
,
get
):
def
handle_ajax
(
self
,
dispatch
,
data
):
'''
Handle AJAX calls directed to this input
Args:
- dispatch (str) - indicates how we want this ajax call to be handled
-
get
(dict) - dictionary of key-value pairs that contain useful data
-
data
(dict) - dictionary of key-value pairs that contain useful data
Returns:
dict - 'success' - whether or not we successfully queued this submission
- 'message' - message to be rendered in case of error
'''
if
dispatch
==
'plot'
:
return
self
.
_plot_data
(
get
)
return
self
.
_plot_data
(
data
)
return
{}
def
ungraded_response
(
self
,
queue_msg
,
queuekey
):
...
...
@@ -751,7 +751,7 @@ class MatlabInput(CodeInput):
msg
=
result
[
'msg'
]
return
msg
def
_plot_data
(
self
,
get
):
def
_plot_data
(
self
,
data
):
'''
AJAX handler for the plot button
Args:
...
...
@@ -765,7 +765,7 @@ class MatlabInput(CodeInput):
return
{
'success'
:
False
,
'message'
:
'Cannot connect to the queue'
}
# pull relevant info out of get
response
=
get
[
'submission'
]
response
=
data
[
'submission'
]
# construct xqueue headers
qinterface
=
self
.
system
.
xqueue
[
'interface'
]
...
...
@@ -951,16 +951,16 @@ class ChemicalEquationInput(InputTypeBase):
"""
return
{
'previewer'
:
'/static/js/capa/chemical_equation_preview.js'
,
}
def
handle_ajax
(
self
,
dispatch
,
get
):
def
handle_ajax
(
self
,
dispatch
,
data
):
'''
Since we only have chemcalc preview this input, check to see if it
matches the corresponding dispatch and send it through if it does
'''
if
dispatch
==
'preview_chemcalc'
:
return
self
.
preview_chemcalc
(
get
)
return
self
.
preview_chemcalc
(
data
)
return
{}
def
preview_chemcalc
(
self
,
get
):
def
preview_chemcalc
(
self
,
data
):
"""
Render an html preview of a chemical formula or equation. get should
contain a key 'formula' and value 'some formula string'.
...
...
@@ -974,7 +974,7 @@ class ChemicalEquationInput(InputTypeBase):
result
=
{
'preview'
:
''
,
'error'
:
''
}
formula
=
get
[
'formula'
]
formula
=
data
[
'formula'
]
if
formula
is
None
:
result
[
'error'
]
=
"No formula specified."
return
result
...
...
common/lib/capa/capa/tests/test_inputtypes.py
View file @
e4ee1c6c
...
...
@@ -467,8 +467,8 @@ class MatlabTest(unittest.TestCase):
self
.
assertEqual
(
context
,
expected
)
def
test_plot_data
(
self
):
get
=
{
'submission'
:
'x = 1234;'
}
response
=
self
.
the_input
.
handle_ajax
(
"plot"
,
get
)
data
=
{
'submission'
:
'x = 1234;'
}
response
=
self
.
the_input
.
handle_ajax
(
"plot"
,
data
)
test_system
()
.
xqueue
[
'interface'
]
.
send_to_queue
.
assert_called_with
(
header
=
ANY
,
body
=
ANY
)
...
...
@@ -477,10 +477,10 @@ class MatlabTest(unittest.TestCase):
self
.
assertEqual
(
self
.
the_input
.
input_state
[
'queuestate'
],
'queued'
)
def
test_plot_data_failure
(
self
):
get
=
{
'submission'
:
'x = 1234;'
}
data
=
{
'submission'
:
'x = 1234;'
}
error_message
=
'Error message!'
test_system
()
.
xqueue
[
'interface'
]
.
send_to_queue
.
return_value
=
(
1
,
error_message
)
response
=
self
.
the_input
.
handle_ajax
(
"plot"
,
get
)
response
=
self
.
the_input
.
handle_ajax
(
"plot"
,
data
)
self
.
assertFalse
(
response
[
'success'
])
self
.
assertEqual
(
response
[
'message'
],
error_message
)
self
.
assertTrue
(
'queuekey'
not
in
self
.
the_input
.
input_state
)
...
...
common/lib/xmodule/xmodule/capa_module.py
View file @
e4ee1c6c
...
...
@@ -519,11 +519,11 @@ class CapaModule(CapaFields, XModule):
# now do the substitutions which are filesystem based, e.g. '/static/' prefixes
return
self
.
system
.
replace_urls
(
html
)
def
handle_ajax
(
self
,
dispatch
,
get
):
def
handle_ajax
(
self
,
dispatch
,
data
):
"""
This is called by courseware.module_render, to handle an AJAX call.
`
get
` is request.POST.
`
data
` is request.POST.
Returns a json dictionary:
{ 'progress_changed' : True/False,
...
...
@@ -547,18 +547,19 @@ class CapaModule(CapaFields, XModule):
before
=
self
.
get_progress
()
try
:
d
=
handlers
[
dispatch
](
get
)
result
=
handlers
[
dispatch
](
data
)
except
Exception
as
err
:
_
,
_
,
traceback_obj
=
sys
.
exc_info
()
raise
ProcessingError
,
err
.
message
,
traceback_obj
raise
ProcessingError
(
err
.
message
,
traceback_obj
)
after
=
self
.
get_progress
()
d
.
update
({
result
.
update
({
'progress_changed'
:
after
!=
before
,
'progress_status'
:
Progress
.
to_js_status_str
(
after
),
})
return
json
.
dumps
(
d
,
cls
=
ComplexEncoder
)
return
json
.
dumps
(
result
,
cls
=
ComplexEncoder
)
def
is_past_due
(
self
):
"""
...
...
@@ -633,32 +634,32 @@ class CapaModule(CapaFields, XModule):
return
False
def
update_score
(
self
,
get
):
def
update_score
(
self
,
data
):
"""
Delivers grading response (e.g. from asynchronous code checking) to
the capa problem, so its score can be updated
`get` must have a field `response`
which is a string that contains the
'data' must have a key 'response'
which is a string that contains the
grader's response
No ajax return is needed. Return empty dict.
"""
queuekey
=
get
[
'queuekey'
]
score_msg
=
get
[
'xqueue_body'
]
queuekey
=
data
[
'queuekey'
]
score_msg
=
data
[
'xqueue_body'
]
self
.
lcp
.
update_score
(
score_msg
,
queuekey
)
self
.
set_state_from_lcp
()
self
.
publish_grade
()
return
dict
()
# No AJAX return is needed
def
handle_ungraded_response
(
self
,
get
):
def
handle_ungraded_response
(
self
,
data
):
"""
Delivers a response from the XQueue to the capa problem
The score of the problem will not be updated
Args:
-
get
(dict) must contain keys:
-
data
(dict) must contain keys:
queuekey - a key specific to this response
xqueue_body - the body of the response
Returns:
...
...
@@ -666,28 +667,30 @@ class CapaModule(CapaFields, XModule):
No ajax return is needed, so an empty dict is returned
"""
queuekey
=
get
[
'queuekey'
]
score_msg
=
get
[
'xqueue_body'
]
queuekey
=
data
[
'queuekey'
]
score_msg
=
data
[
'xqueue_body'
]
# pass along the xqueue message to the problem
self
.
lcp
.
ungraded_response
(
score_msg
,
queuekey
)
self
.
set_state_from_lcp
()
return
dict
()
def
handle_input_ajax
(
self
,
get
):
def
handle_input_ajax
(
self
,
data
):
"""
Handle ajax calls meant for a particular input in the problem
Args:
-
get
(dict) - data that should be passed to the input
-
data
(dict) - data that should be passed to the input
Returns:
- dict containing the response from the input
"""
response
=
self
.
lcp
.
handle_input_ajax
(
get
)
response
=
self
.
lcp
.
handle_input_ajax
(
data
)
# save any state changes that may occur
self
.
set_state_from_lcp
()
return
response
def
get_answer
(
self
,
get
):
def
get_answer
(
self
,
data
):
"""
For the "show answer" button.
...
...
@@ -717,10 +720,9 @@ class CapaModule(CapaFields, XModule):
return
{
'answers'
:
new_answers
}
# Figure out if we should move these to capa_problem?
def
get_problem
(
self
,
get
):
def
get_problem
(
self
,
_data
):
"""
Return results of get_problem_html, as a simple dict for json-ing.
{ 'html': <the-html> }
Used if we want to reconfirm we have the right thing e.g. after
...
...
@@ -729,27 +731,27 @@ class CapaModule(CapaFields, XModule):
return
{
'html'
:
self
.
get_problem_html
(
encapsulate
=
False
)}
@staticmethod
def
make_dict_of_responses
(
get
):
def
make_dict_of_responses
(
data
):
"""
Make dictionary of student responses (aka "answers")
`
get
` is POST dictionary (Django QueryDict).
`
data
` is POST dictionary (Django QueryDict).
The `
get
` dict has keys of the form 'x_y', which are mapped
The `
data
` dict has keys of the form 'x_y', which are mapped
to key 'y' in the returned dict. For example,
'input_1_2_3' would be mapped to '1_2_3' in the returned dict.
Some inputs always expect a list in the returned dict
(e.g. checkbox inputs). The convention is that
keys in the `
get
` dict that end with '[]' will always
keys in the `
data
` dict that end with '[]' will always
have list values in the returned dict.
For example, if the `
get
` dict contains {'input_1[]': 'test' }
For example, if the `
data
` dict contains {'input_1[]': 'test' }
then the output dict would contain {'1': ['test'] }
(the value is a list).
Raises an exception if:
-A key in the `
get
` dictionary does not contain at least one underscore
-A key in the `
data
` dictionary does not contain at least one underscore
(e.g. "input" is invalid, but "input_1" is valid)
-Two keys end up with the same name in the returned dict.
...
...
@@ -758,7 +760,7 @@ class CapaModule(CapaFields, XModule):
"""
answers
=
dict
()
for
key
in
get
:
for
key
in
data
:
# e.g. input_resistor_1 ==> resistor_1
_
,
_
,
name
=
key
.
partition
(
'_'
)
...
...
@@ -777,9 +779,9 @@ class CapaModule(CapaFields, XModule):
name
=
name
[:
-
2
]
if
is_list_key
else
name
if
is_list_key
:
val
=
get
.
getlist
(
key
)
val
=
data
.
getlist
(
key
)
else
:
val
=
get
[
key
]
val
=
data
[
key
]
# If the name already exists, then we don't want
# to override it. Raise an error instead
...
...
@@ -801,7 +803,7 @@ class CapaModule(CapaFields, XModule):
'max_value'
:
score
[
'total'
],
})
def
check_problem
(
self
,
get
):
def
check_problem
(
self
,
data
):
"""
Checks whether answers to a problem are correct
...
...
@@ -813,8 +815,9 @@ class CapaModule(CapaFields, XModule):
event_info
[
'state'
]
=
self
.
lcp
.
get_state
()
event_info
[
'problem_id'
]
=
self
.
location
.
url
()
answers
=
self
.
make_dict_of_responses
(
get
)
answers
=
self
.
make_dict_of_responses
(
data
)
event_info
[
'answers'
]
=
convert_files_to_filenames
(
answers
)
# Too late. Cannot submit
if
self
.
closed
():
event_info
[
'failure'
]
=
'closed'
...
...
@@ -972,7 +975,7 @@ class CapaModule(CapaFields, XModule):
return
{
'success'
:
success
}
def
save_problem
(
self
,
get
):
def
save_problem
(
self
,
data
):
"""
Save the passed in answers.
Returns a dict { 'success' : bool, 'msg' : message }
...
...
@@ -982,7 +985,7 @@ class CapaModule(CapaFields, XModule):
event_info
[
'state'
]
=
self
.
lcp
.
get_state
()
event_info
[
'problem_id'
]
=
self
.
location
.
url
()
answers
=
self
.
make_dict_of_responses
(
get
)
answers
=
self
.
make_dict_of_responses
(
data
)
event_info
[
'answers'
]
=
answers
# Too late. Cannot submit
...
...
@@ -1011,7 +1014,7 @@ class CapaModule(CapaFields, XModule):
return
{
'success'
:
True
,
'msg'
:
msg
}
def
reset_problem
(
self
,
get
):
def
reset_problem
(
self
,
_data
):
"""
Changes problem state to unfinished -- removes student answers,
and causes problem to rerender itself.
...
...
common/lib/xmodule/xmodule/combined_open_ended_module.py
View file @
e4ee1c6c
...
...
@@ -204,9 +204,9 @@ class CombinedOpenEndedModule(CombinedOpenEndedFields, XModule):
return_value
=
self
.
child_module
.
get_html
()
return
return_value
def
handle_ajax
(
self
,
dispatch
,
get
):
def
handle_ajax
(
self
,
dispatch
,
data
):
self
.
save_instance_data
()
return_value
=
self
.
child_module
.
handle_ajax
(
dispatch
,
get
)
return_value
=
self
.
child_module
.
handle_ajax
(
dispatch
,
data
)
self
.
save_instance_data
()
return
return_value
...
...
@@ -266,4 +266,3 @@ class CombinedOpenEndedDescriptor(CombinedOpenEndedFields, RawDescriptor):
non_editable_fields
.
extend
([
CombinedOpenEndedDescriptor
.
due
,
CombinedOpenEndedDescriptor
.
graceperiod
,
CombinedOpenEndedDescriptor
.
markdown
,
CombinedOpenEndedDescriptor
.
version
])
return
non_editable_fields
common/lib/xmodule/xmodule/conditional_module.py
View file @
e4ee1c6c
...
...
@@ -135,7 +135,7 @@ class ConditionalModule(ConditionalFields, XModule):
'depends'
:
';'
.
join
(
self
.
required_html_ids
)
})
def
handle_ajax
(
self
,
dispatch
,
post
):
def
handle_ajax
(
self
,
_dispatch
,
_data
):
"""This is called by courseware.moduleodule_render, to handle
an AJAX call.
"""
...
...
common/lib/xmodule/xmodule/open_ended_grading_classes/combined_open_ended_modulev1.py
View file @
e4ee1c6c
...
...
@@ -500,10 +500,10 @@ class CombinedOpenEndedV1Module():
pass
return
return_html
def
get_rubric
(
self
,
get
):
def
get_rubric
(
self
,
_data
):
"""
Gets the results of a given grader via ajax.
Input: AJAX
get
dictionary
Input: AJAX
data
dictionary
Output: Dictionary to be rendered via ajax that contains the result html.
"""
all_responses
=
[]
...
...
@@ -532,10 +532,10 @@ class CombinedOpenEndedV1Module():
html
=
self
.
system
.
render_template
(
'{0}/combined_open_ended_results.html'
.
format
(
self
.
TEMPLATE_DIR
),
context
)
return
{
'html'
:
html
,
'success'
:
True
}
def
get_legend
(
self
,
get
):
def
get_legend
(
self
,
_data
):
"""
Gets the results of a given grader via ajax.
Input: AJAX
get
dictionary
Input: AJAX
data
dictionary
Output: Dictionary to be rendered via ajax that contains the result html.
"""
context
=
{
...
...
@@ -544,10 +544,10 @@ class CombinedOpenEndedV1Module():
html
=
self
.
system
.
render_template
(
'{0}/combined_open_ended_legend.html'
.
format
(
self
.
TEMPLATE_DIR
),
context
)
return
{
'html'
:
html
,
'success'
:
True
}
def
get_results
(
self
,
get
):
def
get_results
(
self
,
_data
):
"""
Gets the results of a given grader via ajax.
Input: AJAX
get
dictionary
Input: AJAX
data
dictionary
Output: Dictionary to be rendered via ajax that contains the result html.
"""
self
.
update_task_states
()
...
...
@@ -588,19 +588,19 @@ class CombinedOpenEndedV1Module():
html
=
self
.
system
.
render_template
(
'{0}/combined_open_ended_results.html'
.
format
(
self
.
TEMPLATE_DIR
),
context
)
return
{
'html'
:
html
,
'success'
:
True
}
def
get_status_ajax
(
self
,
get
):
def
get_status_ajax
(
self
,
_data
):
"""
Gets the results of a given grader via ajax.
Input: AJAX
get
dictionary
Input: AJAX
data
dictionary
Output: Dictionary to be rendered via ajax that contains the result html.
"""
html
=
self
.
get_status
(
True
)
return
{
'html'
:
html
,
'success'
:
True
}
def
handle_ajax
(
self
,
dispatch
,
get
):
def
handle_ajax
(
self
,
dispatch
,
data
):
"""
This is called by courseware.module_render, to handle an AJAX call.
"
get
" is request.POST.
"
data
" is request.POST.
Returns a json dictionary:
{ 'progress_changed' : True/False,
...
...
@@ -618,30 +618,30 @@ class CombinedOpenEndedV1Module():
}
if
dispatch
not
in
handlers
:
return_html
=
self
.
current_task
.
handle_ajax
(
dispatch
,
get
,
self
.
system
)
return_html
=
self
.
current_task
.
handle_ajax
(
dispatch
,
data
,
self
.
system
)
return
self
.
update_task_states_ajax
(
return_html
)
d
=
handlers
[
dispatch
](
get
)
d
=
handlers
[
dispatch
](
data
)
return
json
.
dumps
(
d
,
cls
=
ComplexEncoder
)
def
next_problem
(
self
,
get
):
def
next_problem
(
self
,
_data
):
"""
Called via ajax to advance to the next problem.
Input: AJAX
get
request.
Input: AJAX
data
request.
Output: Dictionary to be rendered
"""
self
.
update_task_states
()
return
{
'success'
:
True
,
'html'
:
self
.
get_html_nonsystem
(),
'allow_reset'
:
self
.
ready_to_reset
}
def
reset
(
self
,
get
):
def
reset
(
self
,
data
):
"""
If resetting is allowed, reset the state of the combined open ended module.
Input: AJAX
get
dictionary
Input: AJAX
data
dictionary
Output: AJAX dictionary to tbe rendered
"""
if
self
.
state
!=
self
.
DONE
:
if
not
self
.
ready_to_reset
:
return
self
.
out_of_sync_error
(
get
)
return
self
.
out_of_sync_error
(
data
)
if
self
.
student_attempts
>
self
.
attempts
:
return
{
...
...
@@ -789,13 +789,13 @@ class CombinedOpenEndedV1Module():
return
progress_object
def
out_of_sync_error
(
self
,
get
,
msg
=
''
):
def
out_of_sync_error
(
self
,
data
,
msg
=
''
):
"""
return dict out-of-sync error message, and also log.
"""
#This is a dev_facing_error
log
.
warning
(
"Combined module state out sync. state:
%
r,
get
:
%
r.
%
s"
,
self
.
state
,
get
,
msg
)
log
.
warning
(
"Combined module state out sync. state:
%
r,
data
:
%
r.
%
s"
,
self
.
state
,
data
,
msg
)
#This is a student_facing_error
return
{
'success'
:
False
,
'error'
:
'The problem state got out-of-sync. Please try reloading the page.'
}
...
...
common/lib/xmodule/xmodule/open_ended_grading_classes/open_ended_module.py
View file @
e4ee1c6c
...
...
@@ -122,17 +122,17 @@ class OpenEndedModule(openendedchild.OpenEndedChild):
self
.
payload
=
{
'grader_payload'
:
updated_grader_payload
}
def
skip_post_assessment
(
self
,
get
,
system
):
def
skip_post_assessment
(
self
,
_data
,
system
):
"""
Ajax function that allows one to skip the post assessment phase
@param
get
: AJAX dictionary
@param
data
: AJAX dictionary
@param system: ModuleSystem
@return: Success indicator
"""
self
.
child_state
=
self
.
DONE
return
{
'success'
:
True
}
def
message_post
(
self
,
get
,
system
):
def
message_post
(
self
,
data
,
system
):
"""
Handles a student message post (a reaction to the grade they received from an open ended grader type)
Returns a boolean success/fail and an error message
...
...
@@ -141,7 +141,7 @@ class OpenEndedModule(openendedchild.OpenEndedChild):
event_info
=
dict
()
event_info
[
'problem_id'
]
=
self
.
location_string
event_info
[
'student_id'
]
=
system
.
anonymous_student_id
event_info
[
'survey_responses'
]
=
get
event_info
[
'survey_responses'
]
=
data
survey_responses
=
event_info
[
'survey_responses'
]
for
tag
in
[
'feedback'
,
'submission_id'
,
'grader_id'
,
'score'
]:
...
...
@@ -587,10 +587,10 @@ class OpenEndedModule(openendedchild.OpenEndedChild):
html
=
system
.
render_template
(
'{0}/open_ended_evaluation.html'
.
format
(
self
.
TEMPLATE_DIR
),
context
)
return
html
def
handle_ajax
(
self
,
dispatch
,
get
,
system
):
def
handle_ajax
(
self
,
dispatch
,
data
,
system
):
'''
This is called by courseware.module_render, to handle an AJAX call.
"
get
" is request.POST.
"
data
" is request.POST.
Returns a json dictionary:
{ 'progress_changed' : True/False,
...
...
@@ -612,7 +612,7 @@ class OpenEndedModule(openendedchild.OpenEndedChild):
return
json
.
dumps
({
'error'
:
'Error handling action. Please try again.'
,
'success'
:
False
})
before
=
self
.
get_progress
()
d
=
handlers
[
dispatch
](
get
,
system
)
d
=
handlers
[
dispatch
](
data
,
system
)
after
=
self
.
get_progress
()
d
.
update
({
'progress_changed'
:
after
!=
before
,
...
...
@@ -620,20 +620,20 @@ class OpenEndedModule(openendedchild.OpenEndedChild):
})
return
json
.
dumps
(
d
,
cls
=
ComplexEncoder
)
def
check_for_score
(
self
,
get
,
system
):
def
check_for_score
(
self
,
_data
,
system
):
"""
Checks to see if a score has been received yet.
@param
get: AJAX get
dictionary
@param
data: AJAX
dictionary
@param system: Modulesystem (needed to align with other ajax functions)
@return: Returns the current state
"""
state
=
self
.
child_state
return
{
'state'
:
state
}
def
save_answer
(
self
,
get
,
system
):
def
save_answer
(
self
,
data
,
system
):
"""
Saves a student answer
@param
get: AJAX get
dictionary
@param
data: AJAX
dictionary
@param system: modulesystem
@return: Success indicator
"""
...
...
@@ -644,17 +644,17 @@ class OpenEndedModule(openendedchild.OpenEndedChild):
return
msg
if
self
.
child_state
!=
self
.
INITIAL
:
return
self
.
out_of_sync_error
(
get
)
return
self
.
out_of_sync_error
(
data
)
# add new history element with answer and empty score and hint.
success
,
get
=
self
.
append_image_to_student_answer
(
get
)
success
,
data
=
self
.
append_image_to_student_answer
(
data
)
error_message
=
""
if
success
:
success
,
allowed_to_submit
,
error_message
=
self
.
check_if_student_can_submit
()
if
allowed_to_submit
:
get
[
'student_answer'
]
=
OpenEndedModule
.
sanitize_html
(
get
[
'student_answer'
])
self
.
new_history_entry
(
get
[
'student_answer'
])
self
.
send_to_grader
(
get
[
'student_answer'
],
system
)
data
[
'student_answer'
]
=
OpenEndedModule
.
sanitize_html
(
data
[
'student_answer'
])
self
.
new_history_entry
(
data
[
'student_answer'
])
self
.
send_to_grader
(
data
[
'student_answer'
],
system
)
self
.
change_state
(
self
.
ASSESSING
)
else
:
# Error message already defined
...
...
@@ -666,17 +666,17 @@ class OpenEndedModule(openendedchild.OpenEndedChild):
return
{
'success'
:
success
,
'error'
:
error_message
,
'student_response'
:
get
[
'student_answer'
]
'student_response'
:
data
[
'student_answer'
]
}
def
update_score
(
self
,
get
,
system
):
def
update_score
(
self
,
data
,
system
):
"""
Updates the current score via ajax. Called by xqueue.
Input: AJAX
get
dictionary, modulesystem
Input: AJAX
data
dictionary, modulesystem
Output: None
"""
queuekey
=
get
[
'queuekey'
]
score_msg
=
get
[
'xqueue_body'
]
queuekey
=
data
[
'queuekey'
]
score_msg
=
data
[
'xqueue_body'
]
# TODO: Remove need for cmap
self
.
_update_score
(
score_msg
,
queuekey
,
system
)
...
...
common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py
View file @
e4ee1c6c
...
...
@@ -272,13 +272,13 @@ class OpenEndedChild(object):
return
None
return
None
def
out_of_sync_error
(
self
,
get
,
msg
=
''
):
def
out_of_sync_error
(
self
,
data
,
msg
=
''
):
"""
return dict out-of-sync error message, and also log.
"""
# This is a dev_facing_error
log
.
warning
(
"Open ended child state out sync. state:
%
r,
get
:
%
r.
%
s"
,
self
.
child_state
,
get
,
msg
)
log
.
warning
(
"Open ended child state out sync. state:
%
r,
data
:
%
r.
%
s"
,
self
.
child_state
,
data
,
msg
)
# This is a student_facing_error
return
{
'success'
:
False
,
'error'
:
'The problem state got out-of-sync. Please try reloading the page.'
}
...
...
@@ -345,24 +345,24 @@ class OpenEndedChild(object):
return
success
,
image_ok
,
s3_public_url
def
check_for_image_and_upload
(
self
,
get_
data
):
def
check_for_image_and_upload
(
self
,
data
):
"""
Checks to see if an image was passed back in the AJAX query. If so, it will upload it to S3
@param
get_data: AJAX get
data
@return: Success, whether or not a file was in the
get
dictionary,
@param
data: AJAX
data
@return: Success, whether or not a file was in the
data
dictionary,
and the html corresponding to the uploaded image
"""
has_file_to_upload
=
False
uploaded_to_s3
=
False
image_tag
=
""
image_ok
=
False
if
'can_upload_files'
in
get_
data
:
if
get_
data
[
'can_upload_files'
]
in
[
'true'
,
'1'
]:
if
'can_upload_files'
in
data
:
if
data
[
'can_upload_files'
]
in
[
'true'
,
'1'
]:
has_file_to_upload
=
True
file
=
get_
data
[
'student_file'
][
0
]
uploaded_to_s3
,
image_ok
,
s3_public_url
=
self
.
upload_image_to_s3
(
file
)
student_file
=
data
[
'student_file'
][
0
]
uploaded_to_s3
,
image_ok
,
s3_public_url
=
self
.
upload_image_to_s3
(
student_
file
)
if
uploaded_to_s3
:
image_tag
=
self
.
generate_image_tag_from_url
(
s3_public_url
,
file
.
name
)
image_tag
=
self
.
generate_image_tag_from_url
(
s3_public_url
,
student_
file
.
name
)
return
has_file_to_upload
,
uploaded_to_s3
,
image_ok
,
image_tag
...
...
@@ -371,27 +371,27 @@ class OpenEndedChild(object):
Makes an image tag from a given URL
@param s3_public_url: URL of the image
@param image_name: Name of the image
@return: Boolean success, updated AJAX
get
data
@return: Boolean success, updated AJAX data
"""
image_template
=
"""
<a href="{0}" target="_blank">{1}</a>
"""
.
format
(
s3_public_url
,
image_name
)
return
image_template
def
append_image_to_student_answer
(
self
,
get_
data
):
def
append_image_to_student_answer
(
self
,
data
):
"""
Adds an image to a student answer after uploading it to S3
@param
get_data: AJAx get
data
@return: Boolean success, updated AJAX
get
data
@param
data: AJAx
data
@return: Boolean success, updated AJAX data
"""
overall_success
=
False
if
not
self
.
accept_file_upload
:
# If the question does not accept file uploads, do not do anything
return
True
,
get_
data
return
True
,
data
has_file_to_upload
,
uploaded_to_s3
,
image_ok
,
image_tag
=
self
.
check_for_image_and_upload
(
get_
data
)
has_file_to_upload
,
uploaded_to_s3
,
image_ok
,
image_tag
=
self
.
check_for_image_and_upload
(
data
)
if
uploaded_to_s3
and
has_file_to_upload
and
image_ok
:
get_
data
[
'student_answer'
]
+=
image_tag
data
[
'student_answer'
]
+=
image_tag
overall_success
=
True
elif
has_file_to_upload
and
not
uploaded_to_s3
and
image_ok
:
# In this case, an image was submitted by the student, but the image could not be uploaded to S3. Likely
...
...
@@ -403,12 +403,12 @@ class OpenEndedChild(object):
overall_success
=
True
elif
not
has_file_to_upload
:
# If there is no file to upload, probably the student has embedded the link in the answer text
success
,
get_data
[
'student_answer'
]
=
self
.
check_for_url_in_text
(
get_
data
[
'student_answer'
])
success
,
data
[
'student_answer'
]
=
self
.
check_for_url_in_text
(
data
[
'student_answer'
])
overall_success
=
success
# log.debug("Has file: {0} Uploaded: {1} Image Ok: {2}".format(has_file_to_upload, uploaded_to_s3, image_ok))
return
overall_success
,
get_
data
return
overall_success
,
data
def
check_for_url_in_text
(
self
,
string
):
"""
...
...
common/lib/xmodule/xmodule/open_ended_grading_classes/self_assessment_module.py
View file @
e4ee1c6c
...
...
@@ -75,10 +75,10 @@ class SelfAssessmentModule(openendedchild.OpenEndedChild):
html
=
system
.
render_template
(
'{0}/self_assessment_prompt.html'
.
format
(
self
.
TEMPLATE_DIR
),
context
)
return
html
def
handle_ajax
(
self
,
dispatch
,
get
,
system
):
def
handle_ajax
(
self
,
dispatch
,
data
,
system
):
"""
This is called by courseware.module_render, to handle an AJAX call.
"
get
" is request.POST.
"
data
" is request.POST.
Returns a json dictionary:
{ 'progress_changed' : True/False,
...
...
@@ -99,7 +99,7 @@ class SelfAssessmentModule(openendedchild.OpenEndedChild):
return
json
.
dumps
({
'error'
:
'Error handling action. Please try again.'
,
'success'
:
False
})
before
=
self
.
get_progress
()
d
=
handlers
[
dispatch
](
get
,
system
)
d
=
handlers
[
dispatch
](
data
,
system
)
after
=
self
.
get_progress
()
d
.
update
({
'progress_changed'
:
after
!=
before
,
...
...
@@ -160,12 +160,12 @@ class SelfAssessmentModule(openendedchild.OpenEndedChild):
return
system
.
render_template
(
'{0}/self_assessment_hint.html'
.
format
(
self
.
TEMPLATE_DIR
),
context
)
def
save_answer
(
self
,
get
,
system
):
def
save_answer
(
self
,
data
,
system
):
"""
After the answer is submitted, show the rubric.
Args:
get: the GET
dictionary passed to the ajax request. Should contain
data: the request
dictionary passed to the ajax request. Should contain
a key 'student_answer'
Returns:
...
...
@@ -178,16 +178,16 @@ class SelfAssessmentModule(openendedchild.OpenEndedChild):
return
msg
if
self
.
child_state
!=
self
.
INITIAL
:
return
self
.
out_of_sync_error
(
get
)
return
self
.
out_of_sync_error
(
data
)
error_message
=
""
# add new history element with answer and empty score and hint.
success
,
get
=
self
.
append_image_to_student_answer
(
get
)
success
,
data
=
self
.
append_image_to_student_answer
(
data
)
if
success
:
success
,
allowed_to_submit
,
error_message
=
self
.
check_if_student_can_submit
()
if
allowed_to_submit
:
get
[
'student_answer'
]
=
SelfAssessmentModule
.
sanitize_html
(
get
[
'student_answer'
])
self
.
new_history_entry
(
get
[
'student_answer'
])
data
[
'student_answer'
]
=
SelfAssessmentModule
.
sanitize_html
(
data
[
'student_answer'
])
self
.
new_history_entry
(
data
[
'student_answer'
])
self
.
change_state
(
self
.
ASSESSING
)
else
:
# Error message already defined
...
...
@@ -200,10 +200,10 @@ class SelfAssessmentModule(openendedchild.OpenEndedChild):
'success'
:
success
,
'rubric_html'
:
self
.
get_rubric_html
(
system
),
'error'
:
error_message
,
'student_response'
:
get
[
'student_answer'
],
'student_response'
:
data
[
'student_answer'
],
}
def
save_assessment
(
self
,
get
,
system
):
def
save_assessment
(
self
,
data
,
_
system
):
"""
Save the assessment. If the student said they're right, don't ask for a
hint, and go straight to the done state. Otherwise, do ask for a hint.
...
...
@@ -219,11 +219,11 @@ class SelfAssessmentModule(openendedchild.OpenEndedChild):
"""
if
self
.
child_state
!=
self
.
ASSESSING
:
return
self
.
out_of_sync_error
(
get
)
return
self
.
out_of_sync_error
(
data
)
try
:
score
=
int
(
get
[
'assessment'
])
score_list
=
get
.
getlist
(
'score_list[]'
)
score
=
int
(
data
[
'assessment'
])
score_list
=
data
.
getlist
(
'score_list[]'
)
for
i
in
xrange
(
0
,
len
(
score_list
)):
score_list
[
i
]
=
int
(
score_list
[
i
])
except
ValueError
:
...
...
@@ -244,7 +244,7 @@ class SelfAssessmentModule(openendedchild.OpenEndedChild):
d
[
'state'
]
=
self
.
child_state
return
d
def
save_hint
(
self
,
get
,
system
):
def
save_hint
(
self
,
data
,
_
system
):
'''
Not used currently, as hints have been removed from the system.
Save the hint.
...
...
@@ -258,9 +258,9 @@ class SelfAssessmentModule(openendedchild.OpenEndedChild):
if
self
.
child_state
!=
self
.
POST_ASSESSMENT
:
# Note: because we only ask for hints on wrong answers, may not have
# the same number of hints and answers.
return
self
.
out_of_sync_error
(
get
)
return
self
.
out_of_sync_error
(
data
)
self
.
record_latest_post_assessment
(
get
[
'hint'
])
self
.
record_latest_post_assessment
(
data
[
'hint'
])
self
.
change_state
(
self
.
DONE
)
return
{
'success'
:
True
,
...
...
common/lib/xmodule/xmodule/peer_grading_module.py
View file @
e4ee1c6c
...
...
@@ -133,8 +133,8 @@ class PeerGradingModule(PeerGradingFields, XModule):
"""
return
{
'success'
:
False
,
'error'
:
msg
}
def
_check_required
(
self
,
get
,
required
):
actual
=
set
(
get
.
keys
())
def
_check_required
(
self
,
data
,
required
):
actual
=
set
(
data
.
keys
())
missing
=
required
-
actual
if
len
(
missing
)
>
0
:
return
False
,
"Missing required keys: {0}"
.
format
(
', '
.
join
(
missing
))
...
...
@@ -153,7 +153,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
else
:
return
self
.
peer_grading_problem
({
'location'
:
self
.
link_to_location
})[
'html'
]
def
handle_ajax
(
self
,
dispatch
,
get
):
def
handle_ajax
(
self
,
dispatch
,
data
):
"""
Needs to be implemented by child modules. Handles AJAX events.
@return:
...
...
@@ -173,7 +173,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
# This is a dev_facing_error
return
json
.
dumps
({
'error'
:
'Error handling action. Please try again.'
,
'success'
:
False
})
d
=
handlers
[
dispatch
](
get
)
d
=
handlers
[
dispatch
](
data
)
return
json
.
dumps
(
d
,
cls
=
ComplexEncoder
)
...
...
@@ -244,7 +244,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
max_grade
=
self
.
max_grade
return
max_grade
def
get_next_submission
(
self
,
get
):
def
get_next_submission
(
self
,
data
):
"""
Makes a call to the grading controller for the next essay that should be graded
Returns a json dict with the following keys:
...
...
@@ -263,11 +263,11 @@ class PeerGradingModule(PeerGradingFields, XModule):
'error': if success is False, will have an error message with more info.
"""
required
=
set
([
'location'
])
success
,
message
=
self
.
_check_required
(
get
,
required
)
success
,
message
=
self
.
_check_required
(
data
,
required
)
if
not
success
:
return
self
.
_err_response
(
message
)
grader_id
=
self
.
system
.
anonymous_student_id
location
=
get
[
'location'
]
location
=
data
[
'location'
]
try
:
response
=
self
.
peer_gs
.
get_next_submission
(
location
,
grader_id
)
...
...
@@ -280,7 +280,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
return
{
'success'
:
False
,
'error'
:
EXTERNAL_GRADER_NO_CONTACT_ERROR
}
def
save_grade
(
self
,
get
):
def
save_grade
(
self
,
data
):
"""
Saves the grade of a given submission.
Input:
...
...
@@ -298,18 +298,18 @@ class PeerGradingModule(PeerGradingFields, XModule):
required
=
set
([
'location'
,
'submission_id'
,
'submission_key'
,
'score'
,
'feedback'
,
'rubric_scores[]'
,
'submission_flagged'
])
success
,
message
=
self
.
_check_required
(
get
,
required
)
success
,
message
=
self
.
_check_required
(
data
,
required
)
if
not
success
:
return
self
.
_err_response
(
message
)
grader_id
=
self
.
system
.
anonymous_student_id
location
=
get
.
get
(
'location'
)
submission_id
=
get
.
get
(
'submission_id'
)
score
=
get
.
get
(
'score'
)
feedback
=
get
.
get
(
'feedback'
)
submission_key
=
get
.
get
(
'submission_key'
)
rubric_scores
=
get
.
getlist
(
'rubric_scores[]'
)
submission_flagged
=
get
.
get
(
'submission_flagged'
)
location
=
data
.
get
(
'location'
)
submission_id
=
data
.
get
(
'submission_id'
)
score
=
data
.
get
(
'score'
)
feedback
=
data
.
get
(
'feedback'
)
submission_key
=
data
.
get
(
'submission_key'
)
rubric_scores
=
data
.
getlist
(
'rubric_scores[]'
)
submission_flagged
=
data
.
get
(
'submission_flagged'
)
try
:
response
=
self
.
peer_gs
.
save_grade
(
location
,
grader_id
,
submission_id
,
...
...
@@ -328,7 +328,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
'error'
:
EXTERNAL_GRADER_NO_CONTACT_ERROR
}
def
is_student_calibrated
(
self
,
get
):
def
is_student_calibrated
(
self
,
data
):
"""
Calls the grading controller to see if the given student is calibrated
on the given problem
...
...
@@ -347,12 +347,12 @@ class PeerGradingModule(PeerGradingFields, XModule):
"""
required
=
set
([
'location'
])
success
,
message
=
self
.
_check_required
(
get
,
required
)
success
,
message
=
self
.
_check_required
(
data
,
required
)
if
not
success
:
return
self
.
_err_response
(
message
)
grader_id
=
self
.
system
.
anonymous_student_id
location
=
get
[
'location'
]
location
=
data
[
'location'
]
try
:
response
=
self
.
peer_gs
.
is_student_calibrated
(
location
,
grader_id
)
...
...
@@ -367,7 +367,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
'error'
:
EXTERNAL_GRADER_NO_CONTACT_ERROR
}
def
show_calibration_essay
(
self
,
get
):
def
show_calibration_essay
(
self
,
data
):
"""
Fetch the next calibration essay from the grading controller and return it
Inputs:
...
...
@@ -392,13 +392,13 @@ class PeerGradingModule(PeerGradingFields, XModule):
"""
required
=
set
([
'location'
])
success
,
message
=
self
.
_check_required
(
get
,
required
)
success
,
message
=
self
.
_check_required
(
data
,
required
)
if
not
success
:
return
self
.
_err_response
(
message
)
grader_id
=
self
.
system
.
anonymous_student_id
location
=
get
[
'location'
]
location
=
data
[
'location'
]
try
:
response
=
self
.
peer_gs
.
show_calibration_essay
(
location
,
grader_id
)
return
response
...
...
@@ -417,8 +417,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
return
{
'success'
:
False
,
'error'
:
'Error displaying submission. Please notify course staff.'
}
def
save_calibration_essay
(
self
,
get
):
def
save_calibration_essay
(
self
,
data
):
"""
Saves the grader's grade of a given calibration.
Input:
...
...
@@ -437,17 +436,17 @@ class PeerGradingModule(PeerGradingFields, XModule):
"""
required
=
set
([
'location'
,
'submission_id'
,
'submission_key'
,
'score'
,
'feedback'
,
'rubric_scores[]'
])
success
,
message
=
self
.
_check_required
(
get
,
required
)
success
,
message
=
self
.
_check_required
(
data
,
required
)
if
not
success
:
return
self
.
_err_response
(
message
)
grader_id
=
self
.
system
.
anonymous_student_id
location
=
get
.
get
(
'location'
)
calibration_essay_id
=
get
.
get
(
'submission_id'
)
submission_key
=
get
.
get
(
'submission_key'
)
score
=
get
.
get
(
'score'
)
feedback
=
get
.
get
(
'feedback'
)
rubric_scores
=
get
.
getlist
(
'rubric_scores[]'
)
location
=
data
.
get
(
'location'
)
calibration_essay_id
=
data
.
get
(
'submission_id'
)
submission_key
=
data
.
get
(
'submission_key'
)
score
=
data
.
get
(
'score'
)
feedback
=
data
.
get
(
'feedback'
)
rubric_scores
=
data
.
getlist
(
'rubric_scores[]'
)
try
:
response
=
self
.
peer_gs
.
save_calibration_essay
(
location
,
grader_id
,
calibration_essay_id
,
...
...
@@ -473,8 +472,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
})
return
html
def
peer_grading
(
self
,
get
=
None
):
def
peer_grading
(
self
,
_data
=
None
):
'''
Show a peer grading interface
'''
...
...
@@ -553,11 +551,11 @@ class PeerGradingModule(PeerGradingFields, XModule):
return
html
def
peer_grading_problem
(
self
,
get
=
None
):
def
peer_grading_problem
(
self
,
data
=
None
):
'''
Show individual problem interface
'''
if
get
is
None
or
get
.
get
(
'location'
)
is
None
:
if
data
is
None
or
data
.
get
(
'location'
)
is
None
:
if
not
self
.
use_for_single_location
:
# This is an error case, because it must be set to use a single location to be called without get parameters
# This is a dev_facing_error
...
...
@@ -566,8 +564,8 @@ class PeerGradingModule(PeerGradingFields, XModule):
return
{
'html'
:
""
,
'success'
:
False
}
problem_location
=
self
.
link_to_location
elif
get
.
get
(
'location'
)
is
not
None
:
problem_location
=
get
.
get
(
'location'
)
elif
data
.
get
(
'location'
)
is
not
None
:
problem_location
=
data
.
get
(
'location'
)
ajax_url
=
self
.
ajax_url
html
=
self
.
system
.
render_template
(
'peer_grading/peer_grading_problem.html'
,
{
...
...
@@ -617,4 +615,3 @@ class PeerGradingDescriptor(PeerGradingFields, RawDescriptor):
non_editable_fields
.
extend
([
PeerGradingFields
.
due_date
,
PeerGradingFields
.
grace_period_string
,
PeerGradingFields
.
max_grade
])
return
non_editable_fields
common/lib/xmodule/xmodule/poll_module.py
View file @
e4ee1c6c
...
...
@@ -47,12 +47,12 @@ class PollModule(PollFields, XModule):
css
=
{
'scss'
:
[
resource_string
(
__name__
,
'css/poll/display.scss'
)]}
js_module_name
=
"Poll"
def
handle_ajax
(
self
,
dispatch
,
get
):
def
handle_ajax
(
self
,
dispatch
,
data
):
"""Ajax handler.
Args:
dispatch: string request slug
get: dict request get
parameters
data: dict request data
parameters
Returns:
json string
...
...
common/lib/xmodule/xmodule/seq_module.py
View file @
e4ee1c6c
...
...
@@ -62,10 +62,10 @@ class SequenceModule(SequenceFields, XModule):
progress
=
reduce
(
Progress
.
add_counts
,
progresses
)
return
progress
def
handle_ajax
(
self
,
dispatch
,
get
):
# TODO: bounds checking
def
handle_ajax
(
self
,
dispatch
,
data
):
# TODO: bounds checking
''' get = request.POST instance '''
if
dispatch
==
'goto_position'
:
self
.
position
=
int
(
get
[
'position'
])
self
.
position
=
int
(
data
[
'position'
])
return
json
.
dumps
({
'success'
:
True
})
raise
NotFoundError
(
'Unexpected dispatch type'
)
...
...
common/lib/xmodule/xmodule/tests/test_logic.py
View file @
e4ee1c6c
...
...
@@ -40,9 +40,9 @@ class LogicTest(unittest.TestCase):
self
.
raw_model_data
)
def
ajax_request
(
self
,
dispatch
,
get
):
def
ajax_request
(
self
,
dispatch
,
data
):
"""Call Xmodule.handle_ajax."""
return
json
.
loads
(
self
.
xmodule
.
handle_ajax
(
dispatch
,
get
))
return
json
.
loads
(
self
.
xmodule
.
handle_ajax
(
dispatch
,
data
))
class
PollModuleTest
(
LogicTest
):
...
...
common/lib/xmodule/xmodule/timelimit_module.py
View file @
e4ee1c6c
...
...
@@ -98,7 +98,7 @@ class TimeLimitModule(TimeLimitFields, XModule):
progress
=
reduce
(
Progress
.
add_counts
,
progresses
)
return
progress
def
handle_ajax
(
self
,
dispatch
,
get
):
def
handle_ajax
(
self
,
_dispatch
,
_data
):
raise
NotFoundError
(
'Unexpected dispatch type'
)
def
render
(
self
):
...
...
@@ -141,4 +141,3 @@ class TimeLimitDescriptor(TimeLimitFields, XMLEditingDescriptor, XmlDescriptor):
xml_object
.
append
(
etree
.
fromstring
(
child
.
export_to_xml
(
resource_fs
)))
return
xml_object
common/lib/xmodule/xmodule/video_module.py
View file @
e4ee1c6c
...
...
@@ -54,9 +54,9 @@ class VideoModule(VideoFields, XModule):
def
__init__
(
self
,
*
args
,
**
kwargs
):
XModule
.
__init__
(
self
,
*
args
,
**
kwargs
)
def
handle_ajax
(
self
,
dispatch
,
get
):
def
handle_ajax
(
self
,
dispatch
,
data
):
"""This is not being called right now and we raise 404 error."""
log
.
debug
(
u"GET {0}"
.
format
(
get
))
log
.
debug
(
u"GET {0}"
.
format
(
data
))
log
.
debug
(
u"DISPATCH {0}"
.
format
(
dispatch
))
raise
Http404
()
...
...
common/lib/xmodule/xmodule/videoalpha_module.py
View file @
e4ee1c6c
...
...
@@ -125,9 +125,9 @@ class VideoAlphaModule(VideoAlphaFields, XModule):
return
parse_time
(
xmltree
.
get
(
'start_time'
)),
parse_time
(
xmltree
.
get
(
'end_time'
))
def
handle_ajax
(
self
,
dispatch
,
get
):
def
handle_ajax
(
self
,
dispatch
,
data
):
"""This is not being called right now and we raise 404 error."""
log
.
debug
(
u"GET {0}"
.
format
(
get
))
log
.
debug
(
u"GET {0}"
.
format
(
data
))
log
.
debug
(
u"DISPATCH {0}"
.
format
(
dispatch
))
raise
Http404
()
...
...
common/lib/xmodule/xmodule/word_cloud_module.py
View file @
e4ee1c6c
...
...
@@ -168,12 +168,12 @@ class WordCloudModule(WordCloudFields, XModule):
)[:
amount
]
)
def
handle_ajax
(
self
,
dispatch
,
post
):
def
handle_ajax
(
self
,
dispatch
,
data
):
"""Ajax handler.
Args:
dispatch: string request slug
post
: dict request get parameters
data
: dict request get parameters
Returns:
json string
...
...
@@ -187,7 +187,7 @@ class WordCloudModule(WordCloudFields, XModule):
# Student words from client.
# FIXME: we must use raw JSON, not a post data (multipart/form-data)
raw_student_words
=
post
.
getlist
(
'student_words[]'
)
raw_student_words
=
data
.
getlist
(
'student_words[]'
)
student_words
=
filter
(
None
,
map
(
self
.
good_word
,
raw_student_words
))
self
.
student_words
=
student_words
...
...
common/lib/xmodule/xmodule/x_module.py
View file @
e4ee1c6c
...
...
@@ -272,9 +272,9 @@ class XModule(XModuleFields, HTMLSnippet, XBlock):
'''
return
None
def
handle_ajax
(
self
,
_dispatch
,
_
get
):
def
handle_ajax
(
self
,
_dispatch
,
_
data
):
''' dispatch is last part of the URL.
get is a dictionary-like object
'''
data is a dictionary-like object with the content of the request
'''
return
""
...
...
lms/djangoapps/courseware/module_render.py
View file @
e4ee1c6c
...
...
@@ -223,7 +223,7 @@ def get_module_for_descriptor_internal(user, descriptor, model_data_cache, cours
relative_xqueue_callback_url
=
reverse
(
'xqueue_callback'
,
kwargs
=
dict
(
course_id
=
course_id
,
userid
=
str
(
user
.
id
),
id
=
descriptor
.
location
.
url
(),
mod_
id
=
descriptor
.
location
.
url
(),
dispatch
=
dispatch
),
)
return
xqueue_callback_url_prefix
+
relative_xqueue_callback_url
...
...
@@ -399,40 +399,47 @@ def get_module_for_descriptor_internal(user, descriptor, model_data_cache, cours
@csrf_exempt
def
xqueue_callback
(
request
,
course_id
,
userid
,
id
,
dispatch
):
def
xqueue_callback
(
request
,
course_id
,
userid
,
mod_
id
,
dispatch
):
'''
Entry point for graded results from the queueing system.
'''
data
=
request
.
POST
.
copy
()
# Test xqueue package, which we expect to be:
# xpackage = {'xqueue_header': json.dumps({'lms_key':'secretkey',...}),
# 'xqueue_body' : 'Message from grader'}
get
=
request
.
POST
.
copy
()
for
key
in
[
'xqueue_header'
,
'xqueue_body'
]:
if
not
get
.
has_key
(
key
)
:
if
key
not
in
data
:
raise
Http404
header
=
json
.
loads
(
get
[
'xqueue_header'
])
if
not
isinstance
(
header
,
dict
)
or
not
header
.
has_key
(
'lms_key'
):
header
=
json
.
loads
(
data
[
'xqueue_header'
])
if
not
isinstance
(
header
,
dict
)
or
'lms_key'
not
in
header
:
raise
Http404
# Retrieve target StudentModule
user
=
User
.
objects
.
get
(
id
=
userid
)
model_data_cache
=
ModelDataCache
.
cache_for_descriptor_descendents
(
course_id
,
user
,
modulestore
()
.
get_instance
(
course_id
,
id
),
depth
=
0
,
select_for_update
=
True
)
instance
=
get_module
(
user
,
request
,
id
,
model_data_cache
,
course_id
,
grade_bucket_type
=
'xqueue'
)
model_data_cache
=
ModelDataCache
.
cache_for_descriptor_descendents
(
course_id
,
user
,
modulestore
()
.
get_instance
(
course_id
,
mod_id
),
depth
=
0
,
select_for_update
=
True
)
instance
=
get_module
(
user
,
request
,
mod_id
,
model_data_cache
,
course_id
,
grade_bucket_type
=
'xqueue'
)
if
instance
is
None
:
log
.
debug
(
"No module {0} for user {1}--access denied?"
.
format
(
id
,
user
))
msg
=
"No module {0} for user {1}--access denied?"
.
format
(
mod_id
,
user
)
log
.
debug
(
msg
)
raise
Http404
# Transfer 'queuekey' from xqueue response header to
'get'. This is required to
#
use the interface defined by 'handle_ajax'
get
.
update
({
'queuekey'
:
header
[
'lms_key'
]})
# Transfer 'queuekey' from xqueue response header to
the data.
#
This is required to
use the interface defined by 'handle_ajax'
data
.
update
({
'queuekey'
:
header
[
'lms_key'
]})
# We go through the "AJAX" path
#
So far, the only dispatch from xqueue will be 'score_update'
# So far, the only dispatch from xqueue will be 'score_update'
try
:
# Can ignore the return value--not used for xqueue_callback
instance
.
handle_ajax
(
dispatch
,
get
)
instance
.
handle_ajax
(
dispatch
,
data
)
except
:
log
.
exception
(
"error processing ajax call"
)
raise
...
...
@@ -466,23 +473,15 @@ def modx_dispatch(request, dispatch, location, course_id):
if
not
request
.
user
.
is_authenticated
():
raise
PermissionDenied
# Check for submitted files and basic file size checks
p
=
request
.
POST
.
copy
()
if
request
.
FILES
:
for
fileinput_id
in
request
.
FILES
.
keys
():
inputfiles
=
request
.
FILES
.
getlist
(
fileinput_id
)
# Get the submitted data
data
=
request
.
POST
.
copy
()
if
len
(
inputfiles
)
>
settings
.
MAX_FILEUPLOADS_PER_INPUT
:
too_many_files_msg
=
'Submission aborted! Maximum
%
d files may be submitted at once'
%
\
settings
.
MAX_FILEUPLOADS_PER_INPUT
return
HttpResponse
(
json
.
dumps
({
'success'
:
too_many_files_msg
}))
for
inputfile
in
inputfiles
:
if
inputfile
.
size
>
settings
.
STUDENT_FILEUPLOAD_MAX_SIZE
:
# Bytes
file_too_big_msg
=
'Submission aborted! Your file "
%
s" is too large (max size:
%
d MB)'
%
\
(
inputfile
.
name
,
settings
.
STUDENT_FILEUPLOAD_MAX_SIZE
/
(
1000
**
2
))
return
HttpResponse
(
json
.
dumps
({
'success'
:
file_too_big_msg
}))
p
[
fileinput_id
]
=
inputfiles
# Get and check submitted files
files
=
request
.
FILES
or
{}
error_msg
=
_check_files_limits
(
files
)
if
error_msg
:
return
HttpResponse
(
json
.
dumps
({
'success'
:
error_msg
}))
data
.
update
(
files
)
# Merge files into data dictionary
try
:
descriptor
=
modulestore
()
.
get_instance
(
course_id
,
location
)
...
...
@@ -495,8 +494,11 @@ def modx_dispatch(request, dispatch, location, course_id):
)
raise
Http404
model_data_cache
=
ModelDataCache
.
cache_for_descriptor_descendents
(
course_id
,
request
.
user
,
descriptor
)
model_data_cache
=
ModelDataCache
.
cache_for_descriptor_descendents
(
course_id
,
request
.
user
,
descriptor
)
instance
=
get_module
(
request
.
user
,
request
,
location
,
model_data_cache
,
course_id
,
grade_bucket_type
=
'ajax'
)
if
instance
is
None
:
...
...
@@ -507,7 +509,7 @@ def modx_dispatch(request, dispatch, location, course_id):
# Let the module handle the AJAX
try
:
ajax_return
=
instance
.
handle_ajax
(
dispatch
,
p
)
ajax_return
=
instance
.
handle_ajax
(
dispatch
,
data
)
# If we can't find the module, respond with a 404
except
NotFoundError
:
...
...
@@ -529,7 +531,6 @@ def modx_dispatch(request, dispatch, location, course_id):
return
HttpResponse
(
ajax_return
)
def
get_score_bucket
(
grade
,
max_grade
):
"""
Function to split arbitrary score ranges into 3 buckets.
...
...
@@ -542,3 +543,30 @@ def get_score_bucket(grade, max_grade):
score_bucket
=
"correct"
return
score_bucket
def
_check_files_limits
(
files
):
"""
Check if the files in a request are under the limits defined by
`settings.MAX_FILEUPLOADS_PER_INPUT` and
`settings.STUDENT_FILEUPLOAD_MAX_SIZE`.
Returns None if files are correct or an error messages otherwise.
"""
for
fileinput_id
in
files
.
keys
():
inputfiles
=
files
.
getlist
(
fileinput_id
)
# Check number of files submitted
if
len
(
inputfiles
)
>
settings
.
MAX_FILEUPLOADS_PER_INPUT
:
msg
=
'Submission aborted! Maximum
%
d files may be submitted at once'
%
\
settings
.
MAX_FILEUPLOADS_PER_INPUT
return
msg
# Check file sizes
for
inputfile
in
inputfiles
:
if
inputfile
.
size
>
settings
.
STUDENT_FILEUPLOAD_MAX_SIZE
:
# Bytes
msg
=
'Submission aborted! Your file "
%
s" is too large (max size:
%
d MB)'
%
\
(
inputfile
.
name
,
settings
.
STUDENT_FILEUPLOAD_MAX_SIZE
/
(
1000
**
2
))
return
msg
return
None
lms/urls.py
View file @
e4ee1c6c
...
...
@@ -188,7 +188,7 @@ if settings.COURSEWARE_ENABLED:
# into the database.
url
(
r'^software-licenses$'
,
'licenses.views.user_software_license'
,
name
=
"user_software_license"
),
url
(
r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/xqueue/(?P<userid>[^/]*)/(?P<id>.*?)/(?P<dispatch>[^/]*)$'
,
url
(
r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/xqueue/(?P<userid>[^/]*)/(?P<
mod_
id>.*?)/(?P<dispatch>[^/]*)$'
,
'courseware.module_render.xqueue_callback'
,
name
=
'xqueue_callback'
),
url
(
r'^change_setting$'
,
'student.views.change_setting'
,
...
...
@@ -438,5 +438,3 @@ if settings.DEBUG:
#Custom error pages
handler404
=
'static_template_view.views.render_404'
handler500
=
'static_template_view.views.render_500'
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment