diff --git a/lms/djangoapps/certificates/admin.py b/lms/djangoapps/certificates/admin.py index 669b5125fd..69fb1826e0 100644 --- a/lms/djangoapps/certificates/admin.py +++ b/lms/djangoapps/certificates/admin.py @@ -42,7 +42,7 @@ class CertificateTemplateForm(forms.ModelForm): choices=lang_choices, required=False ) - class Meta(object): + class Meta: model = CertificateTemplate fields = '__all__' diff --git a/lms/djangoapps/certificates/api.py b/lms/djangoapps/certificates/api.py index b275661035..c16eb68602 100644 --- a/lms/djangoapps/certificates/api.py +++ b/lms/djangoapps/certificates/api.py @@ -10,7 +10,6 @@ certificates models or any other certificates modules. import logging -import six from django.contrib.auth import get_user_model from django.db.models import Q from eventtracking import tracker @@ -18,13 +17,16 @@ from opaque_keys.edx.django.models import CourseKeyField from organizations.api import get_course_organization_id from lms.djangoapps.branding import api as branding_api -from lms.djangoapps.certificates.generation_handler import ( - is_using_certificate_allowlist as _is_using_certificate_allowlist, - is_using_certificate_allowlist_and_is_on_allowlist as _is_using_certificate_allowlist_and_is_on_allowlist, - generate_allowlist_certificate_task as _generate_allowlist_certificate_task, - generate_user_certificates as _generate_user_certificates, +from lms.djangoapps.certificates.generation_handler import \ + generate_user_certificates as _generate_user_certificates +from lms.djangoapps.certificates.generation_handler import \ + is_using_certificate_allowlist as _is_using_certificate_allowlist +from lms.djangoapps.certificates.generation_handler import \ + is_using_certificate_allowlist_and_is_on_allowlist as _is_using_certificate_allowlist_and_is_on_allowlist +from lms.djangoapps.certificates.generation_handler import \ + generate_allowlist_certificate_task as _generate_allowlist_certificate_task +from lms.djangoapps.certificates.generation_handler import \ regenerate_user_certificates as _regenerate_user_certificates -) from lms.djangoapps.certificates.models import ( CertificateGenerationConfiguration, CertificateGenerationCourseSetting, @@ -273,12 +275,12 @@ def set_cert_generation_enabled(course_key, is_enabled): cert_event_type = 'enabled' if is_enabled else 'disabled' event_name = '.'.join(['edx', 'certificate', 'generation', cert_event_type]) tracker.emit(event_name, { - 'course_id': six.text_type(course_key), + 'course_id': str(course_key), }) if is_enabled: - log.info(u"Enabled self-generated certificates for course '%s'.", six.text_type(course_key)) + log.info("Enabled self-generated certificates for course '%s'.", str(course_key)) else: - log.info(u"Disabled self-generated certificates for course '%s'.", six.text_type(course_key)) + log.info("Disabled self-generated certificates for course '%s'.", str(course_key)) def is_certificate_invalid(student, course_key): diff --git a/lms/djangoapps/certificates/apis/v0/tests/test_views.py b/lms/djangoapps/certificates/apis/v0/tests/test_views.py index 5010161f41..60dba4f698 100644 --- a/lms/djangoapps/certificates/apis/v0/tests/test_views.py +++ b/lms/djangoapps/certificates/apis/v0/tests/test_views.py @@ -3,17 +3,15 @@ Tests for the Certificate REST APIs. """ +from unittest.mock import patch + import ddt -import six from django.conf import settings from django.urls import reverse from django.utils import timezone from freezegun import freeze_time -from mock import patch from rest_framework import status from rest_framework.test import APITestCase -from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase -from xmodule.modulestore.tests.factories import CourseFactory from common.djangoapps.course_modes.models import CourseMode from common.djangoapps.student.tests.factories import UserFactory @@ -23,6 +21,8 @@ from lms.djangoapps.certificates.tests.factories import GeneratedCertificateFact from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory from openedx.core.djangoapps.user_api.tests.factories import UserPreferenceFactory from openedx.core.djangoapps.user_authn.tests.utils import JWT_AUTH_TYPES, AuthAndScopesTestMixin, AuthType +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase +from xmodule.modulestore.tests.factories import CourseFactory @ddt.ddt @@ -35,7 +35,7 @@ class CertificatesDetailRestApiTest(AuthAndScopesTestMixin, SharedModuleStoreTes @classmethod def setUpClass(cls): - super(CertificatesDetailRestApiTest, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory.create( org='edx', number='verified', @@ -86,7 +86,7 @@ class CertificatesDetailRestApiTest(AuthAndScopesTestMixin, SharedModuleStoreTes 'grade': '0.88', 'download_url': 'www.google.com', 'certificate_type': CourseMode.VERIFIED, - 'course_id': six.text_type(self.course.id), + 'course_id': str(self.course.id), 'created_date': self.now} def test_no_certificate(self): @@ -127,7 +127,7 @@ class CertificatesListRestApiTest(AuthAndScopesTestMixin, SharedModuleStoreTestC @classmethod def setUpClass(cls): - super(CertificatesListRestApiTest, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory.create( org='edx', number='verified', @@ -174,7 +174,7 @@ class CertificatesListRestApiTest(AuthAndScopesTestMixin, SharedModuleStoreTestC """ This method is required by AuthAndScopesTestMixin. """ assert response.data ==\ [{'username': self.student.username, - 'course_id': six.text_type(self.course.id), + 'course_id': str(self.course.id), 'course_display_name': self.course.display_name, 'course_organization': self.course.org, 'certificate_type': CourseMode.VERIFIED, diff --git a/lms/djangoapps/certificates/apis/v0/views.py b/lms/djangoapps/certificates/apis/v0/views.py index 4df0800993..a7192ab724 100644 --- a/lms/djangoapps/certificates/apis/v0/views.py +++ b/lms/djangoapps/certificates/apis/v0/views.py @@ -4,7 +4,6 @@ import logging import edx_api_doc_tools as apidocs -import six from django.contrib.auth import get_user_model from edx_rest_framework_extensions import permissions from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication @@ -108,7 +107,7 @@ class CertificatesDetailView(APIView): try: course_key = CourseKey.from_string(course_id) except InvalidKeyError: - log.warning(u'Course ID string "%s" is not valid', course_id) + log.warning('Course ID string "%s" is not valid', course_id) return Response( status=404, data={'error_code': 'course_id_not_valid'} @@ -132,7 +131,7 @@ class CertificatesDetailView(APIView): return Response( { "username": user_cert.get('username'), - "course_id": six.text_type(user_cert.get('course_key')), + "course_id": str(user_cert.get('course_key')), "certificate_type": user_cert.get('type'), "created_date": user_cert.get('created'), "status": user_cert.get('status'), @@ -228,7 +227,7 @@ class CertificatesListView(APIView): for user_cert in self._get_certificates_for_user(username): user_certs.append({ 'username': user_cert.get('username'), - 'course_id': six.text_type(user_cert.get('course_key')), + 'course_id': str(user_cert.get('course_key')), 'course_display_name': user_cert.get('course_display_name'), 'course_organization': user_cert.get('course_organization'), 'certificate_type': user_cert.get('type'), diff --git a/lms/djangoapps/certificates/apps.py b/lms/djangoapps/certificates/apps.py index bba697b978..50e5442c28 100644 --- a/lms/djangoapps/certificates/apps.py +++ b/lms/djangoapps/certificates/apps.py @@ -14,7 +14,7 @@ class CertificatesConfig(AppConfig): """ Application Configuration for Certificates. """ - name = u'lms.djangoapps.certificates' + name = 'lms.djangoapps.certificates' def ready(self): """ diff --git a/lms/djangoapps/certificates/generation.py b/lms/djangoapps/certificates/generation.py index 8569b591ca..0f6f391c38 100644 --- a/lms/djangoapps/certificates/generation.py +++ b/lms/djangoapps/certificates/generation.py @@ -14,15 +14,13 @@ import random from uuid import uuid4 from capa.xqueue_interface import make_hashkey -from xmodule.modulestore.django import modulestore - from common.djangoapps.student.models import CourseEnrollment, UserProfile from lms.djangoapps.certificates.models import CertificateStatuses, GeneratedCertificate from lms.djangoapps.certificates.queue import XQueueCertInterface -from lms.djangoapps.certificates.utils import emit_certificate_event -from lms.djangoapps.certificates.utils import has_html_certificates_enabled +from lms.djangoapps.certificates.utils import emit_certificate_event, has_html_certificates_enabled from lms.djangoapps.grades.api import CourseGradeFactory from lms.djangoapps.instructor.access import list_with_level +from xmodule.modulestore.django import modulestore log = logging.getLogger(__name__) diff --git a/lms/djangoapps/certificates/generation_handler.py b/lms/djangoapps/certificates/generation_handler.py index 1bb7f8d629..c42ad6024a 100644 --- a/lms/djangoapps/certificates/generation_handler.py +++ b/lms/djangoapps/certificates/generation_handler.py @@ -9,12 +9,11 @@ cannot be generated, a message is logged and no further action is taken. import logging from edx_toggles.toggles import LegacyWaffleFlagNamespace -from xmodule.modulestore.django import modulestore from common.djangoapps.student.models import CourseEnrollment from lms.djangoapps.certificates.models import ( - CertificateStatuses, CertificateInvalidation, + CertificateStatuses, CertificateWhitelist, GeneratedCertificate ) @@ -25,6 +24,7 @@ from lms.djangoapps.instructor.access import list_with_level from lms.djangoapps.verify_student.services import IDVerificationService from openedx.core.djangoapps.certificates.api import auto_certificate_generation_enabled from openedx.core.djangoapps.waffle_utils import CourseWaffleFlag +from xmodule.modulestore.django import modulestore log = logging.getLogger(__name__) @@ -52,11 +52,11 @@ def generate_allowlist_certificate_task(user, course_key): """ if not can_generate_allowlist_certificate(user, course_key): log.info( - 'Cannot generate an allowlist certificate for {user} : {course}'.format(user=user.id, course=course_key)) + f'Cannot generate an allowlist certificate for {user.id} : {course_key}') return False log.info( - 'About to create an allowlist certificate task for {user} : {course}'.format(user=user.id, course=course_key)) + f'About to create an allowlist certificate task for {user.id} : {course_key}') kwargs = { 'student': str(user.id), diff --git a/lms/djangoapps/certificates/management/commands/cert_whitelist.py b/lms/djangoapps/certificates/management/commands/cert_whitelist.py index 331719e3f6..410b11fc51 100644 --- a/lms/djangoapps/certificates/management/commands/cert_whitelist.py +++ b/lms/djangoapps/certificates/management/commands/cert_whitelist.py @@ -108,7 +108,7 @@ class Command(BaseCommand): whitelist = CertificateWhitelist.objects.filter(course_id=course) wl_users = '\n'.join( - u"{u.user.username} {u.user.email} {u.whitelist}".format(u=u) + "{u.user.username} {u.user.email} {u.whitelist}".format(u=u) for u in whitelist ) - print(u"User whitelist for course {0}:\n{1}".format(course_id, wl_users)) + print(f"User whitelist for course {course_id}:\n{wl_users}") diff --git a/lms/djangoapps/certificates/management/commands/create_fake_cert.py b/lms/djangoapps/certificates/management/commands/create_fake_cert.py index 2ce247b002..f739c85001 100644 --- a/lms/djangoapps/certificates/management/commands/create_fake_cert.py +++ b/lms/djangoapps/certificates/management/commands/create_fake_cert.py @@ -17,7 +17,6 @@ from textwrap import dedent from django.contrib.auth import get_user_model from django.core.management.base import BaseCommand from opaque_keys.edx.keys import CourseKey -from six import text_type from lms.djangoapps.certificates.models import CertificateStatuses, GeneratedCertificate @@ -104,18 +103,18 @@ class Command(BaseCommand): if created: LOGGER.info( - u"Created certificate for user %s in course %s " - u"with mode %s, status %s, " - u"and grade %s", - user.id, text_type(course_key), + "Created certificate for user %s in course %s " + "with mode %s, status %s, " + "and grade %s", + user.id, str(course_key), cert_mode, status, grade ) else: LOGGER.info( - u"Updated certificate for user %s in course %s " - u"with mode %s, status %s, " - u"and grade %s", - user.id, text_type(course_key), + "Updated certificate for user %s in course %s " + "with mode %s, status %s, " + "and grade %s", + user.id, str(course_key), cert_mode, status, grade ) diff --git a/lms/djangoapps/certificates/management/commands/fix_ungraded_certs.py b/lms/djangoapps/certificates/management/commands/fix_ungraded_certs.py index a687b39fe9..533082de6a 100644 --- a/lms/djangoapps/certificates/management/commands/fix_ungraded_certs.py +++ b/lms/djangoapps/certificates/management/commands/fix_ungraded_certs.py @@ -44,7 +44,7 @@ class Command(BaseCommand): def handle(self, *args, **options): course_id = options['course'] - log.info(u'Fetching ungraded students for %s.', course_id) + log.info('Fetching ungraded students for %s.', course_id) ungraded = GeneratedCertificate.objects.filter( course_id__exact=course_id ).filter(grade__exact='') @@ -52,7 +52,7 @@ class Command(BaseCommand): for cert in ungraded: # grade the student grade = CourseGradeFactory().read(cert.user, course) - log.info(u'grading %s - %s', cert.user, grade.percent) + log.info('grading %s - %s', cert.user, grade.percent) cert.grade = grade.percent if not options['noop']: cert.save() diff --git a/lms/djangoapps/certificates/management/commands/gen_cert_report.py b/lms/djangoapps/certificates/management/commands/gen_cert_report.py index 977a9d9535..e5ce1b8007 100644 --- a/lms/djangoapps/certificates/management/commands/gen_cert_report.py +++ b/lms/djangoapps/certificates/management/commands/gen_cert_report.py @@ -7,7 +7,6 @@ from django.contrib.auth import get_user_model from django.core.management.base import BaseCommand, CommandError from django.db.models import Count from opaque_keys.edx.keys import CourseKey -from six import text_type from lms.djangoapps.certificates.models import GeneratedCertificate @@ -59,7 +58,7 @@ class Command(BaseCommand): # find students who are active # number of enrolled students = downloadable + notpassing - print(u"Looking up certificate states for {0}".format(options['course'])) + print("Looking up certificate states for {}".format(options['course'])) enrolled_current = User.objects.filter( courseenrollment__course_id=course_id, courseenrollment__is_active=True @@ -112,15 +111,15 @@ class Command(BaseCommand): # all states we have seen far all courses status_headings = sorted( - set([status for course in cert_data for status in cert_data[course]]) # pylint: disable=consider-using-set-comprehension + {status for course in cert_data for status in cert_data[course]} # pylint: disable=consider-using-set-comprehension ) # print the heading for the report print("{:>26}".format("course ID"), end=' ') - print(' '.join(["{:>16}".format(heading) for heading in status_headings])) + print(' '.join([f"{heading:>16}" for heading in status_headings])) # print the report - print("{0:>26}".format(text_type(course_id)), end=' ') + print("{:>26}".format(str(course_id)), end=' ') for heading in status_headings: if heading in cert_data[course_id]: print("{:>16}".format(cert_data[course_id][heading]), end=' ') diff --git a/lms/djangoapps/certificates/management/commands/regenerate_user.py b/lms/djangoapps/certificates/management/commands/regenerate_user.py index 3843728edd..7708877e0b 100644 --- a/lms/djangoapps/certificates/management/commands/regenerate_user.py +++ b/lms/djangoapps/certificates/management/commands/regenerate_user.py @@ -7,12 +7,11 @@ import logging from django.contrib.auth import get_user_model from django.core.management.base import BaseCommand from opaque_keys.edx.keys import CourseKey -from six import text_type -from xmodule.modulestore.django import modulestore from lms.djangoapps.badges.events.course_complete import get_completion_badge from lms.djangoapps.badges.utils import badges_enabled from lms.djangoapps.certificates.api import regenerate_user_certificates +from xmodule.modulestore.django import modulestore LOGGER = logging.getLogger(__name__) User = get_user_model() @@ -65,11 +64,11 @@ class Command(BaseCommand): cleaned_options['username'] = '' LOGGER.info( ( - u"Starting to create tasks to regenerate certificates " - u"with arguments %s and options %s" + "Starting to create tasks to regenerate certificates " + "with arguments %s and options %s" ), - text_type(args), - text_type(cleaned_options) + str(args), + str(cleaned_options) ) # try to parse out the course from the serialized form @@ -86,8 +85,8 @@ class Command(BaseCommand): if not options['noop']: LOGGER.info( ( - u"Adding task to the XQueue to generate a certificate " - u"for student %s in course '%s'." + "Adding task to the XQueue to generate a certificate " + "for student %s in course '%s'." ), student.id, course_id @@ -99,7 +98,7 @@ class Command(BaseCommand): if badge: badge.delete() - LOGGER.info(u"Cleared badge for student %s.", student.id) + LOGGER.info("Cleared badge for student %s.", student.id) # Add the certificate request to the queue regenerate_user_certificates( @@ -111,29 +110,29 @@ class Command(BaseCommand): LOGGER.info( ( - u"Added a certificate regeneration task to the XQueue " - u"for student %s in course '%s'." + "Added a certificate regeneration task to the XQueue " + "for student %s in course '%s'." ), student.id, - text_type(course_id) + str(course_id) ) else: LOGGER.info( ( - u"Skipping certificate generation for " - u"student %s in course '%s' " - u"because the noop flag is set." + "Skipping certificate generation for " + "student %s in course '%s' " + "because the noop flag is set." ), student.id, - text_type(course_id) + str(course_id) ) LOGGER.info( ( - u"Finished regenerating certificates command for " - u"user %s and course '%s'." + "Finished regenerating certificates command for " + "user %s and course '%s'." ), student.id, - text_type(course_id) + str(course_id) ) diff --git a/lms/djangoapps/certificates/management/commands/resubmit_error_certificates.py b/lms/djangoapps/certificates/management/commands/resubmit_error_certificates.py index 4b5325de02..a39c7894fd 100644 --- a/lms/djangoapps/certificates/management/commands/resubmit_error_certificates.py +++ b/lms/djangoapps/certificates/management/commands/resubmit_error_certificates.py @@ -24,11 +24,10 @@ from textwrap import dedent from django.core.management.base import BaseCommand, CommandError from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey -from six import text_type -from xmodule.modulestore.django import modulestore from lms.djangoapps.certificates.api import generate_user_certificates from lms.djangoapps.certificates.models import CertificateStatuses, GeneratedCertificate +from xmodule.modulestore.django import modulestore LOGGER = logging.getLogger(__name__) @@ -66,7 +65,7 @@ class Command(BaseCommand): only_course_keys.append(CourseKey.from_string(course_key_str)) except InvalidKeyError as e: raise CommandError( - u'"{course_key_str}" is not a valid course key.'.format( + '"{course_key_str}" is not a valid course key.'.format( course_key_str=course_key_str ) ) from e @@ -74,12 +73,12 @@ class Command(BaseCommand): if only_course_keys: LOGGER.info( ( - u'Starting to re-submit certificates with status "error" ' - u'in these courses: %s' - ), ", ".join([text_type(key) for key in only_course_keys]) + 'Starting to re-submit certificates with status "error" ' + 'in these courses: %s' + ), ", ".join([str(key) for key in only_course_keys]) ) else: - LOGGER.info(u'Starting to re-submit certificates with status "error".') + LOGGER.info('Starting to re-submit certificates with status "error".') # Retrieve the IDs of generated certificates with # error status in the set of courses we're considering. @@ -100,19 +99,19 @@ class Command(BaseCommand): resubmit_count += 1 LOGGER.info( ( - u"Re-submitted certificate for user %s " - u"in course '%s'" + "Re-submitted certificate for user %s " + "in course '%s'" ), user.id, course_key ) else: LOGGER.error( ( - u"Could not find course for course key '%s'. " - u"Certificate for user %s will not be resubmitted." + "Could not find course for course key '%s'. " + "Certificate for user %s will not be resubmitted." ), course_key, user.id ) - LOGGER.info(u"Finished resubmitting %s certificate tasks", resubmit_count) + LOGGER.info("Finished resubmitting %s certificate tasks", resubmit_count) def _load_course_with_cache(self, course_key, course_cache): """Retrieve the course, then cache it to avoid Mongo queries. """ diff --git a/lms/djangoapps/certificates/management/commands/ungenerated_certs.py b/lms/djangoapps/certificates/management/commands/ungenerated_certs.py index ba88a308c1..0c4a899e3a 100644 --- a/lms/djangoapps/certificates/management/commands/ungenerated_certs.py +++ b/lms/djangoapps/certificates/management/commands/ungenerated_certs.py @@ -11,11 +11,10 @@ from django.contrib.auth import get_user_model from django.core.management.base import BaseCommand from opaque_keys.edx.keys import CourseKey from pytz import UTC -from six import text_type -from xmodule.modulestore.django import modulestore from lms.djangoapps.certificates.api import generate_user_certificates from lms.djangoapps.certificates.models import CertificateStatuses, certificate_status_for_student +from xmodule.modulestore.django import modulestore LOGGER = logging.getLogger(__name__) User = get_user_model() @@ -69,11 +68,11 @@ class Command(BaseCommand): def handle(self, *args, **options): LOGGER.info( ( - u"Starting to create tasks for ungenerated certificates " - u"with arguments %s and options %s" + "Starting to create tasks for ungenerated certificates " + "with arguments %s and options %s" ), - text_type(args), - text_type(options) + str(args), + str(options) ) # Will only generate a certificate if the current @@ -113,18 +112,18 @@ class Command(BaseCommand): timeleft = diff * (total - count) / status_interval hours, remainder = divmod(timeleft.seconds, 3600) minutes, _seconds = divmod(remainder, 60) - print(u"{0}/{1} completed ~{2:02}:{3:02}m remaining".format(count, total, hours, minutes)) + print(f"{count}/{total} completed ~{hours:02}:{minutes:02}m remaining") start = datetime.datetime.now(UTC) cert_status = certificate_status_for_student(student, course_key)['status'] LOGGER.info( ( - u"Student %s has certificate status '%s' " - u"in course '%s'" + "Student %s has certificate status '%s' " + "in course '%s'" ), student.id, cert_status, - text_type(course_key) + str(course_key) ) if cert_status in valid_statuses: @@ -144,29 +143,29 @@ class Command(BaseCommand): else: LOGGER.info( ( - u"Skipping certificate generation for " - u"student %s in course '%s' " - u"because the noop flag is set." + "Skipping certificate generation for " + "student %s in course '%s' " + "because the noop flag is set." ), student.id, - text_type(course_key) + str(course_key) ) else: LOGGER.info( ( - u"Skipped student %s because " - u"certificate status '%s' is not in %s" + "Skipped student %s because " + "certificate status '%s' is not in %s" ), student.id, cert_status, - text_type(valid_statuses) + str(valid_statuses) ) LOGGER.info( ( - u"Completed ungenerated certificates command " - u"for course '%s'" + "Completed ungenerated certificates command " + "for course '%s'" ), - text_type(course_key) + str(course_key) ) diff --git a/lms/djangoapps/certificates/models.py b/lms/djangoapps/certificates/models.py index fb91237e1f..da966af006 100644 --- a/lms/djangoapps/certificates/models.py +++ b/lms/djangoapps/certificates/models.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Certificates are created for a student and an offering of a course. @@ -52,7 +51,6 @@ import logging import os import uuid -import six from config_models.models import ConfigurationModel from django.apps import apps from django.conf import settings @@ -82,7 +80,7 @@ log = logging.getLogger(__name__) User = get_user_model() -class CertificateStatuses(object): +class CertificateStatuses: """ Enum for certificate statuses """ @@ -121,7 +119,7 @@ class CertificateStatuses(object): return status in cls.PASSED_STATUSES -class CertificateSocialNetworks(object): +class CertificateSocialNetworks: """ Enum for certificate social networks """ @@ -140,7 +138,7 @@ class CertificateWhitelist(models.Model): .. no_pii: """ - class Meta(object): + class Meta: app_label = "certificates" objects = NoneToEmptyManager() @@ -187,12 +185,12 @@ class CertificateWhitelist(models.Model): result.append({ 'id': item.id, 'user_id': item.user.id, - 'user_name': six.text_type(item.user.username), - 'user_email': six.text_type(item.user.email), - 'course_id': six.text_type(item.course_id), - 'created': item.created.strftime(u"%B %d, %Y"), - 'certificate_generated': certificate_generated and certificate_generated.strftime(u"%B %d, %Y"), - 'notes': six.text_type(item.notes or ''), + 'user_name': str(item.user.username), + 'user_email': str(item.user.email), + 'course_id': str(item.course_id), + 'created': item.created.strftime("%B %d, %Y"), + 'certificate_generated': certificate_generated and certificate_generated.strftime("%B %d, %Y"), + 'notes': str(item.notes or ''), }) return result @@ -284,7 +282,7 @@ class GeneratedCertificate(models.Model): grade = models.CharField(max_length=5, blank=True, default='') key = models.CharField(max_length=32, blank=True, default='') distinction = models.BooleanField(default=False) - status = models.CharField(max_length=32, default=u'unavailable') + status = models.CharField(max_length=32, default='unavailable') mode = models.CharField(max_length=32, choices=MODES, default=MODES.honor) name = models.CharField(blank=True, max_length=255) created_date = models.DateTimeField(auto_now_add=True) @@ -297,7 +295,7 @@ class GeneratedCertificate(models.Model): if 'certificates' in apps.app_configs: history = HistoricalRecords() - class Meta(object): + class Meta: unique_together = (('user', 'course_id'),) app_label = "certificates" @@ -495,11 +493,11 @@ class CertificateGenerationHistory(TimeStampedModel): else: return _("All learners") - class Meta(object): + class Meta: app_label = "certificates" def __str__(self): - return u"certificates %s by %s on %s for %s" % \ + return "certificates %s by %s on %s for %s" % \ ("regenerated" if self.is_regeneration else "generated", self.generated_by, self.created, self.course_id) @@ -522,11 +520,11 @@ class CertificateInvalidation(TimeStampedModel): if 'certificates' in apps.app_configs: history = HistoricalRecords() - class Meta(object): + class Meta: app_label = "certificates" def __str__(self): - return u"Certificate %s, invalidated by %s on %s." % \ + return "Certificate %s, invalidated by %s on %s." % \ (self.generated_certificate, self.invalidated_by, self.created) def deactivate(self): @@ -560,7 +558,7 @@ class CertificateInvalidation(TimeStampedModel): 'id': certificate_invalidation.id, 'user': certificate_invalidation.generated_certificate.user.username, 'invalidated_by': certificate_invalidation.invalidated_by.username, - u'created': certificate_invalidation.created.strftime(u"%B %d, %Y"), + 'created': certificate_invalidation.created.strftime("%B %d, %Y"), 'notes': certificate_invalidation.notes, }) return data @@ -704,7 +702,7 @@ class ExampleCertificateSet(TimeStampedModel): """ course_key = CourseKeyField(max_length=255, db_index=True) - class Meta(object): + class Meta: get_latest_by = 'created' app_label = "certificates" @@ -764,16 +762,15 @@ class ExampleCertificateSet(TimeStampedModel): """ queryset = (ExampleCertificate.objects).select_related('example_cert_set').filter(example_cert_set=self) - for cert in queryset: - yield cert + yield from queryset @staticmethod def _template_for_mode(mode_slug, course_key): """Calculate the template PDF based on the course mode. """ return ( - u"certificate-template-{key.org}-{key.course}-verified.pdf".format(key=course_key) + "certificate-template-{key.org}-{key.course}-verified.pdf".format(key=course_key) if mode_slug == 'verified' - else u"certificate-template-{key.org}-{key.course}.pdf".format(key=course_key) + else "certificate-template-{key.org}-{key.course}.pdf".format(key=course_key) ) @@ -802,25 +799,25 @@ class ExampleCertificate(TimeStampedModel): .. no_pii: """ - class Meta(object): + class Meta: app_label = "certificates" # Statuses - STATUS_STARTED = u'started' - STATUS_SUCCESS = u'success' - STATUS_ERROR = u'error' + STATUS_STARTED = 'started' + STATUS_SUCCESS = 'success' + STATUS_ERROR = 'error' # Dummy full name for the generated certificate - EXAMPLE_FULL_NAME = u'John Doë' + EXAMPLE_FULL_NAME = 'John Doë' example_cert_set = models.ForeignKey(ExampleCertificateSet, on_delete=models.CASCADE) description = models.CharField( max_length=255, help_text=_( - u"A human-readable description of the example certificate. " - u"For example, 'verified' or 'honor' to differentiate between " - u"two types of certificates." + "A human-readable description of the example certificate. " + "For example, 'verified' or 'honor' to differentiate between " + "two types of certificates." ) ) @@ -833,9 +830,9 @@ class ExampleCertificate(TimeStampedModel): db_index=True, unique=True, help_text=_( - u"A unique identifier for the example certificate. " - u"This is used when we receive a response from the queue " - u"to determine which example certificate was processed." + "A unique identifier for the example certificate. " + "This is used when we receive a response from the queue " + "to determine which example certificate was processed." ) ) @@ -844,22 +841,22 @@ class ExampleCertificate(TimeStampedModel): default=_make_uuid, db_index=True, help_text=_( - u"An access key for the example certificate. " - u"This is used when we receive a response from the queue " - u"to validate that the sender is the same entity we asked " - u"to generate the certificate." + "An access key for the example certificate. " + "This is used when we receive a response from the queue " + "to validate that the sender is the same entity we asked " + "to generate the certificate." ) ) full_name = models.CharField( max_length=255, default=EXAMPLE_FULL_NAME, - help_text=_(u"The full name that will appear on the certificate.") + help_text=_("The full name that will appear on the certificate.") ) template = models.CharField( max_length=255, - help_text=_(u"The template file to use when generating the certificate.") + help_text=_("The template file to use when generating the certificate.") ) # Outputs from certificate generation @@ -867,24 +864,24 @@ class ExampleCertificate(TimeStampedModel): max_length=255, default=STATUS_STARTED, choices=( - (STATUS_STARTED, u'Started'), - (STATUS_SUCCESS, u'Success'), - (STATUS_ERROR, u'Error') + (STATUS_STARTED, 'Started'), + (STATUS_SUCCESS, 'Success'), + (STATUS_ERROR, 'Error') ), - help_text=_(u"The status of the example certificate.") + help_text=_("The status of the example certificate.") ) error_reason = models.TextField( null=True, default=None, - help_text=_(u"The reason an error occurred during certificate generation.") + help_text=_("The reason an error occurred during certificate generation.") ) download_url = models.CharField( max_length=255, null=True, default=None, - help_text=_(u"The download URL for the generated certificate.") + help_text=_("The download URL for the generated certificate.") ) def update_status(self, status, error_reason=None, download_url=None): @@ -910,7 +907,7 @@ class ExampleCertificate(TimeStampedModel): """ if status not in [self.STATUS_SUCCESS, self.STATUS_ERROR]: - msg = u"Invalid status: must be either '{success}' or '{error}'.".format( + msg = "Invalid status: must be either '{success}' or '{error}'.".format( success=self.STATUS_SUCCESS, error=self.STATUS_ERROR ) @@ -969,30 +966,30 @@ class CertificateGenerationCourseSetting(TimeStampedModel): self_generation_enabled = models.BooleanField( default=False, help_text=( - u"Allow students to generate their own certificates for the course. " - u"Enabling this does NOT affect usage of the management command used " - u"for batch certificate generation." + "Allow students to generate their own certificates for the course. " + "Enabling this does NOT affect usage of the management command used " + "for batch certificate generation." ) ) language_specific_templates_enabled = models.BooleanField( default=False, help_text=( - u"Render translated certificates rather than using the platform's " - u"default language. Available translations are controlled by the " - u"certificate template." + "Render translated certificates rather than using the platform's " + "default language. Available translations are controlled by the " + "certificate template." ) ) include_hours_of_effort = models.NullBooleanField( default=None, help_text=( - u"Display estimated time to complete the course, which is equal to the maximum hours of effort per week " - u"times the length of the course in weeks. This attribute will only be displayed in a certificate when the " - u"attributes 'Weeks to complete' and 'Max effort' have been provided for the course run and its " - u"certificate template includes Hours of Effort." + "Display estimated time to complete the course, which is equal to the maximum hours of effort per week " + "times the length of the course in weeks. This attribute will only be displayed in a certificate when the " + "attributes 'Weeks to complete' and 'Max effort' have been provided for the course run and its " + "certificate template includes Hours of Effort." ) ) - class Meta(object): + class Meta: get_latest_by = 'created' app_label = "certificates" @@ -1088,7 +1085,7 @@ class CertificateHtmlViewConfiguration(ConfigurationModel): app_label = "certificates" configuration = models.TextField( - help_text=u"Certificate HTML View Parameters (JSON)" + help_text="Certificate HTML View Parameters (JSON)" ) def clean(self): @@ -1124,22 +1121,22 @@ class CertificateTemplate(TimeStampedModel): """ name = models.CharField( max_length=255, - help_text=_(u'Name of template.'), + help_text=_('Name of template.'), ) description = models.CharField( max_length=255, null=True, blank=True, - help_text=_(u'Description and/or admin notes.'), + help_text=_('Description and/or admin notes.'), ) template = models.TextField( - help_text=_(u'Django template HTML.'), + help_text=_('Django template HTML.'), ) organization_id = models.IntegerField( null=True, blank=True, db_index=True, - help_text=_(u'Organization of template.'), + help_text=_('Organization of template.'), ) course_key = CourseKeyField( max_length=255, @@ -1153,24 +1150,24 @@ class CertificateTemplate(TimeStampedModel): default=GeneratedCertificate.MODES.honor, null=True, blank=True, - help_text=_(u'The course mode for this template.'), + help_text=_('The course mode for this template.'), ) is_active = models.BooleanField( - help_text=_(u'On/Off switch.'), + help_text=_('On/Off switch.'), default=False, ) language = models.CharField( max_length=2, blank=True, null=True, - help_text=u'Only certificates for courses in the selected language will be rendered using this template. ' - u'Course language is determined by the first two letters of the language code.' + help_text='Only certificates for courses in the selected language will be rendered using this template. ' + 'Course language is determined by the first two letters of the language code.' ) def __str__(self): - return u'%s' % (self.name, ) + return f'{self.name}' - class Meta(object): + class Meta: get_latest_by = 'created' unique_together = (('organization_id', 'course_key', 'mode', 'language'),) app_label = "certificates" @@ -1204,18 +1201,18 @@ class CertificateTemplateAsset(TimeStampedModel): max_length=255, null=True, blank=True, - help_text=_(u'Description of the asset.'), + help_text=_('Description of the asset.'), ) asset = models.FileField( max_length=255, upload_to=template_assets_path, - help_text=_(u'Asset file. It could be an image or css file.'), + help_text=_('Asset file. It could be an image or css file.'), ) asset_slug = models.SlugField( max_length=255, unique=True, null=True, - help_text=_(u'Asset\'s unique slug. We can reference the asset in templates using this value.'), + help_text=_('Asset\'s unique slug. We can reference the asset in templates using this value.'), ) def save(self, *args, **kwargs): @@ -1229,9 +1226,9 @@ class CertificateTemplateAsset(TimeStampedModel): super().save(*args, **kwargs) def __str__(self): - return u'%s' % (self.asset.url, ) + return f'{self.asset.url}' - class Meta(object): + class Meta: get_latest_by = 'created' app_label = "certificates" diff --git a/lms/djangoapps/certificates/queue.py b/lms/djangoapps/certificates/queue.py index b51d7960f9..c1b1480198 100644 --- a/lms/djangoapps/certificates/queue.py +++ b/lms/djangoapps/certificates/queue.py @@ -7,16 +7,14 @@ import random from uuid import uuid4 import lxml.html -import six -from capa.xqueue_interface import XQueueInterface, make_hashkey, make_xheader from django.conf import settings from django.test.client import RequestFactory from django.urls import reverse from django.utils.encoding import python_2_unicode_compatible from lxml.etree import ParserError, XMLSyntaxError from requests.auth import HTTPBasicAuth -from xmodule.modulestore.django import modulestore +from capa.xqueue_interface import XQueueInterface, make_hashkey, make_xheader from common.djangoapps.course_modes.models import CourseMode from common.djangoapps.student.models import CourseEnrollment, UserProfile from lms.djangoapps.certificates.models import CertificateStatuses as status @@ -28,6 +26,7 @@ from lms.djangoapps.certificates.models import ( ) from lms.djangoapps.grades.api import CourseGradeFactory from lms.djangoapps.verify_student.services import IDVerificationService +from xmodule.modulestore.django import modulestore LOGGER = logging.getLogger(__name__) @@ -39,19 +38,19 @@ class XQueueAddToQueueError(Exception): def __init__(self, error_code, error_msg): self.error_code = error_code self.error_msg = error_msg - super().__init__(six.text_type(self)) + super().__init__(str(self)) def __str__(self): return ( - u"Could not add certificate to the XQueue. " - u"The error code was '{code}' and the message was '{msg}'." + "Could not add certificate to the XQueue. " + "The error code was '{code}' and the message was '{msg}'." ).format( code=self.error_code, msg=self.error_msg ) -class XQueueCertInterface(object): +class XQueueCertInterface: """ XQueueCertificateInterface provides an interface to the xqueue server for @@ -133,12 +132,12 @@ class XQueueCertInterface(object): LOGGER.info( ( - u"Found an existing certificate entry for student %s " - u"in course '%s' " - u"with status '%s' while regenerating certificates. " + "Found an existing certificate entry for student %s " + "in course '%s' " + "with status '%s' while regenerating certificates. " ), student.id, - six.text_type(course_id), + str(course_id), certificate.status ) @@ -153,11 +152,11 @@ class XQueueCertInterface(object): LOGGER.info( ( - u"The certificate status for student %s " - u"in course '%s' has been changed to '%s'." + "The certificate status for student %s " + "in course '%s' has been changed to '%s'." ), student.id, - six.text_type(course_id), + str(course_id), certificate.status ) @@ -225,12 +224,12 @@ class XQueueCertInterface(object): if hasattr(course_id, 'ccx'): LOGGER.warning( ( - u"Cannot create certificate generation task for user %s " - u"in the course '%s'; " - u"certificates are not allowed for CCX courses." + "Cannot create certificate generation task for user %s " + "in the course '%s'; " + "certificates are not allowed for CCX courses." ), student.id, - six.text_type(course_id) + str(course_id) ) return None @@ -260,14 +259,14 @@ class XQueueCertInterface(object): if cert_status not in valid_statuses: LOGGER.warning( ( - u"Cannot create certificate generation task for user %s " - u"in the course '%s'; " - u"the certificate status '%s' is not one of %s." + "Cannot create certificate generation task for user %s " + "in the course '%s'; " + "the certificate status '%s' is not one of %s." ), student.id, - six.text_type(course_id), + str(course_id), cert_status, - six.text_type(valid_statuses) + str(valid_statuses) ) return None @@ -318,14 +317,14 @@ class XQueueCertInterface(object): LOGGER.info( ( - u"Certificate generated for student %s in the course: %s with template: %s. " - u"given template: %s, " - u"user is verified: %s, " - u"mode is verified: %s," - u"generate_pdf is: %s" + "Certificate generated for student %s in the course: %s with template: %s. " + "given template: %s, " + "user is verified: %s, " + "mode is verified: %s," + "generate_pdf is: %s" ), student.username, - six.text_type(course_id), + str(course_id), template_pdf, template_file, user_is_verified, @@ -350,24 +349,24 @@ class XQueueCertInterface(object): except (TypeError, XMLSyntaxError, ParserError) as exc: LOGGER.info( ( - u"Could not retrieve grade for student %s " - u"in the course '%s' " - u"because an exception occurred while parsing the " - u"grade contents '%s' as HTML. " - u"The exception was: '%s'" + "Could not retrieve grade for student %s " + "in the course '%s' " + "because an exception occurred while parsing the " + "grade contents '%s' as HTML. " + "The exception was: '%s'" ), student.id, - six.text_type(course_id), + str(course_id), grade_contents, - six.text_type(exc) + str(exc) ) # Check if the student is whitelisted if is_whitelisted: LOGGER.info( - u"Student %s is whitelisted in '%s'", + "Student %s is whitelisted in '%s'", student.id, - six.text_type(course_id) + str(course_id) ) passing = True @@ -381,7 +380,7 @@ class XQueueCertInterface(object): cert.status = status.audit_passing if passing else status.audit_notpassing cert.save() LOGGER.info( - u"Student %s with enrollment mode %s is not eligible for a certificate.", + "Student %s with enrollment mode %s is not eligible for a certificate.", student.id, enrollment_mode ) @@ -393,12 +392,12 @@ class XQueueCertInterface(object): LOGGER.info( ( - u"Student %s does not have a grade for '%s', " - u"so their certificate status has been set to '%s'. " - u"No certificate generation task was sent to the XQueue." + "Student %s does not have a grade for '%s', " + "so their certificate status has been set to '%s'. " + "No certificate generation task was sent to the XQueue." ), student.id, - six.text_type(course_id), + str(course_id), cert.status ) return cert @@ -412,14 +411,14 @@ class XQueueCertInterface(object): LOGGER.info( ( - u"Student %s is in the embargoed country restricted " - u"list, so their certificate status has been set to '%s' " - u"for the course '%s'. " - u"No certificate generation task was sent to the XQueue." + "Student %s is in the embargoed country restricted " + "list, so their certificate status has been set to '%s' " + "for the course '%s'. " + "No certificate generation task was sent to the XQueue." ), student.id, cert.status, - six.text_type(course_id) + str(course_id) ) return cert @@ -428,12 +427,12 @@ class XQueueCertInterface(object): cert.save() LOGGER.info( ( - u"User %s has a verified enrollment in course %s " - u"but is missing ID verification. " - u"Certificate status has been set to unverified" + "User %s has a verified enrollment in course %s " + "but is missing ID verification. " + "Certificate status has been set to unverified" ), student.id, - six.text_type(course_id), + str(course_id), ) return cert @@ -445,7 +444,7 @@ class XQueueCertInterface(object): Generate a certificate for the student. If `generate_pdf` is True, sends a request to XQueue. """ - course_id = six.text_type(course.id) + course_id = str(course.id) key = make_hashkey(random.random()) cert.key = key @@ -465,7 +464,7 @@ class XQueueCertInterface(object): cert.verify_uuid = uuid4().hex cert.save() - logging.info(u'certificate generated for user: %s with generate_pdf status: %s', + logging.info('certificate generated for user: %s with generate_pdf status: %s', student.username, generate_pdf) if generate_pdf: @@ -473,22 +472,22 @@ class XQueueCertInterface(object): self._send_to_xqueue(contents, key) except XQueueAddToQueueError as exc: cert.status = ExampleCertificate.STATUS_ERROR - cert.error_reason = six.text_type(exc) + cert.error_reason = str(exc) cert.save() LOGGER.critical( ( - u"Could not add certificate task to XQueue. " - u"The course was '%s' and the student was '%s'." - u"The certificate task status has been marked as 'error' " - u"and can be re-submitted with a management command." + "Could not add certificate task to XQueue. " + "The course was '%s' and the student was '%s'." + "The certificate task status has been marked as 'error' " + "and can be re-submitted with a management command." ), course_id, student.id ) else: LOGGER.info( ( - u"The certificate status has been set to '%s'. " - u"Sent a certificate grading task to the XQueue " - u"with the key '%s'. " + "The certificate status has been set to '%s'. " + "Sent a certificate grading task to the XQueue " + "with the key '%s'. " ), cert.status, key @@ -512,7 +511,7 @@ class XQueueCertInterface(object): """ contents = { 'action': 'create', - 'course_id': six.text_type(example_cert.course_key), + 'course_id': str(example_cert.course_key), 'name': example_cert.full_name, 'template_pdf': example_cert.template, @@ -543,18 +542,18 @@ class XQueueCertInterface(object): task_identifier=example_cert.uuid, callback_url_path=callback_url_path ) - LOGGER.info(u"Started generating example certificates for course '%s'.", example_cert.course_key) + LOGGER.info("Started generating example certificates for course '%s'.", example_cert.course_key) except XQueueAddToQueueError as exc: example_cert.update_status( ExampleCertificate.STATUS_ERROR, - error_reason=six.text_type(exc) + error_reason=str(exc) ) LOGGER.critical( ( - u"Could not add example certificate with uuid '%s' to XQueue. " - u"The exception was %s. " - u"The example certificate has been marked with status 'error'." - ), example_cert.uuid, six.text_type(exc) + "Could not add example certificate with uuid '%s' to XQueue. " + "The exception was %s. " + "The example certificate has been marked with status 'error'." + ), example_cert.uuid, str(exc) ) def _send_to_xqueue(self, contents, key, task_identifier=None, callback_url_path='/update_certificate'): @@ -573,7 +572,7 @@ class XQueueCertInterface(object): certificates. """ - callback_url = u'{protocol}://{base_url}{path}'.format( + callback_url = '{protocol}://{base_url}{path}'.format( protocol=("https" if self.use_https else "http"), base_url=settings.SITE_NAME, path=callback_url_path @@ -604,21 +603,21 @@ class XQueueCertInterface(object): header=xheader, body=json.dumps(contents)) if error: exc = XQueueAddToQueueError(error, msg) - LOGGER.critical(six.text_type(exc)) + LOGGER.critical(str(exc)) raise exc def _log_pdf_cert_generation_discontinued_warning(self, student_id, course_id, cert_status, download_url): """Logs PDF certificate generation discontinued warning.""" LOGGER.warning( ( - u"PDF certificate generation discontinued, canceling " - u"PDF certificate generation for student %s " - u"in course '%s' " - u"with status '%s' " - u"and download_url '%s'." + "PDF certificate generation discontinued, canceling " + "PDF certificate generation for student %s " + "in course '%s' " + "with status '%s' " + "and download_url '%s'." ), student_id, - six.text_type(course_id), + str(course_id), cert_status, download_url ) diff --git a/lms/djangoapps/certificates/services.py b/lms/djangoapps/certificates/services.py index 45532b2403..cd9218963a 100644 --- a/lms/djangoapps/certificates/services.py +++ b/lms/djangoapps/certificates/services.py @@ -15,7 +15,7 @@ from lms.djangoapps.utils import _get_key log = logging.getLogger(__name__) -class CertificateService(object): +class CertificateService: """ User Certificate service """ @@ -38,13 +38,13 @@ class CertificateService(object): ) generated_certificate.invalidate() log.info( - u'Certificate invalidated for user %d in course %s', + 'Certificate invalidated for user %d in course %s', user_id, course_key ) except ObjectDoesNotExist: log.warning( - u'Invalidation failed because a certificate for user %d in course %s does not exist.', + 'Invalidation failed because a certificate for user %d in course %s does not exist.', user_id, course_key ) diff --git a/lms/djangoapps/certificates/signals.py b/lms/djangoapps/certificates/signals.py index 967ef2e0a2..b116c86f53 100644 --- a/lms/djangoapps/certificates/signals.py +++ b/lms/djangoapps/certificates/signals.py @@ -4,7 +4,6 @@ Signal handler for enabling/disabling self-generated certificates based on the c import logging -import six from django.db.models.signals import post_save from django.dispatch import receiver @@ -44,7 +43,7 @@ def _update_cert_settings_on_pacing_change(sender, updated_course_overview, **kw updated_course_overview.id, updated_course_overview.self_paced, ) - log.info(u'Certificate Generation Setting Toggled for {course_id} via pacing change'.format( + log.info('Certificate Generation Setting Toggled for {course_id} via pacing change'.format( course_id=updated_course_overview.id )) @@ -63,7 +62,7 @@ def _listen_for_certificate_whitelist_append(sender, instance, **kwargs): # pyl return if _fire_ungenerated_certificate_task(instance.user, instance.course_id): - log.info(u'Certificate generation task initiated for {user} : {course} via whitelist'.format( + log.info('Certificate generation task initiated for {user} : {course} via whitelist'.format( user=instance.user.id, course=instance.course_id )) @@ -84,7 +83,7 @@ def listen_for_passing_grade(sender, user, course_id, **kwargs): # pylint: disa return if _fire_ungenerated_certificate_task(user, course_id): - log.info(u'Certificate generation task initiated for {user} : {course} via passing grade'.format( + log.info('Certificate generation task initiated for {user} : {course} via passing grade'.format( user=user.id, course=course_id )) @@ -106,7 +105,7 @@ def _listen_for_failing_grade(sender, user, course_id, grade, **kwargs): # pyli if cert is not None: if CertificateStatuses.is_passing_status(cert.status): cert.mark_notpassing(grade.percent) - log.info(u'Certificate marked not passing for {user} : {course} via failing grade: {grade}'.format( + log.info('Certificate marked not passing for {user} : {course} via failing grade: {grade}'.format( user=user.id, course=course_id, grade=grade @@ -136,8 +135,8 @@ def _listen_for_id_verification_status_changed(sender, user, **kwargs): # pylin elif grade_factory.read(user=user, course=enrollment.course_overview).passed: if _fire_ungenerated_certificate_task(user, enrollment.course_id, expected_verification_status): message = ( - u'Certificate generation task initiated for {user} : {course} via track change ' + - u'with verification status of {status}' + 'Certificate generation task initiated for {user} : {course} via track change ' + + 'with verification status of {status}' ) log.info(message.format( user=user.id, @@ -168,7 +167,7 @@ def _fire_ungenerated_certificate_task(user, course_key, expected_verification_s traffic to workers. """ - message = u'Entered into Ungenerated Certificate task for {user} : {course}' + message = 'Entered into Ungenerated Certificate task for {user} : {course}' log.info(message.format(user=user.id, course=course_key)) allowed_enrollment_modes_list = [ @@ -188,14 +187,14 @@ def _fire_ungenerated_certificate_task(user, course_key, expected_verification_s if generate_learner_certificate: kwargs = { - 'student': six.text_type(user.id), - 'course_key': six.text_type(course_key) + 'student': str(user.id), + 'course_key': str(course_key) } if expected_verification_status: - kwargs['expected_verification_status'] = six.text_type(expected_verification_status) + kwargs['expected_verification_status'] = str(expected_verification_status) generate_certificate.apply_async(countdown=CERTIFICATE_DELAY_SECONDS, kwargs=kwargs) return True - message = u'Certificate Generation task failed for {user} : {course}' + message = 'Certificate Generation task failed for {user} : {course}' log.info(message.format(user=user.id, course=course_key)) return False diff --git a/lms/djangoapps/certificates/tasks.py b/lms/djangoapps/certificates/tasks.py index f91687f701..d9e4def184 100644 --- a/lms/djangoapps/certificates/tasks.py +++ b/lms/djangoapps/certificates/tasks.py @@ -51,9 +51,9 @@ def generate_certificate(self, **kwargs): actual_verification_status = actual_verification_status['status'] if expected_verification_status != actual_verification_status: logger.warning( - u'Expected verification status {expected} ' - u'differs from actual verification status {actual} ' - u'for user {user} in course {course}'.format( + 'Expected verification status {expected} ' + 'differs from actual verification status {actual} ' + 'for user {user} in course {course}'.format( expected=expected_verification_status, actual=actual_verification_status, user=student.id, diff --git a/lms/djangoapps/certificates/urls.py b/lms/djangoapps/certificates/urls.py index 099e251545..6e0bd8836e 100644 --- a/lms/djangoapps/certificates/urls.py +++ b/lms/djangoapps/certificates/urls.py @@ -12,13 +12,13 @@ app_name = 'certificates' urlpatterns = [ # Certificates HTML view end point to render web certs by user and course url( - r'^user/(?P[^/]*)/course/{course_id}'.format(course_id=settings.COURSE_ID_PATTERN), + fr'^user/(?P[^/]*)/course/{settings.COURSE_ID_PATTERN}', views.unsupported_url, name='unsupported_url' ), url( - r'^course/{course_id}'.format(course_id=settings.COURSE_ID_PATTERN), + fr'^course/{settings.COURSE_ID_PATTERN}', views.render_preview_certificate, name='preview_cert' ), diff --git a/lms/djangoapps/certificates/utils.py b/lms/djangoapps/certificates/utils.py index b74942abdc..a9fc06c1ac 100644 --- a/lms/djangoapps/certificates/utils.py +++ b/lms/djangoapps/certificates/utils.py @@ -4,17 +4,14 @@ Certificates utilities import logging -import six from django.conf import settings from django.urls import reverse from eventtracking import tracker from opaque_keys.edx.keys import CourseKey -from xmodule.modulestore.django import modulestore -from lms.djangoapps.certificates.models import ( - GeneratedCertificate -) +from lms.djangoapps.certificates.models import GeneratedCertificate from openedx.core.djangoapps.content.course_overviews.models import CourseOverview +from xmodule.modulestore.django import modulestore log = logging.getLogger(__name__) @@ -31,12 +28,12 @@ def emit_certificate_event(event_name, user, course_id, course=None, event_data= course = modulestore().get_course(course_id, depth=0) context = { 'org_id': course.org, - 'course_id': six.text_type(course_id) + 'course_id': str(course_id) } data = { 'user_id': user.id, - 'course_id': six.text_type(course_id), + 'course_id': str(course_id), 'certificate_url': get_certificate_url(user.id, course_id, uuid=event_data['certificate_id']) } event_data = event_data or {} @@ -93,9 +90,9 @@ def _certificate_download_url(user_id, course_id, user_certificate=None): ) except GeneratedCertificate.DoesNotExist: log.critical( - u'Unable to lookup certificate\n' - u'user id: %s\n' - u'course: %s', six.text_type(user_id), six.text_type(course_id) + 'Unable to lookup certificate\n' + 'user id: %s\n' + 'course: %s', str(user_id), str(course_id) ) if user_certificate: diff --git a/lms/djangoapps/certificates/views/support.py b/lms/djangoapps/certificates/views/support.py index 72b685e12e..9ed2623a5e 100644 --- a/lms/djangoapps/certificates/views/support.py +++ b/lms/djangoapps/certificates/views/support.py @@ -7,10 +7,10 @@ See lms/djangoapps/support for more details. import logging +import urllib from functools import wraps import bleach -import six from django.db import transaction from django.db.models import Q from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbidden, HttpResponseServerError @@ -18,7 +18,6 @@ from django.utils.translation import ugettext as _ from django.views.decorators.http import require_GET, require_POST from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey -from xmodule.modulestore.django import modulestore from common.djangoapps.student.models import CourseEnrollment, User from common.djangoapps.util.json_request import JsonResponse @@ -27,6 +26,7 @@ from lms.djangoapps.certificates.models import CertificateInvalidation from lms.djangoapps.certificates.permissions import GENERATE_ALL_CERTIFICATES, VIEW_ALL_CERTIFICATES from lms.djangoapps.instructor_task.api import generate_certificates_for_students from openedx.core.djangoapps.content.course_overviews.models import CourseOverview +from xmodule.modulestore.django import modulestore log = logging.getLogger(__name__) @@ -89,7 +89,7 @@ def search_certificates(request): ] """ - unbleached_filter = six.moves.urllib.parse.unquote(six.moves.urllib.parse.quote_plus(request.GET.get("user", ""))) + unbleached_filter = urllib.parse.unquote(urllib.parse.quote_plus(request.GET.get("user", ""))) user_filter = bleach.clean(unbleached_filter) if not user_filter: msg = _("user is not given.") @@ -98,21 +98,21 @@ def search_certificates(request): try: user = User.objects.get(Q(email=user_filter) | Q(username=user_filter)) except User.DoesNotExist: - return HttpResponseBadRequest(_(u"user '{user}' does not exist").format(user=user_filter)) + return HttpResponseBadRequest(_("user '{user}' does not exist").format(user=user_filter)) certificates = get_certificates_for_user(user.username) for cert in certificates: - cert["course_key"] = six.text_type(cert["course_key"]) + cert["course_key"] = str(cert["course_key"]) cert["created"] = cert["created"].isoformat() cert["modified"] = cert["modified"].isoformat() cert["regenerate"] = not cert['is_pdf_certificate'] - course_id = six.moves.urllib.parse.quote_plus(request.GET.get("course_id", ""), safe=':/') + course_id = urllib.parse.quote_plus(request.GET.get("course_id", ""), safe=':/') if course_id: try: course_key = CourseKey.from_string(course_id) except InvalidKeyError: - return HttpResponseBadRequest(_(u"Course id '{course_id}' is not valid").format(course_id=course_id)) + return HttpResponseBadRequest(_("Course id '{course_id}' is not valid").format(course_id=course_id)) else: try: if CourseOverview.get_from_id(course_key): @@ -121,7 +121,7 @@ def search_certificates(request): if not certificates: return JsonResponse([{'username': user.username, 'course_key': course_id, 'regenerate': False}]) except CourseOverview.DoesNotExist: - msg = _(u"The course does not exist against the given key '{course_key}'").format(course_key=course_key) + msg = _("The course does not exist against the given key '{course_key}'").format(course_key=course_key) return HttpResponseBadRequest(msg) return JsonResponse(certificates) @@ -142,14 +142,14 @@ def _validate_post_params(params): username = params.get("username") user = User.objects.get(username=username) except User.DoesNotExist: - msg = _(u"User {username} does not exist").format(username=username) + msg = _("User {username} does not exist").format(username=username) return None, HttpResponseBadRequest(msg) # Validate the course key try: course_key = CourseKey.from_string(params.get("course_key")) except InvalidKeyError: - msg = _(u"{course_key} is not a valid course key").format(course_key=params.get("course_key")) + msg = _("{course_key} is not a valid course key").format(course_key=params.get("course_key")) return None, HttpResponseBadRequest(msg) return {"user": user, "course_key": course_key}, None @@ -188,12 +188,12 @@ def regenerate_certificate_for_user(request): # Check that the course exists course = modulestore().get_course(params["course_key"]) if course is None: - msg = _(u"The course {course_key} does not exist").format(course_key=params["course_key"]) + msg = _("The course {course_key} does not exist").format(course_key=params["course_key"]) return HttpResponseBadRequest(msg) # Check that the user is enrolled in the course if not CourseEnrollment.is_enrolled(params["user"], params["course_key"]): - msg = _(u"User {username} is not enrolled in the course {course_key}").format( + msg = _("User {username} is not enrolled in the course {course_key}").format( username=params["user"].username, course_key=params["course_key"] ) @@ -207,14 +207,14 @@ def regenerate_certificate_for_user(request): # certificates API. This may be overkill, but we're logging everything so we can # track down unexpected errors. log.exception( - u"Could not regenerate certificates for user %s in course %s", + "Could not regenerate certificates for user %s in course %s", params["user"].id, params["course_key"] ) return HttpResponseServerError(_("An unexpected error occurred while regenerating certificates.")) log.info( - u"Started regenerating certificates for user %s in course %s from the support page.", + "Started regenerating certificates for user %s in course %s from the support page.", params["user"].id, params["course_key"] ) return HttpResponse(200) @@ -253,12 +253,12 @@ def generate_certificate_for_user(request): # Check that the course exists CourseOverview.get_from_id(params["course_key"]) except CourseOverview.DoesNotExist: - msg = _(u"The course {course_key} does not exist").format(course_key=params["course_key"]) + msg = _("The course {course_key} does not exist").format(course_key=params["course_key"]) return HttpResponseBadRequest(msg) else: # Check that the user is enrolled in the course if not CourseEnrollment.is_enrolled(params["user"], params["course_key"]): - msg = _(u"User {username} is not enrolled in the course {course_key}").format( + msg = _("User {username} is not enrolled in the course {course_key}").format( username=params["user"].username, course_key=params["course_key"] ) diff --git a/lms/djangoapps/certificates/views/webview.py b/lms/djangoapps/certificates/views/webview.py index ac600db9c3..037a932124 100644 --- a/lms/djangoapps/certificates/views/webview.py +++ b/lms/djangoapps/certificates/views/webview.py @@ -4,11 +4,11 @@ Certificate HTML webview. import logging +import urllib from datetime import datetime from uuid import uuid4 import pytz -import six from django.conf import settings from django.contrib.auth.decorators import login_required from django.http import Http404, HttpResponse @@ -63,27 +63,27 @@ def get_certificate_description(mode, certificate_type, platform_name): certificate_type_description = None if mode == 'honor': # Translators: This text describes the 'Honor' course certificate type. - certificate_type_description = _(u"An {cert_type} certificate signifies that a " - u"learner has agreed to abide by the honor code established by " - u"{platform_name} and has completed all of the required tasks for this course " - u"under its guidelines.").format(cert_type=certificate_type, - platform_name=platform_name) + certificate_type_description = _("An {cert_type} certificate signifies that a " + "learner has agreed to abide by the honor code established by " + "{platform_name} and has completed all of the required tasks for this course " + "under its guidelines.").format(cert_type=certificate_type, + platform_name=platform_name) elif mode == 'verified': # Translators: This text describes the 'ID Verified' course certificate type, which is a higher level of # verification offered by edX. This type of verification is useful for professional education/certifications - certificate_type_description = _(u"A {cert_type} certificate signifies that a " - u"learner has agreed to abide by the honor code established by " - u"{platform_name} and has completed all of the required tasks for this course " - u"under its guidelines. A {cert_type} certificate also indicates that the " - u"identity of the learner has been checked and " - u"is valid.").format(cert_type=certificate_type, - platform_name=platform_name) + certificate_type_description = _("A {cert_type} certificate signifies that a " + "learner has agreed to abide by the honor code established by " + "{platform_name} and has completed all of the required tasks for this course " + "under its guidelines. A {cert_type} certificate also indicates that the " + "identity of the learner has been checked and " + "is valid.").format(cert_type=certificate_type, + platform_name=platform_name) elif mode == 'xseries': # Translators: This text describes the 'XSeries' course certificate type. An XSeries is a collection of # courses related to each other in a meaningful way, such as a specific topic or theme, or even an organization - certificate_type_description = _(u"An {cert_type} certificate demonstrates a high level of " - u"achievement in a program of study, and includes verification of " - u"the student's identity.").format(cert_type=certificate_type) + certificate_type_description = _("An {cert_type} certificate demonstrates a high level of " + "achievement in a program of study, and includes verification of " + "the student's identity.").format(cert_type=certificate_type) return certificate_type_description @@ -97,7 +97,7 @@ def _update_certificate_context(context, course, user_certificate, platform_name # Override the defaults with any mode-specific static values context['certificate_id_number'] = user_certificate.verify_uuid - context['certificate_verify_url'] = u"{prefix}{uuid}{suffix}".format( + context['certificate_verify_url'] = "{prefix}{uuid}{suffix}".format( prefix=context.get('certificate_verify_url_prefix'), uuid=user_certificate.verify_uuid, suffix=context.get('certificate_verify_url_suffix') @@ -108,8 +108,8 @@ def _update_certificate_context(context, course, user_certificate, platform_name context['certificate_date_issued'] = strftime_localized(date, settings.CERTIFICATE_DATE_FORMAT) # Translators: This text represents the verification of the certificate - context['document_meta_description'] = _(u'This is a valid {platform_name} certificate for {user_name}, ' - u'who participated in {partner_short_name} {course_number}').format( + context['document_meta_description'] = _('This is a valid {platform_name} certificate for {user_name}, ' + 'who participated in {partner_short_name} {course_number}').format( platform_name=platform_name, user_name=context['accomplishment_copy_name'], partner_short_name=context['organization_short_name'], @@ -117,7 +117,7 @@ def _update_certificate_context(context, course, user_certificate, platform_name ) # Translators: This text is bound to the HTML 'title' element of the page and appears in the browser title bar - context['document_title'] = _(u"{partner_short_name} {course_number} Certificate | {platform_name}").format( + context['document_title'] = _("{partner_short_name} {course_number} Certificate | {platform_name}").format( partner_short_name=context['organization_short_name'], course_number=context['course_number'], platform_name=platform_name @@ -125,9 +125,9 @@ def _update_certificate_context(context, course, user_certificate, platform_name # Translators: This text fragment appears after the student's name (displayed in a large font) on the certificate # screen. The text describes the accomplishment represented by the certificate information displayed to the user - context['accomplishment_copy_description_full'] = _(u"successfully completed, received a passing grade, and was " - u"awarded this {platform_name} {certificate_type} " - u"Certificate of Completion in ").format( + context['accomplishment_copy_description_full'] = _("successfully completed, received a passing grade, and was " + "awarded this {platform_name} {certificate_type} " + "Certificate of Completion in ").format( platform_name=platform_name, certificate_type=context.get("certificate_type")) @@ -136,9 +136,9 @@ def _update_certificate_context(context, course, user_certificate, platform_name context['certificate_type_description'] = certificate_type_description # Translators: This text describes the purpose (and therefore, value) of a course certificate - context['certificate_info_description'] = _(u"{platform_name} acknowledges achievements through " - u"certificates, which are awarded for course activities " - u"that {platform_name} students complete.").format( + context['certificate_info_description'] = _("{platform_name} acknowledges achievements through " + "certificates, which are awarded for course activities " + "that {platform_name} students complete.").format( platform_name=platform_name, ) @@ -156,7 +156,7 @@ def _update_context_with_basic_info(context, course_id, platform_name, configura # Translators: 'All rights reserved' is a legal term used in copyrighting to protect published content reserved = _("All rights reserved") - context['copyright_text'] = u'© {year} {platform_name}. {reserved}.'.format( + context['copyright_text'] = '© {year} {platform_name}. {reserved}.'.format( year=datetime.now(pytz.timezone(settings.TIME_ZONE)).year, platform_name=platform_name, reserved=reserved @@ -175,7 +175,7 @@ def _update_context_with_basic_info(context, course_id, platform_name, configura context['logo_subtitle'] = _("Certificate Validation") # Translators: Accomplishments describe the awards/certifications obtained by students on this platform - context['accomplishment_copy_about'] = _(u'About {platform_name} Accomplishments').format( + context['accomplishment_copy_about'] = _('About {platform_name} Accomplishments').format( platform_name=platform_name ) @@ -185,39 +185,39 @@ def _update_context_with_basic_info(context, course_id, platform_name, configura # Translators: The Certificate ID Number is an alphanumeric value unique to each individual certificate context['certificate_id_number_title'] = _('Certificate ID Number') - context['certificate_info_title'] = _(u'About {platform_name} Certificates').format( + context['certificate_info_title'] = _('About {platform_name} Certificates').format( platform_name=platform_name ) - context['certificate_verify_title'] = _(u"How {platform_name} Validates Student Certificates").format( + context['certificate_verify_title'] = _("How {platform_name} Validates Student Certificates").format( platform_name=platform_name ) # Translators: This text describes the validation mechanism for a certificate file (known as GPG security) - context['certificate_verify_description'] = _(u'Certificates issued by {platform_name} are signed by a gpg key so ' - u'that they can be validated independently by anyone with the ' - u'{platform_name} public key. For independent verification, ' - u'{platform_name} uses what is called a ' - u'"detached signature""".').format(platform_name=platform_name) + context['certificate_verify_description'] = _('Certificates issued by {platform_name} are signed by a gpg key so ' + 'that they can be validated independently by anyone with the ' + '{platform_name} public key. For independent verification, ' + '{platform_name} uses what is called a ' + '"detached signature""".').format(platform_name=platform_name) context['certificate_verify_urltext'] = _("Validate this certificate for yourself") # Translators: This text describes (at a high level) the mission and charter the edX platform and organization - context['company_about_description'] = _(u"{platform_name} offers interactive online classes and MOOCs.").format( + context['company_about_description'] = _("{platform_name} offers interactive online classes and MOOCs.").format( platform_name=platform_name) - context['company_about_title'] = _(u"About {platform_name}").format(platform_name=platform_name) + context['company_about_title'] = _("About {platform_name}").format(platform_name=platform_name) - context['company_about_urltext'] = _(u"Learn more about {platform_name}").format(platform_name=platform_name) + context['company_about_urltext'] = _("Learn more about {platform_name}").format(platform_name=platform_name) - context['company_courselist_urltext'] = _(u"Learn with {platform_name}").format(platform_name=platform_name) + context['company_courselist_urltext'] = _("Learn with {platform_name}").format(platform_name=platform_name) - context['company_careers_urltext'] = _(u"Work at {platform_name}").format(platform_name=platform_name) + context['company_careers_urltext'] = _("Work at {platform_name}").format(platform_name=platform_name) - context['company_contact_urltext'] = _(u"Contact {platform_name}").format(platform_name=platform_name) + context['company_contact_urltext'] = _("Contact {platform_name}").format(platform_name=platform_name) # Translators: This text appears near the top of the certificate and describes the guarantee provided by edX - context['document_banner'] = _(u"{platform_name} acknowledges the following student accomplishment").format( + context['document_banner'] = _("{platform_name} acknowledges the following student accomplishment").format( platform_name=platform_name ) @@ -234,7 +234,7 @@ def _update_course_context(request, context, course, platform_name): context['course_number'] = course_number if context['organization_long_name']: # Translators: This text represents the description of course - context['accomplishment_copy_course_description'] = _(u'a course of study offered by {partner_short_name}, ' + context['accomplishment_copy_course_description'] = _('a course of study offered by {partner_short_name}, ' 'an online learning initiative of ' '{partner_long_name}.').format( partner_short_name=context['organization_short_name'], @@ -257,7 +257,7 @@ def _update_social_context(request, context, course, user_certificate, platform_ context['facebook_app_id'] = configuration_helpers.get_value("FACEBOOK_APP_ID", settings.FACEBOOK_APP_ID) context['facebook_share_text'] = share_settings.get( 'CERTIFICATE_FACEBOOK_TEXT', - _(u"I completed the {course_title} course on {platform_name}.").format( + _("I completed the {course_title} course on {platform_name}.").format( course_title=context['accomplishment_copy_course_name'], platform_name=platform_name ) @@ -265,7 +265,7 @@ def _update_social_context(request, context, course, user_certificate, platform_ context['twitter_share_enabled'] = share_settings.get('CERTIFICATE_TWITTER', False) context['twitter_share_text'] = share_settings.get( 'CERTIFICATE_TWITTER_TEXT', - _(u"I completed a course at {platform_name}. Take a look at my certificate.").format( + _("I completed a course at {platform_name}. Take a look at my certificate.").format( platform_name=platform_name ) ) @@ -276,7 +276,7 @@ def _update_social_context(request, context, course, user_certificate, platform_ if context.get('twitter_share_enabled', False): twitter_url = 'https://twitter.com/intent/tweet?text={twitter_share_text}&url={share_url}'.format( twitter_share_text=smart_str(context['twitter_share_text']), - share_url=six.moves.urllib.parse.quote_plus(smart_str(share_url)) + share_url=urllib.parse.quote_plus(smart_str(share_url)) ) context['twitter_url'] = twitter_url context['linked_in_url'] = None @@ -301,11 +301,11 @@ def _update_context_with_user_info(context, user, user_certificate): context['accomplishment_copy_name'] = user_fullname context['accomplishment_copy_username'] = user.username - context['accomplishment_more_title'] = _(u"More Information About {user_name}'s Certificate:").format( + context['accomplishment_more_title'] = _("More Information About {user_name}'s Certificate:").format( user_name=user_fullname ) # Translators: This line is displayed to a user who has completed a course and achieved a certification - context['accomplishment_banner_opening'] = _(u"{fullname}, you earned a certificate!").format( + context['accomplishment_banner_opening'] = _("{fullname}, you earned a certificate!").format( fullname=user_fullname ) @@ -315,7 +315,7 @@ def _update_context_with_user_info(context, user, user_certificate): "in your social and professional networks.") # Translators: This line leads the reader to understand more about the certificate that a student has been awarded - context['accomplishment_copy_more_about'] = _(u"More about {fullname}'s accomplishment").format( + context['accomplishment_copy_more_about'] = _("More about {fullname}'s accomplishment").format( fullname=user_fullname ) @@ -336,7 +336,7 @@ def _get_user_certificate(request, user, course_key, course, preview_mode=None): modified_date = datetime.now().date() user_certificate = GeneratedCertificate( mode=preview_mode, - verify_uuid=six.text_type(uuid4().hex), + verify_uuid=str(uuid4().hex), modified_date=modified_date, created_date=datetime.now().date(), ) @@ -364,7 +364,7 @@ def _track_certificate_events(request, course, user, user_certificate): if 'evidence_visit' in request.GET: badge_class = get_completion_badge(course_key, user) if not badge_class: - log.warning(u'Visit to evidence URL for badge, but badges not configured for course "%s"', course_key) + log.warning('Visit to evidence URL for badge, but badges not configured for course "%s"', course_key) badges = [] else: badges = badge_class.get_for_user(user) @@ -379,7 +379,7 @@ def _track_certificate_events(request, course, user, user_certificate): 'badge_generator': badge.backend, 'issuing_component': badge.badge_class.issuing_component, 'user_id': user.id, - 'course_id': six.text_type(course_key), + 'course_id': str(course_key), 'enrollment_mode': badge.badge_class.mode, 'assertion_id': badge.id, 'assertion_image_url': badge.image_url, @@ -389,14 +389,14 @@ def _track_certificate_events(request, course, user, user_certificate): ) else: log.warning( - u"Could not find badge for %s on course %s.", + "Could not find badge for %s on course %s.", user.id, course_key, ) # track certificate evidence_visited event for analytics when certificate_user and accessing_user are different if request.user and request.user.id != user.id: - emit_certificate_event('evidence_visited', user, six.text_type(course.id), course, { + emit_certificate_event('evidence_visited', user, str(course.id), course, { 'certificate_id': user_certificate.verify_uuid, 'enrollment_mode': user_certificate.mode, 'social_network': CertificateSocialNetworks.linkedin @@ -452,7 +452,7 @@ def render_preview_certificate(request, course_id): """ This view renders the course certificate in preview mode """ - return render_html_view(request, six.text_type(course_id)) + return render_html_view(request, str(course_id)) def render_cert_by_uuid(request, certificate_uuid): @@ -464,7 +464,7 @@ def render_cert_by_uuid(request, certificate_uuid): verify_uuid=certificate_uuid, status=CertificateStatuses.downloadable ) - return render_html_view(request, six.text_type(certificate.course_id), certificate) + return render_html_view(request, str(certificate.course_id), certificate) except GeneratedCertificate.DoesNotExist as e: raise Http404 from e @@ -496,8 +496,8 @@ def render_html_view(request, course_id, certificate=None): # For any course or user exceptions, kick the user back to the "Invalid" screen except (InvalidKeyError, Http404) as exception: error_str = ( - u"Invalid cert: error finding course %s " - u"Specific error: %s" + "Invalid cert: error finding course %s " + "Specific error: %s" ) log.info(error_str, course_id, str(exception)) return _render_invalid_certificate(request, course_id, platform_name, configuration) @@ -505,7 +505,7 @@ def render_html_view(request, course_id, certificate=None): # Kick the user back to the "Invalid" screen if the feature is disabled for the course if not course.cert_html_view_enabled: log.info( - u"Invalid cert: HTML certificates disabled for %s. User id: %d", + "Invalid cert: HTML certificates disabled for %s. User id: %d", course_id, user_id, ) @@ -515,7 +515,7 @@ def render_html_view(request, course_id, certificate=None): user_certificate = _get_user_certificate(request, user, course_key, course, preview_mode) if not user_certificate: log.info( - u"Invalid cert: User %d does not have eligible cert for %s.", + "Invalid cert: User %d does not have eligible cert for %s.", user_id, course_id, ) @@ -527,7 +527,7 @@ def render_html_view(request, course_id, certificate=None): active_configuration = get_active_web_certificate(course, preview_mode) if active_configuration is None: log.info( - u"Invalid cert: course %s does not have an active configuration. User id: %d", + "Invalid cert: course %s does not have an active configuration. User id: %d", course_id, user_id, ) @@ -540,7 +540,7 @@ def render_html_view(request, course_id, certificate=None): custom_template = None custom_template_language = None if settings.FEATURES.get('CUSTOM_CERTIFICATE_TEMPLATES_ENABLED', False): - log.info(u"Custom certificate for course %s", course_id) + log.info("Custom certificate for course %s", course_id) custom_template, custom_template_language = _get_custom_template_and_language( course.id, user_certificate.mode, @@ -554,7 +554,7 @@ def render_html_view(request, course_id, certificate=None): certificate_language = custom_template_language if custom_template else user_language log.info( - u"certificate language is: %s for the course: %s", + "certificate language is: %s for the course: %s", certificate_language, course_key ) @@ -631,7 +631,7 @@ def _get_catalog_data_for_course(course_key): log.exception('Error occurred while parsing course run details') catalog_data['content_language'] = course_run_data.get('content_language') log.info( - u"catalog data received for course: %s is : %s", + "catalog data received for course: %s is : %s", course_key, catalog_data, ) @@ -645,7 +645,7 @@ def _get_custom_template_and_language(course_id, course_mode, course_language): """ closest_released_language = get_closest_released_language(course_language) if course_language else None log.info( - u"closest released language for %s is %s and course language was: %s", + "closest released language for %s is %s and course language was: %s", course_id, closest_released_language, course_language diff --git a/lms/djangoapps/certificates/views/xqueue.py b/lms/djangoapps/certificates/views/xqueue.py index f9c76938cd..07ac8f30d4 100644 --- a/lms/djangoapps/certificates/views/xqueue.py +++ b/lms/djangoapps/certificates/views/xqueue.py @@ -12,7 +12,6 @@ from django.http import Http404, HttpResponse, HttpResponseForbidden from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_POST from opaque_keys.edx.keys import CourseKey -from xmodule.modulestore.django import modulestore from common.djangoapps.util.json_request import JsonResponse, JsonResponseBadRequest from common.djangoapps.util.request_rate_limiter import BadRequestRateLimiter @@ -27,6 +26,7 @@ from lms.djangoapps.certificates.models import ( GeneratedCertificate, certificate_status_for_student ) +from xmodule.modulestore.django import modulestore log = logging.getLogger(__name__) User = get_user_model() @@ -56,7 +56,7 @@ def request_certificate(request): f'allowlist. Attempt will be made to generate an allowlist certificate.') generate_allowlist_certificate_task(student, course_key) elif status in [CertificateStatuses.unavailable, CertificateStatuses.notpassing, CertificateStatuses.error]: - log_msg = u'Grading and certification requested for user %s in course %s via /request_certificate call' + log_msg = 'Grading and certification requested for user %s in course %s via /request_certificate call' log.info(log_msg, username, course_key) status = generate_user_certificates(student, course_key, course=course) return HttpResponse(json.dumps({'add_status': status}), content_type='application/json') # pylint: disable=http-response-with-content-type-json, http-response-with-json-dumps @@ -91,8 +91,8 @@ def update_certificate(request): except GeneratedCertificate.DoesNotExist: log.critical( 'Unable to lookup certificate\n' - u'xqueue_body: %s\n' - u'xqueue_header: %s', + 'xqueue_body: %s\n' + 'xqueue_header: %s', xqueue_body, xqueue_header ) @@ -139,7 +139,7 @@ def update_certificate(request): cert.status = status.deleted else: log.critical( - u'Invalid state for cert update: %s', cert.status + 'Invalid state for cert update: %s', cert.status ) return HttpResponse( # pylint: disable=http-response-with-content-type-json, http-response-with-json-dumps json.dumps({ @@ -179,23 +179,23 @@ def update_example_certificate(request): HttpResponse (404): Invalid certificate identifier or access key. """ - log.info(u"Received response for example certificate from XQueue.") + log.info("Received response for example certificate from XQueue.") rate_limiter = BadRequestRateLimiter() # Check the parameters and rate limits # If these are invalid, return an error response. if rate_limiter.is_rate_limit_exceeded(request): - log.info(u"Bad request rate limit exceeded for update example certificate end-point.") + log.info("Bad request rate limit exceeded for update example certificate end-point.") return HttpResponseForbidden("Rate limit exceeded") if 'xqueue_body' not in request.POST: - log.info(u"Missing parameter 'xqueue_body' for update example certificate end-point") + log.info("Missing parameter 'xqueue_body' for update example certificate end-point") rate_limiter.tick_request_counter(request) return JsonResponseBadRequest("Parameter 'xqueue_body' is required.") if 'xqueue_header' not in request.POST: - log.info(u"Missing parameter 'xqueue_header' for update example certificate end-point") + log.info("Missing parameter 'xqueue_header' for update example certificate end-point") rate_limiter.tick_request_counter(request) return JsonResponseBadRequest("Parameter 'xqueue_header' is required.") @@ -203,7 +203,7 @@ def update_example_certificate(request): xqueue_body = json.loads(request.POST['xqueue_body']) xqueue_header = json.loads(request.POST['xqueue_header']) except (ValueError, TypeError): - log.info(u"Could not decode params to example certificate end-point as JSON.") + log.info("Could not decode params to example certificate end-point as JSON.") rate_limiter.tick_request_counter(request) return JsonResponseBadRequest("Parameters must be JSON-serialized.") @@ -218,7 +218,7 @@ def update_example_certificate(request): # were not valid. This most likely means that the request is NOT coming # from the XQueue. Return a 404 and increase the bad request counter # to protect against a DDOS attack. - log.info(u"Could not find example certificate with uuid '%s' and access key '%s'", uuid, access_key) + log.info("Could not find example certificate with uuid '%s' and access key '%s'", uuid, access_key) rate_limiter.tick_request_counter(request) raise Http404 from e @@ -228,8 +228,8 @@ def update_example_certificate(request): cert.update_status(ExampleCertificate.STATUS_ERROR, error_reason=error_reason) log.warning( ( - u"Error occurred during example certificate generation for uuid '%s'. " - u"The error response was '%s'." + "Error occurred during example certificate generation for uuid '%s'. " + "The error response was '%s'." ), uuid, error_reason ) else: @@ -238,13 +238,13 @@ def update_example_certificate(request): download_url = xqueue_body.get('url') if download_url is None: rate_limiter.tick_request_counter(request) - log.warning(u"No download URL provided for example certificate with uuid '%s'.", uuid) + log.warning("No download URL provided for example certificate with uuid '%s'.", uuid) return JsonResponseBadRequest( "Parameter 'download_url' is required for successfully generated certificates." ) else: cert.update_status(ExampleCertificate.STATUS_SUCCESS, download_url=download_url) - log.info(u"Successfully updated example certificate with uuid '%s'.", uuid) + log.info("Successfully updated example certificate with uuid '%s'.", uuid) # Let the XQueue know that we handled the response return JsonResponse({'return_code': 0})