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
594dcaf4
Commit
594dcaf4
authored
Mar 30, 2017
by
Eric Fischer
Committed by
GitHub
Mar 30, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #14780 from edx/efischer/ora_grades
Clear Student State: ORA/Robust Grades fixes
parents
79a9984b
10faaa55
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
84 additions
and
18 deletions
+84
-18
lms/djangoapps/grades/signals/handlers.py
+20
-1
lms/djangoapps/grades/tests/test_signals.py
+37
-0
lms/djangoapps/instructor/enrollment.py
+16
-12
lms/djangoapps/instructor/tests/test_enrollment.py
+7
-1
openedx/core/djangoapps/ccxcon/api.py
+2
-2
requirements/edx/github.txt
+2
-2
No files found.
lms/djangoapps/grades/signals/handlers.py
View file @
594dcaf4
"""
"""
Grades related signals.
Grades related signals.
"""
"""
from
contextlib
import
contextmanager
from
logging
import
getLogger
from
logging
import
getLogger
from
django.dispatch
import
receiver
from
django.dispatch
import
receiver
...
@@ -109,6 +109,25 @@ def submissions_score_reset_handler(sender, **kwargs): # pylint: disable=unused
...
@@ -109,6 +109,25 @@ def submissions_score_reset_handler(sender, **kwargs): # pylint: disable=unused
)
)
@contextmanager
def
disconnect_submissions_signal_receiver
(
signal
):
"""
Context manager to be used for temporarily disconnecting edx-submission's set or reset signal.
"""
if
signal
==
score_set
:
handler
=
submissions_score_set_handler
else
:
if
signal
!=
score_reset
:
raise
ValueError
(
"This context manager only deal with score_set and score_reset signals."
)
handler
=
submissions_score_reset_handler
signal
.
disconnect
(
handler
)
try
:
yield
finally
:
signal
.
connect
(
handler
)
@receiver
(
SCORE_PUBLISHED
)
@receiver
(
SCORE_PUBLISHED
)
def
score_published_handler
(
sender
,
block
,
user
,
raw_earned
,
raw_possible
,
only_if_higher
,
**
kwargs
):
# pylint: disable=unused-argument
def
score_published_handler
(
sender
,
block
,
user
,
raw_earned
,
raw_possible
,
only_if_higher
,
**
kwargs
):
# pylint: disable=unused-argument
"""
"""
...
...
lms/djangoapps/grades/tests/test_signals.py
View file @
594dcaf4
...
@@ -9,6 +9,7 @@ import ddt
...
@@ -9,6 +9,7 @@ import ddt
from
django.test
import
TestCase
from
django.test
import
TestCase
from
mock
import
patch
,
MagicMock
from
mock
import
patch
,
MagicMock
import
pytz
import
pytz
from
submissions.models
import
score_set
,
score_reset
from
util.date_utils
import
to_timestamp
from
util.date_utils
import
to_timestamp
from
..constants
import
ScoreDatabaseTableEnum
from
..constants
import
ScoreDatabaseTableEnum
...
@@ -16,8 +17,10 @@ from ..signals.handlers import (
...
@@ -16,8 +17,10 @@ from ..signals.handlers import (
enqueue_subsection_update
,
enqueue_subsection_update
,
submissions_score_set_handler
,
submissions_score_set_handler
,
submissions_score_reset_handler
,
submissions_score_reset_handler
,
disconnect_submissions_signal_receiver
,
problem_raw_score_changed_handler
,
problem_raw_score_changed_handler
,
)
)
from
..signals.signals
import
PROBLEM_RAW_SCORE_CHANGED
UUID_REGEX
=
re
.
compile
(
ur'
%(hex)
s{8}-
%(hex)
s{4}-
%(hex)
s{4}-
%(hex)
s{4}-
%(hex)
s{12}'
%
{
'hex'
:
u'[0-9a-f]'
})
UUID_REGEX
=
re
.
compile
(
ur'
%(hex)
s{8}-
%(hex)
s{4}-
%(hex)
s{4}-
%(hex)
s{4}-
%(hex)
s{12}'
%
{
'hex'
:
u'[0-9a-f]'
})
...
@@ -214,3 +217,37 @@ class ScoreChangedSignalRelayTest(TestCase):
...
@@ -214,3 +217,37 @@ class ScoreChangedSignalRelayTest(TestCase):
u'usage_id:block-v1:block-key, user_id:1. Task [*UUID*]'
u'usage_id:block-v1:block-key, user_id:1. Task [*UUID*]'
)
.
format
(
time
=
FROZEN_NOW_DATETIME
)
)
.
format
(
time
=
FROZEN_NOW_DATETIME
)
)
)
@ddt.data
(
[
score_set
,
'lms.djangoapps.grades.signals.handlers.submissions_score_set_handler'
,
SUBMISSION_SET_KWARGS
],
[
score_reset
,
'lms.djangoapps.grades.signals.handlers.submissions_score_reset_handler'
,
SUBMISSION_RESET_KWARGS
]
)
@ddt.unpack
def
test_disconnect_manager
(
self
,
signal
,
handler
,
kwargs
):
"""
Tests to confirm the disconnect_submissions_signal_receiver context manager is working correctly.
"""
handler_mock
=
self
.
setup_patch
(
handler
,
None
)
# Receiver connected before we start
signal
.
send
(
None
,
**
kwargs
)
handler_mock
.
assert_called_once
()
handler_mock
.
reset_mock
()
# Disconnect is functioning
with
disconnect_submissions_signal_receiver
(
signal
):
signal
.
send
(
None
,
**
kwargs
)
handler_mock
.
assert_not_called
()
handler_mock
.
reset_mock
()
# And we reconnect properly afterwards
signal
.
send
(
None
,
**
kwargs
)
handler_mock
.
assert_called_once
()
def
test_disconnect_manager_bad_arg
(
self
):
"""
Tests that the disconnect context manager errors when given an invalid signal.
"""
with
self
.
assertRaises
(
ValueError
):
with
disconnect_submissions_signal_receiver
(
PROBLEM_RAW_SCORE_CHANGED
):
pass
lms/djangoapps/instructor/enrollment.py
View file @
594dcaf4
...
@@ -16,12 +16,14 @@ from django.utils.translation import override as override_language
...
@@ -16,12 +16,14 @@ from django.utils.translation import override as override_language
from
eventtracking
import
tracker
from
eventtracking
import
tracker
import
pytz
import
pytz
from
lms.djangoapps.grades.signals.handlers
import
disconnect_submissions_signal_receiver
from
lms.djangoapps.grades.signals.signals
import
PROBLEM_RAW_SCORE_CHANGED
from
lms.djangoapps.grades.signals.signals
import
PROBLEM_RAW_SCORE_CHANGED
from
lms.djangoapps.grades.constants
import
ScoreDatabaseTableEnum
from
lms.djangoapps.grades.constants
import
ScoreDatabaseTableEnum
from
openedx.core.djangoapps.lang_pref
import
LANGUAGE_KEY
from
openedx.core.djangoapps.lang_pref
import
LANGUAGE_KEY
from
openedx.core.djangoapps.site_configuration
import
helpers
as
configuration_helpers
from
openedx.core.djangoapps.site_configuration
import
helpers
as
configuration_helpers
from
openedx.core.djangoapps.user_api.models
import
UserPreference
from
openedx.core.djangoapps.user_api.models
import
UserPreference
from
submissions
import
api
as
sub_api
# installed from the edx-submissions repository
from
submissions
import
api
as
sub_api
# installed from the edx-submissions repository
from
submissions.models
import
score_set
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
from
xmodule.modulestore.exceptions
import
ItemNotFoundError
...
@@ -245,12 +247,13 @@ def reset_student_attempts(course_id, student, module_state_key, requesting_user
...
@@ -245,12 +247,13 @@ def reset_student_attempts(course_id, student, module_state_key, requesting_user
# Inform these blocks of the reset and allow them to handle their data.
# Inform these blocks of the reset and allow them to handle their data.
clear_student_state
=
getattr
(
block
,
"clear_student_state"
,
None
)
clear_student_state
=
getattr
(
block
,
"clear_student_state"
,
None
)
if
callable
(
clear_student_state
):
if
callable
(
clear_student_state
):
clear_student_state
(
with
disconnect_submissions_signal_receiver
(
score_set
):
user_id
=
user_id
,
clear_student_state
(
course_id
=
unicode
(
course_id
),
user_id
=
user_id
,
item_id
=
unicode
(
module_state_key
),
course_id
=
unicode
(
course_id
),
requesting_user_id
=
requesting_user_id
item_id
=
unicode
(
module_state_key
),
)
requesting_user_id
=
requesting_user_id
)
submission_cleared
=
True
submission_cleared
=
True
except
ItemNotFoundError
:
except
ItemNotFoundError
:
block
=
None
block
=
None
...
@@ -290,12 +293,13 @@ def reset_student_attempts(course_id, student, module_state_key, requesting_user
...
@@ -290,12 +293,13 @@ def reset_student_attempts(course_id, student, module_state_key, requesting_user
'event_transaction_type'
:
unicode
(
grade_update_root_type
),
'event_transaction_type'
:
unicode
(
grade_update_root_type
),
}
}
)
)
_fire_score_changed_for_block
(
if
not
submission_cleared
:
course_id
,
_fire_score_changed_for_block
(
student
,
course_id
,
block
,
student
,
module_state_key
,
block
,
)
module_state_key
,
)
else
:
else
:
_reset_module_attempts
(
module_to_reset
)
_reset_module_attempts
(
module_to_reset
)
...
...
lms/djangoapps/instructor/tests/test_enrollment.py
View file @
594dcaf4
...
@@ -401,7 +401,9 @@ class TestInstructorEnrollmentStudentModule(SharedModuleStoreTestCase):
...
@@ -401,7 +401,9 @@ class TestInstructorEnrollmentStudentModule(SharedModuleStoreTestCase):
# Disable the score change signal to prevent other components from being
# Disable the score change signal to prevent other components from being
# pulled into tests.
# pulled into tests.
@mock.patch
(
'lms.djangoapps.grades.signals.handlers.PROBLEM_WEIGHTED_SCORE_CHANGED.send'
)
@mock.patch
(
'lms.djangoapps.grades.signals.handlers.PROBLEM_WEIGHTED_SCORE_CHANGED.send'
)
def
test_delete_submission_scores
(
self
,
_mock_signal
):
@mock.patch
(
'lms.djangoapps.grades.signals.handlers.submissions_score_set_handler'
)
@mock.patch
(
'lms.djangoapps.grades.signals.handlers.submissions_score_reset_handler'
)
def
test_delete_submission_scores
(
self
,
_mock_send_signal
,
mock_set_receiver
,
mock_reset_receiver
):
user
=
UserFactory
()
user
=
UserFactory
()
problem_location
=
self
.
course_key
.
make_usage_key
(
'dummy'
,
'module'
)
problem_location
=
self
.
course_key
.
make_usage_key
(
'dummy'
,
'module'
)
...
@@ -430,6 +432,10 @@ class TestInstructorEnrollmentStudentModule(SharedModuleStoreTestCase):
...
@@ -430,6 +432,10 @@ class TestInstructorEnrollmentStudentModule(SharedModuleStoreTestCase):
delete_module
=
True
,
delete_module
=
True
,
)
)
# Make sure our grades signal receivers handled the reset properly
mock_set_receiver
.
assert_not_called
()
mock_reset_receiver
.
assert_called_once
()
# Verify that the student's scores have been reset in the submissions API
# Verify that the student's scores have been reset in the submissions API
score
=
sub_api
.
get_score
(
student_item
)
score
=
sub_api
.
get_score
(
student_item
)
self
.
assertIs
(
score
,
None
)
self
.
assertIs
(
score
,
None
)
...
...
openedx/core/djangoapps/ccxcon/api.py
View file @
594dcaf4
...
@@ -16,9 +16,9 @@ from rest_framework.status import (
...
@@ -16,9 +16,9 @@ from rest_framework.status import (
)
)
from
lms.djangoapps.courseware.courses
import
get_course_by_id
from
lms.djangoapps.courseware.courses
import
get_course_by_id
from
lms.djangoapps.instructor.access
import
list_with_level
from
openedx.core.djangoapps.models.course_details
import
CourseDetails
from
openedx.core.djangoapps.models.course_details
import
CourseDetails
from
student.models
import
anonymous_id_for_user
from
student.models
import
anonymous_id_for_user
from
student.roles
import
CourseInstructorRole
from
.models
import
CCXCon
from
.models
import
CCXCon
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
...
@@ -122,7 +122,7 @@ def course_info_to_ccxcon(course_key):
...
@@ -122,7 +122,7 @@ def course_info_to_ccxcon(course_key):
)
)
# get the entire list of instructors
# get the entire list of instructors
course_instructors
=
list_with_level
(
course
,
'instructor'
)
course_instructors
=
CourseInstructorRole
(
course
.
id
)
.
users_with_role
(
)
# get anonymous ids for each of them
# get anonymous ids for each of them
course_instructors_ids
=
[
anonymous_id_for_user
(
user
,
course_key
)
for
user
in
course_instructors
]
course_instructors_ids
=
[
anonymous_id_for_user
(
user
,
course_key
)
for
user
in
course_instructors
]
# extract the course details
# extract the course details
...
...
requirements/edx/github.txt
View file @
594dcaf4
...
@@ -75,8 +75,8 @@ git+https://github.com/edx/lettuce.git@0.2.20.002#egg=lettuce==0.2.20.002
...
@@ -75,8 +75,8 @@ git+https://github.com/edx/lettuce.git@0.2.20.002#egg=lettuce==0.2.20.002
-e git+https://github.com/edx/event-tracking.git@0.2.1#egg=event-tracking==0.2.1
-e git+https://github.com/edx/event-tracking.git@0.2.1#egg=event-tracking==0.2.1
-e git+https://github.com/edx/django-splash.git@v0.2#egg=django-splash==0.2
-e git+https://github.com/edx/django-splash.git@v0.2#egg=django-splash==0.2
-e git+https://github.com/edx/acid-block.git@e46f9cda8a03e121a00c7e347084d142d22ebfb7#egg=acid-xblock
-e git+https://github.com/edx/acid-block.git@e46f9cda8a03e121a00c7e347084d142d22ebfb7#egg=acid-xblock
git+https://github.com/edx/edx-ora2.git@1.3.
1#egg=ora2==1.3.1
git+https://github.com/edx/edx-ora2.git@1.3.
2#egg=ora2==1.3.2
-e git+https://github.com/edx/edx-submissions.git@1.
1.6#egg=edx-submissions==1.1.6
-e git+https://github.com/edx/edx-submissions.git@1.
2.0#egg=edx-submissions==1.2.0
git+https://github.com/edx/ease.git@release-2015-07-14#egg=ease==0.1.3
git+https://github.com/edx/ease.git@release-2015-07-14#egg=ease==0.1.3
git+https://github.com/edx/edx-val.git@0.0.13#egg=edxval==0.0.13
git+https://github.com/edx/edx-val.git@0.0.13#egg=edxval==0.0.13
git+https://github.com/pmitros/RecommenderXBlock.git@v1.1#egg=recommender-xblock==1.1
git+https://github.com/pmitros/RecommenderXBlock.git@v1.1#egg=recommender-xblock==1.1
...
...
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