mirror of
https://github.com/zulip/zulip.git
synced 2025-11-09 00:18:12 +00:00
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:
@@ -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))
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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],
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|
||||||
|
|||||||
@@ -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` "
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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')
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user