diff --git a/common/djangoapps/student/__init__.py b/common/djangoapps/student/__init__.py
index a77f14c551..fe279caa86 100644
--- a/common/djangoapps/student/__init__.py
+++ b/common/djangoapps/student/__init__.py
@@ -1,8 +1,9 @@
"""
Student app helpers and settings
"""
-from openedx.core.djangoapps.waffle_utils import WaffleSwitchNamespace
+from __future__ import absolute_import
+from openedx.core.djangoapps.waffle_utils import WaffleSwitchNamespace
# Namespace for student app waffle switches
STUDENT_WAFFLE_NAMESPACE = WaffleSwitchNamespace(name='student')
diff --git a/common/djangoapps/student/admin.py b/common/djangoapps/student/admin.py
index 65868444fa..a650ac28fc 100644
--- a/common/djangoapps/student/admin.py
+++ b/common/djangoapps/student/admin.py
@@ -1,19 +1,23 @@
""" Django admin pages for student app """
+from __future__ import absolute_import
+
from functools import wraps
+
from config_models.admin import ConfigurationModelAdmin
from django import forms
-from django.db import router, transaction
from django.contrib import admin
from django.contrib.admin.sites import NotRegistered
from django.contrib.admin.utils import unquote
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
-from django.contrib.auth.forms import ReadOnlyPasswordHashField, UserChangeForm as BaseUserChangeForm
-from django.db import models
+from django.contrib.auth.forms import ReadOnlyPasswordHashField
+from django.contrib.auth.forms import UserChangeForm as BaseUserChangeForm
+from django.db import models, router, transaction
from django.http import HttpResponseRedirect
from django.http.request import QueryDict
-from django.utils.translation import ugettext_lazy as _, ngettext
from django.urls import reverse
+from django.utils.translation import ngettext
+from django.utils.translation import ugettext_lazy as _
from opaque_keys import InvalidKeyError
from opaque_keys.edx.keys import CourseKey
@@ -27,13 +31,13 @@ from student.models import (
CourseEnrollmentAllowed,
DashboardConfiguration,
LinkedInAddToProfileConfiguration,
+ LoginFailures,
PendingNameChange,
Registration,
RegistrationCookieConfiguration,
UserAttribute,
UserProfile,
- UserTestGroup,
- LoginFailures,
+ UserTestGroup
)
from student.roles import REGISTERED_ACCESS_ROLES
from xmodule.modulestore.django import modulestore
diff --git a/common/djangoapps/student/auth.py b/common/djangoapps/student/auth.py
index 0656610412..d2423d20d9 100644
--- a/common/djangoapps/student/auth.py
+++ b/common/djangoapps/student/auth.py
@@ -4,6 +4,8 @@ authorization has authorization to do so, which infers authorization via role hi
(GlobalStaff is superset of auths of course instructor, ...), which consults the config
to decide whether to check course creator role, and other such functions.
"""
+from __future__ import absolute_import
+
from ccx_keys.locator import CCXBlockUsageLocator, CCXLocator
from django.conf import settings
from django.core.exceptions import PermissionDenied
diff --git a/common/djangoapps/student/forms.py b/common/djangoapps/student/forms.py
index f1c4763d91..4a6f236b0d 100644
--- a/common/djangoapps/student/forms.py
+++ b/common/djangoapps/student/forms.py
@@ -1,6 +1,8 @@
"""
Utility functions for validating forms
"""
+from __future__ import absolute_import
+
import re
from importlib import import_module
@@ -11,14 +13,14 @@ from django.contrib.auth.hashers import UNUSABLE_PASSWORD_PREFIX
from django.contrib.auth.models import User
from django.contrib.auth.tokens import default_token_generator
from django.core.exceptions import ValidationError
-from django.urls import reverse
from django.core.validators import RegexValidator, slug_re
from django.forms import widgets
+from django.urls import reverse
from django.utils.http import int_to_base36
from django.utils.translation import ugettext_lazy as _
-
from edx_ace import ace
from edx_ace.recipient import Recipient
+
from openedx.core.djangoapps.ace_common.template_context import get_base_template_context
from openedx.core.djangoapps.lang_pref import LANGUAGE_KEY
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
@@ -26,7 +28,8 @@ from openedx.core.djangoapps.theming.helpers import get_current_site
from openedx.core.djangoapps.user_api import accounts as accounts_settings
from openedx.core.djangoapps.user_api.accounts.utils import is_secondary_email_feature_enabled
from openedx.core.djangoapps.user_api.preferences.api import get_user_preference
-from student.message_types import AccountRecovery as AccountRecoveryMessage, PasswordReset
+from student.message_types import AccountRecovery as AccountRecoveryMessage
+from student.message_types import PasswordReset
from student.models import AccountRecovery, CourseEnrollmentAllowed, email_exists_or_retired
from util.password_policy_validators import validate_password
diff --git a/common/djangoapps/student/helpers.py b/common/djangoapps/student/helpers.py
index fa7e421368..cf4abdf6b2 100644
--- a/common/djangoapps/student/helpers.py
+++ b/common/djangoapps/student/helpers.py
@@ -1,33 +1,29 @@
"""
Helpers for the student app.
"""
+from __future__ import absolute_import
+
import json
import logging
import mimetypes
-import urllib
-import urlparse
from datetime import datetime
+import six.moves.urllib.parse
from django.conf import settings
-from django.core.exceptions import PermissionDenied
-from django.urls import NoReverseMatch, reverse
-from django.core.validators import ValidationError
from django.contrib.auth import load_backend
from django.contrib.auth.models import User
+from django.core.exceptions import PermissionDenied
+from django.core.validators import ValidationError
from django.db import IntegrityError, transaction
+from django.urls import NoReverseMatch, reverse
from django.utils.translation import ugettext as _
from pytz import UTC
from six import iteritems, text_type
+
import third_party_auth
from course_modes.models import CourseMode
-from lms.djangoapps.certificates.api import (
- get_certificate_url,
- has_html_certificates_enabled
-)
-from lms.djangoapps.certificates.models import (
- CertificateStatuses,
- certificate_status_for_student
-)
+from lms.djangoapps.certificates.api import get_certificate_url, has_html_certificates_enabled
+from lms.djangoapps.certificates.models import CertificateStatuses, certificate_status_for_student
from lms.djangoapps.grades.api import CourseGradeFactory
from lms.djangoapps.verify_student.models import VerificationDeadline
from lms.djangoapps.verify_student.services import IDVerificationService
@@ -42,13 +38,12 @@ from student.models import (
Registration,
UserAttribute,
UserProfile,
- unique_id_for_user,
email_exists_or_retired,
+ unique_id_for_user,
username_exists_or_retired
)
from util.password_policy_validators import normalize_password
-
# Enumeration of per-course verification statuses
# we display on the student dashboard.
VERIFY_STATUS_NEED_TO_VERIFY = "verify_need_to_verify"
@@ -285,7 +280,7 @@ def get_next_url_for_login_page(request):
# Before we redirect to next/dashboard, we need to handle auto-enrollment:
params = [(param, request.GET[param]) for param in POST_AUTH_PARAMS if param in request.GET]
params.append(('next', redirect_to)) # After auto-enrollment, user will be sent to payment page or to this URL
- redirect_to = '{}?{}'.format(reverse('finish_auth'), urllib.urlencode(params))
+ redirect_to = '{}?{}'.format(reverse('finish_auth'), six.moves.urllib.parse.urlencode(params))
# Note: if we are resuming a third party auth pipeline, then the next URL will already
# be saved in the session as part of the pipeline state. That URL will take priority
# over this one.
@@ -299,12 +294,12 @@ def get_next_url_for_login_page(request):
# Don't add tpa_hint if we're already in the TPA pipeline (prevent infinite loop),
# and don't overwrite any existing tpa_hint params (allow tpa_hint override).
running_pipeline = third_party_auth.pipeline.get(request)
- (scheme, netloc, path, query, fragment) = list(urlparse.urlsplit(redirect_to))
+ (scheme, netloc, path, query, fragment) = list(six.moves.urllib.parse.urlsplit(redirect_to))
if not running_pipeline and 'tpa_hint' not in query:
- params = urlparse.parse_qs(query)
+ params = six.moves.urllib.parse.parse_qs(query)
params['tpa_hint'] = [tpa_hint]
- query = urllib.urlencode(params, doseq=True)
- redirect_to = urlparse.urlunsplit((scheme, netloc, path, query, fragment))
+ query = six.moves.urllib.parse.urlencode(params, doseq=True)
+ redirect_to = six.moves.urllib.parse.urlunsplit((scheme, netloc, path, query, fragment))
return redirect_to
@@ -356,7 +351,7 @@ def _get_redirect_to(request):
redirect_to = None
else:
themes = get_themes()
- next_path = urlparse.urlparse(redirect_to).path
+ next_path = six.moves.urllib.parse.urlparse(redirect_to).path
for theme in themes:
if theme.theme_dir_name in next_path:
log.warning(
diff --git a/common/djangoapps/student/message_types.py b/common/djangoapps/student/message_types.py
index 259bae58e5..331197f059 100644
--- a/common/djangoapps/student/message_types.py
+++ b/common/djangoapps/student/message_types.py
@@ -2,6 +2,8 @@
ACE message types for the student module.
"""
+from __future__ import absolute_import
+
from openedx.core.djangoapps.ace_common.message import BaseMessageType
diff --git a/common/djangoapps/student/middleware.py b/common/djangoapps/student/middleware.py
index ffde2e0a2e..e56c36cd02 100644
--- a/common/djangoapps/student/middleware.py
+++ b/common/djangoapps/student/middleware.py
@@ -2,10 +2,13 @@
Middleware that checks user standing for the purpose of keeping users with
disabled accounts from accessing the site.
"""
+from __future__ import absolute_import
+
from django.conf import settings
from django.http import HttpResponseForbidden
from django.utils.translation import ugettext as _
+from openedx.core.djangolib.markup import HTML, Text
from student.models import UserStanding
@@ -24,12 +27,12 @@ class UserStandingMiddleware(object):
pass
else:
if user_account.account_status == UserStanding.ACCOUNT_DISABLED:
- msg = _(
+ msg = Text(_(
'Your account has been disabled. If you believe '
'this was done in error, please contact us at '
'{support_email}'
- ).format(
- support_email=u'{address}'.format(
+ )).format(
+ support_email=HTML(u'{address}').format(
address=settings.DEFAULT_FEEDBACK_EMAIL,
subject_line=_('Disabled Account'),
),
diff --git a/common/djangoapps/student/models.py b/common/djangoapps/student/models.py
index ba0536cb72..b8cad61cd0 100644
--- a/common/djangoapps/student/models.py
+++ b/common/djangoapps/student/models.py
@@ -10,18 +10,18 @@ file and check it in at the same time as your model changes. To do that,
2. ./manage.py lms schemamigration student --auto description_of_your_change
3. Add the migration file created in edx-platform/common/djangoapps/student/migrations/
"""
-from __future__ import print_function
+from __future__ import absolute_import, print_function
+
import hashlib
import json
import logging
-import six
import uuid
from collections import OrderedDict, defaultdict, namedtuple
from datetime import datetime, timedelta
from functools import total_ordering
from importlib import import_module
-from urllib import urlencode
+import six
from config_models.models import ConfigurationModel
from django.apps import apps
from django.conf import settings
@@ -40,6 +40,7 @@ from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext_noop
from django_countries.fields import CountryField
+from edx_django_utils.cache import RequestCache
from edx_rest_api_client.exceptions import SlumberBaseException
from eventtracking import tracker
from model_utils.models import TimeStampedModel
@@ -47,11 +48,12 @@ from opaque_keys.edx.django.models import CourseKeyField
from opaque_keys.edx.keys import CourseKey
from pytz import UTC
from six import text_type
+from six.moves import range
+from six.moves.urllib.parse import urlencode
from slumber.exceptions import HttpClientError, HttpServerError
from user_util import user_util
-from edx_django_utils.cache import RequestCache
-from student.signals import UNENROLL_DONE, ENROLL_STATUS_CHANGE, ENROLLMENT_TRACK_UPDATED
+import openedx.core.djangoapps.django_comment_common.comment_client as cc
from course_modes.models import CourseMode, get_cosmetic_verified_display_price
from courseware.models import (
CourseDynamicUpgradeDeadlineConfiguration,
@@ -59,13 +61,12 @@ from courseware.models import (
OrgDynamicUpgradeDeadlineConfiguration
)
from enrollment.api import _default_course_mode
-
from lms.djangoapps.certificates.models import GeneratedCertificate
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
-import openedx.core.djangoapps.django_comment_common.comment_client as cc
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from openedx.core.djangoapps.xmodule_django.models import NoneToEmptyManager
from openedx.core.djangolib.model_mixins import DeletableByUserValue
+from student.signals import ENROLL_STATUS_CHANGE, ENROLLMENT_TRACK_UPDATED, UNENROLL_DONE
from track import contexts, segment
from util.milestones_helpers import is_entrance_exams_enabled
from util.model_utils import emit_field_changed_events, get_changed_fields_dict
@@ -447,7 +448,7 @@ class UserProfile(models.Model):
# Optional demographic data we started capturing from Fall 2012
this_year = datetime.now(UTC).year
- VALID_YEARS = range(this_year, this_year - 120, -1)
+ VALID_YEARS = list(range(this_year, this_year - 120, -1))
year_of_birth = models.IntegerField(blank=True, null=True, db_index=True)
GENDER_CHOICES = (
('m', ugettext_noop('Male')),
@@ -938,7 +939,7 @@ class LoginFailures(models.Model):
date_str = self.lockout_until.isoformat()
return u'LoginFailures({username}, {count}, {date})'.format(
- username=unicode(self.user.username, 'utf-8'),
+ username=six.text_type(self.user.username, 'utf-8'),
count=self.failure_count,
date=date_str
)
@@ -950,7 +951,7 @@ class LoginFailures(models.Model):
date_str = self.lockout_until.isoformat()
return u'{username}: {count} - {date}'.format(
- username=unicode(self.user.username, 'utf-8'),
+ username=six.text_type(self.user.username, 'utf-8'),
count=self.failure_count,
date=date_str
)
@@ -1114,7 +1115,7 @@ class CourseEnrollment(models.Model):
@course_id.setter
def course_id(self, value):
- if isinstance(value, basestring):
+ if isinstance(value, six.string_types):
self._course_id = CourseKey.from_string(value)
else:
self._course_id = value
diff --git a/common/djangoapps/student/role_helpers.py b/common/djangoapps/student/role_helpers.py
index 5af2b75e47..22b277ffee 100644
--- a/common/djangoapps/student/role_helpers.py
+++ b/common/djangoapps/student/role_helpers.py
@@ -1,20 +1,22 @@
"""
Helpers for student roles
"""
+from __future__ import absolute_import
+
from openedx.core.djangoapps.django_comment_common.models import (
FORUM_ROLE_ADMINISTRATOR,
- FORUM_ROLE_MODERATOR,
- FORUM_ROLE_GROUP_MODERATOR,
FORUM_ROLE_COMMUNITY_TA,
+ FORUM_ROLE_GROUP_MODERATOR,
+ FORUM_ROLE_MODERATOR,
Role
)
from student.roles import (
CourseBetaTesterRole,
CourseInstructorRole,
CourseStaffRole,
- OrgStaffRole,
+ GlobalStaff,
OrgInstructorRole,
- GlobalStaff
+ OrgStaffRole
)
diff --git a/common/djangoapps/student/roles.py b/common/djangoapps/student/roles.py
index da31eb57be..498d0a6ce0 100644
--- a/common/djangoapps/student/roles.py
+++ b/common/djangoapps/student/roles.py
@@ -3,10 +3,13 @@ Classes used to model the roles used in the courseware. Each role is responsible
adding users, removing users, and listing members
"""
+from __future__ import absolute_import
+
import logging
from abc import ABCMeta, abstractmethod
from collections import defaultdict
+import six
from django.contrib.auth.models import User
from opaque_keys.edx.django.models import CourseKeyField
@@ -47,7 +50,7 @@ class BulkRoleCache(object):
for role in CourseAccessRole.objects.filter(user__in=users).select_related('user'):
roles_by_user[role.user.id].add(role)
- users_without_roles = filter(lambda u: u.id not in roles_by_user, users)
+ users_without_roles = [u for u in users if u.id not in roles_by_user]
for user in users_without_roles:
roles_by_user[user.id] = set()
@@ -80,11 +83,10 @@ class RoleCache(object):
)
-class AccessRole(object):
+class AccessRole(six.with_metaclass(ABCMeta, object)):
"""
Object representing a role with particular access to a resource
"""
- __metaclass__ = ABCMeta
@abstractmethod
def has_user(self, user):
diff --git a/common/djangoapps/student/tasks.py b/common/djangoapps/student/tasks.py
index 23b9481c30..ed32d952ad 100644
--- a/common/djangoapps/student/tasks.py
+++ b/common/djangoapps/student/tasks.py
@@ -1,6 +1,8 @@
"""
This file contains celery tasks for sending email
"""
+from __future__ import absolute_import
+
import logging
from boto.exception import NoAuthHandlerFound
diff --git a/common/djangoapps/student/text_me_the_app.py b/common/djangoapps/student/text_me_the_app.py
index 1ff5d6d6bb..91be75bfc7 100644
--- a/common/djangoapps/student/text_me_the_app.py
+++ b/common/djangoapps/student/text_me_the_app.py
@@ -1,6 +1,8 @@
"""
Fragment for rendering text me the app.
"""
+from __future__ import absolute_import
+
from django.template.loader import render_to_string
from web_fragments.fragment import Fragment
diff --git a/common/djangoapps/student/urls.py b/common/djangoapps/student/urls.py
index ac4b6bfb2f..c27030c5a1 100644
--- a/common/djangoapps/student/urls.py
+++ b/common/djangoapps/student/urls.py
@@ -2,6 +2,8 @@
URLs for student app
"""
+from __future__ import absolute_import
+
from django.conf import settings
from django.conf.urls import url
from django.contrib.auth.views import password_reset_complete