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
61a38ec8
Commit
61a38ec8
authored
Dec 12, 2017
by
Bill Filler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix comments from review
parent
1cac8216
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
44 additions
and
42 deletions
+44
-42
common/lib/xmodule/xmodule/seq_module.py
+7
-4
openedx/core/lib/gating/api.py
+12
-5
openedx/core/lib/gating/services.py
+25
-33
No files found.
common/lib/xmodule/xmodule/seq_module.py
View file @
61a38ec8
...
...
@@ -292,7 +292,7 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule):
self
.
_update_position
(
context
,
len
(
display_items
))
prereq_met
=
True
if
self
.
_
find_gating_milestone
():
if
self
.
_
is_prereq_required
():
if
self
.
runtime
.
user_is_staff
:
banner_text
=
_
(
'This subsection is unlocked for learners when they meet the prerequisite requirements.'
)
else
:
...
...
@@ -323,13 +323,16 @@ class SequenceModule(SequenceFields, ProctoringFields, XModule):
return
fragment
def
_
find_gating_milestone
(
self
):
def
_
is_prereq_required
(
self
):
"""
Checks whether a gating milestone exists for this Section
Checks whether a prerequiste is required for this Section
Returns:
milestone if a prereq is required, False otherwise
"""
gating_service
=
self
.
runtime
.
service
(
self
,
'gating'
)
if
gating_service
:
milestone
=
gating_service
.
get_gating_milestone
(
milestone
=
gating_service
.
is_prereq_required
(
self
.
course_id
,
self
.
location
,
'requires'
)
return
milestone
...
...
openedx/core/lib/gating/api.py
View file @
61a38ec8
...
...
@@ -148,7 +148,7 @@ def get_prerequisites(course_key):
milestones_by_block_id
=
{}
block_ids
=
[]
for
milestone
in
course_content_milestones
:
prereq_content_key
=
milestone
[
'namespace'
]
.
replace
(
GATING_NAMESPACE_QUALIFIER
,
''
)
prereq_content_key
=
_get_gating_block_id
(
milestone
)
block_id
=
UsageKey
.
from_string
(
prereq_content_key
)
.
block_id
block_ids
.
append
(
block_id
)
milestones_by_block_id
[
block_id
]
=
milestone
...
...
@@ -273,7 +273,7 @@ def get_required_content(course_key, gated_content_key):
milestone
=
get_gating_milestone
(
course_key
,
gated_content_key
,
'requires'
)
if
milestone
:
return
(
milestone
.
get
(
'namespace'
,
''
)
.
replace
(
GATING_NAMESPACE_QUALIFIER
,
''
),
_get_gating_block_id
(
milestone
),
milestone
.
get
(
'requirements'
,
{})
.
get
(
'min_score'
)
)
else
:
...
...
@@ -317,7 +317,7 @@ def is_prereq_met(content_id, user_id, recalc_on_unmet=False):
Returns:
tuple: True|False,
prereq_meta_info = { 'url': prereq_url
, 'display_name': prereq_nam
e}
prereq_meta_info = { 'url': prereq_url
|None, 'display_name': prereq_name|Non
e}
"""
course_id
=
content_id
.
course_key
...
...
@@ -329,9 +329,10 @@ def is_prereq_met(content_id, user_id, recalc_on_unmet=False):
user_id
)
prereq_met
=
not
unfulfilled_milestones
prereq_meta_info
=
{
'url'
:
None
,
'display_name'
:
None
}
if
prereq_met
or
not
recalc_on_unmet
:
return
prereq_met
,
{}
return
prereq_met
,
prereq_meta_info
milestone
=
unfulfilled_milestones
[
0
]
student
=
User
.
objects
.
get
(
id
=
user_id
)
...
...
@@ -341,7 +342,7 @@ def is_prereq_met(content_id, user_id, recalc_on_unmet=False):
course_structure
=
get_course_blocks
(
student
,
store
.
make_course_usage_key
(
course_id
))
course
=
store
.
get_course
(
course_id
,
depth
=
0
)
subsection_grade_factory
=
SubsectionGradeFactory
(
student
,
course
,
course_structure
)
subsection_usage_key
=
UsageKey
.
from_string
(
milestone
[
'namespace'
]
.
replace
(
GATING_NAMESPACE_QUALIFIER
,
''
))
subsection_usage_key
=
UsageKey
.
from_string
(
_get_gating_block_id
(
milestone
))
if
subsection_usage_key
in
course_structure
:
# this will force a recalcuation of the subsection grade
...
...
@@ -376,6 +377,12 @@ def update_milestone(milestone, subsection_grade, prereq_milestone, user_id):
milestones_helpers
.
remove_user_milestone
({
'id'
:
user_id
},
prereq_milestone
)
return
False
def
_get_gating_block_id
(
milestone
):
"""
Return the block id of the gating milestone
"""
return
milestone
.
get
(
'namespace'
,
''
)
.
replace
(
GATING_NAMESPACE_QUALIFIER
,
''
)
def
_get_minimum_required_percentage
(
milestone
):
"""
Returns the minimum percentage requirement for the given milestone.
...
...
openedx/core/lib/gating/services.py
View file @
61a38ec8
"""
A wrapper class
around requested methods exposed in api.py
A wrapper class
to communicate with Gating api
"""
import
types
from
.
import
api
as
gating_api
class
GatingService
(
object
):
# pylint: disable=too-few-public-methods
class
GatingService
(
object
):
"""
An xBlock service for xBlocks to talk to the Gating api.
NOTE: This is a Singleton class. We should only have one instance of it!
An XBlock service to talk to the Gating api.
"""
_instance
=
None
def
is_prereq_met
(
self
,
content_id
,
user_id
,
recalc_on_unmet
=
False
):
"""
Returns true if the prequiste has been met for a given milestone
REQUESTED_FUNCTIONS
=
[
'get_gating_milestone_meta_info'
,
'get_gating_milestone'
,
'is_prereq_met'
]
Arguments:
content_id (BlockUsageLocator): BlockUsageLocator for the content
user_id: The id of the user
recalc_on_unmet: Recalculate the grade if prereq has not yet been met
def
__new__
(
cls
,
*
args
,
**
kwargs
):
"""
This is the class factory to make sure this is a Singleton
"""
if
not
cls
.
_instance
:
cls
.
_instance
=
super
(
GatingService
,
cls
)
.
__new__
(
cls
,
*
args
,
**
kwargs
)
return
cls
.
_instance
Returns:
tuple: True|False,
prereq_meta_info = { 'url': prereq_url|None, 'display_name': prereq_name|None}
"""
return
gating_api
.
is_prereq_met
(
content_id
,
user_id
,
recalc_on_unmet
)
def
__init__
(
self
):
"""
Class initializer, which just inspects the libraries and exposes the same functions
listed in REQUESTED_FUNCTIONS
def
is_prereq_required
(
self
,
course_key
,
content_key
,
relationship
):
"""
self
.
_bind_to_requested_functions
()
Returns the prerequiste if one is required
def
_bind_to_requested_functions
(
self
):
"""
bind module functions. Since we use underscores to mean private methods, let's exclude those.
Arguments:
course_key (str|CourseKey): The course key
content_key (str|UsageKey): The content usage key
relationship (str): The relationship type (e.g. 'requires')
Returns:
dict or None: The gating milestone dict or None
"""
for
attr_name
in
self
.
REQUESTED_FUNCTIONS
:
attr
=
getattr
(
gating_api
,
attr_name
,
None
)
if
isinstance
(
attr
,
types
.
FunctionType
)
and
not
attr_name
.
startswith
(
'_'
):
if
not
hasattr
(
self
,
attr_name
):
setattr
(
self
,
attr_name
,
attr
)
return
gating_api
.
get_gating_milestone
(
course_key
,
content_key
,
relationship
)
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