refac: ran pyupgrade on lms/djangoapps/badges
This commit is contained in:
@@ -3,7 +3,7 @@ Admin registration for Badge Models
|
||||
"""
|
||||
|
||||
|
||||
from config_models.admin import ConfigurationModelAdmin # lint-amnesty, pylint: disable=import-error
|
||||
from config_models.admin import ConfigurationModelAdmin
|
||||
from django.contrib import admin
|
||||
|
||||
from lms.djangoapps.badges.models import BadgeClass, CourseCompleteImageConfiguration, CourseEventBadgesConfiguration
|
||||
|
||||
@@ -3,7 +3,7 @@ Serializers for Badges
|
||||
"""
|
||||
|
||||
|
||||
from rest_framework import serializers # lint-amnesty, pylint: disable=import-error
|
||||
from rest_framework import serializers
|
||||
|
||||
from lms.djangoapps.badges.models import BadgeAssertion, BadgeClass
|
||||
|
||||
@@ -14,7 +14,7 @@ class BadgeClassSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
image_url = serializers.ImageField(source='image')
|
||||
|
||||
class Meta(object):
|
||||
class Meta:
|
||||
model = BadgeClass
|
||||
fields = ('slug', 'issuing_component', 'display_name', 'course_id', 'description', 'criteria', 'image_url')
|
||||
|
||||
@@ -25,6 +25,6 @@ class BadgeAssertionSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
badge_class = BadgeClassSerializer(read_only=True)
|
||||
|
||||
class Meta(object):
|
||||
class Meta:
|
||||
model = BadgeAssertion
|
||||
fields = ('badge_class', 'image_url', 'assertion_url', 'created')
|
||||
|
||||
@@ -3,18 +3,16 @@ Tests for the badges API views.
|
||||
"""
|
||||
|
||||
|
||||
import six
|
||||
from ddt import data, ddt, unpack # lint-amnesty, pylint: disable=import-error
|
||||
from ddt import data, ddt, unpack
|
||||
from django.conf import settings
|
||||
from django.test.utils import override_settings
|
||||
from six.moves import range
|
||||
|
||||
from lms.djangoapps.badges.tests.factories import BadgeAssertionFactory, BadgeClassFactory, RandomBadgeClassFactory
|
||||
from openedx.core.lib.api.test_utils import ApiTestCase
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
from common.djangoapps.util.testing import UrlResetMixin
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase # lint-amnesty, pylint: disable=import-error, wrong-import-order
|
||||
from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=import-error, wrong-import-order
|
||||
from lms.djangoapps.badges.tests.factories import BadgeAssertionFactory, BadgeClassFactory, RandomBadgeClassFactory
|
||||
from openedx.core.lib.api.test_utils import ApiTestCase
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
|
||||
FEATURES_WITH_BADGES_ENABLED = settings.FEATURES.copy()
|
||||
FEATURES_WITH_BADGES_ENABLED['ENABLE_OPENBADGES'] = True
|
||||
@@ -27,7 +25,7 @@ class UserAssertionTestCase(UrlResetMixin, ModuleStoreTestCase, ApiTestCase):
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(UserAssertionTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.course = CourseFactory.create()
|
||||
self.user = UserFactory.create()
|
||||
# Password defined by factory.
|
||||
@@ -37,7 +35,7 @@ class UserAssertionTestCase(UrlResetMixin, ModuleStoreTestCase, ApiTestCase):
|
||||
"""
|
||||
Return the URL to look up the current user's assertions.
|
||||
"""
|
||||
return '/api/badges/v1/assertions/user/{}/'.format(self.user.username)
|
||||
return f'/api/badges/v1/assertions/user/{self.user.username}/'
|
||||
|
||||
def check_class_structure(self, badge_class, json_class):
|
||||
"""
|
||||
@@ -48,7 +46,7 @@ class UserAssertionTestCase(UrlResetMixin, ModuleStoreTestCase, ApiTestCase):
|
||||
assert badge_class.image.url in json_class['image_url']
|
||||
assert badge_class.description == json_class['description']
|
||||
assert badge_class.criteria == json_class['criteria']
|
||||
assert (badge_class.course_id and six.text_type(badge_class.course_id)) == json_class['course_id']
|
||||
assert (badge_class.course_id and str(badge_class.course_id)) == json_class['course_id']
|
||||
|
||||
def check_assertion_structure(self, assertion, json_assertion):
|
||||
"""
|
||||
@@ -65,7 +63,7 @@ class UserAssertionTestCase(UrlResetMixin, ModuleStoreTestCase, ApiTestCase):
|
||||
if wildcard:
|
||||
return '*'
|
||||
else:
|
||||
return six.text_type(badge_class.course_id)
|
||||
return str(badge_class.course_id)
|
||||
|
||||
def create_badge_class(self, check_course, **kwargs):
|
||||
"""
|
||||
|
||||
@@ -3,12 +3,13 @@ API views for badges
|
||||
"""
|
||||
|
||||
|
||||
from edx_rest_framework_extensions.auth.session.authentication import SessionAuthenticationAllowInactiveUser # lint-amnesty, pylint: disable=import-error
|
||||
from opaque_keys import InvalidKeyError # lint-amnesty, pylint: disable=import-error
|
||||
from opaque_keys.edx.django.models import CourseKeyField # lint-amnesty, pylint: disable=import-error
|
||||
from opaque_keys.edx.keys import CourseKey # lint-amnesty, pylint: disable=import-error
|
||||
from rest_framework import generics # lint-amnesty, pylint: disable=import-error
|
||||
from rest_framework.exceptions import APIException # lint-amnesty, pylint: disable=import-error
|
||||
from edx_rest_framework_extensions.auth.session.authentication import \
|
||||
SessionAuthenticationAllowInactiveUser
|
||||
from opaque_keys import InvalidKeyError
|
||||
from opaque_keys.edx.django.models import CourseKeyField
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
from rest_framework import generics
|
||||
from rest_framework.exceptions import APIException
|
||||
|
||||
from lms.djangoapps.badges.models import BadgeAssertion
|
||||
from openedx.core.djangoapps.user_api.permissions import is_field_shared_factory
|
||||
|
||||
@@ -12,7 +12,7 @@ class BadgesConfig(AppConfig):
|
||||
"""
|
||||
Application Configuration for Badges.
|
||||
"""
|
||||
name = u'lms.djangoapps.badges'
|
||||
name = 'lms.djangoapps.badges'
|
||||
|
||||
def ready(self):
|
||||
"""
|
||||
|
||||
@@ -7,11 +7,10 @@ import hashlib
|
||||
import logging
|
||||
import mimetypes
|
||||
|
||||
import requests # lint-amnesty, pylint: disable=import-error
|
||||
import six
|
||||
import requests
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from eventtracking import tracker # lint-amnesty, pylint: disable=import-error
|
||||
from eventtracking import tracker
|
||||
from lazy import lazy # lint-amnesty, pylint: disable=no-name-in-module
|
||||
from requests.packages.urllib3.exceptions import HTTPError # lint-amnesty, pylint: disable=import-error
|
||||
|
||||
@@ -29,7 +28,7 @@ class BadgrBackend(BadgeBackend):
|
||||
badges = []
|
||||
|
||||
def __init__(self):
|
||||
super(BadgrBackend, self).__init__() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().__init__()
|
||||
if not settings.BADGR_API_TOKEN:
|
||||
raise ImproperlyConfigured("BADGR_API_TOKEN not set.")
|
||||
|
||||
@@ -38,20 +37,20 @@ class BadgrBackend(BadgeBackend):
|
||||
"""
|
||||
Base URL for all API requests.
|
||||
"""
|
||||
return "{}/v1/issuer/issuers/{}".format(settings.BADGR_BASE_URL, settings.BADGR_ISSUER_SLUG)
|
||||
return f"{settings.BADGR_BASE_URL}/v1/issuer/issuers/{settings.BADGR_ISSUER_SLUG}"
|
||||
|
||||
@lazy
|
||||
def _badge_create_url(self):
|
||||
"""
|
||||
URL for generating a new Badge specification
|
||||
"""
|
||||
return "{}/badges".format(self._base_url)
|
||||
return f"{self._base_url}/badges"
|
||||
|
||||
def _badge_url(self, slug):
|
||||
"""
|
||||
Get the URL for a course's badge in a given mode.
|
||||
"""
|
||||
return "{}/{}".format(self._badge_create_url, slug)
|
||||
return f"{self._badge_create_url}/{slug}"
|
||||
|
||||
def _assertion_url(self, slug):
|
||||
"""
|
||||
@@ -67,7 +66,7 @@ class BadgrBackend(BadgeBackend):
|
||||
if badge_class.issuing_component and badge_class.course_id:
|
||||
# Make this unique to the course, and down to 64 characters.
|
||||
# We don't do this to badges without issuing_component set for backwards compatibility.
|
||||
slug = hashlib.sha256((slug + six.text_type(badge_class.course_id)).encode('utf-8')).hexdigest()
|
||||
slug = hashlib.sha256((slug + str(badge_class.course_id)).encode('utf-8')).hexdigest()
|
||||
if len(slug) > MAX_SLUG_LENGTH:
|
||||
# Will be 64 characters.
|
||||
slug = hashlib.sha256(slug).hexdigest()
|
||||
@@ -81,9 +80,9 @@ class BadgrBackend(BadgeBackend):
|
||||
response.raise_for_status()
|
||||
except HTTPError:
|
||||
LOGGER.error(
|
||||
u"Encountered an error when contacting the Badgr-Server. Request sent to %r with headers %r.\n"
|
||||
u"and data values %r\n"
|
||||
u"Response status was %s.\n%s",
|
||||
"Encountered an error when contacting the Badgr-Server. Request sent to %r with headers %r.\n"
|
||||
"and data values %r\n"
|
||||
"Response status was %s.\n%s",
|
||||
response.request.url, response.request.headers,
|
||||
data,
|
||||
response.status_code, response.content
|
||||
@@ -100,8 +99,8 @@ class BadgrBackend(BadgeBackend):
|
||||
content_type, __ = mimetypes.guess_type(image.name)
|
||||
if not content_type:
|
||||
raise ValueError(
|
||||
u"Could not determine content-type of image! Make sure it is a properly named .png file. "
|
||||
u"Filename was: {}".format(image.name)
|
||||
"Could not determine content-type of image! Make sure it is a properly named .png file. "
|
||||
"Filename was: {}".format(image.name)
|
||||
)
|
||||
files = {'image': (image.name, image, content_type)}
|
||||
data = {
|
||||
@@ -126,7 +125,7 @@ class BadgrBackend(BadgeBackend):
|
||||
'badge_slug': assertion.badge_class.slug,
|
||||
'badge_name': assertion.badge_class.display_name,
|
||||
'issuing_component': assertion.badge_class.issuing_component,
|
||||
'course_id': six.text_type(assertion.badge_class.course_id),
|
||||
'course_id': str(assertion.badge_class.course_id),
|
||||
'enrollment_mode': assertion.badge_class.mode,
|
||||
'assertion_id': assertion.id,
|
||||
'assertion_image_url': assertion.image_url,
|
||||
@@ -162,7 +161,7 @@ class BadgrBackend(BadgeBackend):
|
||||
"""
|
||||
Headers to send along with the request-- used for authentication.
|
||||
"""
|
||||
return {'Authorization': u'Token {}'.format(settings.BADGR_API_TOKEN)}
|
||||
return {'Authorization': f'Token {settings.BADGR_API_TOKEN}'}
|
||||
|
||||
def _ensure_badge_created(self, badge_class):
|
||||
"""
|
||||
|
||||
@@ -5,10 +5,8 @@ Base class for badge backends.
|
||||
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
import six
|
||||
|
||||
|
||||
class BadgeBackend(six.with_metaclass(ABCMeta, object)):
|
||||
class BadgeBackend(metaclass=ABCMeta):
|
||||
"""
|
||||
Defines the interface for badging backends.
|
||||
"""
|
||||
|
||||
@@ -4,22 +4,21 @@ Tests for BadgrBackend
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from unittest.mock import Mock, call, patch
|
||||
|
||||
import ddt # lint-amnesty, pylint: disable=import-error
|
||||
import six
|
||||
import ddt
|
||||
from django.db.models.fields.files import ImageFieldFile
|
||||
from django.test.utils import override_settings
|
||||
from lazy.lazy import lazy # lint-amnesty, pylint: disable=import-error, no-name-in-module
|
||||
from mock import Mock, call, patch # lint-amnesty, pylint: disable=import-error
|
||||
from lazy.lazy import lazy # lint-amnesty, pylint: disable=no-name-in-module
|
||||
|
||||
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
|
||||
from common.djangoapps.track.tests import EventTrackingTestCase
|
||||
from lms.djangoapps.badges.backends.badgr import BadgrBackend
|
||||
from lms.djangoapps.badges.models import BadgeAssertion
|
||||
from lms.djangoapps.badges.tests.factories import BadgeClassFactory
|
||||
from openedx.core.lib.tests.assertions.events import assert_event_matches
|
||||
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
|
||||
from common.djangoapps.track.tests import EventTrackingTestCase
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase # lint-amnesty, pylint: disable=import-error, wrong-import-order
|
||||
from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=import-error, wrong-import-order
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
|
||||
BADGR_SETTINGS = {
|
||||
'BADGR_API_TOKEN': '12345',
|
||||
@@ -43,7 +42,7 @@ class BadgrBackendTestCase(ModuleStoreTestCase, EventTrackingTestCase):
|
||||
"""
|
||||
Create a course and user to test with.
|
||||
"""
|
||||
super(BadgrBackendTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
# Need key to be deterministic to test slugs.
|
||||
self.course = CourseFactory.create(
|
||||
org='edX', course='course_test', run='test_run', display_name='Badged',
|
||||
@@ -182,7 +181,7 @@ class BadgrBackendTestCase(ModuleStoreTestCase, EventTrackingTestCase):
|
||||
'name': 'edx.badge.assertion.created',
|
||||
'data': {
|
||||
'user_id': self.user.id,
|
||||
'course_id': six.text_type(self.course.location.course_key),
|
||||
'course_id': str(self.course.location.course_key),
|
||||
'enrollment_mode': 'honor',
|
||||
'assertion_id': assertion.id,
|
||||
'badge_name': 'Test Badge',
|
||||
|
||||
@@ -6,16 +6,13 @@ Helper functions for the course complete event that was originally included with
|
||||
import hashlib
|
||||
import logging
|
||||
|
||||
import six
|
||||
|
||||
from django.urls import reverse
|
||||
from django.utils.text import slugify
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from lms.djangoapps.badges.models import BadgeAssertion, BadgeClass, CourseCompleteImageConfiguration
|
||||
from lms.djangoapps.badges.utils import requires_badges_enabled, site_prefix
|
||||
from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=import-error, wrong-import-order
|
||||
|
||||
from xmodule.modulestore.django import modulestore
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -35,9 +32,9 @@ def course_slug(course_key, mode):
|
||||
"""
|
||||
# Seven digits should be enough to realistically avoid collisions. That's what git services use.
|
||||
digest = hashlib.sha256(
|
||||
u"{}{}".format(six.text_type(course_key), six.text_type(mode)).encode('utf-8')
|
||||
"{}{}".format(str(course_key), str(mode)).encode('utf-8')
|
||||
).hexdigest()[:7]
|
||||
base_slug = slugify(six.text_type(course_key) + u'_{}_'.format(mode))[:248]
|
||||
base_slug = slugify(str(course_key) + f'_{mode}_')[:248]
|
||||
return base_slug + digest
|
||||
|
||||
|
||||
@@ -46,14 +43,14 @@ def badge_description(course, mode):
|
||||
Returns a description for the earned badge.
|
||||
"""
|
||||
if course.end:
|
||||
return _(u'Completed the course "{course_name}" ({course_mode}, {start_date} - {end_date})').format(
|
||||
return _('Completed the course "{course_name}" ({course_mode}, {start_date} - {end_date})').format(
|
||||
start_date=course.start.date(),
|
||||
end_date=course.end.date(),
|
||||
course_name=course.display_name,
|
||||
course_mode=mode,
|
||||
)
|
||||
else:
|
||||
return _(u'Completed the course "{course_name}" ({course_mode})').format(
|
||||
return _('Completed the course "{course_name}" ({course_mode})').format(
|
||||
course_name=course.display_name,
|
||||
course_mode=mode,
|
||||
)
|
||||
@@ -64,7 +61,7 @@ def evidence_url(user_id, course_key):
|
||||
Generates a URL to the user's Certificate HTML view, along with a GET variable that will signal the evidence visit
|
||||
event.
|
||||
"""
|
||||
course_id = six.text_type(course_key)
|
||||
course_id = str(course_key)
|
||||
# avoid circular import problems
|
||||
from lms.djangoapps.certificates.models import GeneratedCertificate
|
||||
cert = GeneratedCertificate.eligible_certificates.get(user__id=int(user_id), course_id=course_id)
|
||||
@@ -76,8 +73,8 @@ def criteria(course_key):
|
||||
"""
|
||||
Constructs the 'criteria' URL from the course about page.
|
||||
"""
|
||||
about_path = reverse('about_course', kwargs={'course_id': six.text_type(course_key)})
|
||||
return u'{}{}'.format(site_prefix(), about_path)
|
||||
about_path = reverse('about_course', kwargs={'course_id': str(course_key)})
|
||||
return f'{site_prefix()}{about_path}'
|
||||
|
||||
|
||||
def get_completion_badge(course_id, user):
|
||||
|
||||
@@ -4,11 +4,11 @@ Tests for the course completion helper functions.
|
||||
from datetime import datetime
|
||||
from uuid import uuid4
|
||||
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
from lms.djangoapps.badges.events import course_complete
|
||||
from lms.djangoapps.certificates.models import GeneratedCertificate
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase # lint-amnesty, pylint: disable=import-error, wrong-import-order
|
||||
from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=import-error, wrong-import-order
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
|
||||
|
||||
class CourseCompleteTestCase(ModuleStoreTestCase):
|
||||
@@ -17,7 +17,7 @@ class CourseCompleteTestCase(ModuleStoreTestCase):
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(CourseCompleteTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
# Need key to be deterministic to test slugs.
|
||||
self.course = CourseFactory.create(
|
||||
org='edX', course='course_test', run='test_run', display_name='Badged',
|
||||
|
||||
@@ -3,19 +3,18 @@ Tests the course meta badging events
|
||||
"""
|
||||
|
||||
|
||||
import six
|
||||
from six.moves import range, zip
|
||||
from ddt import data, ddt, unpack # lint-amnesty, pylint: disable=import-error
|
||||
from unittest.mock import patch
|
||||
|
||||
from ddt import data, ddt, unpack
|
||||
from django.conf import settings
|
||||
from django.test.utils import override_settings
|
||||
from mock import patch # lint-amnesty, pylint: disable=import-error
|
||||
|
||||
from lms.djangoapps.badges.tests.factories import CourseEventBadgesConfigurationFactory, RandomBadgeClassFactory
|
||||
from lms.djangoapps.certificates.models import CertificateStatuses, GeneratedCertificate
|
||||
from common.djangoapps.student.models import CourseEnrollment
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase # lint-amnesty, pylint: disable=import-error, wrong-import-order
|
||||
from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=import-error, wrong-import-order
|
||||
from lms.djangoapps.badges.tests.factories import CourseEventBadgesConfigurationFactory, RandomBadgeClassFactory
|
||||
from lms.djangoapps.certificates.models import CertificateStatuses, GeneratedCertificate
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
|
||||
|
||||
@ddt
|
||||
@@ -27,7 +26,7 @@ class CourseEnrollmentBadgeTest(ModuleStoreTestCase):
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(CourseEnrollmentBadgeTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.badge_classes = [
|
||||
RandomBadgeClassFactory(
|
||||
issuing_component='openedx__course'
|
||||
@@ -77,7 +76,7 @@ class CourseCompletionBadgeTest(ModuleStoreTestCase):
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(CourseCompletionBadgeTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.badge_classes = [
|
||||
RandomBadgeClassFactory(
|
||||
issuing_component='openedx__course'
|
||||
@@ -131,7 +130,7 @@ class CourseGroupBadgeTest(ModuleStoreTestCase):
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(CourseGroupBadgeTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.badge_classes = [
|
||||
RandomBadgeClassFactory(
|
||||
issuing_component='openedx__course'
|
||||
@@ -145,8 +144,8 @@ class CourseGroupBadgeTest(ModuleStoreTestCase):
|
||||
]
|
||||
self.courses = []
|
||||
for _badge_class in self.badge_classes:
|
||||
self.courses.append([CourseFactory().location.course_key for _i in range(3)])
|
||||
lines = [badge_class.slug + ',' + ','.join([six.text_type(course_key) for course_key in keys])
|
||||
self.courses.append([CourseFactory().location.course_key for _i in range(3)]) # lint-amnesty, pylint: disable=no-member
|
||||
lines = [badge_class.slug + ',' + ','.join([str(course_key) for course_key in keys])
|
||||
for badge_class, keys in zip(self.badge_classes, self.courses)]
|
||||
config = '\r'.join(lines)
|
||||
self.config = CourseEventBadgesConfigurationFactory(course_groups=config)
|
||||
|
||||
@@ -5,10 +5,10 @@ Badges related signal handlers.
|
||||
|
||||
from django.dispatch import receiver
|
||||
|
||||
from lms.djangoapps.badges.events.course_meta import award_enrollment_badge
|
||||
from lms.djangoapps.badges.utils import badges_enabled
|
||||
from common.djangoapps.student.models import EnrollStatusChange
|
||||
from common.djangoapps.student.signals import ENROLL_STATUS_CHANGE
|
||||
from lms.djangoapps.badges.events.course_meta import award_enrollment_badge
|
||||
from lms.djangoapps.badges.utils import badges_enabled
|
||||
|
||||
|
||||
@receiver(ENROLL_STATUS_CHANGE)
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
import django.utils.timezone
|
||||
import jsonfield.fields
|
||||
from django.conf import settings
|
||||
@@ -35,13 +32,13 @@ class Migration(migrations.Migration):
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('slug', models.SlugField(max_length=255, validators=[badges_models.validate_lowercase])),
|
||||
('issuing_component', models.SlugField(default=u'', blank=True, validators=[badges_models.validate_lowercase])),
|
||||
('issuing_component', models.SlugField(default='', blank=True, validators=[badges_models.validate_lowercase])),
|
||||
('display_name', models.CharField(max_length=255)),
|
||||
('course_id', CourseKeyField(default=None, max_length=255, blank=True)),
|
||||
('description', models.TextField()),
|
||||
('criteria', models.TextField()),
|
||||
('mode', models.CharField(default=u'', max_length=100, blank=True)),
|
||||
('image', models.ImageField(upload_to=u'badge_classes', validators=[badges_models.validate_badge_image])),
|
||||
('mode', models.CharField(default='', max_length=100, blank=True)),
|
||||
('image', models.ImageField(upload_to='badge_classes', validators=[badges_models.validate_badge_image])),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
@@ -49,13 +46,13 @@ class Migration(migrations.Migration):
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('mode', models.CharField(help_text='The course mode for this badge image. For example, "verified" or "honor".', unique=True, max_length=125)),
|
||||
('icon', models.ImageField(help_text='Badge images must be square PNG files. The file size should be under 250KB.', upload_to=u'course_complete_badges', validators=[badges_models.validate_badge_image])),
|
||||
('icon', models.ImageField(help_text='Badge images must be square PNG files. The file size should be under 250KB.', upload_to='course_complete_badges', validators=[badges_models.validate_badge_image])),
|
||||
('default', models.BooleanField(default=False, help_text='Set this value to True if you want this image to be the default image for any course modes that do not have a specified badge image. You can have only one default image.')),
|
||||
],
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='badgeclass',
|
||||
unique_together=set([('slug', 'issuing_component', 'course_id')]),
|
||||
unique_together={('slug', 'issuing_component', 'course_id')},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='badgeassertion',
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
@@ -45,7 +42,7 @@ def forwards(apps, schema_editor):
|
||||
badge_class.image.name = icon.name
|
||||
badge_class.save()
|
||||
classes[(badge.course_id, badge.mode)] = badge_class
|
||||
if isinstance(badge.data, six.string_types):
|
||||
if isinstance(badge.data, str):
|
||||
data = badge.data
|
||||
else:
|
||||
data = json.dumps(badge.data)
|
||||
@@ -83,7 +80,7 @@ def backwards(apps, schema_editor):
|
||||
if not badge.badge_class.mode:
|
||||
# Can't preserve old badges without modes.
|
||||
continue
|
||||
if isinstance(badge.data, six.string_types):
|
||||
if isinstance(badge.data, str):
|
||||
data = badge.data
|
||||
else:
|
||||
data = json.dumps(badge.data)
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
@@ -20,9 +17,9 @@ class Migration(migrations.Migration):
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('change_date', models.DateTimeField(auto_now_add=True, verbose_name='Change date')),
|
||||
('enabled', models.BooleanField(default=False, verbose_name='Enabled')),
|
||||
('courses_completed', models.TextField(default=u'', help_text="On each line, put the number of completed courses to award a badge for, a comma, and the slug of a badge class you have created that has the issuing component 'openedx__course'. For example: 3,enrolled_3_courses", blank=True)),
|
||||
('courses_enrolled', models.TextField(default=u'', help_text="On each line, put the number of enrolled courses to award a badge for, a comma, and the slug of a badge class you have created that has the issuing component 'openedx__course'. For example: 3,enrolled_3_courses", blank=True)),
|
||||
('course_groups', models.TextField(default=u'', help_text="Each line is a comma-separated list. The first item in each line is the slug of a badge class you have created that has an issuing component of 'openedx__course'. The remaining items in each line are the course keys the learner needs to complete to be awarded the badge. For example: slug_for_compsci_courses_group_badge,course-v1:CompSci+Course+First,course-v1:CompsSci+Course+Second", blank=True)),
|
||||
('courses_completed', models.TextField(default='', help_text="On each line, put the number of completed courses to award a badge for, a comma, and the slug of a badge class you have created that has the issuing component 'openedx__course'. For example: 3,enrolled_3_courses", blank=True)),
|
||||
('courses_enrolled', models.TextField(default='', help_text="On each line, put the number of enrolled courses to award a badge for, a comma, and the slug of a badge class you have created that has the issuing component 'openedx__course'. For example: 3,enrolled_3_courses", blank=True)),
|
||||
('course_groups', models.TextField(default='', help_text="Each line is a comma-separated list. The first item in each line is the slug of a badge class you have created that has an issuing component of 'openedx__course'. The remaining items in each line are the course keys the learner needs to complete to be awarded the badge. For example: slug_for_compsci_courses_group_badge,course-v1:CompSci+Course+First,course-v1:CompsSci+Course+Second", blank=True)),
|
||||
('changed_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, editable=False, to=settings.AUTH_USER_MODEL, null=True, verbose_name='Changed by')),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -5,24 +5,23 @@ Database models for the badges app
|
||||
|
||||
from importlib import import_module
|
||||
|
||||
import six
|
||||
from config_models.models import ConfigurationModel # lint-amnesty, pylint: disable=import-error
|
||||
from config_models.models import ConfigurationModel
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
from django.utils.encoding import python_2_unicode_compatible # lint-amnesty, pylint: disable=no-name-in-module
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from jsonfield import JSONField # lint-amnesty, pylint: disable=import-error
|
||||
from jsonfield import JSONField
|
||||
from lazy import lazy # lint-amnesty, pylint: disable=no-name-in-module
|
||||
from model_utils.models import TimeStampedModel # lint-amnesty, pylint: disable=import-error
|
||||
from opaque_keys import InvalidKeyError # lint-amnesty, pylint: disable=import-error
|
||||
from opaque_keys.edx.django.models import CourseKeyField # lint-amnesty, pylint: disable=import-error
|
||||
from opaque_keys.edx.keys import CourseKey # lint-amnesty, pylint: disable=import-error
|
||||
from model_utils.models import TimeStampedModel
|
||||
from opaque_keys import InvalidKeyError
|
||||
from opaque_keys.edx.django.models import CourseKeyField
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
|
||||
from lms.djangoapps.badges.utils import deserialize_count_specs
|
||||
from openedx.core.djangolib.markup import HTML, Text
|
||||
from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=import-error, wrong-import-order
|
||||
from xmodule.modulestore.django import modulestore
|
||||
|
||||
|
||||
def validate_badge_image(image):
|
||||
@@ -30,9 +29,9 @@ def validate_badge_image(image):
|
||||
Validates that a particular image is small enough to be a badge and square.
|
||||
"""
|
||||
if image.width != image.height:
|
||||
raise ValidationError(_(u"The badge image must be square."))
|
||||
raise ValidationError(_("The badge image must be square."))
|
||||
if not image.size < (250 * 1024):
|
||||
raise ValidationError(_(u"The badge image file size must be less than 250KB."))
|
||||
raise ValidationError(_("The badge image file size must be less than 250KB."))
|
||||
|
||||
|
||||
def validate_lowercase(string):
|
||||
@@ -40,7 +39,7 @@ def validate_lowercase(string):
|
||||
Validates that a string is lowercase.
|
||||
"""
|
||||
if not string.islower():
|
||||
raise ValidationError(_(u"This value must be all lowercase."))
|
||||
raise ValidationError(_("This value must be all lowercase."))
|
||||
|
||||
|
||||
class CourseBadgesDisabledError(Exception):
|
||||
@@ -57,17 +56,17 @@ class BadgeClass(models.Model):
|
||||
.. no_pii:
|
||||
"""
|
||||
slug = models.SlugField(max_length=255, validators=[validate_lowercase])
|
||||
issuing_component = models.SlugField(max_length=50, default=u'', blank=True, validators=[validate_lowercase])
|
||||
issuing_component = models.SlugField(max_length=50, default='', blank=True, validators=[validate_lowercase])
|
||||
display_name = models.CharField(max_length=255)
|
||||
course_id = CourseKeyField(max_length=255, blank=True, default=None)
|
||||
description = models.TextField()
|
||||
criteria = models.TextField()
|
||||
# Mode a badge was awarded for. Included for legacy/migration purposes.
|
||||
mode = models.CharField(max_length=100, default=u'', blank=True)
|
||||
image = models.ImageField(upload_to=u'badge_classes', validators=[validate_badge_image])
|
||||
mode = models.CharField(max_length=100, default='', blank=True)
|
||||
image = models.ImageField(upload_to='badge_classes', validators=[validate_badge_image])
|
||||
|
||||
def __str__(self): # lint-amnesty, pylint: disable=invalid-str-returned
|
||||
return HTML(u"<Badge '{slug}' for '{issuing_component}'>").format(
|
||||
return HTML("<Badge '{slug}' for '{issuing_component}'>").format(
|
||||
slug=HTML(self.slug), issuing_component=HTML(self.issuing_component)
|
||||
)
|
||||
|
||||
@@ -138,9 +137,9 @@ class BadgeClass(models.Model):
|
||||
"""
|
||||
self.slug = self.slug and self.slug.lower()
|
||||
self.issuing_component = self.issuing_component and self.issuing_component.lower()
|
||||
super(BadgeClass, self).save(**kwargs) # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().save(**kwargs)
|
||||
|
||||
class Meta(object):
|
||||
class Meta:
|
||||
app_label = "badges"
|
||||
unique_together = (('slug', 'issuing_component', 'course_id'),)
|
||||
verbose_name_plural = "Badge Classes"
|
||||
@@ -161,7 +160,7 @@ class BadgeAssertion(TimeStampedModel):
|
||||
assertion_url = models.URLField()
|
||||
|
||||
def __str__(self): # lint-amnesty, pylint: disable=invalid-str-returned
|
||||
return HTML(u"<{username} Badge Assertion for {slug} for {issuing_component}").format(
|
||||
return HTML("<{username} Badge Assertion for {slug} for {issuing_component}").format(
|
||||
username=HTML(self.user.username),
|
||||
slug=HTML(self.badge_class.slug),
|
||||
issuing_component=HTML(self.badge_class.issuing_component),
|
||||
@@ -176,7 +175,7 @@ class BadgeAssertion(TimeStampedModel):
|
||||
return cls.objects.filter(user=user, badge_class__course_id=course_id)
|
||||
return cls.objects.filter(user=user)
|
||||
|
||||
class Meta(object):
|
||||
class Meta:
|
||||
app_label = "badges"
|
||||
|
||||
|
||||
@@ -193,29 +192,29 @@ class CourseCompleteImageConfiguration(models.Model):
|
||||
"""
|
||||
mode = models.CharField(
|
||||
max_length=125,
|
||||
help_text=_(u'The course mode for this badge image. For example, "verified" or "honor".'),
|
||||
help_text=_('The course mode for this badge image. For example, "verified" or "honor".'),
|
||||
unique=True,
|
||||
)
|
||||
icon = models.ImageField(
|
||||
# Actual max is 256KB, but need overhead for badge baking. This should be more than enough.
|
||||
help_text=_(
|
||||
u"Badge images must be square PNG files. The file size should be under 250KB."
|
||||
"Badge images must be square PNG files. The file size should be under 250KB."
|
||||
),
|
||||
upload_to=u'course_complete_badges',
|
||||
upload_to='course_complete_badges',
|
||||
validators=[validate_badge_image]
|
||||
)
|
||||
default = models.BooleanField(
|
||||
help_text=_(
|
||||
u"Set this value to True if you want this image to be the default image for any course modes "
|
||||
u"that do not have a specified badge image. You can have only one default image."
|
||||
"Set this value to True if you want this image to be the default image for any course modes "
|
||||
"that do not have a specified badge image. You can have only one default image."
|
||||
),
|
||||
default=False,
|
||||
)
|
||||
|
||||
def __str__(self): # lint-amnesty, pylint: disable=invalid-str-returned
|
||||
return HTML(u"<CourseCompleteImageConfiguration for '{mode}'{default}>").format(
|
||||
return HTML("<CourseCompleteImageConfiguration for '{mode}'{default}>").format(
|
||||
mode=HTML(self.mode),
|
||||
default=HTML(u" (default)") if self.default else HTML(u'')
|
||||
default=HTML(" (default)") if self.default else HTML('')
|
||||
)
|
||||
|
||||
def clean(self):
|
||||
@@ -223,7 +222,7 @@ class CourseCompleteImageConfiguration(models.Model):
|
||||
Make sure there's not more than one default.
|
||||
"""
|
||||
if self.default and CourseCompleteImageConfiguration.objects.filter(default=True).exclude(id=self.id):
|
||||
raise ValidationError(_(u"There can be only one default image."))
|
||||
raise ValidationError(_("There can be only one default image."))
|
||||
|
||||
@classmethod
|
||||
def image_for_mode(cls, mode):
|
||||
@@ -236,7 +235,7 @@ class CourseCompleteImageConfiguration(models.Model):
|
||||
# Fall back to default, if there is one.
|
||||
return cls.objects.get(default=True).icon
|
||||
|
||||
class Meta(object):
|
||||
class Meta:
|
||||
app_label = "badges"
|
||||
|
||||
|
||||
@@ -249,34 +248,34 @@ class CourseEventBadgesConfiguration(ConfigurationModel):
|
||||
.. no_pii:
|
||||
"""
|
||||
courses_completed = models.TextField(
|
||||
blank=True, default=u'',
|
||||
blank=True, default='',
|
||||
help_text=_(
|
||||
u"On each line, put the number of completed courses to award a badge for, a comma, and the slug of a "
|
||||
u"badge class you have created that has the issuing component 'openedx__course'. "
|
||||
u"For example: 3,enrolled_3_courses"
|
||||
"On each line, put the number of completed courses to award a badge for, a comma, and the slug of a "
|
||||
"badge class you have created that has the issuing component 'openedx__course'. "
|
||||
"For example: 3,enrolled_3_courses"
|
||||
)
|
||||
)
|
||||
courses_enrolled = models.TextField(
|
||||
blank=True, default=u'',
|
||||
blank=True, default='',
|
||||
help_text=_(
|
||||
u"On each line, put the number of enrolled courses to award a badge for, a comma, and the slug of a "
|
||||
u"badge class you have created that has the issuing component 'openedx__course'. "
|
||||
u"For example: 3,enrolled_3_courses"
|
||||
"On each line, put the number of enrolled courses to award a badge for, a comma, and the slug of a "
|
||||
"badge class you have created that has the issuing component 'openedx__course'. "
|
||||
"For example: 3,enrolled_3_courses"
|
||||
)
|
||||
)
|
||||
course_groups = models.TextField(
|
||||
blank=True, default=u'',
|
||||
blank=True, default='',
|
||||
help_text=_(
|
||||
u"Each line is a comma-separated list. The first item in each line is the slug of a badge class you "
|
||||
u"have created that has an issuing component of 'openedx__course'. The remaining items in each line are "
|
||||
u"the course keys the learner needs to complete to be awarded the badge. For example: "
|
||||
u"slug_for_compsci_courses_group_badge,course-v1:CompSci+Course+First,course-v1:CompsSci+Course+Second"
|
||||
"Each line is a comma-separated list. The first item in each line is the slug of a badge class you "
|
||||
"have created that has an issuing component of 'openedx__course'. The remaining items in each line are "
|
||||
"the course keys the learner needs to complete to be awarded the badge. For example: "
|
||||
"slug_for_compsci_courses_group_badge,course-v1:CompSci+Course+First,course-v1:CompsSci+Course+Second"
|
||||
)
|
||||
)
|
||||
|
||||
def __str__(self): # lint-amnesty, pylint: disable=invalid-str-returned
|
||||
return HTML(u"<CourseEventBadgesConfiguration ({})>").format(
|
||||
Text(u"Enabled") if self.enabled else Text(u"Disabled")
|
||||
return HTML("<CourseEventBadgesConfiguration ({})>").format(
|
||||
Text("Enabled") if self.enabled else Text("Disabled")
|
||||
)
|
||||
|
||||
@property
|
||||
@@ -314,28 +313,28 @@ class CourseEventBadgesConfiguration(ConfigurationModel):
|
||||
Verify the settings are parseable.
|
||||
"""
|
||||
errors = {}
|
||||
error_message = _(u"Please check the syntax of your entry.")
|
||||
error_message = _("Please check the syntax of your entry.")
|
||||
if 'courses_completed' not in exclude:
|
||||
try:
|
||||
self.completed_settings
|
||||
except (ValueError, InvalidKeyError):
|
||||
errors['courses_completed'] = [six.text_type(error_message)]
|
||||
errors['courses_completed'] = [str(error_message)]
|
||||
if 'courses_enrolled' not in exclude:
|
||||
try:
|
||||
self.enrolled_settings
|
||||
except (ValueError, InvalidKeyError):
|
||||
errors['courses_enrolled'] = [six.text_type(error_message)]
|
||||
errors['courses_enrolled'] = [str(error_message)]
|
||||
if 'course_groups' not in exclude:
|
||||
store = modulestore()
|
||||
try:
|
||||
for key_list in self.course_group_settings.values():
|
||||
for course_key in key_list:
|
||||
if not store.get_course(course_key):
|
||||
ValueError(u"The course {course_key} does not exist.".format(course_key=course_key))
|
||||
ValueError(f"The course {course_key} does not exist.")
|
||||
except (ValueError, InvalidKeyError):
|
||||
errors['course_groups'] = [six.text_type(error_message)]
|
||||
errors['course_groups'] = [str(error_message)]
|
||||
if errors:
|
||||
raise ValidationError(errors)
|
||||
|
||||
class Meta(object):
|
||||
class Meta:
|
||||
app_label = "badges"
|
||||
|
||||
@@ -6,7 +6,7 @@ Badging service for XBlocks
|
||||
from lms.djangoapps.badges.models import BadgeClass
|
||||
|
||||
|
||||
class BadgingService(object):
|
||||
class BadgingService:
|
||||
"""
|
||||
A class that provides functions for managing badges which XBlocks can use.
|
||||
|
||||
|
||||
@@ -5,13 +5,18 @@ Factories for Badge tests
|
||||
|
||||
from random import random
|
||||
|
||||
import factory # lint-amnesty, pylint: disable=import-error
|
||||
import factory
|
||||
from django.core.files.base import ContentFile
|
||||
from factory import DjangoModelFactory # lint-amnesty, pylint: disable=import-error
|
||||
from factory.django import ImageField # lint-amnesty, pylint: disable=import-error
|
||||
from factory import DjangoModelFactory
|
||||
from factory.django import ImageField
|
||||
|
||||
from lms.djangoapps.badges.models import BadgeAssertion, BadgeClass, CourseCompleteImageConfiguration, CourseEventBadgesConfiguration # lint-amnesty, pylint: disable=line-too-long
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
from lms.djangoapps.badges.models import ( # lint-amnesty, pylint: disable=line-too-long
|
||||
BadgeAssertion,
|
||||
BadgeClass,
|
||||
CourseCompleteImageConfiguration,
|
||||
CourseEventBadgesConfiguration
|
||||
)
|
||||
|
||||
|
||||
def generate_dummy_image(_unused):
|
||||
@@ -29,7 +34,7 @@ class CourseCompleteImageConfigurationFactory(DjangoModelFactory):
|
||||
"""
|
||||
Factory for BadgeImageConfigurations
|
||||
"""
|
||||
class Meta(object):
|
||||
class Meta:
|
||||
model = CourseCompleteImageConfiguration
|
||||
|
||||
mode = 'honor'
|
||||
@@ -40,7 +45,7 @@ class BadgeClassFactory(DjangoModelFactory):
|
||||
"""
|
||||
Factory for BadgeClass
|
||||
"""
|
||||
class Meta(object):
|
||||
class Meta:
|
||||
model = BadgeClass
|
||||
|
||||
slug = 'test_slug'
|
||||
@@ -63,7 +68,7 @@ class BadgeAssertionFactory(DjangoModelFactory):
|
||||
"""
|
||||
Factory for BadgeAssertions
|
||||
"""
|
||||
class Meta(object):
|
||||
class Meta:
|
||||
model = BadgeAssertion
|
||||
|
||||
user = factory.SubFactory(UserFactory)
|
||||
@@ -77,7 +82,7 @@ class CourseEventBadgesConfigurationFactory(DjangoModelFactory):
|
||||
"""
|
||||
Factory for CourseEventsBadgesConfiguration
|
||||
"""
|
||||
class Meta(object):
|
||||
class Meta:
|
||||
model = CourseEventBadgesConfiguration
|
||||
|
||||
enabled = True
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
Tests for the Badges app models.
|
||||
"""
|
||||
|
||||
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
import pytest
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.files.images import ImageFile
|
||||
@@ -9,10 +12,9 @@ from django.core.files.storage import default_storage
|
||||
from django.db.utils import IntegrityError
|
||||
from django.test import TestCase
|
||||
from django.test.utils import override_settings
|
||||
from mock import Mock, patch # lint-amnesty, pylint: disable=import-error
|
||||
from path import Path # lint-amnesty, pylint: disable=import-error
|
||||
from six.moves import range
|
||||
from path import Path
|
||||
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
from lms.djangoapps.badges.models import (
|
||||
BadgeAssertion,
|
||||
BadgeClass,
|
||||
@@ -22,9 +24,8 @@ from lms.djangoapps.badges.models import (
|
||||
)
|
||||
from lms.djangoapps.badges.tests.factories import BadgeAssertionFactory, BadgeClassFactory, RandomBadgeClassFactory
|
||||
from lms.djangoapps.certificates.tests.test_models import TEST_DATA_ROOT
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase # lint-amnesty, pylint: disable=import-error, wrong-import-order
|
||||
from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=import-error, wrong-import-order
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
|
||||
|
||||
def get_image(name):
|
||||
@@ -60,7 +61,7 @@ class BadgeImageConfigurationTest(TestCase):
|
||||
.full_clean)
|
||||
|
||||
|
||||
class DummyBackend(object):
|
||||
class DummyBackend:
|
||||
"""
|
||||
Dummy badge backend, used for testing.
|
||||
"""
|
||||
@@ -74,7 +75,7 @@ class BadgeClassTest(ModuleStoreTestCase):
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(BadgeClassTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.addCleanup(self.cleanup_uploads)
|
||||
|
||||
def cleanup_uploads(self):
|
||||
|
||||
@@ -10,8 +10,8 @@ def site_prefix():
|
||||
"""
|
||||
Get the prefix for the site URL-- protocol and server name.
|
||||
"""
|
||||
scheme = u"https" if settings.HTTPS == "on" else u"http"
|
||||
return u'{}://{}'.format(scheme, settings.SITE_NAME)
|
||||
scheme = "https" if settings.HTTPS == "on" else "http"
|
||||
return f'{scheme}://{settings.SITE_NAME}'
|
||||
|
||||
|
||||
def requires_badges_enabled(function):
|
||||
|
||||
Reference in New Issue
Block a user