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
810733db
Commit
810733db
authored
May 28, 2015
by
aamir-khan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ECOM-1592: Adding incourse reverification as a credit requirement in course
parent
d3dde855
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
135 additions
and
16 deletions
+135
-16
openedx/core/djangoapps/credit/signals.py
+1
-1
openedx/core/djangoapps/credit/tasks.py
+107
-14
openedx/core/djangoapps/credit/tests/test_tasks.py
+27
-1
No files found.
openedx/core/djangoapps/credit/signals.py
View file @
810733db
...
@@ -8,7 +8,7 @@ from xmodule.modulestore.django import SignalHandler
...
@@ -8,7 +8,7 @@ from xmodule.modulestore.django import SignalHandler
@receiver
(
SignalHandler
.
course_published
)
@receiver
(
SignalHandler
.
course_published
)
def
listen_for_course_publish
(
sender
,
course_key
,
**
kwargs
):
# pylint: disable=unused-argument
def
listen_for_course_publish
(
sender
,
course_key
,
**
kwargs
):
# pylint: disable=unused-argument
"""
"""
Receives signal and kicks off celery task to update the course requirements
Receives signal and kicks off celery task to update the course requirements
.
"""
"""
# import here, because signal is registered at startup, but items in tasks are not yet able to be loaded
# import here, because signal is registered at startup, but items in tasks are not yet able to be loaded
...
...
openedx/core/djangoapps/credit/tasks.py
View file @
810733db
...
@@ -13,35 +13,27 @@ from openedx.core.djangoapps.credit.models import CreditCourse
...
@@ -13,35 +13,27 @@ from openedx.core.djangoapps.credit.models import CreditCourse
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
LOGGER
=
get_task_logger
(
__name__
)
LOGGER
=
get_task_logger
(
__name__
)
# pylint: disable=not-callable
# pylint: disable=not-callable
@task
(
default_retry_delay
=
settings
.
CREDIT_TASK_DEFAULT_RETRY_DELAY
,
max_retries
=
settings
.
CREDIT_TASK_MAX_RETRIES
)
@task
(
default_retry_delay
=
settings
.
CREDIT_TASK_DEFAULT_RETRY_DELAY
,
max_retries
=
settings
.
CREDIT_TASK_MAX_RETRIES
)
def
update_course_requirements
(
course_id
):
def
update_course_requirements
(
course_id
):
"""
Updates course requirements table for a course.
"""Updates course requirements table for a course.
Args:
Args:
course_id(str): A string representation of course identifier
course_id(str): A string representation of course identifier
Returns:
Returns:
None
None
"""
"""
try
:
try
:
course_key
=
CourseKey
.
from_string
(
course_id
)
course_key
=
CourseKey
.
from_string
(
course_id
)
is_credit_course
=
CreditCourse
.
is_credit_course
(
course_key
)
is_credit_course
=
CreditCourse
.
is_credit_course
(
course_key
)
if
is_credit_course
:
if
is_credit_course
:
course
=
modulestore
()
.
get_course
(
course_key
)
course
=
modulestore
()
.
get_course
(
course_key
)
requirements
=
[
requirements
=
_get_course_credit_requirements
(
course
)
{
"namespace"
:
"grade"
,
"name"
:
"grade"
,
"criteria"
:
{
"min_grade"
:
get_min_grade_for_credit
(
course
)
}
}
]
set_credit_requirements
(
course_key
,
requirements
)
set_credit_requirements
(
course_key
,
requirements
)
except
(
InvalidKeyError
,
ItemNotFoundError
,
InvalidCreditRequirements
)
as
exc
:
except
(
InvalidKeyError
,
ItemNotFoundError
,
InvalidCreditRequirements
)
as
exc
:
LOGGER
.
error
(
'Error on adding the requirements for course
%
s -
%
s'
,
course_id
,
unicode
(
exc
))
LOGGER
.
error
(
'Error on adding the requirements for course
%
s -
%
s'
,
course_id
,
unicode
(
exc
))
...
@@ -50,6 +42,107 @@ def update_course_requirements(course_id):
...
@@ -50,6 +42,107 @@ def update_course_requirements(course_id):
LOGGER
.
info
(
'Requirements added for course
%
s'
,
course_id
)
LOGGER
.
info
(
'Requirements added for course
%
s'
,
course_id
)
def
get_min_grade_for_credit
(
course
):
def
_get_course_credit_requirements
(
course
):
""" Returns the min_grade for the credit requirements """
"""Returns the list of credit requirements for the given course.
return
getattr
(
course
,
"min_grade"
,
0.8
)
It returns the minimum_grade_credit and also the ICRV checkpoints
if any were added in the course
Args:
course(Course): The course object
Returns:
List of minimum_grade_credit and ICRV requirements
"""
icrv_requirements
=
_get_credit_course_requirement_xblocks
(
course
)
min_grade_requirement
=
_get_min_grade_requirement
(
course
)
credit_requirements
=
icrv_requirements
+
min_grade_requirement
return
credit_requirements
def
_get_min_grade_requirement
(
course
):
"""Returns the list of minimum_grade_credit requirements for the given course.
Args:
course(Course): The course object
Raises:
AttributeError if the course has not minimum_grade_credit attribute
Returns:
The list of minimum_grade_credit requirements
"""
requirement
=
[]
try
:
requirement
=
[
{
"namespace"
:
"grade"
,
"name"
:
"grade"
,
"criteria"
:
{
"min_grade"
:
getattr
(
course
,
"minimum_grade_credit"
)
}
}
]
except
AttributeError
:
LOGGER
.
error
(
"The course
%
s does not has minimum_grade_credit attribute"
,
unicode
(
course
.
id
))
return
requirement
def
_get_credit_course_requirement_xblocks
(
course
):
# pylint: disable=invalid-name
"""Generates a course structure dictionary for the specified course.
Args:
course(Course): The course object
Returns:
The list of credit requirements xblocks dicts
"""
blocks_stack
=
[
course
]
requirements_blocks
=
[]
while
blocks_stack
:
curr_block
=
blocks_stack
.
pop
()
children
=
curr_block
.
get_children
()
if
curr_block
.
has_children
else
[]
if
_is_credit_requirement
(
curr_block
):
block
=
{
"namespace"
:
curr_block
.
get_credit_requirement_namespace
(),
"name"
:
curr_block
.
get_credit_requirement_name
(),
"criteria"
:
""
}
requirements_blocks
.
append
(
block
)
# Add this blocks children to the stack so that we can traverse them as well.
blocks_stack
.
extend
(
children
)
return
requirements_blocks
def
_is_credit_requirement
(
xblock
):
"""Check if the given xblock is a credit requirement.
Args:
xblock(XBlock): The given xblock object
Returns:
True if xblock is a credit requirement else False
"""
is_credit_requirement
=
False
if
callable
(
getattr
(
xblock
,
"is_course_credit_requirement"
,
None
)):
is_credit_requirement
=
xblock
.
is_course_credit_requirement
()
if
is_credit_requirement
:
if
not
callable
(
getattr
(
xblock
,
"get_credit_requirement_namespace"
,
None
)):
is_credit_requirement
=
False
LOGGER
.
error
(
"XBlock
%
v is marked as a credit requirement but does not "
"implement get_credit_requirement_namespace()"
,
xblock
)
if
not
callable
(
getattr
(
xblock
,
"get_credit_requirement_name"
,
None
)):
is_credit_requirement
=
False
LOGGER
.
error
(
"XBlock
%
v is marked as a credit requirement but does not "
"implement get_credit_requirement_name()"
,
xblock
)
return
is_credit_requirement
openedx/core/djangoapps/credit/tests/test_tasks.py
View file @
810733db
...
@@ -9,7 +9,7 @@ from openedx.core.djangoapps.credit.models import CreditCourse
...
@@ -9,7 +9,7 @@ from openedx.core.djangoapps.credit.models import CreditCourse
from
openedx.core.djangoapps.credit.signals
import
listen_for_course_publish
from
openedx.core.djangoapps.credit.signals
import
listen_for_course_publish
from
xmodule.modulestore.django
import
SignalHandler
from
xmodule.modulestore.django
import
SignalHandler
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.factories
import
CourseFactory
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
class
TestTaskExecution
(
ModuleStoreTestCase
):
class
TestTaskExecution
(
ModuleStoreTestCase
):
...
@@ -26,6 +26,18 @@ class TestTaskExecution(ModuleStoreTestCase):
...
@@ -26,6 +26,18 @@ class TestTaskExecution(ModuleStoreTestCase):
"""
"""
raise
InvalidCreditRequirements
raise
InvalidCreditRequirements
def
add_icrv_xblock
(
self
):
""" Create the 'edx-reverification-block' in course tree """
section
=
ItemFactory
.
create
(
parent
=
self
.
course
,
category
=
'chapter'
,
display_name
=
'Test Section'
)
subsection
=
ItemFactory
.
create
(
parent
=
section
,
category
=
'sequential'
,
display_name
=
'Test Subsection'
)
vertical
=
ItemFactory
.
create
(
parent
=
subsection
,
category
=
'vertical'
,
display_name
=
'Test Unit'
)
reverification
=
ItemFactory
.
create
(
parent
=
vertical
,
category
=
'edx-reverification-block'
,
display_name
=
'Test Verification Block'
)
def
setUp
(
self
):
def
setUp
(
self
):
super
(
TestTaskExecution
,
self
)
.
setUp
()
super
(
TestTaskExecution
,
self
)
.
setUp
()
...
@@ -57,6 +69,20 @@ class TestTaskExecution(ModuleStoreTestCase):
...
@@ -57,6 +69,20 @@ class TestTaskExecution(ModuleStoreTestCase):
requirements
=
get_credit_requirements
(
self
.
course
.
id
)
requirements
=
get_credit_requirements
(
self
.
course
.
id
)
self
.
assertEqual
(
len
(
requirements
),
1
)
self
.
assertEqual
(
len
(
requirements
),
1
)
def
test_task_adding_icrv_requirements
(
self
):
"""
Make sure that the receiver correctly fires off the task when
invoked by signal
"""
self
.
add_credit_course
(
self
.
course
.
id
)
self
.
add_icrv_xblock
()
requirements
=
get_credit_requirements
(
self
.
course
.
id
)
self
.
assertEqual
(
len
(
requirements
),
0
)
listen_for_course_publish
(
self
,
self
.
course
.
id
)
requirements
=
get_credit_requirements
(
self
.
course
.
id
)
self
.
assertEqual
(
len
(
requirements
),
2
)
@mock.patch
(
@mock.patch
(
'openedx.core.djangoapps.credit.tasks.set_credit_requirements'
,
'openedx.core.djangoapps.credit.tasks.set_credit_requirements'
,
mock
.
Mock
(
mock
.
Mock
(
...
...
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