From 9dac2eff90ef141f28dbefb49607ce3a54c5309c Mon Sep 17 00:00:00 2001
From: Jason Bau <jbau@stanford.edu>
Date: Sun, 8 Sep 2013 20:26:21 -0700
Subject: [PATCH] actually flatten username suggestion to ascii

---
 .../djangoapps/external_auth/tests/test_shib.py | 17 ++++++++++++++++-
 common/djangoapps/external_auth/views.py        | 12 +++++++++++-
 common/djangoapps/student/views.py              |  4 ++++
 3 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/common/djangoapps/external_auth/tests/test_shib.py b/common/djangoapps/external_auth/tests/test_shib.py
index ab12de6aa95..2b6e2a4acfb 100644
--- a/common/djangoapps/external_auth/tests/test_shib.py
+++ b/common/djangoapps/external_auth/tests/test_shib.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 """
 Tests for Shibboleth Authentication
 @jbau
@@ -7,6 +8,7 @@ from mock import patch
 
 from django.conf import settings
 from django.http import HttpResponseRedirect
+from django.test import TestCase
 from django.test.client import RequestFactory, Client as DjangoTestClient
 from django.test.utils import override_settings
 from django.core.urlresolvers import reverse
@@ -19,7 +21,7 @@ from xmodule.modulestore.inheritance import own_metadata
 from xmodule.modulestore.django import editable_modulestore
 
 from external_auth.models import ExternalAuthMap
-from external_auth.views import shib_login, course_specific_login, course_specific_register
+from external_auth.views import shib_login, course_specific_login, course_specific_register, _flatten_to_ascii
 
 from student.views import create_account, change_enrollment
 from student.models import UserProfile, Registration, CourseEnrollment
@@ -504,3 +506,16 @@ class ShibSPTest(ModuleStoreTestCase):
         self.assertEqual(response['location'], 'http://testserver/testredirect')
         # now there is enrollment
         self.assertTrue(CourseEnrollment.is_enrolled(student, course.id))
+
+
+class ShibUtilFnTest(TestCase):
+    """
+    Tests util functions in shib module
+    """
+    def test__flatten_to_ascii(self):
+        DIACRITIC = u"àèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝâêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿÄËÏÖÜŸåÅçÇ"  # pylint: disable=C0103
+        FLATTENED = u"aeiouAEIOUaeiouyAEIOUYaeiouAEIOUanoANOaeiouyAEIOUYaAcC"  # pylint: disable=C0103
+        self.assertEqual(_flatten_to_ascii(u'jas\xf6n'), u'jason')  # umlaut
+        self.assertEqual(_flatten_to_ascii(u'Jason\u5305'), u'Jason')  # mandarin, so it just gets dropped
+        self.assertEqual(_flatten_to_ascii(u'abc'), u'abc')  # pass through
+        self.assertEqual(_flatten_to_ascii(DIACRITIC), FLATTENED)
diff --git a/common/djangoapps/external_auth/views.py b/common/djangoapps/external_auth/views.py
index 78e55dabbc4..db440ca647a 100644
--- a/common/djangoapps/external_auth/views.py
+++ b/common/djangoapps/external_auth/views.py
@@ -5,6 +5,7 @@ import random
 import re
 import string       # pylint: disable=W0402
 import fnmatch
+import unicodedata
 
 from textwrap import dedent
 from external_auth.models import ExternalAuthMap
@@ -228,6 +229,15 @@ def _external_login_or_signup(request,
     return retfun()
 
 
+def _flatten_to_ascii(txt):
+    """
+    Flattens possibly unicode txt to ascii (django username limitation)
+    @param name:
+    @return:
+    """
+    return unicodedata.normalize('NFKD', txt).encode('ASCII', 'ignore')
+
+
 @ensure_csrf_cookie
 @cache_if_anonymous
 def _signup(request, eamap):
@@ -245,7 +255,7 @@ def _signup(request, eamap):
 
     # default conjoin name, no spaces, flattened to ascii b/c django can't handle unicode usernames, sadly
     # but this only affects username, not fullname
-    username = eamap.external_name.replace(' ', '')
+    username = _flatten_to_ascii(eamap.external_name)
 
     context = {'has_extauth_info': True,
                'show_signup_immediately': True,
diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py
index 9fa259132de..9a6924e4782 100644
--- a/common/djangoapps/student/views.py
+++ b/common/djangoapps/student/views.py
@@ -439,6 +439,10 @@ def _get_course_enrollment_domain(course_id):
 
 @ensure_csrf_cookie
 def accounts_login(request):
+    """
+    This view is mainly used as the redirect from the @login_required decorator.  I don't believe that
+    the login path linked from the homepage uses it.
+    """
     if settings.MITX_FEATURES.get('AUTH_USE_CAS'):
         return redirect(reverse('cas-login'))
     # see if the "next" parameter has been set, whether it has a course context, and if so, whether
-- 
GitLab