diff --git a/lms/djangoapps/badges/models.py b/lms/djangoapps/badges/models.py index cc076c488a..3258e73a29 100644 --- a/lms/djangoapps/badges/models.py +++ b/lms/djangoapps/badges/models.py @@ -37,6 +37,12 @@ def validate_lowercase(string): raise ValidationError(_(u"This value must be all lowercase.")) +class CourseBadgesDisabledError(Exception): + """ + Exception raised when Course Badges aren't enabled, but an attempt to fetch one is made anyway. + """ + + class BadgeClass(models.Model): """ Specifies a badge class to be registered with a backend. @@ -67,6 +73,8 @@ class BadgeClass(models.Model): """ slug = slug.lower() issuing_component = issuing_component.lower() + if course_id and not modulestore().get_course(course_id).issue_badges: + raise CourseBadgesDisabledError("This course does not have badges enabled.") if not course_id: course_id = CourseKeyField.Empty try: diff --git a/lms/djangoapps/badges/service.py b/lms/djangoapps/badges/service.py index 05cc520795..83a0d0b505 100644 --- a/lms/djangoapps/badges/service.py +++ b/lms/djangoapps/badges/service.py @@ -7,5 +7,22 @@ from badges.models import BadgeClass class BadgingService(object): """ A class that provides functions for managing badges which XBlocks can use. + + If course_enabled is True, course-level badges are permitted for this course. + + If it is False, any badges that are awarded should be non-course specific. """ + course_badges_enabled = False + + def __init__(self, course_id=None, modulestore=None): + """ + Sets the 'course_badges_enabled' parameter. + """ + if not (course_id and modulestore): + return + + course = modulestore.get_course(course_id) + if course: + self.course_badges_enabled = course.issue_badges + get_badge_class = BadgeClass.get_badge_class diff --git a/lms/djangoapps/badges/tests/test_models.py b/lms/djangoapps/badges/tests/test_models.py index 6058ce0ee2..a59d7020c2 100644 --- a/lms/djangoapps/badges/tests/test_models.py +++ b/lms/djangoapps/badges/tests/test_models.py @@ -12,7 +12,8 @@ from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory -from badges.models import CourseCompleteImageConfiguration, validate_badge_image, BadgeClass, BadgeAssertion +from badges.models import CourseCompleteImageConfiguration, validate_badge_image, BadgeClass, BadgeAssertion, \ + CourseBadgesDisabledError from badges.tests.factories import BadgeClassFactory, BadgeAssertionFactory, RandomBadgeClassFactory from certificates.tests.test_models import TEST_DATA_ROOT from student.tests.factories import UserFactory @@ -105,6 +106,19 @@ class BadgeClassTest(ModuleStoreTestCase): self.assertNotEqual(badge_class.id, course_badge_class.id) self.assertEqual(course_badge_class.id, premade_badge_class.id) + def test_get_badge_class_course_disabled(self): + """ + Verify attempting to fetch a badge class for a course which does not issue badges raises an + exception. + """ + course_key = CourseFactory.create(metadata={'issue_badges': False}).location.course_key + self.assertRaises( + CourseBadgesDisabledError, BadgeClass.get_badge_class, + slug='test_slug', issuing_component='test_component', description='Attempted override', + criteria='test', display_name='Testola', image_file_handle=get_image('good'), + course_id=course_key, + ) + def test_get_badge_class_create(self): """ Verify fetching a badge creates it if it doesn't yet exist. diff --git a/lms/djangoapps/lms_xblock/runtime.py b/lms/djangoapps/lms_xblock/runtime.py index c06784115f..cee5aceaf6 100644 --- a/lms/djangoapps/lms_xblock/runtime.py +++ b/lms/djangoapps/lms_xblock/runtime.py @@ -212,10 +212,11 @@ class LmsModuleSystem(ModuleSystem): # pylint: disable=abstract-method track_function=kwargs.get('track_function', None), cache=request_cache_dict ) + store = modulestore() services['settings'] = SettingsService() services['user_tags'] = UserTagsService(self) if settings.FEATURES["ENABLE_OPENBADGES"]: - services['badging'] = BadgingService() + services['badging'] = BadgingService(course_id=kwargs.get('course_id'), modulestore=store) self.request_token = kwargs.pop('request_token', None) super(LmsModuleSystem, self).__init__(**kwargs) diff --git a/lms/djangoapps/lms_xblock/test/test_runtime.py b/lms/djangoapps/lms_xblock/test/test_runtime.py index 70f3fc56d1..959372e902 100644 --- a/lms/djangoapps/lms_xblock/test/test_runtime.py +++ b/lms/djangoapps/lms_xblock/test/test_runtime.py @@ -11,6 +11,7 @@ from urlparse import urlparse from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locations import BlockUsageLocator, CourseLocator, SlashSeparatedCourseKey +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from badges.tests.factories import BadgeClassFactory from badges.tests.test_models import get_image @@ -21,6 +22,7 @@ from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xblock.exceptions import NoSuchServiceError from student.tests.factories import UserFactory +from xmodule.modulestore.tests.factories import CourseFactory TEST_STRINGS = [ '', @@ -191,16 +193,13 @@ class TestUserServiceAPI(TestCase): self.runtime.service(self.mock_block, 'user_tags').get_tag('fake_scope', self.key) -class TestBadgingService(TestCase): +class TestBadgingService(ModuleStoreTestCase): """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' @@ -233,6 +232,18 @@ class TestBadgingService(TestCase): runtime = self.create_runtime() self.assertFalse(runtime.service(self.mock_block, 'badging')) + @patch.dict(settings.FEATURES, {'ENABLE_OPENBADGES': True}) + def test_course_badges_disabled(self): + self.course_id = CourseFactory.create(metadata={'issue_badges': False}).location.course_key + runtime = self.create_runtime() + self.assertFalse(runtime.service(self.mock_block, 'badging').course_badges_enabled) + + @patch.dict(settings.FEATURES, {'ENABLE_OPENBADGES': True}) + def test_course_badges_enabled(self): + self.course_id = CourseFactory.create(metadata={'issue_badges': True}).location.course_key + runtime = self.create_runtime() + self.assertTrue(runtime.service(self.mock_block, 'badging').course_badges_enabled) + @patch.dict(settings.FEATURES, {'ENABLE_OPENBADGES': True}) def test_get_badge_class(self): runtime = self.create_runtime()