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
25958feb
Commit
25958feb
authored
Nov 10, 2015
by
Jonathan Piacenti
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add XBlock Badging Service.
parent
112a1435
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
101 additions
and
25 deletions
+101
-25
lms/djangoapps/badges/service.py
+11
-0
lms/djangoapps/badges/tests/test_models.py
+16
-20
lms/djangoapps/lms_xblock/runtime.py
+3
-0
lms/djangoapps/lms_xblock/test/test_runtime.py
+71
-5
No files found.
lms/djangoapps/badges/service.py
0 → 100644
View file @
25958feb
"""
Badging service for XBlocks
"""
from
badges.models
import
BadgeClass
class
BadgingService
(
object
):
"""
A class that provides functions for managing badges which XBlocks can use.
"""
get_badge_class
=
BadgeClass
.
get_badge_class
lms/djangoapps/badges/tests/test_models.py
View file @
25958feb
...
@@ -17,11 +17,7 @@ from certificates.tests.test_models import TEST_DATA_ROOT
...
@@ -17,11 +17,7 @@ from certificates.tests.test_models import TEST_DATA_ROOT
from
student.tests.factories
import
UserFactory
from
student.tests.factories
import
UserFactory
class
ImageFetchingMixin
(
object
):
def
get_image
(
name
):
"""
Provides the ability to grab a badge image from the test data root.
"""
def
get_image
(
self
,
name
):
"""
"""
Get one of the test images from the test data directory.
Get one of the test images from the test data directory.
"""
"""
...
@@ -29,7 +25,7 @@ class ImageFetchingMixin(object):
...
@@ -29,7 +25,7 @@ class ImageFetchingMixin(object):
@attr
(
'shard_1'
)
@attr
(
'shard_1'
)
class
BadgeImageConfigurationTest
(
TestCase
,
ImageFetchingMixin
):
class
BadgeImageConfigurationTest
(
TestCase
):
"""
"""
Test the validation features of BadgeImageConfiguration.
Test the validation features of BadgeImageConfiguration.
"""
"""
...
@@ -38,10 +34,10 @@ class BadgeImageConfigurationTest(TestCase, ImageFetchingMixin):
...
@@ -38,10 +34,10 @@ class BadgeImageConfigurationTest(TestCase, ImageFetchingMixin):
"""
"""
Verify that creating two configurations as default is not permitted.
Verify that creating two configurations as default is not permitted.
"""
"""
CourseCompleteImageConfiguration
(
mode
=
'test'
,
icon
=
self
.
get_image
(
'good'
),
default
=
True
)
.
save
()
CourseCompleteImageConfiguration
(
mode
=
'test'
,
icon
=
get_image
(
'good'
),
default
=
True
)
.
save
()
self
.
assertRaises
(
self
.
assertRaises
(
ValidationError
,
ValidationError
,
CourseCompleteImageConfiguration
(
mode
=
'test2'
,
icon
=
self
.
get_image
(
'good'
),
default
=
True
)
.
full_clean
CourseCompleteImageConfiguration
(
mode
=
'test2'
,
icon
=
get_image
(
'good'
),
default
=
True
)
.
full_clean
)
)
def
test_runs_validator
(
self
):
def
test_runs_validator
(
self
):
...
@@ -50,7 +46,7 @@ class BadgeImageConfigurationTest(TestCase, ImageFetchingMixin):
...
@@ -50,7 +46,7 @@ class BadgeImageConfigurationTest(TestCase, ImageFetchingMixin):
"""
"""
self
.
assertRaises
(
self
.
assertRaises
(
ValidationError
,
ValidationError
,
CourseCompleteImageConfiguration
(
mode
=
'test2'
,
icon
=
self
.
get_image
(
'unbalanced'
))
.
full_clean
CourseCompleteImageConfiguration
(
mode
=
'test2'
,
icon
=
get_image
(
'unbalanced'
))
.
full_clean
)
)
...
@@ -60,7 +56,7 @@ class DummyBackend(object):
...
@@ -60,7 +56,7 @@ class DummyBackend(object):
"""
"""
class
BadgeClassTest
(
ModuleStoreTestCase
,
ImageFetchingMixin
):
class
BadgeClassTest
(
ModuleStoreTestCase
):
"""
"""
Test BadgeClass functionality
Test BadgeClass functionality
"""
"""
...
@@ -80,7 +76,7 @@ class BadgeClassTest(ModuleStoreTestCase, ImageFetchingMixin):
...
@@ -80,7 +76,7 @@ class BadgeClassTest(ModuleStoreTestCase, ImageFetchingMixin):
# Ignore additional parameters. This class already exists.
# Ignore additional parameters. This class already exists.
badge_class
=
BadgeClass
.
get_badge_class
(
badge_class
=
BadgeClass
.
get_badge_class
(
slug
=
'test_slug'
,
issuing_component
=
'test_component'
,
description
=
'Attempted override'
,
slug
=
'test_slug'
,
issuing_component
=
'test_component'
,
description
=
'Attempted override'
,
criteria
=
'test'
,
display_name
=
'Testola'
,
image_file_handle
=
self
.
get_image
(
'good'
)
criteria
=
'test'
,
display_name
=
'Testola'
,
image_file_handle
=
get_image
(
'good'
)
)
)
# These defaults are set on the factory.
# These defaults are set on the factory.
self
.
assertEqual
(
badge_class
.
criteria
,
'https://example.com/syllabus'
)
self
.
assertEqual
(
badge_class
.
criteria
,
'https://example.com/syllabus'
)
...
@@ -97,11 +93,11 @@ class BadgeClassTest(ModuleStoreTestCase, ImageFetchingMixin):
...
@@ -97,11 +93,11 @@ class BadgeClassTest(ModuleStoreTestCase, ImageFetchingMixin):
premade_badge_class
=
BadgeClassFactory
.
create
(
course_id
=
course_key
)
premade_badge_class
=
BadgeClassFactory
.
create
(
course_id
=
course_key
)
badge_class
=
BadgeClass
.
get_badge_class
(
badge_class
=
BadgeClass
.
get_badge_class
(
slug
=
'test_slug'
,
issuing_component
=
'test_component'
,
description
=
'Attempted override'
,
slug
=
'test_slug'
,
issuing_component
=
'test_component'
,
description
=
'Attempted override'
,
criteria
=
'test'
,
display_name
=
'Testola'
,
image_file_handle
=
self
.
get_image
(
'good'
)
criteria
=
'test'
,
display_name
=
'Testola'
,
image_file_handle
=
get_image
(
'good'
)
)
)
course_badge_class
=
BadgeClass
.
get_badge_class
(
course_badge_class
=
BadgeClass
.
get_badge_class
(
slug
=
'test_slug'
,
issuing_component
=
'test_component'
,
description
=
'Attempted override'
,
slug
=
'test_slug'
,
issuing_component
=
'test_component'
,
description
=
'Attempted override'
,
criteria
=
'test'
,
display_name
=
'Testola'
,
image_file_handle
=
self
.
get_image
(
'good'
),
criteria
=
'test'
,
display_name
=
'Testola'
,
image_file_handle
=
get_image
(
'good'
),
course_id
=
course_key
,
course_id
=
course_key
,
)
)
self
.
assertNotEqual
(
badge_class
.
id
,
course_badge_class
.
id
)
self
.
assertNotEqual
(
badge_class
.
id
,
course_badge_class
.
id
)
...
@@ -114,7 +110,7 @@ class BadgeClassTest(ModuleStoreTestCase, ImageFetchingMixin):
...
@@ -114,7 +110,7 @@ class BadgeClassTest(ModuleStoreTestCase, ImageFetchingMixin):
badge_class
=
BadgeClass
.
get_badge_class
(
badge_class
=
BadgeClass
.
get_badge_class
(
slug
=
'new_slug'
,
issuing_component
=
'new_component'
,
description
=
'This is a test'
,
slug
=
'new_slug'
,
issuing_component
=
'new_component'
,
description
=
'This is a test'
,
criteria
=
'https://example.com/test_criteria'
,
display_name
=
'Super Badge'
,
criteria
=
'https://example.com/test_criteria'
,
display_name
=
'Super Badge'
,
image_file_handle
=
self
.
get_image
(
'good'
)
image_file_handle
=
get_image
(
'good'
)
)
)
# This should have been saved before being passed back.
# This should have been saved before being passed back.
self
.
assertTrue
(
badge_class
.
id
)
self
.
assertTrue
(
badge_class
.
id
)
...
@@ -152,7 +148,7 @@ class BadgeClassTest(ModuleStoreTestCase, ImageFetchingMixin):
...
@@ -152,7 +148,7 @@ class BadgeClassTest(ModuleStoreTestCase, ImageFetchingMixin):
BadgeClass
.
get_badge_class
,
BadgeClass
.
get_badge_class
,
slug
=
'new_slug'
,
issuing_component
=
'new_component'
,
description
=
'This is a test'
,
slug
=
'new_slug'
,
issuing_component
=
'new_component'
,
description
=
'This is a test'
,
criteria
=
'https://example.com/test_criteria'
,
display_name
=
'Super Badge'
,
criteria
=
'https://example.com/test_criteria'
,
display_name
=
'Super Badge'
,
image_file_handle
=
self
.
get_image
(
'unbalanced'
)
image_file_handle
=
get_image
(
'unbalanced'
)
)
)
def
test_get_for_user
(
self
):
def
test_get_for_user
(
self
):
...
@@ -185,7 +181,7 @@ class BadgeClassTest(ModuleStoreTestCase, ImageFetchingMixin):
...
@@ -185,7 +181,7 @@ class BadgeClassTest(ModuleStoreTestCase, ImageFetchingMixin):
ValidationError
,
ValidationError
,
BadgeClass
(
BadgeClass
(
slug
=
'test'
,
issuing_component
=
'test2'
,
criteria
=
'test3'
,
slug
=
'test'
,
issuing_component
=
'test2'
,
criteria
=
'test3'
,
description
=
'test4'
,
image
=
self
.
get_image
(
'unbalanced'
)
description
=
'test4'
,
image
=
get_image
(
'unbalanced'
)
)
.
full_clean
)
.
full_clean
)
)
...
@@ -221,7 +217,7 @@ class BadgeAssertionTest(ModuleStoreTestCase):
...
@@ -221,7 +217,7 @@ class BadgeAssertionTest(ModuleStoreTestCase):
self
.
assertEqual
(
course_scoped_assertions
,
course_assertions
)
self
.
assertEqual
(
course_scoped_assertions
,
course_assertions
)
class
ValidBadgeImageTest
(
TestCase
,
ImageFetchingMixin
):
class
ValidBadgeImageTest
(
TestCase
):
"""
"""
Tests the badge image field validator.
Tests the badge image field validator.
"""
"""
...
@@ -229,18 +225,18 @@ class ValidBadgeImageTest(TestCase, ImageFetchingMixin):
...
@@ -229,18 +225,18 @@ class ValidBadgeImageTest(TestCase, ImageFetchingMixin):
"""
"""
Verify that saving a valid badge image is no problem.
Verify that saving a valid badge image is no problem.
"""
"""
validate_badge_image
(
self
.
get_image
(
'good'
))
validate_badge_image
(
get_image
(
'good'
))
def
test_unbalanced_image
(
self
):
def
test_unbalanced_image
(
self
):
"""
"""
Verify that setting an image with an uneven width and height raises an error.
Verify that setting an image with an uneven width and height raises an error.
"""
"""
unbalanced
=
ImageFile
(
self
.
get_image
(
'unbalanced'
))
unbalanced
=
ImageFile
(
get_image
(
'unbalanced'
))
self
.
assertRaises
(
ValidationError
,
validate_badge_image
,
unbalanced
)
self
.
assertRaises
(
ValidationError
,
validate_badge_image
,
unbalanced
)
def
test_large_image
(
self
):
def
test_large_image
(
self
):
"""
"""
Verify that setting an image that is too big raises an error.
Verify that setting an image that is too big raises an error.
"""
"""
large
=
self
.
get_image
(
'large'
)
large
=
get_image
(
'large'
)
self
.
assertRaises
(
ValidationError
,
validate_badge_image
,
large
)
self
.
assertRaises
(
ValidationError
,
validate_badge_image
,
large
)
lms/djangoapps/lms_xblock/runtime.py
View file @
25958feb
...
@@ -6,6 +6,7 @@ import re
...
@@ -6,6 +6,7 @@ import re
from
django.core.urlresolvers
import
reverse
from
django.core.urlresolvers
import
reverse
from
django.conf
import
settings
from
django.conf
import
settings
from
badges.service
import
BadgingService
from
openedx.core.djangoapps.user_api.course_tag
import
api
as
user_course_tag_api
from
openedx.core.djangoapps.user_api.course_tag
import
api
as
user_course_tag_api
from
request_cache.middleware
import
RequestCache
from
request_cache.middleware
import
RequestCache
import
xblock.reference.plugins
import
xblock.reference.plugins
...
@@ -213,6 +214,8 @@ class LmsModuleSystem(ModuleSystem): # pylint: disable=abstract-method
...
@@ -213,6 +214,8 @@ class LmsModuleSystem(ModuleSystem): # pylint: disable=abstract-method
)
)
services
[
'settings'
]
=
SettingsService
()
services
[
'settings'
]
=
SettingsService
()
services
[
'user_tags'
]
=
UserTagsService
(
self
)
services
[
'user_tags'
]
=
UserTagsService
(
self
)
if
settings
.
FEATURES
[
"ENABLE_OPENBADGES"
]:
services
[
'badging'
]
=
BadgingService
()
self
.
request_token
=
kwargs
.
pop
(
'request_token'
,
None
)
self
.
request_token
=
kwargs
.
pop
(
'request_token'
,
None
)
super
(
LmsModuleSystem
,
self
)
.
__init__
(
**
kwargs
)
super
(
LmsModuleSystem
,
self
)
.
__init__
(
**
kwargs
)
...
...
lms/djangoapps/lms_xblock/test/test_runtime.py
View file @
25958feb
...
@@ -5,16 +5,23 @@ Tests of the LMS XBlock Runtime and associated utilities
...
@@ -5,16 +5,23 @@ Tests of the LMS XBlock Runtime and associated utilities
from
django.contrib.auth.models
import
User
from
django.contrib.auth.models
import
User
from
django.conf
import
settings
from
django.conf
import
settings
from
ddt
import
ddt
,
data
from
ddt
import
ddt
,
data
from
mock
import
Mock
from
django.test
import
TestCase
from
unittest
import
TestCase
from
mock
import
Mock
,
patch
from
urlparse
import
urlparse
from
urlparse
import
urlparse
from
opaque_keys.edx.keys
import
CourseKey
from
opaque_keys.edx.locations
import
BlockUsageLocator
,
CourseLocator
,
SlashSeparatedCourseKey
from
opaque_keys.edx.locations
import
BlockUsageLocator
,
CourseLocator
,
SlashSeparatedCourseKey
from
badges.tests.factories
import
BadgeClassFactory
from
badges.tests.test_models
import
get_image
from
lms.djangoapps.lms_xblock.runtime
import
quote_slashes
,
unquote_slashes
,
LmsModuleSystem
from
lms.djangoapps.lms_xblock.runtime
import
quote_slashes
,
unquote_slashes
,
LmsModuleSystem
from
xblock.fields
import
ScopeIds
from
xblock.fields
import
ScopeIds
from
xmodule.modulestore.django
import
ModuleI18nService
from
xmodule.modulestore.django
import
ModuleI18nService
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xblock.exceptions
import
NoSuchServiceError
from
xblock.exceptions
import
NoSuchServiceError
from
student.tests.factories
import
UserFactory
TEST_STRINGS
=
[
TEST_STRINGS
=
[
''
,
''
,
'foobar'
,
'foobar'
,
...
@@ -141,9 +148,7 @@ class TestUserServiceAPI(TestCase):
...
@@ -141,9 +148,7 @@ class TestUserServiceAPI(TestCase):
def
setUp
(
self
):
def
setUp
(
self
):
super
(
TestUserServiceAPI
,
self
)
.
setUp
()
super
(
TestUserServiceAPI
,
self
)
.
setUp
()
self
.
course_id
=
SlashSeparatedCourseKey
(
"org"
,
"course"
,
"run"
)
self
.
course_id
=
SlashSeparatedCourseKey
(
"org"
,
"course"
,
"run"
)
self
.
user
=
UserFactory
.
create
()
self
.
user
=
User
(
username
=
'runtime_robot'
,
email
=
'runtime_robot@edx.org'
,
password
=
'test'
,
first_name
=
'Robot'
)
self
.
user
.
save
()
def
mock_get_real_user
(
_anon_id
):
def
mock_get_real_user
(
_anon_id
):
"""Just returns the test user"""
"""Just returns the test user"""
...
@@ -186,6 +191,67 @@ class TestUserServiceAPI(TestCase):
...
@@ -186,6 +191,67 @@ class TestUserServiceAPI(TestCase):
self
.
runtime
.
service
(
self
.
mock_block
,
'user_tags'
)
.
get_tag
(
'fake_scope'
,
self
.
key
)
self
.
runtime
.
service
(
self
.
mock_block
,
'user_tags'
)
.
get_tag
(
'fake_scope'
,
self
.
key
)
class
TestBadgingService
(
TestCase
):
"""Test the badging service interface"""
def
setUp
(
self
):
super
(
TestBadgingService
,
self
)
.
setUp
()
self
.
course_id
=
CourseKey
.
from_string
(
'course-v1:org+course+run'
)
self
.
user
=
User
(
username
=
'test_robot'
,
email
=
'test_robot@edx.org'
,
password
=
'test'
,
first_name
=
'Test'
)
self
.
user
.
save
()
self
.
mock_block
=
Mock
()
self
.
mock_block
.
service_declaration
.
return_value
=
'needs'
def
create_runtime
(
self
):
"""
Create the testing runtime.
"""
def
mock_get_real_user
(
_anon_id
):
"""Just returns the test user"""
return
self
.
user
return
LmsModuleSystem
(
static_url
=
'/static'
,
track_function
=
Mock
(),
get_module
=
Mock
(),
render_template
=
Mock
(),
replace_urls
=
str
,
course_id
=
self
.
course_id
,
get_real_user
=
mock_get_real_user
,
descriptor_runtime
=
Mock
(),
)
@patch.dict
(
settings
.
FEATURES
,
{
'ENABLE_OPENBADGES'
:
True
})
def
test_service_rendered
(
self
):
runtime
=
self
.
create_runtime
()
self
.
assertTrue
(
runtime
.
service
(
self
.
mock_block
,
'badging'
))
@patch.dict
(
settings
.
FEATURES
,
{
'ENABLE_OPENBADGES'
:
False
})
def
test_no_service_rendered
(
self
):
runtime
=
self
.
create_runtime
()
self
.
assertFalse
(
runtime
.
service
(
self
.
mock_block
,
'badging'
))
@patch.dict
(
settings
.
FEATURES
,
{
'ENABLE_OPENBADGES'
:
True
})
def
test_get_badge_class
(
self
):
runtime
=
self
.
create_runtime
()
badge_service
=
runtime
.
service
(
self
.
mock_block
,
'badging'
)
premade_badge_class
=
BadgeClassFactory
.
create
()
# Ignore additional parameters. This class already exists.
# We should get back the first class we created, rather than a new one.
badge_class
=
badge_service
.
get_badge_class
(
slug
=
'test_slug'
,
issuing_component
=
'test_component'
,
description
=
'Attempted override'
,
criteria
=
'test'
,
display_name
=
'Testola'
,
image_file_handle
=
get_image
(
'good'
)
)
# These defaults are set on the factory.
self
.
assertEqual
(
badge_class
.
criteria
,
'https://example.com/syllabus'
)
self
.
assertEqual
(
badge_class
.
display_name
,
'Test Badge'
)
self
.
assertEqual
(
badge_class
.
description
,
"Yay! It's a test badge."
)
# File name won't always be the same.
self
.
assertEqual
(
badge_class
.
image
.
path
,
premade_badge_class
.
image
.
path
)
class
TestI18nService
(
ModuleStoreTestCase
):
class
TestI18nService
(
ModuleStoreTestCase
):
""" Test ModuleI18nService """
""" Test ModuleI18nService """
...
...
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