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
20118614
Commit
20118614
authored
Jun 27, 2012
by
Calen Pennington
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Get capa problems to display from a keystore
parent
69873495
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
97 additions
and
170 deletions
+97
-170
common/lib/xmodule/capa_module.py
+57
-67
common/lib/xmodule/setup.py
+2
-1
common/lib/xmodule/vertical_module.py
+4
-1
lms/djangoapps/courseware/module_render.py
+20
-87
lms/lib/dogfood/views.py
+1
-1
lms/static/coffee/src/courseware.coffee
+2
-2
lms/static/coffee/src/modules/problem.coffee
+8
-8
lms/static/coffee/src/modules/sequence.coffee
+1
-1
lms/templates/problem_ajax.html
+1
-1
lms/urls.py
+1
-1
No files found.
common/lib/xmodule/capa_module.py
View file @
20118614
...
@@ -10,8 +10,8 @@ import StringIO
...
@@ -10,8 +10,8 @@ import StringIO
from
datetime
import
timedelta
from
datetime
import
timedelta
from
lxml
import
etree
from
lxml
import
etree
from
x_module
import
XModule
from
x
module.x
_module
import
XModule
from
mako_module
import
MakoModule
Descriptor
from
xmodule.raw_module
import
Raw
Descriptor
from
progress
import
Progress
from
progress
import
Progress
from
capa.capa_problem
import
LoncapaProblem
from
capa.capa_problem
import
LoncapaProblem
from
capa.responsetypes
import
StudentInputError
from
capa.responsetypes
import
StudentInputError
...
@@ -64,37 +64,25 @@ class ComplexEncoder(json.JSONEncoder):
...
@@ -64,37 +64,25 @@ class ComplexEncoder(json.JSONEncoder):
return
json
.
JSONEncoder
.
default
(
self
,
obj
)
return
json
.
JSONEncoder
.
default
(
self
,
obj
)
class
CapaModuleDescriptor
(
MakoModuleDescriptor
):
class
CapaModule
(
XModule
):
"""
Module implementing problems in the LON-CAPA format,
as implemented by capa.capa_problem
"""
mako_template
=
'widgets/problem-edit.html'
class
Module
(
XModule
):
''' Interface between capa_problem and x_module. Originally a hack
''' Interface between capa_problem and x_module. Originally a hack
meant to be refactored out, but it seems to be serving a useful
meant to be refactored out, but it seems to be serving a useful
prupose now. We can e.g .destroy and create the capa_problem on a
prupose now. We can e.g .destroy and create the capa_problem on a
reset.
reset.
'''
'''
icon_class
=
'problem'
def
get_instance_state
(
self
):
def
get_instance_state
(
self
):
state
=
self
.
lcp
.
get_state
()
state
=
self
.
lcp
.
get_state
()
state
[
'attempts'
]
=
self
.
attempts
state
[
'attempts'
]
=
self
.
attempts
return
json
.
dumps
(
state
)
return
json
.
dumps
(
state
)
def
get_score
(
self
):
def
get_score
(
self
):
return
self
.
lcp
.
get_score
()
return
self
.
lcp
.
get_score
()
def
max_score
(
self
):
def
max_score
(
self
):
return
self
.
lcp
.
get_max_score
()
return
self
.
lcp
.
get_max_score
()
def
get_progress
(
self
):
def
get_progress
(
self
):
''' For now, just return score / max_score
''' For now, just return score / max_score
'''
'''
...
@@ -105,14 +93,13 @@ class Module(XModule):
...
@@ -105,14 +93,13 @@ class Module(XModule):
return
Progress
(
score
,
total
)
return
Progress
(
score
,
total
)
return
None
return
None
def
get_html
(
self
):
def
get_html
(
self
):
return
self
.
system
.
render_template
(
'problem_ajax.html'
,
{
return
self
.
system
.
render_template
(
'problem_ajax.html'
,
{
'id'
:
self
.
item_id
,
'element_id'
:
self
.
location
.
html_id
(),
'ajax_url'
:
self
.
ajax_url
,
'id'
:
self
.
id
,
'ajax_url'
:
self
.
system
.
ajax_url
,
})
})
def
get_problem_html
(
self
,
encapsulate
=
True
):
def
get_problem_html
(
self
,
encapsulate
=
True
):
'''Return html for the problem. Adds check, reset, save buttons
'''Return html for the problem. Adds check, reset, save buttons
as necessary based on the problem config and state.'''
as necessary based on the problem config and state.'''
...
@@ -165,12 +152,12 @@ class Module(XModule):
...
@@ -165,12 +152,12 @@ class Module(XModule):
explain
=
False
explain
=
False
context
=
{
'problem'
:
content
,
context
=
{
'problem'
:
content
,
'id'
:
self
.
i
tem_i
d
,
'id'
:
self
.
id
,
'check_button'
:
check_button
,
'check_button'
:
check_button
,
'reset_button'
:
reset_button
,
'reset_button'
:
reset_button
,
'save_button'
:
save_button
,
'save_button'
:
save_button
,
'answer_available'
:
self
.
answer_available
(),
'answer_available'
:
self
.
answer_available
(),
'ajax_url'
:
self
.
ajax_url
,
'ajax_url'
:
self
.
system
.
ajax_url
,
'attempts_used'
:
self
.
attempts
,
'attempts_used'
:
self
.
attempts
,
'attempts_allowed'
:
self
.
max_attempts
,
'attempts_allowed'
:
self
.
max_attempts
,
'explain'
:
explain
,
'explain'
:
explain
,
...
@@ -180,17 +167,17 @@ class Module(XModule):
...
@@ -180,17 +167,17 @@ class Module(XModule):
html
=
self
.
system
.
render_template
(
'problem.html'
,
context
)
html
=
self
.
system
.
render_template
(
'problem.html'
,
context
)
if
encapsulate
:
if
encapsulate
:
html
=
'<div id="problem_{id}" class="problem" data-url="{ajax_url}">'
.
format
(
html
=
'<div id="problem_{id}" class="problem" data-url="{ajax_url}">'
.
format
(
id
=
self
.
item_id
,
ajax_url
=
self
.
ajax_url
)
+
html
+
"</div>"
id
=
self
.
location
.
html_id
(),
ajax_url
=
self
.
system
.
ajax_url
)
+
html
+
"</div>"
return
html
return
html
def
__init__
(
self
,
system
,
xml
,
item_id
,
instance_state
=
None
,
shared_state
=
None
):
def
__init__
(
self
,
system
,
location
,
definition
,
instance_state
=
None
,
shared_state
=
None
,
**
kwargs
):
XModule
.
__init__
(
self
,
system
,
xml
,
item_id
,
instance_state
,
shared_state
)
XModule
.
__init__
(
self
,
system
,
location
,
definition
,
instance_state
,
shared_state
,
**
kwargs
)
self
.
attempts
=
0
self
.
attempts
=
0
self
.
max_attempts
=
None
self
.
max_attempts
=
None
dom2
=
etree
.
fromstring
(
xml
)
dom2
=
etree
.
fromstring
(
definition
[
'data'
]
)
self
.
explanation
=
"problems/"
+
only_one
(
dom2
.
xpath
(
'/problem/@explain'
),
self
.
explanation
=
"problems/"
+
only_one
(
dom2
.
xpath
(
'/problem/@explain'
),
default
=
"closed"
)
default
=
"closed"
)
...
@@ -205,7 +192,7 @@ class Module(XModule):
...
@@ -205,7 +192,7 @@ class Module(XModule):
self
.
display_due_date
=
None
self
.
display_due_date
=
None
grace_period_string
=
only_one
(
dom2
.
xpath
(
'/problem/@graceperiod'
))
grace_period_string
=
only_one
(
dom2
.
xpath
(
'/problem/@graceperiod'
))
if
len
(
grace_period_string
)
>
0
and
self
.
display_due_date
:
if
len
(
grace_period_string
)
>
0
and
self
.
display_due_date
:
self
.
grace_period
=
parse_timedelta
(
grace_period_string
)
self
.
grace_period
=
parse_timedelta
(
grace_period_string
)
self
.
close_date
=
self
.
display_due_date
+
self
.
grace_period
self
.
close_date
=
self
.
display_due_date
+
self
.
grace_period
#log.debug("Then parsed " + grace_period_string + " to closing date" + str(self.close_date))
#log.debug("Then parsed " + grace_period_string + " to closing date" + str(self.close_date))
...
@@ -240,9 +227,9 @@ class Module(XModule):
...
@@ -240,9 +227,9 @@ class Module(XModule):
self
.
attempts
=
instance_state
[
'attempts'
]
self
.
attempts
=
instance_state
[
'attempts'
]
# TODO: Should be: self.filename=only_one(dom2.xpath('/problem/@filename'))
# TODO: Should be: self.filename=only_one(dom2.xpath('/problem/@filename'))
self
.
filename
=
"problems/"
+
only_one
(
dom2
.
xpath
(
'/problem/@filename'
))
+
".xml"
self
.
filename
=
"problems/"
+
only_one
(
dom2
.
xpath
(
'/problem/@filename'
))
+
".xml"
self
.
name
=
only_one
(
dom2
.
xpath
(
'/problem/@name'
))
self
.
name
=
only_one
(
dom2
.
xpath
(
'/problem/@name'
))
self
.
weight
=
only_one
(
dom2
.
xpath
(
'/problem/@weight'
))
self
.
weight
=
only_one
(
dom2
.
xpath
(
'/problem/@weight'
))
if
self
.
rerandomize
==
'never'
:
if
self
.
rerandomize
==
'never'
:
seed
=
1
seed
=
1
elif
self
.
rerandomize
==
"per_student"
and
hasattr
(
system
,
'id'
):
elif
self
.
rerandomize
==
"per_student"
and
hasattr
(
system
,
'id'
):
...
@@ -250,27 +237,27 @@ class Module(XModule):
...
@@ -250,27 +237,27 @@ class Module(XModule):
else
:
else
:
seed
=
None
seed
=
None
try
:
try
:
fp
=
self
.
filestore
.
open
(
self
.
filename
)
fp
=
self
.
system
.
filestore
.
open
(
self
.
filename
)
except
Exception
,
err
:
except
Exception
:
log
.
exception
(
'
[courseware.capa.capa_module.Module.init] error
%
s: cannot open file
%
s'
%
(
err
,
self
.
filename
)
)
log
.
exception
(
'
cannot open file
%
s'
%
self
.
filename
)
if
self
.
DEBUG
:
if
self
.
system
.
DEBUG
:
# create a dummy problem instead of failing
# create a dummy problem instead of failing
fp
=
StringIO
.
StringIO
(
'<problem><text><font color="red" size="+2">Problem file
%
s is missing</font></text></problem>'
%
self
.
filename
)
fp
=
StringIO
.
StringIO
(
'<problem><text><font color="red" size="+2">Problem file
%
s is missing</font></text></problem>'
%
self
.
filename
)
fp
.
name
=
"StringIO"
fp
.
name
=
"StringIO"
else
:
else
:
raise
raise
try
:
try
:
self
.
lcp
=
LoncapaProblem
(
fp
,
self
.
item_id
,
instance_state
,
seed
=
seed
,
system
=
self
.
system
)
self
.
lcp
=
LoncapaProblem
(
fp
,
self
.
id
,
instance_state
,
seed
=
seed
,
system
=
self
.
system
)
except
Exception
,
err
:
except
Exception
:
msg
=
'
[courseware.capa.capa_module.Module.init] error
%
s: cannot create LoncapaProblem
%
s'
%
(
err
,
self
.
filename
)
msg
=
'
cannot create LoncapaProblem
%
s'
%
self
.
filename
log
.
exception
(
msg
)
log
.
exception
(
msg
)
if
self
.
DEBUG
:
if
self
.
system
.
DEBUG
:
msg
=
'<p>
%
s</p>'
%
msg
.
replace
(
'<'
,
'<'
)
msg
=
'<p>
%
s</p>'
%
msg
.
replace
(
'<'
,
'<'
)
msg
+=
'<p><pre>
%
s</pre></p>'
%
traceback
.
format_exc
()
.
replace
(
'<'
,
'<'
)
msg
+=
'<p><pre>
%
s</pre></p>'
%
traceback
.
format_exc
()
.
replace
(
'<'
,
'<'
)
# create a dummy problem with error message instead of failing
# create a dummy problem with error message instead of failing
fp
=
StringIO
.
StringIO
(
'<problem><text><font color="red" size="+2">Problem file
%
s has an error:</font>
%
s</text></problem>'
%
(
self
.
filename
,
msg
))
fp
=
StringIO
.
StringIO
(
'<problem><text><font color="red" size="+2">Problem file
%
s has an error:</font>
%
s</text></problem>'
%
(
self
.
filename
,
msg
))
fp
.
name
=
"StringIO"
fp
.
name
=
"StringIO"
self
.
lcp
=
LoncapaProblem
(
fp
,
self
.
item_id
,
instance_state
,
seed
=
seed
,
system
=
self
.
system
)
self
.
lcp
=
LoncapaProblem
(
fp
,
self
.
id
,
instance_state
,
seed
=
seed
,
system
=
self
.
system
)
else
:
else
:
raise
raise
...
@@ -299,8 +286,8 @@ class Module(XModule):
...
@@ -299,8 +286,8 @@ class Module(XModule):
d
=
handlers
[
dispatch
](
get
)
d
=
handlers
[
dispatch
](
get
)
after
=
self
.
get_progress
()
after
=
self
.
get_progress
()
d
.
update
({
d
.
update
({
'progress_changed'
:
after
!=
before
,
'progress_changed'
:
after
!=
before
,
'progress_status'
:
Progress
.
to_js_status_str
(
after
),
'progress_status'
:
Progress
.
to_js_status_str
(
after
),
})
})
return
json
.
dumps
(
d
,
cls
=
ComplexEncoder
)
return
json
.
dumps
(
d
,
cls
=
ComplexEncoder
)
...
@@ -313,7 +300,6 @@ class Module(XModule):
...
@@ -313,7 +300,6 @@ class Module(XModule):
return
False
return
False
def
answer_available
(
self
):
def
answer_available
(
self
):
''' Is the user allowed to see an answer?
''' Is the user allowed to see an answer?
'''
'''
...
@@ -334,7 +320,8 @@ class Module(XModule):
...
@@ -334,7 +320,8 @@ class Module(XModule):
if
self
.
show_answer
==
'always'
:
if
self
.
show_answer
==
'always'
:
return
True
return
True
raise
self
.
system
.
exception404
#TODO: Not 404
#TODO: Not 404
raise
self
.
system
.
exception404
def
get_answer
(
self
,
get
):
def
get_answer
(
self
,
get
):
'''
'''
...
@@ -348,8 +335,7 @@ class Module(XModule):
...
@@ -348,8 +335,7 @@ class Module(XModule):
raise
self
.
system
.
exception404
raise
self
.
system
.
exception404
else
:
else
:
answers
=
self
.
lcp
.
get_question_answers
()
answers
=
self
.
lcp
.
get_question_answers
()
return
{
'answers'
:
answers
}
return
{
'answers'
:
answers
}
# Figure out if we should move these to capa_problem?
# Figure out if we should move these to capa_problem?
def
get_problem
(
self
,
get
):
def
get_problem
(
self
,
get
):
...
@@ -359,7 +345,7 @@ class Module(XModule):
...
@@ -359,7 +345,7 @@ class Module(XModule):
Used if we want to reconfirm we have the right thing e.g. after
Used if we want to reconfirm we have the right thing e.g. after
several AJAX calls.
several AJAX calls.
'''
'''
return
{
'html'
:
self
.
get_problem_html
(
encapsulate
=
False
)}
return
{
'html'
:
self
.
get_problem_html
(
encapsulate
=
False
)}
@staticmethod
@staticmethod
def
make_dict_of_responses
(
get
):
def
make_dict_of_responses
(
get
):
...
@@ -409,18 +395,16 @@ class Module(XModule):
...
@@ -409,18 +395,16 @@ class Module(XModule):
correct_map
=
self
.
lcp
.
grade_answers
(
answers
)
correct_map
=
self
.
lcp
.
grade_answers
(
answers
)
except
StudentInputError
as
inst
:
except
StudentInputError
as
inst
:
# TODO (vshnayder): why is this line here?
# TODO (vshnayder): why is this line here?
self
.
lcp
=
LoncapaProblem
(
self
.
filestore
.
open
(
self
.
filename
),
self
.
lcp
=
LoncapaProblem
(
self
.
system
.
filestore
.
open
(
self
.
filename
),
id
=
lcp_id
,
state
=
old_state
,
system
=
self
.
system
)
id
=
lcp_id
,
state
=
old_state
,
system
=
self
.
system
)
traceback
.
print_exc
()
traceback
.
print_exc
()
return
{
'success'
:
inst
.
message
}
return
{
'success'
:
inst
.
message
}
except
:
except
:
# TODO: why is this line here?
# TODO: why is this line here?
self
.
lcp
=
LoncapaProblem
(
self
.
filestore
.
open
(
self
.
filename
),
self
.
lcp
=
LoncapaProblem
(
self
.
system
.
filestore
.
open
(
self
.
filename
),
id
=
lcp_id
,
state
=
old_state
,
system
=
self
.
system
)
id
=
lcp_id
,
state
=
old_state
,
system
=
self
.
system
)
traceback
.
print_exc
()
traceback
.
print_exc
()
raise
Exception
,
"error in capa_module"
raise
Exception
(
"error in capa_module"
)
# TODO: Dead code... is this a bug, or just old?
return
{
'success'
:
'Unknown Error'
}
self
.
attempts
=
self
.
attempts
+
1
self
.
attempts
=
self
.
attempts
+
1
self
.
lcp
.
done
=
True
self
.
lcp
.
done
=
True
...
@@ -431,21 +415,18 @@ class Module(XModule):
...
@@ -431,21 +415,18 @@ class Module(XModule):
if
not
correct_map
.
is_correct
(
answer_id
):
if
not
correct_map
.
is_correct
(
answer_id
):
success
=
'incorrect'
success
=
'incorrect'
event_info
[
'correct_map'
]
=
correct_map
.
get_dict
()
# log this in the tracker
# log this in the tracker
event_info
[
'correct_map'
]
=
correct_map
.
get_dict
()
event_info
[
'success'
]
=
success
event_info
[
'success'
]
=
success
self
.
tracker
(
'save_problem_check'
,
event_info
)
self
.
tracker
(
'save_problem_check'
,
event_info
)
try
:
# render problem into HTML
html
=
self
.
get_problem_html
(
encapsulate
=
False
)
# render problem into HTML
html
=
self
.
get_problem_html
(
encapsulate
=
False
)
except
Exception
,
err
:
log
.
error
(
'failed to generate html'
)
raise
return
{
'success'
:
success
,
return
{
'success'
:
success
,
'contents'
:
html
,
'contents'
:
html
,
}
}
def
save_problem
(
self
,
get
):
def
save_problem
(
self
,
get
):
'''
'''
Save the passed in answers.
Save the passed in answers.
...
@@ -471,8 +452,8 @@ class Module(XModule):
...
@@ -471,8 +452,8 @@ class Module(XModule):
if
self
.
lcp
.
done
and
self
.
rerandomize
==
"always"
:
if
self
.
lcp
.
done
and
self
.
rerandomize
==
"always"
:
event_info
[
'failure'
]
=
'done'
event_info
[
'failure'
]
=
'done'
self
.
tracker
(
'save_problem_fail'
,
event_info
)
self
.
tracker
(
'save_problem_fail'
,
event_info
)
return
{
'success'
:
False
,
return
{
'success'
:
False
,
'error'
:
"Problem needs to be reset prior to save."
}
'error'
:
"Problem needs to be reset prior to save."
}
self
.
lcp
.
student_answers
=
answers
self
.
lcp
.
student_answers
=
answers
...
@@ -503,12 +484,21 @@ class Module(XModule):
...
@@ -503,12 +484,21 @@ class Module(XModule):
self
.
lcp
.
do_reset
()
self
.
lcp
.
do_reset
()
if
self
.
rerandomize
==
"always"
:
if
self
.
rerandomize
==
"always"
:
# reset random number generator seed (note the self.lcp.get_state() in next line)
# reset random number generator seed (note the self.lcp.get_state() in next line)
self
.
lcp
.
seed
=
None
self
.
lcp
.
seed
=
None
self
.
lcp
=
LoncapaProblem
(
self
.
filestore
.
open
(
self
.
filename
),
self
.
lcp
=
LoncapaProblem
(
self
.
system
.
filestore
.
open
(
self
.
filename
),
self
.
i
tem_i
d
,
self
.
lcp
.
get_state
(),
system
=
self
.
system
)
self
.
id
,
self
.
lcp
.
get_state
(),
system
=
self
.
system
)
event_info
[
'new_state'
]
=
self
.
lcp
.
get_state
()
event_info
[
'new_state'
]
=
self
.
lcp
.
get_state
()
self
.
tracker
(
'reset_problem'
,
event_info
)
self
.
tracker
(
'reset_problem'
,
event_info
)
return
{
'html'
:
self
.
get_problem_html
(
encapsulate
=
False
)}
return
{
'html'
:
self
.
get_problem_html
(
encapsulate
=
False
)}
class
CapaDescriptor
(
RawDescriptor
):
"""
Module implementing problems in the LON-CAPA format,
as implemented by capa.capa_problem
"""
module_class
=
CapaModule
common/lib/xmodule/setup.py
View file @
20118614
...
@@ -19,9 +19,10 @@ setup(
...
@@ -19,9 +19,10 @@ setup(
"section = xmodule.translation_module:SemanticSectionDescriptor"
,
"section = xmodule.translation_module:SemanticSectionDescriptor"
,
"sequential = xmodule.seq_module:SequenceDescriptor"
,
"sequential = xmodule.seq_module:SequenceDescriptor"
,
"vertical = xmodule.vertical_module:VerticalDescriptor"
,
"vertical = xmodule.vertical_module:VerticalDescriptor"
,
"problem = xmodule.capa_module:CapaDescriptor"
,
"problemset = xmodule.seq_module:SequenceDescriptor"
,
"problemset = xmodule.seq_module:SequenceDescriptor"
,
"videosequence = xmodule.seq_module:SequenceDescriptor"
,
"video = xmodule.video_module:VideoDescriptor"
,
"video = xmodule.video_module:VideoDescriptor"
,
"videosequence = xmodule.seq_module:SequenceDescriptor"
,
]
]
}
}
)
)
common/lib/xmodule/vertical_module.py
View file @
20118614
...
@@ -10,6 +10,9 @@ class_priority = ['video', 'problem']
...
@@ -10,6 +10,9 @@ class_priority = ['video', 'problem']
class
VerticalModule
(
XModule
):
class
VerticalModule
(
XModule
):
''' Layout module for laying out submodules vertically.'''
''' Layout module for laying out submodules vertically.'''
def
get_html
(
self
):
def
get_html
(
self
):
if
self
.
contents
is
None
:
self
.
contents
=
[
child
.
get_html
()
for
child
in
self
.
get_display_items
()]
return
self
.
system
.
render_template
(
'vert_module.html'
,
{
return
self
.
system
.
render_template
(
'vert_module.html'
,
{
'items'
:
self
.
contents
'items'
:
self
.
contents
})
})
...
@@ -31,7 +34,7 @@ class VerticalModule(XModule):
...
@@ -31,7 +34,7 @@ class VerticalModule(XModule):
def
__init__
(
self
,
system
,
location
,
definition
,
instance_state
=
None
,
shared_state
=
None
,
**
kwargs
):
def
__init__
(
self
,
system
,
location
,
definition
,
instance_state
=
None
,
shared_state
=
None
,
**
kwargs
):
XModule
.
__init__
(
self
,
system
,
location
,
definition
,
instance_state
,
shared_state
,
**
kwargs
)
XModule
.
__init__
(
self
,
system
,
location
,
definition
,
instance_state
,
shared_state
,
**
kwargs
)
self
.
contents
=
[
child
.
get_html
()
for
child
in
self
.
get_display_items
()]
self
.
contents
=
None
class
VerticalDescriptor
(
SequenceDescriptor
):
class
VerticalDescriptor
(
SequenceDescriptor
):
...
...
lms/djangoapps/courseware/module_render.py
View file @
20118614
...
@@ -60,13 +60,7 @@ class I4xSystem(object):
...
@@ -60,13 +60,7 @@ class I4xSystem(object):
'''
'''
self
.
ajax_url
=
ajax_url
self
.
ajax_url
=
ajax_url
self
.
track_function
=
track_function
self
.
track_function
=
track_function
if
not
filestore
:
self
.
filestore
=
OSFS
(
settings
.
DATA_DIR
)
else
:
self
.
filestore
=
filestore
self
.
filestore
=
filestore
if
settings
.
DEBUG
:
log
.
info
(
"[courseware.module_render.I4xSystem] filestore path =
%
s"
,
filestore
)
self
.
get_module
=
get_module
self
.
get_module
=
get_module
self
.
render_function
=
render_function
self
.
render_function
=
render_function
self
.
render_template
=
render_template
self
.
render_template
=
render_template
...
@@ -241,7 +235,7 @@ def get_module(user, request, location, student_module_cache, position=None):
...
@@ -241,7 +235,7 @@ def get_module(user, request, location, student_module_cache, position=None):
shared_state
=
shared_module
.
state
if
shared_module
is
not
None
else
None
shared_state
=
shared_module
.
state
if
shared_module
is
not
None
else
None
# Setup system context for module instance
# Setup system context for module instance
ajax_url
=
settings
.
MITX_ROOT_URL
+
'/modx/'
+
descriptor
.
type
+
'/'
+
descriptor
.
url
+
'/'
ajax_url
=
settings
.
MITX_ROOT_URL
+
'/modx/'
+
descriptor
.
url
+
'/'
def
_get_module
(
location
):
def
_get_module
(
location
):
(
module
,
_
,
_
,
_
)
=
get_module
(
user
,
request
,
location
,
student_module_cache
,
position
)
(
module
,
_
,
_
,
_
)
=
get_module
(
user
,
request
,
location
,
student_module_cache
,
position
)
...
@@ -330,94 +324,33 @@ def render_x_module(user, request, module_xml, student_module_cache, position=No
...
@@ -330,94 +324,33 @@ def render_x_module(user, request, module_xml, student_module_cache, position=No
return
context
return
context
def
modx_dispatch
(
request
,
module
=
None
,
dispatch
=
None
,
id
=
None
):
def
modx_dispatch
(
request
,
dispatch
=
None
,
id
=
None
):
''' Generic view for extensions. This is where AJAX calls go.
''' Generic view for extensions. This is where AJAX calls go.
Arguments:
Arguments:
- request -- the django request.
- request -- the django request.
- module -- the type of the module, as used in the course configuration xml.
e.g. 'problem', 'video', etc
- dispatch -- the command string to pass through to the module's handle_ajax call
- dispatch -- the command string to pass through to the module's handle_ajax call
(e.g. 'problem_reset'). If this string contains '?', only pass
(e.g. 'problem_reset'). If this string contains '?', only pass
through the part before the first '?'.
through the part before the first '?'.
- id -- the module id. Used to look up the student module.
- id -- the module id. Used to look up the XModule instance
e.g. filenamexformularesponse
'''
'''
# ''' (fix emacs broken parsing)
# ''' (fix emacs broken parsing)
if
not
request
.
user
.
is_authenticated
():
return
redirect
(
'/'
)
# python concats adjacent strings
error_msg
=
(
"We're sorry, this module is temporarily unavailable. "
"Our staff is working to fix it as soon as possible"
)
# If there are arguments, get rid of them
# If there are arguments, get rid of them
dispatch
,
_
,
_
=
dispatch
.
partition
(
'?'
)
dispatch
,
_
,
_
=
dispatch
.
partition
(
'?'
)
ajax_url
=
'{root}/modx/{module}/{id}'
.
format
(
root
=
settings
.
MITX_ROOT_URL
,
student_module_cache
=
StudentModuleCache
(
request
.
user
,
keystore
()
.
get_item
(
id
))
module
=
module
,
id
=
id
)
instance
,
instance_module
,
shared_module
,
module_type
=
get_module
(
request
.
user
,
request
,
id
,
student_module_cache
)
coursename
=
multicourse_settings
.
get_coursename_from_request
(
request
)
if
coursename
and
settings
.
ENABLE_MULTICOURSE
:
xp
=
multicourse_settings
.
get_course_xmlpath
(
coursename
)
data_root
=
settings
.
DATA_DIR
+
xp
else
:
data_root
=
settings
.
DATA_DIR
# Grab the XML corresponding to the request from course.xml
if
instance_module
is
None
:
try
:
log
.
debug
(
"Couldn't find module '
%
s' for user '
%
s'"
,
xml
=
content_parser
.
module_xml
(
request
.
user
,
module
,
'id'
,
id
,
coursename
)
id
,
request
.
user
)
except
:
log
.
exception
(
"Unable to load module during ajax call. module=
%
s, dispatch=
%
s, id=
%
s"
,
module
,
dispatch
,
id
)
if
accepts
(
request
,
'text/html'
):
return
render_to_response
(
"module-error.html"
,
{})
else
:
response
=
HttpResponse
(
json
.
dumps
({
'success'
:
error_msg
}))
return
response
module_xml
=
etree
.
fromstring
(
xml
)
student_module_cache
=
StudentModuleCache
(
request
.
user
,
module_xml
)
(
instance
,
instance_state
,
shared_state
,
module_type
)
=
get_module
(
request
.
user
,
request
,
module_xml
,
student_module_cache
,
None
)
if
instance_state
is
None
:
log
.
debug
(
"Couldn't find module '
%
s' for user '
%
s' and id '
%
s'"
,
module
,
request
.
user
,
id
)
raise
Http404
raise
Http404
oldgrade
=
instance_state
.
grade
oldgrade
=
instance_module
.
grade
old_instance_state
=
instance_state
.
state
old_instance_state
=
instance_module
.
state
old_shared_state
=
shared_state
.
state
if
shared_state
is
not
None
else
None
old_shared_state
=
shared_module
.
state
if
shared_module
is
not
None
else
None
module_from_xml
=
make_module_from_xml_fn
(
request
.
user
,
request
,
student_module_cache
,
None
)
# Create the module
system
=
I4xSystem
(
track_function
=
make_track_function
(
request
),
render_function
=
None
,
module_from_xml
=
module_from_xml
,
render_template
=
render_to_string
,
ajax_url
=
ajax_url
,
request
=
request
,
filestore
=
OSFS
(
data_root
),
)
try
:
module_class
=
xmodule
.
get_module_class
(
module
)
instance
=
module_class
(
system
,
xml
,
id
,
instance_state
=
old_instance_state
,
shared_state
=
old_shared_state
)
except
:
log
.
exception
(
"Unable to load module instance during ajax call"
)
if
accepts
(
request
,
'text/html'
):
return
render_to_response
(
"module-error.html"
,
{})
else
:
response
=
HttpResponse
(
json
.
dumps
({
'success'
:
error_msg
}))
return
response
# Let the module handle the AJAX
# Let the module handle the AJAX
try
:
try
:
...
@@ -427,16 +360,16 @@ def modx_dispatch(request, module=None, dispatch=None, id=None):
...
@@ -427,16 +360,16 @@ def modx_dispatch(request, module=None, dispatch=None, id=None):
raise
raise
# Save the state back to the database
# Save the state back to the database
instance_
stat
e
.
state
=
instance
.
get_instance_state
()
instance_
modul
e
.
state
=
instance
.
get_instance_state
()
if
instance
.
get_score
():
if
instance
.
get_score
():
instance_
stat
e
.
grade
=
instance
.
get_score
()[
'score'
]
instance_
modul
e
.
grade
=
instance
.
get_score
()[
'score'
]
if
instance_
state
.
grade
!=
oldgrade
or
instance_stat
e
.
state
!=
old_instance_state
:
if
instance_
module
.
grade
!=
oldgrade
or
instance_modul
e
.
state
!=
old_instance_state
:
instance_
stat
e
.
save
()
instance_
modul
e
.
save
()
if
shared_
stat
e
is
not
None
:
if
shared_
modul
e
is
not
None
:
shared_
stat
e
.
state
=
instance
.
get_shared_state
()
shared_
modul
e
.
state
=
instance
.
get_shared_state
()
if
shared_
stat
e
.
state
!=
old_shared_state
:
if
shared_
modul
e
.
state
!=
old_shared_state
:
shared_
stat
e
.
save
()
shared_
modul
e
.
save
()
# Return whatever the module wanted to return to the client/caller
# Return whatever the module wanted to return to the client/caller
return
HttpResponse
(
ajax_return
)
return
HttpResponse
(
ajax_return
)
lms/lib/dogfood/views.py
View file @
20118614
...
@@ -174,7 +174,7 @@ def quickedit(request, id=None, qetemplate='quickedit.html',coursename=None):
...
@@ -174,7 +174,7 @@ def quickedit(request, id=None, qetemplate='quickedit.html',coursename=None):
module
=
'problem'
module
=
'problem'
xml
=
content_parser
.
module_xml
(
request
.
user
,
module
,
'id'
,
id
,
coursename
)
xml
=
content_parser
.
module_xml
(
request
.
user
,
module
,
'id'
,
id
,
coursename
)
ajax_url
=
settings
.
MITX_ROOT_URL
+
'/modx/'
+
module
+
'/'
+
id
+
'/'
ajax_url
=
settings
.
MITX_ROOT_URL
+
'/modx/'
+
id
+
'/'
# Create the module (instance of capa_module.Module)
# Create the module (instance of capa_module.Module)
system
=
I4xSystem
(
track_function
=
make_track_function
(
request
),
system
=
I4xSystem
(
track_function
=
make_track_function
(
request
),
...
...
lms/static/coffee/src/courseware.coffee
View file @
20118614
...
@@ -20,8 +20,8 @@ class @Courseware
...
@@ -20,8 +20,8 @@ class @Courseware
id
=
$
(
this
).
attr
(
'id'
).
replace
(
/video_/
,
''
)
id
=
$
(
this
).
attr
(
'id'
).
replace
(
/video_/
,
''
)
new
Video
id
,
$
(
this
).
data
(
'streams'
)
new
Video
id
,
$
(
this
).
data
(
'streams'
)
$
(
'.course-content .problems-wrapper'
).
each
->
$
(
'.course-content .problems-wrapper'
).
each
->
id
=
$
(
this
).
attr
(
'
id'
).
replace
(
/problem_/
,
'
'
)
id
=
$
(
this
).
attr
(
'
problem-id
'
)
new
Problem
id
,
$
(
this
).
data
(
'url'
)
new
Problem
id
,
$
(
this
).
attr
(
'id'
),
$
(
this
).
data
(
'url'
)
$
(
'.course-content .histogram'
).
each
->
$
(
'.course-content .histogram'
).
each
->
id
=
$
(
this
).
attr
(
'id'
).
replace
(
/histogram_/
,
''
)
id
=
$
(
this
).
attr
(
'id'
).
replace
(
/histogram_/
,
''
)
new
Histogram
id
,
$
(
this
).
data
(
'histogram'
)
new
Histogram
id
,
$
(
this
).
data
(
'histogram'
)
lms/static/coffee/src/modules/problem.coffee
View file @
20118614
class
@
Problem
class
@
Problem
constructor
:
(
@
id
,
url
)
->
constructor
:
(
@
id
,
@
element_id
,
url
)
->
@
element
=
$
(
"#
problem_
#{
id
}
"
)
@
element
=
$
(
"#
#{
element_
id
}
"
)
@
render
()
@
render
()
$
:
(
selector
)
->
$
:
(
selector
)
->
...
@@ -26,13 +26,13 @@ class @Problem
...
@@ -26,13 +26,13 @@ class @Problem
@
element
.
html
(
content
)
@
element
.
html
(
content
)
@
bind
()
@
bind
()
else
else
$
.
postWithPrefix
"/modx/
problem/
#{
@
id
}
/problem_get"
,
(
response
)
=>
$
.
postWithPrefix
"/modx/
#{
@
id
}
/problem_get"
,
(
response
)
=>
@
element
.
html
(
response
.
html
)
@
element
.
html
(
response
.
html
)
@
bind
()
@
bind
()
check
:
=>
check
:
=>
Logger
.
log
'problem_check'
,
@
answers
Logger
.
log
'problem_check'
,
@
answers
$
.
postWithPrefix
"/modx/
problem/
#{
@
id
}
/problem_check"
,
@
answers
,
(
response
)
=>
$
.
postWithPrefix
"/modx/
#{
@
id
}
/problem_check"
,
@
answers
,
(
response
)
=>
switch
response
.
success
switch
response
.
success
when
'incorrect'
,
'correct'
when
'incorrect'
,
'correct'
@
render
(
response
.
contents
)
@
render
(
response
.
contents
)
...
@@ -42,14 +42,14 @@ class @Problem
...
@@ -42,14 +42,14 @@ class @Problem
reset
:
=>
reset
:
=>
Logger
.
log
'problem_reset'
,
@
answers
Logger
.
log
'problem_reset'
,
@
answers
$
.
postWithPrefix
"/modx/
problem/
#{
@
id
}
/problem_reset"
,
id
:
@
id
,
(
response
)
=>
$
.
postWithPrefix
"/modx/
#{
@
id
}
/problem_reset"
,
id
:
@
id
,
(
response
)
=>
@
render
(
response
.
html
)
@
render
(
response
.
html
)
@
updateProgress
response
@
updateProgress
response
show
:
=>
show
:
=>
if
!
@
element
.
hasClass
'showed'
if
!
@
element
.
hasClass
'showed'
Logger
.
log
'problem_show'
,
problem
:
@
id
Logger
.
log
'problem_show'
,
problem
:
@
id
$
.
postWithPrefix
"/modx/
problem/
#{
@
id
}
/problem_show"
,
(
response
)
=>
$
.
postWithPrefix
"/modx/
#{
@
id
}
/problem_show"
,
(
response
)
=>
answers
=
response
.
answers
answers
=
response
.
answers
$
.
each
answers
,
(
key
,
value
)
=>
$
.
each
answers
,
(
key
,
value
)
=>
if
$
.
isArray
(
value
)
if
$
.
isArray
(
value
)
...
@@ -69,7 +69,7 @@ class @Problem
...
@@ -69,7 +69,7 @@ class @Problem
save
:
=>
save
:
=>
Logger
.
log
'problem_save'
,
@
answers
Logger
.
log
'problem_save'
,
@
answers
$
.
postWithPrefix
"/modx/
problem/
#{
@
id
}
/problem_save"
,
@
answers
,
(
response
)
=>
$
.
postWithPrefix
"/modx/
#{
@
id
}
/problem_save"
,
@
answers
,
(
response
)
=>
if
response
.
success
if
response
.
success
alert
'Saved'
alert
'Saved'
@
updateProgress
response
@
updateProgress
response
...
@@ -94,4 +94,4 @@ class @Problem
...
@@ -94,4 +94,4 @@ class @Problem
element
.
schematic
.
update_value
()
element
.
schematic
.
update_value
()
@
$
(
".CodeMirror"
).
each
(
index
,
element
)
->
@
$
(
".CodeMirror"
).
each
(
index
,
element
)
->
element
.
CodeMirror
.
save
()
if
element
.
CodeMirror
.
save
element
.
CodeMirror
.
save
()
if
element
.
CodeMirror
.
save
@
answers
=
@
$
(
"[id^=input_
#{
@
id
}
_]"
).
serialize
()
@
answers
=
@
$
(
"[id^=input_
#{
@
element_
id
}
_]"
).
serialize
()
lms/static/coffee/src/modules/sequence.coffee
View file @
20118614
...
@@ -88,7 +88,7 @@ class @Sequence
...
@@ -88,7 +88,7 @@ class @Sequence
if
@
position
!=
new_position
if
@
position
!=
new_position
if
@
position
!=
undefined
if
@
position
!=
undefined
@
mark_visited
@
position
@
mark_visited
@
position
$
.
postWithPrefix
"/modx/
#{
@
tag
}
/
#{
@
id
}
/goto_position"
,
position
:
new_position
$
.
postWithPrefix
"/modx/
#{
@
id
}
/goto_position"
,
position
:
new_position
@
mark_active
new_position
@
mark_active
new_position
@
$
(
'#seq_content'
).
html
@
elements
[
new_position
-
1
].
content
@
$
(
'#seq_content'
).
html
@
elements
[
new_position
-
1
].
content
...
...
lms/templates/problem_ajax.html
View file @
20118614
<section
id=
"problem_${
id}"
class=
"problems-wrapper
"
data-url=
"${ajax_url}"
></section>
<section
id=
"problem_${
element_id}"
class=
"problems-wrapper"
problem-id=
"${id}
"
data-url=
"${ajax_url}"
></section>
lms/urls.py
View file @
20118614
...
@@ -57,7 +57,7 @@ if settings.COURSEWARE_ENABLED:
...
@@ -57,7 +57,7 @@ if settings.COURSEWARE_ENABLED:
url
(
r'^courseware/(?P<course>[^/]*)/$'
,
'courseware.views.index'
,
name
=
"courseware_course"
),
url
(
r'^courseware/(?P<course>[^/]*)/$'
,
'courseware.views.index'
,
name
=
"courseware_course"
),
url
(
r'^jumpto/(?P<probname>[^/]+)/$'
,
'courseware.views.jump_to'
),
url
(
r'^jumpto/(?P<probname>[^/]+)/$'
,
'courseware.views.jump_to'
),
url
(
r'^section/(?P<section>[^/]*)/$'
,
'courseware.views.render_section'
),
url
(
r'^section/(?P<section>[^/]*)/$'
,
'courseware.views.render_section'
),
url
(
r'^modx/(?P<
module>[^/]*)/(?P<id>[^/]*
)/(?P<dispatch>[^/]*)$'
,
'courseware.module_render.modx_dispatch'
),
#reset_problem'),
url
(
r'^modx/(?P<
id>.*?
)/(?P<dispatch>[^/]*)$'
,
'courseware.module_render.modx_dispatch'
),
#reset_problem'),
url
(
r'^profile$'
,
'courseware.views.profile'
),
url
(
r'^profile$'
,
'courseware.views.profile'
),
url
(
r'^profile/(?P<student_id>[^/]*)/$'
,
'courseware.views.profile'
),
url
(
r'^profile/(?P<student_id>[^/]*)/$'
,
'courseware.views.profile'
),
url
(
r'^change_setting$'
,
'student.views.change_setting'
),
url
(
r'^change_setting$'
,
'student.views.change_setting'
),
...
...
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