From 5febcce20c00c916b3ebc29d399dff03be1339c2 Mon Sep 17 00:00:00 2001
From: "Dave St.Germain" <dstgermain@edx.org>
Date: Mon, 19 Aug 2019 10:24:15 -0400
Subject: [PATCH] Fix python3 compatibility in SafeCookieData and elsewhere

---
 common/djangoapps/student/models.py                      | 4 ++--
 lms/djangoapps/commerce/tests/test_signals.py            | 9 +++++----
 lms/djangoapps/course_goals/handlers.py                  | 1 +
 lms/djangoapps/verify_student/models.py                  | 4 ++--
 .../verify_student/tests/test_fake_software_secure.py    | 7 ++++---
 openedx/core/djangoapps/safe_sessions/middleware.py      | 9 ++++++---
 6 files changed, 20 insertions(+), 14 deletions(-)

diff --git a/common/djangoapps/student/models.py b/common/djangoapps/student/models.py
index a375daf2ac1..6725cdf0e7c 100644
--- a/common/djangoapps/student/models.py
+++ b/common/djangoapps/student/models.py
@@ -162,8 +162,8 @@ def anonymous_id_for_user(user, course_id, save=True):
 
     # include the secret key as a salt, and to make the ids unique across different LMS installs.
     hasher = hashlib.md5()
-    hasher.update(settings.SECRET_KEY)
-    hasher.update(text_type(user.id))
+    hasher.update(settings.SECRET_KEY.encode('utf8'))
+    hasher.update(text_type(user.id).encode('utf8'))
     if course_id:
         hasher.update(text_type(course_id).encode('utf-8'))
     digest = hasher.hexdigest()
diff --git a/lms/djangoapps/commerce/tests/test_signals.py b/lms/djangoapps/commerce/tests/test_signals.py
index 95a8f21bc10..a2a5f7e240e 100644
--- a/lms/djangoapps/commerce/tests/test_signals.py
+++ b/lms/djangoapps/commerce/tests/test_signals.py
@@ -184,7 +184,7 @@ class TestRefundSignal(TestCase):
                 self.assertFalse(mock_send_notification.called)
 
                 last_request = httpretty.last_request()
-                self.assertDictEqual(json.loads(last_request.body), {'action': 'approve_payment_only'})
+                self.assertDictEqual(json.loads(last_request.body.decode('utf8')), {'action': 'approve_payment_only'})
 
     @mock.patch('lms.djangoapps.commerce.utils._send_refund_notification')
     def test_notification_no_refund(self, mock_send_notification):
@@ -305,8 +305,9 @@ class TestRefundSignal(TestCase):
         # Verify the headers
         expected = {
             'content-type': JSON,
-            'Authorization': 'Basic ' + base64.b64encode(
-                '{user}/token:{pwd}'.format(user=ZENDESK_USER, pwd=ZENDESK_API_KEY))
+            'Authorization': 'Basic {}'.format(base64.b64encode(
+                '{user}/token:{pwd}'.format(user=ZENDESK_USER, pwd=ZENDESK_API_KEY).encode('utf8')).decode('utf8')
+            )
         }
         self.assertDictContainsSubset(expected, last_request.headers)
 
@@ -322,4 +323,4 @@ class TestRefundSignal(TestCase):
                 'tags': ['LMS'] + tags
             }
         }
-        self.assertDictEqual(json.loads(last_request.body), expected)
+        self.assertDictEqual(json.loads(last_request.body.decode('utf8')), expected)
diff --git a/lms/djangoapps/course_goals/handlers.py b/lms/djangoapps/course_goals/handlers.py
index ef4afb8c9f3..2992ba9a285 100644
--- a/lms/djangoapps/course_goals/handlers.py
+++ b/lms/djangoapps/course_goals/handlers.py
@@ -3,6 +3,7 @@ Signal handlers for course goals.
 """
 from __future__ import absolute_import
 
+import six
 from django.db import models
 from django.dispatch import receiver
 
diff --git a/lms/djangoapps/verify_student/models.py b/lms/djangoapps/verify_student/models.py
index e6aba8da2dc..ff03c1bd209 100644
--- a/lms/djangoapps/verify_student/models.py
+++ b/lms/djangoapps/verify_student/models.py
@@ -8,7 +8,7 @@ of a student over a period of time. Right now, the only models are the abstract
 `SoftwareSecurePhotoVerification`. The hope is to keep as much of the
 photo verification process as generic as possible.
 """
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
 
 import functools
 import json
@@ -47,7 +47,7 @@ log = logging.getLogger(__name__)
 
 def generateUUID():  # pylint: disable=invalid-name
     """ Utility function; generates UUIDs """
-    return str(uuid.uuid4())
+    return six.text_type(uuid.uuid4())
 
 
 class VerificationException(Exception):
diff --git a/lms/djangoapps/verify_student/tests/test_fake_software_secure.py b/lms/djangoapps/verify_student/tests/test_fake_software_secure.py
index 43a22bf7f45..6520952d8f1 100644
--- a/lms/djangoapps/verify_student/tests/test_fake_software_secure.py
+++ b/lms/djangoapps/verify_student/tests/test_fake_software_secure.py
@@ -2,7 +2,7 @@
 Tests for the fake software secure response.
 """
 
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
 
 from django.test import TestCase
 from mock import patch
@@ -79,5 +79,6 @@ class SoftwareSecureFakeViewEnabledTest(SoftwareSecureFakeViewTest):
         )
 
         self.assertEqual(response.status_code, 200)
-        self.assertIn('EdX-ID', response.content)
-        self.assertIn('results_callback', response.content)
+        content = response.content.decode('utf8')
+        self.assertIn('EdX-ID', content)
+        self.assertIn('results_callback', content)
diff --git a/openedx/core/djangoapps/safe_sessions/middleware.py b/openedx/core/djangoapps/safe_sessions/middleware.py
index 5443bae9600..6591fe06568 100644
--- a/openedx/core/djangoapps/safe_sessions/middleware.py
+++ b/openedx/core/djangoapps/safe_sessions/middleware.py
@@ -55,7 +55,7 @@ SSL-protected channel.  Otherwise, a session hijacker could copy
 the entire cookie and use it to impersonate the victim.
 
 """
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
 
 from base64 import b64encode
 from contextlib import contextmanager
@@ -70,6 +70,8 @@ from django.contrib.sessions.middleware import SessionMiddleware
 from django.core import signing
 from django.http import HttpResponse
 from django.utils.crypto import get_random_string
+from django.utils.encoding import python_2_unicode_compatible
+
 from six import text_type  # pylint: disable=ungrouped-imports
 
 from openedx.core.lib.mobile_utils import is_request_from_mobile_app
@@ -145,7 +147,7 @@ class SafeCookieData(object):
         safe_cookie_string.
         """
         try:
-            raw_cookie_components = safe_cookie_string.split(cls.SEPARATOR)
+            raw_cookie_components = six.text_type(safe_cookie_string).split(cls.SEPARATOR)
             safe_cookie_data = SafeCookieData(*raw_cookie_components)
         except TypeError:
             raise SafeCookieError(
@@ -160,7 +162,8 @@ class SafeCookieData(object):
                     ))
             return safe_cookie_data
 
-    def __unicode__(self):
+    @python_2_unicode_compatible
+    def __str__(self):
         """
         Returns a string serialization of the safe cookie data.
         """
-- 
GitLab