Commit 99e85556 by Christina Roberts

Merge pull request #7140 from edx/christina/delete-enable-new-dashboard

Delete ENABLE_NEW_DASHBOARD code.
parents 820b0118 61a108d3
......@@ -309,32 +309,6 @@ class UserProfile(models.Model):
self.name = new_name
self.save()
@transaction.commit_on_success
def update_email(self, new_email):
"""Update the user's email and save the change in the history.
Implicitly saves the model.
If the new email is the same as the old email, do not update the history.
Arguments:
new_email (unicode): The new email for the user.
Returns:
None
"""
if self.user.email == new_email:
return
meta = self.get_meta()
if 'old_emails' not in meta:
meta['old_emails'] = []
meta['old_emails'].append([self.user.email, datetime.now(UTC).isoformat()])
self.set_meta(meta)
self.save()
self.user.email = new_email
self.user.save()
class UserSignupSource(models.Model):
"""
......
......@@ -112,7 +112,6 @@ AUTH_EMAIL_OPT_IN_KEY = 'email_opt_in'
AUTH_ENTRY_DASHBOARD = 'dashboard'
AUTH_ENTRY_LOGIN = 'login'
AUTH_ENTRY_PROFILE = 'profile'
AUTH_ENTRY_REGISTER = 'register'
# This is left-over from an A/B test
......@@ -143,16 +142,11 @@ AUTH_DISPATCH_URLS = {
AUTH_ENTRY_LOGIN_2: '/account/login/',
AUTH_ENTRY_REGISTER_2: '/account/register/',
# If linking/unlinking an account from the new student profile
# page, redirect to the profile page. Only used if
# `FEATURES['ENABLE_NEW_DASHBOARD']` is true.
AUTH_ENTRY_PROFILE: '/profile/',
}
_AUTH_ENTRY_CHOICES = frozenset([
AUTH_ENTRY_DASHBOARD,
AUTH_ENTRY_LOGIN,
AUTH_ENTRY_PROFILE,
AUTH_ENTRY_REGISTER,
# This is left-over from an A/B test
......@@ -452,8 +446,6 @@ def parse_query_params(strategy, response, *args, **kwargs):
'is_login': auth_entry in [AUTH_ENTRY_LOGIN, AUTH_ENTRY_LOGIN_2],
# Whether the auth pipeline entered from /register.
'is_register': auth_entry in [AUTH_ENTRY_REGISTER, AUTH_ENTRY_REGISTER_2],
# Whether the auth pipeline entered from /profile.
'is_profile': auth_entry == AUTH_ENTRY_PROFILE,
# Whether the auth pipeline entered from an API
'is_api': auth_entry == AUTH_ENTRY_API,
}
......
......@@ -51,8 +51,6 @@ _MIDDLEWARE_CLASSES = (
'third_party_auth.middleware.ExceptionMiddleware',
)
_SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/dashboard'
_SOCIAL_AUTH_NEW_ASSOCIATION_REDIRECT_URL = '/profile'
_SOCIAL_AUTH_DISCONNECT_REDIRECT_URL = '/profile'
def _merge_auth_info(django_settings, auth_info):
......@@ -97,11 +95,6 @@ def _set_global_settings(django_settings):
# Where to send the user once social authentication is successful.
django_settings.SOCIAL_AUTH_LOGIN_REDIRECT_URL = _SOCIAL_AUTH_LOGIN_REDIRECT_URL
# Change redirects to the profile page if we enable the new dashboard.
if django_settings.FEATURES.get('ENABLE_NEW_DASHBOARD', ''):
django_settings.SOCIAL_AUTH_NEW_ASSOCIATION_REDIRECT_URL = _SOCIAL_AUTH_NEW_ASSOCIATION_REDIRECT_URL
django_settings.SOCIAL_AUTH_DISCONNECT_REDIRECT_URL = _SOCIAL_AUTH_DISCONNECT_REDIRECT_URL
# Inject our customized auth pipeline. All auth backends must work with
# this pipeline.
django_settings.SOCIAL_AUTH_PIPELINE = (
......
......@@ -59,7 +59,6 @@ class StudentAccountUpdateTest(UrlResetMixin, TestCase):
INVALID_KEY = u"123abc"
@mock.patch.dict(settings.FEATURES, {'ENABLE_NEW_DASHBOARD': True})
def setUp(self):
super(StudentAccountUpdateTest, self).setUp("student_account.urls")
......@@ -71,141 +70,6 @@ class StudentAccountUpdateTest(UrlResetMixin, TestCase):
result = self.client.login(username=self.USERNAME, password=self.OLD_PASSWORD)
self.assertTrue(result)
def test_index(self):
response = self.client.get(reverse('account_index'))
self.assertContains(response, "Student Account")
def test_change_email(self):
response = self._change_email(self.NEW_EMAIL, self.OLD_PASSWORD)
self.assertEquals(response.status_code, 200)
# Verify that the email associated with the account remains unchanged
profile_info = profile_api.profile_info(self.USERNAME)
self.assertEquals(profile_info['email'], self.OLD_EMAIL)
# Check that an email was sent with the activation key
self.assertEqual(len(mail.outbox), 1)
self._assert_email(
mail.outbox[0],
[self.NEW_EMAIL],
u"Email Change Request",
u"There was recently a request to change the email address"
)
# Retrieve the activation key from the email
email_body = mail.outbox[0].body
result = re.search('/email/confirmation/([^ \n]+)', email_body)
self.assertIsNot(result, None)
activation_key = result.group(1)
# Attempt to activate the email
response = self.client.get(reverse('email_change_confirm', kwargs={'key': activation_key}))
self.assertEqual(response.status_code, 200)
# Verify that the email was changed
profile_info = profile_api.profile_info(self.USERNAME)
self.assertEquals(profile_info['email'], self.NEW_EMAIL)
# Verify that notification emails were sent
self.assertEqual(len(mail.outbox), 2)
self._assert_email(
mail.outbox[1],
[self.OLD_EMAIL, self.NEW_EMAIL],
u"Email Change Successful",
u"You successfully changed the email address"
)
def test_email_change_wrong_password(self):
response = self._change_email(self.NEW_EMAIL, "wrong password")
self.assertEqual(response.status_code, 401)
def test_email_change_request_no_user(self):
# Patch account API to raise an internal error when an email change is requested
with mock.patch('student_account.views.account_api.request_email_change') as mock_call:
mock_call.side_effect = account_api.AccountUserNotFound
response = self._change_email(self.NEW_EMAIL, self.OLD_PASSWORD)
self.assertEquals(response.status_code, 400)
def test_email_change_request_email_taken_by_active_account(self):
# Create/activate a second user with the new email
activation_key = account_api.create_account(self.ALTERNATE_USERNAME, self.OLD_PASSWORD, self.NEW_EMAIL)
account_api.activate_account(activation_key)
# Request to change the original user's email to the email now used by the second user
response = self._change_email(self.NEW_EMAIL, self.OLD_PASSWORD)
self.assertEquals(response.status_code, 409)
def test_email_change_request_email_taken_by_inactive_account(self):
# Create a second user with the new email, but don't active them
account_api.create_account(self.ALTERNATE_USERNAME, self.OLD_PASSWORD, self.NEW_EMAIL)
# Request to change the original user's email to the email used by the inactive user
response = self._change_email(self.NEW_EMAIL, self.OLD_PASSWORD)
self.assertEquals(response.status_code, 200)
@ddt.data(*INVALID_EMAILS)
def test_email_change_request_email_invalid(self, invalid_email):
# Request to change the user's email to an invalid address
response = self._change_email(invalid_email, self.OLD_PASSWORD)
self.assertEquals(response.status_code, 400)
def test_email_change_confirmation(self):
# Get an email change activation key
activation_key = account_api.request_email_change(self.USERNAME, self.NEW_EMAIL, self.OLD_PASSWORD)
# Follow the link sent in the confirmation email
response = self.client.get(reverse('email_change_confirm', kwargs={'key': activation_key}))
self.assertContains(response, "Email change successful")
# Verify that the email associated with the account has changed
profile_info = profile_api.profile_info(self.USERNAME)
self.assertEquals(profile_info['email'], self.NEW_EMAIL)
def test_email_change_confirmation_invalid_key(self):
# Visit the confirmation page with an invalid key
response = self.client.get(reverse('email_change_confirm', kwargs={'key': self.INVALID_KEY}))
self.assertContains(response, "Something went wrong")
# Verify that the email associated with the account has not changed
profile_info = profile_api.profile_info(self.USERNAME)
self.assertEquals(profile_info['email'], self.OLD_EMAIL)
def test_email_change_confirmation_email_already_exists(self):
# Get an email change activation key
email_activation_key = account_api.request_email_change(self.USERNAME, self.NEW_EMAIL, self.OLD_PASSWORD)
# Create/activate a second user with the new email
account_activation_key = account_api.create_account(self.ALTERNATE_USERNAME, self.OLD_PASSWORD, self.NEW_EMAIL)
account_api.activate_account(account_activation_key)
# Follow the link sent to the original user
response = self.client.get(reverse('email_change_confirm', kwargs={'key': email_activation_key}))
self.assertContains(response, "address you wanted to use is already used")
# Verify that the email associated with the original account has not changed
profile_info = profile_api.profile_info(self.USERNAME)
self.assertEquals(profile_info['email'], self.OLD_EMAIL)
def test_email_change_confirmation_internal_error(self):
# Get an email change activation key
activation_key = account_api.request_email_change(self.USERNAME, self.NEW_EMAIL, self.OLD_PASSWORD)
# Patch account API to return an internal error
with mock.patch('student_account.views.account_api.confirm_email_change') as mock_call:
mock_call.side_effect = account_api.AccountInternalError
response = self.client.get(reverse('email_change_confirm', kwargs={'key': activation_key}))
self.assertContains(response, "Something went wrong")
def test_email_change_request_missing_email_param(self):
response = self._change_email(None, self.OLD_PASSWORD)
self.assertEqual(response.status_code, 400)
def test_email_change_request_missing_password_param(self):
response = self._change_email(self.OLD_EMAIL, None)
self.assertEqual(response.status_code, 400)
@skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in LMS')
def test_password_change(self):
# Request a password change while logged in, simulating
......@@ -316,25 +180,6 @@ class StudentAccountUpdateTest(UrlResetMixin, TestCase):
self.assertEqual(response.status_code, 403)
@ddt.data(
('get', 'account_index', []),
('post', 'email_change_request', []),
('get', 'email_change_confirm', [123])
)
@ddt.unpack
def test_require_login(self, method, url_name, args):
# Access the page while logged out
self.client.logout()
url = reverse(url_name, args=args)
response = getattr(self.client, method)(url, follow=True)
# Should have been redirected to the login page
self.assertEqual(len(response.redirect_chain), 1)
self.assertIn('accounts/login?next=', response.redirect_chain[0][0])
@ddt.data(
('get', 'account_index', []),
('post', 'email_change_request', []),
('get', 'email_change_confirm', [123]),
('post', 'password_change_request', []),
)
@ddt.unpack
......@@ -346,24 +191,6 @@ class StudentAccountUpdateTest(UrlResetMixin, TestCase):
response = getattr(self.client, method)(url)
self.assertEqual(response.status_code, 405)
def _assert_email(self, email, expected_to, expected_subject, expected_body):
"""Check whether an email has the correct properties. """
self.assertEqual(email.to, expected_to)
self.assertIn(expected_subject, email.subject)
self.assertIn(expected_body, email.body)
def _change_email(self, new_email, password):
"""Request to change the user's email. """
data = {}
if new_email is not None:
data['email'] = new_email
if password is not None:
# We can't pass a Unicode object to urlencode, so we encode the Unicode object
data['password'] = password.encode('utf-8')
return self.client.post(path=reverse('email_change_request'), data=data)
def _change_password(self, email=None):
"""Request to change the user's password. """
data = {}
......
......@@ -11,11 +11,3 @@ if settings.FEATURES.get('ENABLE_COMBINED_LOGIN_REGISTRATION'):
url(r'^register/$', 'login_and_registration_form', {'initial_mode': 'register'}, name='account_register'),
url(r'^password$', 'password_change_request_handler', name='password_change_request'),
)
if settings.FEATURES.get('ENABLE_NEW_DASHBOARD'):
urlpatterns += patterns(
'student_account.views',
url(r'^$', 'index', name='account_index'),
url(r'^email$', 'email_change_request_handler', name='email_change_request'),
url(r'^email/confirmation/(?P<key>[^/]*)$', 'email_change_confirmation_handler', name='email_change_confirm'),
)
......@@ -42,31 +42,6 @@ from student_account.helpers import auth_pipeline_urls
AUDIT_LOG = logging.getLogger("audit")
@login_required
@require_http_methods(['GET'])
def index(request):
"""Render the account info page.
Args:
request (HttpRequest)
Returns:
HttpResponse: 200 if the index page was sent successfully
HttpResponse: 302 if not logged in (redirect to login page)
HttpResponse: 405 if using an unsupported HTTP method
Example usage:
GET /account
"""
return render_to_response(
'student_account/index.html', {
'disable_courseware_js': True,
}
)
@require_http_methods(['GET'])
@ensure_csrf_cookie
def login_and_registration_form(request, initial_mode="login"):
......@@ -124,145 +99,6 @@ def login_and_registration_form(request, initial_mode="login"):
return render_to_response('student_account/login_and_register.html', context)
@login_required
@require_http_methods(['POST'])
@ensure_csrf_cookie
def email_change_request_handler(request):
"""Handle a request to change the user's email address.
Sends an email to the newly specified address containing a link
to a confirmation page.
Args:
request (HttpRequest)
Returns:
HttpResponse: 200 if the confirmation email was sent successfully
HttpResponse: 302 if not logged in (redirect to login page)
HttpResponse: 400 if the format of the new email is incorrect, or if
an email change is requested for a user which does not exist
HttpResponse: 401 if the provided password (in the form) is incorrect
HttpResponse: 405 if using an unsupported HTTP method
HttpResponse: 409 if the provided email is already in use
Example usage:
POST /account/email
"""
username = request.user.username
password = request.POST.get('password')
new_email = request.POST.get('email')
if new_email is None:
return HttpResponseBadRequest("Missing param 'email'")
if password is None:
return HttpResponseBadRequest("Missing param 'password'")
old_email = profile_api.profile_info(username)['email']
try:
key = account_api.request_email_change(username, new_email, password)
except (account_api.AccountEmailInvalid, account_api.AccountUserNotFound):
return HttpResponseBadRequest()
except account_api.AccountEmailAlreadyExists:
return HttpResponse(status=409)
except account_api.AccountNotAuthorized:
return HttpResponse(status=401)
context = {
'key': key,
'old_email': old_email,
'new_email': new_email,
}
subject = render_to_string('student_account/emails/email_change_request/subject_line.txt', context)
subject = ''.join(subject.splitlines())
message = render_to_string('student_account/emails/email_change_request/message_body.txt', context)
from_address = microsite.get_value(
'email_from_address',
settings.DEFAULT_FROM_EMAIL
)
# Send a confirmation email to the new address containing the activation key
send_mail(subject, message, from_address, [new_email])
return HttpResponse(status=200)
@login_required
@require_http_methods(['GET'])
def email_change_confirmation_handler(request, key):
"""Complete a change of the user's email address.
This is called when the activation link included in the confirmation
email is clicked.
Args:
request (HttpRequest)
Returns:
HttpResponse: 200 if the email change is successful, the activation key
is invalid, the new email is already in use, or the
user to which the email change will be applied does
not exist
HttpResponse: 302 if not logged in (redirect to login page)
HttpResponse: 405 if using an unsupported HTTP method
Example usage:
GET /account/email/confirmation/{key}
"""
try:
old_email, new_email = account_api.confirm_email_change(key)
except account_api.AccountNotAuthorized:
return render_to_response(
'student_account/email_change_failed.html', {
'disable_courseware_js': True,
'error': 'key_invalid',
}
)
except account_api.AccountEmailAlreadyExists:
return render_to_response(
'student_account/email_change_failed.html', {
'disable_courseware_js': True,
'error': 'email_used',
}
)
except account_api.AccountInternalError:
return render_to_response(
'student_account/email_change_failed.html', {
'disable_courseware_js': True,
'error': 'internal',
}
)
context = {
'old_email': old_email,
'new_email': new_email,
}
subject = render_to_string('student_account/emails/email_change_confirmation/subject_line.txt', context)
subject = ''.join(subject.splitlines())
message = render_to_string('student_account/emails/email_change_confirmation/message_body.txt', context)
from_address = microsite.get_value(
'email_from_address',
settings.DEFAULT_FROM_EMAIL
)
# Notify both old and new emails of the change
send_mail(subject, message, from_address, [old_email, new_email])
return render_to_response(
'student_account/email_change_successful.html', {
'disable_courseware_js': True,
}
)
@require_http_methods(['POST'])
def password_change_request_handler(request):
"""Handle password change requests originating from the account page.
......
......@@ -313,9 +313,6 @@ FEATURES = {
# ENABLE_OAUTH2_PROVIDER to True
'ENABLE_MOBILE_REST_API': False,
# Enable the new dashboard, account, and profile pages
'ENABLE_NEW_DASHBOARD': False,
# Enable the combined login/registration form
'ENABLE_COMBINED_LOGIN_REGISTRATION': False,
......
<%! from django.utils.translation import ugettext as _ %>
<%! from django.core.urlresolvers import reverse %>
<%inherit file="../main.html" />
<section class="container activation">
<section class="message">
<h1 class="invalid">${_("Email change failed.")}</h1>
<hr class="horizontal-divider">
<p>
% if error is 'key_invalid' or error is 'internal':
${_("Something went wrong. Please contact {support} for help.").format(
support="<a href='mailto:{support_email}'>{support_email}</a>".format(
support_email=settings.TECH_SUPPORT_EMAIL
)
)}
% elif error is 'email_used':
${_("The email address you wanted to use is already used by another "
"{platform_name} account.").format(platform_name=settings.PLATFORM_NAME)}
% endif
</p>
<p>
${_("You can try again from the {link_start}account settings{link_end} page.").format(
link_start="<a href='{url}'>".format(url=reverse('account_index')),
link_end="</a>"
)}
</p>
</section>
</section>
<%! from django.utils.translation import ugettext as _ %>
<%! from django.core.urlresolvers import reverse %>
<%inherit file="../main.html" />
<section class="container activation">
<section class="message">
<h1 class="valid">${_("Email change successful!")}</h1>
<hr class="horizontal-divider">
<p>
${_("You should see your new email address listed on the "
"{link_start}account settings{link_end} page.").format(
link_start="<a href='{url}'>".format(url=reverse('account_index')),
link_end="</a>",
)}
</p>
</section>
</section>
<%! from django.utils.translation import ugettext as _ %>
## TODO: Get sign-off from Product on new copy, and think about
## turning this into a large, multi-line message for i18n purposes.
## Greeting
${_("Hi there,")}
## Preamble
${_("You successfully changed the email address associated with your "
"{platform_name} account from {old_email} to {new_email}.").format(
platform_name=settings.PLATFORM_NAME,
old_email=old_email,
new_email=new_email
)
}
## Translators: This is the signature of an email. "\n" is a newline character,
## and should be placed between the closing word and the signing team's name.
${_("Thanks,\n - The {platform_name} Team").format(
platform_name=settings.PLATFORM_NAME,
)}
<%! from django.utils.translation import ugettext as _ %>
${_("{platform_name} Email Change Successful").format(platform_name=settings.PLATFORM_NAME)}
<%! from django.utils.translation import ugettext as _ %>
## TODO: Get sign-off from Product on new copy, and think about
## turning this into a large, multi-line message for i18n purposes.
## Greeting
${_("Hi there,")}
## Preamble
${_("There was recently a request to change the email address associated "
"with your {platform_name} account from {old_email} to {new_email}. "
"If you requested this change, please confirm your new email address "
"by following the link below:").format(
platform_name=settings.PLATFORM_NAME,
old_email=old_email,
new_email=new_email
)
}
## Confirmation link
% if is_secure:
https://${site}/account/email/confirmation/${key}
% else:
http://${site}/account/email/confirmation/${key}
% endif
## Closing
${_("If you don't want to change the email address associated with your "
"account, ignore this message.")}
## Translators: This is the signature of an email. "\n" is a newline character,
## and should be placed between the closing word and the signing team's name.
${_("Thanks,\n - The {platform_name} Team").format(
platform_name=settings.PLATFORM_NAME,
)}
<%! from django.utils.translation import ugettext as _ %>
${_("{platform_name} Email Change Request").format(platform_name=settings.PLATFORM_NAME)}
<%! from django.utils.translation import ugettext as _ %>
<%namespace name='static' file='/static_content.html'/>
<%inherit file="../main.html" />
<%block name="pagetitle">${_("Student Account")}</%block>
<%block name="js_extra">
<script type="text/javascript" src="${static.url('js/vendor/underscore-min.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/backbone-min.js')}"></script>
<%static:js group='student_account'/>
</%block>
<%block name="header_extras">
% for template_name in ["account"]:
<script type="text/template" id="${template_name}-tpl">
<%static:include path="student_account/${template_name}.underscore" />
</script>
% endfor
</%block>
<h1>Student Account</h1>
<p>This is a placeholder for the student's account page.</p>
<div id="account-container"></div>
......@@ -45,11 +45,6 @@ class AccountUsernameAlreadyExists(AccountUserAlreadyExists):
pass
class AccountEmailAlreadyExists(AccountUserAlreadyExists):
"""An account already exists with the requested email. """
pass
class AccountUsernameInvalid(AccountRequestError):
"""The requested username is not in a valid format. """
pass
......@@ -216,122 +211,6 @@ def activate_account(activation_key):
# This implicitly saves the registration
registration.activate()
@intercept_errors(AccountInternalError, ignore_errors=[AccountRequestError])
def request_email_change(username, new_email, password):
"""Request an email change.
Users must confirm the change before we update their information.
Args:
username (unicode): The username associated with the account.
new_email (unicode): The user's new email address.
password (unicode): The password the user entered to authorize the change.
Returns:
unicode: an activation key for the account.
Raises:
AccountUserNotFound
AccountEmailAlreadyExists
AccountEmailInvalid
AccountNotAuthorized
"""
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
raise AccountUserNotFound
# Check the user's credentials
if not user.check_password(password):
raise AccountNotAuthorized
# Validate the email, raising an exception if it is not in the correct format
_validate_email(new_email)
# Verify that no active account has taken the email in between
# the request and the activation.
# We'll check again before confirming and persisting the change,
# but if the email is already taken by an active account, we should
# let the user know as soon as possible.
if User.objects.filter(email=new_email, is_active=True).exists():
raise AccountEmailAlreadyExists
try:
pending_change = PendingEmailChange.objects.get(user=user)
except PendingEmailChange.DoesNotExist:
pending_change = PendingEmailChange(user=user)
# Update the change (re-using the same record if it already exists)
# This will generate a new activation key and save the record.
return pending_change.request_change(new_email)
@intercept_errors(AccountInternalError, ignore_errors=[AccountRequestError])
@transaction.commit_on_success
def confirm_email_change(activation_key):
"""Confirm an email change.
Users can confirm the change by providing an activation key
they received via email.
Args:
activation_key (unicode): The activation key the user received
when he/she requested the email change.
Returns:
Tuple: (old_email, new_email)
Raises:
AccountNotAuthorized: The activation code is invalid.
AccountEmailAlreadyExists: Someone else has already taken the email address.
AccountInternalError
"""
try:
# Activation key has a uniqueness constraint, so we're guaranteed to get
# at most one pending change.
pending_change = PendingEmailChange.objects.select_related('user').get(
activation_key=activation_key
)
except PendingEmailChange.DoesNotExist:
# If there are no changes, then the activation key is invalid
raise AccountNotAuthorized
else:
old_email = pending_change.user.email
new_email = pending_change.new_email
# Verify that no one else has taken the email in between
# the request and the activation.
# In our production database, email has a uniqueness constraint,
# so there is no danger of a race condition here.
if User.objects.filter(email=new_email).exists():
raise AccountEmailAlreadyExists
# Update the email history (in the user profile)
try:
profile = UserProfile.objects.get(user=pending_change.user)
except UserProfile.DoesNotExist:
raise AccountInternalError(
"No profile exists for the user '{username}'".format(
username=pending_change.user.username
)
)
else:
profile.update_email(new_email)
# Delete the pending change, so that the activation code
# will be single-use
pending_change.delete()
# Return the old and new email
# This allows the caller of the function to notify users at both
# the new and old email, which is necessary for security reasons.
return (old_email, new_email)
@intercept_errors(AccountInternalError, ignore_errors=[AccountRequestError])
def request_password_change(email, orig_host, is_secure):
"""Email a single-use link for performing a password reset.
......
......@@ -76,40 +76,6 @@ class AccountApiTest(TestCase):
account = account_api.account_info(self.USERNAME)
self.assertTrue(account['is_active'])
def test_change_email(self):
# Request an email change
account_api.create_account(self.USERNAME, self.PASSWORD, self.EMAIL)
activation_key = account_api.request_email_change(
self.USERNAME, u'new+email@example.com', self.PASSWORD
)
# Verify that the email has not yet changed
account = account_api.account_info(self.USERNAME)
self.assertEqual(account['email'], self.EMAIL)
# Confirm the change, using the activation code
old_email, new_email = account_api.confirm_email_change(activation_key)
self.assertEqual(old_email, self.EMAIL)
self.assertEqual(new_email, u'new+email@example.com')
# Verify that the email is changed
account = account_api.account_info(self.USERNAME)
self.assertEqual(account['email'], u'new+email@example.com')
def test_confirm_email_change_repeat(self):
account_api.create_account(self.USERNAME, self.PASSWORD, self.EMAIL)
activation_key = account_api.request_email_change(
self.USERNAME, u'new+email@example.com', self.PASSWORD
)
# Confirm the change once
account_api.confirm_email_change(activation_key)
# Confirm the change again. The activation code should be
# single-use, so this should raise an error.
with self.assertRaises(account_api.AccountNotAuthorized):
account_api.confirm_email_change(activation_key)
def test_create_account_duplicate_username(self):
account_api.create_account(self.USERNAME, self.PASSWORD, self.EMAIL)
with self.assertRaises(account_api.AccountUserAlreadyExists):
......@@ -155,125 +121,6 @@ class AccountApiTest(TestCase):
def test_activate_account_invalid_key(self):
account_api.activate_account(u'invalid')
@raises(account_api.AccountUserNotFound)
def test_request_email_change_no_user(self):
account_api.request_email_change(u'no_such_user', self.EMAIL, self.PASSWORD)
@ddt.data(*INVALID_EMAILS)
def test_request_email_change_invalid_email(self, invalid_email):
# Create an account with a valid email address
account_api.create_account(self.USERNAME, self.PASSWORD, self.EMAIL)
# Attempt to change the account to an invalid email
with self.assertRaises(account_api.AccountEmailInvalid):
account_api.request_email_change(self.USERNAME, invalid_email, self.PASSWORD)
def test_request_email_change_already_exists(self):
# Create two accounts, both activated
activation_key = account_api.create_account(self.USERNAME, self.PASSWORD, self.EMAIL)
account_api.activate_account(activation_key)
activation_key = account_api.create_account(u'another_user', u'password', u'another+user@example.com')
account_api.activate_account(activation_key)
# Try to change the first user's email to the same as the second user's
with self.assertRaises(account_api.AccountEmailAlreadyExists):
account_api.request_email_change(self.USERNAME, u'another+user@example.com', self.PASSWORD)
def test_request_email_change_duplicates_unactivated_account(self):
# Create two accounts, but the second account is inactive
activation_key = account_api.create_account(self.USERNAME, self.PASSWORD, self.EMAIL)
account_api.activate_account(activation_key)
account_api.create_account(u'another_user', u'password', u'another+user@example.com')
# Try to change the first user's email to the same as the second user's
# Since the second user has not yet activated, this should succeed.
account_api.request_email_change(self.USERNAME, u'another+user@example.com', self.PASSWORD)
def test_request_email_change_same_address(self):
# Create and activate the account
activation_key = account_api.create_account(self.USERNAME, self.PASSWORD, self.EMAIL)
account_api.activate_account(activation_key)
# Try to change the email address to the current address
with self.assertRaises(account_api.AccountEmailAlreadyExists):
account_api.request_email_change(self.USERNAME, self.EMAIL, self.PASSWORD)
def test_request_email_change_wrong_password(self):
account_api.create_account(self.USERNAME, self.PASSWORD, self.EMAIL)
# Use the wrong password
with self.assertRaises(account_api.AccountNotAuthorized):
account_api.request_email_change(self.USERNAME, u'new+email@example.com', u'wrong password')
def test_confirm_email_change_invalid_activation_key(self):
account_api.create_account(self.USERNAME, self.PASSWORD, self.EMAIL)
account_api.request_email_change(self.USERNAME, u'new+email@example.com', self.PASSWORD)
with self.assertRaises(account_api.AccountNotAuthorized):
account_api.confirm_email_change(u'invalid')
def test_confirm_email_change_no_request_pending(self):
account_api.create_account(self.USERNAME, self.PASSWORD, self.EMAIL)
def test_confirm_email_already_exists(self):
account_api.create_account(self.USERNAME, self.PASSWORD, self.EMAIL)
# Request a change
activation_key = account_api.request_email_change(
self.USERNAME, u'new+email@example.com', self.PASSWORD
)
# Another use takes the email before we confirm the change
account_api.create_account(u'other_user', u'password', u'new+email@example.com')
# When we try to confirm our change, we get an error because the email is taken
with self.assertRaises(account_api.AccountEmailAlreadyExists):
account_api.confirm_email_change(activation_key)
# Verify that the email was NOT changed
self.assertEqual(account_api.account_info(self.USERNAME)['email'], self.EMAIL)
def test_confirm_email_no_user_profile(self):
account_api.create_account(self.USERNAME, self.PASSWORD, self.EMAIL)
activation_key = account_api.request_email_change(
self.USERNAME, u'new+email@example.com', self.PASSWORD
)
# This should never happen, but just in case...
UserProfile.objects.get(user__username=self.USERNAME).delete()
with self.assertRaises(account_api.AccountInternalError):
account_api.confirm_email_change(activation_key)
def test_record_email_change_history(self):
account_api.create_account(self.USERNAME, self.PASSWORD, self.EMAIL)
# Change the email once
activation_key = account_api.request_email_change(
self.USERNAME, u'new+email@example.com', self.PASSWORD
)
account_api.confirm_email_change(activation_key)
# Verify that the old email appears in the history
meta = UserProfile.objects.get(user__username=self.USERNAME).get_meta()
self.assertEqual(len(meta['old_emails']), 1)
email, timestamp = meta['old_emails'][0]
self.assertEqual(email, self.EMAIL)
self._assert_is_datetime(timestamp)
# Change the email again
activation_key = account_api.request_email_change(
self.USERNAME, u'another_new+email@example.com', self.PASSWORD
)
account_api.confirm_email_change(activation_key)
# Verify that both emails appear in the history
meta = UserProfile.objects.get(user__username=self.USERNAME).get_meta()
self.assertEqual(len(meta['old_emails']), 2)
email, timestamp = meta['old_emails'][1]
self.assertEqual(email, 'new+email@example.com')
self._assert_is_datetime(timestamp)
@skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in LMS')
def test_request_password_change(self):
# Create and activate an account
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment