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
b9dade55
Commit
b9dade55
authored
Aug 16, 2016
by
Sanford Student
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
handler for SCORE_CHANGED signal
parent
22046d40
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
176 additions
and
19 deletions
+176
-19
lms/djangoapps/courseware/module_render.py
+1
-1
lms/djangoapps/courseware/tests/test_module_render.py
+1
-1
lms/djangoapps/gating/signals.py
+1
-1
lms/djangoapps/gating/tests/test_signals.py
+5
-4
lms/djangoapps/grades/new/subsection_grade.py
+18
-0
lms/djangoapps/grades/signals.py
+37
-3
lms/djangoapps/grades/tests/test_signals.py
+107
-3
lms/djangoapps/lti_provider/tasks.py
+6
-6
No files found.
lms/djangoapps/courseware/module_render.py
View file @
b9dade55
...
@@ -539,7 +539,7 @@ def get_module_system_for_user(user, student_data, # TODO # pylint: disable=to
...
@@ -539,7 +539,7 @@ def get_module_system_for_user(user, student_data, # TODO # pylint: disable=to
sender
=
None
,
sender
=
None
,
points_possible
=
event
[
'max_value'
],
points_possible
=
event
[
'max_value'
],
points_earned
=
event
[
'value'
],
points_earned
=
event
[
'value'
],
user
_id
=
user_id
,
user
=
user
,
course_id
=
unicode
(
course_id
),
course_id
=
unicode
(
course_id
),
usage_id
=
unicode
(
descriptor
.
location
)
usage_id
=
unicode
(
descriptor
.
location
)
)
)
...
...
lms/djangoapps/courseware/tests/test_module_render.py
View file @
b9dade55
...
@@ -1843,7 +1843,7 @@ class TestXmoduleRuntimeEvent(TestSubmittingProblems):
...
@@ -1843,7 +1843,7 @@ class TestXmoduleRuntimeEvent(TestSubmittingProblems):
'sender'
:
None
,
'sender'
:
None
,
'points_possible'
:
self
.
grade_dict
[
'max_value'
],
'points_possible'
:
self
.
grade_dict
[
'max_value'
],
'points_earned'
:
self
.
grade_dict
[
'value'
],
'points_earned'
:
self
.
grade_dict
[
'value'
],
'user
_id'
:
self
.
student_user
.
id
,
'user
'
:
self
.
student_user
,
'course_id'
:
unicode
(
self
.
course
.
id
),
'course_id'
:
unicode
(
self
.
course
.
id
),
'usage_id'
:
unicode
(
self
.
problem
.
location
)
'usage_id'
:
unicode
(
self
.
problem
.
location
)
}
}
...
...
lms/djangoapps/gating/signals.py
View file @
b9dade55
...
@@ -26,5 +26,5 @@ def handle_score_changed(**kwargs):
...
@@ -26,5 +26,5 @@ def handle_score_changed(**kwargs):
gating_api
.
evaluate_prerequisite
(
gating_api
.
evaluate_prerequisite
(
course
,
course
,
UsageKey
.
from_string
(
kwargs
.
get
(
'usage_id'
)),
UsageKey
.
from_string
(
kwargs
.
get
(
'usage_id'
)),
kwargs
.
get
(
'user
_id'
)
,
kwargs
.
get
(
'user
'
)
.
id
,
)
)
lms/djangoapps/gating/tests/test_signals.py
View file @
b9dade55
...
@@ -4,6 +4,7 @@ Unit tests for gating.signals module
...
@@ -4,6 +4,7 @@ Unit tests for gating.signals module
from
mock
import
patch
from
mock
import
patch
from
opaque_keys.edx.keys
import
UsageKey
from
opaque_keys.edx.keys
import
UsageKey
from
student.tests.factories
import
UserFactory
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
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.django
import
modulestore
...
@@ -18,7 +19,7 @@ class TestHandleScoreChanged(ModuleStoreTestCase):
...
@@ -18,7 +19,7 @@ class TestHandleScoreChanged(ModuleStoreTestCase):
def
setUp
(
self
):
def
setUp
(
self
):
super
(
TestHandleScoreChanged
,
self
)
.
setUp
()
super
(
TestHandleScoreChanged
,
self
)
.
setUp
()
self
.
course
=
CourseFactory
.
create
(
org
=
'TestX'
,
number
=
'TS01'
,
run
=
'2016_Q1'
)
self
.
course
=
CourseFactory
.
create
(
org
=
'TestX'
,
number
=
'TS01'
,
run
=
'2016_Q1'
)
self
.
test_user_id
=
0
self
.
user
=
UserFactory
()
self
.
test_usage_key
=
UsageKey
.
from_string
(
'i4x://the/content/key/12345678'
)
self
.
test_usage_key
=
UsageKey
.
from_string
(
'i4x://the/content/key/12345678'
)
@patch
(
'gating.signals.gating_api.evaluate_prerequisite'
)
@patch
(
'gating.signals.gating_api.evaluate_prerequisite'
)
...
@@ -30,11 +31,11 @@ class TestHandleScoreChanged(ModuleStoreTestCase):
...
@@ -30,11 +31,11 @@ class TestHandleScoreChanged(ModuleStoreTestCase):
sender
=
None
,
sender
=
None
,
points_possible
=
1
,
points_possible
=
1
,
points_earned
=
1
,
points_earned
=
1
,
user
_id
=
self
.
test_user_id
,
user
=
self
.
user
,
course_id
=
unicode
(
self
.
course
.
id
),
course_id
=
unicode
(
self
.
course
.
id
),
usage_id
=
unicode
(
self
.
test_usage_key
)
usage_id
=
unicode
(
self
.
test_usage_key
)
)
)
mock_evaluate
.
assert_called_with
(
self
.
course
,
self
.
test_usage_key
,
self
.
test_user_id
)
mock_evaluate
.
assert_called_with
(
self
.
course
,
self
.
test_usage_key
,
self
.
user
.
id
)
# pylint: disable=no-member
@patch
(
'gating.signals.gating_api.evaluate_prerequisite'
)
@patch
(
'gating.signals.gating_api.evaluate_prerequisite'
)
def
test_gating_disabled
(
self
,
mock_evaluate
):
def
test_gating_disabled
(
self
,
mock_evaluate
):
...
@@ -43,7 +44,7 @@ class TestHandleScoreChanged(ModuleStoreTestCase):
...
@@ -43,7 +44,7 @@ class TestHandleScoreChanged(ModuleStoreTestCase):
sender
=
None
,
sender
=
None
,
points_possible
=
1
,
points_possible
=
1
,
points_earned
=
1
,
points_earned
=
1
,
user
_id
=
self
.
test_user_id
,
user
=
self
.
user
,
course_id
=
unicode
(
self
.
course
.
id
),
course_id
=
unicode
(
self
.
course
.
id
),
usage_id
=
unicode
(
self
.
test_usage_key
)
usage_id
=
unicode
(
self
.
test_usage_key
)
)
)
...
...
lms/djangoapps/grades/new/subsection_grade.py
View file @
b9dade55
...
@@ -6,6 +6,7 @@ from lazy import lazy
...
@@ -6,6 +6,7 @@ from lazy import lazy
from
django.conf
import
settings
from
django.conf
import
settings
from
course_blocks.api
import
get_course_blocks
from
courseware.model_data
import
ScoresClient
from
courseware.model_data
import
ScoresClient
from
lms.djangoapps.grades.scores
import
get_score
,
possibly_scored
from
lms.djangoapps.grades.scores
import
get_score
,
possibly_scored
from
lms.djangoapps.grades.models
import
BlockRecord
,
PersistentSubsectionGrade
from
lms.djangoapps.grades.models
import
BlockRecord
,
PersistentSubsectionGrade
...
@@ -59,6 +60,7 @@ class SubsectionGrade(object):
...
@@ -59,6 +60,7 @@ class SubsectionGrade(object):
BlockRecord
(
location
,
weight
,
score
.
possible
)
BlockRecord
(
location
,
weight
,
score
.
possible
)
for
location
,
(
score
,
weight
)
in
self
.
locations_to_weighted_scores
.
iteritems
()
for
location
,
(
score
,
weight
)
in
self
.
locations_to_weighted_scores
.
iteritems
()
]
]
PersistentSubsectionGrade
.
save_grade
(
PersistentSubsectionGrade
.
save_grade
(
user_id
=
student
.
id
,
user_id
=
student
.
id
,
usage_key
=
self
.
location
,
usage_key
=
self
.
location
,
...
@@ -166,6 +168,22 @@ class SubsectionGradeFactory(object):
...
@@ -166,6 +168,22 @@ class SubsectionGradeFactory(object):
self
.
_compute_and_save_grade
(
subsection
,
course_structure
,
course
)
self
.
_compute_and_save_grade
(
subsection
,
course_structure
,
course
)
)
)
def
update
(
self
,
usage_key
,
course_key
):
"""
Updates the SubsectionGrade object for the student and subsection
identified by the given usage key.
"""
from
courseware.courses
import
get_course_by_id
# avoids circular import with courseware.py
course
=
get_course_by_id
(
course_key
,
depth
=
0
)
# save ourselves the extra queries if the course does not use subsection grades
if
not
course
.
enable_subsection_grades_saved
:
return
course_structure
=
get_course_blocks
(
self
.
student
,
usage_key
)
subsection
=
course_structure
[
usage_key
]
self
.
_prefetch_scores
(
course_structure
,
course
)
return
self
.
_compute_and_save_grade
(
subsection
,
course_structure
,
course
)
def
_compute_and_save_grade
(
self
,
subsection
,
course_structure
,
course
):
def
_compute_and_save_grade
(
self
,
subsection
,
course_structure
,
course
):
"""
"""
Freshly computes and updates the grade for the student and subsection.
Freshly computes and updates the grade for the student and subsection.
...
...
lms/djangoapps/grades/signals.py
View file @
b9dade55
"""
"""
Grades related signals.
Grades related signals.
"""
"""
from
django.conf
import
settings
from
django.dispatch
import
receiver
,
Signal
from
django.dispatch
import
receiver
,
Signal
from
logging
import
getLogger
from
logging
import
getLogger
from
opaque_keys.edx.locator
import
CourseLocator
from
opaque_keys.edx.keys
import
UsageKey
from
student.models
import
user_by_anonymous_id
from
student.models
import
user_by_anonymous_id
from
submissions.models
import
score_set
,
score_reset
from
submissions.models
import
score_set
,
score_reset
log
=
getLogger
(
__name__
)
log
=
getLogger
(
__name__
)
...
@@ -58,7 +60,7 @@ def submissions_score_set_handler(sender, **kwargs): # pylint: disable=unused-a
...
@@ -58,7 +60,7 @@ def submissions_score_set_handler(sender, **kwargs): # pylint: disable=unused-a
sender
=
None
,
sender
=
None
,
points_possible
=
points_possible
,
points_possible
=
points_possible
,
points_earned
=
points_earned
,
points_earned
=
points_earned
,
user
_id
=
user
.
id
,
user
=
user
,
course_id
=
course_id
,
course_id
=
course_id
,
usage_id
=
usage_id
usage_id
=
usage_id
)
)
...
@@ -97,7 +99,7 @@ def submissions_score_reset_handler(sender, **kwargs): # pylint: disable=unused
...
@@ -97,7 +99,7 @@ def submissions_score_reset_handler(sender, **kwargs): # pylint: disable=unused
sender
=
None
,
sender
=
None
,
points_possible
=
0
,
points_possible
=
0
,
points_earned
=
0
,
points_earned
=
0
,
user
_id
=
user
.
id
,
user
=
user
,
course_id
=
course_id
,
course_id
=
course_id
,
usage_id
=
usage_id
usage_id
=
usage_id
)
)
...
@@ -106,3 +108,35 @@ def submissions_score_reset_handler(sender, **kwargs): # pylint: disable=unused
...
@@ -106,3 +108,35 @@ def submissions_score_reset_handler(sender, **kwargs): # pylint: disable=unused
u"Failed to process score_reset signal from Submissions API. "
u"Failed to process score_reset signal from Submissions API. "
"user:
%
s, course_id:
%
s, usage_id:
%
s"
,
user
,
course_id
,
usage_id
"user:
%
s, course_id:
%
s, usage_id:
%
s"
,
user
,
course_id
,
usage_id
)
)
@receiver
(
SCORE_CHANGED
)
def
recalculate_subsection_grade_handler
(
sender
,
**
kwargs
):
# pylint: disable=unused-argument
"""
Consume the SCORE_CHANGED signal and trigger an update.
This method expects that the kwargs dictionary will contain the following
entries (See the definition of SCORE_CHANGED):
- points_possible: Maximum score available for the exercise
- points_earned: Score obtained by the user
- user: User object
- course_id: Unicode string representing the course
- usage_id: Unicode string indicating the courseware instance
"""
if
not
settings
.
FEATURES
.
get
(
'ENABLE_SUBSECTION_GRADES_SAVED'
,
False
):
return
try
:
course_id
=
kwargs
.
get
(
'course_id'
,
None
)
usage_id
=
kwargs
.
get
(
'usage_id'
,
None
)
student
=
kwargs
.
get
(
'user'
,
None
)
course_key
=
CourseLocator
.
from_string
(
course_id
)
usage_key
=
UsageKey
.
from_string
(
usage_id
)
.
replace
(
course_key
=
course_key
)
from
lms.djangoapps.grades.new.subsection_grade
import
SubsectionGradeFactory
SubsectionGradeFactory
(
student
)
.
update
(
usage_key
,
course_key
)
except
Exception
as
ex
:
# pylint: disable=broad-except
log
.
exception
(
u"Failed to process SCORE_CHANGED signal. "
"user:
%
s, course_id:
%
s, "
"usage_id:
%
s. Exception:
%
s"
,
unicode
(
student
),
course_id
,
usage_id
,
ex
.
message
)
lms/djangoapps/grades/tests/test_signals.py
View file @
b9dade55
...
@@ -2,10 +2,22 @@
...
@@ -2,10 +2,22 @@
Tests for the score change signals defined in the courseware models module.
Tests for the score change signals defined in the courseware models module.
"""
"""
import
ddt
from
unittest
import
skip
from
django.test
import
TestCase
from
django.test
import
TestCase
from
mock
import
patch
,
MagicMock
from
mock
import
patch
,
MagicMock
from
student.models
import
anonymous_id_for_user
from
student.tests.factories
import
UserFactory
from
xmodule.modulestore
import
ModuleStoreEnum
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
,
check_mongo_calls
from
..signals
import
submissions_score_set_handler
,
submissions_score_reset_handler
from
..signals
import
(
submissions_score_set_handler
,
submissions_score_reset_handler
,
recalculate_subsection_grade_handler
,
SCORE_CHANGED
)
SUBMISSION_SET_KWARGS
=
{
SUBMISSION_SET_KWARGS
=
{
...
@@ -62,7 +74,7 @@ class SubmissionSignalRelayTest(TestCase):
...
@@ -62,7 +74,7 @@ class SubmissionSignalRelayTest(TestCase):
'sender'
:
None
,
'sender'
:
None
,
'points_possible'
:
10
,
'points_possible'
:
10
,
'points_earned'
:
5
,
'points_earned'
:
5
,
'user
_id'
:
42
,
'user
'
:
self
.
user_mock
,
'course_id'
:
'CourseID'
,
'course_id'
:
'CourseID'
,
'usage_id'
:
'i4x://org/course/usage/123456'
'usage_id'
:
'i4x://org/course/usage/123456'
}
}
...
@@ -111,7 +123,7 @@ class SubmissionSignalRelayTest(TestCase):
...
@@ -111,7 +123,7 @@ class SubmissionSignalRelayTest(TestCase):
'sender'
:
None
,
'sender'
:
None
,
'points_possible'
:
0
,
'points_possible'
:
0
,
'points_earned'
:
0
,
'points_earned'
:
0
,
'user
_id'
:
42
,
'user
'
:
self
.
user_mock
,
'course_id'
:
'CourseID'
,
'course_id'
:
'CourseID'
,
'usage_id'
:
'i4x://org/course/usage/123456'
'usage_id'
:
'i4x://org/course/usage/123456'
}
}
...
@@ -148,3 +160,95 @@ class SubmissionSignalRelayTest(TestCase):
...
@@ -148,3 +160,95 @@ class SubmissionSignalRelayTest(TestCase):
self
.
get_user_mock
=
self
.
setup_patch
(
'lms.djangoapps.grades.signals.user_by_anonymous_id'
,
None
)
self
.
get_user_mock
=
self
.
setup_patch
(
'lms.djangoapps.grades.signals.user_by_anonymous_id'
,
None
)
submissions_score_reset_handler
(
None
,
**
SUBMISSION_RESET_KWARGS
)
submissions_score_reset_handler
(
None
,
**
SUBMISSION_RESET_KWARGS
)
self
.
signal_mock
.
assert_not_called
()
self
.
signal_mock
.
assert_not_called
()
@ddt.ddt
class
ScoreChangedUpdatesSubsectionGradeTest
(
ModuleStoreTestCase
):
"""
Ensures that upon SCORE_CHANGED signals, the handler
initiates an update to the affected subsection grade.
"""
def
setUp
(
self
):
super
(
ScoreChangedUpdatesSubsectionGradeTest
,
self
)
.
setUp
()
self
.
user
=
UserFactory
()
def
set_up_course
(
self
,
enable_subsection_grades
=
True
):
"""
Configures the course for this test.
"""
# pylint: disable=attribute-defined-outside-init,no-member
self
.
course
=
CourseFactory
.
create
(
org
=
'edx'
,
name
=
'course'
,
run
=
'run'
,
metadata
=
{
'enable_subsection_grades_saved'
:
enable_subsection_grades
})
self
.
chapter
=
ItemFactory
.
create
(
parent
=
self
.
course
,
category
=
"chapter"
,
display_name
=
"Chapter"
)
self
.
sequential
=
ItemFactory
.
create
(
parent
=
self
.
chapter
,
category
=
'sequential'
,
display_name
=
"Open Sequential"
)
self
.
problem
=
ItemFactory
.
create
(
parent
=
self
.
sequential
,
category
=
'problem'
,
display_name
=
'problem'
)
self
.
score_changed_kwargs
=
{
'points_possible'
:
10
,
'points_earned'
:
5
,
'user'
:
self
.
user
,
'course_id'
:
unicode
(
self
.
course
.
id
),
'usage_id'
:
unicode
(
self
.
problem
.
location
),
}
# this call caches the anonymous id on the user object, saving 4 queries in all happy path tests
_
=
anonymous_id_for_user
(
self
.
user
,
self
.
course
.
id
)
# pylint: enable=attribute-defined-outside-init,no-member
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_subsection_grade_updated_on_signal
(
self
,
default_store
):
with
self
.
store
.
default_store
(
default_store
):
self
.
set_up_course
()
with
check_mongo_calls
(
2
)
and
self
.
assertNumQueries
(
13
):
recalculate_subsection_grade_handler
(
None
,
**
self
.
score_changed_kwargs
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_query_count_does_not_change_with_more_problems
(
self
,
default_store
):
with
self
.
store
.
default_store
(
default_store
):
self
.
set_up_course
()
ItemFactory
.
create
(
parent
=
self
.
sequential
,
category
=
'problem'
,
display_name
=
'problem2'
)
ItemFactory
.
create
(
parent
=
self
.
sequential
,
category
=
'problem'
,
display_name
=
'problem3'
)
with
check_mongo_calls
(
2
)
and
self
.
assertNumQueries
(
13
):
recalculate_subsection_grade_handler
(
None
,
**
self
.
score_changed_kwargs
)
@ddt.data
(
ModuleStoreEnum
.
Type
.
mongo
,
ModuleStoreEnum
.
Type
.
split
)
def
test_subsection_grades_not_enabled_on_course
(
self
,
default_store
):
with
self
.
store
.
default_store
(
default_store
):
self
.
set_up_course
(
enable_subsection_grades
=
False
)
with
check_mongo_calls
(
2
)
and
self
.
assertNumQueries
(
0
):
recalculate_subsection_grade_handler
(
None
,
**
self
.
score_changed_kwargs
)
@skip
(
"Pending completion of TNL-5089"
)
@ddt.data
(
(
ModuleStoreEnum
.
Type
.
mongo
,
True
),
(
ModuleStoreEnum
.
Type
.
split
,
True
),
(
ModuleStoreEnum
.
Type
.
mongo
,
False
),
(
ModuleStoreEnum
.
Type
.
split
,
False
),
)
@ddt.unpack
def
test_score_changed_sent_with_feature_flag
(
self
,
default_store
,
feature_flag
):
with
patch
.
dict
(
'django.conf.settings.FEATURES'
,
{
'ENABLE_SUBSECTION_GRADES_SAVED'
:
feature_flag
}):
with
self
.
store
.
default_store
(
default_store
):
self
.
set_up_course
()
with
check_mongo_calls
(
0
)
and
self
.
assertNumQueries
(
19
if
feature_flag
else
1
):
SCORE_CHANGED
.
send
(
sender
=
None
,
**
self
.
score_changed_kwargs
)
@ddt.data
(
(
'points_possible'
,
2
,
13
),
(
'points_earned'
,
2
,
13
),
(
'user'
,
0
,
0
),
(
'course_id'
,
0
,
0
),
(
'usage_id'
,
0
,
0
),
)
@ddt.unpack
def
test_missing_kwargs
(
self
,
kwarg
,
expected_mongo_calls
,
expected_sql_calls
):
self
.
set_up_course
()
del
self
.
score_changed_kwargs
[
kwarg
]
with
patch
(
'lms.djangoapps.grades.signals.log'
)
as
log_mock
:
with
check_mongo_calls
(
expected_mongo_calls
)
and
self
.
assertNumQueries
(
expected_sql_calls
):
recalculate_subsection_grade_handler
(
None
,
**
self
.
score_changed_kwargs
)
self
.
assertEqual
(
log_mock
.
exception
.
called
,
kwarg
not
in
[
'points_possible'
,
'points_earned'
])
lms/djangoapps/lti_provider/tasks.py
View file @
b9dade55
...
@@ -27,13 +27,13 @@ def score_changed_handler(sender, **kwargs): # pylint: disable=unused-argument
...
@@ -27,13 +27,13 @@ def score_changed_handler(sender, **kwargs): # pylint: disable=unused-argument
"""
"""
points_possible
=
kwargs
.
get
(
'points_possible'
,
None
)
points_possible
=
kwargs
.
get
(
'points_possible'
,
None
)
points_earned
=
kwargs
.
get
(
'points_earned'
,
None
)
points_earned
=
kwargs
.
get
(
'points_earned'
,
None
)
user
_id
=
kwargs
.
get
(
'user_id
'
,
None
)
user
=
kwargs
.
get
(
'user
'
,
None
)
course_id
=
kwargs
.
get
(
'course_id'
,
None
)
course_id
=
kwargs
.
get
(
'course_id'
,
None
)
usage_id
=
kwargs
.
get
(
'usage_id'
,
None
)
usage_id
=
kwargs
.
get
(
'usage_id'
,
None
)
if
None
not
in
(
points_earned
,
points_possible
,
user
_id
,
course_id
,
user_
id
):
if
None
not
in
(
points_earned
,
points_possible
,
user
.
id
,
course_id
,
user
.
id
):
course_key
,
usage_key
=
parse_course_and_usage_keys
(
course_id
,
usage_id
)
course_key
,
usage_key
=
parse_course_and_usage_keys
(
course_id
,
usage_id
)
assignments
=
increment_assignment_versions
(
course_key
,
usage_key
,
user
_
id
)
assignments
=
increment_assignment_versions
(
course_key
,
usage_key
,
user
.
id
)
for
assignment
in
assignments
:
for
assignment
in
assignments
:
if
assignment
.
usage_key
==
usage_key
:
if
assignment
.
usage_key
==
usage_key
:
send_leaf_outcome
.
delay
(
send_leaf_outcome
.
delay
(
...
@@ -41,15 +41,15 @@ def score_changed_handler(sender, **kwargs): # pylint: disable=unused-argument
...
@@ -41,15 +41,15 @@ def score_changed_handler(sender, **kwargs): # pylint: disable=unused-argument
)
)
else
:
else
:
send_composite_outcome
.
apply_async
(
send_composite_outcome
.
apply_async
(
(
user
_
id
,
course_id
,
assignment
.
id
,
assignment
.
version_number
),
(
user
.
id
,
course_id
,
assignment
.
id
,
assignment
.
version_number
),
countdown
=
settings
.
LTI_AGGREGATE_SCORE_PASSBACK_DELAY
countdown
=
settings
.
LTI_AGGREGATE_SCORE_PASSBACK_DELAY
)
)
else
:
else
:
log
.
error
(
log
.
error
(
"Outcome Service: Required signal parameter is None. "
"Outcome Service: Required signal parameter is None. "
"points_possible:
%
s, points_earned:
%
s, user
_id
:
%
s, "
"points_possible:
%
s, points_earned:
%
s, user:
%
s, "
"course_id:
%
s, usage_id:
%
s"
,
"course_id:
%
s, usage_id:
%
s"
,
points_possible
,
points_earned
,
u
ser_id
,
course_id
,
usage_id
points_possible
,
points_earned
,
u
nicode
(
user
)
,
course_id
,
usage_id
)
)
...
...
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