Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-ora2
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-ora2
Commits
e12f27d3
Commit
e12f27d3
authored
Mar 12, 2014
by
Will Daly
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #119 from edx/will/tim-86
Post-release rubric validation
parents
ecc9dde1
81896224
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
1247 additions
and
132 deletions
+1247
-132
apps/openassessment/assessment/test/data/invalid_rubrics.json
+0
-43
apps/openassessment/assessment/test/data/valid_rubrics.json
+0
-55
apps/openassessment/xblock/openassessmentblock.py
+20
-1
apps/openassessment/xblock/static/js/src/oa_edit.js
+3
-0
apps/openassessment/xblock/studio_mixin.py
+1
-1
apps/openassessment/xblock/test/data/invalid_rubrics.json
+335
-0
apps/openassessment/xblock/test/data/valid_assessments.json
+0
-0
apps/openassessment/xblock/test/data/valid_rubrics.json
+738
-0
apps/openassessment/xblock/test/test_openassessment.py
+68
-21
apps/openassessment/xblock/test/test_studio.py
+17
-0
apps/openassessment/xblock/test/test_validation.py
+3
-2
apps/openassessment/xblock/validation.py
+62
-9
No files found.
apps/openassessment/assessment/test/data/invalid_rubrics.json
deleted
100644 → 0
View file @
ecc9dde1
{
"zero_criteria"
:
{
"rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[]
}
},
"zero_options"
:
{
"rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[]
}
]
}
},
"negative_points"
:
{
"rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
-1
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
}
]
}
]
}
}
}
apps/openassessment/assessment/test/data/valid_rubrics.json
deleted
100644 → 0
View file @
ecc9dde1
{
"simple"
:
{
"rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
}
},
"unicode"
:
{
"rubric"
:
{
"prompt"
:
"☃"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"☃"
,
"prompt"
:
"☃"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"☃"
,
"explanation"
:
"☃"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"☃"
,
"explanation"
:
"☃"
}
]
}
]
}
}
}
apps/openassessment/xblock/openassessmentblock.py
View file @
e12f27d3
...
@@ -346,7 +346,7 @@ class OpenAssessmentBlock(
...
@@ -346,7 +346,7 @@ class OpenAssessmentBlock(
block
.
runtime
.
add_node_as_child
(
block
,
child
,
id_generator
)
block
.
runtime
.
add_node_as_child
(
block
,
child
,
id_generator
)
block
=
runtime
.
construct_xblock_from_class
(
cls
,
keys
)
block
=
runtime
.
construct_xblock_from_class
(
cls
,
keys
)
return
update_from_xml
(
block
,
node
,
validator
=
validator
(
block
.
start
,
block
.
du
e
))
return
update_from_xml
(
block
,
node
,
validator
=
validator
(
block
,
strict_post_release
=
Fals
e
))
def
render_assessment
(
self
,
path
,
context_dict
=
None
):
def
render_assessment
(
self
,
path
,
context_dict
=
None
):
"""Render an Assessment Module's HTML
"""Render an Assessment Module's HTML
...
@@ -461,6 +461,25 @@ class OpenAssessmentBlock(
...
@@ -461,6 +461,25 @@ class OpenAssessmentBlock(
else
:
else
:
return
True
,
None
return
True
,
None
def
is_released
(
self
,
step
=
None
):
"""
Check if a question has been released.
Kwargs:
step (str): The step in the workflow to check.
None: check whether the problem as a whole is open.
"submission": check whether the submission section is open.
"peer-assessment": check whether the peer-assessment section is open.
"self-assessment": check whether the self-assessment section is open.
Returns:
bool
"""
# By default, assume that we're published, in case the runtime doesn't support publish date.
is_published
=
getattr
(
self
,
'published_date'
,
True
)
is
not
None
is_open
,
reason
=
self
.
is_open
(
step
=
step
)
return
is_published
and
(
is_open
or
reason
==
'due'
)
def
update_workflow_status
(
self
,
submission_uuid
):
def
update_workflow_status
(
self
,
submission_uuid
):
assessment_ui_model
=
self
.
get_assessment_module
(
'peer-assessment'
)
assessment_ui_model
=
self
.
get_assessment_module
(
'peer-assessment'
)
requirements
=
{
requirements
=
{
...
...
apps/openassessment/xblock/static/js/src/oa_edit.js
View file @
e12f27d3
...
@@ -74,6 +74,9 @@ OpenAssessment.StudioUI.prototype = {
...
@@ -74,6 +74,9 @@ OpenAssessment.StudioUI.prototype = {
// Notify the client-side runtime that we finished saving
// Notify the client-side runtime that we finished saving
// so it can hide the "Saving..." notification.
// so it can hide the "Saving..." notification.
ui
.
runtime
.
notify
(
'save'
,
{
state
:
'end'
});
ui
.
runtime
.
notify
(
'save'
,
{
state
:
'end'
});
// Reload the XML definition in the editor
ui
.
load
();
}).
fail
(
function
(
msg
)
{
}).
fail
(
function
(
msg
)
{
ui
.
showError
(
msg
);
ui
.
showError
(
msg
);
});
});
...
...
apps/openassessment/xblock/studio_mixin.py
View file @
e12f27d3
...
@@ -54,7 +54,7 @@ class StudioMixin(object):
...
@@ -54,7 +54,7 @@ class StudioMixin(object):
"""
"""
if
'xml'
in
data
:
if
'xml'
in
data
:
try
:
try
:
update_from_xml_str
(
self
,
data
[
'xml'
],
validator
=
validator
(
self
.
start
,
self
.
due
))
update_from_xml_str
(
self
,
data
[
'xml'
],
validator
=
validator
(
self
))
except
ValidationError
as
ex
:
except
ValidationError
as
ex
:
return
{
'success'
:
False
,
'msg'
:
_
(
'Validation error: {error}'
)
.
format
(
error
=
ex
.
message
)}
return
{
'success'
:
False
,
'msg'
:
_
(
'Validation error: {error}'
)
.
format
(
error
=
ex
.
message
)}
...
...
apps/openassessment/xblock/test/data/invalid_rubrics.json
0 → 100644
View file @
e12f27d3
{
"zero_criteria"
:
{
"rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[]
},
"current_rubric"
:
null
,
"is_released"
:
false
},
"zero_options"
:
{
"rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[]
}
]
},
"current_rubric"
:
null
,
"is_released"
:
false
},
"negative_points"
:
{
"rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
-1
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
}
]
}
]
},
"current_rubric"
:
null
,
"is_released"
:
false
},
"change_points_after_release"
:
{
"rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"current_rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
2
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"is_released"
:
true
},
"add_criteria_after_release"
:
{
"rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"current_rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
},
{
"order_num"
:
1
,
"name"
:
"Another criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"is_released"
:
true
},
"remove_criteria_after_release"
:
{
"rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
},
{
"order_num"
:
1
,
"name"
:
"Another criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"current_rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"is_released"
:
true
},
"add_options_after_release"
:
{
"rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"current_rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
}
]
}
]
},
"is_released"
:
true
},
"remove_options_after_release"
:
{
"rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
}
]
}
]
},
"current_rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"is_released"
:
true
}
}
apps/openassessment/
assessment
/test/data/valid_assessments.json
→
apps/openassessment/
xblock
/test/data/valid_assessments.json
View file @
e12f27d3
File moved
apps/openassessment/xblock/test/data/valid_rubrics.json
0 → 100644
View file @
e12f27d3
{
"simple"
:
{
"rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"current_rubric"
:
null
,
"is_released"
:
false
},
"unicode"
:
{
"rubric"
:
{
"prompt"
:
"☃"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"☃"
,
"prompt"
:
"☃"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"☃"
,
"explanation"
:
"☃"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"☃"
,
"explanation"
:
"☃"
}
]
}
]
},
"current_rubric"
:
null
,
"is_released"
:
false
},
"change_points_before_release"
:
{
"rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"current_rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
2
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"is_released"
:
false
},
"add_criteria_before_release"
:
{
"rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"current_rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
},
{
"order_num"
:
1
,
"name"
:
"Another criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"is_released"
:
false
},
"remove_criteria_before_release"
:
{
"rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
},
{
"order_num"
:
1
,
"name"
:
"Another criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"current_rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"is_released"
:
false
},
"add_options_before_release"
:
{
"rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"current_rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
}
]
}
]
},
"current_rubric"
:
null
,
"is_released"
:
false
},
"remove_options_before_release"
:
{
"rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
}
]
}
]
},
"current_rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"is_released"
:
false
},
"change_text_before_release"
:
{
"rubric"
:
{
"prompt"
:
"Changed Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Changed criterion"
,
"prompt"
:
"Changed criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"Changed No"
,
"explanation"
:
"Changed no explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Changed yes"
,
"explanation"
:
"Changed yes explanation"
}
]
}
]
},
"current_rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"is_released"
:
false
},
"change_criteria_prompt_after_release"
:
{
"rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Changed criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"current_rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"is_released"
:
true
},
"change_criteria_name_after_release"
:
{
"rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Changed criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"current_rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"is_released"
:
true
},
"change_option_name_after_release"
:
{
"rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"Changed No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"current_rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"is_released"
:
true
},
"change_option_explanation_after_release"
:
{
"rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"Changed No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"current_rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"is_released"
:
true
},
"reorder_criteria_after_release"
:
{
"rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
},
{
"order_num"
:
1
,
"name"
:
"Another criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
}
]
}
]
},
"current_rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Another criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
}
]
},
{
"order_num"
:
1
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"is_released"
:
true
},
"reorder_options_after_release"
:
{
"rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
},
{
"order_num"
:
1
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
}
]
}
]
},
"current_rubric"
:
{
"prompt"
:
"Test Prompt"
,
"criteria"
:
[
{
"order_num"
:
0
,
"name"
:
"Test criterion"
,
"prompt"
:
"Test criterion prompt"
,
"options"
:
[
{
"order_num"
:
0
,
"points"
:
0
,
"name"
:
"No"
,
"explanation"
:
"No explanation"
},
{
"order_num"
:
1
,
"points"
:
2
,
"name"
:
"Yes"
,
"explanation"
:
"Yes explanation"
}
]
}
]
},
"is_released"
:
true
}
}
\ No newline at end of file
apps/openassessment/xblock/test/test_openassessment.py
View file @
e12f27d3
...
@@ -93,25 +93,29 @@ class TestDates(XBlockHandlerTestCase):
...
@@ -93,25 +93,29 @@ class TestDates(XBlockHandlerTestCase):
self
.
assert_is_open
(
self
.
assert_is_open
(
xblock
,
xblock
,
dt
.
datetime
(
2014
,
2
,
28
,
23
,
59
,
59
),
dt
.
datetime
(
2014
,
2
,
28
,
23
,
59
,
59
),
None
,
False
,
"start"
None
,
False
,
"start"
,
released
=
False
)
)
self
.
assert_is_open
(
self
.
assert_is_open
(
xblock
,
xblock
,
dt
.
datetime
(
2014
,
3
,
1
,
1
,
1
,
1
),
dt
.
datetime
(
2014
,
3
,
1
,
1
,
1
,
1
),
None
,
True
,
None
None
,
True
,
None
,
released
=
True
)
)
self
.
assert_is_open
(
self
.
assert_is_open
(
xblock
,
xblock
,
dt
.
datetime
(
2014
,
3
,
4
,
23
,
59
,
59
),
dt
.
datetime
(
2014
,
3
,
4
,
23
,
59
,
59
),
None
,
True
,
None
None
,
True
,
None
,
released
=
True
)
)
self
.
assert_is_open
(
self
.
assert_is_open
(
xblock
,
xblock
,
dt
.
datetime
(
2014
,
3
,
5
,
1
,
1
,
1
),
dt
.
datetime
(
2014
,
3
,
5
,
1
,
1
,
1
),
None
,
False
,
"due"
None
,
False
,
"due"
,
released
=
True
)
)
@scenario
(
'data/dates_scenario.xml'
)
@scenario
(
'data/dates_scenario.xml'
)
...
@@ -123,25 +127,29 @@ class TestDates(XBlockHandlerTestCase):
...
@@ -123,25 +127,29 @@ class TestDates(XBlockHandlerTestCase):
self
.
assert_is_open
(
self
.
assert_is_open
(
xblock
,
xblock
,
dt
.
datetime
(
2014
,
2
,
28
,
23
,
59
,
59
)
.
replace
(
tzinfo
=
pytz
.
utc
),
dt
.
datetime
(
2014
,
2
,
28
,
23
,
59
,
59
)
.
replace
(
tzinfo
=
pytz
.
utc
),
"submission"
,
False
,
"start"
"submission"
,
False
,
"start"
,
released
=
False
)
)
self
.
assert_is_open
(
self
.
assert_is_open
(
xblock
,
xblock
,
dt
.
datetime
(
2014
,
3
,
1
,
1
,
1
,
1
)
.
replace
(
tzinfo
=
pytz
.
utc
),
dt
.
datetime
(
2014
,
3
,
1
,
1
,
1
,
1
)
.
replace
(
tzinfo
=
pytz
.
utc
),
"submission"
,
True
,
None
"submission"
,
True
,
None
,
released
=
True
)
)
self
.
assert_is_open
(
self
.
assert_is_open
(
xblock
,
xblock
,
dt
.
datetime
(
2014
,
3
,
31
,
23
,
59
,
59
)
.
replace
(
tzinfo
=
pytz
.
utc
),
dt
.
datetime
(
2014
,
3
,
31
,
23
,
59
,
59
)
.
replace
(
tzinfo
=
pytz
.
utc
),
"submission"
,
True
,
None
"submission"
,
True
,
None
,
released
=
True
)
)
self
.
assert_is_open
(
self
.
assert_is_open
(
xblock
,
xblock
,
dt
.
datetime
(
2014
,
4
,
1
,
1
,
1
,
1
,
1
)
.
replace
(
tzinfo
=
pytz
.
utc
),
dt
.
datetime
(
2014
,
4
,
1
,
1
,
1
,
1
,
1
)
.
replace
(
tzinfo
=
pytz
.
utc
),
"submission"
,
False
,
"due"
"submission"
,
False
,
"due"
,
released
=
True
)
)
@scenario
(
'data/dates_scenario.xml'
)
@scenario
(
'data/dates_scenario.xml'
)
...
@@ -153,25 +161,29 @@ class TestDates(XBlockHandlerTestCase):
...
@@ -153,25 +161,29 @@ class TestDates(XBlockHandlerTestCase):
self
.
assert_is_open
(
self
.
assert_is_open
(
xblock
,
xblock
,
dt
.
datetime
(
2015
,
1
,
1
,
23
,
59
,
59
)
.
replace
(
tzinfo
=
pytz
.
utc
),
dt
.
datetime
(
2015
,
1
,
1
,
23
,
59
,
59
)
.
replace
(
tzinfo
=
pytz
.
utc
),
"peer-assessment"
,
False
,
"start"
"peer-assessment"
,
False
,
"start"
,
released
=
False
)
)
self
.
assert_is_open
(
self
.
assert_is_open
(
xblock
,
xblock
,
dt
.
datetime
(
2015
,
1
,
2
,
1
,
1
,
1
)
.
replace
(
tzinfo
=
pytz
.
utc
),
dt
.
datetime
(
2015
,
1
,
2
,
1
,
1
,
1
)
.
replace
(
tzinfo
=
pytz
.
utc
),
"peer-assessment"
,
True
,
None
"peer-assessment"
,
True
,
None
,
released
=
True
)
)
self
.
assert_is_open
(
self
.
assert_is_open
(
xblock
,
xblock
,
dt
.
datetime
(
2015
,
3
,
31
,
23
,
59
,
59
)
.
replace
(
tzinfo
=
pytz
.
utc
),
dt
.
datetime
(
2015
,
3
,
31
,
23
,
59
,
59
)
.
replace
(
tzinfo
=
pytz
.
utc
),
"peer-assessment"
,
True
,
None
"peer-assessment"
,
True
,
None
,
released
=
True
)
)
self
.
assert_is_open
(
self
.
assert_is_open
(
xblock
,
xblock
,
dt
.
datetime
(
2015
,
4
,
1
,
1
,
1
,
1
,
1
)
.
replace
(
tzinfo
=
pytz
.
utc
),
dt
.
datetime
(
2015
,
4
,
1
,
1
,
1
,
1
,
1
)
.
replace
(
tzinfo
=
pytz
.
utc
),
"peer-assessment"
,
False
,
"due"
"peer-assessment"
,
False
,
"due"
,
released
=
True
)
)
@scenario
(
'data/dates_scenario.xml'
)
@scenario
(
'data/dates_scenario.xml'
)
...
@@ -183,25 +195,29 @@ class TestDates(XBlockHandlerTestCase):
...
@@ -183,25 +195,29 @@ class TestDates(XBlockHandlerTestCase):
self
.
assert_is_open
(
self
.
assert_is_open
(
xblock
,
xblock
,
dt
.
datetime
(
2016
,
1
,
1
,
23
,
59
,
59
)
.
replace
(
tzinfo
=
pytz
.
utc
),
dt
.
datetime
(
2016
,
1
,
1
,
23
,
59
,
59
)
.
replace
(
tzinfo
=
pytz
.
utc
),
"self-assessment"
,
False
,
"start"
"self-assessment"
,
False
,
"start"
,
released
=
False
)
)
self
.
assert_is_open
(
self
.
assert_is_open
(
xblock
,
xblock
,
dt
.
datetime
(
2016
,
1
,
2
,
1
,
1
,
1
)
.
replace
(
tzinfo
=
pytz
.
utc
),
dt
.
datetime
(
2016
,
1
,
2
,
1
,
1
,
1
)
.
replace
(
tzinfo
=
pytz
.
utc
),
"self-assessment"
,
True
,
None
"self-assessment"
,
True
,
None
,
released
=
True
)
)
self
.
assert_is_open
(
self
.
assert_is_open
(
xblock
,
xblock
,
dt
.
datetime
(
2016
,
3
,
31
,
23
,
59
,
59
)
.
replace
(
tzinfo
=
pytz
.
utc
),
dt
.
datetime
(
2016
,
3
,
31
,
23
,
59
,
59
)
.
replace
(
tzinfo
=
pytz
.
utc
),
"self-assessment"
,
True
,
None
"self-assessment"
,
True
,
None
,
released
=
True
)
)
self
.
assert_is_open
(
self
.
assert_is_open
(
xblock
,
xblock
,
dt
.
datetime
(
2016
,
4
,
1
,
1
,
1
,
1
,
1
)
.
replace
(
tzinfo
=
pytz
.
utc
),
dt
.
datetime
(
2016
,
4
,
1
,
1
,
1
,
1
,
1
)
.
replace
(
tzinfo
=
pytz
.
utc
),
"self-assessment"
,
False
,
"due"
"self-assessment"
,
False
,
"due"
,
released
=
True
)
)
@scenario
(
'data/resolve_dates_scenario.xml'
)
@scenario
(
'data/resolve_dates_scenario.xml'
)
...
@@ -215,28 +231,53 @@ class TestDates(XBlockHandlerTestCase):
...
@@ -215,28 +231,53 @@ class TestDates(XBlockHandlerTestCase):
self
.
assert_is_open
(
self
.
assert_is_open
(
xblock
,
xblock
,
dt
.
datetime
(
2014
,
2
,
28
,
23
,
59
,
59
)
.
replace
(
tzinfo
=
pytz
.
utc
),
dt
.
datetime
(
2014
,
2
,
28
,
23
,
59
,
59
)
.
replace
(
tzinfo
=
pytz
.
utc
),
"peer-assessment"
,
False
,
"start"
"peer-assessment"
,
False
,
"start"
,
released
=
False
)
)
self
.
assert_is_open
(
self
.
assert_is_open
(
xblock
,
xblock
,
dt
.
datetime
(
2014
,
3
,
1
,
1
,
1
,
1
)
.
replace
(
tzinfo
=
pytz
.
utc
),
dt
.
datetime
(
2014
,
3
,
1
,
1
,
1
,
1
)
.
replace
(
tzinfo
=
pytz
.
utc
),
"peer-assessment"
,
True
,
None
"peer-assessment"
,
True
,
None
,
released
=
True
)
)
self
.
assert_is_open
(
self
.
assert_is_open
(
xblock
,
xblock
,
dt
.
datetime
(
2016
,
5
,
1
,
23
,
59
,
59
)
.
replace
(
tzinfo
=
pytz
.
utc
),
dt
.
datetime
(
2016
,
5
,
1
,
23
,
59
,
59
)
.
replace
(
tzinfo
=
pytz
.
utc
),
"peer-assessment"
,
True
,
None
"peer-assessment"
,
True
,
None
,
released
=
True
)
)
self
.
assert_is_open
(
self
.
assert_is_open
(
xblock
,
xblock
,
dt
.
datetime
(
2016
,
5
,
2
,
1
,
1
,
1
)
.
replace
(
tzinfo
=
pytz
.
utc
),
dt
.
datetime
(
2016
,
5
,
2
,
1
,
1
,
1
)
.
replace
(
tzinfo
=
pytz
.
utc
),
"peer-assessment"
,
False
,
"due"
"peer-assessment"
,
False
,
"due"
,
released
=
True
)
)
def
assert_is_open
(
self
,
xblock
,
now
,
step
,
expected_is_open
,
expected_reason
):
@scenario
(
'data/basic_scenario.xml'
)
def
test_is_released_unpublished
(
self
,
xblock
):
# Simulate the runtime published_date mixin field
# The scenario doesn't provide a start date, so `is_released()`
# should be controlled only by the published date.
xblock
.
published_date
=
None
self
.
assertFalse
(
xblock
.
is_released
())
@scenario
(
'data/basic_scenario.xml'
)
def
test_is_released_published
(
self
,
xblock
):
# Simulate the runtime published_date mixin field
# The scenario doesn't provide a start date, so `is_released()`
# should be controlled only by the published date.
xblock
.
published_date
=
dt
.
datetime
(
2013
,
1
,
1
)
.
replace
(
tzinfo
=
pytz
.
utc
)
self
.
assertTrue
(
xblock
.
is_released
())
@scenario
(
'data/basic_scenario.xml'
)
def
test_is_released_no_published_date_field
(
self
,
xblock
):
# If the runtime doesn't provide a published_date field, assume we've been published
self
.
assertTrue
(
xblock
.
is_released
())
def
assert_is_open
(
self
,
xblock
,
now
,
step
,
expected_is_open
,
expected_reason
,
released
=
None
):
"""
"""
Assert whether the XBlock step is open/closed.
Assert whether the XBlock step is open/closed.
...
@@ -247,6 +288,9 @@ class TestDates(XBlockHandlerTestCase):
...
@@ -247,6 +288,9 @@ class TestDates(XBlockHandlerTestCase):
expected_is_open (bool): Do we expect the step to be open or closed?
expected_is_open (bool): Do we expect the step to be open or closed?
expecetd_reason (str): Either "start", "due", or None.
expecetd_reason (str): Either "start", "due", or None.
Kwargs:
released (bool): If set, check whether the XBlock has been released.
Raises:
Raises:
AssertionError
AssertionError
"""
"""
...
@@ -261,3 +305,6 @@ class TestDates(XBlockHandlerTestCase):
...
@@ -261,3 +305,6 @@ class TestDates(XBlockHandlerTestCase):
is_open
,
reason
=
xblock
.
is_open
(
step
=
step
)
is_open
,
reason
=
xblock
.
is_open
(
step
=
step
)
self
.
assertEqual
(
is_open
,
expected_is_open
)
self
.
assertEqual
(
is_open
,
expected_is_open
)
self
.
assertEqual
(
reason
,
expected_reason
)
self
.
assertEqual
(
reason
,
expected_reason
)
if
released
is
not
None
:
self
.
assertEqual
(
xblock
.
is_released
(
step
=
step
),
released
)
apps/openassessment/xblock/test/test_studio.py
View file @
e12f27d3
...
@@ -3,8 +3,10 @@ View-level tests for Studio view of OpenAssessment XBlock.
...
@@ -3,8 +3,10 @@ View-level tests for Studio view of OpenAssessment XBlock.
"""
"""
import
json
import
json
import
datetime
as
dt
import
lxml.etree
as
etree
import
lxml.etree
as
etree
import
mock
import
mock
import
pytz
from
ddt
import
ddt
,
data
from
ddt
import
ddt
,
data
from
.base
import
scenario
,
XBlockHandlerTestCase
from
.base
import
scenario
,
XBlockHandlerTestCase
...
@@ -44,6 +46,10 @@ class StudioViewTest(XBlockHandlerTestCase):
...
@@ -44,6 +46,10 @@ class StudioViewTest(XBlockHandlerTestCase):
@scenario
(
'data/basic_scenario.xml'
)
@scenario
(
'data/basic_scenario.xml'
)
def
test_update_xml
(
self
,
xblock
):
def
test_update_xml
(
self
,
xblock
):
# Set the XBlock's release date to the future,
# so we are not restricted in what we can edit
xblock
.
start
=
dt
.
datetime
(
3000
,
1
,
1
)
.
replace
(
tzinfo
=
pytz
.
utc
)
.
isoformat
()
request
=
json
.
dumps
({
'xml'
:
self
.
load_fixture_str
(
'data/updated_block.xml'
)})
request
=
json
.
dumps
({
'xml'
:
self
.
load_fixture_str
(
'data/updated_block.xml'
)})
# Verify the response is successfully
# Verify the response is successfully
...
@@ -60,6 +66,17 @@ class StudioViewTest(XBlockHandlerTestCase):
...
@@ -60,6 +66,17 @@ class StudioViewTest(XBlockHandlerTestCase):
self
.
assertEqual
(
xblock
.
rubric_criteria
[
0
][
'prompt'
],
'Test criterion prompt'
)
self
.
assertEqual
(
xblock
.
rubric_criteria
[
0
][
'prompt'
],
'Test criterion prompt'
)
@scenario
(
'data/basic_scenario.xml'
)
@scenario
(
'data/basic_scenario.xml'
)
def
test_update_xml_post_release
(
self
,
xblock
):
# XBlock start date defaults to already open,
# so we should get an error when trying to update anything that change the number of points
request
=
json
.
dumps
({
'xml'
:
self
.
load_fixture_str
(
'data/updated_block.xml'
)})
# Verify the response is successfully
resp
=
self
.
request
(
xblock
,
'update_xml'
,
request
,
response_format
=
'json'
)
self
.
assertFalse
(
resp
[
'success'
])
@scenario
(
'data/basic_scenario.xml'
)
def
test_update_xml_invalid_request_data
(
self
,
xblock
):
def
test_update_xml_invalid_request_data
(
self
,
xblock
):
resp
=
self
.
request
(
xblock
,
'update_xml'
,
json
.
dumps
({}),
response_format
=
'json'
)
resp
=
self
.
request
(
xblock
,
'update_xml'
,
json
.
dumps
({}),
response_format
=
'json'
)
self
.
assertFalse
(
resp
[
'success'
])
self
.
assertFalse
(
resp
[
'success'
])
...
...
apps/openassessment/xblock/test/test_validation.py
View file @
e12f27d3
...
@@ -41,18 +41,19 @@ class AssessmentValidationTest(TestCase):
...
@@ -41,18 +41,19 @@ class AssessmentValidationTest(TestCase):
self
.
assertGreater
(
len
(
msg
),
0
)
self
.
assertGreater
(
len
(
msg
),
0
)
@ddt.ddt
@ddt.ddt
class
RubricValidationTest
(
TestCase
):
class
RubricValidationTest
(
TestCase
):
@ddt.file_data
(
'data/valid_rubrics.json'
)
@ddt.file_data
(
'data/valid_rubrics.json'
)
def
test_valid_assessment
(
self
,
data
):
def
test_valid_assessment
(
self
,
data
):
success
,
msg
=
validate_rubric
(
data
[
'rubric'
])
success
,
msg
=
validate_rubric
(
data
[
'rubric'
]
,
data
[
'current_rubric'
],
data
[
'is_released'
]
)
self
.
assertTrue
(
success
)
self
.
assertTrue
(
success
)
self
.
assertEqual
(
msg
,
u''
)
self
.
assertEqual
(
msg
,
u''
)
@ddt.file_data
(
'data/invalid_rubrics.json'
)
@ddt.file_data
(
'data/invalid_rubrics.json'
)
def
test_invalid_assessment
(
self
,
data
):
def
test_invalid_assessment
(
self
,
data
):
success
,
msg
=
validate_rubric
(
data
[
'rubric'
])
success
,
msg
=
validate_rubric
(
data
[
'rubric'
]
,
data
[
'current_rubric'
],
data
[
'is_released'
]
)
self
.
assertFalse
(
success
)
self
.
assertFalse
(
success
)
self
.
assertGreater
(
len
(
msg
),
0
)
self
.
assertGreater
(
len
(
msg
),
0
)
...
...
apps/openassessment/xblock/validation.py
View file @
e12f27d3
"""
"""
Validate changes to an XBlock before it is updated.
"""
"""
from
django.utils.translation
import
ugettext
as
_
from
django.utils.translation
import
ugettext
as
_
from
openassessment.assessment.serializers
import
rubric_from_dict
,
InvalidRubric
from
openassessment.assessment.serializers
import
rubric_from_dict
,
InvalidRubric
from
openassessment.xblock.resolve_dates
import
resolve_dates
,
DateValidationError
,
InvalidDateFormat
from
openassessment.xblock.resolve_dates
import
resolve_dates
,
DateValidationError
,
InvalidDateFormat
def
_match_by_name
(
items
,
others
):
"""
Given two lists of dictionaries, each containing "name" keys,
return a set of tuples, where the items in the tuple are dictionaries
with the same "name" keys.
Args:
items (list of dict): Items to match, each of which must contain a "name" key.
others (list of dict): Items to match, each of which must contain a "name" key.
Returns:
list of tuples, each containing two dictionaries
Raises:
IndexError: A dictionary does no contain a 'name' key.
"""
# Sort each dictionary by its "name" key, then zip them and return
key_func
=
lambda
x
:
x
[
'name'
]
return
zip
(
sorted
(
items
,
key
=
key_func
),
sorted
(
others
,
key
=
key_func
))
def
validate_assessments
(
assessments
,
enforce_peer_then_self
=
False
):
def
validate_assessments
(
assessments
,
enforce_peer_then_self
=
False
):
"""
"""
Check that the assessment dict is semantically valid.
Check that the assessment dict is semantically valid.
...
@@ -54,12 +76,14 @@ def validate_assessments(assessments, enforce_peer_then_self=False):
...
@@ -54,12 +76,14 @@ def validate_assessments(assessments, enforce_peer_then_self=False):
return
(
True
,
u''
)
return
(
True
,
u''
)
def
validate_rubric
(
rubric_dict
):
def
validate_rubric
(
rubric_dict
,
current_rubric
,
is_released
):
"""
"""
Check that the rubric is semantically valid.
Check that the rubric is semantically valid.
Args:
Args:
rubric_dict (dict): Serialized Rubric model
rubric_dict (dict): Serialized Rubric model representing the updated state of the rubric.
current_rubric (dict): Serialized Rubric model representing the current state of the rubric.
is_released (bool): True if and only if the problem has been released.
Returns:
Returns:
tuple (is_valid, msg) where
tuple (is_valid, msg) where
...
@@ -70,7 +94,25 @@ def validate_rubric(rubric_dict):
...
@@ -70,7 +94,25 @@ def validate_rubric(rubric_dict):
rubric_from_dict
(
rubric_dict
)
rubric_from_dict
(
rubric_dict
)
except
InvalidRubric
:
except
InvalidRubric
:
return
(
False
,
u'Rubric definition is not valid'
)
return
(
False
,
u'Rubric definition is not valid'
)
# After a problem is released, authors are allowed to change text,
# but nothing that would change the point value of a rubric.
if
is_released
:
# Number of criteria must be the same
if
len
(
rubric_dict
[
'criteria'
])
!=
len
(
current_rubric
[
'criteria'
]):
return
(
False
,
u'Number of criteria cannot be changed after a problem is released.'
)
# Number of options for each criterion must be the same
for
new_criterion
,
old_criterion
in
_match_by_name
(
rubric_dict
[
'criteria'
],
current_rubric
[
'criteria'
]):
if
len
(
new_criterion
[
'options'
])
!=
len
(
old_criterion
[
'options'
]):
return
(
False
,
u'Number of options cannot be changed after a problem is released.'
)
else
:
else
:
for
new_option
,
old_option
in
_match_by_name
(
new_criterion
[
'options'
],
old_criterion
[
'options'
]):
if
new_option
[
'points'
]
!=
old_option
[
'points'
]:
return
(
False
,
u'Point values cannot be changed after a problem is released.'
)
return
(
True
,
u''
)
return
(
True
,
u''
)
...
@@ -96,30 +138,41 @@ def validate_dates(start, end, date_ranges):
...
@@ -96,30 +138,41 @@ def validate_dates(start, end, date_ranges):
return
(
True
,
u''
)
return
(
True
,
u''
)
def
validator
(
start
,
d
ue
):
def
validator
(
oa_block
,
strict_post_release
=
Tr
ue
):
"""
"""
Return a validator function configured
with the problem's start and end dates
.
Return a validator function configured
for the XBlock
.
This will validate assessments, rubrics, and dates.
This will validate assessments, rubrics, and dates.
Args:
Args:
start (str): ISO-formatted date string indicating when the problem opens.
oa_block (OpenAssessmentBlock): The XBlock being updated.
end (str): ISO-formatted date string indicating when the problem closes.
Kwargs:
strict_post_release (bool): If true, restrict what authors can update once
a problem has been released.
Returns:
Returns:
callable, of a form that can be passed to `update_from_xml`.
callable, of a form that can be passed to `update_from_xml`.
"""
"""
def
_inner
(
rubric_dict
,
submission_dict
,
assessments
):
def
_inner
(
rubric_dict
,
submission_dict
,
assessments
):
success
,
msg
=
validate_assessments
(
assessments
,
enforce_peer_then_self
=
True
)
success
,
msg
=
validate_assessments
(
assessments
,
enforce_peer_then_self
=
True
)
if
not
success
:
if
not
success
:
return
(
False
,
msg
)
return
(
False
,
msg
)
success
,
msg
=
validate_rubric
(
rubric_dict
)
current_rubric
=
{
'prompt'
:
oa_block
.
prompt
,
'criteria'
:
oa_block
.
rubric_criteria
}
success
,
msg
=
validate_rubric
(
rubric_dict
,
current_rubric
,
strict_post_release
and
oa_block
.
is_released
()
)
if
not
success
:
if
not
success
:
return
(
False
,
msg
)
return
(
False
,
msg
)
submission_dates
=
[(
start
,
submission_dict
[
'due'
])]
submission_dates
=
[(
oa_block
.
start
,
submission_dict
[
'due'
])]
assessment_dates
=
[(
asmnt
[
'start'
],
asmnt
[
'due'
])
for
asmnt
in
assessments
]
assessment_dates
=
[(
asmnt
[
'start'
],
asmnt
[
'due'
])
for
asmnt
in
assessments
]
success
,
msg
=
validate_dates
(
start
,
due
,
submission_dates
+
assessment_dates
)
success
,
msg
=
validate_dates
(
oa_block
.
start
,
oa_block
.
due
,
submission_dates
+
assessment_dates
)
if
not
success
:
if
not
success
:
return
(
False
,
msg
)
return
(
False
,
msg
)
...
...
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