2017-11-16 02:28:50 +01:00
|
|
|
from typing import Dict, List, Optional, Text
|
2017-02-08 04:39:55 +01:00
|
|
|
|
2017-11-16 02:28:50 +01:00
|
|
|
from django.db.models.query import QuerySet
|
2017-02-08 04:39:55 +01:00
|
|
|
from django.utils.translation import ugettext as _
|
|
|
|
|
2017-11-27 23:33:13 +01:00
|
|
|
from zerver.lib.cache import generic_bulk_cached_fetch, user_profile_cache_key_id
|
2017-02-08 04:39:55 +01:00
|
|
|
from zerver.lib.request import JsonableError
|
2017-11-01 10:04:16 +01:00
|
|
|
from zerver.models import UserProfile, Service, Realm, \
|
2017-11-27 23:33:13 +01:00
|
|
|
get_user_profile_by_id
|
2017-02-08 04:39:55 +01:00
|
|
|
|
2017-11-05 11:15:10 +01:00
|
|
|
def check_full_name(full_name_raw: Text) -> Text:
|
2017-02-08 04:51:01 +01:00
|
|
|
full_name = full_name_raw.strip()
|
|
|
|
if len(full_name) > UserProfile.MAX_NAME_LENGTH:
|
|
|
|
raise JsonableError(_("Name too long!"))
|
2017-05-12 04:21:49 +02:00
|
|
|
if len(full_name) < UserProfile.MIN_NAME_LENGTH:
|
|
|
|
raise JsonableError(_("Name too short!"))
|
2017-02-08 04:51:01 +01:00
|
|
|
if list(set(full_name).intersection(UserProfile.NAME_INVALID_CHARS)):
|
|
|
|
raise JsonableError(_("Invalid characters in name!"))
|
|
|
|
return full_name
|
|
|
|
|
2017-11-05 11:15:10 +01:00
|
|
|
def check_short_name(short_name_raw: Text) -> Text:
|
2017-06-21 13:46:58 +02:00
|
|
|
short_name = short_name_raw.strip()
|
|
|
|
if len(short_name) == 0:
|
|
|
|
raise JsonableError(_("Bad name or username"))
|
|
|
|
return short_name
|
|
|
|
|
2017-11-05 11:15:10 +01:00
|
|
|
def check_valid_bot_type(bot_type: int) -> None:
|
2017-05-30 19:19:48 +02:00
|
|
|
if bot_type not in UserProfile.ALLOWED_BOT_TYPES:
|
|
|
|
raise JsonableError(_('Invalid bot type'))
|
2017-07-03 18:35:12 +02:00
|
|
|
|
2017-11-05 11:15:10 +01:00
|
|
|
def check_valid_interface_type(interface_type: int) -> None:
|
2017-07-03 18:35:12 +02:00
|
|
|
if interface_type not in Service.ALLOWED_INTERFACE_TYPES:
|
|
|
|
raise JsonableError(_('Invalid interface type'))
|
2017-11-01 10:04:16 +01:00
|
|
|
|
2017-11-16 02:28:50 +01:00
|
|
|
def bulk_get_users(emails: List[str], realm: Optional[Realm],
|
|
|
|
base_query: 'QuerySet[UserProfile]'=None) -> Dict[str, UserProfile]:
|
|
|
|
if base_query is None:
|
|
|
|
assert realm is not None
|
|
|
|
base_query = UserProfile.objects.filter(realm=realm, is_active=True)
|
2017-11-27 23:33:13 +01:00
|
|
|
realm_id = realm.id
|
|
|
|
else:
|
|
|
|
# WARNING: Here we use an invalid realm_id, just to keep the
|
|
|
|
# cache independent of the per-realm caches. If you're using
|
|
|
|
# this flow, you'll need to re-do any filters in base_query in
|
|
|
|
# the code itself; base_query is just a perf optimization.
|
|
|
|
realm_id = 0
|
2017-11-16 02:28:50 +01:00
|
|
|
|
|
|
|
def fetch_users_by_email(emails: List[str]) -> List[UserProfile]:
|
|
|
|
# This should be just
|
|
|
|
#
|
|
|
|
# UserProfile.objects.select_related("realm").filter(email__iexact__in=emails,
|
|
|
|
# realm=realm)
|
|
|
|
#
|
|
|
|
# But chaining __in and __iexact doesn't work with Django's
|
|
|
|
# ORM, so we have the following hack to construct the relevant where clause
|
|
|
|
if len(emails) == 0:
|
|
|
|
return []
|
|
|
|
|
|
|
|
upper_list = ", ".join(["UPPER(%s)"] * len(emails))
|
|
|
|
where_clause = "UPPER(zerver_userprofile.email::text) IN (%s)" % (upper_list,)
|
|
|
|
return base_query.select_related("realm").extra(
|
|
|
|
where=[where_clause],
|
|
|
|
params=emails)
|
|
|
|
|
|
|
|
return generic_bulk_cached_fetch(
|
2017-11-27 23:33:13 +01:00
|
|
|
lambda email: user_profile_cache_key_id(email, realm_id),
|
2017-11-16 02:28:50 +01:00
|
|
|
fetch_users_by_email,
|
|
|
|
[email.lower() for email in emails],
|
|
|
|
id_fetcher=lambda user_profile: user_profile.email.lower()
|
|
|
|
)
|
|
|
|
|
2017-11-01 10:04:16 +01:00
|
|
|
def user_ids_to_users(user_ids: List[int], realm: Realm) -> List[UserProfile]:
|
|
|
|
# TODO: Change this to do a single bulk query with
|
|
|
|
# generic_bulk_cached_fetch; it'll be faster.
|
|
|
|
#
|
|
|
|
# TODO: Consider adding a flag to control whether deactivated
|
|
|
|
# users should be included.
|
|
|
|
user_profiles = []
|
|
|
|
for user_id in user_ids:
|
|
|
|
try:
|
|
|
|
user_profile = get_user_profile_by_id(user_id)
|
|
|
|
except UserProfile.DoesNotExist:
|
|
|
|
raise JsonableError(_("Invalid user ID: %s" % (user_id,)))
|
|
|
|
if user_profile.realm != realm:
|
|
|
|
raise JsonableError(_("Invalid user ID: %s" % (user_id,)))
|
|
|
|
user_profiles.append(user_profile)
|
|
|
|
return user_profiles
|