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
f88cb685
Commit
f88cb685
authored
Nov 09, 2012
by
Victor Shnayder
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
split out the assess and reflect states. Still need matching js
parent
fb3b52b9
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
111 additions
and
69 deletions
+111
-69
common/lib/xmodule/xmodule/self_assessment_module.py
+111
-69
No files found.
common/lib/xmodule/xmodule/self_assessment_module.py
View file @
f88cb685
"""
A Self Assessment module that allows students to write open-ended responses,
submit, then see a rubric and rate themselves. Persists student supplied
hints, answers, and
correctness
judgment (currently only correct/incorrect).
hints, answers, and
assessment
judgment (currently only correct/incorrect).
Parses xml definition file--see below for exact format.
"""
...
...
@@ -33,7 +33,7 @@ log = logging.getLogger("mitx.courseware")
# attempts specified in xml definition overrides this.
MAX_ATTEMPTS
=
1
# Set maximum available number of points. Should be set to 1 for now due to
correctness
handling,
# Set maximum available number of points. Should be set to 1 for now due to
assessment
handling,
# which only allows for correct/incorrect.
MAX_SCORE
=
1
...
...
@@ -73,7 +73,7 @@ class SelfAssessmentModule(XModule):
"""
Definition file should have 4 blocks -- prompt, rubric, submitmessage, hintprompt,
and one optional attribute, attempts, which should be an integer that defaults to 1.
If it's >1, the student will be able to re-submit after they see
If it's >
1, the student will be able to re-submit after they see
the rubric. Note: all the submissions are stored.
Sample file:
...
...
@@ -100,41 +100,28 @@ class SelfAssessmentModule(XModule):
else
:
instance_state
=
{}
log
.
debug
(
'Instance state of self-assessment module {0}: {1}'
.
format
(
location
.
url
(),
instance_state
))
# Pull out state, or initialize variables
# lists of student answers, correctness responses
# ('incorrect'/'correct'), and suggested hints
self
.
student_answers
=
instance_state
.
get
(
'student_answers'
,
[])
self
.
correctness
=
instance_state
.
get
(
'correctness'
,
[])
# assessment responses are 'incorrect'/'correct'
self
.
assessment
=
instance_state
.
get
(
'assessment'
,
[])
self
.
hints
=
instance_state
.
get
(
'hints'
,
[])
# Used to keep track of a submitted answer for which we don't have a
# self-assessment and hint yet: this means that the answers,
# correctness, hints always stay in sync, and have the same number of
# elements.
self
.
state
=
instance_state
.
get
(
'state'
,
'initial'
)
# Used for progress / grading. Currently get credit just for
# completion (doesn't matter if you self-assessed correct/incorrect).
self
.
score
=
instance_state
.
get
(
'score'
,
0
)
self
.
top_score
=
instance_state
.
get
(
'top
_score'
,
MAX_SCORE
)
self
.
max_score
=
instance_state
.
get
(
'max
_score'
,
MAX_SCORE
)
#Get number of attempts student has used from instance state
self
.
attempts
=
instance_state
.
get
(
'attempts'
,
0
)
#Try setting maxattempts, use default if not available in metadata
self
.
max_attempts
=
int
(
self
.
metadata
.
get
(
'attempts'
,
MAX_ATTEMPTS
))
#Extract prompt, submission message, hint prompt, and rubric from definition file
self
.
rubric
=
definition
[
'rubric'
]
self
.
prompt
=
definition
[
'prompt'
]
self
.
submit_message
=
definition
[
'submitmessage'
]
self
.
hint_prompt
=
definition
[
'hintprompt'
]
#Determine if student has answered the question before. This is used to display
#a "previous answer" message to the student if they have.
previous_answer
=
self
.
student_answers
[
-
1
]
if
self
.
student_answers
else
''
#set context variables and render template
...
...
@@ -149,19 +136,24 @@ class SelfAssessmentModule(XModule):
self
.
html
=
self
.
system
.
render_template
(
'self_assessment_prompt.html'
,
context
)
def
get_score
(
self
):
"""
Returns dict with 'score' key
"""
return
{
'score'
:
self
.
score
}
def
max_score
(
self
):
return
self
.
top_score
"""
Return max_score
"""
return
self
.
max_score
def
get_progress
(
self
):
''' For now, just return score / max_score
'''
score
=
self
.
score
total
=
self
.
top_score
if
total
>
0
:
For now, just return score / max_
score
'''
if
self
.
max_score
>
0
:
try
:
return
Progress
(
s
core
,
total
)
return
Progress
(
s
elf
.
score
,
self
.
max_score
)
except
Exception
as
err
:
log
.
exception
(
"Got bad progress"
)
return
None
...
...
@@ -180,8 +172,10 @@ class SelfAssessmentModule(XModule):
"""
handlers
=
{
'show'
:
self
.
show_rubric
,
'save'
:
self
.
save_problem
,
'save_answer'
:
self
.
save_answer
,
'save_assessment'
:
self
.
save_assessment
,
'save_hint'
:
self
.
save_hint
,
'reset'
:
self
.
reset
,
}
if
dispatch
not
in
handlers
:
...
...
@@ -196,6 +190,15 @@ class SelfAssessmentModule(XModule):
})
return
json
.
dumps
(
d
,
cls
=
ComplexEncoder
)
def
out_of_sync_error
(
self
,
get
):
"""
return dict out-of-sync error message, and also log.
"""
log
.
warning
(
"Assessment module state out sync. state:
%
r, get:
%
r"
,
self
.
state
,
get
)
return
{
'success'
:
False
,
'error'
:
'The problem state got out-of-sync'
}
def
get_rubric_html
(
self
):
"""
Return the appropriate version of the rubric, based on the state.
...
...
@@ -245,77 +248,116 @@ class SelfAssessmentModule(XModule):
return
"""<div class="save_message">{0}</div>"""
.
format
(
self
.
message
)
def
s
how_rubric
(
self
,
get
):
def
s
ave_answer
(
self
,
get
):
"""
After the answer is submitted, show the rubric.
"""
# Check to see if attempts are less than max
if
(
self
.
attempts
<
self
.
max_attempts
):
# Dump to temp_answer to keep answer in sync with correctness and hint
self
.
temp_answer
=
get
[
'student_answer'
]
return
{
'success'
:
True
,
'rubric'
:
self
.
get_rubric_html
()
}
else
:
# If too many attempts, prevent student from saving answer and seeing rubric.
if
self
.
attempts
<
self
.
max_attempts
:
# If too many attempts, prevent student from saving answer and
# seeing rubric. In normal use, students shouldn't see this because
# they won't see the reset button once they're out of attempts.
return
{
'success'
:
False
,
'message'
:
'Too many attempts.'
}
def
save_problem
(
self
,
get
):
if
self
.
state
!=
self
.
INITIAL
:
return
self
.
out_of_sync_error
(
get
)
self
.
student_answers
.
append
=
get
[
'student_answer'
]
self
.
state
=
self
.
ASSESSING
return
{
'success'
:
True
,
'rubric'
:
self
.
get_rubric_html
()
}
def
save_assessment
(
self
,
get
):
"""
Save the assessment.
Returns a dict { 'success' : bool, 'hint_html': hint_html 'error' : error-msg},
with 'error' only present if 'success' is False, and 'hint_html' only if success is true
"""
if
(
self
.
state
!=
self
.
ASSESSMENT
or
len
(
self
.
student_answers
)
!=
len
(
self
.
assessment
)
+
1
):
return
self
.
out_of_sync_error
(
get
)
self
.
assessment
.
append
(
get
[
'assessment'
]
.
lower
())
self
.
state
=
self
.
REQUEST_HINT
# TODO: return different hint based on assessment value...
return
{
'success'
:
True
,
'hint_html'
:
self
.
get_hint_html
()}
def
save_hint
(
self
,
get
):
'''
Save the passed in answers.
Returns a dict { 'success' : bool, ['error' : error-msg]},
with the error key only present if success is False.
Save the hint.
Returns a dict { 'success' : bool,
'message_html': message_html,
'error' : error-msg},
with the error key only present if success is False and message_html
only if True.
'''
if
self
.
state
!=
self
.
REQUEST_HINT
or
len
(
self
.
assessment
)
!=
len
(
self
.
hints
)
+
1
:
return
self
.
out_of_sync_error
(
get
)
#Temp answer check is to keep hints, correctness, and answer in sync
if
self
.
temp_answer
is
not
""
:
#Extract correctness and hint from ajax, and add temp answer to student answers
self
.
hints
.
append
(
get
[
'hint'
])
self
.
correctness
.
append
(
get
[
'assessment'
]
.
lower
())
self
.
student_answers
.
append
(
self
.
temp_answer
)
self
.
hints
.
append
(
get
[
'hint'
]
.
lower
())
self
.
state
=
self
.
DONE
# Points are assigned for completion, so always set to 1
points
=
1
# increment attempts
self
.
attempts
=
self
.
attempts
+
1
#Create and store event info dict
#Currently points are assigned for completion, so set to 1 instead of depending on correctness.
points
=
1
event_info
=
dict
()
event_info
[
'state'
]
=
{
'student_answers'
:
self
.
student_answers
,
'hints'
:
self
.
hints
,
'correctness'
:
self
.
correctness
,
'score'
:
points
,
'done'
:
self
.
done
}
# To the tracking logs!
event_info
=
{
'selfassessment_id'
:
self
.
location
.
url
(),
'state'
:
{
'student_answers'
:
self
.
student_answers
,
'assessment'
:
self
.
assessment
,
'hints'
:
self
.
hints
,
'score'
:
points
,
'done'
:
self
.
done
,}}
self
.
system
.
track_function
(
'save_hint'
,
event_info
)
return
{
'success'
:
True
,
'message_html'
:
self
.
get_message_html
()}
# TODO: figure out how to identify self assessment. May not want to confuse with problems.
event_info
[
'selfassessment_id'
]
=
self
.
location
.
url
()
self
.
system
.
track_function
(
'save_problem_succeed'
,
event_info
)
def
reset
(
self
,
get
):
"""
If resetting is allowed, reset the state.
Returns {'success': bool, 'error': msg}
(error only present if not success)
"""
if
self
.
state
!=
DONE
:
return
self
.
out_of_sync_error
(
get
)
if
self
.
attempts
<
self
.
max_attempts
:
return
{
'success'
:
False
,
'error'
:
'Too many attempts.'
}
self
.
state
=
self
.
INITIAL
return
{
'success'
:
True
}
#Return the submitmessage specified in xml defintion on success
return
{
'success'
:
True
,
'message'
:
self
.
submit_message
}
def
get_instance_state
(
self
):
"""
Get the current
correctness
, points, and state
Get the current
assessment
, points, and state
"""
#Assign points based on completion. May want to change to
correctness
-based down the road.
#Assign points based on completion. May want to change to
assessment
-based down the road.
points
=
1
state
=
{
'student_answers'
:
self
.
student_answers
,
'temp_answer'
:
self
.
temp_answer
,
'hints'
:
self
.
hints
,
'
correctness'
:
self
.
correctness
,
'
assessment'
:
self
.
assessment
,
'score'
:
points
,
'
top
_score'
:
MAX_SCORE
,
'
max
_score'
:
MAX_SCORE
,
'attempts'
:
self
.
attempts
}
return
json
.
dumps
(
state
)
...
...
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