Use standard functions for parsing/validating email addresses.

This adds two new functions for parsing out the domain and username
from an email address, and switches our backend to use them and
django.core.validators.valid_email() rather than custom parsing and
raw email.split("@").

(imported from commit 3d6e997d66908811eccb5f82f2f7fe349b40f238)
This commit is contained in:
Tim Abbott
2013-07-18 12:48:56 -04:00
parent bece588897
commit 18f94de07f
7 changed files with 42 additions and 24 deletions

View File

@@ -9,7 +9,8 @@ from zephyr.models import Realm, Stream, UserProfile, UserActivity, \
DefaultStream, UserPresence, MAX_SUBJECT_LENGTH, \
MAX_MESSAGE_LENGTH, get_client, get_stream, get_recipient, get_huddle, \
get_user_profile_by_id, PreregistrationUser, get_display_recipient, \
to_dict_cache_key, get_realm, stringify_message_dict, bulk_get_recipients
to_dict_cache_key, get_realm, stringify_message_dict, bulk_get_recipients, \
email_to_domain, email_to_username
from django.db import transaction, IntegrityError
from django.db.models import F, Q
from django.core.exceptions import ValidationError
@@ -190,7 +191,7 @@ def create_mit_user_if_needed(realm, email):
try:
# Forge a user for this person
return create_user(email, initial_password(email), realm,
compute_mit_user_fullname(email), email.split("@")[0],
compute_mit_user_fullname(email), email_to_username(email),
active=False)
except IntegrityError:
# Unless we raced with another thread doing the same
@@ -1358,12 +1359,14 @@ def do_invite_users(user_profile, invitee_emails, streams):
if email == '':
continue
if not validators.email_re.match(email):
try:
validators.validate_email(email)
except ValidationError:
errors.append((email, "Invalid address."))
continue
if user_profile.realm.restricted_to_domain and \
email.split('@', 1)[-1].lower() != user_profile.realm.domain.lower():
email_to_domain(email).lower() != user_profile.realm.domain.lower():
errors.append((email, "Outside your domain."))
continue

View File

@@ -2,7 +2,7 @@ from __future__ import absolute_import
from zephyr.lib.initial_password import initial_password
from zephyr.models import Realm, Stream, UserProfile, Huddle, \
Subscription, Recipient, Client, get_huddle_hash
Subscription, Recipient, Client, get_huddle_hash, email_to_domain
from zephyr.lib.create_user import create_user_profile
def bulk_create_realms(realm_list):
@@ -31,7 +31,7 @@ def bulk_create_users(realms, users_raw):
# Now create user_profiles
profiles_to_create = []
for (email, full_name, short_name, active) in users:
domain = email.split('@')[1]
domain = email_to_domain(email)
profile = create_user_profile(realms[domain], email,
initial_password(email), active, False,
full_name, short_name, None)

View File

@@ -8,7 +8,7 @@ from django.core.exceptions import ValidationError
from django.db.utils import IntegrityError
from django.core import validators
from zephyr.models import Realm
from zephyr.models import Realm, email_to_username
from zephyr.lib.actions import do_create_user
from zephyr.views import notify_new_user
from zephyr.lib.initial_password import initial_password
@@ -67,7 +67,7 @@ parameters, or specify no parameters for interactive user creation.""")
try:
notify_new_user(do_create_user(email, initial_password(email),
realm, full_name, email.split('@')[0]),
realm, full_name, email_to_username(email)),
internal=True)
except IntegrityError:
raise CommandError("User already exists.")

View File

@@ -6,7 +6,8 @@ from django.utils.timezone import now
from django.contrib.sites.models import Site
from zephyr.models import Message, UserProfile, Stream, Recipient, Client, \
Subscription, Huddle, get_huddle, Realm, UserMessage, \
get_huddle_hash, clear_database, get_client, get_user_profile_by_id
get_huddle_hash, clear_database, get_client, get_user_profile_by_id, \
email_to_domain, email_to_username
from zephyr.lib.actions import do_send_message, set_default_streams, \
do_activate_user, do_deactivate, do_change_password
from zephyr.lib.parallel import run_parallel
@@ -32,7 +33,7 @@ settings.TORNADO_SERVER = None
def create_users(realms, name_list):
user_set = set()
for full_name, email in name_list:
(short_name, domain) = email.split("@")
short_name = email_to_username(email)
user_set.add((email, full_name, short_name, True))
bulk_create_users(realms, user_set)
@@ -336,7 +337,7 @@ def restore_saved_messages():
sender_email = old_message["sender_email"]
domain = sender_email.split('@')[1]
domain = email_to_domain(sender_email)
realm_set.add(domain)
if old_message["sender_email"] not in email_set:
@@ -447,7 +448,7 @@ def restore_saved_messages():
message = Message()
sender_email = old_message["sender_email"]
domain = sender_email.split('@')[1]
domain = email_to_domain(sender_email)
realm = realms[domain]
message.sender = users[sender_email]

View File

@@ -72,6 +72,18 @@ class Realm(models.Model):
('administer', "Administer a realm"),
)
# These functions should only be used on email addresses that have
# been validated via django.core.validators.validate_email
#
# Note that we need to use some care, since can you have multiple @-signs; e.g.
# "tabbott@test"@humbughq.com
# is valid email address
def email_to_username(email):
return "@".join(email.split("@")[:-1])
def email_to_domain(email):
return email.split("@")[-1]
class UserProfile(AbstractBaseUser, PermissionsMixin):
# Fields from models.AbstractUser minus last_name and first_name,
# which we don't use; email is modified to make it indexed and unique.

View File

@@ -9,7 +9,7 @@ from django.db.models import Q
from zephyr.models import Message, UserProfile, Stream, Recipient, Subscription, \
get_display_recipient, Realm, Client, \
PreregistrationUser, UserMessage, \
get_user_profile_by_email
get_user_profile_by_email, email_to_domain
from zephyr.tornadoviews import json_get_updates, api_get_messages
from zephyr.decorator import RespondAsynchronously, RequestVariableConversionError, profiled
from zephyr.lib.initial_password import initial_password
@@ -2558,7 +2558,7 @@ class UserPresenceTests(AuthedTestCase):
self.assertEqual(json['presences'][email][client]['status'], 'idle')
# We only want @humbughq.com emails
for email in json['presences'].keys():
self.assertEqual(email.split('@')[1], 'humbughq.com')
self.assertEqual(email_to_domain(email), 'humbughq.com')
class UnreadCountTests(AuthedTestCase):

View File

@@ -20,7 +20,8 @@ from zephyr.models import Message, UserProfile, Stream, Subscription, \
PreregistrationUser, get_client, MitUser, UserActivity, \
MAX_SUBJECT_LENGTH, get_stream, bulk_get_streams, UserPresence, \
get_recipient, valid_stream_name, to_dict_cache_key, to_dict_cache_key_id, \
extract_message_dict, stringify_message_dict, parse_usermessage_flags
extract_message_dict, stringify_message_dict, parse_usermessage_flags, \
email_to_domain, email_to_username
from zephyr.lib.actions import do_remove_subscription, bulk_remove_subscriptions, \
do_change_password, create_mit_user_if_needed, do_change_full_name, \
do_change_enable_desktop_notifications, do_change_enter_sends, do_change_enable_sounds, \
@@ -233,6 +234,7 @@ def accounts_register(request):
email = prereg_user.email
mit_beta_user = isinstance(confirmation.content_object, MitUser)
validators.validate_email(email)
# If someone invited you, you are joining their realm regardless
# of your e-mail address.
#
@@ -240,7 +242,7 @@ def accounts_register(request):
if not mit_beta_user and prereg_user.referred_by:
domain = prereg_user.referred_by.realm.domain
else:
domain = email.split('@')[-1]
domain = email_to_domain(email)
try:
if mit_beta_user:
@@ -259,7 +261,7 @@ def accounts_register(request):
if form.is_valid():
password = form.cleaned_data['password']
full_name = form.cleaned_data['full_name']
short_name = email.split('@')[0]
short_name = email_to_username(email)
(realm, _) = Realm.objects.get_or_create(domain=domain)
first_in_realm = len(UserProfile.objects.filter(realm=realm)) == 0
@@ -328,7 +330,7 @@ def accounts_register(request):
@login_required(login_url = settings.HOME_NOT_LOGGED_IN)
def accounts_accept_terms(request):
email = request.user.email
company_name = email.split('@')[-1]
domain = email_to_domain(email)
if request.method == "POST":
form = ToSForm(request.POST)
if form.is_valid():
@@ -347,7 +349,7 @@ def accounts_accept_terms(request):
else:
form = ToSForm()
return render_to_response('zephyr/accounts_accept_terms.html',
{ 'form': form, 'company_name': company_name, 'email': email },
{ 'form': form, 'company_name': domain, 'email': email },
context_instance=RequestContext(request))
def api_endpoint_docs(request):
@@ -1012,14 +1014,14 @@ def mit_to_mit(user_profile, email):
# We have to handle this specially, inferring the domain from the
# e-mail address, because the recipient may not existing in Humbug
# and we may need to make a stub MIT user on the fly.
if not validators.email_re.match(email):
try:
validators.validate_email(email)
except ValidationError:
return False
if user_profile.realm.domain != "mit.edu":
return False
domain = email_to_domain(email)
domain = email.split("@", 1)[1]
return user_profile.realm.domain == domain
return user_profile.realm.domain == "mit.edu" and domain == "mit.edu"
def create_mirrored_message_users(request, user_profile, recipients):
if "sender" not in request.POST: