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
62dcd09b
Commit
62dcd09b
authored
Feb 06, 2013
by
VikParuchuri
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1428 from MITx/feature/diana/close-oe-problems
Close OE Problems
parents
53312713
f3fa4380
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
90 additions
and
19 deletions
+90
-19
common/lib/xmodule/xmodule/combined_open_ended_module.py
+30
-0
common/lib/xmodule/xmodule/open_ended_module.py
+5
-8
common/lib/xmodule/xmodule/openendedchild.py
+23
-1
common/lib/xmodule/xmodule/self_assessment_module.py
+4
-9
common/lib/xmodule/xmodule/tests/test_combined_open_ended.py
+2
-0
common/lib/xmodule/xmodule/tests/test_self_assessment.py
+3
-1
common/lib/xmodule/xmodule/timeparse.py
+23
-0
No files found.
common/lib/xmodule/xmodule/combined_open_ended_module.py
View file @
62dcd09b
...
@@ -7,7 +7,11 @@ from lxml import etree
...
@@ -7,7 +7,11 @@ from lxml import etree
from
lxml.html
import
rewrite_links
from
lxml.html
import
rewrite_links
from
path
import
path
from
path
import
path
import
os
import
os
import
dateutil
import
dateutil.parser
import
datetime
import
sys
import
sys
from
timeparse
import
parse_timedelta
from
pkg_resources
import
resource_string
from
pkg_resources
import
resource_string
...
@@ -157,12 +161,35 @@ class CombinedOpenEndedModule(XModule):
...
@@ -157,12 +161,35 @@ class CombinedOpenEndedModule(XModule):
self
.
attempts
=
instance_state
.
get
(
'attempts'
,
0
)
self
.
attempts
=
instance_state
.
get
(
'attempts'
,
0
)
#Allow reset is true if student has failed the criteria to move to the next child task
#Allow reset is true if student has failed the criteria to move to the next child task
self
.
allow_reset
=
instance_state
.
get
(
'ready_to_reset'
,
False
)
self
.
allow_reset
=
instance_state
.
get
(
'ready_to_reset'
,
False
)
self
.
max_attempts
=
int
(
self
.
metadata
.
get
(
'attempts'
,
MAX_ATTEMPTS
))
self
.
max_attempts
=
int
(
self
.
metadata
.
get
(
'attempts'
,
MAX_ATTEMPTS
))
self
.
is_scored
=
self
.
metadata
.
get
(
'is_graded'
,
IS_SCORED
)
in
TRUE_DICT
self
.
is_scored
=
self
.
metadata
.
get
(
'is_graded'
,
IS_SCORED
)
in
TRUE_DICT
self
.
accept_file_upload
=
self
.
metadata
.
get
(
'accept_file_upload'
,
ACCEPT_FILE_UPLOAD
)
in
TRUE_DICT
self
.
accept_file_upload
=
self
.
metadata
.
get
(
'accept_file_upload'
,
ACCEPT_FILE_UPLOAD
)
in
TRUE_DICT
display_due_date_string
=
self
.
metadata
.
get
(
'due'
,
None
)
if
display_due_date_string
is
not
None
:
try
:
self
.
display_due_date
=
dateutil
.
parser
.
parse
(
display_due_date_string
)
except
ValueError
:
log
.
error
(
"Could not parse due date {0} for location {1}"
.
format
(
display_due_date_string
,
location
))
raise
else
:
self
.
display_due_date
=
None
grace_period_string
=
self
.
metadata
.
get
(
'graceperiod'
,
None
)
if
grace_period_string
is
not
None
and
self
.
display_due_date
:
try
:
self
.
grace_period
=
parse_timedelta
(
grace_period_string
)
self
.
close_date
=
self
.
display_due_date
+
self
.
grace_period
except
:
log
.
error
(
"Error parsing the grace period {0} for location {1}"
.
format
(
grace_period_string
,
location
))
raise
else
:
self
.
grace_period
=
None
self
.
close_date
=
self
.
display_due_date
# Used for progress / grading. Currently get credit just for
# Used for progress / grading. Currently get credit just for
# completion (doesn't matter if you self-assessed correct/incorrect).
# completion (doesn't matter if you self-assessed correct/incorrect).
self
.
_max_score
=
int
(
self
.
metadata
.
get
(
'max_score'
,
MAX_SCORE
))
self
.
_max_score
=
int
(
self
.
metadata
.
get
(
'max_score'
,
MAX_SCORE
))
...
@@ -185,11 +212,13 @@ class CombinedOpenEndedModule(XModule):
...
@@ -185,11 +212,13 @@ class CombinedOpenEndedModule(XModule):
'rubric'
:
definition
[
'rubric'
],
'rubric'
:
definition
[
'rubric'
],
'display_name'
:
self
.
display_name
,
'display_name'
:
self
.
display_name
,
'accept_file_upload'
:
self
.
accept_file_upload
,
'accept_file_upload'
:
self
.
accept_file_upload
,
'close_date'
:
self
.
close_date
}
}
self
.
task_xml
=
definition
[
'task_xml'
]
self
.
task_xml
=
definition
[
'task_xml'
]
self
.
setup_next_task
()
self
.
setup_next_task
()
def
get_tag_name
(
self
,
xml
):
def
get_tag_name
(
self
,
xml
):
"""
"""
Gets the tag name of a given xml block.
Gets the tag name of a given xml block.
...
@@ -299,6 +328,7 @@ class CombinedOpenEndedModule(XModule):
...
@@ -299,6 +328,7 @@ class CombinedOpenEndedModule(XModule):
return
True
return
True
def
check_allow_reset
(
self
):
def
check_allow_reset
(
self
):
"""
"""
Checks to see if the student has passed the criteria to move to the next module. If not, sets
Checks to see if the student has passed the criteria to move to the next module. If not, sets
...
...
common/lib/xmodule/xmodule/open_ended_module.py
View file @
62dcd09b
...
@@ -549,14 +549,11 @@ class OpenEndedModule(openendedchild.OpenEndedChild):
...
@@ -549,14 +549,11 @@ class OpenEndedModule(openendedchild.OpenEndedChild):
@param system: modulesystem
@param system: modulesystem
@return: Success indicator
@return: Success indicator
"""
"""
if
self
.
attempts
>
self
.
max_attempts
:
# Once we close the problem, we should not allow students
# If too many attempts, prevent student from saving answer and
# to save answers
# seeing rubric. In normal use, students shouldn't see this because
closed
,
msg
=
self
.
check_if_closed
()
# they won't see the reset button once they're out of attempts.
if
closed
:
return
{
return
msg
'success'
:
False
,
'error'
:
'Too many attempts.'
}
if
self
.
state
!=
self
.
INITIAL
:
if
self
.
state
!=
self
.
INITIAL
:
return
self
.
out_of_sync_error
(
get
)
return
self
.
out_of_sync_error
(
get
)
...
...
common/lib/xmodule/xmodule/openendedchild.py
View file @
62dcd09b
...
@@ -74,7 +74,7 @@ class OpenEndedChild(object):
...
@@ -74,7 +74,7 @@ class OpenEndedChild(object):
'done'
:
'Problem complete'
,
'done'
:
'Problem complete'
,
}
}
def
__init__
(
self
,
system
,
location
,
definition
,
descriptor
,
static_data
,
def
__init__
(
self
,
system
,
location
,
definition
,
descriptor
,
static_data
,
instance_state
=
None
,
shared_state
=
None
,
**
kwargs
):
instance_state
=
None
,
shared_state
=
None
,
**
kwargs
):
# Load instance state
# Load instance state
if
instance_state
is
not
None
:
if
instance_state
is
not
None
:
...
@@ -99,6 +99,7 @@ class OpenEndedChild(object):
...
@@ -99,6 +99,7 @@ class OpenEndedChild(object):
self
.
rubric
=
static_data
[
'rubric'
]
self
.
rubric
=
static_data
[
'rubric'
]
self
.
display_name
=
static_data
[
'display_name'
]
self
.
display_name
=
static_data
[
'display_name'
]
self
.
accept_file_upload
=
static_data
[
'accept_file_upload'
]
self
.
accept_file_upload
=
static_data
[
'accept_file_upload'
]
self
.
close_date
=
static_data
[
'close_date'
]
# Used for progress / grading. Currently get credit just for
# Used for progress / grading. Currently get credit just for
# completion (doesn't matter if you self-assessed correct/incorrect).
# completion (doesn't matter if you self-assessed correct/incorrect).
...
@@ -117,6 +118,27 @@ class OpenEndedChild(object):
...
@@ -117,6 +118,27 @@ class OpenEndedChild(object):
"""
"""
pass
pass
def
closed
(
self
):
if
self
.
close_date
is
not
None
and
datetime
.
utcnow
()
>
self
.
close_date
:
return
True
return
False
def
check_if_closed
(
self
):
if
self
.
closed
():
return
True
,
{
'success'
:
False
,
'error'
:
'This problem is now closed.'
}
elif
self
.
attempts
>
self
.
max_attempts
:
return
True
,
{
'success'
:
False
,
'error'
:
'Too many attempts.'
}
else
:
return
False
,
{}
def
latest_answer
(
self
):
def
latest_answer
(
self
):
"""Empty string if not available"""
"""Empty string if not available"""
if
not
self
.
history
:
if
not
self
.
history
:
...
...
common/lib/xmodule/xmodule/self_assessment_module.py
View file @
62dcd09b
...
@@ -190,15 +190,10 @@ class SelfAssessmentModule(openendedchild.OpenEndedChild):
...
@@ -190,15 +190,10 @@ class SelfAssessmentModule(openendedchild.OpenEndedChild):
Dictionary with keys 'success' and either 'error' (if not success),
Dictionary with keys 'success' and either 'error' (if not success),
or 'rubric_html' (if success).
or 'rubric_html' (if success).
"""
"""
# Check to see if attempts are less than max
# Check to see if this problem is closed
if
self
.
attempts
>
self
.
max_attempts
:
closed
,
msg
=
self
.
check_if_closed
()
# If too many attempts, prevent student from saving answer and
if
closed
:
# seeing rubric. In normal use, students shouldn't see this because
return
msg
# they won't see the reset button once they're out of attempts.
return
{
'success'
:
False
,
'error'
:
'Too many attempts.'
}
if
self
.
state
!=
self
.
INITIAL
:
if
self
.
state
!=
self
.
INITIAL
:
return
self
.
out_of_sync_error
(
get
)
return
self
.
out_of_sync_error
(
get
)
...
...
common/lib/xmodule/xmodule/tests/test_combined_open_ended.py
View file @
62dcd09b
...
@@ -42,6 +42,7 @@ class OpenEndedChildTest(unittest.TestCase):
...
@@ -42,6 +42,7 @@ class OpenEndedChildTest(unittest.TestCase):
'max_score'
:
max_score
,
'max_score'
:
max_score
,
'display_name'
:
'Name'
,
'display_name'
:
'Name'
,
'accept_file_upload'
:
False
,
'accept_file_upload'
:
False
,
'close_date'
:
None
}
}
definition
=
Mock
()
definition
=
Mock
()
descriptor
=
Mock
()
descriptor
=
Mock
()
...
@@ -157,6 +158,7 @@ class OpenEndedModuleTest(unittest.TestCase):
...
@@ -157,6 +158,7 @@ class OpenEndedModuleTest(unittest.TestCase):
'max_score'
:
max_score
,
'max_score'
:
max_score
,
'display_name'
:
'Name'
,
'display_name'
:
'Name'
,
'accept_file_upload'
:
False
,
'accept_file_upload'
:
False
,
'close_date'
:
None
}
}
oeparam
=
etree
.
XML
(
'''
oeparam
=
etree
.
XML
(
'''
...
...
common/lib/xmodule/xmodule/tests/test_self_assessment.py
View file @
62dcd09b
...
@@ -46,11 +46,13 @@ class SelfAssessmentTest(unittest.TestCase):
...
@@ -46,11 +46,13 @@ class SelfAssessmentTest(unittest.TestCase):
'max_score'
:
1
,
'max_score'
:
1
,
'display_name'
:
"Name"
,
'display_name'
:
"Name"
,
'accept_file_upload'
:
False
,
'accept_file_upload'
:
False
,
'close_date'
:
None
}
}
self
.
module
=
SelfAssessmentModule
(
test_system
,
self
.
location
,
self
.
module
=
SelfAssessmentModule
(
test_system
,
self
.
location
,
self
.
definition
,
self
.
descriptor
,
self
.
definition
,
self
.
descriptor
,
static_data
,
state
,
metadata
=
self
.
metadata
)
static_data
,
state
,
metadata
=
self
.
metadata
)
def
test_get_html
(
self
):
def
test_get_html
(
self
):
html
=
self
.
module
.
get_html
(
test_system
)
html
=
self
.
module
.
get_html
(
test_system
)
...
...
common/lib/xmodule/xmodule/timeparse.py
View file @
62dcd09b
...
@@ -2,9 +2,12 @@
...
@@ -2,9 +2,12 @@
Helper functions for handling time in the format we like.
Helper functions for handling time in the format we like.
"""
"""
import
time
import
time
import
re
from
datetime
import
timedelta
TIME_FORMAT
=
"
%
Y-
%
m-
%
dT
%
H:
%
M"
TIME_FORMAT
=
"
%
Y-
%
m-
%
dT
%
H:
%
M"
TIMEDELTA_REGEX
=
re
.
compile
(
r'^((?P<days>\d+?) day(?:s?))?(\s)?((?P<hours>\d+?) hour(?:s?))?(\s)?((?P<minutes>\d+?) minute(?:s)?)?(\s)?((?P<seconds>\d+?) second(?:s)?)?$'
)
def
parse_time
(
time_str
):
def
parse_time
(
time_str
):
"""
"""
...
@@ -22,3 +25,23 @@ def stringify_time(time_struct):
...
@@ -22,3 +25,23 @@ def stringify_time(time_struct):
Convert a time struct to a string
Convert a time struct to a string
"""
"""
return
time
.
strftime
(
TIME_FORMAT
,
time_struct
)
return
time
.
strftime
(
TIME_FORMAT
,
time_struct
)
def
parse_timedelta
(
time_str
):
"""
time_str: A string with the following components:
<D> day[s] (optional)
<H> hour[s] (optional)
<M> minute[s] (optional)
<S> second[s] (optional)
Returns a datetime.timedelta parsed from the string
"""
parts
=
TIMEDELTA_REGEX
.
match
(
time_str
)
if
not
parts
:
return
parts
=
parts
.
groupdict
()
time_params
=
{}
for
(
name
,
param
)
in
parts
.
iteritems
():
if
param
:
time_params
[
name
]
=
int
(
param
)
return
timedelta
(
**
time_params
)
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