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
64c4ae4a
Commit
64c4ae4a
authored
Nov 24, 2017
by
Tomasz Gargas
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add block completion value as optional field in course_blocks.api.
Signed-off-by: Tomasz Gargas <tomasz@opencraft.com>
parent
3cc25a30
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
225 additions
and
3 deletions
+225
-3
lms/djangoapps/course_api/blocks/api.py
+9
-3
lms/djangoapps/course_api/blocks/transformers/__init__.py
+6
-0
lms/djangoapps/course_api/blocks/transformers/block_completion.py
+86
-0
lms/djangoapps/course_api/blocks/transformers/tests/test_block_completion.py
+118
-0
lms/djangoapps/course_api/blocks/views.py
+5
-0
setup.py
+1
-0
No files found.
lms/djangoapps/course_api/blocks/api.py
View file @
64c4ae4a
...
...
@@ -8,6 +8,7 @@ from openedx.core.djangoapps.content.block_structure.transformers import BlockSt
from
.serializers
import
BlockDictSerializer
,
BlockSerializer
from
.transformers.blocks_api
import
BlocksAPITransformer
from
.transformers.block_completion
import
BlockCompletionTransformer
from
.transformers.milestones
import
MilestonesAndSpecialExamsTransformer
...
...
@@ -51,9 +52,11 @@ def get_blocks(
"""
# create ordered list of transformers, adding BlocksAPITransformer at end.
transformers
=
BlockStructureTransformers
()
include_special_exams
=
False
if
requested_fields
is
not
None
and
'special_exam_info'
in
requested_fields
:
include_special_exams
=
True
if
requested_fields
is
None
:
requested_fields
=
[]
include_completion
=
'completion'
in
requested_fields
include_special_exams
=
'special_exam_info'
in
requested_fields
if
user
is
not
None
:
transformers
+=
COURSE_BLOCK_ACCESS_TRANSFORMERS
transformers
+=
[
MilestonesAndSpecialExamsTransformer
(
include_special_exams
),
HiddenContentTransformer
()]
...
...
@@ -66,6 +69,9 @@ def get_blocks(
)
]
if
include_completion
:
transformers
+=
[
BlockCompletionTransformer
()]
# transform
blocks
=
get_course_blocks
(
user
,
usage_key
,
transformers
)
...
...
lms/djangoapps/course_api/blocks/transformers/__init__.py
View file @
64c4ae4a
...
...
@@ -4,6 +4,7 @@ Course API Block Transformers
from
lms.djangoapps.course_blocks.transformers.visibility
import
VisibilityTransformer
from
.student_view
import
StudentViewTransformer
from
.block_completion
import
BlockCompletionTransformer
from
.block_counts
import
BlockCountsTransformer
from
.navigation
import
BlockNavigationTransformer
from
.milestones
import
MilestonesAndSpecialExamsTransformer
...
...
@@ -63,5 +64,10 @@ SUPPORTED_FIELDS = [
'merged_visible_to_staff_only'
,
VisibilityTransformer
,
requested_field_name
=
'visible_to_staff_only'
,
),
SupportedFieldType
(
BlockCompletionTransformer
.
COMPLETION
,
BlockCompletionTransformer
,
'completion'
)
]
lms/djangoapps/course_api/blocks/transformers/block_completion.py
0 → 100644
View file @
64c4ae4a
"""
Block Completion Transformer
"""
from
xblock.completable
import
XBlockCompletionMode
as
CompletionMode
from
lms.djangoapps.completion.models
import
BlockCompletion
from
openedx.core.djangoapps.content.block_structure.transformer
import
BlockStructureTransformer
class
BlockCompletionTransformer
(
BlockStructureTransformer
):
"""
Keep track of the completion of each block within the block structure.
"""
READ_VERSION
=
0
WRITE_VERSION
=
1
COMPLETION
=
'completion'
def
__init__
(
self
):
super
(
BlockCompletionTransformer
,
self
)
.
__init__
()
@classmethod
def
name
(
cls
):
return
"blocks_api:completion"
@classmethod
def
get_block_completion
(
cls
,
block_structure
,
block_key
):
"""
Return the precalculated completion of a block within the block_structure:
Arguments:
block_structure: a BlockStructure instance
block_key: the key of the block whose completion we want to know
Returns:
block_completion: float or None
"""
return
block_structure
.
get_transformer_block_field
(
block_key
,
cls
,
cls
.
COMPLETION
,
)
@classmethod
def
collect
(
cls
,
block_structure
):
block_structure
.
request_xblock_fields
(
'completion_mode'
)
def
transform
(
self
,
usage_info
,
block_structure
):
"""
Mutates block_structure adding extra field which contains block's completion.
"""
def
_is_block_an_aggregator_or_excluded
(
block_key
):
"""
Checks whether block's completion method
is of `AGGREGATOR` or `EXCLUDED` type.
"""
completion_mode
=
block_structure
.
get_xblock_field
(
block_key
,
'completion_mode'
)
return
completion_mode
in
(
CompletionMode
.
AGGREGATOR
,
CompletionMode
.
EXCLUDED
)
completions
=
BlockCompletion
.
objects
.
filter
(
user
=
usage_info
.
user
,
course_key
=
usage_info
.
course_key
,
)
.
values_list
(
'block_key'
,
'completion'
,
)
completions_dict
=
{
block
.
map_into_course
(
usage_info
.
course_key
):
completion
for
block
,
completion
in
completions
}
for
block_key
in
block_structure
.
topological_traversal
():
if
_is_block_an_aggregator_or_excluded
(
block_key
):
completion_value
=
None
elif
block_key
in
completions_dict
:
completion_value
=
completions_dict
[
block_key
]
else
:
completion_value
=
0.0
block_structure
.
set_transformer_block_field
(
block_key
,
self
,
self
.
COMPLETION
,
completion_value
)
lms/djangoapps/course_api/blocks/transformers/tests/test_block_completion.py
0 → 100644
View file @
64c4ae4a
"""
Tests for BlockCompletionTransformer.
"""
from
xblock.core
import
XBlock
from
xblock.completable
import
CompletableXBlockMixin
,
XBlockCompletionMode
from
lms.djangoapps.completion.models
import
BlockCompletion
from
lms.djangoapps.completion.test_utils
import
CompletionWaffleTestMixin
from
lms.djangoapps.course_api.blocks.transformers.block_completion
import
BlockCompletionTransformer
from
lms.djangoapps.course_blocks.transformers.tests.helpers
import
ModuleStoreTestCase
,
TransformerRegistryTestMixin
from
student.tests.factories
import
UserFactory
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
from
...api
import
get_course_blocks
class
StubAggregatorXBlock
(
XBlock
):
"""
XBlock to test behaviour of BlockCompletionTransformer
when transforming aggregator XBlock.
"""
completion_mode
=
XBlockCompletionMode
.
AGGREGATOR
class
StubExcludedXBlock
(
XBlock
):
"""
XBlock to test behaviour of BlockCompletionTransformer
when transforming excluded XBlock.
"""
completion_mode
=
XBlockCompletionMode
.
EXCLUDED
class
StubCompletableXBlock
(
XBlock
,
CompletableXBlockMixin
):
"""
XBlock to test behaviour of BlockCompletionTransformer
when transforming completable XBlock.
"""
pass
class
BlockCompletionTransformerTestCase
(
TransformerRegistryTestMixin
,
ModuleStoreTestCase
,
CompletionWaffleTestMixin
):
"""
Tests behaviour of BlockCompletionTransformer
"""
TRANSFORMER_CLASS_TO_TEST
=
BlockCompletionTransformer
COMPLETION_TEST_VALUE
=
0.4
def
setUp
(
self
):
super
(
BlockCompletionTransformerTestCase
,
self
)
.
setUp
()
self
.
user
=
UserFactory
.
create
(
password
=
'test'
)
self
.
override_waffle_switch
(
True
)
@XBlock.register_temp_plugin
(
StubAggregatorXBlock
,
identifier
=
'aggregator'
)
def
test_transform_gives_none_for_aggregator
(
self
):
course
=
CourseFactory
.
create
()
block
=
ItemFactory
.
create
(
category
=
'aggregator'
,
parent
=
course
)
block_structure
=
get_course_blocks
(
self
.
user
,
course
.
location
,
self
.
transformers
)
self
.
_assert_block_has_proper_completion_value
(
block_structure
,
block
.
location
,
None
)
@XBlock.register_temp_plugin
(
StubExcludedXBlock
,
identifier
=
'excluded'
)
def
test_transform_gives_none_for_excluded
(
self
):
course
=
CourseFactory
.
create
()
block
=
ItemFactory
.
create
(
category
=
'excluded'
,
parent
=
course
)
block_structure
=
get_course_blocks
(
self
.
user
,
course
.
location
,
self
.
transformers
)
self
.
_assert_block_has_proper_completion_value
(
block_structure
,
block
.
location
,
None
)
@XBlock.register_temp_plugin
(
StubCompletableXBlock
,
identifier
=
'comp'
)
def
test_transform_gives_value_for_completable
(
self
):
course
=
CourseFactory
.
create
()
block
=
ItemFactory
.
create
(
category
=
'comp'
,
parent
=
course
)
BlockCompletion
.
objects
.
submit_completion
(
user
=
self
.
user
,
course_key
=
block
.
location
.
course_key
,
block_key
=
block
.
location
,
completion
=
self
.
COMPLETION_TEST_VALUE
,
)
block_structure
=
get_course_blocks
(
self
.
user
,
course
.
location
,
self
.
transformers
)
self
.
_assert_block_has_proper_completion_value
(
block_structure
,
block
.
location
,
self
.
COMPLETION_TEST_VALUE
)
def
test_transform_gives_zero_for_ordinary_block
(
self
):
course
=
CourseFactory
.
create
()
block
=
ItemFactory
.
create
(
category
=
'html'
,
parent
=
course
)
block_structure
=
get_course_blocks
(
self
.
user
,
course
.
location
,
self
.
transformers
)
self
.
_assert_block_has_proper_completion_value
(
block_structure
,
block
.
location
,
0.0
)
def
_assert_block_has_proper_completion_value
(
self
,
block_structure
,
block_key
,
expected_value
):
"""
Checks whether block's completion has expected value.
"""
block_data
=
block_structure
.
get_transformer_block_data
(
block_key
,
self
.
TRANSFORMER_CLASS_TO_TEST
)
completion_value
=
block_data
.
fields
[
'completion'
]
self
.
assertEqual
(
completion_value
,
expected_value
)
lms/djangoapps/course_api/blocks/views.py
View file @
64c4ae4a
...
...
@@ -128,6 +128,11 @@ class BlocksView(DeveloperErrorViewMixin, ListAPIView):
the child blocks. Returned only if "children" is included in the
"requested_fields" parameter.
* completion: (float or None) The level of completion of the block.
Its value can vary between 0.0 and 1.0 or be equal to None
if block is not completable. Returned only if "completion"
is included in the "requested_fields" parameter.
* block_counts: (dict) For each block type specified in the
block_counts parameter to the endpoint, the aggregate number of
blocks of that type for this block and all of its descendants.
...
...
setup.py
View file @
64c4ae4a
...
...
@@ -58,6 +58,7 @@ setup(
"course_blocks_api = lms.djangoapps.course_api.blocks.transformers.blocks_api:BlocksAPITransformer"
,
"milestones = lms.djangoapps.course_api.blocks.transformers.milestones:MilestonesAndSpecialExamsTransformer"
,
"grades = lms.djangoapps.grades.transformer:GradesTransformer"
,
"completion = lms.djangoapps.course_api.blocks.transformers.block_completion:BlockCompletionTransformer"
],
"openedx.ace.policy"
:
[
"bulk_email_optout = lms.djangoapps.bulk_email.policies:CourseEmailOptout"
...
...
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