email: Convert accounts code to use delivery_email.

A key part of this is the new helper, get_user_by_delivery_email.  Its
verbose name is important for clarity; it should help avoid blind
copy-pasting of get_user (which we'll also want to rename).
Unfortunately, it requires detailed understanding of the context to
figure out which one to use; each is used in about half of call sites.

Another important note is that this PR doesn't migrate get_user calls
in the tests except where not doing so would cause the tests to fail.
This probably deserves a follow-up refactor to avoid bugs here.
This commit is contained in:
Tim Abbott
2018-12-06 15:05:57 -08:00
parent 67f0b1bbca
commit e603237010
22 changed files with 80 additions and 56 deletions

View File

@@ -586,15 +586,15 @@ def user_activity_intervals() -> Tuple[mark_safe, Dict[str, float]]:
).only( ).only(
'start', 'start',
'end', 'end',
'user_profile__email', 'user_profile__delivery_email',
'user_profile__realm__string_id' 'user_profile__realm__string_id'
).order_by( ).order_by(
'user_profile__realm__string_id', 'user_profile__realm__string_id',
'user_profile__email' 'user_profile__delivery_email'
) )
by_string_id = lambda row: row.user_profile.realm.string_id by_string_id = lambda row: row.user_profile.realm.string_id
by_email = lambda row: row.user_profile.email by_email = lambda row: row.user_profile.delivery_email
realm_minutes = {} realm_minutes = {}
@@ -879,7 +879,7 @@ def get_activity(request: HttpRequest) -> HttpResponse:
def get_user_activity_records_for_realm(realm: str, is_bot: bool) -> QuerySet: def get_user_activity_records_for_realm(realm: str, is_bot: bool) -> QuerySet:
fields = [ fields = [
'user_profile__full_name', 'user_profile__full_name',
'user_profile__email', 'user_profile__delivery_email',
'query', 'query',
'client__name', 'client__name',
'count', 'count',
@@ -891,7 +891,7 @@ def get_user_activity_records_for_realm(realm: str, is_bot: bool) -> QuerySet:
user_profile__is_active=True, user_profile__is_active=True,
user_profile__is_bot=is_bot user_profile__is_bot=is_bot
) )
records = records.order_by("user_profile__email", "-last_visit") records = records.order_by("user_profile__delivery_email", "-last_visit")
records = records.select_related('user_profile', 'client').only(*fields) records = records.select_related('user_profile', 'client').only(*fields)
return records return records
@@ -905,7 +905,7 @@ def get_user_activity_records_for_email(email: str) -> List[QuerySet]:
] ]
records = UserActivity.objects.filter( records = UserActivity.objects.filter(
user_profile__email=email user_profile__delivery_email=email
) )
records = records.order_by("-last_visit") records = records.order_by("-last_visit")
records = records.select_related('user_profile', 'client').only(*fields) records = records.select_related('user_profile', 'client').only(*fields)
@@ -1079,7 +1079,7 @@ def realm_user_summary_table(all_records: List[QuerySet],
user_records = {} user_records = {}
def by_email(record: QuerySet) -> str: def by_email(record: QuerySet) -> str:
return record.user_profile.email return record.user_profile.delivery_email
for email, records in itertools.groupby(all_records, by_email): for email, records in itertools.groupby(all_records, by_email):
user_records[email] = get_user_activity_summary(list(records)) user_records[email] = get_user_activity_summary(list(records))
@@ -1150,7 +1150,7 @@ def get_realm_activity(request: HttpRequest, realm_str: str) -> HttpResponse:
except Realm.DoesNotExist: except Realm.DoesNotExist:
return HttpResponseNotFound("Realm %s does not exist" % (realm_str,)) return HttpResponseNotFound("Realm %s does not exist" % (realm_str,))
admin_emails = {admin.email for admin in admins} admin_emails = {admin.delivery_email for admin in admins}
for is_bot, page_title in [(False, 'Humans'), (True, 'Bots')]: for is_bot, page_title in [(False, 'Humans'), (True, 'Bots')]:
all_records = list(get_user_activity_records_for_realm(realm_str, is_bot)) all_records = list(get_user_activity_records_for_realm(realm_str, is_bot))

View File

@@ -24,6 +24,9 @@ with only a few things you need to know to get started.
eventually call the `send_email` function. The most interesting one is eventually call the `send_email` function. The most interesting one is
`send_future_email`. The `ScheduledEmail` entries are eventually processed `send_future_email`. The `ScheduledEmail` entries are eventually processed
by a supervisor job that runs `zerver/management/commands/deliver_email.py`. by a supervisor job that runs `zerver/management/commands/deliver_email.py`.
* Always use `user_profile.delivery_email`, not `user_profile.email`,
when passing data into the `send_email` library. The
`user_profile.email` field may not always be valid.
* A good way to find a bunch of example email pathways is to `git grep` for * A good way to find a bunch of example email pathways is to `git grep` for
`zerver/emails` in the `zerver/` directory. `zerver/emails` in the `zerver/` directory.

View File

@@ -235,7 +235,7 @@ def validate_api_key(request: HttpRequest, role: Optional[str],
raise JsonableError(_("This API is not available to incoming webhook bots.")) raise JsonableError(_("This API is not available to incoming webhook bots."))
request.user = user_profile request.user = user_profile
request._email = user_profile.email request._email = user_profile.delivery_email
process_client(request, user_profile, client_name=client_name) process_client(request, user_profile, client_name=client_name)
return user_profile return user_profile
@@ -257,7 +257,7 @@ def validate_account_and_subdomain(request: HttpRequest, user_profile: UserProfi
request.META["SERVER_NAME"] == "127.0.0.1" and request.META["SERVER_NAME"] == "127.0.0.1" and
request.META["REMOTE_ADDR"] == "127.0.0.1")): request.META["REMOTE_ADDR"] == "127.0.0.1")):
logging.warning("User %s (%s) attempted to access API on wrong subdomain (%s)" % ( logging.warning("User %s (%s) attempted to access API on wrong subdomain (%s)" % (
user_profile.email, user_profile.realm.subdomain, get_subdomain(request))) user_profile.delivery_email, user_profile.realm.subdomain, get_subdomain(request)))
raise JsonableError(_("Account is not associated with this subdomain")) raise JsonableError(_("Account is not associated with this subdomain"))
def access_user_by_api_key(request: HttpRequest, api_key: str, email: Optional[str]=None) -> UserProfile: def access_user_by_api_key(request: HttpRequest, api_key: str, email: Optional[str]=None) -> UserProfile:
@@ -265,7 +265,7 @@ def access_user_by_api_key(request: HttpRequest, api_key: str, email: Optional[s
user_profile = get_user_profile_by_api_key(api_key) user_profile = get_user_profile_by_api_key(api_key)
except UserProfile.DoesNotExist: except UserProfile.DoesNotExist:
raise JsonableError(_("Invalid API key")) raise JsonableError(_("Invalid API key"))
if email is not None and email.lower() != user_profile.email.lower(): if email is not None and email.lower() != user_profile.delivery_email.lower():
# This covers the case that the API key is correct, but for a # This covers the case that the API key is correct, but for a
# different user. We may end up wanting to relaxing this # different user. We may end up wanting to relaxing this
# constraint or give a different error message in the future. # constraint or give a different error message in the future.
@@ -311,7 +311,7 @@ body:
{body} {body}
""".format( """.format(
email=user_profile.email, email=user_profile.delivery_email,
realm=user_profile.realm.string_id, realm=user_profile.realm.string_id,
client_name=request.client.name, client_name=request.client.name,
body=payload, body=payload,
@@ -426,7 +426,7 @@ def do_login(request: HttpRequest, user_profile: UserProfile) -> None:
and also adds helpful data needed by our server logs. and also adds helpful data needed by our server logs.
""" """
django_login(request, user_profile) django_login(request, user_profile)
request._email = user_profile.email request._email = user_profile.delivery_email
process_client(request, user_profile, is_browser_view=True) process_client(request, user_profile, is_browser_view=True)
if settings.TWO_FACTOR_AUTHENTICATION_ENABLED: if settings.TWO_FACTOR_AUTHENTICATION_ENABLED:
# Login with two factor authentication as well. # Login with two factor authentication as well.
@@ -442,7 +442,7 @@ def log_view_func(view_func: ViewFuncT) -> ViewFuncT:
def add_logging_data(view_func: ViewFuncT) -> ViewFuncT: def add_logging_data(view_func: ViewFuncT) -> ViewFuncT:
@wraps(view_func) @wraps(view_func)
def _wrapped_view_func(request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: def _wrapped_view_func(request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
request._email = request.user.email request._email = request.user.delivery_email
process_client(request, request.user, is_browser_view=True, process_client(request, request.user, is_browser_view=True,
query=view_func.__name__) query=view_func.__name__)
return rate_limit()(view_func)(request, *args, **kwargs) return rate_limit()(view_func)(request, *args, **kwargs)
@@ -660,7 +660,7 @@ def authenticate_log_and_execute_json(request: HttpRequest,
process_client(request, user_profile, is_browser_view=True, process_client(request, user_profile, is_browser_view=True,
query=view_func.__name__) query=view_func.__name__)
request._email = user_profile.email request._email = user_profile.delivery_email
return rate_limit()(view_func)(request, user_profile, *args, **kwargs) return rate_limit()(view_func)(request, user_profile, *args, **kwargs)
# Checks if the request is a POST request and that the user is logged # Checks if the request is a POST request and that the user is logged

View File

@@ -24,7 +24,8 @@ from zerver.lib.request import JsonableError
from zerver.lib.send_email import send_email, FromAddress from zerver.lib.send_email import send_email, FromAddress
from zerver.lib.subdomains import get_subdomain, user_matches_subdomain, is_root_domain_available from zerver.lib.subdomains import get_subdomain, user_matches_subdomain, is_root_domain_available
from zerver.lib.users import check_full_name from zerver.lib.users import check_full_name
from zerver.models import Realm, get_user, UserProfile, get_realm, email_to_domain, \ from zerver.models import Realm, get_user_by_delivery_email, UserProfile, get_realm, \
email_to_domain, \
email_allowed_for_realm, DisposableEmailError, DomainNotAllowedForRealmError, \ email_allowed_for_realm, DisposableEmailError, DomainNotAllowedForRealmError, \
EmailContainsPlusError EmailContainsPlusError
from zproject.backends import email_auth_enabled, email_belongs_to_ldap from zproject.backends import email_auth_enabled, email_belongs_to_ldap
@@ -234,7 +235,7 @@ class ZulipPasswordResetForm(PasswordResetForm):
user = None # type: Optional[UserProfile] user = None # type: Optional[UserProfile]
try: try:
user = get_user(email, realm) user = get_user_by_delivery_email(email, realm)
except UserProfile.DoesNotExist: except UserProfile.DoesNotExist:
pass pass
@@ -256,7 +257,8 @@ class ZulipPasswordResetForm(PasswordResetForm):
context=context) context=context)
else: else:
context['active_account_in_realm'] = False context['active_account_in_realm'] = False
active_accounts_in_other_realms = UserProfile.objects.filter(email__iexact=email, is_active=True) active_accounts_in_other_realms = UserProfile.objects.filter(
delivery_email__iexact=email, is_active=True)
if active_accounts_in_other_realms: if active_accounts_in_other_realms:
context['active_accounts_in_other_realms'] = active_accounts_in_other_realms context['active_accounts_in_other_realms'] = active_accounts_in_other_realms
send_email('zerver/emails/password_reset', to_emails=[email], send_email('zerver/emails/password_reset', to_emails=[email],

View File

@@ -87,7 +87,7 @@ from zerver.models import Realm, RealmEmoji, Stream, UserProfile, UserActivity,
get_user_profile_by_id, PreregistrationUser, get_display_recipient, \ get_user_profile_by_id, PreregistrationUser, get_display_recipient, \
get_realm, bulk_get_recipients, get_stream_recipient, get_stream_recipients, \ get_realm, bulk_get_recipients, get_stream_recipient, get_stream_recipients, \
email_allowed_for_realm, email_to_username, display_recipient_cache_key, \ email_allowed_for_realm, email_to_username, display_recipient_cache_key, \
get_user, get_stream_cache_key, active_non_guest_user_ids, \ get_user_by_delivery_email, get_stream_cache_key, active_non_guest_user_ids, \
UserActivityInterval, active_user_ids, get_active_streams, \ UserActivityInterval, active_user_ids, get_active_streams, \
realm_filters_for_realm, RealmFilter, stream_name_in_use, \ realm_filters_for_realm, RealmFilter, stream_name_in_use, \
get_old_unclaimed_attachments, is_cross_realm_bot_email, \ get_old_unclaimed_attachments, is_cross_realm_bot_email, \
@@ -364,12 +364,12 @@ def process_new_human_user(user_profile: UserProfile,
# inactive so we can keep track of the PreregistrationUser we # inactive so we can keep track of the PreregistrationUser we
# actually used for analytics # actually used for analytics
if prereg_user is not None: if prereg_user is not None:
PreregistrationUser.objects.filter(email__iexact=user_profile.email).exclude( PreregistrationUser.objects.filter(email__iexact=user_profile.delivery_email).exclude(
id=prereg_user.id).update(status=0) id=prereg_user.id).update(status=0)
if prereg_user.referred_by is not None: if prereg_user.referred_by is not None:
notify_invites_changed(user_profile) notify_invites_changed(user_profile)
else: else:
PreregistrationUser.objects.filter(email__iexact=user_profile.email).update(status=0) PreregistrationUser.objects.filter(email__iexact=user_profile.delivery_email).update(status=0)
notify_new_user(user_profile) notify_new_user(user_profile)
if user_profile.realm.send_welcome_emails: if user_profile.realm.send_welcome_emails:
@@ -810,7 +810,7 @@ def compute_jabber_user_fullname(email: str) -> str:
def create_mirror_user_if_needed(realm: Realm, email: str, def create_mirror_user_if_needed(realm: Realm, email: str,
email_to_fullname: Callable[[str], str]) -> UserProfile: email_to_fullname: Callable[[str], str]) -> UserProfile:
try: try:
return get_user(email, realm) return get_user_by_delivery_email(email, realm)
except UserProfile.DoesNotExist: except UserProfile.DoesNotExist:
try: try:
# Forge a user for this person # Forge a user for this person
@@ -824,7 +824,7 @@ def create_mirror_user_if_needed(realm: Realm, email: str,
is_mirror_dummy=True, is_mirror_dummy=True,
) )
except IntegrityError: except IntegrityError:
return get_user(email, realm) return get_user_by_delivery_email(email, realm)
def send_welcome_bot_response(message: MutableMapping[str, Any]) -> None: def send_welcome_bot_response(message: MutableMapping[str, Any]) -> None:
welcome_bot = get_system_bot(settings.WELCOME_BOT) welcome_bot = get_system_bot(settings.WELCOME_BOT)
@@ -4440,7 +4440,7 @@ def validate_email_for_realm(target_realm: Realm, email: str) -> None:
email_not_system_bot(email) email_not_system_bot(email)
try: try:
existing_user_profile = get_user(email, target_realm) existing_user_profile = get_user_by_delivery_email(email, target_realm)
except UserProfile.DoesNotExist: except UserProfile.DoesNotExist:
return return

View File

@@ -356,7 +356,7 @@ def delete_user_profile_caches(user_profiles: Iterable['UserProfile']) -> None:
from zerver.lib.users import get_all_api_keys from zerver.lib.users import get_all_api_keys
keys = [] keys = []
for user_profile in user_profiles: for user_profile in user_profiles:
keys.append(user_profile_by_email_cache_key(user_profile.email)) keys.append(user_profile_by_email_cache_key(user_profile.delivery_email))
keys.append(user_profile_by_id_cache_key(user_profile.id)) keys.append(user_profile_by_id_cache_key(user_profile.id))
for api_key in get_all_api_keys(user_profile): for api_key in get_all_api_keys(user_profile):
keys.append(user_profile_by_api_key_cache_key(api_key)) keys.append(user_profile_by_api_key_cache_key(api_key))

View File

@@ -48,7 +48,8 @@ def user_cache_items(items_for_remote_cache: Dict[str, Tuple[UserProfile]],
user_profile: UserProfile) -> None: user_profile: UserProfile) -> None:
for api_key in get_all_api_keys(user_profile): for api_key in get_all_api_keys(user_profile):
items_for_remote_cache[user_profile_by_api_key_cache_key(api_key)] = (user_profile,) items_for_remote_cache[user_profile_by_api_key_cache_key(api_key)] = (user_profile,)
items_for_remote_cache[user_profile_cache_key(user_profile.email, user_profile.realm)] = (user_profile,) items_for_remote_cache[user_profile_cache_key(user_profile.email,
user_profile.realm)] = (user_profile,)
# We have other user_profile caches, but none of them are on the # We have other user_profile caches, but none of them are on the
# core serving path for lots of requests. # core serving path for lots of requests.

View File

@@ -110,7 +110,8 @@ You can use the command list_realms to find ID of the realms in this server."""
# throw an error if they don't exist. # throw an error if they don't exist.
if realm is not None: if realm is not None:
try: try:
return UserProfile.objects.select_related().get(email__iexact=email.strip(), realm=realm) return UserProfile.objects.select_related().get(
delivery_email__iexact=email.strip(), realm=realm)
except UserProfile.DoesNotExist: except UserProfile.DoesNotExist:
raise CommandError("The realm '%s' does not contain a user with email '%s'" % (realm, email)) raise CommandError("The realm '%s' does not contain a user with email '%s'" % (realm, email))
@@ -118,7 +119,7 @@ You can use the command list_realms to find ID of the realms in this server."""
# optimistically try to see if there is exactly one user with # optimistically try to see if there is exactly one user with
# that email; if so, we'll return it. # that email; if so, we'll return it.
try: try:
return UserProfile.objects.select_related().get(email__iexact=email.strip()) return UserProfile.objects.select_related().get(delivery_email__iexact=email.strip())
except MultipleObjectsReturned: except MultipleObjectsReturned:
raise CommandError("This Zulip server contains multiple users with that email " + raise CommandError("This Zulip server contains multiple users with that email " +
"(in different realms); please pass `--realm` " "(in different realms); please pass `--realm` "

View File

@@ -508,7 +508,7 @@ def enqueue_welcome_emails(user: UserProfile, realm_creation: bool=False) -> Non
from_address = FromAddress.SUPPORT from_address = FromAddress.SUPPORT
other_account_count = UserProfile.objects.filter( other_account_count = UserProfile.objects.filter(
email__iexact=user.email).exclude(id=user.id).count() delivery_email__iexact=user.delivery_email).exclude(id=user.id).count()
unsubscribe_link = one_click_unsubscribe_link(user, "welcome") unsubscribe_link = one_click_unsubscribe_link(user, "welcome")
context = common_context(user) context = common_context(user)
context.update({ context.update({

View File

@@ -185,7 +185,7 @@ def access_user_by_id(user_profile: UserProfile, user_id: int,
def get_accounts_for_email(email: str) -> List[Dict[str, Optional[str]]]: def get_accounts_for_email(email: str) -> List[Dict[str, Optional[str]]]:
if settings.PRODUCTION: # nocoverage if settings.PRODUCTION: # nocoverage
return [] return []
profiles = UserProfile.objects.select_related('realm').filter(email__iexact=email.strip(), profiles = UserProfile.objects.select_related('realm').filter(delivery_email__iexact=email.strip(),
is_active=True, is_active=True,
is_bot=False, is_bot=False,
realm__deactivated=False) realm__deactivated=False)

View File

@@ -11,7 +11,7 @@ from django.utils.timezone import now as timezone_now
from zerver.lib.context_managers import lockfile from zerver.lib.context_managers import lockfile
from zerver.lib.logging_util import log_to_file from zerver.lib.logging_util import log_to_file
from zerver.lib.management import sleep_forever from zerver.lib.management import sleep_forever
from zerver.models import ScheduledMessage, Message, get_user from zerver.models import ScheduledMessage, Message, get_user_by_delivery_email
from zerver.lib.actions import do_send_messages from zerver.lib.actions import do_send_messages
from zerver.lib.addressee import Addressee from zerver.lib.addressee import Addressee
@@ -44,7 +44,7 @@ Usage: ./manage.py deliver_scheduled_messages
if delivery_type == ScheduledMessage.SEND_LATER: if delivery_type == ScheduledMessage.SEND_LATER:
message.sender = original_sender message.sender = original_sender
elif delivery_type == ScheduledMessage.REMIND: elif delivery_type == ScheduledMessage.REMIND:
message.sender = get_user(settings.REMINDER_BOT, original_sender.realm) message.sender = get_user_by_delivery_email(settings.REMINDER_BOT, original_sender.realm)
return {'message': message, 'stream': scheduled_message.stream, return {'message': message, 'stream': scheduled_message.stream,
'realm': scheduled_message.realm} 'realm': scheduled_message.realm}

View File

@@ -1784,16 +1784,32 @@ def get_user_profile_by_id(uid: int) -> UserProfile:
@cache_with_key(user_profile_by_email_cache_key, timeout=3600*24*7) @cache_with_key(user_profile_by_email_cache_key, timeout=3600*24*7)
def get_user_profile_by_email(email: str) -> UserProfile: def get_user_profile_by_email(email: str) -> UserProfile:
return UserProfile.objects.select_related().get(email__iexact=email.strip()) return UserProfile.objects.select_related().get(delivery_email__iexact=email.strip())
@cache_with_key(user_profile_by_api_key_cache_key, timeout=3600*24*7) @cache_with_key(user_profile_by_api_key_cache_key, timeout=3600*24*7)
def get_user_profile_by_api_key(api_key: str) -> UserProfile: def get_user_profile_by_api_key(api_key: str) -> UserProfile:
return UserProfile.objects.select_related().get(api_key=api_key) return UserProfile.objects.select_related().get(api_key=api_key)
def get_user_by_delivery_email(email: str, realm: Realm) -> UserProfile:
# Fetches users by delivery_email for use in
# authentication/registration contexts. Do not use for user-facing
# views (e.g. Zulip API endpoints); for that, you want get_user.
return UserProfile.objects.select_related().get(delivery_email__iexact=email.strip(), realm=realm)
@cache_with_key(user_profile_cache_key, timeout=3600*24*7) @cache_with_key(user_profile_cache_key, timeout=3600*24*7)
def get_user(email: str, realm: Realm) -> UserProfile: def get_user(email: str, realm: Realm) -> UserProfile:
# Fetches the user by its visible-to-other users username (in the
# `email` field). For use in API contexts; do not use in
# authentication/registration contexts; for that, you need to use
# get_user_by_delivery_email.
return UserProfile.objects.select_related().get(email__iexact=email.strip(), realm=realm) return UserProfile.objects.select_related().get(email__iexact=email.strip(), realm=realm)
def get_active_user_by_delivery_email(email: str, realm: Realm) -> UserProfile:
user_profile = get_user_by_delivery_email(email, realm)
if not user_profile.is_active:
raise UserProfile.DoesNotExist()
return user_profile
def get_active_user(email: str, realm: Realm) -> UserProfile: def get_active_user(email: str, realm: Realm) -> UserProfile:
user_profile = get_user(email, realm) user_profile = get_user(email, realm)
if not user_profile.is_active: if not user_profile.is_active:
@@ -1858,7 +1874,7 @@ def get_source_profile(email: str, string_id: str) -> Optional[UserProfile]:
return None return None
try: try:
return get_user(email, realm) return get_user_by_delivery_email(email, realm)
except UserProfile.DoesNotExist: except UserProfile.DoesNotExist:
return None return None

View File

@@ -45,7 +45,7 @@ from zerver.models import (
get_display_recipient, Message, Realm, Recipient, Stream, Subscription, get_display_recipient, Message, Realm, Recipient, Stream, Subscription,
DefaultStream, UserProfile, get_user_profile_by_id, active_non_guest_user_ids, DefaultStream, UserProfile, get_user_profile_by_id, active_non_guest_user_ids,
get_default_stream_groups, flush_per_request_caches, DefaultStreamGroup, get_default_stream_groups, flush_per_request_caches, DefaultStreamGroup,
get_client, get_client, get_user
) )
from zerver.lib.actions import ( from zerver.lib.actions import (
@@ -53,7 +53,7 @@ from zerver.lib.actions import (
do_create_realm, do_remove_default_stream, bulk_get_subscriber_user_ids, do_create_realm, do_remove_default_stream, bulk_get_subscriber_user_ids,
gather_subscriptions_helper, bulk_add_subscriptions, bulk_remove_subscriptions, gather_subscriptions_helper, bulk_add_subscriptions, bulk_remove_subscriptions,
gather_subscriptions, get_default_streams_for_realm, get_realm, get_stream, gather_subscriptions, get_default_streams_for_realm, get_realm, get_stream,
get_user, set_default_streams, check_stream_name, do_get_streams, set_default_streams, check_stream_name, do_get_streams,
create_stream_if_needed, create_streams_if_needed, create_stream_if_needed, create_streams_if_needed,
ensure_stream, ensure_stream,
do_deactivate_stream, do_deactivate_stream,

View File

@@ -21,7 +21,7 @@ from zerver.models import UserProfile, Recipient, \
Realm, RealmDomain, UserActivity, UserHotspot, \ Realm, RealmDomain, UserActivity, UserHotspot, \
get_user, get_realm, get_client, get_stream, get_stream_recipient, \ get_user, get_realm, get_client, get_stream, get_stream_recipient, \
get_source_profile, Message, get_context_for_message, \ get_source_profile, Message, get_context_for_message, \
ScheduledEmail, check_valid_user_ids, \ ScheduledEmail, check_valid_user_ids, get_user, \
get_user_by_id_in_realm_including_cross_realm, CustomProfileField get_user_by_id_in_realm_including_cross_realm, CustomProfileField
from zerver.lib.avatar import avatar_url from zerver.lib.avatar import avatar_url

View File

@@ -4,7 +4,7 @@ from django.shortcuts import render, redirect
from django.views.decorators.http import require_GET from django.views.decorators.http import require_GET
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from zerver.models import get_realm, get_user from zerver.models import get_realm, get_user_by_delivery_email
from zerver.lib.notifications import enqueue_welcome_emails from zerver.lib.notifications import enqueue_welcome_emails
from zerver.lib.response import json_success from zerver.lib.response import json_success
from zproject.email_backends import ( from zproject.email_backends import (
@@ -94,7 +94,7 @@ def generate_all_emails(request: HttpRequest) -> HttpResponse:
# Email change successful # Email change successful
key = Confirmation.objects.filter(type=Confirmation.EMAIL_CHANGE).latest('id').confirmation_key key = Confirmation.objects.filter(type=Confirmation.EMAIL_CHANGE).latest('id').confirmation_key
url = confirmation_url(key, realm.host, Confirmation.EMAIL_CHANGE) url = confirmation_url(key, realm.host, Confirmation.EMAIL_CHANGE)
user_profile = get_user(registered_email, realm) user_profile = get_user_by_delivery_email(registered_email, realm)
result = client.get(url) result = client.get(url)
assert result.status_code == 200 assert result.status_code == 200
@@ -106,6 +106,6 @@ def generate_all_emails(request: HttpRequest) -> HttpResponse:
enqueue_welcome_emails(user_profile) enqueue_welcome_emails(user_profile)
# Follow up day1 day2 emails for admin user # Follow up day1 day2 emails for admin user
enqueue_welcome_emails(get_user("iago@zulip.com", realm), realm_creation=True) enqueue_welcome_emails(get_user_by_delivery_email("iago@zulip.com", realm), realm_creation=True)
return redirect(email_page) return redirect(email_page)

View File

@@ -15,7 +15,8 @@ from zerver.lib.request import has_request_variables, REQ, JsonableError
from zerver.lib.response import json_success, json_error from zerver.lib.response import json_success, json_error
from zerver.lib.timestamp import datetime_to_timestamp from zerver.lib.timestamp import datetime_to_timestamp
from zerver.lib.validator import check_bool from zerver.lib.validator import check_bool
from zerver.models import UserActivity, UserPresence, UserProfile, get_active_user from zerver.models import UserActivity, UserPresence, UserProfile, \
get_active_user_by_delivery_email
def get_status_list(requesting_user_profile: UserProfile) -> Dict[str, Any]: def get_status_list(requesting_user_profile: UserProfile) -> Dict[str, Any]:
return {'presences': get_status_dict(requesting_user_profile), return {'presences': get_status_dict(requesting_user_profile),
@@ -24,7 +25,7 @@ def get_status_list(requesting_user_profile: UserProfile) -> Dict[str, Any]:
def get_presence_backend(request: HttpRequest, user_profile: UserProfile, def get_presence_backend(request: HttpRequest, user_profile: UserProfile,
email: str) -> HttpResponse: email: str) -> HttpResponse:
try: try:
target = get_active_user(email, user_profile.realm) target = get_active_user_by_delivery_email(email, user_profile.realm)
except UserProfile.DoesNotExist: except UserProfile.DoesNotExist:
return json_error(_('No such user')) return json_error(_('No such user'))
if target.is_bot: if target.is_bot:

View File

@@ -14,7 +14,7 @@ from django.core import validators
from zerver.context_processors import get_realm_from_request from zerver.context_processors import get_realm_from_request
from zerver.models import UserProfile, Realm, Stream, MultiuseInvite, \ from zerver.models import UserProfile, Realm, Stream, MultiuseInvite, \
name_changes_disabled, email_to_username, email_allowed_for_realm, \ name_changes_disabled, email_to_username, email_allowed_for_realm, \
get_realm, get_user, get_default_stream_groups, DisposableEmailError, \ get_realm, get_user_by_delivery_email, get_default_stream_groups, DisposableEmailError, \
DomainNotAllowedForRealmError, get_source_profile, EmailContainsPlusError DomainNotAllowedForRealmError, get_source_profile, EmailContainsPlusError
from zerver.lib.send_email import send_email, FromAddress from zerver.lib.send_email import send_email, FromAddress
from zerver.lib.events import do_events_register from zerver.lib.events import do_events_register
@@ -219,7 +219,7 @@ def accounts_register(request: HttpRequest) -> HttpResponse:
if not realm_creation: if not realm_creation:
try: try:
existing_user_profile = get_user(email, realm) # type: Optional[UserProfile] existing_user_profile = get_user_by_delivery_email(email, realm) # type: Optional[UserProfile]
except UserProfile.DoesNotExist: except UserProfile.DoesNotExist:
existing_user_profile = None existing_user_profile = None
else: else:

View File

@@ -36,7 +36,7 @@ from zerver.lib.users import check_valid_bot_type, check_bot_creation_policy, \
validate_user_custom_profile_data validate_user_custom_profile_data
from zerver.lib.utils import generate_api_key, generate_random_token from zerver.lib.utils import generate_api_key, generate_random_token
from zerver.models import UserProfile, Stream, Message, email_allowed_for_realm, \ from zerver.models import UserProfile, Stream, Message, email_allowed_for_realm, \
get_user, Service, get_user_including_cross_realm, \ get_user_by_delivery_email, Service, get_user_including_cross_realm, \
DomainNotAllowedForRealmError, DisposableEmailError, get_user_profile_by_id_in_realm, \ DomainNotAllowedForRealmError, DisposableEmailError, get_user_profile_by_id_in_realm, \
EmailContainsPlusError, get_user_by_id_in_realm_including_cross_realm EmailContainsPlusError, get_user_by_id_in_realm_including_cross_realm
@@ -284,7 +284,7 @@ def add_bot_backend(
# We validate client-side as well # We validate client-side as well
return json_error(_('Bad name or username')) return json_error(_('Bad name or username'))
try: try:
get_user(email, user_profile.realm) get_user_by_delivery_email(email, user_profile.realm)
return json_error(_("Username already in use")) return json_error(_("Username already in use"))
except UserProfile.DoesNotExist: except UserProfile.DoesNotExist:
pass pass
@@ -471,7 +471,7 @@ def create_user_backend(request: HttpRequest, user_profile: UserProfile,
return json_error(_("Email addresses containing + are not allowed.")) return json_error(_("Email addresses containing + are not allowed."))
try: try:
get_user(email, user_profile.realm) get_user_by_delivery_email(email, user_profile.realm)
return json_error(_("Email '%s' already in use") % (email,)) return json_error(_("Email '%s' already in use") % (email,))
except UserProfile.DoesNotExist: except UserProfile.DoesNotExist:
pass pass

View File

@@ -14,7 +14,7 @@ from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_error, json_success from zerver.lib.response import json_error, json_success
from zerver.lib.webhooks.common import check_send_webhook_message, \ from zerver.lib.webhooks.common import check_send_webhook_message, \
UnexpectedWebhookEventType UnexpectedWebhookEventType
from zerver.models import Realm, UserProfile, get_user from zerver.models import Realm, UserProfile, get_user_by_delivery_email
IGNORED_EVENTS = [ IGNORED_EVENTS = [
'comment_created', # we handle issue_update event instead 'comment_created', # we handle issue_update event instead
@@ -112,7 +112,7 @@ def get_issue_string(payload: Dict[str, Any], issue_id: Optional[str]=None) -> s
def get_assignee_mention(assignee_email: str, realm: Realm) -> str: def get_assignee_mention(assignee_email: str, realm: Realm) -> str:
if assignee_email != '': if assignee_email != '':
try: try:
assignee_name = get_user(assignee_email, realm).full_name assignee_name = get_user_by_delivery_email(assignee_email, realm).full_name
except UserProfile.DoesNotExist: except UserProfile.DoesNotExist:
assignee_name = assignee_email assignee_name = assignee_email
return u"**{}**".format(assignee_name) return u"**{}**".format(assignee_name)

View File

@@ -3,7 +3,7 @@ import ujson
from zerver.lib.test_classes import WebhookTestCase from zerver.lib.test_classes import WebhookTestCase
from zerver.lib.send_email import FromAddress from zerver.lib.send_email import FromAddress
from zerver.models import Recipient, get_user, get_realm from zerver.models import Recipient, get_user_by_delivery_email, get_realm
from zerver.webhooks.teamcity.view import MISCONFIGURED_PAYLOAD_TYPE_ERROR_MESSAGE from zerver.webhooks.teamcity.view import MISCONFIGURED_PAYLOAD_TYPE_ERROR_MESSAGE
class TeamcityHookTests(WebhookTestCase): class TeamcityHookTests(WebhookTestCase):
@@ -44,7 +44,7 @@ class TeamcityHookTests(WebhookTestCase):
def test_non_generic_payload_ignore_pm_notification(self) -> None: def test_non_generic_payload_ignore_pm_notification(self) -> None:
expected_message = MISCONFIGURED_PAYLOAD_TYPE_ERROR_MESSAGE.format( expected_message = MISCONFIGURED_PAYLOAD_TYPE_ERROR_MESSAGE.format(
bot_name=get_user('webhook-bot@zulip.com', get_realm('zulip')).full_name, bot_name=get_user_by_delivery_email('webhook-bot@zulip.com', get_realm('zulip')).full_name,
support_email=FromAddress.SUPPORT support_email=FromAddress.SUPPORT
).strip() ).strip()
payload = self.get_body('slack_non_generic_payload') payload = self.get_body('slack_non_generic_payload')

View File

@@ -4,7 +4,7 @@ from typing import Any
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from zerver.models import UserProfile, get_realm, get_user from zerver.models import UserProfile, get_realm, get_user_by_delivery_email
class Command(BaseCommand): class Command(BaseCommand):
help = """Sync your API key from ~/.zuliprc into your development instance""" help = """Sync your API key from ~/.zuliprc into your development instance"""
@@ -21,7 +21,7 @@ class Command(BaseCommand):
try: try:
realm = get_realm("zulip") realm = get_realm("zulip")
user_profile = get_user(email, realm) user_profile = get_user_by_delivery_email(email, realm)
user_profile.api_key = api_key user_profile.api_key = api_key
user_profile.save(update_fields=["api_key"]) user_profile.save(update_fields=["api_key"])
except UserProfile.DoesNotExist: except UserProfile.DoesNotExist:

View File

@@ -23,7 +23,7 @@ from zerver.lib.request import JsonableError
from zerver.lib.subdomains import user_matches_subdomain, get_subdomain from zerver.lib.subdomains import user_matches_subdomain, get_subdomain
from zerver.lib.users import check_full_name from zerver.lib.users import check_full_name
from zerver.models import UserProfile, Realm, get_user_profile_by_id, \ from zerver.models import UserProfile, Realm, get_user_profile_by_id, \
remote_user_to_email, email_to_username, get_realm, get_user remote_user_to_email, email_to_username, get_realm, get_user_by_delivery_email
def pad_method_dict(method_dict: Dict[str, bool]) -> Dict[str, bool]: def pad_method_dict(method_dict: Dict[str, bool]) -> Dict[str, bool]:
"""Pads an authentication methods dict to contain all auth backends """Pads an authentication methods dict to contain all auth backends
@@ -83,13 +83,13 @@ def require_email_format_usernames(realm: Optional[Realm]=None) -> bool:
def common_get_active_user(email: str, realm: Realm, def common_get_active_user(email: str, realm: Realm,
return_data: Optional[Dict[str, Any]]=None) -> Optional[UserProfile]: return_data: Optional[Dict[str, Any]]=None) -> Optional[UserProfile]:
try: try:
user_profile = get_user(email, realm) user_profile = get_user_by_delivery_email(email, realm)
except UserProfile.DoesNotExist: except UserProfile.DoesNotExist:
# If the user doesn't have an account in the target realm, we # If the user doesn't have an account in the target realm, we
# check whether they might have an account in another realm, # check whether they might have an account in another realm,
# and if so, provide a helpful error message via # and if so, provide a helpful error message via
# `invalid_subdomain`. # `invalid_subdomain`.
if not UserProfile.objects.filter(email__iexact=email).exists(): if not UserProfile.objects.filter(delivery_email__iexact=email).exists():
return None return None
if return_data is not None: if return_data is not None:
return_data['invalid_subdomain'] = True return_data['invalid_subdomain'] = True