refactor: ran pyupgrade on lms/djangoapps/certificates

This commit is contained in:
usamasadiq
2021-02-25 19:58:39 +05:00
parent b59b6b4147
commit 84bb9faa3f
24 changed files with 364 additions and 378 deletions

View File

@@ -42,7 +42,7 @@ class CertificateTemplateForm(forms.ModelForm):
choices=lang_choices, required=False
)
class Meta(object):
class Meta:
model = CertificateTemplate
fields = '__all__'

View File

@@ -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):

View File

@@ -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,

View File

@@ -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'),

View File

@@ -14,7 +14,7 @@ class CertificatesConfig(AppConfig):
"""
Application Configuration for Certificates.
"""
name = u'lms.djangoapps.certificates'
name = 'lms.djangoapps.certificates'
def ready(self):
"""

View File

@@ -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__)

View File

@@ -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),

View File

@@ -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}")

View File

@@ -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
)

View File

@@ -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()

View File

@@ -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=' ')

View File

@@ -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'] = '<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)
)

View File

@@ -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. """

View File

@@ -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)
)

View File

@@ -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"

View File

@@ -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
)

View File

@@ -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
)

View File

@@ -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

View File

@@ -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,

View File

@@ -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<user_id>[^/]*)/course/{course_id}'.format(course_id=settings.COURSE_ID_PATTERN),
fr'^user/(?P<user_id>[^/]*)/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'
),

View File

@@ -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:

View File

@@ -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"]
)

View File

@@ -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'&copy; {year} {platform_name}. {reserved}.'.format(
context['copyright_text'] = '&copy; {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"&quot;".').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"&quot;".').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

View File

@@ -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})