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
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
103 additions
and
27 deletions
+103
-27
lms/djangoapps/badges/service.py
+11
-0
lms/djangoapps/badges/tests/test_models.py
+18
-22
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,19 +17,15 @@ from certificates.tests.test_models import TEST_DATA_ROOT
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
.
Get one of the test images from the test data directory
.
"""
def
get_image
(
self
,
name
):
"""
Get one of the test images from the test data directory.
"""
return
ImageFile
(
open
(
TEST_DATA_ROOT
/
'badges'
/
name
+
'.png'
))
return
ImageFile
(
open
(
TEST_DATA_ROOT
/
'badges'
/
name
+
'.png'
))
@attr
(
'shard_1'
)
class
BadgeImageConfigurationTest
(
TestCase
,
ImageFetchingMixin
):
class
BadgeImageConfigurationTest
(
TestCase
):
"""
Test the validation features of BadgeImageConfiguration.
"""
...
...
@@ -38,10 +34,10 @@ class BadgeImageConfigurationTest(TestCase, ImageFetchingMixin):
"""
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
(
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
):
...
...
@@ -50,7 +46,7 @@ class BadgeImageConfigurationTest(TestCase, ImageFetchingMixin):
"""
self
.
assertRaises
(
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):
"""
class
BadgeClassTest
(
ModuleStoreTestCase
,
ImageFetchingMixin
):
class
BadgeClassTest
(
ModuleStoreTestCase
):
"""
Test BadgeClass functionality
"""
...
...
@@ -80,7 +76,7 @@ class BadgeClassTest(ModuleStoreTestCase, ImageFetchingMixin):
# Ignore additional parameters. This class already exists.
badge_class
=
BadgeClass
.
get_badge_class
(
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.
self
.
assertEqual
(
badge_class
.
criteria
,
'https://example.com/syllabus'
)
...
...
@@ -97,11 +93,11 @@ class BadgeClassTest(ModuleStoreTestCase, ImageFetchingMixin):
premade_badge_class
=
BadgeClassFactory
.
create
(
course_id
=
course_key
)
badge_class
=
BadgeClass
.
get_badge_class
(
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
(
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
,
)
self
.
assertNotEqual
(
badge_class
.
id
,
course_badge_class
.
id
)
...
...
@@ -114,7 +110,7 @@ class BadgeClassTest(ModuleStoreTestCase, ImageFetchingMixin):
badge_class
=
BadgeClass
.
get_badge_class
(
slug
=
'new_slug'
,
issuing_component
=
'new_component'
,
description
=
'This is a test'
,
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.
self
.
assertTrue
(
badge_class
.
id
)
...
...
@@ -152,7 +148,7 @@ class BadgeClassTest(ModuleStoreTestCase, ImageFetchingMixin):
BadgeClass
.
get_badge_class
,
slug
=
'new_slug'
,
issuing_component
=
'new_component'
,
description
=
'This is a test'
,
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
):
...
...
@@ -185,7 +181,7 @@ class BadgeClassTest(ModuleStoreTestCase, ImageFetchingMixin):
ValidationError
,
BadgeClass
(
slug
=
'test'
,
issuing_component
=
'test2'
,
criteria
=
'test3'
,
description
=
'test4'
,
image
=
self
.
get_image
(
'unbalanced'
)
description
=
'test4'
,
image
=
get_image
(
'unbalanced'
)
)
.
full_clean
)
...
...
@@ -221,7 +217,7 @@ class BadgeAssertionTest(ModuleStoreTestCase):
self
.
assertEqual
(
course_scoped_assertions
,
course_assertions
)
class
ValidBadgeImageTest
(
TestCase
,
ImageFetchingMixin
):
class
ValidBadgeImageTest
(
TestCase
):
"""
Tests the badge image field validator.
"""
...
...
@@ -229,18 +225,18 @@ class ValidBadgeImageTest(TestCase, ImageFetchingMixin):
"""
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
):
"""
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
)
def
test_large_image
(
self
):
"""
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
)
lms/djangoapps/lms_xblock/runtime.py
View file @
25958feb
...
...
@@ -6,6 +6,7 @@ import re
from
django.core.urlresolvers
import
reverse
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
request_cache.middleware
import
RequestCache
import
xblock.reference.plugins
...
...
@@ -213,6 +214,8 @@ class LmsModuleSystem(ModuleSystem): # pylint: disable=abstract-method
)
services
[
'settings'
]
=
SettingsService
()
services
[
'user_tags'
]
=
UserTagsService
(
self
)
if
settings
.
FEATURES
[
"ENABLE_OPENBADGES"
]:
services
[
'badging'
]
=
BadgingService
()
self
.
request_token
=
kwargs
.
pop
(
'request_token'
,
None
)
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
from
django.contrib.auth.models
import
User
from
django.conf
import
settings
from
ddt
import
ddt
,
data
from
mock
import
Mock
from
unittest
import
TestCase
from
django.test
import
TestCase
from
mock
import
Mock
,
patch
from
urlparse
import
urlparse
from
opaque_keys.edx.keys
import
CourseKey
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
xblock.fields
import
ScopeIds
from
xmodule.modulestore.django
import
ModuleI18nService
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xblock.exceptions
import
NoSuchServiceError
from
student.tests.factories
import
UserFactory
TEST_STRINGS
=
[
''
,
'foobar'
,
...
...
@@ -141,9 +148,7 @@ class TestUserServiceAPI(TestCase):
def
setUp
(
self
):
super
(
TestUserServiceAPI
,
self
)
.
setUp
()
self
.
course_id
=
SlashSeparatedCourseKey
(
"org"
,
"course"
,
"run"
)
self
.
user
=
User
(
username
=
'runtime_robot'
,
email
=
'runtime_robot@edx.org'
,
password
=
'test'
,
first_name
=
'Robot'
)
self
.
user
.
save
()
self
.
user
=
UserFactory
.
create
()
def
mock_get_real_user
(
_anon_id
):
"""Just returns the test user"""
...
...
@@ -186,6 +191,67 @@ class TestUserServiceAPI(TestCase):
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
):
""" 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