@@ -50,7 +50,7 @@ class AccessTokenExchangeFormTest(AccessTokenExchangeTestMixin):
|
||||
self.assertTrue(form.is_valid())
|
||||
self.assertEqual(form.cleaned_data["user"], self.user)
|
||||
self.assertEqual(form.cleaned_data["client"], self.oauth_client)
|
||||
self.assertEqual(scope.to_names(form.cleaned_data["scope"]), expected_scopes)
|
||||
self.assertEqual(set(scope.to_names(form.cleaned_data["scope"])), set(expected_scopes))
|
||||
|
||||
|
||||
# This is necessary because cms does not implement third party auth
|
||||
|
||||
@@ -63,11 +63,16 @@ class AccessTokenExchangeViewTest(AccessTokenExchangeTestMixin):
|
||||
timedelta(seconds=int(content["expires_in"])),
|
||||
provider.constants.EXPIRE_DELTA_PUBLIC
|
||||
)
|
||||
self.assertEqual(content["scope"], ' '.join(expected_scopes))
|
||||
actual_scopes = content["scope"]
|
||||
if actual_scopes:
|
||||
actual_scopes = actual_scopes.split(' ')
|
||||
else:
|
||||
actual_scopes = []
|
||||
self.assertEqual(set(actual_scopes), set(expected_scopes))
|
||||
token = self.oauth2_adapter.get_access_token(token_string=content["access_token"])
|
||||
self.assertEqual(token.user, self.user)
|
||||
self.assertEqual(self.oauth2_adapter.get_client_for_token(token), self.oauth_client)
|
||||
self.assertEqual(self.oauth2_adapter.get_token_scope_names(token), expected_scopes)
|
||||
self.assertEqual(set(self.oauth2_adapter.get_token_scope_names(token)), set(expected_scopes))
|
||||
|
||||
def test_single_access_token(self):
|
||||
def extract_token(response):
|
||||
@@ -184,7 +189,7 @@ class TestLoginWithAccessTokenView(TestCase):
|
||||
Calls the login_with_access_token endpoint and verifies the response given the expected values.
|
||||
"""
|
||||
url = reverse("login_with_access_token")
|
||||
response = self.client.post(url, HTTP_AUTHORIZATION=b"Bearer {0}".format(access_token))
|
||||
response = self.client.post(url, HTTP_AUTHORIZATION=u"Bearer {0}".format(access_token).encode('utf-8'))
|
||||
self.assertEqual(response.status_code, expected_status_code)
|
||||
if expected_cookie_name:
|
||||
self.assertIn(expected_cookie_name, response.cookies)
|
||||
|
||||
@@ -10,7 +10,6 @@ import ddt
|
||||
import mock
|
||||
import six
|
||||
from django.core.management import call_command
|
||||
from django.utils import six
|
||||
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
|
||||
|
||||
@@ -230,6 +229,12 @@ class TestDumpToNeo4jCommand(TestDumpToNeo4jCommandBase):
|
||||
)
|
||||
|
||||
|
||||
class SomeThing(object):
|
||||
"""Just to test the stringification of an object."""
|
||||
def __str__(self):
|
||||
return "<SomeThing>"
|
||||
|
||||
|
||||
@skip_unless_lms
|
||||
@ddt.ddt
|
||||
class TestModuleStoreSerializer(TestDumpToNeo4jCommandBase):
|
||||
@@ -379,7 +384,7 @@ class TestModuleStoreSerializer(TestDumpToNeo4jCommandBase):
|
||||
|
||||
@ddt.data(
|
||||
(1, 1),
|
||||
(object, "<type 'object'>"),
|
||||
(SomeThing(), "<SomeThing>"),
|
||||
(1.5, 1.5),
|
||||
("úñîçø∂é", "úñîçø∂é"),
|
||||
(b"plain string", b"plain string"),
|
||||
@@ -388,7 +393,8 @@ class TestModuleStoreSerializer(TestDumpToNeo4jCommandBase):
|
||||
((1,), "(1,)"),
|
||||
# list of elements should be coerced into a list of the
|
||||
# string representations of those elements
|
||||
([object, object], ["<type 'object'>", "<type 'object'>"])
|
||||
([SomeThing(), SomeThing()], ["<SomeThing>", "<SomeThing>"]),
|
||||
([1, 2], ["1", "2"]),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_coerce_types(self, original_value, coerced_expected):
|
||||
|
||||
@@ -36,7 +36,7 @@ def get_shared_secret_key(provider_id):
|
||||
|
||||
if isinstance(secret, six.text_type):
|
||||
try:
|
||||
secret = str(secret)
|
||||
secret.encode('ascii')
|
||||
except UnicodeEncodeError:
|
||||
secret = None
|
||||
log.error(u'Shared secret key for credit provider "%s" contains non-ASCII unicode.', provider_id)
|
||||
|
||||
@@ -8,6 +8,7 @@ from datetime import datetime
|
||||
|
||||
import six
|
||||
from django.db import models
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django_mysql.models import ListCharField
|
||||
from oauth2_provider.settings import oauth2_settings
|
||||
@@ -19,6 +20,7 @@ from openedx.core.djangolib.markup import HTML
|
||||
from openedx.core.lib.request_utils import get_request_or_stub
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class RestrictedApplication(models.Model):
|
||||
"""
|
||||
This model lists which django-oauth-toolkit Applications are considered 'restricted'
|
||||
@@ -35,7 +37,7 @@ class RestrictedApplication(models.Model):
|
||||
class Meta:
|
||||
app_label = 'oauth_dispatch'
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
"""
|
||||
Return a unicode representation of this object
|
||||
"""
|
||||
@@ -59,6 +61,7 @@ class RestrictedApplication(models.Model):
|
||||
return access_token.expires == datetime(1970, 1, 1, tzinfo=utc)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class ApplicationAccess(models.Model):
|
||||
"""
|
||||
Specifies access control information for the associated Application.
|
||||
@@ -81,7 +84,7 @@ class ApplicationAccess(models.Model):
|
||||
def get_scopes(cls, application):
|
||||
return cls.objects.get(application=application).scopes
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
"""
|
||||
Return a unicode representation of this object.
|
||||
"""
|
||||
@@ -91,6 +94,7 @@ class ApplicationAccess(models.Model):
|
||||
)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class ApplicationOrganization(models.Model):
|
||||
"""
|
||||
Associates a DOT Application to an Organization.
|
||||
@@ -129,7 +133,7 @@ class ApplicationOrganization(models.Model):
|
||||
queryset = queryset.filter(relation_type=relation_type)
|
||||
return [r.organization.name for r in queryset]
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
"""
|
||||
Return a unicode representation of this object.
|
||||
"""
|
||||
|
||||
@@ -63,7 +63,7 @@ class AccessTokenLoginMixin(object):
|
||||
|
||||
return self.client.post(
|
||||
self.login_with_access_token_url,
|
||||
HTTP_AUTHORIZATION=b"Bearer {0}".format(access_token if access_token else self.access_token)
|
||||
HTTP_AUTHORIZATION=u"Bearer {0}".format(access_token if access_token else self.access_token).encode('utf-8')
|
||||
)
|
||||
|
||||
def _assert_access_token_is_valid(self, access_token=None):
|
||||
|
||||
@@ -210,7 +210,7 @@ def get_all_orgs():
|
||||
This can be used, for example, to do filtering.
|
||||
|
||||
Returns:
|
||||
A list of all organizations present in the site configuration.
|
||||
A set of all organizations present in the site configuration.
|
||||
"""
|
||||
# Import is placed here to avoid model import at project startup.
|
||||
from openedx.core.djangoapps.site_configuration.models import SiteConfiguration
|
||||
|
||||
@@ -114,7 +114,7 @@ class SiteConfiguration(models.Model):
|
||||
for example, to do filtering.
|
||||
|
||||
Returns:
|
||||
A list of all organizations present in site configuration.
|
||||
A set of all organizations present in site configuration.
|
||||
"""
|
||||
org_filter_set = set()
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ Tests for site configuration's django models.
|
||||
from __future__ import absolute_import
|
||||
|
||||
from mock import patch
|
||||
import six
|
||||
|
||||
from django.test import TestCase
|
||||
from django.db import IntegrityError, transaction
|
||||
@@ -321,10 +322,7 @@ class SiteConfigurationTests(TestCase):
|
||||
)
|
||||
|
||||
# Test that the default value is returned if the value for the given key is not found in the configuration
|
||||
self.assertListEqual(
|
||||
list(SiteConfiguration.get_all_orgs()),
|
||||
expected_orgs,
|
||||
)
|
||||
six.assertCountEqual(self, SiteConfiguration.get_all_orgs(), expected_orgs)
|
||||
|
||||
def test_get_all_orgs_returns_only_enabled(self):
|
||||
"""
|
||||
@@ -343,7 +341,4 @@ class SiteConfigurationTests(TestCase):
|
||||
)
|
||||
|
||||
# Test that the default value is returned if the value for the given key is not found in the configuration
|
||||
self.assertListEqual(
|
||||
list(SiteConfiguration.get_all_orgs()),
|
||||
expected_orgs,
|
||||
)
|
||||
six.assertCountEqual(self, SiteConfiguration.get_all_orgs(), expected_orgs)
|
||||
|
||||
@@ -225,13 +225,13 @@ class StudentViewShimTest(TestCase):
|
||||
)
|
||||
response = view(HttpRequest())
|
||||
self.assertEqual(response.status_code, 403)
|
||||
self.assertEqual(response.content, "third-party-auth")
|
||||
self.assertEqual(response.content, b"third-party-auth")
|
||||
|
||||
def test_non_json_response(self):
|
||||
view = self._shimmed_view(HttpResponse(content="Not a JSON dict"))
|
||||
response = view(HttpRequest())
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.content, "Not a JSON dict")
|
||||
self.assertEqual(response.content, b"Not a JSON dict")
|
||||
|
||||
@ddt.data("redirect", "redirect_url")
|
||||
def test_ignore_redirect_from_json(self, redirect_key):
|
||||
@@ -254,7 +254,7 @@ class StudentViewShimTest(TestCase):
|
||||
)
|
||||
response = view(HttpRequest())
|
||||
self.assertEqual(response.status_code, 400)
|
||||
self.assertEqual(response.content, "Error!")
|
||||
self.assertEqual(response.content, b"Error!")
|
||||
|
||||
def test_preserve_headers(self):
|
||||
view_response = HttpResponse()
|
||||
|
||||
@@ -8,6 +8,7 @@ from __future__ import absolute_import
|
||||
|
||||
import logging
|
||||
|
||||
import six
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import authenticate
|
||||
from django.contrib.auth import login as django_login
|
||||
@@ -110,11 +111,11 @@ def _enforce_password_policy_compliance(request, user):
|
||||
password_policy_compliance.enforce_compliance_on_login(user, request.POST.get('password'))
|
||||
except password_policy_compliance.NonCompliantPasswordWarning as e:
|
||||
# Allow login, but warn the user that they will be required to reset their password soon.
|
||||
PageLevelMessages.register_warning_message(request, e.message)
|
||||
PageLevelMessages.register_warning_message(request, six.text_type(e))
|
||||
except password_policy_compliance.NonCompliantPasswordException as e:
|
||||
send_password_reset_email_for_user(user, request)
|
||||
# Prevent the login attempt.
|
||||
raise AuthFailedError(e.message)
|
||||
raise AuthFailedError(six.text_type(e))
|
||||
|
||||
|
||||
def _generate_not_activated_message(user):
|
||||
|
||||
@@ -323,7 +323,7 @@ class LoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMixin, ModuleSto
|
||||
visible=True,
|
||||
enabled=True,
|
||||
icon_class='',
|
||||
icon_image=SimpleUploadedFile('icon.svg', '<svg><rect width="50" height="100"/></svg>'),
|
||||
icon_image=SimpleUploadedFile('icon.svg', b'<svg><rect width="50" height="100"/></svg>'),
|
||||
)
|
||||
self.hidden_enabled_provider = self.configure_linkedin_provider(
|
||||
visible=False,
|
||||
@@ -606,7 +606,7 @@ class LoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMixin, ModuleSto
|
||||
tpa_hint = self.hidden_disabled_provider.provider_id
|
||||
params = [("next", "/courses/something/?tpa_hint={0}".format(tpa_hint))]
|
||||
response = self.client.get(reverse('signin_user'), params, HTTP_ACCEPT="text/html")
|
||||
self.assertNotIn(response.content, tpa_hint)
|
||||
self.assertNotIn(response.content.decode('utf-8'), tpa_hint)
|
||||
|
||||
@ddt.data(
|
||||
('signin_user', 'login'),
|
||||
@@ -650,7 +650,7 @@ class LoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMixin, ModuleSto
|
||||
tpa_hint = self.hidden_disabled_provider.provider_id
|
||||
params = [("next", "/courses/something/?tpa_hint={0}".format(tpa_hint))]
|
||||
response = self.client.get(reverse(url_name), params, HTTP_ACCEPT="text/html")
|
||||
self.assertNotIn(response.content, tpa_hint)
|
||||
self.assertNotIn(response.content.decode('utf-8'), tpa_hint)
|
||||
|
||||
@override_settings(FEATURES=dict(settings.FEATURES, THIRD_PARTY_AUTH_HINT='oa2-google-oauth2'))
|
||||
@ddt.data(
|
||||
|
||||
@@ -10,6 +10,7 @@ from config_models.models import ConfigurationModel
|
||||
from django.db import models
|
||||
from django.db.models.signals import post_save, pre_save
|
||||
from django.dispatch import receiver
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.translation import ugettext_lazy
|
||||
from edx_django_utils.cache import RequestCache
|
||||
from opaque_keys.edx.django.models import CourseKeyField
|
||||
@@ -92,6 +93,7 @@ def pre_save_callback(sender, instance, **kwargs): # pylint: disable=unused-arg
|
||||
instance._old_mode = None # pylint: disable=protected-access
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class VerifiedTrackCohortedCourse(models.Model):
|
||||
"""
|
||||
Tracks which courses have verified track auto-cohorting enabled.
|
||||
@@ -109,7 +111,7 @@ class VerifiedTrackCohortedCourse(models.Model):
|
||||
|
||||
CACHE_NAMESPACE = u"verified_track_content.VerifiedTrackCohortedCourse.cache."
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return u"Course: {}, enabled: {}".format(six.text_type(self.course_key), self.enabled)
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
"""Tests for zendesk_proxy views."""
|
||||
from __future__ import absolute_import
|
||||
import json
|
||||
|
||||
from copy import deepcopy
|
||||
import json
|
||||
|
||||
import ddt
|
||||
from django.urls import reverse
|
||||
from django.test.utils import override_settings
|
||||
from mock import MagicMock, patch
|
||||
import six
|
||||
from six.moves import range
|
||||
|
||||
from openedx.core.djangoapps.zendesk_proxy.v0.views import ZENDESK_REQUESTS_PER_HOUR
|
||||
from openedx.core.lib.api.test_utils import ApiTestCase
|
||||
from six.moves import range
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@@ -45,14 +47,30 @@ class ZendeskProxyTestCase(ApiTestCase):
|
||||
self.assertHttpCreated(response)
|
||||
(mock_args, mock_kwargs) = mock_post.call_args
|
||||
self.assertEqual(mock_args, ('https://www.superrealurlsthataredefinitelynotfake.com/api/v2/tickets.json',))
|
||||
six.assertCountEqual(self, mock_kwargs.keys(), ['headers', 'data'])
|
||||
self.assertEqual(
|
||||
mock_kwargs,
|
||||
mock_kwargs['headers'],
|
||||
{
|
||||
'headers': {
|
||||
'content-type': 'application/json',
|
||||
'Authorization': 'Bearer abcdefghijklmnopqrstuvwxyz1234567890'
|
||||
'content-type': 'application/json',
|
||||
'Authorization': 'Bearer abcdefghijklmnopqrstuvwxyz1234567890'
|
||||
}
|
||||
)
|
||||
self.assertEqual(
|
||||
json.loads(mock_kwargs['data']),
|
||||
{
|
||||
'ticket': {
|
||||
'comment': {
|
||||
'body': "Help! I'm trapped in a unit test factory and I can't get out!",
|
||||
'uploads': None,
|
||||
},
|
||||
'custom_fields': None,
|
||||
'requester': {
|
||||
'email': 'JohnQStudent@example.com',
|
||||
'name': 'John Q. Student',
|
||||
},
|
||||
'subject': 'Python Unit Test Help Request',
|
||||
'tags': ['python_unit_test'],
|
||||
},
|
||||
'data': '{"ticket": {"comment": {"body": "Help! I\'m trapped in a unit test factory and I can\'t get out!", "uploads": null}, "tags": ["python_unit_test"], "subject": "Python Unit Test Help Request", "custom_fields": null, "requester": {"name": "John Q. Student", "email": "JohnQStudent@example.com"}}}' # pylint: disable=line-too-long
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
"""Tests for zendesk_proxy views."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
import json
|
||||
|
||||
from copy import deepcopy
|
||||
import json
|
||||
|
||||
import ddt
|
||||
from django.urls import reverse
|
||||
from django.test.utils import override_settings
|
||||
from mock import MagicMock, patch
|
||||
import six
|
||||
from six.moves import range
|
||||
|
||||
from openedx.core.djangoapps.zendesk_proxy.v1.views import ZendeskProxyThrottle
|
||||
from openedx.core.lib.api.test_utils import ApiTestCase
|
||||
from six.moves import range
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@@ -53,14 +56,30 @@ class ZendeskProxyTestCase(ApiTestCase):
|
||||
self.assertHttpCreated(response)
|
||||
(mock_args, mock_kwargs) = mock_post.call_args
|
||||
self.assertEqual(mock_args, ('https://www.superrealurlsthataredefinitelynotfake.com/api/v2/tickets.json',))
|
||||
six.assertCountEqual(self, mock_kwargs.keys(), ['headers', 'data'])
|
||||
self.assertEqual(
|
||||
mock_kwargs,
|
||||
mock_kwargs['headers'],
|
||||
{
|
||||
'headers': {
|
||||
'content-type': 'application/json',
|
||||
'Authorization': 'Bearer abcdefghijklmnopqrstuvwxyz1234567890'
|
||||
'content-type': 'application/json',
|
||||
'Authorization': 'Bearer abcdefghijklmnopqrstuvwxyz1234567890'
|
||||
}
|
||||
)
|
||||
self.assertEqual(
|
||||
json.loads(mock_kwargs['data']),
|
||||
{
|
||||
'ticket': {
|
||||
'comment': {
|
||||
'body': "Help! I'm trapped in a unit test factory and I can't get out!",
|
||||
'uploads': None,
|
||||
},
|
||||
'custom_fields': [{'id': '001', 'value': 'demo-course'}],
|
||||
'requester': {
|
||||
'email': 'JohnQStudent@example.com',
|
||||
'name': 'John Q. Student',
|
||||
},
|
||||
'subject': 'Python Unit Test Help Request',
|
||||
'tags': ['python_unit_test'],
|
||||
},
|
||||
'data': '{"ticket": {"comment": {"body": "Help! I\'m trapped in a unit test factory and I can\'t get out!", "uploads": null}, "tags": ["python_unit_test"], "subject": "Python Unit Test Help Request", "custom_fields": [{"id": "001", "value": "demo-course"}], "requester": {"name": "John Q. Student", "email": "JohnQStudent@example.com"}}}' # pylint: disable=line-too-long
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user