2013-04-23 18:51:17 +02:00
|
|
|
|
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
|
2016-06-16 22:22:26 +02:00
|
|
|
from zerver.models import UserProfile, Recipient, Subscription, Realm, Stream
|
2018-06-06 14:30:26 +02:00
|
|
|
from zerver.lib.upload import copy_avatar
|
2018-06-13 14:10:53 +02:00
|
|
|
from zerver.lib.hotspots import copy_hotpots
|
2018-08-01 11:18:37 +02:00
|
|
|
from zerver.lib.utils import generate_api_key
|
2018-06-06 14:30:26 +02:00
|
|
|
|
2013-02-12 21:14:48 +01:00
|
|
|
import base64
|
2013-06-18 23:55:55 +02:00
|
|
|
import ujson
|
2013-07-30 01:59:24 +02:00
|
|
|
import os
|
2013-05-30 20:21:26 +02:00
|
|
|
import string
|
2013-05-08 15:27:27 +02:00
|
|
|
|
2018-05-11 01:40:23 +02:00
|
|
|
from typing import Optional
|
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:
|
2018-05-21 19:30:26 +02:00
|
|
|
"""Warning: Does not save, to avoid extra database queries"""
|
|
|
|
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
|
|
|
|
do_change_avatar_fields(target_profile, UserProfile.AVATAR_FROM_USER)
|
|
|
|
copy_avatar(source_profile, target_profile)
|
2018-05-25 19:24:30 +02:00
|
|
|
|
2018-06-13 14:10:53 +02:00
|
|
|
copy_hotpots(source_profile, target_profile)
|
|
|
|
|
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
|
2018-05-11 01:40:23 +02:00
|
|
|
def create_user_profile(realm: Realm, email: str, password: Optional[str],
|
|
|
|
active: bool, bot_type: Optional[int], full_name: str,
|
|
|
|
short_name: str, bot_owner: Optional[UserProfile],
|
|
|
|
is_mirror_dummy: bool, tos_version: Optional[str],
|
|
|
|
timezone: Optional[str],
|
|
|
|
tutorial_status: Optional[str] = UserProfile.TUTORIAL_WAITING,
|
2017-12-19 18:51:39 +01:00
|
|
|
enter_sends: bool = False) -> 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
|
|
|
|
2013-04-01 16:57:50 +02:00
|
|
|
user_profile = UserProfile(email=email, is_staff=False, is_active=active,
|
|
|
|
full_name=full_name, short_name=short_name,
|
|
|
|
last_login=now, date_joined=now, realm=realm,
|
2016-05-18 20:23:03 +02:00
|
|
|
pointer=-1, is_bot=bool(bot_type), bot_type=bot_type,
|
2017-01-12 11:14:13 +01:00
|
|
|
bot_owner=bot_owner, is_mirror_dummy=is_mirror_dummy,
|
2017-05-04 15:19:06 +02:00
|
|
|
tos_version=tos_version, timezone=timezone,
|
2017-03-22 23:26:35 +01:00
|
|
|
tutorial_status=tutorial_status,
|
2017-03-29 23:21:44 +02:00
|
|
|
enter_sends=enter_sends,
|
2016-08-04 17:32:41 +02:00
|
|
|
onboarding_steps=ujson.dumps([]),
|
2018-03-30 22:38:16 +02:00
|
|
|
default_language=realm.default_language,
|
models: Create delivery_email field in userprofile.
This commit creates a new field called delivery_email. For now, it is
exactly the same as email upon user profile creation and should stay
that way even when email is changed, and is used only for sending
outgoing email from Zulip.
The purpose of this field is to support an upcoming option where the
existing `email` field in Zulip becomes effectively the user's
"display email" address, as part of making it possible for users
actual email addresses (that can receive email, stored in the
delivery_email field) to not be available to other non-administrator
users in the organization.
Because the `email` field is used in numerous places in display code,
in the API, and in database queries, the shortest path to implementing
this "private email" feature is to keep "email" as-is in those parts
of the codebase, and just set the existing "email" ("display email")
model field to be something generated like
"username@zulip.example.com" for display purposes.
Eventually, we'll want to do further refactoring, either in the form
of having both `display_email` and `delivery_email` as fields, or
renaming "email" to "username".
2018-07-05 20:08:30 +02:00
|
|
|
twenty_four_hour_time=realm.default_twenty_four_hour_time,
|
|
|
|
delivery_email=email)
|
2013-02-12 21:14:48 +01:00
|
|
|
|
2016-05-18 20:23:03 +02:00
|
|
|
if bot_type or not active:
|
2013-11-12 18:20:05 +01:00
|
|
|
password = None
|
|
|
|
|
|
|
|
user_profile.set_password(password)
|
2013-05-03 00:25:43 +02:00
|
|
|
|
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
|
|
|
|
2018-05-11 01:40:23 +02:00
|
|
|
def create_user(email: str, password: Optional[str], realm: Realm,
|
|
|
|
full_name: str, short_name: str, active: bool = True,
|
2017-12-19 18:51:39 +01:00
|
|
|
is_realm_admin: bool = False, bot_type: Optional[int] = None,
|
|
|
|
bot_owner: Optional[UserProfile] = None,
|
2018-05-11 01:40:23 +02:00
|
|
|
tos_version: Optional[str] = None, timezone: str = "",
|
|
|
|
avatar_source: str = UserProfile.AVATAR_FROM_GRAVATAR,
|
2017-12-19 18:51:39 +01:00
|
|
|
is_mirror_dummy: bool = False,
|
|
|
|
default_sending_stream: Optional[Stream] = None,
|
|
|
|
default_events_register_stream: Optional[Stream] = None,
|
2018-05-22 18:13:51 +02:00
|
|
|
default_all_public_streams: Optional[bool] = None,
|
|
|
|
source_profile: Optional[UserProfile] = None) -> UserProfile:
|
2016-05-18 20:23:03 +02:00
|
|
|
user_profile = create_user_profile(realm, email, password, active, bot_type,
|
2014-01-07 18:57:54 +01:00
|
|
|
full_name, short_name, bot_owner,
|
2017-05-04 15:19:06 +02:00
|
|
|
is_mirror_dummy, tos_version, timezone)
|
2017-08-18 07:12:22 +02:00
|
|
|
user_profile.is_realm_admin = is_realm_admin
|
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
|
|
|
|
# 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
|
|
|
|
2013-04-01 16:57:50 +02:00
|
|
|
recipient = Recipient.objects.create(type_id=user_profile.id,
|
|
|
|
type=Recipient.PERSONAL)
|
|
|
|
Subscription.objects.create(user_profile=user_profile, recipient=recipient)
|
|
|
|
return user_profile
|