2020-06-11 00:54:34 +02:00
|
|
|
from typing import Optional
|
|
|
|
|
2020-08-07 01:09:47 +02:00
|
|
|
import orjson
|
2013-02-12 21:14:48 +01:00
|
|
|
from django.contrib.auth.models import UserManager
|
2017-04-15 04:03:56 +02:00
|
|
|
from django.utils.timezone import now as timezone_now
|
2020-06-11 00:54:34 +02:00
|
|
|
|
2020-12-20 13:03:32 +01:00
|
|
|
from zerver.lib.hotspots import copy_hotspots
|
2020-06-11 00:54:34 +02:00
|
|
|
from zerver.lib.upload import copy_avatar
|
2018-08-01 11:18:37 +02:00
|
|
|
from zerver.lib.utils import generate_api_key
|
users: Remove redundant get_role_for_new_user in lib/create_user.py.
The function get_role_for_new_user was added to get role from the
invited_as value, as invited_as values were one of (1,2,3,4)
previously, but it was then changed to be the actual role value,
i.e. one of (100, 200, 400, 600), in 1f8f227444.
So, we can safely remove this function now and use invited_as value
directly and handle realm_creation case by using an if condition.
2021-04-30 14:37:48 +02:00
|
|
|
from zerver.models import Realm, Recipient, Stream, Subscription, UserProfile, get_fake_email_domain
|
2018-06-06 14:30:26 +02:00
|
|
|
|
2016-06-16 22:22:26 +02:00
|
|
|
|
2018-05-22 18:13:51 +02:00
|
|
|
def copy_user_settings(source_profile: UserProfile, target_profile: UserProfile) -> None:
|
2020-06-26 19:35:42 +02:00
|
|
|
# Important note: Code run from here to configure the user's
|
|
|
|
# settings should not call send_event, as that would cause clients
|
|
|
|
# to throw an exception (we haven't sent the realm_user/add event
|
|
|
|
# yet, so that event will include the updated details of target_profile).
|
|
|
|
#
|
|
|
|
# Note that this function will do at least one save() on target_profile.
|
2018-05-21 19:30:26 +02:00
|
|
|
for settings_name in UserProfile.property_types:
|
|
|
|
value = getattr(source_profile, settings_name)
|
|
|
|
setattr(target_profile, settings_name, value)
|
|
|
|
|
|
|
|
for settings_name in UserProfile.notification_setting_types:
|
|
|
|
value = getattr(source_profile, settings_name)
|
|
|
|
setattr(target_profile, settings_name, value)
|
|
|
|
|
2018-05-25 19:24:30 +02:00
|
|
|
setattr(target_profile, "full_name", source_profile.full_name)
|
2018-06-13 20:16:51 +02:00
|
|
|
setattr(target_profile, "enter_sends", source_profile.enter_sends)
|
2018-06-06 14:30:26 +02:00
|
|
|
target_profile.save()
|
|
|
|
|
|
|
|
if source_profile.avatar_source == UserProfile.AVATAR_FROM_USER:
|
|
|
|
from zerver.lib.actions import do_change_avatar_fields
|
2021-02-12 08:19:30 +01:00
|
|
|
|
|
|
|
do_change_avatar_fields(
|
|
|
|
target_profile,
|
|
|
|
UserProfile.AVATAR_FROM_USER,
|
|
|
|
skip_notify=True,
|
|
|
|
acting_user=target_profile,
|
|
|
|
)
|
2018-06-06 14:30:26 +02:00
|
|
|
copy_avatar(source_profile, target_profile)
|
2018-05-25 19:24:30 +02:00
|
|
|
|
2020-12-20 13:03:32 +01:00
|
|
|
copy_hotspots(source_profile, target_profile)
|
2018-06-13 14:10:53 +02:00
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
|
2020-12-19 17:51:38 +01:00
|
|
|
def get_display_email_address(user_profile: UserProfile) -> str:
|
2019-09-23 22:38:13 +02:00
|
|
|
if not user_profile.email_address_is_realm_public():
|
2021-01-18 14:34:54 +01:00
|
|
|
return f"user{user_profile.id}@{get_fake_email_domain(user_profile.realm)}"
|
2018-12-06 23:17:46 +01:00
|
|
|
return user_profile.delivery_email
|
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
|
2013-04-01 16:57:50 +02:00
|
|
|
# create_user_profile is based on Django's User.objects.create_user,
|
2013-02-12 21:14:48 +01:00
|
|
|
# except that we don't save to the database so it can used in
|
|
|
|
# bulk_creates
|
2013-04-01 16:57:50 +02:00
|
|
|
#
|
|
|
|
# Only use this for bulk_create -- for normal usage one should use
|
|
|
|
# create_user (below) which will also make the Subscription and
|
|
|
|
# Recipient objects
|
2021-02-12 08:19:30 +01:00
|
|
|
def create_user_profile(
|
|
|
|
realm: Realm,
|
|
|
|
email: str,
|
|
|
|
password: Optional[str],
|
|
|
|
active: bool,
|
|
|
|
bot_type: Optional[int],
|
|
|
|
full_name: str,
|
|
|
|
bot_owner: Optional[UserProfile],
|
|
|
|
is_mirror_dummy: bool,
|
|
|
|
tos_version: Optional[str],
|
|
|
|
timezone: Optional[str],
|
|
|
|
tutorial_status: str = UserProfile.TUTORIAL_WAITING,
|
|
|
|
enter_sends: bool = False,
|
|
|
|
force_id: Optional[int] = None,
|
|
|
|
) -> UserProfile:
|
2017-04-15 04:03:56 +02:00
|
|
|
now = timezone_now()
|
2013-02-12 21:14:48 +01:00
|
|
|
email = UserManager.normalize_email(email)
|
2014-10-01 02:17:11 +02:00
|
|
|
|
2020-05-02 18:42:30 +02:00
|
|
|
extra_kwargs = {}
|
|
|
|
if force_id is not None:
|
2021-02-12 08:20:45 +01:00
|
|
|
extra_kwargs["id"] = force_id
|
2020-05-02 18:42:30 +02:00
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
user_profile = UserProfile(
|
|
|
|
is_staff=False,
|
|
|
|
is_active=active,
|
|
|
|
full_name=full_name,
|
|
|
|
last_login=now,
|
|
|
|
date_joined=now,
|
|
|
|
realm=realm,
|
|
|
|
is_bot=bool(bot_type),
|
|
|
|
bot_type=bot_type,
|
|
|
|
bot_owner=bot_owner,
|
|
|
|
is_mirror_dummy=is_mirror_dummy,
|
|
|
|
tos_version=tos_version,
|
|
|
|
timezone=timezone,
|
|
|
|
tutorial_status=tutorial_status,
|
|
|
|
enter_sends=enter_sends,
|
|
|
|
onboarding_steps=orjson.dumps([]).decode(),
|
|
|
|
default_language=realm.default_language,
|
|
|
|
twenty_four_hour_time=realm.default_twenty_four_hour_time,
|
|
|
|
delivery_email=email,
|
|
|
|
**extra_kwargs,
|
|
|
|
)
|
2016-05-18 20:23:03 +02:00
|
|
|
if bot_type or not active:
|
2013-11-12 18:20:05 +01:00
|
|
|
password = None
|
2019-09-23 22:38:13 +02:00
|
|
|
if user_profile.email_address_is_realm_public():
|
2018-12-06 23:17:46 +01:00
|
|
|
# If emails are visible to everyone, we can set this here and save a DB query
|
2020-12-19 17:51:38 +01:00
|
|
|
user_profile.email = get_display_email_address(user_profile)
|
2013-11-12 18:20:05 +01:00
|
|
|
user_profile.set_password(password)
|
2018-08-01 11:18:37 +02:00
|
|
|
user_profile.api_key = generate_api_key()
|
2013-04-01 16:57:50 +02:00
|
|
|
return user_profile
|
2013-02-12 21:14:48 +01:00
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
|
|
|
|
def create_user(
|
|
|
|
email: str,
|
|
|
|
password: Optional[str],
|
|
|
|
realm: Realm,
|
|
|
|
full_name: str,
|
|
|
|
active: bool = True,
|
|
|
|
role: Optional[int] = None,
|
|
|
|
bot_type: Optional[int] = None,
|
|
|
|
bot_owner: Optional[UserProfile] = None,
|
|
|
|
tos_version: Optional[str] = None,
|
|
|
|
timezone: str = "",
|
|
|
|
avatar_source: str = UserProfile.AVATAR_FROM_GRAVATAR,
|
|
|
|
is_mirror_dummy: bool = False,
|
|
|
|
default_sending_stream: Optional[Stream] = None,
|
|
|
|
default_events_register_stream: Optional[Stream] = None,
|
|
|
|
default_all_public_streams: Optional[bool] = None,
|
|
|
|
source_profile: Optional[UserProfile] = None,
|
|
|
|
force_id: Optional[int] = None,
|
|
|
|
) -> UserProfile:
|
2020-07-16 14:10:43 +02:00
|
|
|
user_profile = create_user_profile(
|
|
|
|
realm,
|
|
|
|
email,
|
|
|
|
password,
|
|
|
|
active,
|
|
|
|
bot_type,
|
|
|
|
full_name,
|
|
|
|
bot_owner,
|
|
|
|
is_mirror_dummy,
|
|
|
|
tos_version,
|
2020-05-02 18:42:30 +02:00
|
|
|
timezone,
|
2021-02-12 08:19:30 +01:00
|
|
|
force_id=force_id,
|
2020-07-16 14:10:43 +02:00
|
|
|
)
|
2013-06-14 20:03:11 +02:00
|
|
|
user_profile.avatar_source = avatar_source
|
2017-05-04 15:19:06 +02:00
|
|
|
user_profile.timezone = timezone
|
2014-02-11 18:43:30 +01:00
|
|
|
user_profile.default_sending_stream = default_sending_stream
|
|
|
|
user_profile.default_events_register_stream = default_events_register_stream
|
2020-06-03 01:11:36 +02:00
|
|
|
if role is not None:
|
|
|
|
user_profile.role = role
|
2014-02-11 18:43:30 +01:00
|
|
|
# Allow the ORM default to be used if not provided
|
|
|
|
if default_all_public_streams is not None:
|
|
|
|
user_profile.default_all_public_streams = default_all_public_streams
|
2018-05-22 18:13:51 +02:00
|
|
|
# If a source profile was specified, we copy settings from that
|
|
|
|
# user. Note that this is positioned in a way that overrides
|
|
|
|
# other arguments passed in, which is correct for most defaults
|
|
|
|
# like timezone where the source profile likely has a better value
|
|
|
|
# than the guess. As we decide on details like avatars and full
|
|
|
|
# names for this feature, we may want to move it.
|
|
|
|
if source_profile is not None:
|
2018-06-06 14:30:26 +02:00
|
|
|
# copy_user_settings saves the attribute values so a secondary
|
|
|
|
# save is not required.
|
2018-05-22 18:13:51 +02:00
|
|
|
copy_user_settings(source_profile, user_profile)
|
2018-06-06 14:30:26 +02:00
|
|
|
else:
|
|
|
|
user_profile.save()
|
2018-05-22 18:13:51 +02:00
|
|
|
|
2019-09-23 22:38:13 +02:00
|
|
|
if not user_profile.email_address_is_realm_public():
|
2018-12-06 23:17:46 +01:00
|
|
|
# With restricted access to email addresses, we can't generate
|
|
|
|
# the fake email addresses we use for display purposes without
|
|
|
|
# a User ID, which isn't generated until the .save() above.
|
2020-12-19 17:51:38 +01:00
|
|
|
user_profile.email = get_display_email_address(user_profile)
|
2021-02-12 08:20:45 +01:00
|
|
|
user_profile.save(update_fields=["email"])
|
2018-12-06 23:17:46 +01:00
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
recipient = Recipient.objects.create(type_id=user_profile.id, type=Recipient.PERSONAL)
|
2019-11-28 16:56:04 +01:00
|
|
|
user_profile.recipient = recipient
|
|
|
|
user_profile.save(update_fields=["recipient"])
|
|
|
|
|
2021-02-14 00:03:40 +01:00
|
|
|
Subscription.objects.create(
|
|
|
|
user_profile=user_profile, recipient=recipient, is_user_active=user_profile.is_active
|
|
|
|
)
|
2013-04-01 16:57:50 +02:00
|
|
|
return user_profile
|