mirror of
https://github.com/zulip/zulip.git
synced 2025-11-04 22:13:26 +00:00
python: Reformat with Black, except quotes.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
committed by
Tim Abbott
parent
5028c081cb
commit
11741543da
@@ -38,8 +38,7 @@ def check_full_name(full_name_raw: str) -> str:
|
||||
if len(full_name) < UserProfile.MIN_NAME_LENGTH:
|
||||
raise JsonableError(_("Name too short!"))
|
||||
for character in full_name:
|
||||
if (unicodedata.category(character)[0] == 'C' or
|
||||
character in UserProfile.NAME_INVALID_CHARS):
|
||||
if unicodedata.category(character)[0] == 'C' or character in UserProfile.NAME_INVALID_CHARS:
|
||||
raise JsonableError(_("Invalid characters in name!"))
|
||||
# Names ending with e.g. `|15` could be ambiguous for
|
||||
# sloppily-written parsers of our Markdown syntax for mentioning
|
||||
@@ -49,6 +48,7 @@ def check_full_name(full_name_raw: str) -> str:
|
||||
raise JsonableError(_("Invalid format!"))
|
||||
return full_name
|
||||
|
||||
|
||||
# NOTE: We don't try to absolutely prevent 2 bots from having the same
|
||||
# name (e.g. you can get there by reactivating a deactivated bot after
|
||||
# making a new bot with the same name). This is just a check designed
|
||||
@@ -63,16 +63,18 @@ def check_bot_name_available(realm_id: int, full_name: str) -> None:
|
||||
if dup_exists:
|
||||
raise JsonableError(_("Name is already in use!"))
|
||||
|
||||
|
||||
def check_short_name(short_name_raw: str) -> str:
|
||||
short_name = short_name_raw.strip()
|
||||
if len(short_name) == 0:
|
||||
raise JsonableError(_("Bad name or username"))
|
||||
return short_name
|
||||
|
||||
def check_valid_bot_config(bot_type: int, service_name: str,
|
||||
config_data: Dict[str, str]) -> None:
|
||||
|
||||
def check_valid_bot_config(bot_type: int, service_name: str, config_data: Dict[str, str]) -> None:
|
||||
if bot_type == UserProfile.INCOMING_WEBHOOK_BOT:
|
||||
from zerver.lib.integrations import WEBHOOK_INTEGRATIONS
|
||||
|
||||
config_options = None
|
||||
for integration in WEBHOOK_INTEGRATIONS:
|
||||
if integration.name == service_name:
|
||||
@@ -84,20 +86,22 @@ def check_valid_bot_config(bot_type: int, service_name: str,
|
||||
|
||||
missing_keys = set(config_options.keys()) - set(config_data.keys())
|
||||
if missing_keys:
|
||||
raise JsonableError(_("Missing configuration parameters: {}").format(
|
||||
missing_keys,
|
||||
))
|
||||
raise JsonableError(
|
||||
_("Missing configuration parameters: {}").format(
|
||||
missing_keys,
|
||||
)
|
||||
)
|
||||
|
||||
for key, validator in config_options.items():
|
||||
value = config_data[key]
|
||||
error = validator(key, value)
|
||||
if error:
|
||||
raise JsonableError(_("Invalid {} value {} ({})").format(
|
||||
key, value, error))
|
||||
raise JsonableError(_("Invalid {} value {} ({})").format(key, value, error))
|
||||
|
||||
elif bot_type == UserProfile.EMBEDDED_BOT:
|
||||
try:
|
||||
from zerver.lib.bot_lib import get_bot_handler
|
||||
|
||||
bot_handler = get_bot_handler(service_name)
|
||||
if hasattr(bot_handler, 'validate_config'):
|
||||
bot_handler.validate_config(config_data)
|
||||
@@ -109,14 +113,19 @@ def check_valid_bot_config(bot_type: int, service_name: str,
|
||||
# error message.
|
||||
raise JsonableError(_("Invalid configuration data!"))
|
||||
|
||||
|
||||
# Adds an outgoing webhook or embedded bot service.
|
||||
def add_service(name: str, user_profile: UserProfile, base_url: Optional[str]=None,
|
||||
interface: Optional[int]=None, token: Optional[str]=None) -> None:
|
||||
Service.objects.create(name=name,
|
||||
user_profile=user_profile,
|
||||
base_url=base_url,
|
||||
interface=interface,
|
||||
token=token)
|
||||
def add_service(
|
||||
name: str,
|
||||
user_profile: UserProfile,
|
||||
base_url: Optional[str] = None,
|
||||
interface: Optional[int] = None,
|
||||
token: Optional[str] = None,
|
||||
) -> None:
|
||||
Service.objects.create(
|
||||
name=name, user_profile=user_profile, base_url=base_url, interface=interface, token=token
|
||||
)
|
||||
|
||||
|
||||
def check_bot_creation_policy(user_profile: UserProfile, bot_type: int) -> None:
|
||||
# Realm administrators can always add bot
|
||||
@@ -127,23 +136,30 @@ def check_bot_creation_policy(user_profile: UserProfile, bot_type: int) -> None:
|
||||
return
|
||||
if user_profile.realm.bot_creation_policy == Realm.BOT_CREATION_ADMINS_ONLY:
|
||||
raise OrganizationAdministratorRequired()
|
||||
if user_profile.realm.bot_creation_policy == Realm.BOT_CREATION_LIMIT_GENERIC_BOTS and \
|
||||
bot_type == UserProfile.DEFAULT_BOT:
|
||||
if (
|
||||
user_profile.realm.bot_creation_policy == Realm.BOT_CREATION_LIMIT_GENERIC_BOTS
|
||||
and bot_type == UserProfile.DEFAULT_BOT
|
||||
):
|
||||
raise OrganizationAdministratorRequired()
|
||||
|
||||
|
||||
def check_valid_bot_type(user_profile: UserProfile, bot_type: int) -> None:
|
||||
if bot_type not in user_profile.allowed_bot_types:
|
||||
raise JsonableError(_('Invalid bot type'))
|
||||
|
||||
|
||||
def check_valid_interface_type(interface_type: Optional[int]) -> None:
|
||||
if interface_type not in Service.ALLOWED_INTERFACE_TYPES:
|
||||
raise JsonableError(_('Invalid interface type'))
|
||||
|
||||
|
||||
def is_administrator_role(role: int) -> bool:
|
||||
return role in {UserProfile.ROLE_REALM_ADMINISTRATOR, UserProfile.ROLE_REALM_OWNER}
|
||||
|
||||
def bulk_get_users(emails: List[str], realm: Optional[Realm],
|
||||
base_query: 'QuerySet[UserProfile]'=None) -> Dict[str, UserProfile]:
|
||||
|
||||
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
|
||||
query = UserProfile.objects.filter(realm=realm, is_active=True)
|
||||
@@ -167,9 +183,7 @@ def bulk_get_users(emails: List[str], realm: Optional[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
|
||||
where_clause = "upper(zerver_userprofile.email::text) IN (SELECT upper(email) FROM unnest(%s) AS email)"
|
||||
return query.select_related("realm").extra(
|
||||
where=[where_clause],
|
||||
params=(emails,))
|
||||
return query.select_related("realm").extra(where=[where_clause], params=(emails,))
|
||||
|
||||
def user_to_email(user_profile: UserProfile) -> str:
|
||||
return user_profile.email.lower()
|
||||
@@ -183,9 +197,11 @@ def bulk_get_users(emails: List[str], realm: Optional[Realm],
|
||||
id_fetcher=user_to_email,
|
||||
)
|
||||
|
||||
|
||||
def get_user_id(user: UserProfile) -> int:
|
||||
return user.id
|
||||
|
||||
|
||||
def user_ids_to_users(user_ids: Sequence[int], realm: Realm) -> List[UserProfile]:
|
||||
# TODO: Consider adding a flag to control whether deactivated
|
||||
# users should be included.
|
||||
@@ -211,6 +227,7 @@ def user_ids_to_users(user_ids: Sequence[int], realm: Realm) -> List[UserProfile
|
||||
raise JsonableError(_("Invalid user ID: {}").format(user_profile.id))
|
||||
return user_profiles
|
||||
|
||||
|
||||
def access_bot_by_id(user_profile: UserProfile, user_id: int) -> UserProfile:
|
||||
try:
|
||||
target = get_user_profile_by_id_in_realm(user_id, user_profile.realm)
|
||||
@@ -222,12 +239,13 @@ def access_bot_by_id(user_profile: UserProfile, user_id: int) -> UserProfile:
|
||||
raise JsonableError(_("Insufficient permission"))
|
||||
return target
|
||||
|
||||
|
||||
def access_user_by_id(
|
||||
user_profile: UserProfile,
|
||||
target_user_id: int,
|
||||
*,
|
||||
allow_deactivated: bool=False,
|
||||
allow_bots: bool=False,
|
||||
allow_deactivated: bool = False,
|
||||
allow_bots: bool = False,
|
||||
for_admin: bool,
|
||||
) -> UserProfile:
|
||||
"""Master function for accessing another user by ID in API code;
|
||||
@@ -250,26 +268,41 @@ def access_user_by_id(
|
||||
raise JsonableError(_("Insufficient permission"))
|
||||
return target
|
||||
|
||||
|
||||
def get_accounts_for_email(email: str) -> List[Dict[str, Optional[str]]]:
|
||||
profiles = UserProfile.objects.select_related('realm').filter(delivery_email__iexact=email.strip(),
|
||||
is_active=True,
|
||||
realm__deactivated=False,
|
||||
is_bot=False).order_by('date_joined')
|
||||
return [{"realm_name": profile.realm.name,
|
||||
"string_id": profile.realm.string_id,
|
||||
"full_name": profile.full_name,
|
||||
"avatar": avatar_url(profile)}
|
||||
for profile in profiles]
|
||||
profiles = (
|
||||
UserProfile.objects.select_related('realm')
|
||||
.filter(
|
||||
delivery_email__iexact=email.strip(),
|
||||
is_active=True,
|
||||
realm__deactivated=False,
|
||||
is_bot=False,
|
||||
)
|
||||
.order_by('date_joined')
|
||||
)
|
||||
return [
|
||||
{
|
||||
"realm_name": profile.realm.name,
|
||||
"string_id": profile.realm.string_id,
|
||||
"full_name": profile.full_name,
|
||||
"avatar": avatar_url(profile),
|
||||
}
|
||||
for profile in profiles
|
||||
]
|
||||
|
||||
|
||||
def get_api_key(user_profile: UserProfile) -> str:
|
||||
return user_profile.api_key
|
||||
|
||||
|
||||
def get_all_api_keys(user_profile: UserProfile) -> List[str]:
|
||||
# Users can only have one API key for now
|
||||
return [user_profile.api_key]
|
||||
|
||||
def validate_user_custom_profile_field(realm_id: int, field: CustomProfileField,
|
||||
value: Union[int, str, List[int]]) -> Union[int, str, List[int]]:
|
||||
|
||||
def validate_user_custom_profile_field(
|
||||
realm_id: int, field: CustomProfileField, value: Union[int, str, List[int]]
|
||||
) -> Union[int, str, List[int]]:
|
||||
validators = CustomProfileField.FIELD_VALIDATORS
|
||||
field_type = field.field_type
|
||||
var_name = f'{field.name}'
|
||||
@@ -288,8 +321,10 @@ def validate_user_custom_profile_field(realm_id: int, field: CustomProfileField,
|
||||
else:
|
||||
raise AssertionError("Invalid field type")
|
||||
|
||||
def validate_user_custom_profile_data(realm_id: int,
|
||||
profile_data: List[Dict[str, Union[int, str, List[int]]]]) -> None:
|
||||
|
||||
def validate_user_custom_profile_data(
|
||||
realm_id: int, profile_data: List[Dict[str, Union[int, str, List[int]]]]
|
||||
) -> None:
|
||||
# This function validate all custom field values according to their field type.
|
||||
for item in profile_data:
|
||||
field_id = item['id']
|
||||
@@ -303,6 +338,7 @@ def validate_user_custom_profile_data(realm_id: int,
|
||||
except ValidationError as error:
|
||||
raise JsonableError(error.message)
|
||||
|
||||
|
||||
def compute_show_invites_and_add_streams(user_profile: Optional[UserProfile]) -> Tuple[bool, bool]:
|
||||
if user_profile is None:
|
||||
return False, False
|
||||
@@ -318,9 +354,15 @@ def compute_show_invites_and_add_streams(user_profile: Optional[UserProfile]) ->
|
||||
|
||||
return True, True
|
||||
|
||||
def format_user_row(realm: Realm, acting_user: Optional[UserProfile], row: Dict[str, Any],
|
||||
client_gravatar: bool, user_avatar_url_field_optional: bool,
|
||||
custom_profile_field_data: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
||||
|
||||
def format_user_row(
|
||||
realm: Realm,
|
||||
acting_user: Optional[UserProfile],
|
||||
row: Dict[str, Any],
|
||||
client_gravatar: bool,
|
||||
user_avatar_url_field_optional: bool,
|
||||
custom_profile_field_data: Optional[Dict[str, Any]] = None,
|
||||
) -> Dict[str, Any]:
|
||||
"""Formats a user row returned by a database fetch using
|
||||
.values(*realm_user_dict_fields) into a dictionary representation
|
||||
of that user for API delivery to clients. The acting_user
|
||||
@@ -341,8 +383,8 @@ def format_user_row(realm: Realm, acting_user: Optional[UserProfile], row: Dict[
|
||||
is_bot=is_bot,
|
||||
full_name=row['full_name'],
|
||||
timezone=canonicalize_timezone(row['timezone']),
|
||||
is_active = row['is_active'],
|
||||
date_joined = row['date_joined'].isoformat(),
|
||||
is_active=row['is_active'],
|
||||
date_joined=row['date_joined'].isoformat(),
|
||||
)
|
||||
|
||||
# Zulip clients that support using `GET /avatar/{user_id}` as a
|
||||
@@ -365,16 +407,20 @@ def format_user_row(realm: Realm, acting_user: Optional[UserProfile], row: Dict[
|
||||
# different optimization for organizations with 10,000s of users.
|
||||
include_avatar_url = not user_avatar_url_field_optional or not row['long_term_idle']
|
||||
if include_avatar_url:
|
||||
result['avatar_url'] = get_avatar_field(user_id=row['id'],
|
||||
realm_id=realm.id,
|
||||
email=row['delivery_email'],
|
||||
avatar_source=row['avatar_source'],
|
||||
avatar_version=row['avatar_version'],
|
||||
medium=False,
|
||||
client_gravatar=client_gravatar)
|
||||
result['avatar_url'] = get_avatar_field(
|
||||
user_id=row['id'],
|
||||
realm_id=realm.id,
|
||||
email=row['delivery_email'],
|
||||
avatar_source=row['avatar_source'],
|
||||
avatar_version=row['avatar_version'],
|
||||
medium=False,
|
||||
client_gravatar=client_gravatar,
|
||||
)
|
||||
|
||||
if acting_user is not None and (realm.email_address_visibility == Realm.EMAIL_ADDRESS_VISIBILITY_ADMINS and
|
||||
acting_user.is_realm_admin):
|
||||
if acting_user is not None and (
|
||||
realm.email_address_visibility == Realm.EMAIL_ADDRESS_VISIBILITY_ADMINS
|
||||
and acting_user.is_realm_admin
|
||||
):
|
||||
result['delivery_email'] = row['delivery_email']
|
||||
|
||||
if is_bot:
|
||||
@@ -388,6 +434,7 @@ def format_user_row(realm: Realm, acting_user: Optional[UserProfile], row: Dict[
|
||||
result['profile_data'] = custom_profile_field_data
|
||||
return result
|
||||
|
||||
|
||||
def user_profile_to_user_row(user_profile: UserProfile) -> Dict[str, Any]:
|
||||
# What we're trying to do is simulate the user_profile having been
|
||||
# fetched from a QuerySet using `.values(*realm_user_dict_fields)`
|
||||
@@ -404,16 +451,18 @@ def user_profile_to_user_row(user_profile: UserProfile) -> Dict[str, Any]:
|
||||
# This could be potentially simplified in the future by
|
||||
# changing realm_user_dict_fields to name the bot owner with
|
||||
# the less readable `bot_owner` (instead of `bot_owner_id`).
|
||||
user_row = model_to_dict(user_profile,
|
||||
fields=[*realm_user_dict_fields, 'bot_owner'])
|
||||
user_row = model_to_dict(user_profile, fields=[*realm_user_dict_fields, 'bot_owner'])
|
||||
user_row['bot_owner_id'] = user_row['bot_owner']
|
||||
del user_row['bot_owner']
|
||||
return user_row
|
||||
|
||||
|
||||
def get_cross_realm_dicts() -> List[Dict[str, Any]]:
|
||||
users = bulk_get_users(list(settings.CROSS_REALM_BOT_EMAILS), None,
|
||||
base_query=UserProfile.objects.filter(
|
||||
realm__string_id=settings.SYSTEM_BOT_REALM)).values()
|
||||
users = bulk_get_users(
|
||||
list(settings.CROSS_REALM_BOT_EMAILS),
|
||||
None,
|
||||
base_query=UserProfile.objects.filter(realm__string_id=settings.SYSTEM_BOT_REALM),
|
||||
).values()
|
||||
result = []
|
||||
for user in users:
|
||||
# Important: We filter here, is addition to in
|
||||
@@ -427,17 +476,23 @@ def get_cross_realm_dicts() -> List[Dict[str, Any]]:
|
||||
# just set bot_owner_id=None.
|
||||
user_row['bot_owner_id'] = None
|
||||
|
||||
result.append(format_user_row(user.realm,
|
||||
acting_user=user,
|
||||
row=user_row,
|
||||
client_gravatar=False,
|
||||
user_avatar_url_field_optional=False,
|
||||
custom_profile_field_data=None))
|
||||
result.append(
|
||||
format_user_row(
|
||||
user.realm,
|
||||
acting_user=user,
|
||||
row=user_row,
|
||||
client_gravatar=False,
|
||||
user_avatar_url_field_optional=False,
|
||||
custom_profile_field_data=None,
|
||||
)
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
def get_custom_profile_field_values(custom_profile_field_values:
|
||||
List[CustomProfileFieldValue]) -> Dict[int, Dict[str, Any]]:
|
||||
|
||||
def get_custom_profile_field_values(
|
||||
custom_profile_field_values: List[CustomProfileFieldValue],
|
||||
) -> Dict[int, Dict[str, Any]]:
|
||||
profiles_by_user_id: Dict[int, Dict[str, Any]] = defaultdict(dict)
|
||||
for profile_field in custom_profile_field_values:
|
||||
user_id = profile_field.user_profile_id
|
||||
@@ -452,9 +507,16 @@ def get_custom_profile_field_values(custom_profile_field_values:
|
||||
}
|
||||
return profiles_by_user_id
|
||||
|
||||
def get_raw_user_data(realm: Realm, acting_user: Optional[UserProfile], *, target_user: Optional[UserProfile]=None,
|
||||
client_gravatar: bool, user_avatar_url_field_optional: bool,
|
||||
include_custom_profile_fields: bool=True) -> Dict[int, Dict[str, str]]:
|
||||
|
||||
def get_raw_user_data(
|
||||
realm: Realm,
|
||||
acting_user: Optional[UserProfile],
|
||||
*,
|
||||
target_user: Optional[UserProfile] = None,
|
||||
client_gravatar: bool,
|
||||
user_avatar_url_field_optional: bool,
|
||||
include_custom_profile_fields: bool = True,
|
||||
) -> Dict[int, Dict[str, str]]:
|
||||
"""Fetches data about the target user(s) appropriate for sending to
|
||||
acting_user via the standard format for the Zulip API. If
|
||||
target_user is None, we fetch all users in the realm.
|
||||
@@ -482,11 +544,12 @@ def get_raw_user_data(realm: Realm, acting_user: Optional[UserProfile], *, targe
|
||||
if profiles_by_user_id is not None:
|
||||
custom_profile_field_data = profiles_by_user_id.get(row['id'], {})
|
||||
|
||||
result[row['id']] = format_user_row(realm,
|
||||
acting_user=acting_user,
|
||||
row=row,
|
||||
client_gravatar=client_gravatar,
|
||||
user_avatar_url_field_optional=user_avatar_url_field_optional,
|
||||
custom_profile_field_data=custom_profile_field_data,
|
||||
)
|
||||
result[row['id']] = format_user_row(
|
||||
realm,
|
||||
acting_user=acting_user,
|
||||
row=row,
|
||||
client_gravatar=client_gravatar,
|
||||
user_avatar_url_field_optional=user_avatar_url_field_optional,
|
||||
custom_profile_field_data=custom_profile_field_data,
|
||||
)
|
||||
return result
|
||||
|
||||
Reference in New Issue
Block a user